Skip to content

Commit

Permalink
[225] Add some DevTools to help build and test the application
Browse files Browse the repository at this point in the history
Bug: #225
Signed-off-by: Stéphane Bégaudeau <[email protected]>
  • Loading branch information
sbegaudeau committed Aug 19, 2023
1 parent a271ac0 commit e802c31
Show file tree
Hide file tree
Showing 39 changed files with 1,738 additions and 286 deletions.
55 changes: 22 additions & 33 deletions frontend/svalyn-studio-app/src/app/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

import CssBaseline from '@mui/material/CssBaseline';
import { ThemeProvider } from '@mui/material/styles';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import { Route, Routes } from 'react-router-dom';
import { ChangeProposalsRouter } from '../changeproposals/ChangeProposalsRouter';
import { DomainsRouter } from '../domains/DomainsRouter';
import { ErrorsRouter } from '../errors/ErrorsRouter';
Expand All @@ -38,38 +36,29 @@ import { ProjectRouter } from '../projects/ProjectRouter';
import { SearchRouter } from '../search/SearchRouter';
import { SettingsRouter } from '../settings/SettingsRouter';
import { WorkspaceView } from '../workspace/WorkspaceView';
import { AuthenticationRedirectionBoundary } from './AuthenticationRedirectionBoundary';
import { theme } from './theme';

export const App = () => {
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<BrowserRouter>
<AuthenticationRedirectionBoundary>
<PaletteProvider>
<Routes>
<Route path="/" element={<HomeView />} />
<Route path="/new/*" element={<NewRouter />} />
<Route path="/orgs/:organizationIdentifier/*" element={<OrganizationRouter />} />
<Route path="/projects/:projectIdentifier/*" element={<ProjectRouter />} />
<Route path="/projects/:projectIdentifier/changes/:changeId" element={<WorkspaceView />} />
<Route path="/changeproposals/*" element={<ChangeProposalsRouter />} />
<Route path="/domains/*" element={<DomainsRouter />} />
<Route path="/search/*" element={<SearchRouter />} />
<Route path="/profiles/*" element={<ProfilesRouter />} />
<Route path="/notifications/*" element={<NotificationsRouter />} />
<Route path="/invitations/*" element={<InvitationsRouter />} />
<Route path="/settings/*" element={<SettingsRouter />} />
<Route path="/help/*" element={<HelpRouter />} />
<Route path="/errors/*" element={<ErrorsRouter />} />
<Route path="/login/*" element={<LoginRouter />} />
<Route path="/oauth2/*" element={<OAuth2Router />} />
<Route path="*" element={<NotFoundView />} />
</Routes>
</PaletteProvider>
</AuthenticationRedirectionBoundary>
</BrowserRouter>
</ThemeProvider>
<PaletteProvider>
<Routes>
<Route path="/" element={<HomeView />} />
<Route path="/new/*" element={<NewRouter />} />
<Route path="/orgs/:organizationIdentifier/*" element={<OrganizationRouter />} />
<Route path="/projects/:projectIdentifier/*" element={<ProjectRouter />} />
<Route path="/projects/:projectIdentifier/changes/:changeId" element={<WorkspaceView />} />
<Route path="/changeproposals/*" element={<ChangeProposalsRouter />} />
<Route path="/domains/*" element={<DomainsRouter />} />
<Route path="/search/*" element={<SearchRouter />} />
<Route path="/profiles/*" element={<ProfilesRouter />} />
<Route path="/notifications/*" element={<NotificationsRouter />} />
<Route path="/invitations/*" element={<InvitationsRouter />} />
<Route path="/settings/*" element={<SettingsRouter />} />
<Route path="/help/*" element={<HelpRouter />} />
<Route path="/errors/*" element={<ErrorsRouter />} />
<Route path="/login/*" element={<LoginRouter />} />
<Route path="/oauth2/*" element={<OAuth2Router />} />
<Route path="*" element={<NotFoundView />} />
</Routes>
</PaletteProvider>
);
};
9 changes: 8 additions & 1 deletion frontend/svalyn-studio-app/src/app/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

import { purple } from '@mui/material/colors';
import { blueGrey, purple } from '@mui/material/colors';
import { createTheme } from '@mui/material/styles';

