Loading frontend/src/instructor/InstructorTeamSelector/TeamButton.tsx +30 −32 Original line number Diff line number Diff line import type { TeamState } from '@inject/graphql' import type { AnchorButtonProps } from '@blueprintjs/core' import { LinkButton } from '@inject/shared' import type { NavigateOptions } from '@tanstack/react-router' import { useMatches } from '@tanstack/react-router' import { type FC } from 'react' import { TeamLabel } from '../../components/TeamLabel' import { InstructorTeamLayoutRoute } from '../../routes/_protected/instructor/$exerciseId/$teamId/route' interface TeamButtonProps { teamState: TeamState hideLabel: boolean | undefined exerciseId: string teamId: string buttonProps: AnchorButtonProps } const TeamButton: FC<TeamButtonProps> = ({ teamState, hideLabel }) => ( export const TeamButton: FC<TeamButtonProps> = ({ exerciseId, teamId, buttonProps, }) => { const matches = useMatches() const { params, fullPath } = matches.at(-1) ?? {} const teamSelected = !!params && 'teamId' in params && !!params.teamId return ( <LinkButton key={teamState.id} link={{ to: InstructorTeamLayoutRoute.to, link={ { to: teamSelected ? fullPath : InstructorTeamLayoutRoute.to, params: { exerciseId: teamState.exercise.id, teamId: teamState.id, ...(teamSelected ? params : {}), exerciseId, teamId, }, }} button={{ alignText: 'left', fill: true, minimal: true, title: teamState.name, children: ( <TeamLabel teamState={teamState} hideLabel={hideLabel} minimal showUsers /> ), ellipsizeText: true, }} } as NavigateOptions } button={buttonProps} /> ) export default TeamButton } frontend/src/instructor/InstructorTeamSelector/TeamListVertical.tsx +19 −3 Original line number Diff line number Diff line import type { FC } from 'react' import TeamButton from './TeamButton' import { TeamLabel } from '../../components' import { TeamButton } from './TeamButton' import { useSubscribedTeams } from './useSubscribedTeams' const TeamListVertical: FC<{ Loading @@ -16,8 +17,23 @@ const TeamListVertical: FC<{ {selectedTeamStates.map(teamState => ( <TeamButton key={teamState.id} hideLabel={hideLabel} exerciseId={teamState.exercise.id} teamId={teamState.id} buttonProps={{ alignText: 'left', fill: true, minimal: true, title: teamState.name, children: ( <TeamLabel teamState={teamState} hideLabel={hideLabel} minimal showUsers /> ), ellipsizeText: true, }} /> ))} </> Loading frontend/src/views/InstructorView/TeamTabs.tsx +22 −28 Original line number Diff line number Diff line import type { AnchorButtonProps } from '@blueprintjs/core' import { Boundary, Button, Loading @@ -8,12 +9,11 @@ import { } from '@blueprintjs/core' import { css, cx } from '@emotion/css' import type { Team, TeamState } from '@inject/graphql' import { LinkButton } from '@inject/shared' import { useClickAway } from 'ahooks' import type { FC } from 'react' import { memo, useRef, useState } from 'react' import { TeamButton } from '../../instructor/InstructorTeamSelector/TeamButton' import { useSubscribedTeams } from '../../instructor/InstructorTeamSelector/useSubscribedTeams' import { InstructorTeamLayoutRoute } from '../../routes/_protected/instructor/$exerciseId/$teamId/route' import { barClass } from './barClass' const buttonGroupContainer = css` Loading Loading @@ -55,30 +55,6 @@ const Dropdown: FC<{ ) } const TeamButton: FC<{ item: Team; exerciseId: string }> = ({ exerciseId, item, }) => ( <LinkButton key={item.id} link={{ to: InstructorTeamLayoutRoute.to, params: { teamId: item.id, exerciseId, }, }} button={{ text: item.name, minimal: true, style: { minWidth: 'fit-content', }, }} /> ) // TODO: when clicking (when no team is selected), loops and the tab becomes unresponsive const TeamTabs: FC<{ teamId?: string exerciseId: string Loading @@ -88,13 +64,26 @@ const TeamTabs: FC<{ context: 'instructor', }) const getButtonProps = (item: Team): AnchorButtonProps => ({ text: item.name, minimal: true, style: { minWidth: 'fit-content', }, }) const overflowRenderer = (overflowItems: Team[]) => ( <div style={{ marginLeft: 'auto' }}> <Popover content={ <ButtonGroup vertical className={buttonGroupContainer}> {overflowItems.map(item => ( <TeamButton key={item.id} exerciseId={exerciseId} item={item} /> <TeamButton key={item.id} exerciseId={exerciseId} teamId={item.id} buttonProps={getButtonProps(item)} /> ))} </ButtonGroup> } Loading @@ -106,7 +95,12 @@ const TeamTabs: FC<{ ) const visibleItemRenderer = (item: Team) => ( <TeamButton exerciseId={exerciseId} item={item} /> <TeamButton key={item.id} exerciseId={exerciseId} teamId={item.id} buttonProps={getButtonProps(item)} /> ) return ( Loading Loading
frontend/src/instructor/InstructorTeamSelector/TeamButton.tsx +30 −32 Original line number Diff line number Diff line import type { TeamState } from '@inject/graphql' import type { AnchorButtonProps } from '@blueprintjs/core' import { LinkButton } from '@inject/shared' import type { NavigateOptions } from '@tanstack/react-router' import { useMatches } from '@tanstack/react-router' import { type FC } from 'react' import { TeamLabel } from '../../components/TeamLabel' import { InstructorTeamLayoutRoute } from '../../routes/_protected/instructor/$exerciseId/$teamId/route' interface TeamButtonProps { teamState: TeamState hideLabel: boolean | undefined exerciseId: string teamId: string buttonProps: AnchorButtonProps } const TeamButton: FC<TeamButtonProps> = ({ teamState, hideLabel }) => ( export const TeamButton: FC<TeamButtonProps> = ({ exerciseId, teamId, buttonProps, }) => { const matches = useMatches() const { params, fullPath } = matches.at(-1) ?? {} const teamSelected = !!params && 'teamId' in params && !!params.teamId return ( <LinkButton key={teamState.id} link={{ to: InstructorTeamLayoutRoute.to, link={ { to: teamSelected ? fullPath : InstructorTeamLayoutRoute.to, params: { exerciseId: teamState.exercise.id, teamId: teamState.id, ...(teamSelected ? params : {}), exerciseId, teamId, }, }} button={{ alignText: 'left', fill: true, minimal: true, title: teamState.name, children: ( <TeamLabel teamState={teamState} hideLabel={hideLabel} minimal showUsers /> ), ellipsizeText: true, }} } as NavigateOptions } button={buttonProps} /> ) export default TeamButton }
frontend/src/instructor/InstructorTeamSelector/TeamListVertical.tsx +19 −3 Original line number Diff line number Diff line import type { FC } from 'react' import TeamButton from './TeamButton' import { TeamLabel } from '../../components' import { TeamButton } from './TeamButton' import { useSubscribedTeams } from './useSubscribedTeams' const TeamListVertical: FC<{ Loading @@ -16,8 +17,23 @@ const TeamListVertical: FC<{ {selectedTeamStates.map(teamState => ( <TeamButton key={teamState.id} hideLabel={hideLabel} exerciseId={teamState.exercise.id} teamId={teamState.id} buttonProps={{ alignText: 'left', fill: true, minimal: true, title: teamState.name, children: ( <TeamLabel teamState={teamState} hideLabel={hideLabel} minimal showUsers /> ), ellipsizeText: true, }} /> ))} </> Loading
frontend/src/views/InstructorView/TeamTabs.tsx +22 −28 Original line number Diff line number Diff line import type { AnchorButtonProps } from '@blueprintjs/core' import { Boundary, Button, Loading @@ -8,12 +9,11 @@ import { } from '@blueprintjs/core' import { css, cx } from '@emotion/css' import type { Team, TeamState } from '@inject/graphql' import { LinkButton } from '@inject/shared' import { useClickAway } from 'ahooks' import type { FC } from 'react' import { memo, useRef, useState } from 'react' import { TeamButton } from '../../instructor/InstructorTeamSelector/TeamButton' import { useSubscribedTeams } from '../../instructor/InstructorTeamSelector/useSubscribedTeams' import { InstructorTeamLayoutRoute } from '../../routes/_protected/instructor/$exerciseId/$teamId/route' import { barClass } from './barClass' const buttonGroupContainer = css` Loading Loading @@ -55,30 +55,6 @@ const Dropdown: FC<{ ) } const TeamButton: FC<{ item: Team; exerciseId: string }> = ({ exerciseId, item, }) => ( <LinkButton key={item.id} link={{ to: InstructorTeamLayoutRoute.to, params: { teamId: item.id, exerciseId, }, }} button={{ text: item.name, minimal: true, style: { minWidth: 'fit-content', }, }} /> ) // TODO: when clicking (when no team is selected), loops and the tab becomes unresponsive const TeamTabs: FC<{ teamId?: string exerciseId: string Loading @@ -88,13 +64,26 @@ const TeamTabs: FC<{ context: 'instructor', }) const getButtonProps = (item: Team): AnchorButtonProps => ({ text: item.name, minimal: true, style: { minWidth: 'fit-content', }, }) const overflowRenderer = (overflowItems: Team[]) => ( <div style={{ marginLeft: 'auto' }}> <Popover content={ <ButtonGroup vertical className={buttonGroupContainer}> {overflowItems.map(item => ( <TeamButton key={item.id} exerciseId={exerciseId} item={item} /> <TeamButton key={item.id} exerciseId={exerciseId} teamId={item.id} buttonProps={getButtonProps(item)} /> ))} </ButtonGroup> } Loading @@ -106,7 +95,12 @@ const TeamTabs: FC<{ ) const visibleItemRenderer = (item: Team) => ( <TeamButton exerciseId={exerciseId} item={item} /> <TeamButton key={item.id} exerciseId={exerciseId} teamId={item.id} buttonProps={getButtonProps(item)} /> ) return ( Loading