Skip to content

Commit ce2b7fc

Browse files
MDE/PKFE-32 applied status context to available actions
1 parent d3af32a commit ce2b7fc

File tree

7 files changed

+81
-36
lines changed

7 files changed

+81
-36
lines changed

app/front-end/src/features/editor/components/editorView/editorColumnMenu.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const StyledGridColumnMenuContainer = styled(GridColumnMenuContainer)(({ theme }
1010
}));
1111

1212
interface GridColumnMenuContainerProps extends GridColumnMenuProps {
13+
disabled: boolean;
1314
handleAggregation: (column: string, action: FileContentAggregationActions) => void;
1415
}
1516

@@ -30,6 +31,7 @@ interface GridColumnMenuContainerProps extends GridColumnMenuProps {
3031
* @component
3132
*/
3233
export const EditorColumnMenu: React.FC<GridColumnMenuContainerProps> = ({
34+
disabled,
3335
handleAggregation,
3436
hideMenu,
3537
colDef,
@@ -40,7 +42,7 @@ export const EditorColumnMenu: React.FC<GridColumnMenuContainerProps> = ({
4042
? fileContent.aggregations[colDef.field].action
4143
: FileContentAggregationActions.NONE;
4244

43-
return (
45+
return !disabled ? (
4446
<StyledGridColumnMenuContainer hideMenu={hideMenu} colDef={colDef} {...other}>
4547
<EditorColumnMenuAggregationItem
4648
initialValue={aggregationActiveAction}
@@ -50,5 +52,5 @@ export const EditorColumnMenu: React.FC<GridColumnMenuContainerProps> = ({
5052
<Divider />
5153
<GridColumnMenuHideItem onClick={hideMenu} colDef={colDef!} />
5254
</StyledGridColumnMenuContainer>
53-
);
55+
) : null;
5456
};

app/front-end/src/features/editor/components/editorView/editorToolbar.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { useStatusContext } from '@/hooks';
12
import { socket } from '@/lib';
23
import { Events } from '@/types';
34
import { Done as DoneIcon, Error as ErrorIcon } from '@mui/icons-material';
@@ -12,7 +13,6 @@ import {
1213
import { useEffect, useState } from 'react';
1314

1415
interface EditorToolbarProps extends GridToolbarProps, ToolbarPropsOverrides {
15-
disabled?: boolean;
1616
handleSave: () => void;
1717
}
1818

@@ -47,11 +47,12 @@ interface EditorToolbarProps extends GridToolbarProps, ToolbarPropsOverrides {
4747
*
4848
* @returns {JSX.Element} The rendered toolbar component with buttons for DataGrid actions and a save button with status feedback.
4949
*/
50-
export const EditorToolbar: React.FC<EditorToolbarProps> = ({ disabled, handleSave }) => {
50+
export const EditorToolbar: React.FC<EditorToolbarProps> = ({ handleSave }) => {
5151
const [isSaving, setIsSaving] = useState(false);
5252
const [saveStatus, setSaveStatus] = useState(true);
5353

5454
const Theme = useTheme();
55+
const { blocked } = useStatusContext();
5556

5657
useEffect(() => {
5758
const handleWorkspaceFileSaveFeedback = (data: { status: 'success' | 'error' }) => {
@@ -63,7 +64,7 @@ export const EditorToolbar: React.FC<EditorToolbarProps> = ({ disabled, handleSa
6364
return () => {
6465
socket.off(Events.WORKSPACE_FILE_SAVE_FEEDBACK_EVENT);
6566
};
66-
});
67+
}, []);
6768

6869
return (
6970
<GridToolbarContainer>
@@ -77,7 +78,7 @@ export const EditorToolbar: React.FC<EditorToolbarProps> = ({ disabled, handleSa
7778
setIsSaving(true);
7879
handleSave();
7980
}}
80-
disabled={disabled || isSaving}
81+
disabled={blocked}
8182
startIcon={
8283
isSaving ? (
8384
<CircularProgress size={16} sx={{ color: Theme.palette.primary.main }} />

app/front-end/src/features/editor/components/editorView/editorView.tsx

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { EditorColumnMenu, EditorHeader, EditorToolbar } from '@/features/editor/components/editorView';
22
import { useWorkspaceContext } from '@/features/editor/hooks';
33
import { FileContentAggregationActions, FileDataRequestDTO, FileDataResponseDTO } from '@/features/editor/types';
4-
import { useSessionContext } from '@/hooks';
4+
import { useSessionContext, useStatusContext } from '@/hooks';
55
import { axios } from '@/lib';
66
import { Endpoints } from '@/types';
7-
import { DataGrid, useGridApiRef } from '@mui/x-data-grid';
7+
import { DataGrid, GridPagination, useGridApiRef } from '@mui/x-data-grid';
88
import { useCallback, useEffect, useState } from 'react';
99

1010
/**
@@ -56,10 +56,13 @@ export const EditorView: React.FC = () => {
5656
});
5757

5858
const { connected } = useSessionContext();
59-
const { file, fileContent, filePagination, fileStateReset, fileStateUpdate } = useWorkspaceContext();
59+
const { file, fileContent, filePagination, fileStateUpdate } = useWorkspaceContext();
60+
const { blocked, blockedStateUpdate } = useStatusContext();
6061
const ref = useGridApiRef();
6162

6263
const handleSave = async () => {
64+
blockedStateUpdate(true);
65+
6366
const data: FileDataRequestDTO = {
6467
page: filePagination.page,
6568
rowsPerPage: filePagination.rowsPerPage,
@@ -83,6 +86,8 @@ export const EditorView: React.FC = () => {
8386
fileStateUpdate(undefined, { ...fileContent, aggregations: responseColumnsAggregation }, undefined);
8487
} catch (error) {
8588
console.error('Failed to save file content:', error);
89+
} finally {
90+
blockedStateUpdate(false);
8691
}
8792
};
8893

@@ -94,20 +99,27 @@ export const EditorView: React.FC = () => {
9499
break;
95100
default:
96101
{
97-
const response = await axios.get(`${Endpoints.WORKSPACE_AGGREGATE}/${file.id}`, {
98-
params: {
99-
field: column,
100-
action: action,
101-
},
102-
});
103-
104-
const { field: responseField, action: responseAction, value: responseValue } = response.data;
105-
106-
const newAggregations = {
107-
...fileContent.aggregations,
108-
[responseField]: { action: responseAction, value: responseValue },
109-
};
110-
fileStateUpdate(undefined, { ...fileContent, aggregations: newAggregations }, undefined);
102+
blockedStateUpdate(true);
103+
try {
104+
const response = await axios.get(`${Endpoints.WORKSPACE_AGGREGATE}/${file.id}`, {
105+
params: {
106+
field: column,
107+
action: action,
108+
},
109+
});
110+
111+
const { field: responseField, action: responseAction, value: responseValue } = response.data;
112+
113+
const newAggregations = {
114+
...fileContent.aggregations,
115+
[responseField]: { action: responseAction, value: responseValue },
116+
};
117+
fileStateUpdate(undefined, { ...fileContent, aggregations: newAggregations }, undefined);
118+
} catch (error) {
119+
console.error('Failed to fetch aggregation data:', error);
120+
} finally {
121+
blockedStateUpdate(false);
122+
}
111123
}
112124
break;
113125
}
@@ -119,7 +131,7 @@ export const EditorView: React.FC = () => {
119131
return;
120132
}
121133

122-
setIsLoading(true);
134+
blockedStateUpdate(true);
123135

124136
try {
125137
const response = await axios.get<FileDataResponseDTO>(`${Endpoints.WORKSPACE_FILE}/${file.id}`, {
@@ -134,6 +146,7 @@ export const EditorView: React.FC = () => {
134146
console.error('Failed to fetch file content:', error);
135147
} finally {
136148
setIsLoading(false);
149+
blockedStateUpdate(false);
137150
}
138151
}, [file.id, filePagination.page, filePagination.rowsPerPage]);
139152

@@ -186,7 +199,7 @@ export const EditorView: React.FC = () => {
186199
return (
187200
<DataGrid
188201
sx={{ height: '100%', border: 'none' }}
189-
loading={isLoading}
202+
loading={blocked || isLoading}
190203
rows={fileContent.rows}
191204
columns={fileContent.columns}
192205
pagination
@@ -198,6 +211,7 @@ export const EditorView: React.FC = () => {
198211
paginationModel: { pageSize: filePagination.rowsPerPage, page: filePagination.page },
199212
},
200213
}}
214+
disableColumnMenu={blocked}
201215
pageSizeOptions={[25, 50, 100]}
202216
onPaginationModelChange={(model) => {
203217
fileStateUpdate(undefined, undefined, {
@@ -207,8 +221,9 @@ export const EditorView: React.FC = () => {
207221
});
208222
}}
209223
slots={{
210-
toolbar: (props) => <EditorToolbar {...props} disabled={isLoading} handleSave={handleSave} />,
211-
columnMenu: (props) => <EditorColumnMenu {...props} handleAggregation={handleAggregation} />,
224+
toolbar: (props) => <EditorToolbar {...props} disabled={blocked || !file.id} handleSave={handleSave} />,
225+
columnMenu: (props) => <EditorColumnMenu {...props} disabled={blocked} handleAggregation={handleAggregation} />,
226+
pagination: (props) => <GridPagination disabled={blocked} {...props} />,
212227
}}
213228
slotProps={{
214229
toolbar: {},

app/front-end/src/features/editor/components/fileTreeView/fileTreeItem/fileTreeItem.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { FileTreeItemContextMenu, FileTreeItemLabel } from '@/features/editor/co
22
import { useWorkspaceContext } from '@/features/editor/hooks';
33
import { FileTypes } from '@/features/editor/types';
44
import { getIconFromFileType, isExpandable } from '@/features/editor/utils';
5+
import { useStatusContext } from '@/hooks';
56
import { FolderRounded as FolderRoundedIcon } from '@mui/icons-material';
67
import Collapse from '@mui/material/Collapse';
78
import { alpha, styled } from '@mui/material/styles';
@@ -136,6 +137,7 @@ export const FileTreeItem = React.forwardRef(function CustomTreeItem(
136137
}
137138

138139
const { fileStateUpdate, filesHistoryStateUpdate } = useWorkspaceContext();
140+
const { blocked } = useStatusContext();
139141
const [contextMenu, setContextMenu] = useState<(EventTarget & HTMLDivElement) | null>(null);
140142
const [contextMenuPosition, setContextMenuPosition] = useState<{ top: number; left: number }>({
141143
top: 0,
@@ -170,10 +172,15 @@ export const FileTreeItem = React.forwardRef(function CustomTreeItem(
170172
<StyledFileTreeItemContent
171173
{...getContentProps({
172174
onClick: (event) => {
173-
if (getContentProps().onClick) getContentProps().onClick(event);
174-
handleClick(item.id, item.label, item.fileType);
175+
if (!blocked) {
176+
if (getContentProps().onClick) getContentProps().onClick(event);
177+
handleClick(item.id, item.label, item.fileType);
178+
}
179+
},
180+
181+
onContextMenu: (event) => {
182+
if (!blocked) handleOpenContextMenu(event);
175183
},
176-
onContextMenu: (event) => handleOpenContextMenu(event),
177184
className: clsx('content', {
178185
'Mui-expanded': status.expanded,
179186
'Mui-selected': status.selected,

app/front-end/src/features/editor/components/fileTreeView/fileTreeView.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { FileTreeItem, FileTreeItemContextMenu } from '@/features/editor/components/fileTreeView/fileTreeItem';
22
import { useWorkspaceContext } from '@/features/editor/hooks';
3+
import { useStatusContext } from '@/hooks';
34
import { Box, Button, LinearProgress } from '@mui/material';
45
import { RichTreeView } from '@mui/x-tree-view/RichTreeView';
56
import { useState } from 'react';
@@ -43,6 +44,7 @@ export const FileTreeView: React.FC = () => {
4344
});
4445

4546
const { fileTree, fileTreeIsLoading } = useWorkspaceContext();
47+
const { blocked } = useStatusContext();
4648

4749
const handleOpenContextMenu = (event: React.MouseEvent<HTMLButtonElement>) => {
4850
event.stopPropagation();
@@ -67,7 +69,12 @@ export const FileTreeView: React.FC = () => {
6769
</Box>
6870
) : (
6971
<>
70-
<Button variant='outlined' onClick={(event) => handleOpenContextMenu(event)} sx={{ mb: '1.5rem' }}>
72+
<Button
73+
variant='outlined'
74+
disabled={blocked}
75+
onClick={(event) => handleOpenContextMenu(event)}
76+
sx={{ mb: '1.5rem' }}
77+
>
7178
New
7279
</Button>
7380
<FileTreeItemContextMenu

app/front-end/src/features/editor/components/filebarView/filebarGroupItem.tsx

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { useWorkspaceContext } from '@/features/editor/hooks';
22
import { FileModel } from '@/features/editor/types';
3+
import { useStatusContext } from '@/hooks';
34
import { Close as CloseIcon } from '@mui/icons-material';
45
import { alpha, Box, IconButton, Typography, useTheme } from '@mui/material';
56

@@ -25,6 +26,7 @@ import { alpha, Box, IconButton, Typography, useTheme } from '@mui/material';
2526
export const FilebarGroupItem: React.FC<FileModel> = (file) => {
2627
const Theme = useTheme();
2728
const Workspace = useWorkspaceContext();
29+
const { blocked } = useStatusContext();
2830

2931
const { id, label } = file;
3032

@@ -39,18 +41,24 @@ export const FilebarGroupItem: React.FC<FileModel> = (file) => {
3941
borderRadius: '0rem',
4042
':hover': {
4143
backgroundColor:
42-
Workspace.file.id === id ? Theme.palette.background.default : alpha(Theme.palette.background.default, 0.5),
44+
Workspace.file.id === id
45+
? Theme.palette.background.default
46+
: blocked
47+
? Theme.palette.action.selected
48+
: alpha(Theme.palette.background.default, 0.5),
4349
},
44-
cursor: 'pointer',
50+
cursor: blocked ? 'default' : 'pointer',
4551
display: 'flex',
4652
flexDirection: 'row',
4753
alignItems: 'center',
4854
gap: '0.5rem',
4955
}}
5056
onClick={() => {
5157
// Update the workspace to the selected file
52-
Workspace.fileStateUpdate(file);
53-
Workspace.filesHistoryStateUpdate(file);
58+
if (!blocked) {
59+
Workspace.fileStateUpdate(file);
60+
Workspace.filesHistoryStateUpdate(file);
61+
}
5462
}}
5563
>
5664
<Typography
@@ -68,6 +76,7 @@ export const FilebarGroupItem: React.FC<FileModel> = (file) => {
6876
</Typography>
6977
<IconButton
7078
size='small'
79+
disabled={blocked}
7180
onClick={(event) => {
7281
event.stopPropagation();
7382
}}

app/front-end/src/features/editor/stores/workspaceContextProvider.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { FileContentModel, FileModel, FilePaginationModel, FileTypes } from '@/features/editor/types';
2-
import { useSessionContext } from '@/hooks';
2+
import { useSessionContext, useStatusContext } from '@/hooks';
33
import { axios, socket } from '@/lib';
44
import { Endpoints, Events } from '@/types';
55
import { TreeViewBaseItem } from '@mui/x-tree-view';
@@ -149,15 +149,19 @@ export const WorkspaceContextProvider: React.FC<Props> = ({ children }) => {
149149
const [fileTreeIsLoading, setFileTreeIsLoading] = useState(true);
150150
const [fileTree, setFileTree] = useState<TreeViewBaseItem<FileModel>[]>([]);
151151

152+
const { blockedStateUpdate } = useStatusContext();
153+
152154
const getWorkspace = useCallback(async () => {
153155
setFileTreeIsLoading(true);
156+
blockedStateUpdate(true);
154157
try {
155158
const response = await axios.get(Endpoints.WORKSPACE);
156159
setFileTree(response.data);
157160
} catch (error) {
158161
console.error('Failed to fetch workspace data:', error);
159162
} finally {
160163
setFileTreeIsLoading(false);
164+
blockedStateUpdate(false);
161165
}
162166
}, []);
163167

0 commit comments

Comments
 (0)