Skip to content

Commit

Permalink
MDE/PKFE-44 initial commit for sorting
Browse files Browse the repository at this point in the history
  • Loading branch information
mantvydasdeltuva committed Sep 23, 2024
1 parent f492789 commit 7e92594
Show file tree
Hide file tree
Showing 13 changed files with 530 additions and 34 deletions.
332 changes: 324 additions & 8 deletions app/back-end/src/routes/workspace_route.py

Large diffs are not rendered by default.

35 changes: 31 additions & 4 deletions app/back-end/src/utils/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def socketio_emit_to_user_session(event, data, uuid, sid):
)


def build_workspace_structure(path, user_workspace_dir):
def build_workspace_structure(path: str, user_workspace_dir):
"""
Recursively build the directory structure for the workspace.
Expand All @@ -92,17 +92,36 @@ def build_workspace_structure(path, user_workspace_dir):
- "children" (list): # A list of child items, which is empty for files and populated
with nested dictionaries for directories.
"""
file_type = (
"folder"
if os.path.isdir(path)
else (
"txt" if path.endswith(".txt") else ("csv" if path.endswith(".csv") else "unsupported")
)
)

if file_type == "unsupported":
return None

workspace_structure = {
"id": os.path.relpath(path, user_workspace_dir),
"label": os.path.basename(path),
"fileType": "folder" if os.path.isdir(path) else "csv",
"fileType": file_type,
"children": [],
}

if os.path.isdir(path):
if file_type == "folder":
workspace_structure["children"] = [
build_workspace_structure(os.path.join(path, child), user_workspace_dir)
# build_workspace_structure(os.path.join(path, child), user_workspace_dir)
# for child in os.listdir(path)
child_structure
for child in os.listdir(path)
if (
child_structure := build_workspace_structure(
os.path.join(path, child), user_workspace_dir
)
)
is not None
]

return workspace_structure
Expand All @@ -126,3 +145,11 @@ def is_number(value):
return True
except ValueError:
return False


