Skip to content

Commit

Permalink
Appswitcher enhancements (#4137)
Browse files Browse the repository at this point in the history
  • Loading branch information
hardl authored Feb 12, 2025
1 parent 9ced5e6 commit 9cb65f7
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 28 deletions.
54 changes: 35 additions & 19 deletions core/src/navigation/services/header.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { StateHelpers, GenericHelpers } from '../../utilities/helpers';
import { LuigiConfig, LuigiI18N, LuigiUX } from './../../core-api';
import { get } from 'lodash';

export const processHeaderSettings = component => {
export const processHeaderSettings = (component) => {
StateHelpers.doOnStoreChange(
component.store,
() => {
Expand All @@ -20,7 +21,7 @@ export const processHeaderSettings = component => {
component.get().showMainAppEntry ||
(component.get().appSwitcherItems && component.get().appSwitcherItems.length > 0)
});
return LuigiConfig.getConfigValueAsync('settings.header').then(header => {
return LuigiConfig.getConfigValueAsync('settings.header').then((header) => {
if (header) {
component.set({ defaultTitle: header.title || '' });
component.set({ defaultSubTitle: header.subTitle || '' });
Expand Down Expand Up @@ -75,30 +76,45 @@ const segmentMatches = (linkSegment, pathSegment, pathParams) => {
return false;
};

export const updateTitle = component => {
const checkMatch = (route, pathData, pathParams) => {
let match = true;
GenericHelpers.trimTrailingSlash(GenericHelpers.trimLeadingSlash(route))
.split('/')
.forEach((pathSegment, index) => {
if (match) {
if (index + 1 >= pathData.length) {
match = false;
} else if (
!pathData[index + 1].pathSegment ||
!segmentMatches(pathSegment, pathData[index + 1].pathSegment, pathParams)
) {
match = false;
}
}
});
return match;
};

export const updateTitle = (component) => {
const appSwitcherItems = component.get().appSwitcherItems;
const pathData = component.get().pathData;
const pathParams = component.get().pathParams;
let selectedItem;
if (appSwitcherItems && pathData) {
[...appSwitcherItems]
.sort((el1, el2) => (el2.link || '').localeCompare(el1.link || ''))
.some(item => {
let match = true;
GenericHelpers.trimTrailingSlash(GenericHelpers.trimLeadingSlash(item.link))
.split('/')
.forEach((pathSegment, index) => {
if (match) {
if (index + 1 >= pathData.length) {
match = false;
} else if (
!pathData[index + 1].pathSegment ||
!segmentMatches(pathSegment, pathData[index + 1].pathSegment, pathParams)
) {
match = false;
}
}
});
.some((item) => {
let match = checkMatch(item.link, pathData, pathParams);

if (!match && item.selectionConditions?.route) {
match = checkMatch(item.selectionConditions.route, pathData, pathParams);
if (match) {
(item.selectionConditions.contextCriteria || []).forEach((ccrit) => {
match = match && get(pathData._context, ccrit.key) === ccrit.value;
});
}
}

if (match) {
selectedItem = item;
}
Expand Down
103 changes: 94 additions & 9 deletions core/test/header.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@ const headerService = require('../src/navigation/services/header');
const assert = require('chai').assert;
const sinon = require('sinon');

describe('Header', function() {
describe('processHeaderSettings', function() {
describe('Header', function () {
describe('processHeaderSettings', function () {
let clock;
let component;
const setHeaderSettings = headerSettings => {
const setHeaderSettings = (headerSettings) => {
window.Luigi.config = {
settings: {
header: Object.assign({}, headerSettings)
}
};
};

const addToConfig = addition => {
const addToConfig = (addition) => {
window.Luigi.config = { ...window.Luigi.config, ...addition };
};

Expand All @@ -23,13 +23,13 @@ describe('Header', function() {
let componentData = {};
component = {
get: () => componentData,
set: o => {
set: (o) => {
componentData = { ...componentData, ...o };
},
store: {
on: (e, cb) => {},
get: () => {},
subscribe: fn => fn(),
subscribe: (fn) => fn(),
subscribeToScope: () => {}
}
};
Expand Down Expand Up @@ -274,7 +274,7 @@ describe('Header', function() {

describe('updateTitle', () => {
let component;
const setHeaderSettings = headerSettings => {
const setHeaderSettings = (headerSettings) => {
window.Luigi.config = {
settings: {
header: Object.assign({}, headerSettings)
Expand All @@ -286,13 +286,13 @@ describe('Header', function() {
let componentData = {};
component = {
get: () => componentData,
set: o => {
set: (o) => {
componentData = { ...componentData, ...o };
},
store: {
on: (e, cb) => {},
get: () => {},
subscribe: fn => fn(),
subscribe: (fn) => fn(),
subscribeToScope: () => {}
}
};
Expand Down Expand Up @@ -422,5 +422,90 @@ describe('Header', function() {
headerService.updateTitle(component);
assert.equal(document.title, 'Luigi Two');
});

it('set appSwitcherItems with selection conditions, update title', () => {
const headerSettings = {
title: 'Luigi',
subTitle: 'one'
};
setHeaderSettings(headerSettings);

document.title = '';
const items = [
{
title: 'Luigi One',
subTitle: 'project one',
link: '/projects/pr1'
},
{
title: 'Luigi Two',
subTitle: 'project two',
link: '/projects/pr2',
selectionConditions: {
route: '/something/else',
contextCriteria: [
{
key: 'some.key',
value: 'value'
},
{
key: 'some.otherkey',
value: 'value'
}
]
}
}
];
const pathData = [
{
children: [{ pathSegment: 'overview' }, { pathSegment: 'something' }]
},
{
pathSegment: 'something',
children: [
{
pathSegment: 'else'
}
]
},
{
pathSegment: 'else'
}
];

component.set({
appSwitcherItems: items
});
component.set({
pathData: pathData
});
headerService.updateTitle(component);
assert.notEqual(document.title, 'Luigi Two');

pathData._context = {
some: {
key: 'value'
}
};
component.set({
pathData: pathData
});

headerService.updateTitle(component);
assert.notEqual(document.title, 'Luigi Two');

pathData._context = {
some: {
key: 'value',
otherkey: 'value'
}
};
component.set({
pathData: pathData
});

headerService.updateTitle(component);
assert.equal(document.title, 'Luigi Two');
});
});
});
3 changes: 3 additions & 0 deletions docs/navigation-parameters-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -1164,6 +1164,9 @@ The app switcher is a dropdown list available in the top navigation bar. It allo
- **title** defines the application title. This is shown in the **appSwitcher** drop-down as well as the title in the header of the Luigi application if a user is in the context of the app.
- **subTitle** defines the application sub-title. This is shown as the sub-title in the header of the Luigi application if a user is in the context of the app.
- **link** is a link within the Luigi application that defines the root of the app. It is used to switch to the application if the drop-down entry is selected. It is also used to determine if a user is within the app's scope, so that the corresponding title and sub-title can be rendered in the header.
- **selectionConditions**
- **type**: Object
- **description**: It allows to specify additional "selected state" conditions, next to `link` match. The object should contain a `route` property to specify an additional path that is matched by this item, as well as `contextCriteria`, an Array of `key: string, value:string` objects, each of which can define a context key and a matching value (all contextCriteria must match).
### showMainAppEntry
- **type**: boolean
Expand Down

0 comments on commit 9cb65f7

Please sign in to comment.