From 7130b3c7bd6103d670a3941bcebdbcc302d27894 Mon Sep 17 00:00:00 2001 From: SuZhoue-Joe Date: Thu, 29 Jun 2023 14:32:55 +0800 Subject: [PATCH] feat: make url stateful Signed-off-by: SuZhoue-Joe feat: optimize code Signed-off-by: SuZhoue-Joe feat: remove useless change Signed-off-by: SuZhoue-Joe feat: optimize url listener Signed-off-by: SuZhoue-Joe feat: make formatUrlWithWorkspaceId extensible Signed-off-by: SuZhoue-Joe feat: modify the async format to be sync function Signed-off-by: SuZhoue-Joe feat: use path to maintain workspace info Signed-off-by: SuZhou-Joe feat: optimize code Signed-off-by: SuZhou-Joe feat: optimize code Signed-off-by: SuZhou-Joe feat: optimize code Signed-off-by: SuZhou-Joe feat: optimize code Signed-off-by: SuZhou-Joe feat: optimize code Signed-off-by: SuZhou-Joe feat: optimize code Signed-off-by: SuZhou-Joe feat: format Signed-off-by: SuZhou-Joe feat: format Signed-off-by: SuZhou-Joe feat: format Signed-off-by: SuZhou-Joe feat: format Signed-off-by: SuZhou-Joe feat: format Signed-off-by: SuZhou-Joe feat: format Signed-off-by: SuZhou-Joe feat: format Signed-off-by: SuZhou-Joe --- src/core/public/http/base_path.ts | 24 ++++++++--- src/core/public/http/http_service.ts | 3 +- src/core/public/http/types.ts | 11 +++-- .../injected_metadata_service.ts | 11 +++++ src/core/public/utils/index.ts | 1 + src/core/public/utils/workspace.ts | 15 +++++++ src/plugins/workspace/public/plugin.ts | 31 ++++++++++++++ src/plugins/workspace/server/index.ts | 9 ++++ .../workspace/server/workspaces_service.ts | 41 +++++++++++++++++++ 9 files changed, 137 insertions(+), 9 deletions(-) create mode 100644 src/core/public/utils/workspace.ts create mode 100644 src/plugins/workspace/public/plugin.ts create mode 100644 src/plugins/workspace/server/index.ts create mode 100644 src/plugins/workspace/server/workspaces_service.ts diff --git a/src/core/public/http/base_path.ts b/src/core/public/http/base_path.ts index b31504676dba..8c45d707cf26 100644 --- a/src/core/public/http/base_path.ts +++ b/src/core/public/http/base_path.ts @@ -33,14 +33,28 @@ import { modifyUrl } from '@osd/std'; export class BasePath { constructor( private readonly basePath: string = '', - public readonly serverBasePath: string = basePath + public readonly serverBasePath: string = basePath, + private readonly workspaceBasePath: string = '' ) {} public get = () => { + return `${this.basePath}${this.workspaceBasePath}`; + }; + + public getBasePath = () => { return this.basePath; }; public prepend = (path: string): string => { + if (!this.get()) return path; + return modifyUrl(path, (parts) => { + if (!parts.hostname && parts.pathname && parts.pathname.startsWith('/')) { + parts.pathname = `${this.get()}${parts.pathname}`; + } + }); + }; + + public prependWithoutWorkspacePath = (path: string): string => { if (!this.basePath) return path; return modifyUrl(path, (parts) => { if (!parts.hostname && parts.pathname && parts.pathname.startsWith('/')) { @@ -50,16 +64,16 @@ export class BasePath { }; public remove = (path: string): string => { - if (!this.basePath) { + if (!this.get()) { return path; } - if (path === this.basePath) { + if (path === this.get()) { return '/'; } - if (path.startsWith(`${this.basePath}/`)) { - return path.slice(this.basePath.length); + if (path.startsWith(`${this.get()}/`)) { + return path.slice(this.get().length); } return path; diff --git a/src/core/public/http/http_service.ts b/src/core/public/http/http_service.ts index f26323f261aa..10d51bb2de7d 100644 --- a/src/core/public/http/http_service.ts +++ b/src/core/public/http/http_service.ts @@ -52,7 +52,8 @@ export class HttpService implements CoreService { const opensearchDashboardsVersion = injectedMetadata.getOpenSearchDashboardsVersion(); const basePath = new BasePath( injectedMetadata.getBasePath(), - injectedMetadata.getServerBasePath() + injectedMetadata.getServerBasePath(), + injectedMetadata.getWorkspaceBasePath() ); const fetchService = new Fetch({ basePath, opensearchDashboardsVersion }); const loadingCount = this.loadingCount.setup({ fatalErrors }); diff --git a/src/core/public/http/types.ts b/src/core/public/http/types.ts index 3b7dff71c811..ce56cfc3c826 100644 --- a/src/core/public/http/types.ts +++ b/src/core/public/http/types.ts @@ -93,17 +93,17 @@ export type HttpStart = HttpSetup; */ export interface IBasePath { /** - * Gets the `basePath` string. + * Gets the `basePath + workspace` string. */ get: () => string; /** - * Prepends `path` with the basePath. + * Prepends `path` with the basePath + workspace. */ prepend: (url: string) => string; /** - * Removes the prepended basePath from the `path`. + * Removes the prepended basePath + workspace from the `path`. */ remove: (url: string) => string; @@ -113,6 +113,11 @@ export interface IBasePath { * See {@link BasePath.get} for getting the basePath value for a specific request */ readonly serverBasePath: string; + + /** + * Prepends `path` with the basePath. + */ + prependWithoutWorkspacePath: (url: string) => string; } /** diff --git a/src/core/public/injected_metadata/injected_metadata_service.ts b/src/core/public/injected_metadata/injected_metadata_service.ts index f4c6a7f7b91a..ccda2fbc925a 100644 --- a/src/core/public/injected_metadata/injected_metadata_service.ts +++ b/src/core/public/injected_metadata/injected_metadata_service.ts @@ -38,6 +38,7 @@ import { UserProvidedValues, } from '../../server/types'; import { AppCategory, Branding } from '../'; +import { getWorkspaceIdFromUrl } from '../utils'; export interface InjectedPluginMetadata { id: PluginName; @@ -151,6 +152,15 @@ export class InjectedMetadataService { getSurvey: () => { return this.state.survey; }, + + getWorkspaceBasePath: () => { + const workspaceId = getWorkspaceIdFromUrl(window.location.href); + if (workspaceId) { + return `/w/${workspaceId}`; + } + + return ''; + }, }; } } @@ -186,6 +196,7 @@ export interface InjectedMetadataSetup { }; getBranding: () => Branding; getSurvey: () => string | undefined; + getWorkspaceBasePath: () => string; } /** @internal */ diff --git a/src/core/public/utils/index.ts b/src/core/public/utils/index.ts index 7676b9482aac..0719f5e83c53 100644 --- a/src/core/public/utils/index.ts +++ b/src/core/public/utils/index.ts @@ -31,3 +31,4 @@ export { shareWeakReplay } from './share_weak_replay'; export { Sha256 } from './crypto'; export { MountWrapper, mountReactNode } from './mount'; +export { getWorkspaceIdFromUrl } from './workspace'; diff --git a/src/core/public/utils/workspace.ts b/src/core/public/utils/workspace.ts new file mode 100644 index 000000000000..e93355aa00e3 --- /dev/null +++ b/src/core/public/utils/workspace.ts @@ -0,0 +1,15 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const getWorkspaceIdFromUrl = (url: string): string => { + const regexp = /\/w\/([^\/]*)/; + const urlObject = new URL(url); + const matchedResult = urlObject.pathname.match(regexp); + if (matchedResult) { + return matchedResult[1]; + } + + return ''; +}; diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts new file mode 100644 index 000000000000..967452fac54c --- /dev/null +++ b/src/plugins/workspace/public/plugin.ts @@ -0,0 +1,31 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { CoreSetup, CoreStart, Plugin } from '../../../core/public'; +import { getWorkspaceIdFromUrl } from '../../../core/public/utils'; + +export class WorkspacesPlugin implements Plugin<{}, {}> { + private getWorkpsaceIdFromURL(): string | null { + return getWorkspaceIdFromUrl(window.location.href); + } + public async setup(core: CoreSetup) { + /** + * Retrive workspace id from url + */ + const workspaceId = this.getWorkpsaceIdFromURL(); + + if (workspaceId) { + /** + * Enter a workspace + */ + } + + return {}; + } + + public start(core: CoreStart) { + return {}; + } +} diff --git a/src/plugins/workspace/server/index.ts b/src/plugins/workspace/server/index.ts new file mode 100644 index 000000000000..4722aec72593 --- /dev/null +++ b/src/plugins/workspace/server/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { PluginInitializerContext } from 'opensearch-dashboards/server'; +import { WorkspacesService } from './workspaces_service'; + +export const plugin = (initContext: PluginInitializerContext) => new WorkspacesService(); diff --git a/src/plugins/workspace/server/workspaces_service.ts b/src/plugins/workspace/server/workspaces_service.ts new file mode 100644 index 000000000000..55ac292f66ea --- /dev/null +++ b/src/plugins/workspace/server/workspaces_service.ts @@ -0,0 +1,41 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ +import { URL } from 'node:url'; +import { HttpServiceSetup, Plugin } from 'opensearch-dashboards/server'; + +export interface WorkspacesSetupDeps { + http: HttpServiceSetup; +} + +export class WorkspacesService implements Plugin<{}, {}> { + private proxyWorkspaceTrafficToRealHandler(setupDeps: WorkspacesSetupDeps) { + /** + * Proxy all {basePath}/w/{workspaceId}{osdPath*} paths to + * {basePath}{osdPath*} + */ + setupDeps.http.registerOnPreRouting((request, response, toolkit) => { + const regexp = /\/w\/([^\/]*)/; + const matchedResult = request.url.pathname.match(regexp); + if (matchedResult) { + const requestUrl = new URL(request.url.toString()); + requestUrl.pathname = requestUrl.pathname.replace(regexp, ''); + return toolkit.rewriteUrl(requestUrl.toString()); + } + return toolkit.next(); + }); + } + + public async setup(setupDeps: WorkspacesSetupDeps) { + this.proxyWorkspaceTrafficToRealHandler(setupDeps); + + return {}; + } + + public async start(deps: {}) { + return {}; + } + + public async stop() {} +}