def convert_to_number(value):
"""Helper function to convert a value to float if possible, otherwise return the original value."""
try:
return float(value)
except ValueError:
return value
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { EditorColumnMenuAggregationItem } from '@/features/editor/components/editorView';
import { EditorColumnMenuAggregationItem, EditorColumnMenuSortItem } from '@/features/editor/components/editorView';
import { useWorkspaceContext } from '@/features/editor/hooks';
import { FileContentAggregationActions } from '@/features/editor/types';
import { FileContentAggregationActions, SortEnum } from '@/features/editor/types';
import { Divider } from '@mui/material';
import { styled } from '@mui/material/styles';
import { GridColumnMenuContainer, GridColumnMenuHideItem, GridColumnMenuProps } from '@mui/x-data-grid';
Expand All @@ -12,6 +12,7 @@ const StyledGridColumnMenuContainer = styled(GridColumnMenuContainer)(({ theme }
interface GridColumnMenuContainerProps extends GridColumnMenuProps {
disabled: boolean;
handleAggregation: (column: string, action: FileContentAggregationActions) => void;
handleSort: (column: string, sort: SortEnum) => void;
}

/**
Expand All @@ -33,6 +34,7 @@ interface GridColumnMenuContainerProps extends GridColumnMenuProps {
export const EditorColumnMenu: React.FC<GridColumnMenuContainerProps> = ({
disabled,
handleAggregation,
handleSort,
hideMenu,
colDef,
...other
Expand All @@ -44,6 +46,11 @@ export const EditorColumnMenu: React.FC<GridColumnMenuContainerProps> = ({

return !disabled ? (
<StyledGridColumnMenuContainer hideMenu={hideMenu} colDef={colDef} {...other}>
<EditorColumnMenuSortItem
onClick={hideMenu}
onSort={(sort: SortEnum) => handleSort(colDef.field, sort)}
></EditorColumnMenuSortItem>
<Divider />
<EditorColumnMenuAggregationItem
initialValue={aggregationActiveAction}
onClick={hideMenu}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { SortEnum } from '@/features/editor/types';
import {
ArrowDownward as ArrowDownwardIcon,
ArrowUpward as ArrowUpwardIcon,
Remove as RemoveIcon,
} from '@mui/icons-material';
import { Box, Button, Typography, useTheme } from '@mui/material';
import { MouseEvent as MouseEventReact } from 'react';

export interface EditorColumnMenuSortItemProps {
onClick: (event: MouseEventReact<HTMLButtonElement, MouseEvent>) => void;
onSort: (sort: SortEnum) => void;
}

export const EditorColumnMenuSortItem: React.FC<EditorColumnMenuSortItemProps> = ({ onClick, onSort }) => {
const Theme = useTheme();

const handleClick = (event: MouseEventReact<HTMLButtonElement, MouseEvent>, sort: SortEnum) => {
onClick(event);
switch (sort) {
case SortEnum.ASC:
onSort(SortEnum.ASC);
break;
case SortEnum.DESC:
onSort(SortEnum.DESC);
break;
default:
onSort(SortEnum.NONE);
}
};

return (
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
<Button
onClick={(event) => handleClick(event, SortEnum.ASC)}
sx={{ justifyContent: 'left', px: '0.85rem', borderRadius: '0' }}
>
<Box sx={{ display: 'flex', flexDirection: 'row', gap: '1rem', alignItems: 'center' }}>
<ArrowUpwardIcon sx={{ color: Theme.palette.text.secondary }} />
<Typography>Sort ASC</Typography>
</Box>
</Button>
<Button
onClick={(event) => handleClick(event, SortEnum.DESC)}
sx={{ justifyContent: 'left', px: '0.85rem', borderRadius: '0' }}
>
<Box sx={{ display: 'flex', flexDirection: 'row', gap: '1rem', alignItems: 'center' }}>
<ArrowDownwardIcon sx={{ color: Theme.palette.text.secondary }} />
<Typography>Sort DESC</Typography>
</Box>
</Button>
<Button
onClick={(event) => handleClick(event, SortEnum.NONE)}
sx={{ justifyContent: 'left', px: '0.85rem', borderRadius: '0' }}
>
<Box sx={{ display: 'flex', flexDirection: 'row', gap: '1rem', alignItems: 'center' }}>
<RemoveIcon sx={{ color: Theme.palette.text.secondary }} />
<Typography>Unsort</Typography>
</Box>
</Button>
</Box>
);
};
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { FileContentAggregationModel } from '@/features/editor/types';
import { FileContentAggregationModel, FileContentSortModel, SortEnum } from '@/features/editor/types';
import { ArrowDownward as ArrowDownwardIcon, ArrowUpward as ArrowUpwardIcon } from '@mui/icons-material';
import { Box, Typography, useTheme } from '@mui/material';
import React from 'react';

export interface EditorHeaderProps {
columnName: string;
gridColumnsAggregation: FileContentAggregationModel;
gridColumnsSort: FileContentSortModel;
}

/**
Expand All @@ -20,11 +22,15 @@ export interface EditorHeaderProps {
*
* @component
*/
export const EditorHeader: React.ElementType<EditorHeaderProps> = ({ columnName, gridColumnsAggregation }) => {
export const EditorHeader: React.ElementType<EditorHeaderProps> = ({
columnName,
gridColumnsAggregation,
gridColumnsSort,
}) => {
const Theme = useTheme();

if (!gridColumnsAggregation[columnName])
return <Typography sx={{ fontSize: '0.875rem', fontWeight: 'bold' }}>{columnName}</Typography>;
// if (!gridColumnsAggregation[columnName])
// return <Typography sx={{ fontSize: '0.875rem', fontWeight: 'bold' }}>{columnName}</Typography>;

return (
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
Expand All @@ -36,12 +42,27 @@ export const EditorHeader: React.ElementType<EditorHeaderProps> = ({ columnName,
color: Theme.palette.primary.main,
}}
>
{gridColumnsAggregation[columnName].action.toUpperCase()}
{gridColumnsAggregation[columnName]?.action.toUpperCase()}
</Typography>
<Typography sx={{ fontSize: '0.875rem', fontWeight: 'bold' }}>{columnName}</Typography>
{gridColumnsSort[columnName] === SortEnum.ASC ? (
<ArrowUpwardIcon
sx={{
fontSize: '1.25rem',
color: Theme.palette.primary.main,
}}
/>
) : gridColumnsSort[columnName] === SortEnum.DESC ? (
<ArrowDownwardIcon
sx={{
fontSize: '1.25rem',
color: Theme.palette.primary.main,
}}
/>
) : null}
</Box>
<Typography sx={{ fontSize: '0.75rem', fontWeight: 'bold', color: Theme.palette.primary.main }}>
{gridColumnsAggregation[columnName].value}
{gridColumnsAggregation[columnName]?.value}
</Typography>
</Box>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { EditorColumnMenu, EditorHeader, EditorToolbar } from '@/features/editor/components/editorView';
import { useWorkspaceContext } from '@/features/editor/hooks';
import { FileContentAggregationActions, FileDataRequestDTO, FileDataResponseDTO } from '@/features/editor/types';
import {
FileContentAggregationActions,
FileDataRequestDTO,
FileDataResponseDTO,
SortEnum,
} from '@/features/editor/types';
import { useSessionContext, useStatusContext } from '@/hooks';
import { axios } from '@/lib';
import { Endpoints } from '@/types';
Expand Down Expand Up @@ -73,8 +78,13 @@ export const EditorView: React.FC = () => {
};

try {
const fileContentResponse = await axios.put<FileDataResponseDTO>(`${Endpoints.WORKSPACE_FILE}/${file.id}`, data);
setFileContentResponse(fileContentResponse.data);
await axios.put<FileDataResponseDTO>(`${Endpoints.WORKSPACE_FILE}/${file.id}`, data, {
params: {
sorts: JSON.stringify(fileContent.sorts),
},
});

await getWorkspaceFile();

const responseAggregate = await axios.get(`${Endpoints.WORKSPACE_AGGREGATE}/all/${file.id}`, {
params: {
Expand Down Expand Up @@ -125,6 +135,16 @@ export const EditorView: React.FC = () => {
}
};

const handleSort = async (column: string, sort: SortEnum) => {
if (sort === SortEnum.NONE) {
console.log('Unsort column:', column);
fileStateUpdate(undefined, { ...fileContent, sorts: {} }, undefined);
return;
}

fileStateUpdate(undefined, { ...fileContent, sorts: { [column]: sort } }, undefined);
};

const getWorkspaceFile = useCallback(async () => {
if (!file.id) {
setFileContentResponse({ totalRows: 0, header: [], rows: [], page: 0 });
Expand All @@ -138,6 +158,7 @@ export const EditorView: React.FC = () => {
params: {
page: filePagination.page,
rowsPerPage: filePagination.rowsPerPage,
sorts: JSON.stringify(fileContent.sorts),
},
});

Expand All @@ -148,7 +169,7 @@ export const EditorView: React.FC = () => {
setIsLoading(false);
blockedStateUpdate(false);
}
}, [file.id, filePagination.page, filePagination.rowsPerPage]);
}, [filePagination.page, filePagination.rowsPerPage, fileContent.sorts]);

// File content fetching effect
useEffect(() => {
Expand All @@ -157,15 +178,23 @@ export const EditorView: React.FC = () => {

// Aggregation reset effect
useEffect(() => {
fileStateUpdate(undefined, { columns: fileContent.columns, rows: fileContent.rows, aggregations: {} }, undefined);
fileStateUpdate(
undefined,
{ columns: fileContent.columns, rows: fileContent.rows, aggregations: {}, sorts: {} },
undefined
);
}, [file.id]);

// Parse file content response effect
useEffect(() => {
const { totalRows, header, rows } = fileContentResponse;

if (!header) {
fileStateUpdate(undefined, { columns: [], rows: [], aggregations: fileContent.aggregations }, undefined);
fileStateUpdate(
undefined,
{ columns: [], rows: [], aggregations: fileContent.aggregations, sorts: fileContent.sorts },
undefined
);
return;
}

Expand All @@ -176,7 +205,13 @@ export const EditorView: React.FC = () => {
flex: 1,
minWidth: 150,
editable: true,
renderHeader: () => <EditorHeader columnName={value} gridColumnsAggregation={fileContent.aggregations} />,
renderHeader: () => (
<EditorHeader
columnName={value}
gridColumnsAggregation={fileContent.aggregations}
gridColumnsSort={fileContent.sorts}
/>
),
};
});

Expand All @@ -191,10 +226,10 @@ export const EditorView: React.FC = () => {

fileStateUpdate(
undefined,
{ columns: parsedColumns, rows: parsedRows, aggregations: fileContent.aggregations },
{ columns: parsedColumns, rows: parsedRows, aggregations: fileContent.aggregations, sorts: fileContent.sorts },
{ page: filePagination.page, rowsPerPage: filePagination.rowsPerPage, totalRows: totalRows }
);
}, [fileContentResponse, fileContent.aggregations]);
}, [fileContentResponse, fileContent.aggregations, fileContent.sorts]);

return (
<DataGrid
Expand Down Expand Up @@ -222,7 +257,14 @@ export const EditorView: React.FC = () => {
}}
slots={{
toolbar: (props) => <EditorToolbar {...props} disabled={blocked || !file.id} handleSave={handleSave} />,
columnMenu: (props) => <EditorColumnMenu {...props} disabled={blocked} handleAggregation={handleAggregation} />,
columnMenu: (props) => (
<EditorColumnMenu
{...props}
disabled={blocked}
handleAggregation={handleAggregation}
handleSort={handleSort}
/>
),
pagination: (props) => <GridPagination disabled={blocked} {...props} />,
}}
slotProps={{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export { EditorColumnMenu } from './editorColumnMenu';
export { EditorColumnMenuAggregationItem } from './editorColumnMenuAggregationItem';
export type { EditorColumnMenuAggregationItemProps } from './editorColumnMenuAggregationItem';
export { EditorColumnMenuSortItem } from './editorColumnMenuSortItem';
export type { EditorColumnMenuSortItemProps } from './editorColumnMenuSortItem';
export { EditorHeader } from './editorHeader';
export type { EditorHeaderProps } from './editorHeader';
export { EditorToolbar } from './editorToolbar';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export interface WorkspaceContextProps {
export const WorkspaceContext = createContext<WorkspaceContextProps>({
// File state defaults
file: { id: '', label: '', type: FileTypes.FOLDER },
fileContent: { columns: [], rows: [], aggregations: {} },
fileContent: { columns: [], rows: [], aggregations: {}, sorts: {} },
filePagination: { page: 0, rowsPerPage: 100, totalRows: 0 },
fileStateReset: () => {},
fileStateUpdate: () => {},
Expand Down Expand Up @@ -91,7 +91,12 @@ export const WorkspaceContextProvider: React.FC<Props> = ({ children }) => {

// File state
const [file, setFile] = useState<FileModel>({ id: '', label: '', type: FileTypes.FOLDER });
const [fileContent, setFileContent] = useState<FileContentModel>({ columns: [], rows: [], aggregations: {} });
const [fileContent, setFileContent] = useState<FileContentModel>({
columns: [],
rows: [],
aggregations: {},
sorts: {},
});
const [filePagination, setFilePagination] = useState<FilePaginationModel>({
page: 0,
rowsPerPage: 100,
Expand All @@ -106,7 +111,7 @@ export const WorkspaceContextProvider: React.FC<Props> = ({ children }) => {

const fileStateReset = useCallback(() => {
setFile({ id: '', label: '', type: FileTypes.FOLDER });
setFileContent({ columns: [], rows: [], aggregations: {} });
setFileContent({ columns: [], rows: [], aggregations: {}, sorts: {} });
setFilePagination({ page: 0, rowsPerPage: 100, totalRows: 0 });
}, []);

Expand Down
Loading

0 comments on commit 7e92594

Please sign in to comment.