Skip to content
18 changes: 9 additions & 9 deletions lua/spec/team_participants_tbd_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,10 @@ describe('Team Participants TBD Functionality', function()
TeamParticipantsWikiParser.fillIncompleteRoster(opponent, 5)

assert.are_equal(7, #opponent.players)
local actualPlayers = Array.filter(opponent.players, function(p)
return p.extradata.type == 'player'
local activePlayers = Array.filter(opponent.players, function(p)
return p.extradata.type == 'player' and not p.extradata.status
end)
assert.are_equal(5, #actualPlayers)
assert.are_equal(5, #activePlayers)
end)

it('handles missing data gracefully', function()
Expand Down Expand Up @@ -184,14 +184,14 @@ describe('Team Participants TBD Functionality', function()
TeamParticipantsController.fillIncompleteRosters(parsedData)

local opponent = parsedData.participants[1].opponent
local actualPlayers = Array.filter(opponent.players, function(p)
return p.extradata.type == 'player'
local activePlayers = Array.filter(opponent.players, function(p)
return p.extradata.type == 'player' and not p.extradata.status
end)

assert.are_equal(5, #actualPlayers)
assert.are_equal('alexis', actualPlayers[1].displayName)
assert.are_equal('TBD', actualPlayers[4].displayName)
assert.are_equal('TBD', actualPlayers[5].displayName)
assert.are_equal(5, #activePlayers)
assert.are_equal('alexis', activePlayers[1].displayName)
assert.are_equal('TBD', activePlayers[4].displayName)
assert.are_equal('TBD', activePlayers[5].displayName)

LpdbQuery:revert()
TeamTemplateMock.tearDown()
Expand Down
9 changes: 5 additions & 4 deletions lua/wikis/commons/TeamParticipants/Controller.lua
Original file line number Diff line number Diff line change
Expand Up @@ -105,19 +105,20 @@ function TeamParticipantsController.importSquadMembersFromDatabase(participant)
end)

return Array.map(membersToImport, function (member)
local memberType = member.type
local status
if member.hasLeft then
memberType = 'former'
status = 'former'
elseif member.role and member.role:lower() == 'substitute' then
memberType = 'sub'
status = 'sub'
end
return TeamParticipantsWikiParser.parsePlayer{
member.displayName,
link = member.pageName,
flag = member.nationality,
faction = member.faction,
role = member.role,
type = memberType,
type = member.type,
status = status,
}
end)
end
Expand Down
30 changes: 21 additions & 9 deletions lua/wikis/commons/TeamParticipants/Parse/Wiki.lua
Original file line number Diff line number Diff line change
Expand Up @@ -211,18 +211,30 @@ function TeamParticipantsWikiParser.parsePlayer(playerInput)
local playedInput = Logic.readBoolOrNil(playerInput.played)
local resultsInput = Logic.readBoolOrNil(playerInput.results)
local roles = RoleUtil.readRoleArgs(playerInput.role)
local playerType = playerInput.type or 'player'

local hasNoStaffRoles = Array.all(roles, function(role) return role.type ~= RoleUtil.ROLE_TYPE.STAFF end)
local inputType = playerInput.type or 'player'
local hasStaffRoles = Array.any(roles, function(role) return role.type == RoleUtil.ROLE_TYPE.STAFF end)

local status = playerInput.status
if not status then
if inputType == 'former' then
status = 'former'
elseif inputType == 'sub' then
status = 'sub'
end
end

if playerType ~= 'staff' and not hasNoStaffRoles then
local playerType
if inputType == 'staff' or hasStaffRoles then
playerType = 'staff'
else
playerType = 'player'
end

player.extradata = {
roles = roles,
trophies = tonumber(playerInput.trophies),
type = playerType,
status = status,
played = Logic.nilOr(playedInput, true),
results = Logic.nilOr(resultsInput, playedInput, true),
}
Expand All @@ -239,16 +251,16 @@ function TeamParticipantsWikiParser.fillIncompleteRoster(opponent, minimumPlayer
return
end

local actualPlayers = Array.filter(opponent.players, function(player)
return player.extradata.type == 'player'
local activePlayers = Array.filter(opponent.players, function(player)
return player.extradata.type == 'player' and not player.extradata.status
end)

local actualPlayerCount = #actualPlayers
if actualPlayerCount >= expectedPlayerCount then
local activePlayerCount = #activePlayers
if activePlayerCount >= expectedPlayerCount then
return
end

local tbdPlayers = TeamParticipantsWikiParser.createTBDPlayers(expectedPlayerCount - actualPlayerCount)
local tbdPlayers = TeamParticipantsWikiParser.createTBDPlayers(expectedPlayerCount - activePlayerCount)
Array.extendWith(opponent.players, tbdPlayers)
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function PotentialQualifiers:render()

local children = {
Div{
classes = {'team-participant-card__potential-qualifiers-title'},
classes = {'team-participant-card__subheader'},
children = 'Potential qualifiers'
},
Div{
Expand Down
112 changes: 76 additions & 36 deletions lua/wikis/commons/Widget/Participants/Team/Roster.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
---
-- @Liquipedia
-- page=Module:Widget/Participants/Team/Roster
Expand Down Expand Up @@ -38,13 +38,15 @@
[TAB_ENUM.STAFF] = {title = 'Staff', order = 4},
}

---@type table<string, ParticipantsTeamCardTabs>
local PERSON_TYPE_TO_TAB = {
player = TAB_ENUM.MAIN,
sub = TAB_ENUM.SUB,
former = TAB_ENUM.FORMER,
staff = TAB_ENUM.STAFF,
}
---@param player table
---@return ParticipantsTeamCardTabs
local function getPlayerTab(player)
local status = player.extradata.status
if status == 'former' then return TAB_ENUM.FORMER end
if status == 'sub' then return TAB_ENUM.SUB end
if player.extradata.type == 'staff' then return TAB_ENUM.STAFF end
return TAB_ENUM.MAIN
end

-- The biz logic behind the role display is somewhat complicated.
-- There's 2 areas we show the role, left-role and right-role
Expand All @@ -59,7 +61,6 @@
---@return string?, string[]?
local function getRoleDisplays(player)
local roles = player.extradata.roles or {}
local playerType = player.extradata.type
local played = player.extradata.played

local function roleLeftDisplay()
Expand All @@ -76,7 +77,7 @@
local function roleRightDisplay()
local rightRoles = {}
-- Add status label first (Left or DNP)
if playerType == 'former' then
if player.extradata.status == 'former' then
table.insert(rightRoles, 'Left')
elseif not played then
table.insert(rightRoles, 'DNP')
Expand All @@ -100,11 +101,11 @@
---@return Widget
function ParticipantsTeamRoster:render()
local participant = self.props.participant
local makeRostersDisplay = function(players)
-- Used for making the sorting stable

-- Used for making the sorting stable
local sortPlayers = function(players)
local playerToIndex = Table.map(players, function(index, player) return player, index end)
-- Sort the players based on their roles first, then by their original order
players = Array.sortBy(players, FnUtil.identity, function (a, b)
return Array.sortBy(players, FnUtil.identity, function(a, b)
local function getPlayerSortOrder(player)
local roles = player.extradata.roles or {}
return roles[1] and roles[1].sortOrder or math.huge
Expand All @@ -116,38 +117,76 @@
end
return orderA < orderB
end)
end

local makePlayerWidget = function(player, index)
local playerTeam = participant.opponent.template ~= player.team and player.team or nil
local playerTeamAsOpponent = playerTeam and Opponent.readOpponentArgs{
type = Opponent.team,
template = playerTeam,
} or nil
local roleLeft, roleRight = getRoleDisplays(player)
return ParticipantsTeamMember{
player = player,
team = playerTeamAsOpponent,
even = index % 2 == 0,
roleLeft = roleLeft,
roleRight = roleRight,
trophies = player.extradata.trophies or 0,
}
end

---@param groups {label: string?, players: table[]}[]
local makeRostersDisplay = function(groups)
local children = {}
for _, group in ipairs(groups) do
if group.label then
table.insert(children, Div{
classes = {'team-participant-card__subheader'},
children = group.label,
})
end
table.insert(children, Div{
classes = { 'team-participant-roster' },
children = Array.map(group.players, makePlayerWidget),
})
end
return Div{
classes = { 'team-participant-roster' },
children = Array.map(players, function(player, index)
local playerTeam = participant.opponent.template ~= player.team and player.team or nil
local playerTeamAsOpponent = playerTeam and Opponent.readOpponentArgs{
type = Opponent.team,
template = playerTeam,
} or nil
local roleLeft, roleRight = getRoleDisplays(player)
return ParticipantsTeamMember{
player = player,
team = playerTeamAsOpponent,
even = index % 2 == 0,
roleLeft = roleLeft,
roleRight = roleRight,
trophies = player.extradata.trophies or 0,
strikethrough = player.extradata.type == 'former',
}
end)
children = children,
}
end

local tabs = Array.map(Table.entries(TAB_DATA), function(tabTuple)
local tabTypeEnum, tabData = tabTuple[1], tabTuple[2]
local tabPlayers = Array.filter(participant.opponent.players or {}, function(player)
local personType = player.extradata.type
return PERSON_TYPE_TO_TAB[personType] == tabTypeEnum
end)
local tabPlayers = sortPlayers(Array.filter(participant.opponent.players or {}, function(player)
return getPlayerTab(player) == tabTypeEnum
end))

local groups
if tabTypeEnum == TAB_ENUM.FORMER then
local formerPlayers = Array.filter(tabPlayers, function(player)
return player.extradata.type ~= 'staff'
end)
local formerStaff = Array.filter(tabPlayers, function(player)
return player.extradata.type == 'staff'
end)
if #formerPlayers > 0 and #formerStaff > 0 then
groups = {
{ label = 'Players', players = formerPlayers },
{ label = 'Staff', players = formerStaff },
}
end
end
if not groups then
groups = { { players = tabPlayers } }
end

return {
order = tabData.order,
title = tabData.title,
type = tabTypeEnum,
groups = groups,
players = tabPlayers,
}
end)
Expand All @@ -162,7 +201,8 @@
and #tabs[2].players == 1
then
-- If we only have main and staff, and exactly one staff, just show both rosters without a switch
return makeRostersDisplay(Array.extend(tabs[1].players, tabs[2].players))
local mergedPlayers = sortPlayers(Array.extend(tabs[1].players, tabs[2].players))
return makeRostersDisplay({ { players = mergedPlayers } })
end
tabs = Array.sortBy(tabs, Operator.property('order'))

Expand All @@ -177,7 +217,7 @@
tabs = Array.map(tabs, function(tab)
return {
label = tab.title,
content = makeRostersDisplay(tab.players),
content = makeRostersDisplay(tab.groups),
}
end),
}
Expand Down
28 changes: 14 additions & 14 deletions stylesheets/commons/TeamParticipantCard.scss
Original file line number Diff line number Diff line change
Expand Up @@ -427,20 +427,6 @@ $compact-selector: '[data-switch-group="team-cards-compact"]';
flex-direction: column;
gap: 0.25rem;

&-title {
padding: 0 0.5rem;
font-size: 0.875rem;
font-weight: bold;

.theme--light & {
color: var( --clr-secondary-25 );
}

.theme--dark & {
color: var( --clr-secondary-90 );
}
}

&-list {
display: flex;
flex-direction: column;
Expand All @@ -467,6 +453,20 @@ $compact-selector: '[data-switch-group="team-cards-compact"]';
}
}
}

&__subheader {
padding: 0 0.5rem;
font-size: 0.875rem;
font-weight: bold;

.theme--light & {
color: var( --clr-secondary-25 );
}

.theme--dark & {
color: var( --clr-secondary-90 );
}
}
}

body:has( .switch-toggle-active#{ $compact-selector } ) {
Expand Down
Loading