Skip to content

Commit

Permalink
Add newTab option to linkManager (#2190)
Browse files Browse the repository at this point in the history
Enables opening paths in a new tab
  • Loading branch information
ndricimrr authored Aug 23, 2021
1 parent e0fd05a commit 71060de
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 34 deletions.
36 changes: 14 additions & 22 deletions client/luigi-client.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,12 +304,7 @@ export declare interface LinkManager {
* LuigiClient.linkManager().navigate('/settings', null, true) // preserve view
* LuigiClient.linkManager().navigate('#?intent=Sales-order?id=13') // intent navigation
*/
navigate: (
path: string,
sessionId?: string,
preserveView?: boolean,
modalSettings?: ModalSettings
) => void;
navigate: (path: string, sessionId?: string, preserveView?: boolean, modalSettings?: ModalSettings) => void;

/** @lends linkManager */
/**
Expand Down Expand Up @@ -367,10 +362,7 @@ export declare interface LinkManager {
* @example
* const splitViewHandle = LuigiClient.linkManager().openAsSplitView('projects/pr1/logs', {title: 'Logs', size: 40, collapsed: true});
*/
openAsSplitView: (
path: string,
splitViewSettings?: SplitViewSettings
) => SplitViewInstance;
openAsSplitView: (path: string, splitViewSettings?: SplitViewSettings) => SplitViewInstance;

/**
* Opens a view in a drawer. You can specify if the drawer has a header, if a backdrop is active in the background and configure the size of the drawer. By default the header is shown. The backdrop is not visible and has to be activated. The size of the drawer is by default set to `s` which means 25% of the micro frontend size. You can also use `l`(75%), `m`(50%) or `xs`(15.5%). Optionally, use it in combination with any of the navigation functions.
Expand All @@ -397,6 +389,14 @@ export declare interface LinkManager {
* LuigiClient.linkManager().withoutSync().fromClosestContext().navigate('settings');
*/
withoutSync: () => this;

/**
* Enables navigating to a new tab.
* @since NEXT_RELEASE
* @example
* LuigiClient.linkManager().newTab().navigate('/projects/xy/foobar');
*/
newTab: () => this;
}

export declare interface StorageManager {
Expand Down Expand Up @@ -471,12 +471,8 @@ export declare interface StorageManager {
* @param {Lifecycle~initListenerCallback} initFn the function that is called once Luigi is initialized, receives current context and origin as parameters
* @memberof Lifecycle
*/
export function addInitListener(
initFn: (context: Context, origin?: string) => void
): number;
export type addInitListener = (
initFn: (context: Context, origin?: string) => void
) => number;
export function addInitListener(initFn: (context: Context, origin?: string) => void): number;
export type addInitListener = (initFn: (context: Context, origin?: string) => void) => number;

/**
* Callback of the addInitListener
Expand All @@ -497,12 +493,8 @@ export type removeInitListener = (id: number) => boolean;
* @param {function} contextUpdatedFn the listener function called each time Luigi context changes
* @memberof Lifecycle
*/
export function addContextUpdateListener(
contextUpdatedFn: (context: Context) => void
): string;
export type addContextUpdateListener = (
contextUpdatedFn: (context: Context) => void
) => string;
export function addContextUpdateListener(contextUpdatedFn: (context: Context) => void): string;
export type addContextUpdateListener = (contextUpdatedFn: (context: Context) => void) => string;

/**
* Removes a context update listener.
Expand Down
14 changes: 13 additions & 1 deletion client/src/linkManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ export class linkManager extends LuigiClientBase {
fromVirtualTreeRoot: false,
fromParent: false,
relative: false,
link: ''
link: '',
newTab: false
};
}

Expand Down Expand Up @@ -313,4 +314,15 @@ export class linkManager extends LuigiClientBase {
this.options.withoutSync = true;
return this;
}

/**
* Enables navigating to a new tab.
* @since NEXT_RELEASE
* @example
* LuigiClient.linkManager().newTab().navigate('/projects/xy/foobar');
*/
newTab() {
this.options.newTab = true;
return this;
}
}
41 changes: 31 additions & 10 deletions core/src/App.html
Original file line number Diff line number Diff line change
Expand Up @@ -918,8 +918,7 @@
resetMicrofrontendModalData();

const openViewInModal = async (nodepath, settings) => {
const { nodeObject } = await Navigation.extractDataFromPath(nodepath);
if (await Navigation.shouldPreventNavigation(nodeObject)) {
if (await NavigationHelpers.shouldPreventNavigationForPath(nodepath)) {
return;
}
mfModal.displayed = true;
Expand Down Expand Up @@ -981,8 +980,7 @@
resetMicrofrontendDrawerData();

const openViewInDrawer = async (nodepath, settings) => {
const { nodeObject } = await Navigation.extractDataFromPath(nodepath);
if (await Navigation.shouldPreventNavigation(nodeObject)) {
if (await NavigationHelpers.shouldPreventNavigationForPath(nodepath)) {
return;
}
mfDrawer.displayed = true;
Expand Down Expand Up @@ -1046,12 +1044,24 @@
internalUserSettingsObject.displayed = false;
};

// Open View in New Tab

const openViewInNewTab = async nodepath => {
if (await NavigationHelpers.shouldPreventNavigationForPath(nodepath)) {
return;
}

window.open(nodepath, '_blank');
};

function init(node) {
const isolateAllViews = LuigiConfig.getConfigValue('navigation.defaults.isolateView');
const defaultPageErrorHandler = LuigiConfig.getConfigValue(
'navigation.defaults.pageErrorHandler'
);
const defaultRunTimeErrorHandler = LuigiConfig.getConfigValue('navigation.defaults.runTimeErrorHandler')
const defaultRunTimeErrorHandler = LuigiConfig.getConfigValue(
'navigation.defaults.runTimeErrorHandler'
);
const config = {
iframe: null,
navigateOk: null,
Expand Down Expand Up @@ -1232,7 +1242,11 @@

if ('luigi.navigation.open' === e.data.msg) {
isNavigateBack = false;
if (e.data.params.modal !== undefined) {
if (e.data.params.newTab) {
let path = buildPath(e.data.params);
path = GenericHelpers.addLeadingSlash(path);
openViewInNewTab(path);
} else if (e.data.params.modal !== undefined) {
let path = buildPath(e.data.params);
path = GenericHelpers.addLeadingSlash(path);
contentNode = node;
Expand Down Expand Up @@ -1404,14 +1418,21 @@
e.data.data.id,
e.data.data.operation,
e.data.data.params
)
);
}

if('luigi-runtime-error-handling'===e.data.msg){
if ('luigi-runtime-error-handling' === e.data.msg) {
let currentNode = iframe.luigi.currentNode;
if(currentNode && currentNode.runTimeErrorHandler && GenericHelpers.isFunction(currentNode.runTimeErrorHandler.errorFn)){
if (
currentNode &&
currentNode.runTimeErrorHandler &&
GenericHelpers.isFunction(currentNode.runTimeErrorHandler.errorFn)
) {
currentNode.runTimeErrorHandler.errorFn(e.data.errorObj, currentNode);
}else if(defaultRunTimeErrorHandler && GenericHelpers.isFunction(defaultRunTimeErrorHandler.errorFn)){
} else if (
defaultRunTimeErrorHandler &&
GenericHelpers.isFunction(defaultRunTimeErrorHandler.errorFn)
) {
defaultRunTimeErrorHandler.errorFn(e.data.errorObj, currentNode);
}
}
Expand Down
13 changes: 13 additions & 0 deletions core/src/utilities/helpers/navigation-helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,19 @@ class NavigationHelpersClass {
return strippedNode;
}

/**
* Checks if for the given node path navigation should be prevented or not
* @param {string} nodepath path to check
* @returns {boolean} navigation should be prevented or not
*/
async shouldPreventNavigationForPath(nodepath) {
const { nodeObject } = await Navigation.extractDataFromPath(nodepath);
if (await Navigation.shouldPreventNavigation(nodeObject)) {
return true;
}
return false;
}

/**
* Returns a nested property value defined by a chain string
* @param {*} obj the object
Expand Down
36 changes: 35 additions & 1 deletion core/test/utilities/helpers/navigation-helpers.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
const chai = require('chai');
const assert = chai.assert;
const sinon = require('sinon');
import { AuthHelpers, NavigationHelpers } from '../../../src/utilities/helpers';
import { AuthHelpers, NavigationHelpers, GenericHelpers, RoutingHelpers } from '../../../src/utilities/helpers';
import { LuigiAuth, LuigiConfig } from '../../../src/core-api';
import { Routing } from '../../../src/services/routing';
import { Navigation } from '../../../src/navigation/services/navigation';

describe('Navigation-helpers', () => {
describe('isNodeAccessPermitted', () => {
Expand Down Expand Up @@ -234,6 +235,39 @@ describe('Navigation-helpers', () => {
});
});

describe('shouldPreventNavigationForPath', () => {
afterEach(() => {
sinon.restore();
sinon.reset();
});

it('returns true when navigation should be prevented for path', async () => {
sinon.stub(Navigation, 'getNavigationPath').returns('testPreventNavigation');
sinon.stub(RoutingHelpers, 'getLastNodeObject').returns({
pathSegment: 'testPreventNavigation',
label: 'Prevent navigation conditionally',
onNodeActivation: () => {
return false;
}
});
const actual = await NavigationHelpers.shouldPreventNavigationForPath('testPreventNavigation');
assert.equal(actual, true);
});

it('returns false when navigation should not be prevented for path', async () => {
sinon.stub(Navigation, 'getNavigationPath').returns('testNotPreventNavigation');
sinon.stub(RoutingHelpers, 'getLastNodeObject').returns({
pathSegment: 'testNotPreventNavigation',
label: 'Do not prevent navigation conditionally',
onNodeActivation: () => {
return true;
}
});
const actual = await NavigationHelpers.shouldPreventNavigationForPath('testNotPreventNavigation');
assert.equal(actual, false);
});
});

describe('node title data', () => {
let object;

Expand Down
14 changes: 14 additions & 0 deletions docs/luigi-client-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,20 @@ LuigiClient.linkManager().withoutSync().fromClosestContext().navigate('settings'

- **since**: 0.7.7

#### newTab

Enables navigating to a new tab.

##### Examples

```javascript
LuigiClient.linkManager().newTab().navigate('/projects/xy/foobar');
```

**Meta**

- **since**: NEXT_RELEASE

#### navigate

Navigates to the given path in the application hosted by Luigi. It contains either a full absolute path or a relative path without a leading slash that uses the active route as a base. This is the standard navigation.
Expand Down
19 changes: 19 additions & 0 deletions test/e2e-test-application/src/app/project/project.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,25 @@ <h3 class="fd-layout-panel__title">Navigate</h3>
>
</app-code-snippet>
</li>
<li class="fd-list__item">
<a
href="javascript:void(0)"
class="fd-link"
(click)="
linkManager()
.fromClosestContext()
.withParams({ foo: 'bar' })
.newTab()
.navigate('settings')
"
>
navigate to new tab, using closest context and params</a
>
<app-code-snippet
data="linkManager().fromClosestContext().withParams({ foo: 'bar' }).newTab().navigate('settings')"
>
</app-code-snippet>
</li>
</ul>
</div>
</div>
Expand Down

0 comments on commit 71060de

Please sign in to comment.