feat: add ExpiryIndicatorClassic functionality with configuration and rendering

- Implemented ExpiryIndicatorClassic.js for managing expiry dates in SharePoint lists.
- Created classic-elements.xml to define the module for ExpiryIndicator assets.
- Added upgrade-actions-v2.xml to apply the new element manifests.
- Introduced ExpiryModels.test.ts for unit testing the expiry configuration and rules validation.
This commit is contained in:
Torsten Brendgen
2026-07-18 19:52:50 +02:00
parent f6e3af23c2
commit 0d6768e24c
18 changed files with 18610 additions and 45 deletions

View File

@@ -22,8 +22,10 @@ $context.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials
try {
$list = $context.Web.Lists.GetByTitle($ListTitle)
$field = $list.Fields.GetByInternalNameOrTitle($ExpiryFieldInternalName)
$customActions = $list.UserCustomActions
$context.Load($list)
$context.Load($field)
$context.Load($customActions)
$context.ExecuteQuery()
if ($field.ClientSideComponentId -ne $FieldCustomizerComponentId) {
@@ -34,8 +36,16 @@ try {
$field.ClientSideComponentId = [Guid]::Empty
$field.ClientSideComponentProperties = ''
$field.Update()
$customActions | Where-Object {
$_.Name -eq 'ExpiryIndicator.Classic.ScriptLink' -or
$_.Name -eq 'ExpiryIndicator.Classic.Ribbon'
} | ForEach-Object {
$_.DeleteObject()
}
$context.ExecuteQuery()
Write-Host 'ExpiryIndicator-Verknüpfung wurde entfernt. Feld und Daten bleiben unverändert.'
Write-Host 'ExpiryIndicator-Verknüpfung und Classic-Registrierungen wurden entfernt. Feld und Daten bleiben unverändert.'
}
}
finally {

View File

@@ -9,7 +9,11 @@ param(
[Parameter(Mandatory = $true)]
[string]$ExpiryFieldInternalName,
[Guid]$FieldCustomizerComponentId = 'a555f4fc-d6a6-4421-8189-457449d9bbde'
[Guid]$FieldCustomizerComponentId = 'a555f4fc-d6a6-4421-8189-457449d9bbde',
[string]$ClassicScriptUrl = '~site/SiteAssets/ExpiryIndicator/ExpiryIndicatorClassic.js',
[switch]$SkipClassic
)
$isapiPath = Join-Path ([Environment]::GetFolderPath('CommonProgramFiles')) 'microsoft shared\Web Server Extensions\16\ISAPI'
@@ -41,16 +45,67 @@ try {
}
$field.Update()
# Remove the temporary list-scoped command registration used by older
# diagnostic scripts. The app feature owns the production registration.
# Remove old diagnostic registrations and make the V2 Classic
# registrations idempotent.
$customActions | Where-Object {
$_.Name -eq 'ExpiryIndicator.CommandSet'
$_.Name -eq 'ExpiryIndicator.CommandSet' -or
$_.Name -eq 'ExpiryIndicator.Classic.ScriptLink' -or
$_.Name -eq 'ExpiryIndicator.Classic.Ribbon'
} | ForEach-Object {
$_.DeleteObject()
}
$context.ExecuteQuery()
if (-not $SkipClassic) {
$scriptAction = $list.UserCustomActions.Add()
$scriptAction.Name = 'ExpiryIndicator.Classic.ScriptLink'
$scriptAction.Title = 'ExpiryIndicator Classic runtime'
$scriptAction.Location = 'ScriptLink'
$separator = if ($ClassicScriptUrl.Contains('?')) { '&' } else { '?' }
$scriptAction.ScriptSrc = $ClassicScriptUrl + $separator + 'expiryField=' + [Uri]::EscapeDataString($field.InternalName)
$scriptAction.Sequence = 650
$scriptAction.Update()
$ribbonLocation = if ($list.BaseType -eq [Microsoft.SharePoint.Client.BaseType]::DocumentLibrary) {
'Ribbon.Library.Actions.Controls._children'
}
else {
'Ribbon.List.Actions.Controls._children'
}
$ribbonXml = @"
<CommandUIExtension xmlns="http://schemas.microsoft.com/sharepoint/">
<CommandUIDefinitions>
<CommandUIDefinition Location="$ribbonLocation">
<Button Id="ExpiryIndicator.Classic.ExtendOneYear.Button"
Command="ExpiryIndicator.Classic.ExtendOneYear"
Sequence="90"
LabelText="Ablaufdatum +1 Jahr"
Description="Verlängert das Ablaufdatum der ausgewählten Elemente um ein Kalenderjahr."
TemplateAlias="o1" />
</CommandUIDefinition>
</CommandUIDefinitions>
<CommandUIHandlers>
<CommandUIHandler Command="ExpiryIndicator.Classic.ExtendOneYear"
CommandAction="javascript:ExpiryIndicatorClassic.extendSelected();"
EnabledScript="javascript:ExpiryIndicatorClassic.canExtend();" />
</CommandUIHandlers>
</CommandUIExtension>
"@
$ribbonAction = $list.UserCustomActions.Add()
$ribbonAction.Name = 'ExpiryIndicator.Classic.Ribbon'
$ribbonAction.Title = 'ExpiryIndicator Classic ribbon command'
$ribbonAction.Location = 'CommandUI.Ribbon'
$ribbonAction.CommandUIExtension = $ribbonXml
$ribbonAction.Sequence = 651
$ribbonAction.Update()
$context.ExecuteQuery()
Write-Host 'Classic-Ansicht: CSR/JSLink und Ribbon-Befehl wurden registriert.'
}
Write-Host "ExpiryIndicator wurde für '$($list.Title)' an '$($field.InternalName)' gebunden."
}
finally {