Add Current Navigation Application Customizer
- Created a new SPFx Application Customizer for current navigation. - Implemented core functionality to fetch and render navigation items from a SharePoint term set. - Added styles for the navigation component using SCSS. - Included localization support for English and German languages. - Developed unit tests for core navigation functionalities. - Configured TypeScript and TSLint settings for the project. - Added validation scripts for static assets and package configuration.
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
import {
|
||||
buildCurrentNavigationItems, getLocalProperty, parseBoolean, resolveTermUrl, selectCurrentNavigationRoot
|
||||
} from '../src/services/CurrentNavigationCore';
|
||||
import { ICurrentNavigationTerm } from '../src/services/CurrentNavigationTypes';
|
||||
|
||||
let passed: number = 0;
|
||||
function assert(name: string, condition: boolean): void {
|
||||
if (!condition) { throw new Error('FAILED: ' + name); }
|
||||
passed++; console.log('OK:', name);
|
||||
}
|
||||
function term(value: any): ICurrentNavigationTerm { return value as ICurrentNavigationTerm; } // tslint:disable-line:no-any
|
||||
|
||||
const terms: ICurrentNavigationTerm[] = [
|
||||
term({ Id: 'root', Name: 'HR', PathOfTerm: 'HR', LocalCustomProperties: {
|
||||
'CurrentNavigation.Root': 'true', '_Sys_Nav_SimpleLinkUrl': '/sites/portal/hr/SitePages/Home.aspx'
|
||||
}}),
|
||||
term({ Id: 'docs', Name: 'Dokumente', PathOfTerm: 'HR;Dokumente', LocalCustomProperties: {
|
||||
'_Sys_Nav_SimpleLinkUrl': '/sites/portal/hr/Dokumente'
|
||||
}}),
|
||||
term({ Id: 'admin', Name: 'Administration', PathOfTerm: 'HR;Administration', LocalCustomProperties: {
|
||||
'CurrentNavigation.Hidden': 'true'
|
||||
}}),
|
||||
term({ Id: 'secret', Name: 'Intern', PathOfTerm: 'HR;Administration;Intern', LocalCustomProperties: {} }),
|
||||
term({ Id: 'forms', Name: 'Formulare', PathOfTerm: 'HR;Dokumente;Formulare', LocalCustomProperties: {} })
|
||||
];
|
||||
|
||||
assert('German boolean is accepted', parseBoolean('ja'));
|
||||
assert('local property is read', getLocalProperty(terms[0], 'CurrentNavigation.Root') === 'true');
|
||||
assert('site collection token resolves', resolveTermUrl(term({
|
||||
LocalCustomProperties: { '_Sys_Nav_SimpleLinkUrl': '~sitecollection/start' }
|
||||
}), 'https://portal/sites/a') === 'https://portal/sites/a/start');
|
||||
const root: ICurrentNavigationTerm = selectCurrentNavigationRoot(
|
||||
terms, 'https://portal/sites/portal/hr', 'https://portal/sites/portal'
|
||||
);
|
||||
assert('root is selected through its site home URL', !!root && root.Id === 'root');
|
||||
const items = buildCurrentNavigationItems(terms, root, 'https://portal/sites/portal', 1031, 3, false);
|
||||
assert('root is not rendered by default', items.length === 1 && items[0].id === 'docs');
|
||||
assert('descendants are nested', items[0].items.length === 1 && items[0].items[0].id === 'forms');
|
||||
assert('hidden branch is removed', items.every(item => item.id !== 'admin'));
|
||||
const withRoot = buildCurrentNavigationItems(terms, root, 'https://portal/sites/portal', 1031, 3, true);
|
||||
assert('root can be rendered', withRoot.length === 1 && withRoot[0].id === 'root');
|
||||
const unordered = buildCurrentNavigationItems(
|
||||
[terms[4], terms[1], terms[0]], root, 'https://portal/sites/portal', 1031, 3, false
|
||||
);
|
||||
assert('hierarchy is independent of taxonomy response order',
|
||||
unordered.length === 1 && unordered[0].id === 'docs' && unordered[0].items[0].id === 'forms');
|
||||
console.log('CurrentNavigation core tests passed:', passed);
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5", "module": "commonjs", "moduleResolution": "node",
|
||||
"outDir": "../temp/tests", "rootDir": "..", "skipLibCheck": true,
|
||||
"types": [], "lib": ["es5", "dom", "es2015.collection"]
|
||||
},
|
||||
"files": [
|
||||
"../src/services/CurrentNavigationTypes.ts",
|
||||
"../src/services/CurrentNavigationCore.ts",
|
||||
"CurrentNavigationCore.test.ts"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
'use strict';
|
||||
var fs = require('fs');
|
||||
function read(path) { return fs.readFileSync(path, 'utf8'); }
|
||||
function json(path) { return JSON.parse(read(path)); }
|
||||
function assert(name, condition) { if (!condition) { throw new Error('FAILED: ' + name); } console.log('OK:', name); }
|
||||
var packageJson = json('package.json');
|
||||
var solution = json('config/package-solution.json').solution;
|
||||
var manifest = json('src/extensions/currentNavigation/CurrentNavigationApplicationCustomizer.manifest.json');
|
||||
var app = read('src/extensions/currentNavigation/CurrentNavigationApplicationCustomizer.ts');
|
||||
var renderer = read('src/extensions/currentNavigation/CurrentNavigationRenderer.ts');
|
||||
var service = read('src/services/CurrentNavigationTaxonomyService.ts');
|
||||
assert('package version', packageJson.version === '1.0.0');
|
||||
assert('solution version', solution.version === '1.0.0.0');
|
||||
assert('tenant deployment', solution.skipFeatureDeployment === true);
|
||||
assert('component type', manifest.extensionType === 'ApplicationCustomizer');
|
||||
assert('safe renderer', renderer.indexOf('innerHTML') < 0 && app.indexOf('innerHTML') < 0);
|
||||
assert('placeholder lifecycle cleanup', app.indexOf('changedEvent.remove') >= 0);
|
||||
assert('local properties loaded', service.indexOf('LocalCustomProperties') >= 0);
|
||||
assert('root property present', read('src/services/CurrentNavigationCore.ts').indexOf('CurrentNavigation.Root') >= 0);
|
||||
assert('hidden property present', read('src/services/CurrentNavigationCore.ts').indexOf('CurrentNavigation.Hidden') >= 0);
|
||||
console.log('CurrentNavigation static tests passed.');
|
||||
Reference in New Issue
Block a user