-
Notifications
You must be signed in to change notification settings - Fork 239
feat(workspaces): Save and restore tabs COMPASS-9499 #7253
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 36 commits
68b9e53
a9ea81e
fc3f50c
5932624
8cd1ac5
b5c6f66
b308225
a5713b4
2351763
619362d
25cf5e6
e3876f9
8908793
920f572
aa78f68
42a15e0
9736436
3fd3b6b
04b30c3
321a649
b667dd5
27bae4b
0d14953
2932698
88c8435
da2be3e
b2eb338
9f9bab3
b0af4d9
992f191
13e2c7d
097a002
4f1d184
5aeb75d
ef2d42e
a7df6a5
76ae816
a6d7db9
139f4f4
e4f9a7a
dec0e41
cac3263
a8c7218
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| export type { ReadAllResult } from './user-data'; | ||
| export { type IUserData, FileUserData, AtlasUserData } from './user-data'; | ||
| export { IUserData, FileUserData, AtlasUserData } from './user-data'; | ||
| export { z } from 'zod'; |
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see this file ever being used, why did you added it? |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| export { WorkspacesStorageServiceProviderDesktop } from './workspaces-storage-desktop'; | ||
| export { WorkspacesStorageServiceProviderWeb } from './workspaces-storage-web'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| import React, { useRef } from 'react'; | ||
| import { FileUserData, type IUserData } from '@mongodb-js/compass-user-data'; | ||
| import { | ||
| WorkspacesStateSchema, | ||
| WorkspacesStorageServiceContext, | ||
| } from './workspaces-storage'; | ||
| import { EJSON } from 'bson'; | ||
|
|
||
| export const WorkspacesStorageServiceProviderDesktop: React.FunctionComponent = | ||
| ({ children }) => { | ||
| const storageRef = useRef<IUserData<typeof WorkspacesStateSchema>>( | ||
| new FileUserData(WorkspacesStateSchema, 'WorkspacesState', { | ||
| serialize: (content) => EJSON.stringify(content, undefined, 2), | ||
| deserialize: (content: string) => EJSON.parse(content), | ||
syn-zhu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| }) as IUserData<typeof WorkspacesStateSchema> | ||
| ); | ||
| return ( | ||
| <WorkspacesStorageServiceContext.Provider value={storageRef.current}> | ||
| {children} | ||
| </WorkspacesStorageServiceContext.Provider> | ||
| ); | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| import React, { useRef } from 'react'; | ||
| import { AtlasUserData, type IUserData } from '@mongodb-js/compass-user-data'; | ||
| import { | ||
| WorkspacesStateSchema, | ||
| WorkspacesStorageServiceContext, | ||
| } from './workspaces-storage'; | ||
| import { EJSON } from 'bson'; | ||
|
|
||
| export const WorkspacesStorageServiceProviderWeb: React.FunctionComponent<{ | ||
| orgId: string; | ||
| projectId: string; | ||
| getResourceUrl: (path?: string) => string; | ||
| authenticatedFetch: ( | ||
| url: RequestInfo | URL, | ||
| options?: RequestInit | ||
| ) => Promise<Response>; | ||
| }> = ({ orgId, projectId, getResourceUrl, authenticatedFetch, children }) => { | ||
| const storageRef = useRef<IUserData<typeof WorkspacesStateSchema>>( | ||
| new AtlasUserData(WorkspacesStateSchema, 'WorkspacesState', { | ||
| orgId, | ||
| projectId, | ||
| getResourceUrl, | ||
| authenticatedFetch, | ||
| serialize: (content) => EJSON.stringify(content), | ||
| deserialize: (content: string) => EJSON.parse(content), | ||
syn-zhu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| }) | ||
| ); | ||
| return ( | ||
| <WorkspacesStorageServiceContext.Provider value={storageRef.current}> | ||
| {children} | ||
| </WorkspacesStorageServiceContext.Provider> | ||
| ); | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| import { createServiceLocator } from '@mongodb-js/compass-app-registry'; | ||
| import { | ||
| IUserData, | ||
| type ReadAllResult, | ||
| z, | ||
| } from '@mongodb-js/compass-user-data'; | ||
| import React, { useContext, useRef } from 'react'; | ||
|
|
||
| /** | ||
| * Schema for saving workspace tab state to user data | ||
| */ | ||
|
|
||
| // Define schema for collection subtab | ||
|
||
| const CollectionSubtabSchema = z.enum([ | ||
| 'Documents', | ||
| 'Aggregations', | ||
| 'Schema', | ||
| 'Indexes', | ||
| 'Validation', | ||
| 'GlobalWrites', | ||
| ]); | ||
|
|
||
| // Define schema for workspace tab type | ||
| const WorkspaceTabTypeSchema = z.enum([ | ||
| 'Welcome', | ||
| 'My Queries', | ||
| 'Data Modeling', | ||
| 'Shell', | ||
| 'Databases', | ||
| 'Performance', | ||
| 'Collections', | ||
| 'Collection', | ||
| ]); | ||
|
|
||
| // Define schema for a workspace tab | ||
| export const WorkspaceTabSchema = z.object({ | ||
| id: z.string(), | ||
| type: WorkspaceTabTypeSchema, | ||
| connectionId: z.string().optional(), | ||
| namespace: z.string().optional(), | ||
| initialQuery: z.record(z.any()).optional(), | ||
| initialAggregation: z.record(z.any()).optional(), | ||
| initialPipeline: z.array(z.record(z.any())).optional(), | ||
| initialPipelineText: z.string().optional(), | ||
| editViewName: z.string().optional(), | ||
| initialEvaluate: z.union([z.string(), z.array(z.string())]).optional(), | ||
| initialInput: z.string().optional(), | ||
| subTab: CollectionSubtabSchema.optional(), | ||
| }); | ||
|
||
|
|
||
| // Define schema for the complete workspaces state | ||
| export const WorkspacesStateSchema = z.object({ | ||
| tabs: z.array(WorkspaceTabSchema), | ||
| activeTabId: z.string().nullable(), | ||
| timestamp: z.number(), | ||
| }); | ||
|
|
||
| // TypeScript types derived from the schemas | ||
| export type WorkspaceTabData = z.output<typeof WorkspaceTabSchema>; | ||
| export type WorkspacesStateData = z.output<typeof WorkspacesStateSchema>; | ||
|
|
||
| const throwIfNotTestEnv = () => { | ||
| if (process.env.NODE_ENV !== 'test') { | ||
| throw new Error("Can't find Workspaces storage service in React context"); | ||
| } | ||
| }; | ||
|
|
||
| export class noopUserData<T extends z.Schema> extends IUserData<T> { | ||
| write(): Promise<boolean> { | ||
| throwIfNotTestEnv(); | ||
| return Promise.resolve(true); | ||
| } | ||
| delete(): Promise<boolean> { | ||
| throwIfNotTestEnv(); | ||
| return Promise.resolve(true); | ||
| } | ||
| readAll(): Promise<ReadAllResult<T>> { | ||
| throwIfNotTestEnv(); | ||
| return Promise.resolve({ data: [], errors: [] }); | ||
| } | ||
| readOne(): Promise<z.output<T>> { | ||
| throwIfNotTestEnv(); | ||
| return Promise.resolve(undefined); | ||
| } | ||
| updateAttributes(): Promise<boolean> { | ||
| throwIfNotTestEnv(); | ||
| return Promise.resolve(true); | ||
| } | ||
| } | ||
|
|
||
| export const noopWorkspacesStorageService: IUserData< | ||
| typeof WorkspacesStateSchema | ||
| > = new noopUserData(WorkspacesStateSchema, 'WorkspacesState'); | ||
|
|
||
| export const WorkspacesStorageServiceContext = React.createContext< | ||
| IUserData<typeof WorkspacesStateSchema> | ||
| >(noopWorkspacesStorageService); | ||
|
|
||
| export const workspacesStorageServiceLocator = createServiceLocator(() => { | ||
| const service = useContext(WorkspacesStorageServiceContext); | ||
| return service; | ||
| }, 'workspacesStorageServiceLocator'); | ||
Uh oh!
There was an error while loading. Please reload this page.