From 823127bc1a6583888b11d659d84ad9e7e0e53caa Mon Sep 17 00:00:00 2001 From: Stephen Smith Date: Thu, 8 Feb 2024 10:20:01 -0500 Subject: [PATCH] 21225: Add mutually exclusive tabs to multi panel view, use for project tabs Arvados-DCO-1.1-Signed-off-by: Stephen Smith --- .../multi-panel-view/multi-panel-view.tsx | 93 +++++++++++++------ .../src/views/project-panel/project-panel.tsx | 46 +++++++-- 2 files changed, 103 insertions(+), 36 deletions(-) diff --git a/services/workbench2/src/components/multi-panel-view/multi-panel-view.tsx b/services/workbench2/src/components/multi-panel-view/multi-panel-view.tsx index 7e0ca8fd1f..72903d7ef5 100644 --- a/services/workbench2/src/components/multi-panel-view/multi-panel-view.tsx +++ b/services/workbench2/src/components/multi-panel-view/multi-panel-view.tsx @@ -8,6 +8,8 @@ import { Grid, Paper, StyleRulesCallback, + Tab, + Tabs, Tooltip, withStyles, WithStyles @@ -19,7 +21,7 @@ import { InfoIcon } from 'components/icon/icon'; import { ReactNodeArray } from 'prop-types'; import classNames from 'classnames'; -type CssRules = 'root' | 'button' | 'buttonIcon' | 'content'; +type CssRules = 'root' | 'button' | 'buttonIcon' | 'content' | 'tabsWrapper' | 'tabsRoot' | 'tabs'; const styles: StyleRulesCallback = theme => ({ root: { @@ -37,6 +39,17 @@ const styles: StyleRulesCallback = theme => ({ content: { overflow: 'auto', }, + tabsWrapper: { + width: '100%', + }, + tabsRoot: { + flexGrow: 1, + }, + tabs: { + flexGrow: 1, + flexShrink: 1, + maxWidth: 'initial', + }, }); interface MPVHideablePanelDataProps { @@ -114,6 +127,7 @@ export interface MPVPanelState { } interface MPVContainerDataProps { panelStates?: MPVPanelState[]; + mutuallyExclusive?: boolean; } type MPVContainerProps = MPVContainerDataProps & GridProps; @@ -131,44 +145,56 @@ const MPVContainerComponent = ({ children, panelStates, classes, ...props }: MPV const [panelVisibility, setPanelVisibility] = useState(initialVisibility); const [previousPanelVisibility, setPreviousPanelVisibility] = useState(initialVisibility); const [highlightedPanel, setHighlightedPanel] = useState(-1); + const currentSelectedPanel = panelVisibility.findIndex(Boolean); const [selectedPanel, setSelectedPanel] = useState(-1); const panelRef = useRef(null); let panels: JSX.Element[] = []; let buttons: JSX.Element[] = []; + let tabs: JSX.Element[] = []; + let buttonBar: JSX.Element = <>; if (isArray(children)) { - for (let idx = 0; idx < children.length; idx++) { - const showFn = (idx: number) => () => { - setPreviousPanelVisibility(initialVisibility); + const showFn = (idx: number) => () => { + setPreviousPanelVisibility(initialVisibility); + if (props.mutuallyExclusive) { + // Hide all other panels setPanelVisibility([ - ...panelVisibility.slice(0, idx), + ...(new Array(idx).fill(false)), true, - ...panelVisibility.slice(idx + 1) + ...(new Array(panelVisibility.length-(idx+1)).fill(false)), ]); - setSelectedPanel(idx); - }; - const hideFn = (idx: number) => () => { - setPreviousPanelVisibility(initialVisibility); + } else { setPanelVisibility([ ...panelVisibility.slice(0, idx), - false, - ...panelVisibility.slice(idx + 1) - ]) - }; - const maximizeFn = (idx: number) => () => { - setPreviousPanelVisibility(panelVisibility); - // Maximize X == hide all but X - setPanelVisibility([ - ...panelVisibility.slice(0, idx).map(() => false), true, - ...panelVisibility.slice(idx + 1).map(() => false), + ...panelVisibility.slice(idx + 1) ]); - }; - const unMaximizeFn = (idx: number) => () => { - setPanelVisibility(previousPanelVisibility); - setSelectedPanel(idx); } + setSelectedPanel(idx); + }; + const hideFn = (idx: number) => () => { + setPreviousPanelVisibility(initialVisibility); + setPanelVisibility([ + ...panelVisibility.slice(0, idx), + false, + ...panelVisibility.slice(idx+1) + ]) + }; + const maximizeFn = (idx: number) => () => { + setPreviousPanelVisibility(panelVisibility); + // Maximize X == hide all but X + setPanelVisibility([ + ...panelVisibility.slice(0, idx).map(() => false), + true, + ...panelVisibility.slice(idx+1).map(() => false), + ]); + }; + const unMaximizeFn = (idx: number) => () => { + setPanelVisibility(previousPanelVisibility); + setSelectedPanel(idx); + } + for (let idx = 0; idx < children.length; idx++) { const panelName = panelStates === undefined ? `Panel ${idx + 1}` : (panelStates[idx] && panelStates[idx].name) || `Panel ${idx + 1}`; @@ -198,6 +224,11 @@ const MPVContainerComponent = ({ children, panelStates, classes, ...props }: MPV ]; + tabs = [ + ...tabs, + <>{panelName} + ]; + const aPanel = ; panels = [...panels, aPanel]; }; + + buttonBar = props.mutuallyExclusive ? + + showFn(val)()}> + {tabs.map((tgl, idx) => )} + + : + <> + {buttons.map((tgl, idx) => {tgl})} + ; }; - return + return - {buttons.map((tgl, idx) => {tgl})} + {buttonBar} setSelectedPanel(-1)}> diff --git a/services/workbench2/src/views/project-panel/project-panel.tsx b/services/workbench2/src/views/project-panel/project-panel.tsx index 5e10d022cd..3d64f6517a 100644 --- a/services/workbench2/src/views/project-panel/project-panel.tsx +++ b/services/workbench2/src/views/project-panel/project-panel.tsx @@ -53,9 +53,10 @@ import { resourceIsFrozen } from 'common/frozen-resources'; import { ProjectResource } from 'models/project'; import { deselectAllOthers, toggleOne } from 'store/multiselect/multiselect-actions'; import { DetailsCardRoot } from 'views-components/details-card/details-card-root'; +import { MPVContainer, MPVPanelContent, MPVPanelState } from 'components/multi-panel-view/multi-panel-view'; import { PROJECT_PANEL_ID } from 'store/project-panel/project-panel-action-bind'; -type CssRules = 'root' | 'button' ; +type CssRules = 'root' | 'button' | 'mpvRoot' | 'dataExplorer'; const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ root: { @@ -66,6 +67,12 @@ const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ button: { marginLeft: theme.spacing.unit, }, + mpvRoot: { + flexGrow: 1, + }, + dataExplorer: { + height: "100%", + }, }); export enum ProjectPanelColumnNames { @@ -238,6 +245,10 @@ export const projectPanelColumns: DataColumns = [ const DEFAULT_VIEW_MESSAGES = ['Your project is empty.', 'Please create a project or create a collection and upload a data.']; +const panelsData: MPVPanelState[] = [ + { name: "Subprojects", visible: true }, +]; + interface ProjectPanelDataProps { currentItemId: string; resources: ResourcesState; @@ -269,15 +280,30 @@ export const ProjectPanel = withStyles(styles)( const { classes } = this.props; return
- + + + + +
} -- 2.30.2