diff --git a/apps/web/package.json b/apps/web/package.json index c31bb9017f2ea078ef797e79174aa40e8c948b67..89ca061311669b5955b216903bdafbcdaf379a74 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -12,6 +12,7 @@ "dependencies": { "@graphpolaris/shared": "workspace:*", "@mui/base": "5.0.0-alpha.118", + "@mui/icons-material": "^5.11.11", "@mui/material": "^5.11.13", "@reduxjs/toolkit": "^1.9.2", "graphology": "^0.25.1", diff --git a/apps/web/src/app/app.tsx b/apps/web/src/app/app.tsx index dcdc35b0784678e3a90e1e6f79b796f2fe0a1c2d..9ae2badfaf7eceda8e4dcb1a6792d14e5751e0b5 100644 --- a/apps/web/src/app/app.tsx +++ b/apps/web/src/app/app.tsx @@ -16,24 +16,26 @@ import { } from '@graphpolaris/shared/lib/data-access/store'; import { AuthorizationHandler, - useIsAuthorized, + useAuthorization, } from '@graphpolaris/shared/lib/data-access/authorization'; +import { Navbar } from '../components/navbar/navbar'; export function App() { const dispatch = useAppDispatch(); - const userIsAuthorized = useIsAuthorized(); + const authorization = useAuthorization(); useEffect(() => { - if (userIsAuthorized) { + if (authorization.userAuthorized) { GetAllDatabases().then((d) => { console.log(d); }); } - }, [userIsAuthorized]); + }, [authorization.userAuthorized]); return ( <> - {!userIsAuthorized && <LoginScreen />} + {!authorization.userAuthorized && <LoginScreen />} + <Navbar /> <GridLayout className="layout" cols={10} diff --git a/apps/web/src/components/navbar/AddDatabaseForm/AddDatabaseFormComponent.tsx b/apps/web/src/components/navbar/AddDatabaseForm/AddDatabaseFormComponent.tsx deleted file mode 100644 index c4682516870ec05ee2438e538142e626d7147952..0000000000000000000000000000000000000000 --- a/apps/web/src/components/navbar/AddDatabaseForm/AddDatabaseFormComponent.tsx +++ /dev/null @@ -1,217 +0,0 @@ -/** - * This program has been developed by students from the bachelor Computer Science at - * Utrecht University within the Software Project course. - * © Copyright Utrecht University (Department of Information and Computing Sciences) - */ - -/* istanbul ignore file */ -/* The comment above was added so the code coverage wouldn't count this file towards code coverage. - * We do not test components/renderfunctions/styling files. - * See testing plan for more details.*/ -import React from 'react'; -import { ClassNameMap } from '@material-ui/styles'; -import { TextField, Button, WithStyles, withStyles, NativeSelect } from '@material-ui/core'; -import { useStyles } from './AddDatabaseFormUIStylesheet'; - -/** AddDatabaseFormProps is an interface containing the AuthViewModel. */ -export interface AddDatabaseFormProps extends WithStyles<typeof useStyles> { - open: boolean; - onClose(): void; - onSubmit( - username: string, - password: string, - hostname: string, - port: number, - databaseName: string, - internalDatabase: string, - databaseType: string, - ): void; -} - -/** AddDatabaseFormState is an interface containing the databasehost information. */ -export interface AddDatabaseFormState { - username: string; - password: string; - hostname: string; - port: number; - databaseName: string; - internalDatabase: string; - databaseType: string; - - styles: ClassNameMap; -} - -/** AddDatabaseForm is the View implementation for the connect screen that will be rendered. */ -class AddDatabaseForm extends React.Component<AddDatabaseFormProps, AddDatabaseFormState> { - public constructor(props: AddDatabaseFormProps) { - super(props); - - this.state = { - username: 'root', - password: 'DikkeDraak', - hostname: 'https://datastrophe.science.uu.nl/', - port: 8529, - databaseName: 'Tweede Kamer Dataset', - internalDatabase: 'TweedeKamer', - styles: this.props.classes, - databaseType: 'arangodb', - }; - } - - /** - * Validates if the port value is numerical. Only then will the state be updated. - * @param port The new port value. - */ - private handlePortChanged(port: string): void { - if (!isNaN(Number(port))) this.setState({ ...this.state, port: Number(port) }); - } - - /** Handles the submit button click. Calls the onSubmit in the props with all the fields. */ - private handleSubmitClicked(): void { - this.props.onSubmit( - this.state.username, - this.state.password, - this.state.hostname, - this.state.port, - this.state.databaseName, - this.state.internalDatabase, - this.state.databaseType, - ); - } - - public render(): JSX.Element { - const { - username, - password, - port, - hostname, - databaseName, - internalDatabase, - styles, - databaseType, - } = this.state; - - return this.props.open ? ( - <div - className={styles.wrapper} - onMouseDown={() => { - this.props.onClose(); - }} - > - <div - className={styles.authWrapper} - onMouseDown={(e) => { - e.stopPropagation(); - }} - > - <h1 className={styles.header}>Database Connect</h1> - <form - className={styles.formWrapper} - onSubmit={(event: React.FormEvent) => { - event.preventDefault(); - this.handleSubmitClicked(); - }} - > - <div className={styles.loginContainer}> - <TextField - className={styles.passLabel} - label="Database name" - type="databaseName" - value={databaseName} - onChange={(event) => - this.setState({ ...this.state, databaseName: event.currentTarget.value }) - } - required - /> - </div> - <div className={styles.loginContainer}> - <NativeSelect - className={styles.passLabel} - value={databaseType} - onChange={(event) => { - this.setState({ ...this.state, databaseType: event.currentTarget.value }); - }} - > - <option value="arangodb">arangodb</option> - <option value="neo4j">neo4j</option> - </NativeSelect> - </div> - <div className={styles.loginContainerRow}> - <TextField - className={styles.hostLabel} - label="Hostname/IP" - type="hostname" - value={hostname} - onChange={(event) => - this.setState({ ...this.state, hostname: event.currentTarget.value }) - } - required - /> - <TextField - className={styles.portLabel} - label="Port" - type="port" - value={port} - onChange={(event) => this.handlePortChanged(event.currentTarget.value)} - required - /> - </div> - <div className={styles.loginContainer}> - <TextField - className={styles.userLabel} - label="Username" - type="username" - value={username} - onChange={(event) => - this.setState({ ...this.state, username: event.currentTarget.value }) - } - required - /> - </div> - <div className={styles.loginContainer}> - <TextField - className={styles.passLabel} - label="Password" - type="password" - value={password} - onChange={(event) => - this.setState({ ...this.state, password: event.currentTarget.value }) - } - required - /> - </div> - <div className={styles.loginContainer}> - <TextField - className={styles.passLabel} - label="Internal database" - type="internalDatabaseName" - value={internalDatabase} - onChange={(event) => - this.setState({ ...this.state, internalDatabase: event.currentTarget.value }) - } - required - /> - </div> - <div className={styles.loginContainerButton}> - <Button variant="outlined" type="submit"> - Submit - </Button> - <Button - className={styles.cancelButton} - variant="outlined" - onClick={() => { - this.props.onClose(); - }} - > - Cancel - </Button> - </div> - </form> - </div> - </div> - ) : ( - <></> - ); - } -} -export default withStyles(useStyles)(AddDatabaseForm); diff --git a/apps/web/src/components/navbar/AddDatabaseForm/add-database-form.scss b/apps/web/src/components/navbar/AddDatabaseForm/add-database-form.scss deleted file mode 100644 index 97642ae3758a844a1c36c7afcb9185993e8c419b..0000000000000000000000000000000000000000 --- a/apps/web/src/components/navbar/AddDatabaseForm/add-database-form.scss +++ /dev/null @@ -1,75 +0,0 @@ -.wrapper { - height: 100vh; - display: flex; - align-items: center; - width: 100vw; - background-color: rgba(0, 0, 0, 0.87); - position: absolute; - z-index: 1225; -} - -.authWrapper { - font-family: Poppins, sans-serif; - display: flex; - flex-direction: column; - flex-wrap: wrap; - justify-content: center; - max-width: 400px; - margin: auto; - overflow: auto; - min-height: 300px; - background-color: #f7f8fc; - padding: 30px; - border-radius: 5px; - padding-bottom: 300px; -} - -.header { - text-align: center; -} - -.formWrapper { -} - -.loginContainer { - margin: 5px 0px !important; -} - -.loginContainerRow { - display: flex; - flex-direction: row; - margin: 5px 0px; -} - -.loginContainerButton { - margin-top: 10px !important; - - & button { - width: 100%; - } -} - -.hostLabel { - flex: 1 0 66.66667%; - - & div { - width: 95%; - } -} - -.portLabel { - flex: 1 0 33.33334%; -} - -.userLabel { - width: 100%; -} - -passLabel { - width: 100%; -} - -cancelButton { - margin-top: 2.5%; -} - diff --git a/apps/web/src/components/navbar/navbar.tsx b/apps/web/src/components/navbar/navbar.tsx index 325670160bbf99d4d3512eba328e00d63d9a94a6..ef3d9c91ec3ddf61b1b4d975fea0285372bd95db 100644 --- a/apps/web/src/components/navbar/navbar.tsx +++ b/apps/web/src/components/navbar/navbar.tsx @@ -8,9 +8,7 @@ /* The comment above was added so the code coverage wouldn't count this file towards code coverage. * We do not test components/renderfunctions/styling files. * See testing plan for more details.*/ -import React from 'react'; -import { ClassNameMap } from '@material-ui/styles'; -import NavbarViewModel from '../../view-model/navbar/NavbarViewModel'; +import React, { useState } from 'react'; import { AppBar, Toolbar, @@ -21,23 +19,32 @@ import { Menu, IconButton, Button, -} from '@material-ui/core/'; -import { AccountCircle } from '@material-ui/icons'; +} from '@mui/material'; +import { AccountCircle } from '@mui/icons-material'; import logo from './logogp.png'; -import logo2 from './logogpwhite.png'; -import AddDatabaseForm from './AddDatabaseForm/AddDatabaseFormComponent'; +import logo_white from './logogpwhite.png'; +import AddDatabaseForm from './AddDatabaseForm'; +import { useTheme } from '@mui/material/styles'; +import styles from './navbar.module.scss'; +import { + AddDatabase, + AddDatabaseRequest, + GetAllDatabases, + RequestSchema, + useAuthorization, +} from '@graphpolaris/shared/lib/data-access'; +import { + updateCurrentDatabase, + updateDatabaseList, +} from '@graphpolaris/shared/lib/data-access/store/sessionSlice'; /** NavbarComponentProps is an interface containing the NavbarViewModel. */ export interface NavbarComponentProps { - navbarViewModel: NavbarViewModel; - currentColours: any; - changeColourPalette: () => void; + // changeColourPalette: () => void; FIXME move to redux } -/** NavbarComponentState is an interface containing the type of visualisations. */ +/** NavbarComponentState is an interface containing the type of visualizations. */ export interface NavbarComponentState { - styles: ClassNameMap; - isAuthorized: boolean; clientID: string; sessionID: string; @@ -53,291 +60,266 @@ export interface NavbarComponentState { } /** NavbarComponent is the View implementation for Navbar */ -export default class Navbar - extends React.Component<NavbarComponentProps, NavbarComponentState> - implements BaseView -{ - private navbarViewModel: NavbarViewModel; +export const Navbar = (props: NavbarComponentProps) => { + const theme = useTheme(); + const authorization = useAuthorization(); - public constructor(props: NavbarComponentProps) { - super(props); + // const { navbarViewModel, currentColours } = props; + // this.navbarViewModel = navbarViewModel; - const { navbarViewModel, currentColours } = props; - this.navbarViewModel = navbarViewModel; + const [state, setState] = useState<NavbarComponentState>({ + isAuthorized: false, + clientID: authorization.userAuthorized ? authorization.userId || '' : '', + sessionID: authorization.sessionId || '', + databases: [], + currentDatabase: '', - this.state = { - isAuthorized: false, - styles: navbarViewModel.styles, - clientID: navbarViewModel.clientID, - sessionID: navbarViewModel.sessionID, - databases: [], - currentDatabase: navbarViewModel.currentDatabase, - - userMenuAnchor: undefined, - selectDatabaseMenuAnchor: undefined, - showAddDatabaseForm: false, - }; - } - - public componentDidMount(): void { - this.navbarViewModel.attachView(this); - } - - public componentWillUnmount(): void { - this.navbarViewModel.detachView(); - } - - /** onViewModelChanged updates the NavbarComponent each time the navbarViewModel changes */ - public onViewModelChanged(): void { - this.setState({ - isAuthorized: this.navbarViewModel.isAuthorized, - clientID: this.navbarViewModel.clientID, - sessionID: this.navbarViewModel.sessionID, - databases: this.navbarViewModel.databases, - currentDatabase: this.navbarViewModel.currentDatabase, - }); - } + userMenuAnchor: undefined, + selectDatabaseMenuAnchor: undefined, + showAddDatabaseForm: false, + }); /** Closes the user menu. Also closes all nested menu's. */ - private closeUserMenu(): void { + function closeUserMenu(): void { // If a nested window is open, close the main user menu a bit later - if (this.state.selectDatabaseMenuAnchor != undefined) { - this.setState({ selectDatabaseMenuAnchor: undefined }); - setTimeout(() => this.setState({ userMenuAnchor: undefined }), 100); - } else this.setState({ userMenuAnchor: undefined }); + if (state.selectDatabaseMenuAnchor != undefined) { + setState({ ...state, selectDatabaseMenuAnchor: undefined }); + setTimeout(() => setState({ ...state, userMenuAnchor: undefined }), 100); + } else setState({ ...state, userMenuAnchor: undefined }); + } + + function changeColourPalette() { + // TODO } /** - * Render will render the navigation bar - * @return {JSX.Element} The TypeScript code of the navigation bar + * Called when the user clicks on the 'submit' button of the add database form. */ - public render(): JSX.Element { - const { styles } = this.state; - const currentLogo = - this.props.currentColours.logo == 'white' ? logo2 : logo; + function onAddDatabaseFormSubmit( + request: AddDatabaseRequest + ): Promise<void | Response> { + return AddDatabase(request).then(() => + GetAllDatabases().then((databases) => { + updateDatabaseList(databases); + updateCurrentDatabase(request.name); + // When the database changes, request the new schema + console.log('databases ' + databases); + RequestSchema(request.name); + }) + ); + } - return ( - <div className={styles.root}> - <CssBaseline /> - <AppBar - title="GraphPolaris" - style={{ - zIndex: 1250, - backgroundColor: '#' + this.props.currentColours.background, - }} - position="fixed" - className={styles.appBar} - > - <Toolbar style={{ marginLeft: -5 }}> - <a href="https://graphpolaris.com/" className={styles.logo}> - <img src={currentLogo} className={styles.logo} /> - </a> - <div className={styles.menubox}> - <Button - className={styles.menuText} - style={{ color: '#' + this.props.currentColours.menuText }} - onClick={this.props.changeColourPalette} - > - Change Palette - </Button> - <Button - href="https://graphpolaris.com/" - className={styles.menuText} - style={{ color: '#' + this.props.currentColours.menuText }} - > - Home - </Button> - <Button - href="https://graphpolaris.com/index.php/products/" - className={styles.menuText} - style={{ color: '#' + this.props.currentColours.menuText }} - > - Products - </Button> - <Button - href="https://graphpolaris.com#usecases" - className={styles.menuText} - style={{ color: '#' + this.props.currentColours.menuText }} - > - Use Cases - </Button> - <Button - href="https://graphpolaris.com#earlyadoption" - className={styles.menuText} - style={{ color: '#' + this.props.currentColours.menuText }} - > - Contact - </Button> - {this.state.isAuthorized ? ( - <div> - <IconButton - color="inherit" + const currentLogo = theme.palette.custom.logo == 'white' ? logo_white : logo; + + return ( + <div className={styles.root}> + <CssBaseline /> + <AppBar + title="GraphPolaris" + style={{ + zIndex: 1250, + backgroundColor: theme.palette.custom.background, + }} + position="fixed" + className={styles.appBar} + > + <Toolbar style={{ marginLeft: -5 }}> + <a href="https://graphpolaris.com/" className={styles.logo}> + <img src={currentLogo} className={styles.logo} /> + </a> + <div className={styles.menubox}> + <Button + className={styles.menuText} + style={{ color: theme.palette.custom.menuText }} + onClick={changeColourPalette} + > + Change Palette + </Button> + <Button + href="https://graphpolaris.com/" + className={styles.menuText} + style={{ color: theme.palette.custom.menuText }} + > + Home + </Button> + <Button + href="https://graphpolaris.com/index.php/products/" + className={styles.menuText} + style={{ color: theme.palette.custom.menuText }} + > + Products + </Button> + <Button + href="https://graphpolaris.com#usecases" + className={styles.menuText} + style={{ color: theme.palette.custom.menuText }} + > + Use Cases + </Button> + <Button + href="https://graphpolaris.com#earlyadoption" + className={styles.menuText} + style={{ color: theme.palette.custom.menuText }} + > + Contact + </Button> + {state.isAuthorized ? ( + <div> + <IconButton + color="inherit" + onClick={(event) => + setState({ + ...state, + userMenuAnchor: event.currentTarget, + }) + } + > + <AccountCircle htmlColor={theme.palette.custom.menuText} /> + </IconButton> + <Menu + id="user-menus" + anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }} + transformOrigin={{ vertical: 'top', horizontal: 'left' }} + anchorEl={state.userMenuAnchor} + keepMounted + open={Boolean(state.userMenuAnchor)} + onClose={() => closeUserMenu()} + > + <MenuItem> + <ListItemText primary={'clientID: ' + state.clientID} /> + </MenuItem> + <MenuItem> + <ListItemText primary={'sessionID: ' + state.sessionID} /> + </MenuItem> + {/* <MenuItem + onClick={() => + navbarViewModel.handleLoginButtonClicked('google') + } + > + <ListItemText primary={'request new'} /> + </MenuItem> */} + {/*<MenuItem onClick={() => LocalStorage.instance().Reset()}>*/} + {/* <ListItemText primary={'Empty localstorage'} />*/} + {/*</MenuItem>*/} + <MenuItem + onClick={() => + setState({ + ...state, + userMenuAnchor: undefined, + showAddDatabaseForm: true, + }) + } + > + <ListItemText primary={'Add database'} /> + </MenuItem> + <MenuItem onClick={(event) => - this.setState({ - ...this.state, - userMenuAnchor: event.currentTarget, + setState({ + ...state, + selectDatabaseMenuAnchor: event.currentTarget, }) } > - <AccountCircle - htmlColor={'#' + this.props.currentColours.menuText} - /> - </IconButton> + <ListItemText primary={'Change database'} /> + </MenuItem> <Menu - id="user-menus" - getContentAnchorEl={null} - anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }} - transformOrigin={{ vertical: 'top', horizontal: 'left' }} - anchorEl={this.state.userMenuAnchor} + id="databases-menus" + anchorOrigin={{ vertical: 'top', horizontal: 'left' }} + transformOrigin={{ vertical: 'top', horizontal: 'right' }} + anchorEl={state.selectDatabaseMenuAnchor} keepMounted - open={Boolean(this.state.userMenuAnchor)} - onClose={() => this.closeUserMenu()} + disableAutoFocusItem + open={Boolean(state.selectDatabaseMenuAnchor)} + onClose={() => closeUserMenu()} > - <MenuItem> - <ListItemText - primary={'clientID: ' + this.state.clientID} - /> - </MenuItem> - <MenuItem> - <ListItemText - primary={'sessionID: ' + this.state.sessionID} - /> - </MenuItem> - <MenuItem - onClick={() => - this.navbarViewModel.handleLoginButtonClicked('google') - } - > - <ListItemText primary={'request new'} /> - </MenuItem> - {/*<MenuItem onClick={() => LocalStorage.instance().Reset()}>*/} - {/* <ListItemText primary={'Empty localstorage'} />*/} - {/*</MenuItem>*/} - <MenuItem - onClick={() => - this.setState({ - ...this.state, - userMenuAnchor: undefined, - showAddDatabaseForm: true, - }) - } - > - <ListItemText primary={'Add database'} /> - </MenuItem> - <MenuItem - onClick={(event) => - this.setState({ - ...this.state, - selectDatabaseMenuAnchor: event.currentTarget, - }) - } - > - <ListItemText primary={'Change database'} /> - </MenuItem> - <Menu - id="databases-menus" - getContentAnchorEl={null} - anchorOrigin={{ vertical: 'top', horizontal: 'left' }} - transformOrigin={{ vertical: 'top', horizontal: 'right' }} - anchorEl={this.state.selectDatabaseMenuAnchor} - keepMounted - disableAutoFocusItem - open={Boolean(this.state.selectDatabaseMenuAnchor)} - onClose={() => this.closeUserMenu()} - > - {this.state.databases.length > 0 ? ( - this.state.databases.map((database) => ( - <MenuItem - key={database} - selected={database == this.state.currentDatabase} - onClick={() => { - if (this.state.currentDatabase != database) { - this.navbarViewModel.updateCurrentDatabase( - database - ); - this.closeUserMenu(); - } - }} - > - <ListItemText primary={database} /> - </MenuItem> - )) - ) : ( - <MenuItem key="placeholder" value="" disabled> - no databases connected + {state.databases.length > 0 ? ( + state.databases.map((database) => ( + <MenuItem + key={database} + selected={database == state.currentDatabase} + onClick={() => { + if (state.currentDatabase != database) { + updateCurrentDatabase(database); + closeUserMenu(); + } + }} + > + <ListItemText primary={database} /> </MenuItem> - )} - </Menu> + )) + ) : ( + <MenuItem key="placeholder" value="" disabled> + no databases connected + </MenuItem> + )} </Menu> - </div> - ) : ( - <div> - <Button - className={styles.loginButton} - onClick={(event) => - this.setState({ - ...this.state, - userMenuAnchor: event.currentTarget, - }) + </Menu> + </div> + ) : ( + <div> + <Button + className={styles.loginButton} + onClick={(event) => + setState({ + ...state, + userMenuAnchor: event.currentTarget, + }) + } + > + <span + className={styles.loginButtonText} + style={{ + color: theme.palette.custom.menuText, + }} + > + Login + </span> + </Button> + {/* <Menu + id="user-menus" + getContentAnchorEl={null} + anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }} + transformOrigin={{ vertical: 'top', horizontal: 'left' }} + anchorEl={state.userMenuAnchor} + keepMounted + open={Boolean(state.userMenuAnchor)} + onClose={() => closeUserMenu()} + > + <MenuItem + onClick={() => + navbarViewModel.handleLoginButtonClicked('google') } > - <span - className={styles.loginButtonText} - style={{ - color: '#' + this.props.currentColours.menuText, - }} - > - Login - </span> - </Button> - <Menu - id="user-menus" - getContentAnchorEl={null} - anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }} - transformOrigin={{ vertical: 'top', horizontal: 'left' }} - anchorEl={this.state.userMenuAnchor} - keepMounted - open={Boolean(this.state.userMenuAnchor)} - onClose={() => this.closeUserMenu()} + <ListItemText primary={'Login with Google'} /> + </MenuItem> + <MenuItem + onClick={() => + navbarViewModel.handleLoginButtonClicked('github') + } > - <MenuItem - onClick={() => - this.navbarViewModel.handleLoginButtonClicked('google') - } - > - <ListItemText primary={'Login with Google'} /> - </MenuItem> - <MenuItem - onClick={() => - this.navbarViewModel.handleLoginButtonClicked('github') - } - > - <ListItemText primary={'Login with GitHub'} /> - </MenuItem> - <MenuItem - onClick={() => - this.navbarViewModel.handleLoginButtonClicked('free') - } - > - <ListItemText primary={'Login with free (debug)'} /> - </MenuItem> - </Menu> - </div> - )} - </div> - </Toolbar> - </AppBar> - <AddDatabaseForm - open={this.state.showAddDatabaseForm} - onClose={() => - this.setState({ ...this.state, showAddDatabaseForm: false }) - } - onSubmit={(...params) => { - this.navbarViewModel.onAddDatabaseFormSubmit(...params); - this.setState({ ...this.state, showAddDatabaseForm: false }); - }} - /> - </div> - ); - } -} + <ListItemText primary={'Login with GitHub'} /> + </MenuItem> + <MenuItem + onClick={() => + navbarViewModel.handleLoginButtonClicked('free') + } + > + <ListItemText primary={'Login with free (debug)'} /> + </MenuItem> + </Menu> */} + </div> + )} + </div> + </Toolbar> + </AppBar> + <AddDatabaseForm + open={state.showAddDatabaseForm} + onClose={() => setState({ ...state, showAddDatabaseForm: false })} + onSubmit={(...params) => { + onAddDatabaseFormSubmit(...params); + setState({ ...state, showAddDatabaseForm: false }); + }} + /> + </div> + ); +}; diff --git a/libs/shared/lib/data-access/api/database.ts b/libs/shared/lib/data-access/api/database.ts index e583b7f98b94c453b605250846a7efc44ca9d224..b627ba76dd56946a53719b29f5d66f787bc67c28 100644 --- a/libs/shared/lib/data-access/api/database.ts +++ b/libs/shared/lib/data-access/api/database.ts @@ -2,6 +2,13 @@ import { AuthorizationHandler } from '@graphpolaris/shared/lib/data-access/authorization'; +export enum DatabaseType { + ArangoDB = 0, + Neo4j = 1, +} + +export const databaseNameMapping: string[] = ['arangodb', 'neo4j']; + export type AddDatabaseRequest = { name: string; internal_database_name: string; @@ -9,7 +16,7 @@ export type AddDatabaseRequest = { port: number; username: string; password: string; - type: number; // Database type. 0 = ArangoDB, 1 = Neo4j + type: DatabaseType; // Database type. 0 = ArangoDB, 1 = Neo4j }; export function AddDatabase(request: AddDatabaseRequest): Promise<void> { diff --git a/libs/shared/lib/data-access/api/index.ts b/libs/shared/lib/data-access/api/index.ts index 94a2ddb8716278114077b272a51852400dbb44b9..eed07d0e97fe3d9e4353a511b074d44726399bcb 100644 --- a/libs/shared/lib/data-access/api/index.ts +++ b/libs/shared/lib/data-access/api/index.ts @@ -1,2 +1,3 @@ export * from './database' -export * from './user' \ No newline at end of file +export * from './user' +export * from './schema' \ No newline at end of file diff --git a/libs/shared/lib/data-access/authorization/authorizationHandler.ts b/libs/shared/lib/data-access/authorization/authorizationHandler.ts index 4571c3b053f55a273620e386a8dcc3940cb343cd..d8f2d1b7457571a856eb64f1eec4c6a0e976e8ae 100644 --- a/libs/shared/lib/data-access/authorization/authorizationHandler.ts +++ b/libs/shared/lib/data-access/authorization/authorizationHandler.ts @@ -96,18 +96,18 @@ export class AuthorizationHandler { if (this.accessToken !== '') { // Initialise the new refresh token - this.initialiseRefreshToken(); + this.initializeRefreshToken(); } } } /** - * initialiseRefreshToken attempts to initialise a refresh token + * initializeRefreshToken attempts to initialize a refresh token */ - private async initialiseRefreshToken() { + private async initializeRefreshToken() { fetch( 'https://api.graphpolaris.com/auth/refresh?access_token=' + - this.accessToken, + this.accessToken, { method: 'GET', credentials: 'include', @@ -166,7 +166,7 @@ export class AuthorizationHandler { this.accessToken = accessToken; // Activate the refresh token - this.initialiseRefreshToken(); + this.initializeRefreshToken(); // Start the automatic refreshing every 10 minutes setInterval(() => { diff --git a/libs/shared/lib/data-access/authorization/authorizationHook.tsx b/libs/shared/lib/data-access/authorization/authorizationHook.tsx index 81d0d4fae7a880f127edaafcad32243725fb9795..4110005e881aa28f62ecda514643609294a6b0fa 100644 --- a/libs/shared/lib/data-access/authorization/authorizationHook.tsx +++ b/libs/shared/lib/data-access/authorization/authorizationHook.tsx @@ -1,28 +1,41 @@ import { useEffect, useState } from 'react'; import { AuthorizationHandler } from '@graphpolaris/shared/lib/data-access'; -export function useIsAuthorized() { - const [userAuthorized, setUserAuthorized] = useState(false); +interface useIsAuthorizedState { + userAuthorized: boolean; + userId?: string; + sessionId?: string; +} + +export function useAuthorization() { + const [state, setState] = useState<useIsAuthorizedState>({ + userAuthorized: false, + }); + const authInstance = AuthorizationHandler.instance(); const authCallback = async () => { - setUserAuthorized(true); + setState({ + userAuthorized: authInstance.Authorized(), + userId: authInstance.UserID(), + sessionId: authInstance.SessionID(), + }); // Print the user that is currently logged in // const user = await GetUserInfo(); // console.log(user); }; - AuthorizationHandler.instance().setCallback(authCallback); + authInstance.setCallback(authCallback); // Attempt to Authorize the user const authorize = async () => { - const authorized = await AuthorizationHandler.instance().Authorize(); - setUserAuthorized(authorized); + const authorized = await authInstance.Authorize(); + if (authorized) authCallback(); }; useEffect(() => { authorize(); }, []); - return userAuthorized; + return state; } diff --git a/libs/shared/lib/data-access/store/hooks.ts b/libs/shared/lib/data-access/store/hooks.ts index 3577224132af3e1d28b0581af468410336ea592e..e1c5935f4bd900657af37422a67b5e24b670acf2 100644 --- a/libs/shared/lib/data-access/store/hooks.ts +++ b/libs/shared/lib/data-access/store/hooks.ts @@ -11,6 +11,7 @@ import { selectQuerybuilderGraph, selectQuerybuilderGraphology, } from '@graphpolaris/shared/lib/data-access/store/querybuilderSlice'; +import { sessionCacheState } from './sessionSlice'; // Use throughout your app instead of plain `useDispatch` and `useSelector` export const useAppDispatch: () => AppDispatch = useDispatch; @@ -33,3 +34,4 @@ export const useQuerybuilderGraph = () => // Overall Configuration of the app export const useConfig = () => useAppSelector(configState); +export const useSessionCache = () => useAppSelector(sessionCacheState); diff --git a/libs/shared/lib/data-access/store/store.ts b/libs/shared/lib/data-access/store/store.ts index 31e0086c5cbc87571e61b46f78334ca177fceac2..ef639a9206b474aae0bf000ed34b2111fcadbea5 100644 --- a/libs/shared/lib/data-access/store/store.ts +++ b/libs/shared/lib/data-access/store/store.ts @@ -4,6 +4,7 @@ import graphQueryResultSlice from './graphQueryResultSlice'; import querybuilderSlice from './querybuilderSlice'; import schemaSlice from './schemaSlice'; import configSlice from './configSlice'; +import sessionSlice from './sessionSlice'; export const store = configureStore({ reducer: { @@ -11,6 +12,7 @@ export const store = configureStore({ schema: schemaSlice, colorPaletteConfig: colorPaletteConfigSlice, querybuilder: querybuilderSlice, + sessionCache: sessionSlice, config: configSlice, }, middleware: (getDefaultMiddleware) => diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c0bd7f0cc8610cba4f060887d3e5d7c273fc4dfc..33b0e34d8c275022c78de3749e3e3c79dd21eb47 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -21,10 +21,10 @@ importers: version: 8.0.3 prettier: specifier: latest - version: 2.8.7 + version: 2.8.8 turbo: specifier: latest - version: 1.8.6 + version: 1.8.8 apps/web: dependencies: @@ -34,6 +34,9 @@ importers: '@mui/base': specifier: 5.0.0-alpha.118 version: 5.0.0-alpha.118(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0) + '@mui/icons-material': + specifier: ^5.11.11 + version: 5.11.11(@mui/material@5.11.13)(@types/react@18.0.28)(react@18.2.0) '@mui/material': specifier: ^5.11.13 version: 5.11.13(@emotion/react@11.10.6)(@emotion/styled@11.10.6)(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0) @@ -215,7 +218,7 @@ importers: devDependencies: '@storybook/addon-styling': specifier: ^0.3.2 - version: 0.3.2(@storybook/addons@6.5.16)(@storybook/api@6.5.16)(@storybook/components@6.5.16)(@storybook/core-events@6.5.16)(@storybook/manager-api@7.0.5)(@storybook/theming@6.5.16)(react-dom@18.2.0)(react@18.2.0)(sass-loader@13.2.2) + version: 0.3.2(@storybook/addons@6.5.16)(@storybook/api@6.5.16)(@storybook/components@6.5.16)(@storybook/core-events@6.5.16)(@storybook/manager-api@7.0.7)(@storybook/theming@6.5.16)(react-dom@18.2.0)(react@18.2.0)(sass-loader@13.2.2) '@storybook/preset-scss': specifier: ^1.0.3 version: 1.0.3(css-loader@6.7.3)(sass-loader@13.2.2)(style-loader@3.3.2) @@ -393,13 +396,13 @@ importers: version: 7.0.0-rc.5(react-dom@18.2.0)(react@18.2.0) '@storybook/addon-interactions': specifier: next - version: 7.0.0-rc.5(react-dom@18.2.0)(react@18.2.0) + version: 7.0.7(react-dom@18.2.0)(react@18.2.0) '@storybook/addon-links': specifier: ^7.0.5 version: 7.0.5(react-dom@18.2.0)(react@18.2.0) '@storybook/addon-styling': specifier: ^0.3.2 - version: 0.3.2(@storybook/addons@6.5.16)(@storybook/api@6.5.16)(@storybook/components@6.5.16)(@storybook/core-events@6.5.16)(@storybook/manager-api@7.0.5)(@storybook/theming@6.5.16)(react-dom@18.2.0)(react@18.2.0)(sass-loader@13.2.2) + version: 0.3.2(@storybook/addons@6.5.16)(@storybook/api@6.5.16)(@storybook/components@6.5.16)(@storybook/core-events@6.5.16)(@storybook/manager-api@7.0.7)(@storybook/theming@6.5.16)(react-dom@18.2.0)(react@18.2.0)(sass-loader@13.2.2) '@storybook/blocks': specifier: ^7.0.5 version: 7.0.5(react-dom@18.2.0)(react@18.2.0) @@ -459,7 +462,7 @@ importers: version: 4.2.1(@types/node@18.13.0)(sass@1.59.3) vite-plugin-sass-dts: specifier: ^1.3.2 - version: 1.3.2(postcss@8.4.21)(prettier@2.8.7)(sass@1.59.3)(vite@4.2.1) + version: 1.3.2(postcss@8.4.21)(prettier@2.8.8)(sass@1.59.3)(vite@4.2.1) vite-tsconfig-paths: specifier: ^4.0.7 version: 4.0.7(typescript@4.9.5)(vite@4.2.1) @@ -3789,8 +3792,8 @@ packages: '@storybook/preview-api': 7.0.0-rc.5 dev: true - /@storybook/addon-interactions@7.0.0-rc.5(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-OPAp+0LS+vtFcBvfrY+5/xFyXfihLCWJauFmMI02g0tsHObB4Ua6juAnOYSwNSKdea0uW5GGTkVRxS7zEgqr3Q==} + /@storybook/addon-interactions@7.0.7(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-jBl6O5sSbix0X1G9dFuWvvu4qefgLP9dAB/utVdDadZxlbPfa5B2C2q2YIqjcKZoX8DS8Fh8SUhlX1mdW5tu5w==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -3800,16 +3803,16 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.0.0-rc.5 - '@storybook/components': 7.0.0-rc.5(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-common': 7.0.0-rc.5 - '@storybook/core-events': 7.0.0-rc.5 + '@storybook/client-logger': 7.0.7 + '@storybook/components': 7.0.7(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-common': 7.0.7 + '@storybook/core-events': 7.0.7 '@storybook/global': 5.0.0 - '@storybook/instrumenter': 7.0.0-rc.5 - '@storybook/manager-api': 7.0.0-rc.5(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.0-rc.5 - '@storybook/theming': 7.0.0-rc.5(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.0-rc.5 + '@storybook/instrumenter': 7.0.7 + '@storybook/manager-api': 7.0.7(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.7 + '@storybook/theming': 7.0.7(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.7 jest-mock: 27.5.1 polished: 4.2.2 react: 18.2.0 @@ -3889,7 +3892,7 @@ packages: ts-dedent: 2.2.0 dev: true - /@storybook/addon-styling@0.3.2(@storybook/addons@6.5.16)(@storybook/api@6.5.16)(@storybook/components@6.5.16)(@storybook/core-events@6.5.16)(@storybook/manager-api@7.0.5)(@storybook/theming@6.5.16)(react-dom@18.2.0)(react@18.2.0)(sass-loader@13.2.2): + /@storybook/addon-styling@0.3.2(@storybook/addons@6.5.16)(@storybook/api@6.5.16)(@storybook/components@6.5.16)(@storybook/core-events@6.5.16)(@storybook/manager-api@7.0.7)(@storybook/theming@6.5.16)(react-dom@18.2.0)(react@18.2.0)(sass-loader@13.2.2): resolution: {integrity: sha512-ztKy9uU2yKBtvBp4/Km4LD1JCNNFHpXS33LjbeIfho0toRv100g8tUojrdnoRX1b2KVK6cqep5mJV0z2ak9hIQ==} peerDependencies: '@storybook/addons': ^6.5.8 @@ -3916,7 +3919,7 @@ packages: '@storybook/api': 6.5.16(react-dom@18.2.0)(react@18.2.0) '@storybook/components': 6.5.16(react-dom@18.2.0)(react@18.2.0) '@storybook/core-events': 6.5.16 - '@storybook/manager-api': 7.0.5(react-dom@18.2.0)(react@18.2.0) + '@storybook/manager-api': 7.0.7(react-dom@18.2.0)(react@18.2.0) '@storybook/theming': 6.5.16(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -4169,12 +4172,12 @@ packages: telejson: 7.0.4 dev: true - /@storybook/channel-postmessage@7.0.6: - resolution: {integrity: sha512-xBsh/+85GS4bJ08r7z1iRn26EI6hGmMgNpjpFztRigMhsq5SkD9FJb+Nh9bbaHm+yPOCqJcaHQ2aQpuJNT8dHA==} + /@storybook/channel-postmessage@7.0.7: + resolution: {integrity: sha512-XMtYfcaE0UoY/V7K1cTu9PcWETD4iyWb/Yswc4F9VrPw0Ui4UwGS1j4iaAu8DC06yyoJs4XvxYFBMlCQmKja6A==} dependencies: - '@storybook/channels': 7.0.6 - '@storybook/client-logger': 7.0.6 - '@storybook/core-events': 7.0.6 + '@storybook/channels': 7.0.7 + '@storybook/client-logger': 7.0.7 + '@storybook/core-events': 7.0.7 '@storybook/global': 5.0.0 qs: 6.11.1 telejson: 7.0.4 @@ -4205,8 +4208,8 @@ packages: resolution: {integrity: sha512-WiSPXgOK63jAlDDmbTs1sVXoYe3r/4VjpfwhEcxSPU544YQVARF1ePtiGjlp8HVFhZh1Q7afbVGJ9w96++u98A==} dev: true - /@storybook/channels@7.0.6: - resolution: {integrity: sha512-+34cVmrXZ3lb1s5tDK+OWd5HLtEPSUMas0VKFJ0k9LBpFlVl9aiCZBJRvSYmWL7beauUfa+HSmJgjlD6228ChQ==} + /@storybook/channels@7.0.7: + resolution: {integrity: sha512-Om4ovBLNw8pVrBu83MpOKgAuGO9Dpr1Coh2qp8t64WRPkejX1mxOY9IgH723//zH3igx8LCkf9rvBvcrsyaScQ==} dev: true /@storybook/cli@7.0.5: @@ -4240,7 +4243,7 @@ packages: globby: 11.1.0 jscodeshift: 0.14.0(@babel/preset-env@7.21.4) leven: 3.1.0 - prettier: 2.8.7 + prettier: 2.8.8 prompts: 2.4.2 puppeteer-core: 2.1.1 read-pkg-up: 7.0.1 @@ -4277,8 +4280,8 @@ packages: '@storybook/global': 5.0.0 dev: true - /@storybook/client-logger@7.0.6: - resolution: {integrity: sha512-TC/E5BBkY+WNldNw5p5Ffr9x4UgMe48GmC50ikBpQFk6og1B7XpFGMMbj40EBB0R5cpZkQNEVQh4OvunEygNzg==} + /@storybook/client-logger@7.0.7: + resolution: {integrity: sha512-EclHjDs5HwHMKB4X2orn/KKA0DTIDmp4AXAUJGRfxb5ArpKEb7tXLHsgrRBlaoz1j5LAwKTmEyZOONh9G3etjg==} dependencies: '@storybook/global': 5.0.0 dev: true @@ -4297,7 +4300,7 @@ packages: globby: 11.1.0 jscodeshift: 0.14.0(@babel/preset-env@7.21.4) lodash: 4.17.21 - prettier: 2.8.7 + prettier: 2.8.8 recast: 0.23.1 transitivePeerDependencies: - supports-color @@ -4357,6 +4360,24 @@ packages: util-deprecate: 1.0.2 dev: true + /@storybook/components@7.0.7(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-6PLs9LMkBuhH/w4bSJ72tYgICMbOOIHuoB/fQdVlzhsdnXL2fM/v4RVW2N7v+Oz3lYXp/JtV8V9Ub8h6eDQKXg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@storybook/client-logger': 7.0.7 + '@storybook/csf': 0.1.0 + '@storybook/global': 5.0.0 + '@storybook/theming': 7.0.7(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.7 + memoizerific: 1.11.3 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + use-resize-observer: 9.1.0(react-dom@18.2.0)(react@18.2.0) + util-deprecate: 1.0.2 + dev: true + /@storybook/core-client@7.0.0-rc.5: resolution: {integrity: sha512-jBY4kJDL5sdVcnGzz+cpruzkF01Hi+DJ/c9mpNiL+CjiDSFewtCk28Qggwccm9tKne5eAlrFiJAu5MOlbIcM+g==} dependencies: @@ -4424,6 +4445,32 @@ packages: - supports-color dev: true + /@storybook/core-common@7.0.7: + resolution: {integrity: sha512-c8T24wex9bnCYdZVZFNX4VV+wfhrp47OLzVONZDqxMhq6G//Bgv5zH4Awcx5UfWf/05VcP7KGF1VKj8ebRyEEA==} + dependencies: + '@storybook/node-logger': 7.0.7 + '@storybook/types': 7.0.7 + '@types/node': 16.18.16 + '@types/pretty-hrtime': 1.0.1 + chalk: 4.1.2 + esbuild: 0.17.12 + esbuild-register: 3.4.2(esbuild@0.17.12) + file-system-cache: 2.0.2 + find-up: 5.0.0 + fs-extra: 11.1.1 + glob: 8.1.0 + glob-promise: 6.0.2(glob@8.1.0) + handlebars: 4.7.7 + lazy-universal-dotenv: 4.0.0 + picomatch: 2.3.1 + pkg-dir: 5.0.0 + pretty-hrtime: 1.0.3 + resolve-from: 5.0.0 + ts-dedent: 2.2.0 + transitivePeerDependencies: + - supports-color + dev: true + /@storybook/core-events@6.5.16: resolution: {integrity: sha512-qMZQwmvzpH5F2uwNUllTPg6eZXr2OaYZQRRN8VZJiuorZzDNdAFmiVWMWdkThwmyLEJuQKXxqCL8lMj/7PPM+g==} dependencies: @@ -4438,8 +4485,8 @@ packages: resolution: {integrity: sha512-bYQFZlJR3n5gFk5GVIemuL3m6aYPF6DVnzj6n9UcMZDlHcOZ2B2WbTmAUrGy0bmtj/Fd6ZJKDpBhh3cRRsYkbA==} dev: true - /@storybook/core-events@7.0.6: - resolution: {integrity: sha512-kGrtjlYtjd4iTVk+Phb4CymZaVkB+MGscKAgcO8gfgJ/Q/gq8HQLVZSIzeoCDcDSHOGlBzbg2WVtdHIHhCKlOQ==} + /@storybook/core-events@7.0.7: + resolution: {integrity: sha512-XNsR2RgaL2vBwuqsu+KA1DzGmB1UFfrAhpxhmyWTKDCniwtTLlaXgfKbqwcrOrPu/o1YswgIup/9UHepRHaf4A==} dev: true /@storybook/core-server@7.0.5: @@ -4598,24 +4645,14 @@ packages: resolution: {integrity: sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==} dev: true - /@storybook/instrumenter@7.0.0-rc.5: - resolution: {integrity: sha512-e9AtV1hNTs4ppmqKfst/cInmRnhkK9VcGf3xB/d9Qqm0Sqo+sNXu6ywK5KpAURdCzsUEOPXbJ9H52yTrU4f74A==} + /@storybook/instrumenter@7.0.7: + resolution: {integrity: sha512-0zE5lM3laKvCT4GW/XKKw8kakvI4catqK8PObZolRhfxbtGufW4VJZ2E8vXLtgA/+K3zikypjuWE6d45NLbh9w==} dependencies: - '@storybook/channels': 7.0.0-rc.5 - '@storybook/client-logger': 7.0.0-rc.5 - '@storybook/core-events': 7.0.0-rc.5 + '@storybook/channels': 7.0.7 + '@storybook/client-logger': 7.0.7 + '@storybook/core-events': 7.0.7 '@storybook/global': 5.0.0 - '@storybook/preview-api': 7.0.0-rc.5 - dev: true - - /@storybook/instrumenter@7.0.6: - resolution: {integrity: sha512-JUcDas1cYCE+ZMVOw5CKc5g6PxDe3HH+IGdh/W9wL5vmdOUvAs858m7NLxkjkQGufof+Ohbmf/Yz5gyXaZ5+Yg==} - dependencies: - '@storybook/channels': 7.0.6 - '@storybook/client-logger': 7.0.6 - '@storybook/core-events': 7.0.6 - '@storybook/global': 5.0.0 - '@storybook/preview-api': 7.0.6 + '@storybook/preview-api': 7.0.7 dev: true /@storybook/manager-api@7.0.0-rc.5(react-dom@18.2.0)(react@18.2.0): @@ -4668,6 +4705,31 @@ packages: ts-dedent: 2.2.0 dev: true + /@storybook/manager-api@7.0.7(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-QTd/P72peAhofKqK+8yzIO9iWAEfPn8WUGGveV2KGaTlSlgbr87RLHEKilcXMZcYhBWC9izFRmjKum9ROdskrQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@storybook/channels': 7.0.7 + '@storybook/client-logger': 7.0.7 + '@storybook/core-events': 7.0.7 + '@storybook/csf': 0.1.0 + '@storybook/global': 5.0.0 + '@storybook/router': 7.0.7(react-dom@18.2.0)(react@18.2.0) + '@storybook/theming': 7.0.7(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.7 + dequal: 2.0.3 + lodash: 4.17.21 + memoizerific: 1.11.3 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + semver: 7.3.8 + store2: 2.14.2 + telejson: 7.0.4 + ts-dedent: 2.2.0 + dev: true + /@storybook/manager@7.0.5: resolution: {integrity: sha512-EwgEXetNfpitkxJ+WCqVF71aqaLR+3exDfL088NalxLZOJIokodvbtEKdueJr7CzrqTdxMIm9um5YX1ZgxdUcg==} dev: true @@ -4698,6 +4760,15 @@ packages: pretty-hrtime: 1.0.3 dev: true + /@storybook/node-logger@7.0.7: + resolution: {integrity: sha512-5Y4LLgKeCStq1ktCKZ5eNPzQQSQ+CYZAlkEdzQ3Pp//0KXaZvVxEvGtaYhAymP2HatLpI8Oneo4lHrJioRfgww==} + dependencies: + '@types/npmlog': 4.1.4 + chalk: 4.1.2 + npmlog: 5.0.1 + pretty-hrtime: 1.0.3 + dev: true + /@storybook/postinstall@7.0.0-rc.5: resolution: {integrity: sha512-F23wxKEJ2XoVnHT7oAMjCXtANWvNq7M+FmIowgI98b3FT1dxt9fFPKKY+3Lcqp0Xa6Pzezd03KR9vAxXvvK/iQ==} dev: true @@ -4755,16 +4826,16 @@ packages: util-deprecate: 1.0.2 dev: true - /@storybook/preview-api@7.0.6: - resolution: {integrity: sha512-uNsedNyiEccBV2EDUC/xcKTbmiNCYuVHbgOoWTmBz0ZqFo9bX0jxkpyYWHEhJM79qqVqmrpiQ5jbS8QKn8TIxQ==} + /@storybook/preview-api@7.0.7: + resolution: {integrity: sha512-R5pmGTodpu6hbwEg2RM2ulWtW3d426YzsisHrZJ+FT9lecWauN1y9xHCz7HdNzEFhT8r4YOa24L9ZS3mosZ7hA==} dependencies: - '@storybook/channel-postmessage': 7.0.6 - '@storybook/channels': 7.0.6 - '@storybook/client-logger': 7.0.6 - '@storybook/core-events': 7.0.6 + '@storybook/channel-postmessage': 7.0.7 + '@storybook/channels': 7.0.7 + '@storybook/client-logger': 7.0.7 + '@storybook/core-events': 7.0.7 '@storybook/csf': 0.1.0 '@storybook/global': 5.0.0 - '@storybook/types': 7.0.6 + '@storybook/types': 7.0.7 '@types/qs': 6.9.7 dequal: 2.0.3 lodash: 4.17.21 @@ -4944,6 +5015,19 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true + /@storybook/router@7.0.7(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-/lM8/NHQKeshfnC3ayFuO8Y9TCSHnCAPRhIsVxvanBzcj+ILbCIyZ+TspvB3hT4MbX/Ez+JR8VrMbjXIGwmH8w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@storybook/client-logger': 7.0.7 + memoizerific: 1.11.3 + qs: 6.11.1 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: true + /@storybook/semver@7.3.2: resolution: {integrity: sha512-SWeszlsiPsMI0Ps0jVNtH64cI5c0UF3f7KgjVKJoNP30crQ6wUSddY2hsdeczZXEKVJGEn50Q60flcGsQGIcrg==} engines: {node: '>=10'} @@ -4973,8 +5057,8 @@ packages: /@storybook/testing-library@0.0.14-next.1: resolution: {integrity: sha512-1CAl40IKIhcPaCC4pYCG0b9IiYNymktfV/jTrX7ctquRY3akaN7f4A1SippVHosksft0M+rQTFE0ccfWW581fw==} dependencies: - '@storybook/client-logger': 7.0.6 - '@storybook/instrumenter': 7.0.6 + '@storybook/client-logger': 7.0.7 + '@storybook/instrumenter': 7.0.7 '@testing-library/dom': 8.20.0 '@testing-library/user-event': 13.5.0(@testing-library/dom@8.20.0) ts-dedent: 2.2.0 @@ -5022,6 +5106,20 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true + /@storybook/theming@7.0.7(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-InTZe+Sgco1NsxgiG+cyUKWQe3GsjlIyU/o5qDdtOTXcZ64HzyBuAZlAequSddqfDeMDqxRFPc2w1J28MAUHxA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@emotion/use-insertion-effect-with-fallbacks': 1.0.0(react@18.2.0) + '@storybook/client-logger': 7.0.7 + '@storybook/global': 5.0.0 + memoizerific: 1.11.3 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: true + /@storybook/types@7.0.0-rc.5: resolution: {integrity: sha512-gLKUY7EfPYenz0Y1jw90AUAUlKTHOj9p7J3d8GcI5x5buHdU+M7Q1jotPWzDwRFI24y3Ob31oyCBhysIw8S2Aw==} dependencies: @@ -5040,10 +5138,10 @@ packages: file-system-cache: 2.0.2 dev: true - /@storybook/types@7.0.6: - resolution: {integrity: sha512-dFASQxzvldU2Nx/eJG+oL4wCchUWAKOmOSYJYhKgtGpx99oXOiWUyC0SgCpTveBJ7AppoiseyasQ9Gd/Ccycdw==} + /@storybook/types@7.0.7: + resolution: {integrity: sha512-v9piuwp8FvTiHXIOOi5lEyTEJKhnbcbhVxgJ3VFhhXYFd0DTz6Bst0XIIgkgs21ITb3xhkfPbCRUueMcbXO1MA==} dependencies: - '@storybook/channels': 7.0.6 + '@storybook/channels': 7.0.7 '@types/babel__core': 7.20.0 '@types/express': 4.17.17 file-system-cache: 2.0.2 @@ -7006,7 +7104,7 @@ packages: dev: true /concat-map@0.0.1: - resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} /concat-stream@1.6.2: resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} @@ -11071,8 +11169,8 @@ packages: hasBin: true dev: true - /prettier@2.8.7: - resolution: {integrity: sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==} + /prettier@2.8.8: + resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} engines: {node: '>=10.13.0'} hasBin: true dev: true @@ -12701,65 +12799,65 @@ packages: tslib: 1.14.1 typescript: 4.9.5 - /turbo-darwin-64@1.8.6: - resolution: {integrity: sha512-VlXkQR0TEBAEyBRsvAXBax+fj1EdPKPliwBaCnRLiDUcA/8wYlKte/Kk6ubmj9E0n7U/B4keCxxHiJZqW/5Rqg==} + /turbo-darwin-64@1.8.8: + resolution: {integrity: sha512-18cSeIm7aeEvIxGyq7PVoFyEnPpWDM/0CpZvXKHpQ6qMTkfNt517qVqUTAwsIYqNS8xazcKAqkNbvU1V49n65Q==} cpu: [x64] os: [darwin] requiresBuild: true dev: true optional: true - /turbo-darwin-arm64@1.8.6: - resolution: {integrity: sha512-w4L2QLj90ex68UXxTPoqtZPl8mWzc6a1RtPjQhoxAWtZf9T2WXi813dCzYEbVUVC09/DOW/VxZRN7sb2r0KP9A==} + /turbo-darwin-arm64@1.8.8: + resolution: {integrity: sha512-ruGRI9nHxojIGLQv1TPgN7ud4HO4V8mFBwSgO6oDoZTNuk5ybWybItGR+yu6fni5vJoyMHXOYA2srnxvOc7hjQ==} cpu: [arm64] os: [darwin] requiresBuild: true dev: true optional: true - /turbo-linux-64@1.8.6: - resolution: {integrity: sha512-eV245jefIhMAZskqQKalFwreC5UEdQcuHcBiWcgUk0py76fbwB7+1HfH5cmeJlb3a1sB6f3H0HHmGPmb34feCA==} + /turbo-linux-64@1.8.8: + resolution: {integrity: sha512-N/GkHTHeIQogXB1/6ZWfxHx+ubYeb8Jlq3b/3jnU4zLucpZzTQ8XkXIAfJG/TL3Q7ON7xQ8yGOyGLhHL7MpFRg==} cpu: [x64] os: [linux] requiresBuild: true dev: true optional: true - /turbo-linux-arm64@1.8.6: - resolution: {integrity: sha512-Kiw3nyEvNU6Bpil4zE5FwhasPAOi59R4YdCmjJp0Sen6V9u+/Jij6SWwaoUdATORJLiYQBbhontWBH55B53VDw==} + /turbo-linux-arm64@1.8.8: + resolution: {integrity: sha512-hKqLbBHgUkYf2Ww8uBL9UYdBFQ5677a7QXdsFhONXoACbDUPvpK4BKlz3NN7G4NZ+g9dGju+OJJjQP0VXRHb5w==} cpu: [arm64] os: [linux] requiresBuild: true dev: true optional: true - /turbo-windows-64@1.8.6: - resolution: {integrity: sha512-34BkAG9r4nE00xeMeVahaF82h8R6SO+IIOcD60fNr2p+Ch+YcQa+DbEWA/KUj3coUTIiNP5XnRCLRUYADdlxjQ==} + /turbo-windows-64@1.8.8: + resolution: {integrity: sha512-2ndjDJyzkNslXxLt+PQuU21AHJWc8f6MnLypXy3KsN4EyX/uKKGZS0QJWz27PeHg0JS75PVvhfFV+L9t9i+Yyg==} cpu: [x64] os: [win32] requiresBuild: true dev: true optional: true - /turbo-windows-arm64@1.8.6: - resolution: {integrity: sha512-4jWUaI7Lmonp2I3x81GruiCYd0aQsG/xDOYhuv9+j2yIgB/UHJFz/P8PWp/nziwPtGpRd/AheDlPzzyd9lWoqw==} + /turbo-windows-arm64@1.8.8: + resolution: {integrity: sha512-xCA3oxgmW9OMqpI34AAmKfOVsfDljhD5YBwgs0ZDsn5h3kCHhC4x9W5dDk1oyQ4F5EXSH3xVym5/xl1J6WRpUg==} cpu: [arm64] os: [win32] requiresBuild: true dev: true optional: true - /turbo@1.8.6: - resolution: {integrity: sha512-6IOOaa8ytgjnSCTnp3LKAd2uGBZ/Kmx8ZPlI/YMWuKMUqvkXKLbh+w76ApMgMm+faUqti+QujVWovCu2kY6KuQ==} + /turbo@1.8.8: + resolution: {integrity: sha512-qYJ5NjoTX+591/x09KgsDOPVDUJfU9GoS+6jszQQlLp1AHrf1wRFA3Yps8U+/HTG03q0M4qouOfOLtRQP4QypA==} hasBin: true requiresBuild: true optionalDependencies: - turbo-darwin-64: 1.8.6 - turbo-darwin-arm64: 1.8.6 - turbo-linux-64: 1.8.6 - turbo-linux-arm64: 1.8.6 - turbo-windows-64: 1.8.6 - turbo-windows-arm64: 1.8.6 + turbo-darwin-64: 1.8.8 + turbo-darwin-arm64: 1.8.8 + turbo-linux-64: 1.8.8 + turbo-linux-arm64: 1.8.8 + turbo-windows-64: 1.8.8 + turbo-windows-arm64: 1.8.8 dev: true /type-check@0.3.2: @@ -13178,7 +13276,7 @@ packages: vite: 4.2.1(@types/node@18.13.0)(sass@1.59.3) dev: true - /vite-plugin-sass-dts@1.3.2(postcss@8.4.21)(prettier@2.8.7)(sass@1.59.3)(vite@4.2.1): + /vite-plugin-sass-dts@1.3.2(postcss@8.4.21)(prettier@2.8.8)(sass@1.59.3)(vite@4.2.1): resolution: {integrity: sha512-zClOXVLQHKG//aZ+gsDXMnhLLVKJprrv3x+KQBf/8GD/dM4FHmlK4zMM5JcOr12oq3kTz+DUYCtCEYsFY8eDPQ==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -13189,7 +13287,7 @@ packages: dependencies: postcss: 8.4.21 postcss-js: 4.0.1(postcss@8.4.21) - prettier: 2.8.7 + prettier: 2.8.8 sass: 1.59.3 vite: 4.2.1(@types/node@18.13.0)(sass@1.59.3) dev: true