Skip to content
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

Routing core api #2207

Merged
merged 41 commits into from
Aug 31, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
30d6ebe
routing core api
JohannesDoberer Aug 5, 2021
c4e3856
core api routing
JohannesDoberer Aug 11, 2021
ea53e03
Merge branch 'master' into routing-core-api
JohannesDoberer Aug 11, 2021
d536f76
add searchparams instead of overwrite
JohannesDoberer Aug 12, 2021
b896421
Merge branch 'master' into routing-core-api
JohannesDoberer Aug 12, 2021
1794569
leftover
JohannesDoberer Aug 12, 2021
07158a7
Update docs/luigi-core-api.md
JohannesDoberer Aug 16, 2021
443e629
Update docs/luigi-core-api.md
JohannesDoberer Aug 16, 2021
ea33b6f
Update docs/luigi-core-api.md
JohannesDoberer Aug 16, 2021
ec38ac4
Merge branch 'master' into routing-core-api
JohannesDoberer Aug 16, 2021
bd449c1
Merge branch 'master' into routing-core-api
alexandra-simeonova Aug 17, 2021
db9ee70
Update core/src/core-api/routing.js
JohannesDoberer Aug 18, 2021
da9994b
Update core/src/core-api/routing.js
JohannesDoberer Aug 18, 2021
152e21e
prettier
JohannesDoberer Aug 18, 2021
7148edf
prettier
JohannesDoberer Aug 18, 2021
ea833fb
prettier
JohannesDoberer Aug 18, 2021
9b2060c
Merge branch 'master' into routing-core-api
JohannesDoberer Aug 18, 2021
f649f9d
Merge branch 'master' into routing-core-api
JohannesDoberer Aug 23, 2021
7291264
Update core/src/core-api/routing.js
JohannesDoberer Aug 24, 2021
ea91ea7
Update core/src/utilities/helpers/routing-helpers.js
JohannesDoberer Aug 24, 2021
19944bd
Update core/src/utilities/helpers/routing-helpers.js
JohannesDoberer Aug 24, 2021
086df53
Update core/src/utilities/helpers/routing-helpers.js
JohannesDoberer Aug 24, 2021
e028cb1
Update core/src/utilities/helpers/routing-helpers.js
JohannesDoberer Aug 24, 2021
f5765a4
Update core/test/core-api/routing.spec.js
JohannesDoberer Aug 24, 2021
b4bbd89
suggestions
JohannesDoberer Aug 24, 2021
5b2693f
erge branch 'routing-core-api' of github.com:JohannesDoberer/luigi in…
JohannesDoberer Aug 24, 2021
c508e90
Update core/src/core-api/routing.js
JohannesDoberer Aug 24, 2021
4af6e07
Update core/src/core-api/routing.js
JohannesDoberer Aug 24, 2021
75644a1
Merge branch 'master' into routing-core-api
stanleychh Aug 24, 2021
92fc950
added delete function and reduced code
JohannesDoberer Aug 25, 2021
b8b8045
Merge branch 'master' into routing-core-api
JohannesDoberer Aug 25, 2021
e1e0d75
Merge branch 'master' into routing-core-api
UlianaMunich Aug 26, 2021
bf83cba
refactor delete search param
JohannesDoberer Aug 26, 2021
14bcac3
Merge branch 'routing-core-api' of github.com:JohannesDoberer/luigi i…
JohannesDoberer Aug 26, 2021
2b4d911
fix tets
JohannesDoberer Aug 26, 2021
1b9d33a
Merge branch 'master' into routing-core-api
UlianaMunich Aug 26, 2021
3705265
Merge branch 'master' into routing-core-api
JohannesDoberer Aug 27, 2021
096222a
refactoring
JohannesDoberer Aug 27, 2021
21df41d
Merge branch 'master' into routing-core-api
JohannesDoberer Aug 27, 2021
128aaa8
refactoring
JohannesDoberer Aug 31, 2021
fca773b
Merge branch 'master' into routing-core-api
JohannesDoberer Aug 31, 2021
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
3 changes: 3 additions & 0 deletions core/src/core-api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { ux } from './ux';
import { globalSearch } from './globalsearch';
import { theming } from './theming';
import { featureToggles } from './featuretoggles';
import { routing } from './routing';

