diff --git a/components/actions/ActionPhase.js b/components/actions/ActionPhase.js index df983599..d5cb7ea8 100644 --- a/components/actions/ActionPhase.js +++ b/components/actions/ActionPhase.js @@ -73,7 +73,9 @@ function Phase(props) { const theme = useTheme(); let blockColor = theme.themeColors.light; - const color = getStatusColorForAction(action, plan, theme); + const color = statusSummary + ? getStatusColorForAction(action, plan, theme) + : theme.graphColors.grey050; let labelClass = 'disabled'; @@ -85,7 +87,7 @@ function Phase(props) { } else if (active) { blockColor = color; labelClass = 'active'; - } else if (statusSummary.isCompleted) { + } else if (statusSummary?.isCompleted) { blockColor = color; labelClass = 'disabled'; } @@ -115,9 +117,10 @@ function ActionPhase(props) { } // Override phase name in special case statuses const inactive = ['cancelled', 'merged', 'postponed', 'completed'].includes( - status.identifier + status?.identifier ); - if (inactive) { + + if (status && inactive) { activePhaseName = status.identifier === ActionStatusSummaryIdentifier.Merged ? `${t('actions:action-status-merged', getActionTermContext(plan))}` @@ -141,7 +144,7 @@ function ActionPhase(props) { /> ))} - {!compact && status.identifier !== 'UNDEFINED' && ( + {!compact && !!status && status.identifier !== 'UNDEFINED' && ( <> {status.label} {reason && ( @@ -158,7 +161,8 @@ function ActionPhase(props) { } ActionPhase.propTypes = { - status: PropTypes.shape().isRequired, + /** If status is undefined, status colors and labels will be hidden */ + status: PropTypes.shape(), activePhase: PropTypes.shape(), reason: PropTypes.string, phases: PropTypes.arrayOf( diff --git a/components/dashboard/ActionStatusTable.tsx b/components/dashboard/ActionStatusTable.tsx index dd38e57b..a3ec7f72 100644 --- a/components/dashboard/ActionStatusTable.tsx +++ b/components/dashboard/ActionStatusTable.tsx @@ -1,4 +1,4 @@ -import React, { ReactNode, useState } from 'react'; +import React, { ReactNode, useState, createContext } from 'react'; import { Table, Button } from 'reactstrap'; import styled from 'styled-components'; @@ -16,6 +16,21 @@ import { import { PlanContextFragment } from 'common/__generated__/graphql'; import { COLUMN_CONFIG } from './dashboard.constants'; +type TActionTableContext = { + plan?: PlanContextFragment; + planViewUrl?: string | null; + /** Custom configuration for cell components */ + config: { + hasPhaseAndStatusColumns?: boolean; + }; +}; + +export const ActionTableContext = createContext({ + plan: undefined, + planViewUrl: undefined, + config: {}, +}); + const TableWrapper = styled.div` width: 100%; display: flex; @@ -163,6 +178,12 @@ const preprocessForSorting = ( } }; +const hasPhaseAndStatusColumns = (columns: ColumnConfig[]) => + !!( + columns.find((c) => c.__typename === 'ImplementationPhaseColumnBlock') && + columns.find((c) => c.__typename === 'StatusColumnBlock') + ); + interface Props { actions: ActionListAction[]; orgs: ActionListOrganization[]; @@ -232,7 +253,15 @@ const ActionStatusTable = (props: Props) => { : columns; return ( - <> + {sort.key && ( @@ -294,7 +323,7 @@ const ActionStatusTable = (props: Props) => { - + ); }; diff --git a/components/dashboard/ActionTableTooltips.tsx b/components/dashboard/ActionTableTooltips.tsx index 708cacae..cd92938c 100644 --- a/components/dashboard/ActionTableTooltips.tsx +++ b/components/dashboard/ActionTableTooltips.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useContext } from 'react'; import styled from 'styled-components'; import dayjs from 'common/dayjs'; import { @@ -11,6 +11,7 @@ import { ActionListAction } from './dashboard.types'; import { PlanContextFragment } from 'common/__generated__/graphql'; import { getTaskCounts } from './cells/TasksStatusCell'; import { useTheme } from 'common/theme'; +import { ActionTableContext } from './ActionStatusTable'; const TooltipTitle = styled.p` font-weight: ${(props) => props.theme.fontWeightBold}; @@ -126,14 +127,18 @@ export const TasksTooltipContent = ({ action, plan }: TooltipWithPlanProps) => { // TODO: Should we split implementation phase and status? export const ImplementationPhaseTooltipContent = ({ action, - plan, }: TooltipWithPlanProps) => { const { t } = useTranslation(['common', 'actions']); + const { plan, config } = useContext(ActionTableContext); const activePhase = action.implementationPhase; const merged = action.mergedWith; const status = action.statusSummary; + if (!plan) { + return null; + } + const getMergedName = (mergedWith, planId) => { if (mergedWith.plan.id !== planId) { return `${mergedWith.plan.shortName} ${mergedWith.identifier}`; @@ -145,6 +150,7 @@ export const ImplementationPhaseTooltipContent = ({ const statusDisplay = ( {status.label} ); + // If action is merged, display merged status if (merged) { return ( @@ -156,6 +162,7 @@ export const ImplementationPhaseTooltipContent = ({ ); } + // If action has no active phase or it's cancelled, or plan has no implementation phases : display only status if (!activePhase || status?.identifier === 'cancelled') { return statusDisplay; @@ -163,8 +170,12 @@ export const ImplementationPhaseTooltipContent = ({ return (
- {statusDisplay} - + {!config.hasPhaseAndStatusColumns && ( + <> + {statusDisplay} + + + )} {t('actions:action-implementation-phase')}: {plan.actionImplementationPhases.map((phase) => ( diff --git a/components/dashboard/cells/ImplementationPhaseCell.tsx b/components/dashboard/cells/ImplementationPhaseCell.tsx index 28a8578d..d9201145 100644 --- a/components/dashboard/cells/ImplementationPhaseCell.tsx +++ b/components/dashboard/cells/ImplementationPhaseCell.tsx @@ -2,6 +2,8 @@ import { ActionListAction } from '../dashboard.types'; import styled from 'styled-components'; import { PlanContextFragment } from 'common/__generated__/graphql'; import ActionPhase from 'components/actions/ActionPhase'; +import { useContext } from 'react'; +import { ActionTableContext } from '../ActionStatusTable'; interface Props { action: ActionListAction; @@ -13,18 +15,28 @@ const StatusDisplay = styled.div` height: 100%; `; -const ImplementationPhaseCell = ({ action, plan }: Props) => ( - - - -); +const ImplementationPhaseCell = ({ action }: Props) => { + const { plan, config } = useContext(ActionTableContext); + + if (!plan) { + return null; + } + + return ( + + + + ); +}; export default ImplementationPhaseCell;