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

Add newTab option to linkManager #2190

Merged
merged 8 commits into from
Aug 23, 2021
Merged
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
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) {
Comment on lines +1245 to +1249
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Added if clause that checks if newTab is activated.

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
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