diff --git a/frontend/svalyn-studio-app/src/app/App.tsx b/frontend/svalyn-studio-app/src/app/App.tsx index 535bcee..1f13bef 100644 --- a/frontend/svalyn-studio-app/src/app/App.tsx +++ b/frontend/svalyn-studio-app/src/app/App.tsx @@ -35,7 +35,6 @@ import { ProfilesRouter } from '../profiles/ProfilesRouter'; import { ProjectRouter } from '../projects/ProjectRouter'; import { SearchRouter } from '../search/SearchRouter'; import { SettingsRouter } from '../settings/SettingsRouter'; -import { WorkspaceView } from '../workspace/WorkspaceView'; export const App = () => { return ( @@ -45,7 +44,6 @@ export const App = () => { } /> } /> } /> - } /> } /> } /> } /> diff --git a/frontend/svalyn-studio-app/src/projects/ProjectProvider.tsx b/frontend/svalyn-studio-app/src/projects/ProjectProvider.tsx new file mode 100644 index 0000000..20e692e --- /dev/null +++ b/frontend/svalyn-studio-app/src/projects/ProjectProvider.tsx @@ -0,0 +1,87 @@ +/* + * 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 { gql, useQuery } from '@apollo/client'; +import CorporateFareIcon from '@mui/icons-material/CorporateFare'; +import { useSnackbar } from 'notistack'; +import { useEffect } from 'react'; +import { useParams } from 'react-router-dom'; +import { NotFoundView } from '../notfound/NotFoundView'; +import { goToDomains, goToHelp, goToHome, goToNotifications, goToSettings } from '../palette/DefaultPaletteActions'; +import { PaletteNavigationAction } from '../palette/Palette.types'; +import { usePalette } from '../palette/usePalette'; +import { GetProjectData, GetProjectVariables, ProjectProviderProps } from './ProjectProvider.types'; +import { ProjectContext } from './useProject'; + +const getProjectQuery = gql` + query getProject($identifier: ID!) { + viewer { + project(identifier: $identifier) { + identifier + name + description + organization { + identifier + name + role + } + } + } + } +`; + +export const ProjectProvider = ({ children }: ProjectProviderProps) => { + const { projectIdentifier } = useParams(); + + const { enqueueSnackbar } = useSnackbar(); + const { setActions } = usePalette(); + + const variables: GetProjectVariables = { identifier: projectIdentifier ?? '' }; + const { data, error } = useQuery(getProjectQuery, { variables }); + + useEffect(() => { + if (data) { + const { + viewer: { project }, + } = data; + if (project) { + const backToOrganization: PaletteNavigationAction = { + type: 'navigation-action', + id: 'go-to-organization', + icon: , + label: project.organization.name, + to: `/orgs/${project.organization.identifier}`, + }; + setActions([goToHome, backToOrganization, goToDomains, goToNotifications, goToSettings, goToHelp]); + } + } + if (error) { + enqueueSnackbar(error.message, { variant: 'error' }); + } + }, [data, error]); + + if (!data) { + return null; + } + if (!data.viewer.project) { + return ; + } + + return {children}; +}; diff --git a/frontend/svalyn-studio-app/src/projects/ProjectProvider.types.ts b/frontend/svalyn-studio-app/src/projects/ProjectProvider.types.ts new file mode 100644 index 0000000..7d55fe1 --- /dev/null +++ b/frontend/svalyn-studio-app/src/projects/ProjectProvider.types.ts @@ -0,0 +1,49 @@ +/* + * 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 ProjectProviderProps { + children?: React.ReactNode; +} + +export interface GetProjectData { + viewer: Viewer; +} + +export interface Viewer { + project: Project | null; +} + +export interface Project { + identifier: string; + name: string; + description: string; + organization: Organization; +} + +export interface Organization { + identifier: string; + name: string; + role: MembershipRole; +} + +export type MembershipRole = 'ADMIN' | 'MEMBER' | 'NONE'; + +export interface GetProjectVariables { + identifier: string; +} diff --git a/frontend/svalyn-studio-app/src/projects/ProjectRouter.tsx b/frontend/svalyn-studio-app/src/projects/ProjectRouter.tsx index 86796f1..7fb7b8e 100644 --- a/frontend/svalyn-studio-app/src/projects/ProjectRouter.tsx +++ b/frontend/svalyn-studio-app/src/projects/ProjectRouter.tsx @@ -18,6 +18,7 @@ */ import { Route, Routes } from 'react-router-dom'; +import { ProjectProvider } from './ProjectProvider'; import { ProjectShell } from './ProjectShell'; import { ProjectActivityView } from './activity/ProjectActivityView'; import { ChangeProposalRouter } from './changeproposal/ChangeProposalRouter'; @@ -27,21 +28,31 @@ import { NewChangeProposalView } from './new-changeproposal/NewChangeProposalVie import { ResourceView } from './resource/ResourceView'; import { ProjectSettingsView } from './settings/ProjectSettingsView'; import { ProjectTagsView } from './tags/ProjectTagsView'; +import { WorkspaceView } from './workspace/WorkspaceView'; export const ProjectRouter = () => { return ( - + - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> + + + + + + + + + } /> + + + ); +}; + +const withProjectShell = (Component: () => JSX.Element | null) => { + return ( + + ); }; diff --git a/frontend/svalyn-studio-app/src/projects/ProjectShell.tsx b/frontend/svalyn-studio-app/src/projects/ProjectShell.tsx index 0b3ee3c..6747aa6 100644 --- a/frontend/svalyn-studio-app/src/projects/ProjectShell.tsx +++ b/frontend/svalyn-studio-app/src/projects/ProjectShell.tsx @@ -17,95 +17,29 @@ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { gql, useQuery } from '@apollo/client'; -import CorporateFareIcon from '@mui/icons-material/CorporateFare'; import Box from '@mui/material/Box'; -import { useSnackbar } from 'notistack'; -import { useEffect } from 'react'; -import { useParams } from 'react-router-dom'; import { Navbar } from '../navbars/Navbar'; -import { NotFoundView } from '../notfound/NotFoundView'; -import { goToDomains, goToHelp, goToHome, goToNotifications, goToSettings } from '../palette/DefaultPaletteActions'; -import { PaletteNavigationAction } from '../palette/Palette.types'; -import { usePalette } from '../palette/usePalette'; import { ProjectBreadcrumbs } from './ProjectBreadcrumbs'; import { ProjectDrawer } from './ProjectDrawer'; -import { GetProjectData, GetProjectVariables, ProjectShellProps } from './ProjectShell.types'; -import { ProjectContext } from './useProject'; - -const getProjectQuery = gql` - query getProject($identifier: ID!) { - viewer { - project(identifier: $identifier) { - identifier - name - description - organization { - identifier - name - role - } - } - } - } -`; +import { ProjectShellProps } from './ProjectShell.types'; export const ProjectShell = ({ children }: ProjectShellProps) => { - const { enqueueSnackbar } = useSnackbar(); - - const { projectIdentifier } = useParams(); - const variables: GetProjectVariables = { identifier: projectIdentifier ?? '' }; - const { data, error } = useQuery(getProjectQuery, { variables }); - - const { setActions } = usePalette(); - - useEffect(() => { - if (data) { - const { - viewer: { project }, - } = data; - if (project) { - const backToOrganization: PaletteNavigationAction = { - type: 'navigation-action', - id: 'go-to-organization', - icon: , - label: project.organization.name, - to: `/orgs/${project.organization.identifier}`, - }; - setActions([goToHome, backToOrganization, goToDomains, goToNotifications, goToSettings, goToHelp]); - } - } - if (error) { - enqueueSnackbar(error.message, { variant: 'error' }); - } - }, [data, error]); - - if (!data) { - return null; - } - - if (!data.viewer.project) { - return ; - } - return ( - - - - - - - - {children} - + + + + + + + {children} - + ); }; diff --git a/frontend/svalyn-studio-app/src/projects/ProjectShell.types.ts b/frontend/svalyn-studio-app/src/projects/ProjectShell.types.ts index 7a41984..d8b1883 100644 --- a/frontend/svalyn-studio-app/src/projects/ProjectShell.types.ts +++ b/frontend/svalyn-studio-app/src/projects/ProjectShell.types.ts @@ -20,30 +20,3 @@ export interface ProjectShellProps { children?: React.ReactNode; } - -export interface GetProjectData { - viewer: Viewer; -} - -export interface Viewer { - project: Project | null; -} - -export interface Project { - identifier: string; - name: string; - description: string; - organization: Organization; -} - -export interface Organization { - identifier: string; - name: string; - role: MembershipRole; -} - -export type MembershipRole = 'ADMIN' | 'MEMBER' | 'NONE'; - -export interface GetProjectVariables { - identifier: string; -} diff --git a/frontend/svalyn-studio-app/src/workspace/WorkspaceView.tsx b/frontend/svalyn-studio-app/src/projects/workspace/WorkspaceView.tsx similarity index 90% rename from frontend/svalyn-studio-app/src/workspace/WorkspaceView.tsx rename to frontend/svalyn-studio-app/src/projects/workspace/WorkspaceView.tsx index a6cc7c2..0418c5d 100644 --- a/frontend/svalyn-studio-app/src/workspace/WorkspaceView.tsx +++ b/frontend/svalyn-studio-app/src/projects/workspace/WorkspaceView.tsx @@ -22,11 +22,11 @@ import Box from '@mui/material/Box'; import { useSnackbar } from 'notistack'; import { useEffect } from 'react'; import { useParams } from 'react-router-dom'; -import { Workbench } from '../workbench/Workbench'; -import { IEditingContext } from '../workbench/api/editingcontext/EditingContext.types'; -import { EditingContextProvider } from '../workbench/api/editingcontext/EditingContextProvider'; -import { IAdaptable, IAdapterFactory } from '../workbench/api/providers/AdapterFactory.types'; -import { AdapterFactoryProvider } from '../workbench/api/providers/AdapterFactoryProvider'; +import { Workbench } from '../../workbench/Workbench'; +import { IEditingContext } from '../../workbench/api/editingcontext/EditingContext.types'; +import { EditingContextProvider } from '../../workbench/api/editingcontext/EditingContextProvider'; +import { IAdaptable, IAdapterFactory } from '../../workbench/api/providers/AdapterFactory.types'; +import { AdapterFactoryProvider } from '../../workbench/api/providers/AdapterFactoryProvider'; import { Change, GetChangeResourcesData, GetChangeResourcesVariables } from './WorkspaceView.types'; import { ChangeData, ChangeDataItemProvider } from './data/ChangeData'; import { FileData, FileDataItemProvider } from './data/FileData'; diff --git a/frontend/svalyn-studio-app/src/workspace/WorkspaceView.types.ts b/frontend/svalyn-studio-app/src/projects/workspace/WorkspaceView.types.ts similarity index 100% rename from frontend/svalyn-studio-app/src/workspace/WorkspaceView.types.ts rename to frontend/svalyn-studio-app/src/projects/workspace/WorkspaceView.types.ts diff --git a/frontend/svalyn-studio-app/src/workspace/data/ChangeData.ts b/frontend/svalyn-studio-app/src/projects/workspace/data/ChangeData.ts similarity index 94% rename from frontend/svalyn-studio-app/src/workspace/data/ChangeData.ts rename to frontend/svalyn-studio-app/src/projects/workspace/data/ChangeData.ts index 14de857..92f0a3f 100644 --- a/frontend/svalyn-studio-app/src/workspace/data/ChangeData.ts +++ b/frontend/svalyn-studio-app/src/projects/workspace/data/ChangeData.ts @@ -18,14 +18,14 @@ */ import { ReactNode } from 'react'; -import { IAdaptable } from '../../workbench/api/providers/AdapterFactory.types'; +import { IAdaptable } from '../../../workbench/api/providers/AdapterFactory.types'; import { IItemIdentityProvider, IItemLabelProvider, IItemViewProvider, ITreeItemContentProvider, ViewContent, -} from '../../workbench/api/providers/ItemProviders.types'; +} from '../../../workbench/api/providers/ItemProviders.types'; import { IContainerData, IResourceData } from './ResourceData'; export class ChangeData implements IContainerData { diff --git a/frontend/svalyn-studio-app/src/workspace/data/FileData.ts b/frontend/svalyn-studio-app/src/projects/workspace/data/FileData.ts similarity index 96% rename from frontend/svalyn-studio-app/src/workspace/data/FileData.ts rename to frontend/svalyn-studio-app/src/projects/workspace/data/FileData.ts index 15bba33..9ce8611 100644 --- a/frontend/svalyn-studio-app/src/workspace/data/FileData.ts +++ b/frontend/svalyn-studio-app/src/projects/workspace/data/FileData.ts @@ -19,14 +19,14 @@ import { ApolloClient, gql } from '@apollo/client'; import { ReactNode } from 'react'; -import { IAdaptable } from '../../workbench/api/providers/AdapterFactory.types'; +import { IAdaptable } from '../../../workbench/api/providers/AdapterFactory.types'; import { IItemIdentityProvider, IItemLabelProvider, IItemViewProvider, ITreeItemContentProvider, ViewContent, -} from '../../workbench/api/providers/ItemProviders.types'; +} from '../../../workbench/api/providers/ItemProviders.types'; import { IContainerData, IResourceData } from './ResourceData'; export class FileData implements IResourceData { diff --git a/frontend/svalyn-studio-app/src/workspace/data/FolderData.ts b/frontend/svalyn-studio-app/src/projects/workspace/data/FolderData.ts similarity index 94% rename from frontend/svalyn-studio-app/src/workspace/data/FolderData.ts rename to frontend/svalyn-studio-app/src/projects/workspace/data/FolderData.ts index e9ac7c6..969655c 100644 --- a/frontend/svalyn-studio-app/src/workspace/data/FolderData.ts +++ b/frontend/svalyn-studio-app/src/projects/workspace/data/FolderData.ts @@ -18,14 +18,14 @@ */ import { ReactNode } from 'react'; -import { IAdaptable } from '../../workbench/api/providers/AdapterFactory.types'; +import { IAdaptable } from '../../../workbench/api/providers/AdapterFactory.types'; import { IItemIdentityProvider, IItemLabelProvider, IItemViewProvider, ITreeItemContentProvider, ViewContent, -} from '../../workbench/api/providers/ItemProviders.types'; +} from '../../../workbench/api/providers/ItemProviders.types'; import { IContainerData, IResourceData } from './ResourceData'; export class FolderData implements IContainerData { diff --git a/frontend/svalyn-studio-app/src/workspace/data/ResourceData.ts b/frontend/svalyn-studio-app/src/projects/workspace/data/ResourceData.ts similarity index 93% rename from frontend/svalyn-studio-app/src/workspace/data/ResourceData.ts rename to frontend/svalyn-studio-app/src/projects/workspace/data/ResourceData.ts index 868a7d4..5eb8984 100644 --- a/frontend/svalyn-studio-app/src/workspace/data/ResourceData.ts +++ b/frontend/svalyn-studio-app/src/projects/workspace/data/ResourceData.ts @@ -17,7 +17,7 @@ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { IAdaptable } from '../../workbench/api/providers/AdapterFactory.types'; +import { IAdaptable } from '../../../workbench/api/providers/AdapterFactory.types'; export interface IResourceData extends IAdaptable { container: IContainerData | null; diff --git a/frontend/svalyn-studio-app/src/workspace/data/SingleChangeEditingContextData.ts b/frontend/svalyn-studio-app/src/projects/workspace/data/SingleChangeEditingContextData.ts similarity index 91% rename from frontend/svalyn-studio-app/src/workspace/data/SingleChangeEditingContextData.ts rename to frontend/svalyn-studio-app/src/projects/workspace/data/SingleChangeEditingContextData.ts index fbc06c7..c31935f 100644 --- a/frontend/svalyn-studio-app/src/workspace/data/SingleChangeEditingContextData.ts +++ b/frontend/svalyn-studio-app/src/projects/workspace/data/SingleChangeEditingContextData.ts @@ -18,15 +18,15 @@ */ import { ReactNode } from 'react'; -import { IEditingContext } from '../../workbench/api/editingcontext/EditingContext.types'; -import { IAdaptable } from '../../workbench/api/providers/AdapterFactory.types'; +import { IEditingContext } from '../../../workbench/api/editingcontext/EditingContext.types'; +import { IAdaptable } from '../../../workbench/api/providers/AdapterFactory.types'; import { IItemIdentityProvider, IItemLabelProvider, IItemViewProvider, ITreeItemContentProvider, ViewContent, -} from '../../workbench/api/providers/ItemProviders.types'; +} from '../../../workbench/api/providers/ItemProviders.types'; import { ChangeData } from './ChangeData'; export class SingleChangeEditingContextData implements IEditingContext { diff --git a/frontend/svalyn-studio-app/src/viewers/ViewerCard.tsx b/frontend/svalyn-studio-app/src/viewers/ViewerCard.tsx index d66bfe3..72a4b8c 100644 --- a/frontend/svalyn-studio-app/src/viewers/ViewerCard.tsx +++ b/frontend/svalyn-studio-app/src/viewers/ViewerCard.tsx @@ -24,9 +24,9 @@ import Divider from '@mui/material/Divider'; import IconButton from '@mui/material/IconButton'; import Paper from '@mui/material/Paper'; import Typography from '@mui/material/Typography'; +import { FileData, FileDataItemProvider } from '../projects/workspace/data/FileData'; import { IAdaptable, IAdapterFactory } from '../workbench/api/providers/AdapterFactory.types'; import { AdapterFactoryProvider } from '../workbench/api/providers/AdapterFactoryProvider'; -import { FileData, FileDataItemProvider } from '../workspace/data/FileData'; import { Viewer } from './Viewer'; import { ViewerCardProps } from './ViewerCard.types';