Skip to content
33 changes: 1 addition & 32 deletions src/components/app-top-bar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,10 @@ import { PARAM_USE_NAME } from '../utils/config-params';
import { useDispatch, useSelector } from 'react-redux';
import PropTypes from 'prop-types';
import AppPackage from '../../package.json';
import { isNodeBuilt, isNodeReadOnly } from './graph/util/model-functions';
import { getServersInfos } from '../services/study';
import { fetchVersion } from '../services/utils';
import { RunButtonContainer } from './run-button-container';
import { useParameterState } from './dialogs/parameters/use-parameters-state';
import StudyNavigationSyncToggle from './study-navigation-sync-toggle';
import { WorkspaceToolbar } from './workspace/core/workspace-toolbar';
import { WorkspaceSwitcher } from './workspace/core/workspace-switcher';

const styles = {
boxContent: (theme) => ({
Expand All @@ -39,23 +35,12 @@ const styles = {
width: '100%',
marginLeft: theme.spacing(1),
}),
runButtonContainer: {
display: 'flex',
alignItems: 'center',
marginRight: 1.5,
},
syncToggleContainer: {
display: 'flex',
alignItems: 'center',
marginRight: 1.5,
},
};

const AppTopBar = ({ userProfile, userManager }) => {
const dispatch = useDispatch();
const theme = useSelector((state) => state[PARAM_THEME]);
const studyUuid = useSelector((state) => state.studyUuid);
const currentNode = useSelector((state) => state.currentTreeNode);
const currentRootNetworkUuid = useSelector((state) => state.currentRootNetworkUuid);

const [appsAndUrls, setAppsAndUrls] = useState([]);
Expand Down Expand Up @@ -97,23 +82,7 @@ const AppTopBar = ({ userProfile, userManager }) => {
>
{userProfile && studyUuid && currentRootNetworkUuid && (
<Box sx={styles.boxContent}>
<Box sx={{ display: 'flex', alignItems: 'center', marginLeft: 1.5, marginRight: 'auto' }}>
<WorkspaceToolbar />
</Box>
<Box sx={{ display: 'flex', alignItems: 'center', marginRight: 1.5, marginLeft: 'auto' }}>
<WorkspaceSwitcher />
</Box>
<Box sx={styles.runButtonContainer}>
<RunButtonContainer
studyUuid={studyUuid}
currentNode={currentNode}
currentRootNetworkUuid={currentRootNetworkUuid}
disabled={!isNodeBuilt(currentNode) || isNodeReadOnly(currentNode)}
/>
</Box>
<Box sx={styles.syncToggleContainer}>
<StudyNavigationSyncToggle />
</Box>
<WorkspaceToolbar />
</Box>
)}
</TopBar>
Expand Down
96 changes: 96 additions & 0 deletions src/components/breadcrumbs/current-selection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/**
* Copyright (c) 2026, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

import { Box, Paper, Tooltip } from '@mui/material';
import { BuildStatusChip, type MuiStyles } from '@gridsuite/commons-ui';
import type { UUID } from 'node:crypto';
import { useIntl } from 'react-intl';
import { useSelector } from 'react-redux';
import { CurrentTreeNode, NodeType } from '../graph/tree-node.type';
import { RootNetworkMetadata } from '../graph/menus/network-modifications/network-modification-menu.type';
import { AppState } from '../../redux/reducer.type';
import { BlockedByActivityIndicator, NodeActivityChip } from 'components/node-activity/node-activity-display';
import { useNodeActivity } from 'components/node-activity/hooks/use-node-activity';
import RootNetworkSelect from './root-network-select';

const styles = {
container: {
display: 'flex',
alignItems: 'center',
borderRadius: '8px',
minHeight: 32,
px: 1,
},
label: (theme) => ({
display: { xs: 'none', lg: 'block' },
mr: 1,
fontSize: theme.typography.fontSize,
}),
rootNetworkSlot: {
display: 'flex',
alignItems: 'center',
mr: 1,
},
nodeLabel: (theme) => ({
maxWidth: 500,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
fontSize: theme.typography.fontSize,
}),
chipSlot: {
display: 'flex',
alignItems: 'center',
ml: 1,
},
blockedSpinner: {
ml: 1,
},
} as const satisfies MuiStyles;

export default function CurrentSelection() {
const intl = useIntl();
const currentNode: CurrentTreeNode | null = useSelector((state: AppState) => state.currentTreeNode);
const currentRootNetworkUuid: UUID | null = useSelector((state: AppState) => state.currentRootNetworkUuid);
const rootNetworks: RootNetworkMetadata[] = useSelector((state: AppState) => state.rootNetworks);
const isRootNode = currentNode?.type === NodeType.ROOT;
const nodeLabel = isRootNode ? intl.formatMessage({ id: 'root' }) : currentNode?.data.label;
const activity = useNodeActivity(currentNode?.id);

return (
<Paper elevation={1} sx={styles.container}>
{rootNetworks.length > 1 && (
<>
<Box sx={styles.label}>{intl.formatMessage({ id: 'root' })}</Box>
<Box sx={styles.rootNetworkSlot}>
<RootNetworkSelect
currentRootNetworkUuid={currentRootNetworkUuid}
rootNetworks={rootNetworks}
/>
</Box>
</>
)}
<Box sx={styles.label}>{intl.formatMessage({ id: 'node' })}</Box>
<Tooltip title={nodeLabel || ''}>
<Box sx={styles.nodeLabel}>{nodeLabel}</Box>
</Tooltip>
<Box sx={styles.chipSlot}>
{activity && <NodeActivityChip activity={activity} />}
{!activity && currentNode && !isRootNode && (
<BuildStatusChip buildStatus={currentNode.data.globalBuildStatus} />
)}
</Box>
<BlockedByActivityIndicator
nodeId={currentNode?.id}
ownActivity={activity}
size={20}
sx={styles.blockedSpinner}
placement="bottom"
/>
</Paper>
);
}
26 changes: 18 additions & 8 deletions src/components/breadcrumbs/root-network-select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

import { Box, ListItemText, MenuItem, Select } from '@mui/material';
import { Box, MenuItem, Select } from '@mui/material';
import type { UUID } from 'node:crypto';
import { RemoveRedEye, VisibilityOff } from '@mui/icons-material';
import { RootNetworkMetadata } from '../graph/menus/network-modifications/network-modification-menu.type';
Expand All @@ -15,12 +15,22 @@ import { mergeSx, type MuiStyles } from '@gridsuite/commons-ui';
const styles = {
selectRoot: (theme) => ({
height: theme.spacing(4),
width: theme.spacing(15),
width: 'fit-content',
paddingTop: theme.spacing(1),
paddingBottom: theme.spacing(1),
'& .MuiOutlinedInput-notchedOutline': { border: 'none' },
'& .MuiSelect-select.MuiSelect-select': { paddingLeft: 0, paddingRight: theme.spacing(3.5) },
}),
selectInput: (theme) => ({
display: 'flex',
gap: 1,
alignItems: 'center',
fontSize: theme.typography.fontSize,
}),
selectItem: (theme) => ({
gap: 1,
fontSize: theme.typography.fontSize,
}),
selectInput: { display: 'flex', gap: 1, alignItems: 'center' },
selectItem: { gap: 1 },
hiddenItem: { display: 'none' },
} as const satisfies MuiStyles;

Expand All @@ -45,8 +55,8 @@ export default function RootNetworkSelect({ currentRootNetworkUuid, rootNetworks
const tag = rootNetworks.find((item) => item.rootNetworkUuid === value)?.tag;
return (
<Box sx={styles.selectInput}>
<RemoveRedEye />
<ListItemText primary={tag} />
{tag}
<RemoveRedEye fontSize="small" />
</Box>
);
}}
Expand All @@ -60,8 +70,8 @@ export default function RootNetworkSelect({ currentRootNetworkUuid, rootNetworks
item.rootNetworkUuid === currentRootNetworkUuid ? styles.hiddenItem : undefined
)}
>
<VisibilityOff />
<ListItemText primary={item.tag} />
{item.tag}
<VisibilityOff fontSize="small" />
</MenuItem>
))}
</Select>
Expand Down
51 changes: 17 additions & 34 deletions src/components/breadcrumbs/study-path-breadcrumbs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,10 @@
*/

import { MoreHoriz } from '@mui/icons-material';
import { Box, Breadcrumbs as MuiBreadcrumbs, Tooltip } from '@mui/material';
import { Box, Breadcrumbs as MuiBreadcrumbs, type Theme, Tooltip, useMediaQuery } from '@mui/material';
import { type MuiStyles } from '@gridsuite/commons-ui';
import { CurrentTreeNode, NodeType } from '../graph/tree-node.type';
import { useSelector } from 'react-redux';
import { AppState } from '../../redux/reducer.type';
import { RootNetworkMetadata } from '../graph/menus/network-modifications/network-modification-menu.type';
import type { UUID } from 'node:crypto';
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
import RootNetworkSelect from './root-network-select';
import { useIntl } from 'react-intl';
import CurrentSelection from './current-selection';

const styles = {
tooltipItem: {
Expand All @@ -29,6 +23,12 @@ const styles = {
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
},
parentDirectoryItem: {
maxWidth: 200,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
},
} as const satisfies MuiStyles;

export interface StudyPathBreadcrumbsProps {
Expand All @@ -40,13 +40,8 @@ export default function StudyPathBreadcrumbs({
studyName,
parentDirectoriesNames,
}: Readonly<StudyPathBreadcrumbsProps>) {
const intl = useIntl();
const currentNode: CurrentTreeNode | null = useSelector((state: AppState) => state.currentTreeNode);
const currentRootNetworkUuid: UUID | null = useSelector((state: AppState) => state.currentRootNetworkUuid);
const rootNetworks: RootNetworkMetadata[] = useSelector((state: AppState) => state.rootNetworks);
const currentRootNetworkTag = rootNetworks.find((item) => item.rootNetworkUuid === currentRootNetworkUuid)?.tag;
const isRootNode = currentNode?.type === NodeType.ROOT;
const nodeLabel = isRootNode ? intl.formatMessage({ id: 'root' }) : currentNode?.data.label;
const nearestParentDirectoryName = parentDirectoriesNames?.at(-1);
const showParentDirectory = useMediaQuery((theme: Theme) => theme.breakpoints.up('md'));

return (
<MuiBreadcrumbs
Expand All @@ -64,17 +59,7 @@ export default function StudyPathBreadcrumbs({
<KeyboardArrowRightIcon fontSize="small" />
</Box>
))}
<Box sx={styles.tooltipItem}>
{studyName}
<KeyboardArrowRightIcon fontSize="small" />
</Box>
<Box sx={styles.tooltipItem}>{nodeLabel}</Box>
{rootNetworks?.length > 1 && (
<Box sx={styles.tooltipItem}>
<KeyboardArrowRightIcon fontSize="small" />
{currentRootNetworkTag}
</Box>
)}
<Box sx={styles.tooltipItem}>{studyName}</Box>
</Box>
}
slotProps={{
Expand All @@ -87,17 +72,15 @@ export default function StudyPathBreadcrumbs({
>
<MoreHoriz sx={{ display: 'flex', alignItems: 'center' }} />
</Tooltip>
{showParentDirectory && nearestParentDirectoryName && (
<Tooltip title={nearestParentDirectoryName}>
<Box sx={styles.parentDirectoryItem}>{nearestParentDirectoryName}</Box>
</Tooltip>
)}
<Tooltip title={studyName || ''}>
<Box sx={styles.breadcrumbItem}>{studyName}</Box>
</Tooltip>
<Tooltip title={nodeLabel || ''}>
<Box sx={styles.breadcrumbItem}>{nodeLabel}</Box>
</Tooltip>
{rootNetworks && rootNetworks.length > 1 && (
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<RootNetworkSelect currentRootNetworkUuid={currentRootNetworkUuid} rootNetworks={rootNetworks} />
</Box>
)}
<CurrentSelection />
</MuiBreadcrumbs>
);
}
Loading
Loading