dev-3.0 #1

Merged
Torsten merged 10 commits from dev-3.0 into main 2026-08-18 20:49:15 +00:00
7 changed files with 36 additions and 16 deletions
Showing only changes of commit 84307cd078 - Show all commits
+3 -2
View File
@@ -6,7 +6,7 @@ PortalSettings V3 ist ein providerbasiertes SPFx-WebPart für SharePoint Server
| Eigenschaft | Wert | | Eigenschaft | Wert |
|---|---| |---|---|
| Version | 3.2.0 | | Version | 3.2.1 |
| SharePoint Framework | 1.4.1 | | SharePoint Framework | 1.4.1 |
| Build-Node | 8.17.0 | | Build-Node | 8.17.0 |
| npm | 6.x | | npm | 6.x |
@@ -48,6 +48,7 @@ Die Oberfläche wird vollständig vom WebPart erzeugt und verwendet kein `innerH
### ExpiryIndicator ### ExpiryIndicator
- Erkennung direkt nach der App-Installation über den Application Customizer im Root Web
- Site-Collection-Standard aus dem Root-Web-Property-Bag - Site-Collection-Standard aus dem Root-Web-Property-Bag
- Übersicht registrierter Listen- und Bibliotheksbindungen - Übersicht registrierter Listen- und Bibliotheksbindungen
- Web-, Listen- und Datumsfeldauswahl ohne Eingabe technischer IDs - Web-, Listen- und Datumsfeldauswahl ohne Eingabe technischer IDs
@@ -164,7 +165,7 @@ sharepoint/solution/portal-settings.sppkg
## Installation ## Installation
1. `portal-settings.sppkg` im App Catalog durch Version `3.2.0.0` ersetzen. 1. `portal-settings.sppkg` im App Catalog durch Version `3.2.1.0` ersetzen.
2. Die App im Root Web der gewünschten Site Collection installieren oder aktualisieren. 2. Die App im Root Web der gewünschten Site Collection installieren oder aktualisieren.
3. Die App provisioniert automatisch die veröffentlichte Seite `SitePages/PortalSettings.aspx` mit dem WebPart. 3. Die App provisioniert automatisch die veröffentlichte Seite `SitePages/PortalSettings.aspx` mit dem WebPart.
4. Eine bereits vorhandene `PortalSettings.aspx` wird nicht überschrieben. 4. Eine bereits vorhandene `PortalSettings.aspx` wird nicht überschrieben.
+2 -1
View File
@@ -2,7 +2,7 @@
Stand: 21.07.2026 Stand: 21.07.2026
Branch: `dev-3.0` Branch: `dev-3.0`
Zielversion: 3.2.0 Zielversion: 3.2.1
## Architektur ## Architektur
@@ -40,6 +40,7 @@ Zielversion: 3.2.0
- [x] CustomBranding-Vertragsmarker und Component-ID-Fallback unterstützt. - [x] CustomBranding-Vertragsmarker und Component-ID-Fallback unterstützt.
- [x] Branding-Sicherheitsprüfung vor dem Speichern. - [x] Branding-Sicherheitsprüfung vor dem Speichern.
- [x] ExpiryIndicator-Site-Collection-Standard abgebildet. - [x] ExpiryIndicator-Site-Collection-Standard abgebildet.
- [x] ExpiryIndicator direkt über seine Root-Web-Application-Customizer-Action erkennen.
- [x] Expiry-Bindungsinventar dargestellt. - [x] Expiry-Bindungsinventar dargestellt.
- [x] Web-, Listen- und Datumsfeld-Picker umgesetzt. - [x] Web-, Listen- und Datumsfeld-Picker umgesetzt.
- [x] Neue Field-Customizer-Bindung aus dem WebPart möglich. - [x] Neue Field-Customizer-Bindung aus dem WebPart möglich.
+1 -1
View File
@@ -3,7 +3,7 @@
"solution": { "solution": {
"name": "portal-settings-client-side-solution", "name": "portal-settings-client-side-solution",
"id": "1c98e32d-bb7b-43b7-9625-074d6e4ea286", "id": "1c98e32d-bb7b-43b7-9625-074d6e4ea286",
"version": "3.2.0.0", "version": "3.2.1.0",
"includeClientSideAssets": true, "includeClientSideAssets": true,
"skipFeatureDeployment": false, "skipFeatureDeployment": false,
"features": [ "features": [
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "portal-settings", "name": "portal-settings",
"version": "3.2.0", "version": "3.2.1",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "portal-settings", "name": "portal-settings",
"version": "3.2.0", "version": "3.2.1",
"private": true, "private": true,
"main": "lib/index.js", "main": "lib/index.js",
"engines": { "engines": {
+22 -8
View File
@@ -32,13 +32,16 @@ export class PortalSettingsDataService {
} }
public load(providers: Array<ISettingsProvider<any>>): Promise<ILoadedSettingsProvider[]> { public load(providers: Array<ISettingsProvider<any>>): Promise<ILoadedSettingsProvider[]> {
return Promise.all([this.getSiteActions(), this.getRootProperties()]) return Promise.all([this.getSiteActions(), this.getRootWebActions(), this.getRootProperties()])
.then((values: any[]): ILoadedSettingsProvider[] => { .then((values: any[]): ILoadedSettingsProvider[] => {
const actions: IUserCustomActionInfo[] = values[0]; const siteActions: IUserCustomActionInfo[] = values[0];
const properties: any = values[1]; const registrationActions: IUserCustomActionInfo[] = siteActions.concat(values[1]);
const properties: any = values[2];
const loaded: ILoadedSettingsProvider[] = []; const loaded: ILoadedSettingsProvider[] = [];
for (let i: number = 0; i < providers.length; i++) { for (let i: number = 0; i < providers.length; i++) {
const result: ILoadedSettingsProvider = this.loadProvider(providers[i], actions, properties); const result: ILoadedSettingsProvider = this.loadProvider(
providers[i], siteActions, registrationActions, properties
);
if (result) { loaded.push(result); } if (result) { loaded.push(result); }
} }
return loaded; return loaded;
@@ -178,13 +181,14 @@ export class PortalSettingsDataService {
private loadProvider( private loadProvider(
provider: ISettingsProvider<any>, provider: ISettingsProvider<any>,
actions: IUserCustomActionInfo[], siteActions: IUserCustomActionInfo[],
registrationActions: IUserCustomActionInfo[],
properties: any properties: any
): ILoadedSettingsProvider | undefined { ): ILoadedSettingsProvider | undefined {
let raw: any; let raw: any;
const context: IProviderLoadContext = {}; const context: IProviderLoadContext = {};
if (provider.storage.kind === 'siteUserCustomAction') { if (provider.storage.kind === 'siteUserCustomAction') {
const action: IUserCustomActionInfo = this.findAction(provider, actions); const action: IUserCustomActionInfo = this.findAction(provider, siteActions);
if (!action && !provider.storage.action) { return undefined; } if (!action && !provider.storage.action) { return undefined; }
if (action) { if (action) {
context.action = action; context.action = action;
@@ -197,7 +201,7 @@ export class PortalSettingsDataService {
const stored: any = this.getProperty(properties, propertyKey); const stored: any = this.getProperty(properties, propertyKey);
const descriptor: any = this.getProperty(properties, DescriptorProperty); const descriptor: any = this.getProperty(properties, DescriptorProperty);
const bindingsValue: any = this.getProperty(properties, BindingsProperty); const bindingsValue: any = this.getProperty(properties, BindingsProperty);
const registration: IUserCustomActionInfo = this.findAnyAction(provider, actions); const registration: IUserCustomActionInfo = this.findAnyAction(provider, registrationActions);
if (!stored && !descriptor && !bindingsValue && !registration) { return undefined; } if (!stored && !descriptor && !bindingsValue && !registration) { return undefined; }
if (registration) { context.action = registration; } if (registration) { context.action = registration; }
raw = this.parseJson(stored, provider.createDefault()); raw = this.parseJson(stored, provider.createDefault());
@@ -218,8 +222,18 @@ export class PortalSettingsDataService {
private getSiteActions(): Promise<IUserCustomActionInfo[]> { private getSiteActions(): Promise<IUserCustomActionInfo[]> {
const url: string = this.siteUrl + '/_api/site/UserCustomActions' + const url: string = this.siteUrl + '/_api/site/UserCustomActions' +
'?$select=Id,Title,Name,Location,ClientSideComponentId,ClientSideComponentProperties'; '?$select=Id,Title,Name,Location,ClientSideComponentId,ClientSideComponentProperties';
return this.getActions(url, 'Site-Collection-UserCustomActions konnten nicht gelesen werden.');
}
private getRootWebActions(): Promise<IUserCustomActionInfo[]> {
const url: string = this.siteUrl + '/_api/site/rootweb/UserCustomActions' +
'?$select=Id,Title,Name,Location,ClientSideComponentId,ClientSideComponentProperties';
return this.getActions(url, 'Root-Web-UserCustomActions konnten nicht gelesen werden.');
}
private getActions(url: string, errorMessage: string): Promise<IUserCustomActionInfo[]> {
return this.context.spHttpClient.get(url, SPHttpClient.configurations.v1, { headers: this.readHeaders() }) return this.context.spHttpClient.get(url, SPHttpClient.configurations.v1, { headers: this.readHeaders() })
.then((response: SPHttpClientResponse): Promise<any> => this.ensureJson(response, 'UserCustomActions konnten nicht gelesen werden.')) .then((response: SPHttpClientResponse): Promise<any> => this.ensureJson(response, errorMessage))
.then((payload: any): IUserCustomActionInfo[] => this.results(payload).map((source: any): IUserCustomActionInfo => ({ .then((payload: any): IUserCustomActionInfo[] => this.results(payload).map((source: any): IUserCustomActionInfo => ({
id: this.normalizeGuid(source.Id), id: this.normalizeGuid(source.Id),
title: source.Title || '', title: source.Title || '',
+6 -2
View File
@@ -23,9 +23,10 @@ var sourceFiles = [
'src/ui/DynamicFormRenderer.ts', 'src/ui/DynamicFormRenderer.ts',
'src/ui/PortalSettingsApp.ts' 'src/ui/PortalSettingsApp.ts'
].map(read).join('\n'); ].map(read).join('\n');
var dataService = read('src/services/PortalSettingsDataService.ts');
assert(packageJson.version === '3.2.0', 'Package-Version ist nicht 3.2.0.'); assert(packageJson.version === '3.2.1', 'Package-Version ist nicht 3.2.1.');
assert(solution.version === '3.2.0.0', 'Solution-Version ist nicht 3.2.0.0.'); assert(solution.version === '3.2.1.0', 'Solution-Version ist nicht 3.2.1.0.');
assert(solution.features && solution.features.length === 1, 'Das Seiten-Provisioning-Feature fehlt.'); assert(solution.features && solution.features.length === 1, 'Das Seiten-Provisioning-Feature fehlt.');
assert(solution.features[0].assets.elementManifests.indexOf('elements.xml') >= 0 && assert(solution.features[0].assets.elementManifests.indexOf('elements.xml') >= 0 &&
solution.features[0].assets.elementFiles.indexOf('PortalSettings.aspx') >= 0 && solution.features[0].assets.elementFiles.indexOf('PortalSettings.aspx') >= 0 &&
@@ -47,6 +48,9 @@ assert(upgradeActions.indexOf('71841e33-8bbd-4007-83a6-d950453226a2\\elements.xm
'Die Upgrade-Provisionierung fehlt.'); 'Die Upgrade-Provisionierung fehlt.');
assert(!fs.existsSync(path.join(root, 'src/extensions/portalSettings/PortalSettingsApplicationCustomizer.ts')), 'Alter Application Customizer ist noch vorhanden.'); assert(!fs.existsSync(path.join(root, 'src/extensions/portalSettings/PortalSettingsApplicationCustomizer.ts')), 'Alter Application Customizer ist noch vorhanden.');
assert(sourceFiles.indexOf('innerHTML') < 0, 'UI darf innerHTML nicht verwenden.'); assert(sourceFiles.indexOf('innerHTML') < 0, 'UI darf innerHTML nicht verwenden.');
assert(dataService.indexOf('/_api/site/rootweb/UserCustomActions') >= 0 &&
dataService.indexOf('siteActions.concat(values[1])') >= 0,
'Root-Web-Actions werden nicht für die Provider-Erkennung berücksichtigt.');
['themePrimary', 'neutralPrimary', 'neutralLight', 'white'].forEach(function (slot) { ['themePrimary', 'neutralPrimary', 'neutralLight', 'white'].forEach(function (slot) {
assert(styles.indexOf('[theme: ' + slot + ', default:') >= 0, 'Themeslot fehlt: ' + slot); assert(styles.indexOf('[theme: ' + slot + ', default:') >= 0, 'Themeslot fehlt: ' + slot);
}); });