feat: Update version to 3.0.1 and enhance portal settings configuration
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# CustomBranding
|
# CustomBranding
|
||||||
|
|
||||||
CustomBranding 3.0 ist ein zentraler SPFx-1.4.1-Application-Customizer für SharePoint Server Subscription Edition. Die Solution lädt freigegebene Stylesheets und rendert eine kontrollierte Komponentenstruktur im oberen oder unteren SharePoint-Placeholder. Moderne und klassische Seiten verwenden dieselben `ClientSideComponentProperties`.
|
CustomBranding 3.0.1 ist ein zentraler SPFx-1.4.1-Application-Customizer für SharePoint Server Subscription Edition. Die Solution lädt freigegebene Stylesheets und rendert eine kontrollierte Komponentenstruktur im oberen oder unteren SharePoint-Placeholder. Moderne und klassische Seiten verwenden dieselben `ClientSideComponentProperties`.
|
||||||
|
|
||||||
Die Konfiguration liegt in genau einer `SPSite.UserCustomAction` pro Site Collection. Es werden weder eine versteckte Liste noch ein Property Bag benötigt. Dadurch gilt das Branding automatisch für das Root Web, vorhandene Subwebs und später angelegte Subwebs.
|
Die Konfiguration liegt in genau einer `SPSite.UserCustomAction` pro Site Collection. Es werden weder eine versteckte Liste noch ein Property Bag benötigt. Dadurch gilt das Branding automatisch für das Root Web, vorhandene Subwebs und später angelegte Subwebs.
|
||||||
|
|
||||||
@@ -79,6 +79,11 @@ Das aktuelle Konfigurationsschema hat die Version 2:
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"schemaVersion": 2,
|
"schemaVersion": 2,
|
||||||
|
"portalSettings": {
|
||||||
|
"providerKey": "custombranding",
|
||||||
|
"contractVersion": 1,
|
||||||
|
"minimumPortalSettingsVersion": "3.0.0"
|
||||||
|
},
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"debug": false,
|
"debug": false,
|
||||||
"allowedCssHosts": [],
|
"allowedCssHosts": [],
|
||||||
@@ -151,12 +156,15 @@ Der site-scoped ScriptLink gilt auch für später angelegte Subwebs. Entfernen l
|
|||||||
|
|
||||||
## PortalSettings v3
|
## PortalSettings v3
|
||||||
|
|
||||||
CustomBranding funktioniert unabhängig von PortalSettings. Das geplante PortalSettings-v3-Webpart kann die Action anhand folgender Werte erkennen und die Properties schemaerhaltend bearbeiten:
|
CustomBranding funktioniert unabhängig von PortalSettings. PortalSettings ab Version 3.0.1 kann die zentrale Action anhand folgender Werte erkennen, die Properties schemaerhaltend bearbeiten und eine noch fehlende Action beim ersten Speichern selbst anlegen:
|
||||||
|
|
||||||
- Component ID: `035ba968-6488-4d42-86b3-0470ffcc95b9`
|
- Component ID: `035ba968-6488-4d42-86b3-0470ffcc95b9`
|
||||||
- Location: `ClientSideExtension.ApplicationCustomizer`
|
- Location: `ClientSideExtension.ApplicationCustomizer`
|
||||||
- Scope: `SPSite.UserCustomActions`
|
- Scope: `SPSite.UserCustomActions`
|
||||||
- Schema: `schemaVersion: 2`
|
- Schema: `schemaVersion: 2`
|
||||||
|
- Provider-Marker: `portalSettings.providerKey: custombranding`
|
||||||
|
|
||||||
|
Ist noch keine Action vorhanden, erscheint CustomBranding in PortalSettings als **Bereit zur Aktivierung**. Voraussetzung ist lediglich, dass `custom-branding.sppkg` bereits im App Catalog bereitgestellt wurde. Der Button **CustomBranding aktivieren** erzeugt anschließend genau eine site-scoped Action. Das PowerShell-Skript bleibt für automatisierte Rollouts und Classic-ScriptLink-Registrierungen verfügbar.
|
||||||
|
|
||||||
Ein Editor muss unbekannte Properties erhalten und vor dem Speichern dieselben Element-, Attribut-, URL- und CSS-Grenzen beachten.
|
Ein Editor muss unbekannte Properties erhalten und vor dem Speichern dieselben Element-, Attribut-, URL- und CSS-Grenzen beachten.
|
||||||
|
|
||||||
@@ -195,7 +203,7 @@ window.CustomBrandingClassic.reload()
|
|||||||
|
|
||||||
## Upgrade von 1.x
|
## Upgrade von 1.x
|
||||||
|
|
||||||
1. Paket im App Catalog durch Version `3.0.0.0` ersetzen und bereitstellen.
|
1. Paket im App Catalog durch Version `3.0.1.0` ersetzen und bereitstellen.
|
||||||
2. `add-custombranding.ps1` einmal pro Site Collection ausführen; bestehende Properties bleiben erhalten.
|
2. `add-custombranding.ps1` einmal pro Site Collection ausführen; bestehende Properties bleiben erhalten.
|
||||||
3. Moderne und gegebenenfalls klassische Seiten testen.
|
3. Moderne und gegebenenfalls klassische Seiten testen.
|
||||||
4. Erst nach erfolgreicher Abnahme alte web-scoped Aktionen als bereinigt bestätigen.
|
4. Erst nach erfolgreicher Abnahme alte web-scoped Aktionen als bereinigt bestätigen.
|
||||||
|
|||||||
@@ -3,12 +3,12 @@
|
|||||||
Analysestand: 20.07.2026
|
Analysestand: 20.07.2026
|
||||||
Umgesetzt: 20.07.2026
|
Umgesetzt: 20.07.2026
|
||||||
Ausgangsversion: 1.0.4
|
Ausgangsversion: 1.0.4
|
||||||
Zielversion: 3.0.0
|
Zielversion: 3.0.1
|
||||||
Status: Implementierung und lokale Qualitätssicherung abgeschlossen
|
Status: Implementierung und lokale Qualitätssicherung abgeschlossen
|
||||||
|
|
||||||
## Zielbild
|
## Zielbild
|
||||||
|
|
||||||
CustomBranding wird pro Site Collection genau einmal über eine `SPSite.UserCustomAction` registriert und konfiguriert. Moderne und klassische Seiten lesen dieselben versionierten `ClientSideComponentProperties`. Es werden weder eine versteckte Liste noch ein Property Bag eingesetzt. PortalSettings bleibt in diesem Durchlauf unverändert; der Vertrag für das spätere PortalSettings-v3-Webpart ist in der README dokumentiert.
|
CustomBranding wird pro Site Collection genau einmal über eine `SPSite.UserCustomAction` registriert und konfiguriert. Moderne und klassische Seiten lesen dieselben versionierten `ClientSideComponentProperties`. Es werden weder eine versteckte Liste noch ein Property Bag eingesetzt. PortalSettings 3.0.1 kann die zentrale Action erkennen, bearbeiten und bei Bedarf beim ersten Speichern anlegen.
|
||||||
|
|
||||||
## Sicherheit und Konfigurationsmodell
|
## Sicherheit und Konfigurationsmodell
|
||||||
|
|
||||||
@@ -26,6 +26,9 @@ CustomBranding wird pro Site Collection genau einmal über eine `SPSite.UserCust
|
|||||||
- [x] `enabled`, `debug`, `allowedCssHosts`, `cssfiles`, Top und Bottom konsistent typisiert.
|
- [x] `enabled`, `debug`, `allowedCssHosts`, `cssfiles`, Top und Bottom konsistent typisiert.
|
||||||
- [x] Unbekannte Properties werden ignoriert; Warnungen erscheinen nur im Debug-Modus.
|
- [x] Unbekannte Properties werden ignoriert; Warnungen erscheinen nur im Debug-Modus.
|
||||||
- [x] Keine feste Abhängigkeit oder Verlinkung zu PortalSettings mehr vorhanden.
|
- [x] Keine feste Abhängigkeit oder Verlinkung zu PortalSettings mehr vorhanden.
|
||||||
|
- [x] Versionierten, rein deklarativen PortalSettings-Vertragsmarker ergänzt.
|
||||||
|
- [x] Runtime, Standardkonfiguration und Deployment-Skript auf denselben Providervertrag gebracht.
|
||||||
|
- [x] Direkte Aktivierung aus PortalSettings 3.0.1 dokumentiert.
|
||||||
|
|
||||||
## Lifecycle und Stylesheet-Management
|
## Lifecycle und Stylesheet-Management
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"solution": {
|
"solution": {
|
||||||
"name": "custom-branding-client-side-solution",
|
"name": "custom-branding-client-side-solution",
|
||||||
"id": "03a7c4de-e031-4b83-a683-5ca5c364166e",
|
"id": "03a7c4de-e031-4b83-a683-5ca5c364166e",
|
||||||
"version": "3.0.0.0",
|
"version": "3.0.1.0",
|
||||||
"includeClientSideAssets": true,
|
"includeClientSideAssets": true,
|
||||||
"skipFeatureDeployment": true
|
"skipFeatureDeployment": true
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -42,6 +42,11 @@ $classicActionName = 'CustomBranding.Classic.ScriptLink'
|
|||||||
function New-DefaultCustomBrandingConfiguration {
|
function New-DefaultCustomBrandingConfiguration {
|
||||||
return @{
|
return @{
|
||||||
schemaVersion = 2
|
schemaVersion = 2
|
||||||
|
portalSettings = @{
|
||||||
|
providerKey = 'custombranding'
|
||||||
|
contractVersion = 1
|
||||||
|
minimumPortalSettingsVersion = '3.0.0'
|
||||||
|
}
|
||||||
enabled = $true
|
enabled = $true
|
||||||
debug = $false
|
debug = $false
|
||||||
allowedCssHosts = @()
|
allowedCssHosts = @()
|
||||||
@@ -122,6 +127,11 @@ try {
|
|||||||
$configuration = Get-ExistingConfiguration -Action $action
|
$configuration = Get-ExistingConfiguration -Action $action
|
||||||
|
|
||||||
$configuration.schemaVersion = 2
|
$configuration.schemaVersion = 2
|
||||||
|
$configuration.portalSettings = @{
|
||||||
|
providerKey = 'custombranding'
|
||||||
|
contractVersion = 1
|
||||||
|
minimumPortalSettingsVersion = '3.0.0'
|
||||||
|
}
|
||||||
if (-not $configuration.ContainsKey('placeholdertop')) { $configuration.placeholdertop = @{ elements = @() } }
|
if (-not $configuration.ContainsKey('placeholdertop')) { $configuration.placeholdertop = @{ elements = @() } }
|
||||||
if (-not $configuration.ContainsKey('placeholderbottom')) { $configuration.placeholderbottom = @{ elements = @() } }
|
if (-not $configuration.ContainsKey('placeholderbottom')) { $configuration.placeholderbottom = @{ elements = @() } }
|
||||||
if (-not $configuration.ContainsKey('cssfiles')) { $configuration.cssfiles = @() }
|
if (-not $configuration.ContainsKey('cssfiles')) { $configuration.cssfiles = @() }
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
{
|
{
|
||||||
"schemaVersion": 2,
|
"schemaVersion": 2,
|
||||||
|
"portalSettings": {
|
||||||
|
"providerKey": "custombranding",
|
||||||
|
"contractVersion": 1,
|
||||||
|
"minimumPortalSettingsVersion": "3.0.0"
|
||||||
|
},
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"debug": false,
|
"debug": false,
|
||||||
"allowedCssHosts": [],
|
"allowedCssHosts": [],
|
||||||
|
|||||||
Generated
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "custom-branding",
|
"name": "custom-branding",
|
||||||
"version": "3.0.0",
|
"version": "3.0.1",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "custom-branding",
|
"name": "custom-branding",
|
||||||
"version": "3.0.0",
|
"version": "3.0.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import {
|
|||||||
IBrandingNormalizationResult,
|
IBrandingNormalizationResult,
|
||||||
ICssFile,
|
ICssFile,
|
||||||
ICustomBrandingApplicationCustomizerProperties,
|
ICustomBrandingApplicationCustomizerProperties,
|
||||||
ICustomBrandingConfig
|
ICustomBrandingConfig,
|
||||||
|
IPortalSettingsDescriptor
|
||||||
} from './BrandingTypes';
|
} from './BrandingTypes';
|
||||||
|
|
||||||
export const BrandingSchemaVersion: number = 2;
|
export const BrandingSchemaVersion: number = 2;
|
||||||
@@ -59,6 +60,7 @@ export function normalizeBrandingConfig(
|
|||||||
|
|
||||||
const config: ICustomBrandingConfig = {
|
const config: ICustomBrandingConfig = {
|
||||||
schemaVersion: BrandingSchemaVersion,
|
schemaVersion: BrandingSchemaVersion,
|
||||||
|
portalSettings: createPortalSettingsDescriptor(),
|
||||||
enabled: raw.enabled !== false,
|
enabled: raw.enabled !== false,
|
||||||
debug: raw.debug === true,
|
debug: raw.debug === true,
|
||||||
allowedCssHosts: allowedCssHosts,
|
allowedCssHosts: allowedCssHosts,
|
||||||
@@ -128,6 +130,7 @@ export function sanitizeStyle(propertyName: string, value: string): string | und
|
|||||||
function createEmptyConfig(): ICustomBrandingConfig {
|
function createEmptyConfig(): ICustomBrandingConfig {
|
||||||
return {
|
return {
|
||||||
schemaVersion: BrandingSchemaVersion,
|
schemaVersion: BrandingSchemaVersion,
|
||||||
|
portalSettings: createPortalSettingsDescriptor(),
|
||||||
enabled: true,
|
enabled: true,
|
||||||
debug: false,
|
debug: false,
|
||||||
allowedCssHosts: [],
|
allowedCssHosts: [],
|
||||||
@@ -137,6 +140,14 @@ function createEmptyConfig(): ICustomBrandingConfig {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createPortalSettingsDescriptor(): IPortalSettingsDescriptor {
|
||||||
|
return {
|
||||||
|
providerKey: 'custombranding',
|
||||||
|
contractVersion: 1,
|
||||||
|
minimumPortalSettingsVersion: '3.0.0'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function normalizeHosts(value: any): string[] {
|
function normalizeHosts(value: any): string[] {
|
||||||
if (!Array.isArray(value)) {
|
if (!Array.isArray(value)) {
|
||||||
return [];
|
return [];
|
||||||
@@ -303,4 +314,3 @@ function hasKeys(value: { [key: string]: string }): boolean {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,8 +17,15 @@ export interface IPlaceholderConfig {
|
|||||||
elements: IBrandingElement[];
|
elements: IBrandingElement[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IPortalSettingsDescriptor {
|
||||||
|
providerKey: 'custombranding';
|
||||||
|
contractVersion: number;
|
||||||
|
minimumPortalSettingsVersion: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ICustomBrandingConfig {
|
export interface ICustomBrandingConfig {
|
||||||
schemaVersion: number;
|
schemaVersion: number;
|
||||||
|
portalSettings: IPortalSettingsDescriptor;
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
debug: boolean;
|
debug: boolean;
|
||||||
allowedCssHosts: string[];
|
allowedCssHosts: string[];
|
||||||
@@ -29,6 +36,7 @@ export interface ICustomBrandingConfig {
|
|||||||
|
|
||||||
export interface ICustomBrandingApplicationCustomizerProperties {
|
export interface ICustomBrandingApplicationCustomizerProperties {
|
||||||
schemaVersion?: number;
|
schemaVersion?: number;
|
||||||
|
portalSettings?: IPortalSettingsDescriptor;
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
debug?: boolean;
|
debug?: boolean;
|
||||||
allowedCssHosts?: string[];
|
allowedCssHosts?: string[];
|
||||||
@@ -42,4 +50,3 @@ export interface IBrandingNormalizationResult {
|
|||||||
config: ICustomBrandingConfig;
|
config: ICustomBrandingConfig;
|
||||||
warnings: string[];
|
warnings: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ function element(raw) {
|
|||||||
|
|
||||||
var empty = normalize({}, siteUrl);
|
var empty = normalize({}, siteUrl);
|
||||||
assert(empty.config.schemaVersion === 2, 'Das aktuelle Schema muss Version 2 verwenden.');
|
assert(empty.config.schemaVersion === 2, 'Das aktuelle Schema muss Version 2 verwenden.');
|
||||||
|
assert(empty.config.portalSettings.providerKey === 'custombranding', 'PortalSettings Provider-Key fehlt.');
|
||||||
|
assert(empty.config.portalSettings.contractVersion === 1, 'PortalSettings Contract-Version fehlt.');
|
||||||
assert(empty.config.enabled === true, 'Branding muss standardmaessig aktiviert sein.');
|
assert(empty.config.enabled === true, 'Branding muss standardmaessig aktiviert sein.');
|
||||||
|
|
||||||
var legacy = normalize({ elements: [{ type: 'span', content: 'Alt' }] }, siteUrl);
|
var legacy = normalize({ elements: [{ type: 'span', content: 'Alt' }] }, siteUrl);
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ var appSource = read('src/extensions/customBranding/CustomBrandingApplicationCus
|
|||||||
var rendererSource = read('src/extensions/customBranding/BrandingDomRenderer.ts');
|
var rendererSource = read('src/extensions/customBranding/BrandingDomRenderer.ts');
|
||||||
var classicSource = read('classic/custom-branding-classic.js');
|
var classicSource = read('classic/custom-branding-classic.js');
|
||||||
|
|
||||||
assert(packageJson.version === '3.0.0', 'package.json hat nicht Version 3.0.0.');
|
assert(packageJson.version === '3.0.1', 'package.json hat nicht Version 3.0.1.');
|
||||||
assert(solution.version === '3.0.0.0', 'Solution-Version ist inkonsistent.');
|
assert(solution.version === '3.0.1.0', 'Solution-Version ist inkonsistent.');
|
||||||
assert(solution.skipFeatureDeployment === true, 'Tenantweite Bereitstellung ist nicht aktiviert.');
|
assert(solution.skipFeatureDeployment === true, 'Tenantweite Bereitstellung ist nicht aktiviert.');
|
||||||
assert(!solution.features, 'Die alte web-scoped Feature-Registrierung ist noch vorhanden.');
|
assert(!solution.features, 'Die alte web-scoped Feature-Registrierung ist noch vorhanden.');
|
||||||
assert(!fs.existsSync(path.join(root, 'sharepoint/assets/elements.xml')), 'elements.xml muss entfernt sein.');
|
assert(!fs.existsSync(path.join(root, 'sharepoint/assets/elements.xml')), 'elements.xml muss entfernt sein.');
|
||||||
|
|||||||
Reference in New Issue
Block a user