export const LuigiConfig = config;
export const LuigiAuth = auth;
Expand All @@ -19,6 +20,7 @@ export const LuigiUX = ux;
export const LuigiGlobalSearch = globalSearch;
export const LuigiTheming = theming;
export const LuigiFeatureToggles = featureToggles;
export const LuigiRouting = routing;

// Expose it window for user app to call Luigi.setConfig()
window.Luigi = config;
Expand All @@ -31,3 +33,4 @@ window.Luigi.ux = () => ux;
window.Luigi.globalSearch = () => globalSearch;
window.Luigi.theming = () => theming;
window.Luigi.featureToggles = () => featureToggles;
window.Luigi.routing = () => routing;
78 changes: 78 additions & 0 deletions core/src/core-api/routing.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { LuigiConfig } from '.';
import { Iframe } from '../services';
import { GenericHelpers, RoutingHelpers } from '../utilities/helpers';
/**
* @name Routing
*/
class LuigiRouting {
/**
* Use these functions for navigation-related features.
* @name Routing
*/
constructor() {}

/**
* Get search parameter from URL as an object.
* @memberof Routing
* @since NEXTRELEASE
* @returns {Object}
* @example
* Luigi.routing().getSearchParams();
*/
getSearchParams() {
const queryParams = {};
const url = new URL(location);
if (LuigiConfig.getConfigValue('routing.useHashRouting')) {
for (const [key, value] of new URLSearchParams(url.hash.split('?')[1])) {
queryParams[key] = value;
}
} else {
for (const [key, value] of url.searchParams.entries()) {
queryParams[key] = value;
}
}
return queryParams;
}

/**
* Add search parameters to the URL.
* If [hash routing](navigation-parameters-reference.md#usehashrouting) is enabled, the search parameters will be set after the hash.
* In order to delete a search query param you can set the value of the param to undefined.
* @memberof Routing
* @since NEXTRELEASE
* @param {Object} params
* @example
* Luigi.routing().addSearchParams({luigi:'rocks', mario:undefined});
*/
addSearchParams(params) {
if (!GenericHelpers.isObject(params)) {
console.log('Params argument must be an object');
return;
}
const url = new URL(location);
if (LuigiConfig.getConfigValue('routing.useHashRouting')) {
let [hashValue, givenQueryParamsString] = url.hash.split('?');
let searchParams = new URLSearchParams(givenQueryParamsString);
this._modifySearchParam(params, searchParams);
url.hash = hashValue;
if (searchParams.toString() !== '') {
url.hash += `?${decodeURIComponent(searchParams.toString())}`;
}
} else {
this._modifySearchParam(params, url.searchParams);
}
window.history.pushState({}, '', url.href);
}

//Adds and remove properties from searchParams
_modifySearchParam(params, searchParams) {
for (const [key, value] of Object.entries(params)) {
searchParams.set(key, value);
if (value === undefined) {
searchParams.delete(key);
}
}
}
}

export const routing = new LuigiRouting();
15 changes: 14 additions & 1 deletion core/src/utilities/helpers/routing-helpers.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Helper methods for 'routing.js' file. They don't require any method from 'routing.js' but are required by them.
// They are also rarely used directly from outside of 'routing.js'
import { LuigiConfig, LuigiFeatureToggles, LuigiI18N } from '../../core-api';
import { LuigiConfig, LuigiFeatureToggles, LuigiI18N, LuigiRouting } from '../../core-api';
import { AsyncHelpers, EscapingHelpers, EventListenerHelpers, GenericHelpers } from './';
import { Routing } from '../../services/routing';

Expand Down Expand Up @@ -266,6 +266,7 @@ class RoutingHelpersClass {
const contextVarPrefix = 'context.';
const nodeParamsVarPrefix = 'nodeParams.';
const i18n_currentLocale = '{i18n.currentLocale}';
const searchQuery = 'routing.queryParams';

viewUrl = GenericHelpers.replaceVars(viewUrl, componentData.pathParams, ':', false);
viewUrl = GenericHelpers.replaceVars(viewUrl, componentData.context, contextVarPrefix);
Expand All @@ -275,6 +276,18 @@ class RoutingHelpersClass {
viewUrl = viewUrl.replace(i18n_currentLocale, LuigiI18N.getCurrentLocale());
}

if (viewUrl.includes(searchQuery)) {
const viewUrlSearchParam = viewUrl.split('?')[1];
if (viewUrlSearchParam) {
const key = viewUrlSearchParam.split('=')[0];
if (LuigiRouting.getSearchParams()[key]) {
viewUrl = viewUrl.replace(`{${searchQuery}.${key}}`, LuigiRouting.getSearchParams()[key]);
} else {
viewUrl = viewUrl.replace(`?${key}={${searchQuery}.${key}}`, '');
}
}
}

return viewUrl;
}

