forked from opensearch-project/OpenSearch-Dashboards
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add core workspace module (#145)
The core workspace module(WorkspaceService) is a foundational component that enables the implementation of workspace features within OSD plugins. The purpose of the core workspace module is to provide a framework for workspace implementations. This module does not implement specific workspace functionality but provides the essential infrastructure for plugins to extend and customize workspace features, it maintains a shared workspace state(observables) across the entire application to ensure a consistent and up-to-date view of workspace-related information to all parts of the application. --------- Signed-off-by: Yulong Ruan <ruanyl@amazon.com>
- Loading branch information
Showing
11 changed files
with
741 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
export { | ||
WorkspacesStart, | ||
WorkspacesService, | ||
WorkspacesSetup, | ||
WorkspaceObservables, | ||
} from './workspaces_service'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import { BehaviorSubject } from 'rxjs'; | ||
import { WorkspaceAttribute } from '..'; | ||
|
||
const currentWorkspaceId$ = new BehaviorSubject<string>(''); | ||
const workspaceList$ = new BehaviorSubject<WorkspaceAttribute[]>([]); | ||
const currentWorkspace$ = new BehaviorSubject<WorkspaceAttribute | null>(null); | ||
const initialized$ = new BehaviorSubject<boolean>(false); | ||
const workspaceEnabled$ = new BehaviorSubject<boolean>(false); | ||
|
||
const createWorkspacesSetupContractMock = () => ({ | ||
currentWorkspaceId$, | ||
workspaceList$, | ||
currentWorkspace$, | ||
initialized$, | ||
workspaceEnabled$, | ||
registerWorkspaceMenuRender: jest.fn(), | ||
}); | ||
|
||
const createWorkspacesStartContractMock = () => ({ | ||
currentWorkspaceId$, | ||
workspaceList$, | ||
currentWorkspace$, | ||
initialized$, | ||
workspaceEnabled$, | ||
renderWorkspaceMenu: jest.fn(), | ||
}); | ||
|
||
export const workspacesServiceMock = { | ||
createSetupContractMock: createWorkspacesSetupContractMock, | ||
createStartContract: createWorkspacesStartContractMock, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import { BehaviorSubject, combineLatest } from 'rxjs'; | ||
import { isEqual } from 'lodash'; | ||
|
||
import { CoreService, WorkspaceAttribute } from '../../types'; | ||
import { InternalApplicationStart } from '../application'; | ||
import { HttpSetup } from '../http'; | ||
|
||
type WorkspaceMenuRenderFn = ({ | ||
basePath, | ||
getUrlForApp, | ||
observables, | ||
}: { | ||
getUrlForApp: InternalApplicationStart['getUrlForApp']; | ||
basePath: HttpSetup['basePath']; | ||
observables: WorkspaceObservables; | ||
}) => JSX.Element | null; | ||
|
||
type WorkspaceObject = WorkspaceAttribute & { readonly?: boolean }; | ||
|
||
export interface WorkspaceObservables { | ||
currentWorkspaceId$: BehaviorSubject<string>; | ||
currentWorkspace$: BehaviorSubject<WorkspaceObject | null>; | ||
workspaceList$: BehaviorSubject<WorkspaceObject[]>; | ||
workspaceEnabled$: BehaviorSubject<boolean>; | ||
initialized$: BehaviorSubject<boolean>; | ||
} | ||
|
||
enum WORKSPACE_ERROR { | ||
WORKSPACE_STALED = 'WORKSPACE_STALED', | ||
} | ||
|
||
/** | ||
* @public | ||
*/ | ||
export interface WorkspacesSetup extends WorkspaceObservables { | ||
registerWorkspaceMenuRender: (render: WorkspaceMenuRenderFn) => void; | ||
} | ||
|
||
export interface WorkspacesStart extends WorkspaceObservables { | ||
renderWorkspaceMenu: () => JSX.Element | null; | ||
} | ||
|
||
export class WorkspacesService implements CoreService<WorkspacesSetup, WorkspacesStart> { | ||
private currentWorkspaceId$ = new BehaviorSubject<string>(''); | ||
private workspaceList$ = new BehaviorSubject<WorkspaceObject[]>([]); | ||
private currentWorkspace$ = new BehaviorSubject<WorkspaceObject | null>(null); | ||
private initialized$ = new BehaviorSubject<boolean>(false); | ||
private workspaceEnabled$ = new BehaviorSubject<boolean>(false); | ||
private _renderWorkspaceMenu: WorkspaceMenuRenderFn | null = null; | ||
|
||
constructor() { | ||
combineLatest([this.initialized$, this.workspaceList$, this.currentWorkspaceId$]).subscribe( | ||
([workspaceInitialized, workspaceList, currentWorkspaceId]) => { | ||
if (workspaceInitialized) { | ||
const currentWorkspace = workspaceList.find((w) => w && w.id === currentWorkspaceId); | ||
|
||
/** | ||
* Do a simple idempotent verification here | ||
*/ | ||
if (!isEqual(currentWorkspace, this.currentWorkspace$.getValue())) { | ||
this.currentWorkspace$.next(currentWorkspace ?? null); | ||
} | ||
|
||
if (currentWorkspaceId && !currentWorkspace?.id) { | ||
/** | ||
* Current workspace is staled | ||
*/ | ||
this.currentWorkspaceId$.error({ | ||
reason: WORKSPACE_ERROR.WORKSPACE_STALED, | ||
}); | ||
this.currentWorkspace$.error({ | ||
reason: WORKSPACE_ERROR.WORKSPACE_STALED, | ||
}); | ||
} | ||
} | ||
} | ||
); | ||
} | ||
|
||
public setup(): WorkspacesSetup { | ||
return { | ||
currentWorkspaceId$: this.currentWorkspaceId$, | ||
currentWorkspace$: this.currentWorkspace$, | ||
workspaceList$: this.workspaceList$, | ||
initialized$: this.initialized$, | ||
workspaceEnabled$: this.workspaceEnabled$, | ||
registerWorkspaceMenuRender: (render: WorkspaceMenuRenderFn) => | ||
(this._renderWorkspaceMenu = render), | ||
}; | ||
} | ||
|
||
public start({ | ||
http, | ||
application, | ||
}: { | ||
application: InternalApplicationStart; | ||
http: HttpSetup; | ||
}): WorkspacesStart { | ||
const observables = { | ||
currentWorkspaceId$: this.currentWorkspaceId$, | ||
currentWorkspace$: this.currentWorkspace$, | ||
workspaceList$: this.workspaceList$, | ||
initialized$: this.initialized$, | ||
workspaceEnabled$: this.workspaceEnabled$, | ||
}; | ||
return { | ||
...observables, | ||
renderWorkspaceMenu: () => { | ||
if (this._renderWorkspaceMenu) { | ||
return this._renderWorkspaceMenu({ | ||
basePath: http.basePath, | ||
getUrlForApp: application.getUrlForApp, | ||
observables, | ||
}); | ||
} | ||
return null; | ||
}, | ||
}; | ||
} | ||
|
||
public async stop() { | ||
this.currentWorkspace$.unsubscribe(); | ||
this.currentWorkspaceId$.unsubscribe(); | ||
this.workspaceList$.unsubscribe(); | ||
this.workspaceEnabled$.unsubscribe(); | ||
this.initialized$.unsubscribe(); | ||
this._renderWorkspaceMenu = null; | ||
} | ||
} |
Oops, something went wrong.