Skip to content

Commit

Permalink
fix design mode
Browse files Browse the repository at this point in the history
Signed-off-by: Teo Koon Peng <[email protected]>
  • Loading branch information
koonpeng committed Aug 22, 2024
1 parent 09dbfcc commit 932b04b
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 56 deletions.
3 changes: 1 addition & 2 deletions packages/dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
"date-fns": "^2.30.0",
"debug": "^4.2.0",
"eventemitter3": "^4.0.7",
"jsdom": "^24.1.1",
"keycloak-js": "^25.0.2",
"react": "^18.2.0",
"react-components": "workspace:*",
Expand All @@ -67,13 +66,13 @@
"@testing-library/dom": "^9.3.4",
"@testing-library/react": "^14.2.2",
"@testing-library/user-event": "^14.5.2",
"@types/history": "^5.0.0",
"@vitejs/plugin-react-swc": "^3.7.0",
"@vitest/coverage-v8": "^2.0.4",
"api-server": "file:../api-server",
"concurrently": "^8.2.2",
"eslint": "^8.57.0",
"history": "^5.3.0",
"jsdom": "^24.1.1",
"storybook": "^8.0.5",
"typescript": "~5.5.4",
"typescript-json-schema": "^0.64.0",
Expand Down
16 changes: 8 additions & 8 deletions packages/dashboard/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const homeWorkspace: WorkspaceState = {
windows: {
map: {
layout: { x: 0, y: 0, w: 12, h: 6 },
component: mapApp.Component,
Component: mapApp.Component,
},
},
};
Expand All @@ -34,19 +34,19 @@ const robotsWorkspace: WorkspaceState = {
windows: {
robots: {
layout: { x: 0, y: 0, w: 7, h: 4 },
component: robotsApp.Component,
Component: robotsApp.Component,
},
map: { layout: { x: 8, y: 0, w: 5, h: 8 }, component: mapApp.Component },
doors: { layout: { x: 0, y: 0, w: 7, h: 4 }, component: doorsApp.Component },
lifts: { layout: { x: 0, y: 0, w: 7, h: 4 }, component: liftsApp.Component },
mutexGroups: { layout: { x: 8, y: 0, w: 5, h: 4 }, component: robotMutexGroupsApp.Component },
map: { layout: { x: 8, y: 0, w: 5, h: 8 }, Component: mapApp.Component },
doors: { layout: { x: 0, y: 0, w: 7, h: 4 }, Component: doorsApp.Component },
lifts: { layout: { x: 0, y: 0, w: 7, h: 4 }, Component: liftsApp.Component },
mutexGroups: { layout: { x: 8, y: 0, w: 5, h: 4 }, Component: robotMutexGroupsApp.Component },
},
};

const tasksWorkspace: WorkspaceState = {
windows: {
tasks: { layout: { x: 0, y: 0, w: 7, h: 8 }, component: tasksApp.Component },
map: { layout: { x: 8, y: 0, w: 5, h: 8 }, component: mapApp.Component },
tasks: { layout: { x: 0, y: 0, w: 7, h: 8 }, Component: tasksApp.Component },
map: { layout: { x: 8, y: 0, w: 5, h: 8 }, Component: mapApp.Component },
},
};

Expand Down
26 changes: 15 additions & 11 deletions packages/dashboard/src/components/micro-app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,20 @@ export function createMicroApp<P>(
return {
appId,
displayName,
Component: React.forwardRef<HTMLDivElement>((microAppProps: MicroAppProps, ref) => {
const settings = useSettings();
return (
<Window ref={ref} title={displayName} {...microAppProps}>
{/* TODO(koonpeng): Implement fallback */}
<Suspense fallback={null}>
<LazyComponent {...props(settings)} />
</Suspense>
</Window>
);
}) as React.ComponentType<MicroAppProps>,
Component: React.forwardRef<HTMLDivElement>(
({ children, ...otherProps }: React.PropsWithChildren<MicroAppProps>, ref) => {
const settings = useSettings();
return (
<Window ref={ref} title={displayName} {...otherProps}>
{/* TODO(koonpeng): Implement fallback */}
<Suspense fallback={null}>
<LazyComponent {...props(settings)} />
</Suspense>
{/* this contains the resize handle */}
{children}
</Window>
);
},
) as React.ComponentType<MicroAppProps>,
};
}
24 changes: 21 additions & 3 deletions packages/dashboard/src/components/workspace.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import React from 'react';
import { WindowContainer, WindowLayout } from 'react-components';

import { MicroAppProps } from './micro-app';

export interface WindowState {
layout: Omit<WindowLayout, 'i'>;
component: React.ComponentType;
Component: React.ComponentType<MicroAppProps>;
}