Expand Down
129 changes: 129 additions & 0 deletions core/test/core-api/routing.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
const chai = require('chai');
const assert = chai.assert;
const sinon = require('sinon');

import { afterEach } from 'mocha';
import { LuigiRouting, LuigiConfig } from '../../src/core-api';

describe('Luigi routing', function() {
let globalLocationRef = global.location;

beforeEach(() => {
window.history.pushState = sinon.spy();
});
afterEach(() => {
global.location = globalLocationRef;
});
describe('SearchParams path routing', () => {
it('get searchparams', () => {
global.location = 'http://some.url.de?test=tets&luigi=rocks';
assert.deepEqual(LuigiRouting.getSearchParams(), { test: 'tets', luigi: 'rocks' });
});
it('get searchparams', () => {
global.location = 'http://some.url.de/something?test=tets&luigi=rocks';
assert.deepEqual(LuigiRouting.getSearchParams(), { test: 'tets', luigi: 'rocks' });
});
it('get searchparams when no query parameter', () => {
global.location = 'http://some.url.de';
assert.deepEqual(LuigiRouting.getSearchParams(), {});
});
it('set searchparams', () => {
window.state = {};
global.location = 'http://some.url.de';
LuigiRouting.addSearchParams({ foo: 'bar' });
sinon.assert.calledWithExactly(window.history.pushState, window.state, '', 'http://some.url.de/?foo=bar');
});
it('add search params to searchparams', () => {
window.state = {};
global.location = 'http://some.url.de?test=tets';
LuigiRouting.addSearchParams({ foo: 'bar' });
sinon.assert.calledWithExactly(
window.history.pushState,
window.state,
'',
'http://some.url.de/?test=tets&foo=bar'
);
});
it('call addSearchParams with wrong argument', () => {
console.log = sinon.spy();
global.location = 'http://some.url.de';
LuigiRouting.addSearchParams('bar');
sinon.assert.calledWith(console.log, 'Params argument must be an object');
});
it('delete search params from url', () => {
window.state = {};
global.location = 'http://some.url.de?luigi=rocks&mario=red';
LuigiRouting.addSearchParams({ mario: undefined });
sinon.assert.calledWithExactly(window.history.pushState, window.state, '', 'http://some.url.de/?luigi=rocks');
});
});
describe('SearchParams hash routing', () => {
beforeEach(() => {
sinon
.stub(LuigiConfig, 'getConfigValue')
.withArgs('routing.useHashRouting')
.returns(true);
});
afterEach(() => {
sinon.restore();
});
it('get searchparams hash routing', () => {
global.location = 'http://some.url.de/#/?test=tets&luigi=rocks';
assert.deepEqual(LuigiRouting.getSearchParams(), { test: 'tets', luigi: 'rocks' });
});
it('get searchparams', () => {
global.location = 'http://some.url.de/#/something?test=tets&luigi=rocks';
assert.deepEqual(LuigiRouting.getSearchParams(), { test: 'tets', luigi: 'rocks' });
});
it('get searchparams hash routing', () => {
global.location = 'http://some.url.de/#/';
assert.deepEqual(LuigiRouting.getSearchParams(), {});
});
it('add searchparams hash routing', () => {
window.state = {};
global.location = 'http://some.url.de/#/';
LuigiRouting.addSearchParams({ foo: 'bar' });
sinon.assert.calledWithExactly(window.history.pushState, window.state, '', 'http://some.url.de/#/?foo=bar');
});
it('add search params to hash routing', () => {
window.state = {};
global.location = 'http://some.url.de/#/?test=tets';
LuigiRouting.addSearchParams({ foo: 'bar' });
sinon.assert.calledWithExactly(
window.history.pushState,
window.state,
'',
'http://some.url.de/#/?test=tets&foo=bar'
);
});
it('add search params to hash routing', () => {
window.state = {};
global.location = 'http://some.url.de/#/?~luigi=rocks';
LuigiRouting.addSearchParams({ foo: 'bar' });
sinon.assert.calledWithExactly(
window.history.pushState,
window.state,
'',
'http://some.url.de/#/?~luigi=rocks&foo=bar'
);
});
it('call addSearchParams with wrong argument hash routing', () => {
console.log = sinon.spy();
global.location = 'http://some.url.de/#/';
LuigiRouting.addSearchParams('bar');
sinon.assert.calledWith(console.log, 'Params argument must be an object');
});
it('delete search params from url', () => {
window.state = {};
global.location = 'http://some.url.de/#/?luigi=rocks&mario=red';
LuigiRouting.addSearchParams({ mario: undefined });
sinon.assert.calledWithExactly(window.history.pushState, window.state, '', 'http://some.url.de/#/?luigi=rocks');
});

it('_modifySearchParam', () => {
let searchParams = new URLSearchParams('mario=rocks');
LuigiRouting._modifySearchParam({ test: 'tets', luigi: 'rocks', mario: undefined }, searchParams);
assert.equal(searchParams.toString(), 'test=tets&luigi=rocks');
});
});
});
21 changes: 20 additions & 1 deletion core/test/utilities/helpers/routing-helpers.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const chai = require('chai');
const expect = chai.expect;
const assert = chai.assert;
import { GenericHelpers, RoutingHelpers } from '../../../src/utilities/helpers';
import { LuigiConfig, LuigiFeatureToggles, LuigiI18N } from '../../../src/core-api';
import { LuigiConfig, LuigiFeatureToggles, LuigiI18N, LuigiRouting } from '../../../src/core-api';
import { Routing } from '../../../src/services/routing';
import { config } from '../../../src/core-api/config';

