feat: update version to 2.1.2 and enhance ExpiryIndicator functionality with new binding handling

This commit is contained in:
Torsten Brendgen
2026-07-18 23:48:40 +02:00
parent 69a96b90c5
commit d97dbf45aa
10 changed files with 71 additions and 18 deletions

View File

@@ -354,7 +354,7 @@ Version 2.1 legt bei der App-Installation `ExpiryIndicatorClassic.js` unter
- einen einmaligen Web-`ScriptLink` für CSR/JSLink, der das gebundene Feld der aktuellen Liste selbst erkennt,
- die Berechnung, Beschriftung und den Zeilenverlauf in der klassischen Ansicht,
- den Ribbon-Befehl **Ablaufdatum +1 Jahr**,
- den Ribbon-Befehl **Ablaufdatum +1 Jahr** im Tab **Files** beziehungsweise **Items**,
- den Einstellungsdialog über denselben URL-Parameter `expiryIndicatorSettings=1`.
Soll nur die moderne Ansicht aktiviert werden, kann die Classic-Registrierung ausgelassen werden:
@@ -414,7 +414,7 @@ anlegen. Das Skript bleibt vor allem für automatisierte oder umfangreiche Rollo
### Upgrade auf Version 2.1
1. Das vorhandene Paket im App Catalog durch Version `2.1.1.0` ersetzen.
1. Das vorhandene Paket im App Catalog durch Version `2.1.2.0` ersetzen.
2. Die App in der Site aktualisieren. Die enthaltene Feature-UpgradeAction provisioniert ausschließlich das
aktualisierten Assets und legt keine fachliche Spalte an.
3. `Enable-ExpiryIndicator.ps1` für jede bereits angebundene Liste erneut ausführen. Das Skript erhält die

View File

