* [ACS-12451] Add missing ADF upgrade guides * [ACS-12451] CR fix * [ACS-12451] CR fixes
19 KiB
Title
| Title |
|---|
| Upgrading from ADF v8.5 to v9.0 |
Upgrading from ADF v8.5 to v9.0
This guide provides instructions on how to upgrade your v8.5.0 ADF projects to v9.0.0.
Before you begin
Always perform upgrades on a "clean" project state, back up your changes or make a project backup. Because this
release bumps the Angular major, budget time to run the Angular 20 ng update migrations on your own app,
rebuild, and re-test. Expect to install with --legacy-peer-deps (see below).
Contents
- Library updates
- Breaking changes
- Angular 20 / TypeScript 5.9
- Knowledge Discovery removed
MaterialModuleremoved- Search query-builder refactor
- Extension auth guards are now typed
- Process instance model — subprocess/linked-process fields
- Task cloud — Runtime Bundle task fetch
- Multiline text widget base class
- Text field default max length
- Tree and chip DOM / accessibility changes
- New components and features
- Behavioural changes
Library updates
Update the package.json file with the latest library versions:
{
"dependencies": {
"@alfresco/adf-core": "9.0.0",
"@alfresco/adf-content-services": "9.0.0",
"@alfresco/adf-process-services": "9.0.0",
"@alfresco/adf-process-services-cloud": "9.0.0",
"@alfresco/adf-insights": "9.0.0",
"@alfresco/adf-extensions": "9.0.0",
"@alfresco/js-api": ">=10.0.0",
"@ngx-translate/core": ">=17.0.0"
}
}
Bump your Angular platform to 20.x in lockstep (@angular/core/@angular/material/@angular/cdk 20.x,
typescript 5.9). Clean node_modules and package-lock.json, then npm install.
Breaking changes
Angular 20 / TypeScript 5.9
ADF 9.0.0 is built against Angular 20 and must be consumed by an Angular 20 app — there is no cross-version support with Angular 19.
| Package | v8.5.0 | v9.0.0 |
|---|---|---|
@angular/core, @angular/common, … |
19.2.x | 20.3.x |
@angular/material, @angular/cdk |
19.2.x | 20.2.x |
@angular/material-date-fns-adapter |
19.2.x | 20.2.x |
typescript |
5.8.3 | 5.9.3 |
ng-packagr |
19.2.x | 20.3.x |
@angular-eslint/* |
19.3.0 | 20.7.0 |
@typescript-eslint/* |
6.x | 8.x |
zone.js |
0.15.0 | 0.15.0 (unchanged) |
rxjs |
7.8.2 | 7.8.2 (unchanged) |
nx |
22.x | 22.x (unchanged) |
- Run the Angular 20 update on your own app (
ng update @angular/core@20 @angular/cdk@20 @angular/material@20) and move to TypeScript 5.9. Follow the official Angular update guide. - Expect
npm install --legacy-peer-deps. A transitive dependency (@mat-datetimepicker/core) still declares an Angular-19 CDK peer range while ADF ships CDK 20, so npm reports a peer conflict without the flag. - ESLint:
@typescript-eslint/brace-stylewas removed in@typescript-eslintv8 — drop it from any shared config that inherited it from ADF. Angular 20 also newly recommends@angular-eslint/prefer-inject(constructor injection →inject()); this surfaces as warnings only. - CDK
PortalInjectorremoved — Angular CDK 20 removedPortalInjector. ADF replaced its internal usage withInjector.create(); if your own code importedPortalInjectorfrom@angular/cdk/portal, make the same swap.
Knowledge Discovery removed
The Knowledge Discovery / Search-AI / Knowledge Retrieval feature (the HxI-connector agent-based AI query
feature originally added in 7.0.0) was removed entirely from both @alfresco/adf-content-services and
@alfresco/js-api. There is no replacement — remove all usages.
Removed from @alfresco/adf-content-services (the agent, search-ai and prediction barrels were deleted):
| Removed | Kind |
|---|---|
AgentService |
Service |
SearchAiService |
Service |
SearchAiInputState |
Interface |
PredictionService |
Service |
Removed from @alfresco/js-api:
- content-rest-api:
AgentsApi,SearchAiApi; modelsAgent,AgentEntry,AgentPaging,AgentPagingList,AiAnswer,AiAnswerEntry,AiAnswerReference,AiAnswerObjectReference,KnowledgeRetrievalConfig,KnowledgeRetrievalConfigEntry,QuestionModel,QuestionRequest,RestrictionQuery. - hxi-connector-api (entire secondary API removed):
PredictionsApi,Prediction,PredictionEntry,PredictionPaging,PredictionPagingList, and theUpdateType/ReviewStatustypes. AlfrescoApi.hxiConnectorClient— the client property (and its config/auth wiring) was removed fromAlfrescoApi/AlfrescoApiType.
MaterialModule removed
The deprecated MaterialModule re-export barrel was removed from both @alfresco/adf-core and
@alfresco/adf-content-services, and is no longer re-exported by CoreModule / ContentModule.
Import the specific @angular/material/* modules you actually use directly from Angular Material:
// Before
import { MaterialModule } from '@alfresco/adf-core'; // (or from @alfresco/adf-content-services)
// After — import only what you use, from Angular Material
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
// …etc
Apps that were transitively relying on Material modules via ADF's module exports must now import each Material module explicitly.
Search query-builder refactor
BaseQueryBuilderService (the base of SearchQueryBuilderService and SearchHeaderQueryBuilderService) was
refactored to parse the user query on demand and to support two query modes. This removes the old
"emit updated → subscriber calls execute()" indirection:
- The
updatedSubject<SearchRequest>was removed. Code subscribing toqueryBuilder.updatedmust instead react toqueryBuilder.execute()results (executed/ the returnedSearchRequest). - The
update(queryBody?)method was removed. Callexecute()directly.
// Before
this.queryBuilder.updated.subscribe((query) => { /* … */ });
this.queryBuilder.update();
// After
this.queryBuilder.execute(); // executes and emits results directly
- The
userQuerysetter no longer trims and parenthesizes. PreviouslyuserQuery = 'foo'stored'(foo)'; now it stores the raw value'foo'and derives the compiled query via the new read-onlyparsedQuerygetter. ReadparsedQuerywhere you previously read the wrappeduserQuery. - New
searchMode: 'regular' | 'formula'(default'regular'). Inregularmode a user term is expanded across the configured fields (search.app:fields, default["cm:name"]); informulamode the raw input is used verbatim as an AFTS expression. - New read-only
wildcardsEnabled— driven by the newsearch-wildcards-enabledapp-config flag (defaulttrue). Whenfalse, terms match exactly (no trailing*) and the search-text widget'ssearchPrefix/searchSuffixare not applied. updateSelectedConfiguration(id)gained two optional params —updateSelectedConfiguration(id, resetFilters = true, shouldExecute = true)— non-breaking for existing single-argument callers.SearchTextComponent.enableChangeUpdatenow defaults tofalse(wastrue).
execute(updateQueryParams = true, queryBody?) keeps the same signature as in 8.5.0.
Extension auth guards are now typed
ExtensionService.authGuards and the setAuthGuards() / getAuthGuards() signatures were narrowed from
Record<string, unknown> / Array<unknown> to Record<string, CanActivateFn> / Array<CanActivateFn>
(@angular/router) in @alfresco/adf-extensions. Code that registered auth guards with a looser type now gets a
compile error — register CanActivateFn guards.
Process instance model — subprocess/linked-process fields
ProcessInstanceCloud replaced its two related-instance arrays with counts:
| Before (8.5.0) | After (9.0.0) |
|---|---|
linkedProcesses?: RelatedProcessInstance[] |
linkedProcessesCount?: number |
subprocesses?: RelatedProcessInstance[] |
subprocessesCount?: number |
Code reading processInstance.linkedProcesses / processInstance.subprocesses must switch to the count fields
(the full related-instance collections are no longer carried on the model).
Task cloud — Runtime Bundle task fetch
TaskCloudService.getTaskById dropped its third service argument:
- Before:
getTaskById(appName, taskId, service: 'query' | 'rb' = 'query') - After:
getTaskById(appName, taskId)
Endpoint selection is now controlled by the new ADF_TASK_RUNTIME_BUNDLE_FALLBACK_ENABLED injection token
(InjectionToken<Observable<boolean> | boolean>, from @alfresco/adf-process-services-cloud). When it resolves
truthy, getTaskById / FormCloudService.getTask read active tasks from the always-current Runtime Bundle
endpoint and transparently fall back to the Query Service on HTTP 404 (e.g. completed/archived tasks).
Default (token absent) is unchanged — Query Service only. Any caller passing 'rb'/'query' must drop the
argument and provide the token instead. The feature also adds two public exports: the
TaskDetailsCloudModelRuntimeBundle interface and the resolveTaskRuntimeBundleFallback$(token) helper.
Multiline text widget base class
MultilineTextWidgetComponentComponent now extends WidgetComponent (previously FormattableTextWidgetComponent),
implements OnInit, and renders validation errors via Material mat-error (an errorStateMatcher +
translateParameters) instead of the shared ErrorWidgetComponent. Custom widgets that subclassed it and relied
on FormattableTextWidgetComponent members must adapt. Many other widgets were migrated to the same mat-error
rendering in the same change — the core AmountWidgetComponent, DecimalWidgetComponent, NumberWidgetComponent;
the cloud dropdown/date/date-time/display-external-property widgets; the process-services (non-cloud)
dropdown/typeahead/functional-group/people widgets; TagActionsComponent; and the StartTaskComponent
date field. Custom CSS targeting the old ErrorWidgetComponent markup for any of these widgets may need updating.
Text field default max length
The TEXT field now enforces a default maximum length of 1024 characters when the field defines no explicit
maxLength, and oversized paste is blocked:
- New exported constant
DEFAULT_TEXT_MAX_LENGTH = 1024(@alfresco/adf-core). FORM_FIELD_VALIDATORSnow appliesMaxLengthFieldValidatortoTEXTwith a1024fallback (and a separate uncapped validator forMULTILINE_TEXT);MaxLengthFieldValidator's constructor gained a 3rdfallbackMaxLength?param.- Pasting text that would exceed the resolved max length is now prevented, the field is marked touched, and a
FORM.FIELD.VALIDATOR.NO_LONGER_THANerror shows.
TEXT fields that previously relied on unlimited length now cap at 1024 unless the field itself defines a
maxLength.
Tree and chip DOM / accessibility changes
Keyboard-accessibility rework changed the DOM of a few components (no @Input/@Output were removed, but markup,
CSS selectors and automation ids changed — update tests/CSS that target the old markup):
TreeComponent(adf-tree) — the expand/collapse chevron button was removed from the tab order (tabindex="-1",aria-hidden="true") and the labelspanis no longer interactive (lostrole="button"/tabindex="0"). Keyboard users now operate the row: Enter expands/collapses, Space selects/toggles. Rows gainedaria-label/aria-selected; selection is announced viaLiveAnnouncer(newADF-TREE.ARIA.SELECTED/DESELECTEDkeys).DynamicChipListComponent— the chip delete affordance changed from a<mat-icon matChipRemove>to a real<button class="adf-dynamic-chip-list-delete-btn" data-automation-id="adf-dynamic-chip-list-delete-btn-<id>">. The old.adf-dynamic-chip-list-delete-iconelement /adf-dynamic-chip-list-delete-{name}id are gone (@Output() removedChipis unchanged; it now emits from the button click). A new publicfocusDeleteButton(index)method was added, and a newDYNAMIC_CHIP_LIST.DELETEi18n key.
New components and features
- Session timeout (opt-in,
@alfresco/adf-core) — a new subsystem that tracks user idle activity, shows a countdown "Are you still working?" dialog, and logs out on timeout, synchronised across browser tabs viaBroadcastChannel. Enable it with the newprovideSessionTimeout(options?)provider and/or asessionTimeoutblock inapp.config.json:New exports include{ "sessionTimeout": { "enabled": true, "idleTimeoutMs": 1800000, "dialogTimeoutMs": 60000 } }SessionTimeoutService,SessionTimeoutDialogComponent(adf-session-timeout-dialog),IdleActivityTracker,SessionTimeoutSyncChannel, theSESSION_TIMEOUT_OPTIONStoken, theSESSION_TIMEOUT_CONFIG_KEY/DEFAULT_SESSION_TIMEOUT_OPTIONSconstants, and theSessionTimeoutOptionsinterface. Defaults: 30-minute idle timeout, 60-second warning dialog. NewSESSION_TIMEOUT.*i18n keys. - Clock-drift-tolerant token expiry (opt-in) — a new
oauth2.timeSyncapp-config flag makes OAuth token expiry checks use a server-time-corrected clock (to avoid false logouts on VMs/Citrix with drifted clocks). Backed by a reworkedTimeSyncService(getCorrectedNow()) and a new exportedTimeSyncDateTimeProvider;OauthConfigModelgained optionaltimeSync?: booleanandshowDebugInformation?: booleanfields, and a new top-levelserverTimeUrlapp-config key (AppConfigValues.SERVER_TIME_URL) points at the endpoint used to read server time. Off by default — behaviour is unchanged unlessoauth2.timeSyncis enabled. - Type-aware form field value adapter — a new root-provided
FormFieldValueAdapterService(register/hasAdapter/adapt, with the exportedFormFieldValueAdaptertype) in@alfresco/adf-core, the inbound counterpart to 8.5.0'sFormFieldValueFormatterService. Both are gated by the existingADF_TYPED_VALUE_FORMATTING_ENABLEDtoken. A companionReactivePreselectionServicenow backs the cloud People/Group widgets' preselection. - Repeatable-section row-count event — a new
'onRowCountChanged'form-rules event is emitted (viaFormService.formRulesEvent) when a repeatable section adds/removes a row, driven by the newFormModel.onRepeatableSectionRowCountChanged(sectionField). TheFormValidationServiceinterface gained an optionalformRulesEvent?: Subject<FormRulesEvent>. - Dropdown/radio labels in display-text expressions — when typed-value formatting is enabled,
${field.x}expressions now resolve dropdown/radio values to their option label instead of the raw id. NewFormFieldTypes.DISPLAY_TEXT_TYPES/FormFieldTypes.isDisplayTextType()helpers. - Multiline text auto-grow — the multiline text widget grows unbounded by default; setting the field param
autoGrow: falsecaps its height (scrollable). Driven byfield.params.autoGrow(no new@Input). - Silent document-list reload —
DocumentListService.reloadSilently()/reloadSilently$reload the list without resetting the current selection (used to keep the context menu open during bulk upload). UrlServiceblob helpers — new publiccreateObjectUrl(blob)andtrustUrl(url)methods (the existingcreateTrustedUrl(blob)is now composed from them).CustomResourcesService.getRecentFilesgained an optional 4thincludeFields: string[] = []param (forwarded fromloadFolderByNodeIdfor-recent-), so extra fields (e.g.isFavorite) can be requested.- Version list now shows the version's modified-by user (
modifiedByUser.displayName) and the modified date and time (date: 'medium').
Behavioural changes
| Area | Change |
|---|---|
| Auth — OIDC | OidcAuthenticationService.reset() now calls oauthService.logOut(true) (terminates the OAuth session) instead of reloading the IDP configuration — supports the session-timeout logout redirect. |
| Search — node selector | ContentNodeSelectorPanelComponent no longer leaves stale ANCESTOR: filters when switching sites/clearing the search; filtering now correctly scopes to the chosen site. |
| Forms — people widget | PeopleWidgetComponent (process-services) now debounces its user search by 300 ms instead of querying on every keystroke. |
| Forms — spinner | The Automate-form spinner overlay is now fully disposed on host destroy, so it no longer persists outside the form. |
| Forms — task fetch | Task claim/unclaim status is evaluated against the always-current Runtime Bundle when the RB-fallback token is enabled (fixes stale block-task claim status). |
| Uploads | FetchHttpClient now converts a Node ReadStream/Buffer to a Blob (with filename) before appending to FormData, fixing broken multipart uploads under the fetch client. |
| Uploads | The form multi-file attachment viewer now updates when a different file is selected; the "upload new version" button re-enables after use; bulk upload no longer collapses the context menu. |
| Viewer | Firefox-headless race fixed — PDF blob/MIME state is assigned atomically and MIME types are normalised (charset params stripped). |
| Accessibility — tags | Tag delete controls are now real keyboard-operable buttons; focus is restored sensibly after a tag is removed, and blank/whitespace tags are rejected. |