Expand Down Expand Up @@ -97,6 +97,25 @@ describe('Routing-helpers', () => {
expect(RoutingHelpers.substituteViewUrl(viewUrl, {})).to.equal(expected);
});
});
describe('substitute search query params', () => {
afterEach(() => {
sinon.restore();
});
it('substitutes search query parameter', () => {
sinon.stub(LuigiRouting, 'getSearchParams').returns({ luigi: 'rocks' });
const viewUrl = '/microfrontend.html?luigi={routing.queryParams.luigi}';
const expected = '/microfrontend.html?luigi=rocks';

expect(RoutingHelpers.substituteViewUrl(viewUrl, {})).to.equal(expected);
});
it('substitutes search query parameter', () => {
sinon.stub(LuigiRouting, 'getSearchParams').returns({ mario: 'rocks' });
const viewUrl = '/microfrontend.html?luigi={routing.queryParams.luigi}';
const expected = '/microfrontend.html';

expect(RoutingHelpers.substituteViewUrl(viewUrl, {})).to.equal(expected);
});
});

describe('defaultChildNodes', () => {
let mockPathData;
Expand Down
43 changes: 43 additions & 0 deletions docs/luigi-core-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ This document outlines the features provided by the Luigi Core API. It covers th
- [Global search](#globalsearch) - functions related to Luigi's global search
- [Theming](#theming) - functions related to Luigi theming capabilties
- [Feature toggles](#featuretoggles) - functions related to Luigi's feature toggle mechanism
- [Routing](#routing) - functions to get and set search query parameters

## Luigi Config

Expand Down Expand Up @@ -1285,3 +1286,45 @@ Returns **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Gl
**Meta**

- **since**: 1.4.0

## Luigi.routing()

<!-- Generated by documentation.js. Update this documentation by updating the source code. -->

### Routing

#### getSearchParams

Get search parameter from URL as an object.

##### Examples

```javascript
Luigi.routing().getSearchParams();
```

Returns **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)**

**Meta**

- **since**: NEXTRELEASE

#### addSearchParams

Add search parameters to the URL.
If [hash routing](navigation-parameters-reference.md#usehashrouting) is enabled, the search parameters will be set after the hash.
In order to delete a search query param you can set the value of the param to undefined.

##### Parameters

- `params` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)**

##### Examples

```javascript
Luigi.routing().addSearchParams({luigi:'rocks', mario:undefined});
```

**Meta**

- **since**: NEXTRELEASE
5 changes: 3 additions & 2 deletions scripts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
"docu:client:generate:section": "documentation readme ../client/src/luigi-client.js -f md --readme-file=../docs/luigi-client-api.md --section='API Reference' --markdown-toc=false --quiet --github false",
"docu:client:validate": "documentation lint ../client/src/luigi-client.js",
"docu:core": "npm run docu:core:validate && npm run docu:core:generate:sections",
"docu:core:validate": "documentation lint --shallow ../core/src/core-api/config.js ../core/src/core-api/elements.js ../core/src/core-api/auth.js ../core/src/core-api/navigation.js ../core/src/core-api/i18n.js ../core/src/core-api/custom-messages.js ../core/src/core-api/ux.js ../core/src/core-api/globalsearch.js ../core/src/core-api/theming.js ../core/src/core-api/featuretoggles.js",
"docu:core:generate:sections": "npm run docu:core:generate:config && npm run docu:core:generate:dom-elements && npm run docu:core:generate:auth && npm run docu:core:generate:navigation && npm run docu:core:generate:i18n && npm run docu:core:generate:custom-messages && npm run docu:core:generate:ux && npm run docu:core:generate:globalsearch && npm run docu:core:generate:theming && npm run docu:core:generate:featuretoggles",
"docu:core:validate": "documentation lint --shallow ../core/src/core-api/config.js ../core/src/core-api/elements.js ../core/src/core-api/auth.js ../core/src/core-api/navigation.js ../core/src/core-api/i18n.js ../core/src/core-api/custom-messages.js ../core/src/core-api/ux.js ../core/src/core-api/globalsearch.js ../core/src/core-api/theming.js ../core/src/core-api/featuretoggles.js ../core/src/core-api/routing.js",
"docu:core:generate:sections": "npm run docu:core:generate:config && npm run docu:core:generate:dom-elements && npm run docu:core:generate:auth && npm run docu:core:generate:navigation && npm run docu:core:generate:i18n && npm run docu:core:generate:custom-messages && npm run docu:core:generate:ux && npm run docu:core:generate:globalsearch && npm run docu:core:generate:theming && npm run docu:core:generate:featuretoggles && npm run docu:core:generate:routing",
"docu:core:generate:config": "documentation readme ../core/src/core-api/config.js --shallow -f md --section='Luigi Config' --readme-file=../docs/luigi-core-api.md --markdown-toc=false --github false --quiet",
"docu:core:generate:dom-elements": "documentation readme ../core/src/core-api/dom-elements.js --shallow -f md --section='Luigi.elements()' --readme-file=../docs/luigi-core-api.md --markdown-toc=false --github false --quiet",
"docu:core:generate:auth": "documentation readme ../core/src/core-api/auth.js --shallow -f md --section='Luigi.auth()' --readme-file=../docs/luigi-core-api.md --markdown-toc=false --github false --quiet",
Expand All @@ -20,6 +20,7 @@
"docu:core:generate:globalsearch": "documentation readme ../core/src/core-api/globalSearch.js --shallow -f md --section='Luigi.globalSearch()' --readme-file=../docs/luigi-core-api.md --markdown-toc=false --github false --quiet",
"docu:core:generate:theming": "documentation readme ../core/src/core-api/theming.js --shallow -f md --section='Luigi.theming()' --readme-file=../docs/luigi-core-api.md --markdown-toc=false --github false --quiet",
"docu:core:generate:featuretoggles": "documentation readme ../core/src/core-api/featuretoggles.js --shallow -f md --section='Luigi.featureToggles()' --readme-file=../docs/luigi-core-api.md --markdown-toc=false --github false --quiet",
"docu:core:generate:routing": "documentation readme ../core/src/core-api/routing.js --shallow -f md --section='Luigi.routing()' --readme-file=../docs/luigi-core-api.md --markdown-toc=false --github false --quiet",
"release": "babel-node tools/release-cli/release-cli.js",
"release:watch": "nodemon --exec babel-node tools/release-cli/release-cli.js",
"publish:nightly": "babel-node tools/publish-nightly.js"
Expand Down