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';