Skip to content

Commit

Permalink
[Backport workspace][Workspace]Add workspace id in basePath (opensear…
Browse files Browse the repository at this point in the history
…ch-project#212) (opensearch-project#225)

* [Workspace]Add workspace id in basePath (opensearch-project#212)

* feat: enable workspace id in basePath

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: add unit test

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: remove useless test object id

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: add unit test

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: add unit test

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: update snapshot

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: move formatUrlWithWorkspaceId to core/public/utils

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: remove useless variable

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: remove useless variable

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: optimization

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: optimization

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: optimization

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: move workspace/utils to core

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: move workspace/utils to core

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: update comment

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: optimize code

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: update unit test

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: optimization

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: add space under license

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* fix: unit test

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

---------

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>
(cherry picked from commit 43e91fa)

* feat: some sync

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* feat: remove useless code

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* fix: modify import path

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* fix: unit test

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

* fix: unit test

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>

---------

Signed-off-by: SuZhou-Joe <suzhou@amazon.com>
  • Loading branch information
SuZhou-Joe committed Oct 16, 2023
1 parent 2964934 commit 9b8bdf6
Show file tree
Hide file tree
Showing 30 changed files with 766 additions and 83 deletions.
32 changes: 32 additions & 0 deletions src/core/public/http/base_path.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,36 @@ describe('BasePath', () => {
expect(new BasePath('/foo/bar', '/foo').serverBasePath).toEqual('/foo');
});
});

describe('workspaceBasePath', () => {
it('get path with workspace', () => {
expect(new BasePath('/foo/bar', '/foo/bar', '/workspace').get()).toEqual(
'/foo/bar/workspace'
);
});

it('getBasePath with workspace provided', () => {
expect(new BasePath('/foo/bar', '/foo/bar', '/workspace').getBasePath()).toEqual('/foo/bar');
});

it('prepend with workspace provided', () => {
expect(new BasePath('/foo/bar', '/foo/bar', '/workspace').prepend('/prepend')).toEqual(
'/foo/bar/workspace/prepend'
);
});

it('prepend with workspace provided but calls without workspace', () => {
expect(
new BasePath('/foo/bar', '/foo/bar', '/workspace').prepend('/prepend', {
withoutWorkspace: true,
})
).toEqual('/foo/bar/prepend');
});

it('remove with workspace provided', () => {
expect(
new BasePath('/foo/bar', '/foo/bar', '/workspace').remove('/foo/bar/workspace/remove')
).toEqual('/remove');
});
});
});
10 changes: 5 additions & 5 deletions src/core/public/http/http_service.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export type HttpSetupMock = jest.Mocked<HttpSetup> & {
anonymousPaths: jest.Mocked<HttpSetup['anonymousPaths']>;
};

