Loading analyst/src/components/Milestones/index.tsx +9 −54 Original line number Diff line number Diff line import { Boundary, ButtonGroup, Classes, OverflowList, Popover, } from '@blueprintjs/core' import { css } from '@emotion/css' import { useSubscribedTeams } from '@inject/frontend' import type { Team } from '@inject/graphql' import { useContext, useState } from 'react' import { useContext } from 'react' import { ExerciseContext } from '../ExerciseContext' import { TeamSelector } from '../TeamSelector' import { useTeamSelectorProps } from '../TeamSelector/useTeamSelectorProps' import MilestoneCards from './MilestoneCards' import Title from './Title' // TODO: convert to table Loading @@ -23,42 +16,10 @@ export const Milestones = () => { context: 'analyst', }) const [selectedId, setSelectedId] = useState<string | undefined>() const handleClick = (item: Team | undefined) => () => { setSelectedId(item?.id) } const overflowRenderer = (overflowItems: (Team | undefined)[]) => ( <div style={{ marginLeft: 'auto' }}> <Popover content={ <ButtonGroup vertical style={{ padding: 8 }}> {overflowItems.map(item => ( <Title key={item?.id || 'AllTeamsTab'} team={item} onClick={handleClick(item)} active={selectedId === item?.id} /> ))} </ButtonGroup> } position='bottom-left' > <span className={Classes.BREADCRUMBS_COLLAPSED} style={{ margin: 4 }} /> </Popover> </div> ) const visibleItemRenderer = (item: Team | undefined) => ( <Title key={item?.id || 'AllTeamsTab'} team={item} onClick={handleClick(item)} active={selectedId === item?.id} /> ) const teamSelectorProps = useTeamSelectorProps({ teams, includeAll: true, }) return ( <div Loading @@ -70,15 +31,9 @@ export const Milestones = () => { height: 100%; `} > <OverflowList style={{ alignItems: 'center' }} collapseFrom={Boundary.END} items={[undefined, ...teams]} overflowRenderer={overflowRenderer} visibleItemRenderer={visibleItemRenderer} /> <TeamSelector {...teamSelectorProps} /> <MilestoneCards teamId={selectedId} /> <MilestoneCards teamId={teamSelectorProps.selectedTeam?.id} /> </div> ) } analyst/src/components/TeamOrAllSelectPage/index.tsxdeleted 100644 → 0 +0 −94 Original line number Diff line number Diff line import { Boundary, ButtonGroup, Classes, Divider, OverflowList, Popover, } from '@blueprintjs/core' import { css } from '@emotion/css' import { type Team } from '@inject/graphql' import { TabButton } from '@inject/shared' import type { FC, ReactNode } from 'react' import { useEffect, useState } from 'react' const wrapper = css` display: flex; flex-direction: column; height: 100%; overflow: auto; ` interface TeamOrAllSelectPageProps { teams: Team[] getChildren: (selectedTeam: Team | undefined) => ReactNode allTeamsLabel?: string initialSelectedTeam?: Team | undefined } export const TeamOrAllSelectPage: FC<TeamOrAllSelectPageProps> = ({ teams, getChildren, allTeamsLabel = 'All teams', initialSelectedTeam, }) => { const [selectedTeam, setSelectedTeam] = useState<Team | undefined>( initialSelectedTeam ) const handleClick = (item: Team | undefined) => () => setSelectedTeam(item) useEffect(() => { if (selectedTeam && !teams.find(team => team.id === selectedTeam.id)) { setSelectedTeam(undefined) } }, [teams, selectedTeam]) const overflowRenderer = (overflowItems: (Team | undefined)[]) => ( <div style={{ marginLeft: 'auto' }}> <Popover content={ <ButtonGroup vertical style={{ padding: 8 }}> {overflowItems.map(item => ( <TabButton key={item?.id || 'AllTeamsTab'} active={ selectedTeam?.id === item?.id || (!item && !selectedTeam) } onClick={handleClick(item)} > {item?.name || allTeamsLabel} </TabButton> ))} </ButtonGroup> } position='bottom-left' > <span className={Classes.BREADCRUMBS_COLLAPSED} style={{ margin: 4 }} /> </Popover> </div> ) const visibleItemRenderer = (item: Team | undefined) => ( <TabButton key={item?.id || 'AllTeamsTab'} active={selectedTeam?.id === item?.id || (!item && !selectedTeam)} onClick={handleClick(item)} > {item?.name || allTeamsLabel} </TabButton> ) return ( <div className={wrapper}> <OverflowList style={{ alignItems: 'center', marginBottom: 8 }} collapseFrom={Boundary.END} items={[undefined, ...teams]} overflowRenderer={overflowRenderer} visibleItemRenderer={visibleItemRenderer} /> <Divider /> {getChildren(selectedTeam)} </div> ) } analyst/src/components/TeamSelectPage/index.tsx +6 −64 Original line number Diff line number Diff line import { Boundary, ButtonGroup, Classes, Divider, OverflowList, Popover, } from '@blueprintjs/core' import { Divider } from '@blueprintjs/core' import { css } from '@emotion/css' import type { Team } from '@inject/graphql' import { TabButton } from '@inject/shared' import type { FC, ReactNode } from 'react' import { useEffect, useState } from 'react' import { TeamSelector } from '../TeamSelector' import { useTeamSelectorProps } from '../TeamSelector/useTeamSelectorProps' const wrapper = css` display: flex; Loading @@ -19,13 +12,6 @@ const wrapper = css` overflow: auto; ` const buttonGroupContainer = css` padding: 0.5rem; min-width: max-content; max-height: 32rem; overflow-y: auto; ` interface TeamSelectPageProps { teams: Team[] getChildren: (selectedTeam: Team) => ReactNode Loading @@ -35,57 +21,13 @@ export const TeamSelectPage: FC<TeamSelectPageProps> = ({ teams, getChildren, }) => { const [selectedTeam, setSelectedTeam] = useState<Team>(teams[0]) const handleClick = (item: Team) => () => setSelectedTeam(item) useEffect(() => { setSelectedTeam(prev => teams.find(team => team.id === prev.id) || teams[0]) }, [teams]) const overflowRenderer = (overflowItems: Team[]) => ( <div style={{ marginLeft: 'auto' }}> <Popover content={ <ButtonGroup vertical className={buttonGroupContainer}> {overflowItems.map(item => ( <TabButton key={item.id} active={selectedTeam.id === item.id} onClick={handleClick(item)} > {item.name} </TabButton> ))} </ButtonGroup> } position='bottom-left' > <span className={Classes.BREADCRUMBS_COLLAPSED} style={{ margin: 4 }} /> </Popover> </div> ) const visibleItemRenderer = (item: Team) => ( <TabButton key={item.id} active={selectedTeam.id === item.id} onClick={handleClick(item)} > {item.name} </TabButton> ) const teamSelectorProps = useTeamSelectorProps({ teams }) return ( <div className={wrapper}> <OverflowList style={{ alignItems: 'center' }} collapseFrom={Boundary.END} items={teams} overflowRenderer={overflowRenderer} visibleItemRenderer={visibleItemRenderer} /> <TeamSelector {...teamSelectorProps} /> <Divider /> {getChildren(selectedTeam)} {getChildren(teamSelectorProps.selectedTeam)} </div> ) } analyst/src/components/TeamSelector/TeamButton.tsx 0 → 100644 +22 −0 Original line number Diff line number Diff line import type { Team } from '@inject/graphql' import { TabButton } from '@inject/shared' import type { FC } from 'react' interface TeamButtonProps { team: Team | undefined selectedTeamId: string | undefined onClick: () => void } export const TeamButton: FC<TeamButtonProps> = ({ team, selectedTeamId, onClick, }) => ( <TabButton active={selectedTeamId === team?.id || (!team && !selectedTeamId)} onClick={onClick} > {team?.name || 'All teams'} </TabButton> ) analyst/src/components/TeamSelector/index.tsx 0 → 100644 +84 −0 Original line number Diff line number Diff line import { Boundary, ButtonGroup, Classes, OverflowList, Popover, } from '@blueprintjs/core' import { css, cx } from '@emotion/css' import type { Team } from '@inject/graphql' import type { Dispatch, FC, SetStateAction } from 'react' import { TeamButton } from './TeamButton' import type { TeamSelectorProps } from './types' export const TeamSelector: FC<TeamSelectorProps> = ({ selectedTeam, setSelectedTeam, items, }) => { const handleClick = (item: Team | undefined) => (setSelectedTeam as Dispatch<SetStateAction<Team | undefined>>)(item) const overflowRenderer = (overflowItems: (Team | undefined)[]) => ( <div className={css` margin-left: auto; `} > <Popover content={ <ButtonGroup vertical className={css` display: flex; flex-direction: column; padding: 0.5rem; overflow-y: auto; max-height: 60vh; `} > {overflowItems.map(item => ( <TeamButton key={item?.id || 'all-teams-tab'} team={item} selectedTeamId={selectedTeam?.id} onClick={() => handleClick(item)} /> ))} </ButtonGroup> } position='bottom-left' > <span className={cx( Classes.BREADCRUMBS_COLLAPSED, css` margin: 0.25rem; ` )} /> </Popover> </div> ) const visibleItemRenderer = (item: Team | undefined) => ( <TeamButton key={item?.id || 'all-teams-tab'} team={item} selectedTeamId={selectedTeam?.id} onClick={() => handleClick(item)} /> ) return ( <OverflowList className={css` align-items: center; `} collapseFrom={Boundary.END} items={items} overflowRenderer={overflowRenderer} visibleItemRenderer={visibleItemRenderer} /> ) } Loading
analyst/src/components/Milestones/index.tsx +9 −54 Original line number Diff line number Diff line import { Boundary, ButtonGroup, Classes, OverflowList, Popover, } from '@blueprintjs/core' import { css } from '@emotion/css' import { useSubscribedTeams } from '@inject/frontend' import type { Team } from '@inject/graphql' import { useContext, useState } from 'react' import { useContext } from 'react' import { ExerciseContext } from '../ExerciseContext' import { TeamSelector } from '../TeamSelector' import { useTeamSelectorProps } from '../TeamSelector/useTeamSelectorProps' import MilestoneCards from './MilestoneCards' import Title from './Title' // TODO: convert to table Loading @@ -23,42 +16,10 @@ export const Milestones = () => { context: 'analyst', }) const [selectedId, setSelectedId] = useState<string | undefined>() const handleClick = (item: Team | undefined) => () => { setSelectedId(item?.id) } const overflowRenderer = (overflowItems: (Team | undefined)[]) => ( <div style={{ marginLeft: 'auto' }}> <Popover content={ <ButtonGroup vertical style={{ padding: 8 }}> {overflowItems.map(item => ( <Title key={item?.id || 'AllTeamsTab'} team={item} onClick={handleClick(item)} active={selectedId === item?.id} /> ))} </ButtonGroup> } position='bottom-left' > <span className={Classes.BREADCRUMBS_COLLAPSED} style={{ margin: 4 }} /> </Popover> </div> ) const visibleItemRenderer = (item: Team | undefined) => ( <Title key={item?.id || 'AllTeamsTab'} team={item} onClick={handleClick(item)} active={selectedId === item?.id} /> ) const teamSelectorProps = useTeamSelectorProps({ teams, includeAll: true, }) return ( <div Loading @@ -70,15 +31,9 @@ export const Milestones = () => { height: 100%; `} > <OverflowList style={{ alignItems: 'center' }} collapseFrom={Boundary.END} items={[undefined, ...teams]} overflowRenderer={overflowRenderer} visibleItemRenderer={visibleItemRenderer} /> <TeamSelector {...teamSelectorProps} /> <MilestoneCards teamId={selectedId} /> <MilestoneCards teamId={teamSelectorProps.selectedTeam?.id} /> </div> ) }
analyst/src/components/TeamOrAllSelectPage/index.tsxdeleted 100644 → 0 +0 −94 Original line number Diff line number Diff line import { Boundary, ButtonGroup, Classes, Divider, OverflowList, Popover, } from '@blueprintjs/core' import { css } from '@emotion/css' import { type Team } from '@inject/graphql' import { TabButton } from '@inject/shared' import type { FC, ReactNode } from 'react' import { useEffect, useState } from 'react' const wrapper = css` display: flex; flex-direction: column; height: 100%; overflow: auto; ` interface TeamOrAllSelectPageProps { teams: Team[] getChildren: (selectedTeam: Team | undefined) => ReactNode allTeamsLabel?: string initialSelectedTeam?: Team | undefined } export const TeamOrAllSelectPage: FC<TeamOrAllSelectPageProps> = ({ teams, getChildren, allTeamsLabel = 'All teams', initialSelectedTeam, }) => { const [selectedTeam, setSelectedTeam] = useState<Team | undefined>( initialSelectedTeam ) const handleClick = (item: Team | undefined) => () => setSelectedTeam(item) useEffect(() => { if (selectedTeam && !teams.find(team => team.id === selectedTeam.id)) { setSelectedTeam(undefined) } }, [teams, selectedTeam]) const overflowRenderer = (overflowItems: (Team | undefined)[]) => ( <div style={{ marginLeft: 'auto' }}> <Popover content={ <ButtonGroup vertical style={{ padding: 8 }}> {overflowItems.map(item => ( <TabButton key={item?.id || 'AllTeamsTab'} active={ selectedTeam?.id === item?.id || (!item && !selectedTeam) } onClick={handleClick(item)} > {item?.name || allTeamsLabel} </TabButton> ))} </ButtonGroup> } position='bottom-left' > <span className={Classes.BREADCRUMBS_COLLAPSED} style={{ margin: 4 }} /> </Popover> </div> ) const visibleItemRenderer = (item: Team | undefined) => ( <TabButton key={item?.id || 'AllTeamsTab'} active={selectedTeam?.id === item?.id || (!item && !selectedTeam)} onClick={handleClick(item)} > {item?.name || allTeamsLabel} </TabButton> ) return ( <div className={wrapper}> <OverflowList style={{ alignItems: 'center', marginBottom: 8 }} collapseFrom={Boundary.END} items={[undefined, ...teams]} overflowRenderer={overflowRenderer} visibleItemRenderer={visibleItemRenderer} /> <Divider /> {getChildren(selectedTeam)} </div> ) }
analyst/src/components/TeamSelectPage/index.tsx +6 −64 Original line number Diff line number Diff line import { Boundary, ButtonGroup, Classes, Divider, OverflowList, Popover, } from '@blueprintjs/core' import { Divider } from '@blueprintjs/core' import { css } from '@emotion/css' import type { Team } from '@inject/graphql' import { TabButton } from '@inject/shared' import type { FC, ReactNode } from 'react' import { useEffect, useState } from 'react' import { TeamSelector } from '../TeamSelector' import { useTeamSelectorProps } from '../TeamSelector/useTeamSelectorProps' const wrapper = css` display: flex; Loading @@ -19,13 +12,6 @@ const wrapper = css` overflow: auto; ` const buttonGroupContainer = css` padding: 0.5rem; min-width: max-content; max-height: 32rem; overflow-y: auto; ` interface TeamSelectPageProps { teams: Team[] getChildren: (selectedTeam: Team) => ReactNode Loading @@ -35,57 +21,13 @@ export const TeamSelectPage: FC<TeamSelectPageProps> = ({ teams, getChildren, }) => { const [selectedTeam, setSelectedTeam] = useState<Team>(teams[0]) const handleClick = (item: Team) => () => setSelectedTeam(item) useEffect(() => { setSelectedTeam(prev => teams.find(team => team.id === prev.id) || teams[0]) }, [teams]) const overflowRenderer = (overflowItems: Team[]) => ( <div style={{ marginLeft: 'auto' }}> <Popover content={ <ButtonGroup vertical className={buttonGroupContainer}> {overflowItems.map(item => ( <TabButton key={item.id} active={selectedTeam.id === item.id} onClick={handleClick(item)} > {item.name} </TabButton> ))} </ButtonGroup> } position='bottom-left' > <span className={Classes.BREADCRUMBS_COLLAPSED} style={{ margin: 4 }} /> </Popover> </div> ) const visibleItemRenderer = (item: Team) => ( <TabButton key={item.id} active={selectedTeam.id === item.id} onClick={handleClick(item)} > {item.name} </TabButton> ) const teamSelectorProps = useTeamSelectorProps({ teams }) return ( <div className={wrapper}> <OverflowList style={{ alignItems: 'center' }} collapseFrom={Boundary.END} items={teams} overflowRenderer={overflowRenderer} visibleItemRenderer={visibleItemRenderer} /> <TeamSelector {...teamSelectorProps} /> <Divider /> {getChildren(selectedTeam)} {getChildren(teamSelectorProps.selectedTeam)} </div> ) }
analyst/src/components/TeamSelector/TeamButton.tsx 0 → 100644 +22 −0 Original line number Diff line number Diff line import type { Team } from '@inject/graphql' import { TabButton } from '@inject/shared' import type { FC } from 'react' interface TeamButtonProps { team: Team | undefined selectedTeamId: string | undefined onClick: () => void } export const TeamButton: FC<TeamButtonProps> = ({ team, selectedTeamId, onClick, }) => ( <TabButton active={selectedTeamId === team?.id || (!team && !selectedTeamId)} onClick={onClick} > {team?.name || 'All teams'} </TabButton> )
analyst/src/components/TeamSelector/index.tsx 0 → 100644 +84 −0 Original line number Diff line number Diff line import { Boundary, ButtonGroup, Classes, OverflowList, Popover, } from '@blueprintjs/core' import { css, cx } from '@emotion/css' import type { Team } from '@inject/graphql' import type { Dispatch, FC, SetStateAction } from 'react' import { TeamButton } from './TeamButton' import type { TeamSelectorProps } from './types' export const TeamSelector: FC<TeamSelectorProps> = ({ selectedTeam, setSelectedTeam, items, }) => { const handleClick = (item: Team | undefined) => (setSelectedTeam as Dispatch<SetStateAction<Team | undefined>>)(item) const overflowRenderer = (overflowItems: (Team | undefined)[]) => ( <div className={css` margin-left: auto; `} > <Popover content={ <ButtonGroup vertical className={css` display: flex; flex-direction: column; padding: 0.5rem; overflow-y: auto; max-height: 60vh; `} > {overflowItems.map(item => ( <TeamButton key={item?.id || 'all-teams-tab'} team={item} selectedTeamId={selectedTeam?.id} onClick={() => handleClick(item)} /> ))} </ButtonGroup> } position='bottom-left' > <span className={cx( Classes.BREADCRUMBS_COLLAPSED, css` margin: 0.25rem; ` )} /> </Popover> </div> ) const visibleItemRenderer = (item: Team | undefined) => ( <TeamButton key={item?.id || 'all-teams-tab'} team={item} selectedTeamId={selectedTeam?.id} onClick={() => handleClick(item)} /> ) return ( <OverflowList className={css` align-items: center; `} collapseFrom={Boundary.END} items={items} overflowRenderer={overflowRenderer} visibleItemRenderer={visibleItemRenderer} /> ) }