import SourceSansProRegular from '../fonts/SourceSansPro-Regular.ttf';
Expand All @@ -33,6 +33,11 @@ export const theme = createTheme({
light: purple[600],
dark: purple[600],
},
code: {
main: blueGrey[900],
light: blueGrey[900],
dark: blueGrey[900],
},
},
typography: {
fontFamily: 'Source Sans Pro, Helvetica Neue, Helvetica, Arial, sans-serif',
Expand Down Expand Up @@ -95,10 +100,12 @@ export const theme = createTheme({
declare module '@mui/material/styles' {
interface Palette {
done: Palette['primary'];
code: Palette['primary'];
}

interface PaletteOptions {
done: PaletteOptions['primary'];
code: PaletteOptions['primary'];
}

interface TypographyVariants {
Expand Down
46 changes: 46 additions & 0 deletions frontend/svalyn-studio-app/src/devtools/DevTools.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2023 Stéphane Bégaudeau.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
* LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

import { useEffect, useState } from 'react';
import { DevToolsProps, DevToolsState } from './DevTools.types';
import { DevToolsDialog } from './dialog/DevToolsDialog';

export const DevTools = ({ children }: DevToolsProps) => {
const [state, setState] = useState<DevToolsState>({ dialogOpen: false });

useEffect(() => {
const listener = (event: KeyboardEvent) => {
if (event.key === 'F12' && event.shiftKey) {
setState((prevState) => ({ ...prevState, dialogOpen: true }));
}
};
document.addEventListener('keydown', listener);

return () => document.removeEventListener('keydown', listener);
}, []);

const handleClose = () => setState((prevState) => ({ ...prevState, dialogOpen: false }));

return (
<>
<div id="devtools">{children}</div>
<DevToolsDialog open={state.dialogOpen} onClose={handleClose} />
</>
);
};
26 changes: 26 additions & 0 deletions frontend/svalyn-studio-app/src/devtools/DevTools.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2023 Stéphane Bégaudeau.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
* LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

export interface DevToolsProps {
children: React.ReactNode;
}

export interface DevToolsState {
dialogOpen: boolean;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright (c) 2023 Stéphane Bégaudeau.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
* LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

import React, { useState } from 'react';
import { Message } from '../../snackbar/ErrorSnackbar.types';
import {
ConsoleContextProviderProps,
ConsoleContextProviderState,
ConsoleContextValue,
} from './ConsoleContextProvider.types';

export const ConsoleContext = React.createContext<ConsoleContextValue>({
messages: [],
pushMessage: () => {},
clearMessages: () => {},
});

export const ConsoleContextProvider = ({ children }: ConsoleContextProviderProps) => {
const [state, setState] = useState<ConsoleContextProviderState>({
messages: [],
});

const pushMessage = (message: Message) =>
setState((prevState) => ({ ...prevState, messages: [...prevState.messages, message] }));

const clearMessages = () => setState((prevState) => ({ ...prevState, messages: [] }));

const value: ConsoleContextValue = {
messages: [...state.messages],
pushMessage,
clearMessages,
};

return <ConsoleContext.Provider value={value}>{children}</ConsoleContext.Provider>;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2023 Stéphane Bégaudeau.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
* LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

import { Message } from '../../snackbar/ErrorSnackbar.types';

export interface ConsoleContextValue {
messages: Message[];
pushMessage: (message: Message) => void;
clearMessages: () => void;
}

export interface ConsoleContextProviderProps {
children: React.ReactNode;
}

export interface ConsoleContextProviderState {
messages: Message[];
}
77 changes: 77 additions & 0 deletions frontend/svalyn-studio-app/src/devtools/console/ConsoleLine.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright (c) 2023 Stéphane Bégaudeau.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
* LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import { Theme, alpha } from '@mui/material/styles';
import { VariantType } from '../../snackbar/ErrorSnackbar.types';
import { ConsoleLineProps } from './ConsoleLine.types';

const getTextColor = (theme: Theme, severity: VariantType): string => {
let textColor = theme.palette.getContrastText(theme.palette.code.main);
if (severity === 'error') {
textColor = theme.palette.error[theme.palette.mode];
} else if (severity === 'warning') {
textColor = theme.palette.warning[theme.palette.mode];
} else if (severity === 'success') {
textColor = theme.palette.success[theme.palette.mode];
}
return textColor;
};

export const ConsoleLine = ({ index, line, severity }: ConsoleLineProps) => {
return (
<Box
key={index}
sx={{
display: 'flex',
flexDirection: 'row',
gap: (theme) => theme.spacing(2),
paddingY: (theme) => theme.spacing(0.25),
color: (theme) => alpha(getTextColor(theme, severity), 0.7),
'&:hover': {
color: (theme) => getTextColor(theme, severity),
backgroundColor: (theme) => alpha(theme.palette.divider, 0.1),
},
}}
>
<Typography
variant="tcontent"
sx={{
width: (theme) => theme.spacing(6),
textAlign: 'right',
textOverflow: 'ellipsis',
overflow: 'hidden',
whiteSpace: 'nowrap',
userSelect: 'none',
}}
>
{index}
</Typography>
<Typography
variant="tcontent"
sx={{
whiteSpace: 'nowrap',
}}
>
{line}
</Typography>
</Box>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2023 Stéphane Bégaudeau.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
* LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

import { VariantType } from '../../snackbar/ErrorSnackbar.types';

export interface ConsoleLineProps {
index: number;
line: string;
severity: VariantType;
}
Loading

0 comments on commit e802c31

Please sign in to comment.