const createServiceMock = ({ basePath = '' } = {}): HttpSetupMock => ({
const createServiceMock = ({ basePath = '', workspaceBasePath = '' } = {}): HttpSetupMock => ({
fetch: jest.fn(),
get: jest.fn(),
head: jest.fn(),
Expand All @@ -48,7 +48,7 @@ const createServiceMock = ({ basePath = '' } = {}): HttpSetupMock => ({
patch: jest.fn(),
delete: jest.fn(),
options: jest.fn(),
basePath: new BasePath(basePath),
basePath: new BasePath(basePath, undefined, workspaceBasePath),
anonymousPaths: {
register: jest.fn(),
isAnonymous: jest.fn(),
Expand All @@ -58,14 +58,14 @@ const createServiceMock = ({ basePath = '' } = {}): HttpSetupMock => ({
intercept: jest.fn(),
});

const createMock = ({ basePath = '' } = {}) => {
const createMock = ({ basePath = '', workspaceBasePath = '' } = {}) => {
const mocked: jest.Mocked<PublicMethodsOf<HttpService>> = {
setup: jest.fn(),
start: jest.fn(),
stop: jest.fn(),
};
mocked.setup.mockReturnValue(createServiceMock({ basePath }));
mocked.start.mockReturnValue(createServiceMock({ basePath }));
mocked.setup.mockReturnValue(createServiceMock({ basePath, workspaceBasePath }));
mocked.start.mockReturnValue(createServiceMock({ basePath, workspaceBasePath }));
return mocked;
};

Expand Down
26 changes: 26 additions & 0 deletions src/core/public/http/http_service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,32 @@ describe('#setup()', () => {
// We don't verify that this Observable comes from Fetch#getLoadingCount$() to avoid complex mocking
expect(loadingServiceSetup.addLoadingCountSource).toHaveBeenCalledWith(expect.any(Observable));
});

it('setup basePath without workspaceId provided in window.location.href', () => {
const injectedMetadata = injectedMetadataServiceMock.createSetupContract();
const fatalErrors = fatalErrorsServiceMock.createSetupContract();
const httpService = new HttpService();
const setupResult = httpService.setup({ fatalErrors, injectedMetadata });
expect(setupResult.basePath.get()).toEqual('');
});

it('setup basePath with workspaceId provided in window.location.href', () => {
const windowSpy = jest.spyOn(window, 'window', 'get');
windowSpy.mockImplementation(
() =>
({
location: {
href: 'http://localhost/w/workspaceId/app',
},
} as any)
);
const injectedMetadata = injectedMetadataServiceMock.createSetupContract();
const fatalErrors = fatalErrorsServiceMock.createSetupContract();
const httpService = new HttpService();
const setupResult = httpService.setup({ fatalErrors, injectedMetadata });
expect(setupResult.basePath.get()).toEqual('/w/workspaceId');
windowSpy.mockRestore();
});
});

describe('#stop()', () => {
Expand Down
2 changes: 0 additions & 2 deletions src/core/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -358,5 +358,3 @@ export {
MANAGEMENT_WORKSPACE_ID,
WORKSPACE_TYPE,
} from '../utils';

export { getWorkspaceIdFromUrl } from './utils';
5 changes: 3 additions & 2 deletions src/core/public/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@
export { shareWeakReplay } from './share_weak_replay';
export { Sha256 } from './crypto';
export { MountWrapper, mountReactNode } from './mount';
export { getWorkspaceIdFromUrl } from './workspace';
export {
WORKSPACE_PATH_PREFIX,
WORKSPACE_TYPE,
formatUrlWithWorkspaceId,
getWorkspaceIdFromUrl,
PUBLIC_WORKSPACE_ID,
MANAGEMENT_WORKSPACE_ID,
WORKSPACE_TYPE,
} from '../../utils';
15 changes: 0 additions & 15 deletions src/core/public/utils/workspace.ts

This file was deleted.

1 change: 1 addition & 0 deletions src/core/public/workspace/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

export { WorkspacesStart, WorkspacesService, WorkspacesSetup } from './workspaces_service';
1 change: 1 addition & 0 deletions src/core/server/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ export * from './crypto';
export * from './from_root';
export * from './package_json';
export * from './streams';
export { getWorkspaceIdFromUrl, cleanWorkspaceId } from '../../utils';
1 change: 1 addition & 0 deletions src/core/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,4 @@ export {
WORKSPACE_TYPE,
PERSONAL_WORKSPACE_ID_PREFIX,
} from './constants';
export { getWorkspaceIdFromUrl, formatUrlWithWorkspaceId, cleanWorkspaceId } from './workspace';
32 changes: 32 additions & 0 deletions src/core/utils/workspace.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { getWorkspaceIdFromUrl, formatUrlWithWorkspaceId } from './workspace';
import { httpServiceMock } from '../public/mocks';

describe('#getWorkspaceIdFromUrl', () => {
it('return workspace when there is a match', () => {
expect(getWorkspaceIdFromUrl('http://localhost/w/foo')).toEqual('foo');
});

it('return empty when there is not a match', () => {
expect(getWorkspaceIdFromUrl('http://localhost/w2/foo')).toEqual('');
});
});

describe('#formatUrlWithWorkspaceId', () => {
const basePathWithoutWorkspaceBasePath = httpServiceMock.createSetupContract().basePath;
it('return url with workspace prefix when format with a id provided', () => {
expect(
formatUrlWithWorkspaceId('/app/dashboard', 'foo', basePathWithoutWorkspaceBasePath)
).toEqual('http://localhost/w/foo/app/dashboard');
});

it('return url without workspace prefix when format without a id', () => {
expect(
formatUrlWithWorkspaceId('/w/foo/app/dashboard', '', basePathWithoutWorkspaceBasePath)
).toEqual('http://localhost/app/dashboard');
});
});
42 changes: 42 additions & 0 deletions src/core/utils/workspace.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { WORKSPACE_PATH_PREFIX } from './constants';
import { IBasePath } from '../public';

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

export const cleanWorkspaceId = (path: string) => {
return path.replace(/^\/w\/([^\/]*)/, '');
};

export const formatUrlWithWorkspaceId = (url: string, workspaceId: string, basePath: IBasePath) => {
const newUrl = new URL(url, window.location.href);
/**
* Patch workspace id into path
*/
newUrl.pathname = basePath.remove(newUrl.pathname);

if (workspaceId) {
newUrl.pathname = `${WORKSPACE_PATH_PREFIX}/${workspaceId}${newUrl.pathname}`;
} else {
newUrl.pathname = cleanWorkspaceId(newUrl.pathname);
}

newUrl.pathname = basePath.prepend(newUrl.pathname, {
withoutWorkspace: true,
});

return newUrl.toString();
};

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -1075,10 +1075,7 @@ export class SavedObjectsTable extends Component<SavedObjectsTableProps, SavedOb
const hideImport = workspaceEnabled && !workspaceId;

return (
<EuiPageContent
horizontalPosition="center"
style={this.props.fullWidth ? {} : { maxWidth: '75%', marginTop: '40px' }}
>
<EuiPageContent horizontalPosition="center">
{this.renderFlyout()}
{this.renderRelationships()}
{this.renderDeleteConfirmModal()}
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/workspace/public/components/utils/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import { WORKSPACE_OVERVIEW_APP_ID } from '../../../common/constants';
import { CoreStart } from '../../../../../core/public';
import { formatUrlWithWorkspaceId } from '../../utils';
import { formatUrlWithWorkspaceId } from '../../../../../core/public/utils';

type Core = Pick<CoreStart, 'application' | 'http'>;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { i18n } from '@osd/i18n';
import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public';
import { WorkspaceForm, WorkspaceFormSubmitData } from './workspace_form';
import { WORKSPACE_OVERVIEW_APP_ID, WORKSPACE_OP_TYPE_CREATE } from '../../../common/constants';
import { formatUrlWithWorkspaceId } from '../../utils';
import { formatUrlWithWorkspaceId } from '../../../../../core/public/utils';
import { WorkspaceClient } from '../../workspace_client';

export const WorkspaceCreator = () => {
Expand Down
Loading

0 comments on commit 9b8bdf6

Please sign in to comment.