@@ -3,7 +3,7 @@
"solution": {
"name": "expiry-indicator-client-side-solution",
"id": "68bb6d2d-9895-45b4-88e8-b98835faa981",
"version": "2.1.1.0",
"version": "2.1.2.0",
"includeClientSideAssets": true,
"skipFeatureDeployment": false,
"features": [
@@ -11,7 +11,7 @@
"title": "ExpiryIndicator extension registration",
"description": "Registers ExpiryIndicator commands and its settings Application Customizer. Does not provision ExpiryDate.",
"id": "913402af-ab9a-4974-9f86-5c2159ae41db",
"version": "2.1.1.0",
"version": "2.1.2.0",
"assets": {
"elementManifests": [
"elements.xml",

2
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "expiry-indicator",
"version": "2.1.1",
"version": "2.1.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "expiry-indicator",
"version": "2.1.1",
"version": "2.1.2",
"private": true,
"engines": {
"node": ">=6.9.0 <9.0.0"

View File

@@ -18,6 +18,23 @@ $isapiPath = Join-Path ([Environment]::GetFolderPath('CommonProgramFiles')) 'mic
Add-Type -Path (Join-Path $isapiPath 'Microsoft.SharePoint.Client.Runtime.dll')
Add-Type -Path (Join-Path $isapiPath 'Microsoft.SharePoint.Client.dll')
function Expand-ExpiryIndicatorBindings {
param([object]$Value)
if ($null -eq $Value) { return }
if ($Value -is [System.Array]) {
foreach ($item in $Value) {
Expand-ExpiryIndicatorBindings -Value $item
}
return
}
if ($Value.PSObject.Properties['webUrl'] -and
$Value.PSObject.Properties['listId'] -and
$Value.PSObject.Properties['fieldInternalName']) {
Write-Output $Value
}
}
$context = New-Object Microsoft.SharePoint.Client.ClientContext($SiteUrl)
$context.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials
@@ -50,7 +67,8 @@ try {
$existingBindingsJson = [string]$rootWeb.AllProperties[$bindingsKey]
if (-not [string]::IsNullOrWhiteSpace($existingBindingsJson)) {
try {
$bindings = @($existingBindingsJson | ConvertFrom-Json)
$parsedBindings = $existingBindingsJson | ConvertFrom-Json
$bindings = @(Expand-ExpiryIndicatorBindings -Value $parsedBindings)
}
catch {
$bindings = @()

View File

@@ -20,6 +20,23 @@ $isapiPath = Join-Path ([Environment]::GetFolderPath('CommonProgramFiles')) 'mic
Add-Type -Path (Join-Path $isapiPath 'Microsoft.SharePoint.Client.Runtime.dll')
Add-Type -Path (Join-Path $isapiPath 'Microsoft.SharePoint.Client.dll')
function Expand-ExpiryIndicatorBindings {
param([object]$Value)
if ($null -eq $Value) { return }
if ($Value -is [System.Array]) {
foreach ($item in $Value) {
Expand-ExpiryIndicatorBindings -Value $item
}
return
}
if ($Value.PSObject.Properties['webUrl'] -and
$Value.PSObject.Properties['listId'] -and
$Value.PSObject.Properties['fieldInternalName']) {
Write-Output $Value
}
}
$context = New-Object Microsoft.SharePoint.Client.ClientContext($SiteUrl)
$context.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials
@@ -58,7 +75,7 @@ try {
$rootWeb.AllProperties[$descriptorKey] = ([ordered]@{
key = 'ExpiryIndicator'
displayName = 'Expiry Indicator'
version = '2.1.1'
version = '2.1.2'
provider = 'expiryIndicator'
componentIds = @(
'a555f4fc-d6a6-4421-8189-457449d9bbde',
@@ -72,7 +89,8 @@ try {
$existingBindingsJson = [string]$rootWeb.AllProperties[$bindingsKey]
if (-not [string]::IsNullOrWhiteSpace($existingBindingsJson)) {
try {
$bindings = @($existingBindingsJson | ConvertFrom-Json)
$parsedBindings = $existingBindingsJson | ConvertFrom-Json
$bindings = @(Expand-ExpiryIndicatorBindings -Value $parsedBindings)
}
catch {
Write-Warning 'Das vorhandene ExpiryIndicator-Bindungsinventar war ungültig und wird neu aufgebaut.'
@@ -130,10 +148,10 @@ try {
$scriptAction.Update()
$ribbonLocation = if ($list.BaseType -eq [Microsoft.SharePoint.Client.BaseType]::DocumentLibrary) {
'Ribbon.Library.Actions.Controls._children'
'Ribbon.Documents.Manage.Controls._children'
}
else {
'Ribbon.List.Actions.Controls._children'
'Ribbon.ListItem.Actions.Controls._children'
}
$ribbonXml = @"

View File

@@ -4,7 +4,7 @@
var FIELD_CUSTOMIZER_ID = 'a555f4fc-d6a6-4421-8189-457449d9bbde';
var SITE_DEFAULTS_PROPERTY = 'PortalSettings.ExpiryIndicator.Defaults';
var WEB_OVERRIDE_PROPERTY = 'PortalSettings.ExpiryIndicator.Override';
var state = { context: null, field: null, config: null, loading: null };
var state = { context: null, field: null, config: null, loading: null, itemEntityType: null };
function configuredExpiryField() {
var scripts = document.getElementsByTagName('script');
@@ -421,16 +421,33 @@
} catch (ignore) { return []; }
}
function getItemEntityType() {
if (state.itemEntityType) { return Promise.resolve(state.itemEntityType); }
return request('GET', listUrl(state.context) + '?$select=ListItemEntityTypeFullName')
.then(function (data) {
var list = data.d || data;
if (!list.ListItemEntityTypeFullName) {
throw new Error('Der REST-Entitätstyp der Liste konnte nicht ermittelt werden.');
}
state.itemEntityType = list.ListItemEntityTypeFullName;
return state.itemEntityType;
});
}
function extendOne(id, config) {
var fields = [config.baseField, config.expiryField].concat(ruleFields(config));
return request('GET', listUrl(state.context) + '/items(' + id + ')?$select=Id,' + fields.join(','))
.then(function (data) {
return Promise.all([
request('GET', listUrl(state.context) + '/items(' + id + ')?$select=Id,' + fields.join(',')),
getItemEntityType()
]).then(function (results) {
var data = results[0];
var entityType = results[1];
var item = data.d || data;
var created = parseDate(item[config.baseField]);
var expiry = parseDate(item[config.expiryField]);
var base = expiry || addDuration(created, behavior(config, item).lifeTime);
var updated = addDuration(base, { value: 1, unit: 'years' });
var body = { '__metadata': { 'type': item.__metadata.type } };
var body = { '__metadata': { 'type': item.__metadata && item.__metadata.type || entityType } };
body[config.expiryField] = updated.toISOString();
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();

View File

@@ -4,7 +4,7 @@
"alias": "ExpiryIndicatorFieldCustomizer",
"componentType": "Extension",
"extensionType": "FieldCustomizer",
"version": "2.1.1",
"version": "2.1.2",
"manifestVersion": 2,
"requiresCustomScript": false
}

View File

@@ -4,7 +4,7 @@
"alias": "ExpiryIndicatorApplicationCustomizer",
"componentType": "Extension",
"extensionType": "ApplicationCustomizer",
"version": "2.1.1",
"version": "2.1.2",
"manifestVersion": 2,
"requiresCustomScript": false
}

View File

@@ -4,7 +4,7 @@
"alias": "ExpiryIndicatorCommandSet",
"componentType": "Extension",
"extensionType": "ListViewCommandSet",
"version": "2.1.1",
"version": "2.1.2",
"manifestVersion": 2,
"requiresCustomScript": false,
"items": {