Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions packages/components/src/internal/url/AppURL.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,85 @@ describe('AppURL', () => {
expect(url.isAppPath()).not.toBeTruthy();
});

test('fromMenuUrl undefined / invalid', () => {
expect(AppURL.fromMenuUrl(undefined, 'samplemanager', '/DefaultTestContainer')).toBeUndefined();
expect(AppURL.fromMenuUrl('/samples/blood', 'samplemanager', '/DefaultTestContainer')).toBeUndefined();
expect(AppURL.fromMenuUrl('samples/blood', 'samplemanager', '/DefaultTestContainer')).toBeUndefined();
expect(AppURL.fromMenuUrl('', 'samplemanager', '/DefaultTestContainer')).toBeUndefined();
});

test('fromMenuUrl basic path', () => {
const url = AppURL.fromMenuUrl('#/samples/blood', 'samplemanager', '/DefaultTestContainer');
expect(url).toBeDefined();
expect(url.getProductId()).toEqual('samplemanager');
expect(url.getContainerPath()).toEqual('/DefaultTestContainer');
// productId and containerPath match the current context, so it should be an app path
expect(url.isAppPath()).toBeTruthy();
expect(url.toString()).toEqual('/samples/blood');
expect(url.toHref()).toEqual('#/samples/blood');
});

test('fromMenuUrl with single query param', () => {
const url = AppURL.fromMenuUrl('#/samples/blood?RowId=4', 'samplemanager', '/DefaultTestContainer');
expect(url).toBeDefined();
expect(url.toString()).toEqual('/samples/blood?RowId=4');
expect(url.toHref()).toEqual('#/samples/blood?RowId=4');
});

test('fromMenuUrl with multiple query params', () => {
const url = AppURL.fromMenuUrl(
'#/samples/blood?foo=bar&baz=qux',
'samplemanager',
'/DefaultTestContainer'
);
expect(url).toBeDefined();
const actual = url.toString();
expect(actual.startsWith('/samples/blood?')).toBeTruthy();
expect(actual).toContain('foo=bar');
expect(actual).toContain('baz=qux');
});

test('fromMenuUrl with repeated query param key', () => {
const url = AppURL.fromMenuUrl(
'#/samples?tag=a&tag=b',
'samplemanager',
'/DefaultTestContainer'
);
expect(url).toBeDefined();
// Repeated keys should be preserved as an array of values
expect(url.toString()).toEqual('/samples?tag=a&tag=b');
});

test('fromMenuUrl with different productId', () => {
// productId differs from current controller, so the URL is rendered as a full URL
const url = AppURL.fromMenuUrl('#/dashboard', 'biologics', '/DefaultTestContainer');
expect(url).toBeDefined();
expect(url.getProductId()).toEqual('biologics');
expect(url.isAppPath()).not.toBeTruthy();
expect(url.toString()).toEqual('/labkey/DefaultTestContainer/biologics-app.view#/dashboard');
});

test('fromMenuUrl with different containerPath', () => {
// containerPath differs from the current container, so the URL is rendered as a full URL
const url = AppURL.fromMenuUrl(
'#/samples/blood',
'samplemanager',
'/DefaultTestContainer/ChildFolder'
);
expect(url).toBeDefined();
expect(url.getContainerPath()).toEqual('/DefaultTestContainer/ChildFolder');
expect(url.isAppPath()).not.toBeTruthy();
expect(url.toString()).toEqual(
'/labkey/DefaultTestContainer/ChildFolder/samplemanager-app.view#/samples/blood'
);
});

test('fromMenuUrl with hash-only url', () => {
const url = AppURL.fromMenuUrl('#', 'samplemanager', '/DefaultTestContainer');
expect(url).toBeDefined();
expect(url.toString()).toEqual('');
});

test('containerPath', () => {
let url = AppURL.create('some', 'fun', 'path');

Expand Down
16 changes: 14 additions & 2 deletions packages/components/src/internal/url/AppURL.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import { ActionURL, Filter, getServerContext } from '@labkey/api';

import { getPrimaryAppProductId } from '../app/products';
import { getQueryParams } from '../util/URL';

export function applyURL(prop: string, options?: BuildURLOptions): string {
if (options) {
Expand Down Expand Up @@ -125,9 +126,20 @@ export class AppURL {
if (url === undefined) return undefined;
if (!url.startsWith('#')) return undefined;
let path = url.replace('#', '');
if (path.indexOf('?') > -1) path = path.substring(0, path.indexOf('?'));
let params: Record<string, QueryParamValue> = undefined;

return new AppURL({ _basePath: path, _containerPath: containerPath, _productId: productId });
if (path.indexOf('?') > -1) {
params = getQueryParams(path.substring(path.indexOf('?')));
path = path.substring(0, path.indexOf('?'));
}

let appUrl = new AppURL({ _basePath: path, _containerPath: containerPath, _productId: productId });

if (params) {
appUrl = appUrl.addParams(params);
}

return appUrl;
}

addFilters(...filters: Filter.IFilter[]): AppURL {
Expand Down