Add Portal Settings Web Part with styles, localization, and tests

- Implemented the PortalSettings Web Part with a new manifest and TypeScript file.
- Created SCSS styles for the Web Part, defining various UI elements and responsive design.
- Added localization support for English and German languages.
- Developed tests for Provider Registry and static assets validation.
- Included PowerShell script for project validation.
This commit is contained in:
Torsten Brendgen
2026-07-21 22:43:35 +02:00
parent 62fef65c12
commit 10f7463094
49 changed files with 2411 additions and 462 deletions

220
README.md
View File

@@ -1,67 +1,201 @@
# PortalSettings
# PortalSettings V3
PortalSettings wird einmal im Root Web einer Site Collection installiert. Die Seite erkennt registrierte
Einstellungsanbieter automatisch und zeigt nur Tabs fuer tatsaechlich vorhandene Solutions.
PortalSettings V3 ist ein providerbasiertes SPFx-WebPart für SharePoint Server Subscription Edition. Es wird einmal im Root Web einer Site Collection installiert und verwaltet die zentralen beziehungsweise lokalen Einstellungen erkannter Portal-Erweiterungen.
Aktuell verwaltet sie:
## Version und Voraussetzungen
- Custom Branding
- Mega Menu
- ExpiryIndicator
| Eigenschaft | Wert |
|---|---|
| Version | 3.0.0 |
| SharePoint Framework | 1.4.1 |
| Build-Node | 8.17.0 |
| npm | 6.x |
| Gulp | lokal 3.9.1 |
| Komponente | Client-Side WebPart |
Fuer Mega Menu wird das Termset ueber einen durchsuchbaren Picker aus dem Default Site Collection Term Store ausgewaehlt. PortalSettings speichert Termset-ID, Namen, Cache-Dauer und Debug-Modus einmal zentral im Property Bag des Root Webs. Beim Speichern werden identische Runtime-Bindungen rekursiv auf das Root Web und alle vorhandenen Unterwebs synchronisiert. Individuelle Stylesheets werden ausschliesslich ueber Custom Branding eingebunden.
Die frühere provisionierte `PortalSettings.aspx` und der leere Application Customizer wurden entfernt. Die Oberfläche wird vollständig vom WebPart erzeugt und verwendet kein `innerHTML`.
## ExpiryIndicator 2.1
## Unterstützte Solutions
- Site-Collection-Standard im Property Bag des Root Webs,
- Inventar aller durch das Aktivierungsskript registrierten Bindungen in Root Web und Subwebs,
- Popup zum Anbinden vorhandener Datumsfelder ohne PowerShell,
- Vererbung des zentralen Standards durch alle Bindungen,
- weiterhin moegliche lokale Ausnahmen in `ClientSideComponentProperties` des gebundenen Feldes,
- keine zusaetzliche Konfigurationsliste,
- Unterstuetzung alter Einzelregeln und verschachtelter V2-Regeln mit `and`/`or`,
- Validierung und Formatierung der vollstaendigen JSON-Konfiguration vor dem Speichern.
### MegaMenu
Die Prioritaet lautet: lokale Feldausnahme, Subweb-Override, Site-Collection-Standard, eingebauter Standard.
PortalSettings bleibt fuer den Betrieb des ExpiryIndicators optional.
- Erkennung der zentralen `SPSite.UserCustomAction`
- Auswahl des Navigationstermsets aus dem Default Site Collection Term Store
- Mega-Menu- oder Flyout-Modus
- Cache-Dauer und Cache-Version
- Debug-Modus
- schemaerhaltendes Speichern unbekannter Properties
## Erkennung
### CustomBranding
- Custom Branding wird anhand seiner aktiven Application-Customizer-UserCustomAction erkannt.
- Mega Menu wird anhand seiner zentralen Root-Web-Konfiguration oder einer aktiven Runtime-Bindung erkannt.
- ExpiryIndicator registriert einen Solution-Descriptor und sein Bindungsinventar im Property Bag des Root Webs.
- zentrale `SPSite.UserCustomAction`
- Aktivierung und Debug-Modus
- CSS-Dateien inklusive `media`
- Allowlist externer CSS-Hosts
- Header- und Footer-Elemente
- Sicherheitsprüfung von Tags, Event-Attributen, URLs, Tiefe und Elementanzahl
- Kompatibilität mit dem Legacy-Root-Array `elements`
Custom Branding kann beim Speichern auf eine site-scoped UserCustomAction angehoben werden. Mega Menu verwendet wegen der On-Premises-Loader-Eigenheiten bewusst web-scoped Runtime-Bindungen. Die fachliche Konfiguration bleibt dennoch einmalig und zentral: PortalSettings speichert sie im Root Web und verteilt sie auf alle vorhandenen Webs. Fuer spaeter neu angelegte Unterwebs wird die Konfiguration einfach erneut gespeichert, wodurch die Synchronisierung idempotent nachgezogen wird.
### ExpiryIndicator
Neue eigene Solutions werden zentral im Provider-Register in `PortalSettings.aspx` hinterlegt. Ein Provider
definiert Kennung, Anzeigename, Component-ID, Panel und Erkennungsart. So bleibt PortalSettings die gemeinsame
Admin-Oberflaeche, ohne dass nicht installierte Solutions leere Tabs erzeugen.
- Site-Collection-Standard aus dem Root-Web-Property-Bag
- Übersicht registrierter Listen- und Bibliotheksbindungen
- Web-, Listen- und Datumsfeldauswahl ohne Eingabe technischer IDs
- Anbinden eines vorhandenen Datumsfeldes
- zentrale Laufzeiten, Farben und AND-/OR-Regeln
- lokale Ausnahmen pro Bindung
- Umschalten einer Bindung auf Vererbung
- Validierung von internen Feldnamen, Laufzeiten, Farbregeln und Bedingungsgruppen
## Architektur
```text
PortalSettingsWebPart
├── ProviderRegistry
│ ├── MegaMenuSettingsProvider
│ ├── CustomBrandingSettingsProvider
│ └── ExpiryIndicatorSettingsProvider
├── DynamicFormRenderer
│ ├── Sections und Überschriften
│ ├── Hinweise und Trennlinien
│ ├── Text, Zahl, Toggle und Choice Cards
│ ├── Termset-Picker
│ ├── JSON- und Listen-Editoren
│ ├── Bindungsinventar
│ └── Zusammenfassung und JSON-Vorschau
└── Storage
├── SPSite.UserCustomActions
├── Root-Web-Property-Bag
└── Field.ClientSideComponentProperties
```
Provider beschreiben fachliche Felder und Layout deklarativ. Der Renderer kennt keine MegaMenu-, Branding- oder ExpiryIndicator-Sonderformulare. Neue Standardfelder benötigen deshalb keine Änderung am Renderer.
Spezielle Infrastruktur wie Taxonomy oder Field-Customizer-Bindungen wird über geprüfte Services angebunden. Provider dürfen kein freies HTML, JavaScript oder CSS liefern.
## Layout-Elemente
Ein Provider kann folgende Elementtypen verwenden:
- `heading`, `text`, `notice`, `divider`, `group`
- `textField`, `number`, `boolean`
- `choice`, `choiceCards`
- `termSet`, `stringList`, `json`
- `bindingInventory`
- `propertySummary`, `jsonPreview`
Sections unterstützen ein-, zwei- und dreispaltige Layouts, optionale Beschreibungstexte sowie einklappbare Expertenbereiche. Elemente können über `visibleWhen` abhängig von anderen Konfigurationswerten erscheinen.
Das Styling verwendet ausschließlich SharePoint-Themeslots wie `themePrimary`, `neutralPrimary`, `neutralLight` und `white`. Responsive Layout, Tastaturfokus, Forced Colors und reduzierte Bewegung sind berücksichtigt.
## Provider-Vertrag
Ein Provider implementiert:
```ts
interface ISettingsProvider<TConfig> {
key: string;
displayName: string;
description: string;
schemaVersion: number;
minimumPortalSettingsVersion: string;
componentIds: string[];
storage: IProviderStorageDefinition;
sections: ISettingsSection[];
createDefault(): TConfig;
normalize(value: any): TConfig;
validate(value: TConfig): string[];
}
```
Neue Provider werden unter `src/providers` angelegt und einmal in `ProviderRegistry.ts` registriert. Ein Provider definiert selbst:
- Erkennungs-IDs
- Speicherart
- Konfigurationsversion
- Sections und Layout
- Felder und Hilfetexte
- Normalisierung
- Validierung
- Standardwerte
## Schutz vor Datenverlust
PortalSettings normalisiert gelesene Werte für die Anzeige, überschreibt beim Speichern aber nicht blind das komplette Objekt. Bearbeitete Werte werden rekursiv in die ursprüngliche Konfiguration gemergt. Unbekannte zukünftige Properties bleiben dadurch erhalten.
JSON-Editoren ändern das Modell nur, wenn der aktuelle Inhalt gültiges JSON ist. Unsichere CustomBranding-Strukturen und ungültige ExpiryIndicator-Regeln werden vor dem Speichern abgelehnt.
## Berechtigungen
Das WebPart zeigt die Verwaltungsoberfläche nur Site-Collection-Administratoren. Die eigentliche Sicherheitsgrenze bleiben die SharePoint-Berechtigungen der REST-Endpunkte.
Für ExpiryIndicator-Bindungen werden zusätzlich Berechtigungen zum Verwalten der betreffenden Liste und Felder benötigt.
## Build
Die Solution verwendet die SPFx-1.4.1-Toolchain und wird reproduzierbar mit Node.js 8.17.0 gebaut:
```powershell
npm install
npm test
npm run package
```
Das Paket liegt danach unter `sharepoint/solution/portal-settings.sppkg`.
Das Paket entsteht unter:
## Installation und Upgrade
```text
sharepoint/solution/portal-settings.sppkg
```
1. `portal-settings.sppkg` im App Catalog durch Version `2.2.0.0` ersetzen.
2. PortalSettings im Root Web der Site Collection installieren beziehungsweise aktualisieren.
3. `expiry-indicator.sppkg` durch Version `2.1.0.0` ersetzen und die App aktualisieren.
4. `/SitePages/PortalSettings.aspx` mit geleertem Browsercache laden.
5. **ExpiryIndicator anbinden** auswaehlen und Web-URL, Listentitel und internen Namen des vorhandenen
Datumsfeldes eingeben. Optional werden Classic ScriptLink und Ribbon-Befehl mitregistriert.
`npm run package` führt die Provider- und statischen Sicherheitsprüfungen vor dem Ship-Build aus.
Das PowerShell-Skript bleibt fuer automatisierte Rollouts und Massenbereitstellungen erhalten, ist fuer eine
manuelle Bindung ueber PortalSettings aber nicht mehr erforderlich.
## Installation
Der ExpiryIndicator-Tab erscheint erst, wenn mindestens eine Bindung registriert ist, ein zentraler Standard
existiert oder der Solution-Descriptor im Root Web vorhanden ist.
1. `portal-settings.sppkg` im App Catalog durch Version `3.0.0.0` ersetzen.
2. Die App im Root Web der gewünschten Site Collection installieren oder aktualisieren.
3. Eine moderne Seite erstellen.
4. Das WebPart **Portal Settings** einmal auf der Seite hinzufügen.
5. Die Seite veröffentlichen und nur für die gewünschte Administratorgruppe verlinken.
Zum Anbinden werden mindestens die Berechtigungen **Listen verwalten** und zum Registrieren der optionalen
Classic-Webaktion **Web verwalten** benoetigt. Die ExpiryIndicator-App muss zuvor im Root Web installiert sein.
Optional kann eine Seite per PnP PowerShell erzeugt werden:
```powershell
.\deployment\Add-PortalSettingsPage.ps1 `
-SiteUrl 'http://clshp001/sites/target' `
-PageName 'PortalSettingsV3' `
-Publish
```
Die Standardseite heißt absichtlich `PortalSettingsV3.aspx`, damit die alte V2-Seite während der Abnahme erhalten bleiben kann.
## Migration von V2
V3 liest die vorhandenen Konfigurationsorte direkt weiter:
- MegaMenu und CustomBranding aus zentralen UserCustomActions
- ExpiryIndicator-Defaults, Descriptor und Bindungsinventar aus dem Root Web
- lokale ExpiryIndicator-Ausnahmen aus dem gebundenen Feld
Es ist keine Datenmigration in eine neue Liste erforderlich. Empfohlenes Vorgehen:
1. V3-Paket installieren.
2. `PortalSettingsV3.aspx` parallel zur alten Seite bereitstellen.
3. Alle drei Provider laden und Konfigurationen testweise speichern.
4. Root Web und Subwebs prüfen.
5. Erst danach die alte `PortalSettings.aspx` löschen oder archivieren.
## Diagnose
Wenn kein Tab erscheint, muss zunächst die zentrale Registrierung der jeweiligen Solution vorhanden sein. PortalSettings erkennt keine bloß im App Catalog hochgeladene, aber nicht für die Site Collection registrierte Runtime.
Browserkonsole:
```javascript
performance.getEntriesByType('resource')
.map(function (entry) { return entry.name; })
.filter(function (url) { return url.toLowerCase().indexOf('portal-settings') >= 0; });
```
Die sichtbare Statusmeldung enthält REST-Statuscode und SharePoint-Fehlertext, wenn Lesen oder Speichern fehlschlägt.