export interface WorkspaceState {
Expand All @@ -13,9 +15,10 @@ export interface WorkspaceState {
export interface WorkspaceProps {
state: WorkspaceState;
onStateChange: (state: WorkspaceState) => void;
designMode?: boolean;
}

export const Workspace = ({ state, onStateChange }: WorkspaceProps) => {
export const Workspace = ({ state, onStateChange, designMode = false }: WorkspaceProps) => {
const layout: WindowLayout[] = Object.entries(state.windows).map(([k, w]) => ({
i: k,
...w.layout,
Expand All @@ -29,18 +32,33 @@ export const Workspace = ({ state, onStateChange }: WorkspaceProps) => {
newLayout.forEach((l) => (newState.windows[l.i].layout = l));
onStateChange(newState);
}}
designMode={designMode}
>
{Object.entries(state.windows).map(([k, w]) => (
<w.component key={k} />
<w.Component
key={k}
onClose={() => {
const newState = { ...state };
delete newState.windows[k];
onStateChange(newState);
}}
/>
))}
</WindowContainer>
);
};

export interface StaticWorkspaceProps {
/**
* Initial state of the workspace. This is only used on the first render, changes on this
* after the initial render will not do anything.
*/
initialState: WorkspaceState;
}

/**
* A simple predefined workspace where the layout is fixed.
*/
export const StaticWorkspace = ({ initialState }: StaticWorkspaceProps) => {
const [wsState, setWsState] = React.useState(initialState);
return <Workspace state={wsState} onStateChange={setWsState} />;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,6 @@ export function DoorDataGridTable({ doors, onDoorClick }: DoorDataGridTableProps
rowsPerPageOptions={[5]}
sx={{
fontSize: isScreenHeightLessThan800 ? '0.7rem' : 'inherit',
overflowX: 'scroll',
}}
autoPageSize={isScreenHeightLessThan800}
density={isScreenHeightLessThan800 ? 'compact' : 'standard'}
Expand Down
26 changes: 25 additions & 1 deletion packages/react-components/lib/window/window-container.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'react-grid-layout/css/styles.css';
import './no-rgl-animations.css';

import { styled } from '@mui/material';
import React from 'react';
import { default as GridLayout_, Layout as WindowLayout, WidthProvider } from 'react-grid-layout';

Expand Down Expand Up @@ -58,11 +59,34 @@ export const WindowContainer: React.FC<WindowContainerProps> = ({
preventCollision
isResizable={designMode}
isDraggable={designMode}
draggableHandle=".rgl-draggable"
onLayoutChange={onLayoutChange}
draggableCancel=".custom-resize-handle,.window-toolbar-items"
resizeHandle={<ResizeHandle className="custom-resize-handle" />}
>
{children}
</GridLayout>
</WindowManagerStateContext.Provider>
);
};

/**
* A custom resize handle that uses theme properties
*/
const ResizeHandle = styled('span')(({ theme }) => ({
position: 'absolute',
right: theme.spacing(1),
bottom: theme.spacing(1),
width: 20,
height: 20,
cursor: 'se-resize',
'&::after': {
content: '""',
position: 'absolute',
right: 0,
bottom: 0,
width: '0.5rem',
height: '0.5rem',
borderRight: `2px solid ${theme.palette.grey[500]}`,
borderBottom: `2px solid ${theme.palette.grey[500]}`,
},
}));
10 changes: 8 additions & 2 deletions packages/react-components/lib/window/window-toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,21 @@ import React from 'react';

export interface WindowToolbarProps extends AppBarProps {
title: string;
toolbarItemContainerProps?: React.ComponentProps<typeof Box>;
}

export const WindowToolbar: React.FC<WindowToolbarProps> = ({ title, children, ...otherProps }) => {
export const WindowToolbar: React.FC<WindowToolbarProps> = ({
title,
toolbarItemContainerProps,
children,
...otherProps
}) => {
return (
<AppBar position="static" elevation={0} {...otherProps}>
<Toolbar variant="dense" disableGutters sx={{ paddingLeft: 2 }}>
<Grid container justifyContent="space-between" alignItems="center">
<Typography variant="h6">{title}</Typography>
<Box>{children}</Box>
<Box {...toolbarItemContainerProps}>{children}</Box>
</Grid>
</Toolbar>
</AppBar>
Expand Down
49 changes: 35 additions & 14 deletions packages/react-components/lib/window/window.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type {} from '@emotion/styled';
import CloseIcon from '@mui/icons-material/Close';
import { Box, Grid, IconButton, Paper, PaperProps, styled, useTheme } from '@mui/material';
import { Box, IconButton, Paper, PaperProps, styled, useTheme } from '@mui/material';
import React from 'react';
import { Layout } from 'react-grid-layout';

Expand All @@ -22,31 +22,52 @@ export const Window = styled(
) => {
const theme = useTheme();

// The resize marker injected by `react-grid-layout` must be a direct children, but we
// want to wrap the window components in a div so it shows a scrollbar. So we assume that
// the injected resize marker is always the last component and render it separately.
const childrenArr = React.Children.toArray(children);
const childComponents = childrenArr.slice(0, childrenArr.length - 1);
const resizeComponent = childrenArr[childrenArr.length - 1];

const windowManagerState = React.useContext(WindowManagerStateContext);
return (
<Paper
ref={ref}
variant="outlined"
sx={{
cursor: windowManagerState.designMode ? 'move' : undefined,
cursor: 'move',
borderRadius: theme.shape.borderRadius,
'& > :not(.custom-resize-handle)': {
pointerEvents: windowManagerState.designMode ? 'none' : undefined,
},
'& .window-toolbar-items': {
pointerEvents: 'auto',
},
...sx,
}}
{...otherProps}
>
<Grid item className="rgl-draggable">
<WindowToolbar title={title}>
{toolbar}
{windowManagerState.designMode && (
<IconButton color="inherit" onClick={() => onClose && onClose()}>
<CloseIcon />
</IconButton>
)}
</WindowToolbar>
</Grid>
<Box sx={{ overflow: 'auto', width: '100%', height: '100%', cursor: 'auto' }}>
{children}
<WindowToolbar
title={title}
toolbarItemContainerProps={{ className: 'window-toolbar-items' }}
>
{toolbar}
{windowManagerState.designMode && (
<IconButton
color="inherit"
onClick={() => {
console.log('clicked');
onClose && onClose();
}}
>
<CloseIcon />
</IconButton>
)}
</WindowToolbar>
<Box width="100%" height="100%" overflow="auto">
{childComponents}
</Box>
{resizeComponent}
</Paper>
);
},
Expand Down
17 changes: 3 additions & 14 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 932b04b

Please sign in to comment.