[ACS-10035] Ensure ADW handles no PUT for preferences API method in ACS below 25.x v. [PoC] (#4750)

* [ACS-10035]: adds evaluator and helper functions

* [ACS-10035]: disables navbar savedSearch for non-supported versions

* [ACS-10035]: extends app extension service to allow manual rule evaluation; clean up

* [ACS-10035]: introduces pipe as an alternative option for compatibility check

* [ACS-10035]: disables save search feature if is not supported

* [ACS-10035]: adds test for new method

* [ACS-10035]: sonarQube issue

* [10035]: adds unit tests for evaluators and helper fns

* [ACS-10035]: fixes failed test

* [ACS-10035]: fixes naming

* [ACS-10035]: fixes race condition issue on direct page refresh

* [ACS-10035]: fixes import

* [ACS-10035]: sonarQube issues

* [ACS-10035]: fixes sonarQube with fake versions

* [ACS-10035]: fixes tests

* [ACS-10035]: improves pipe logic stream

* [ACS-10035]: fixes sonarQube; adjusts tests

* [ACS-10035]: adds documentation

* [ACS-10035]: exposes isFeatureSupportedInCurrentAcs from aca-content lib

* [ACS-10035]: minor fixes

* [ACS-10035]: typo fix
This commit is contained in:
rmnvch
2025-09-09 07:21:52 +02:00
committed by GitHub
parent 9395d980e2
commit 74448ac12e
13 changed files with 260 additions and 16 deletions

View File

@@ -212,7 +212,10 @@
"items": [
{
"id": "app.search.navbar",
"component": "app.search.navbar"
"component": "app.search.navbar",
"rules": {
"visible": "isSavedSearchAvailable"
}
}
]
}

View File

@@ -134,6 +134,7 @@ import { SaveSearchSidenavComponent } from './components/search/search-save/side
isSmartFolder: rules.isSmartFolder,
isMultiSelection: rules.isMultiselection,
canPrintFile: rules.canPrintFile,
isSavedSearchAvailable: rules.isSavedSearchAvailable,
'app.selection.canDelete': rules.canDeleteSelection,
'app.selection.canDownload': rules.canDownloadSelection,

View File

@@ -26,17 +26,18 @@
<div class="aca-content__advanced-filters--header">
<p>{{ 'APP.BROWSE.SEARCH.ADVANCED_FILTERS' | translate }}</p>
<div class="aca-content__advanced-filters--header--action-buttons">
<button
*ngIf="initialSavedSearch !== undefined else saveSearchButton"
mat-button
[disabled]="!encodedQuery"
class="aca-content__save-search-action"
title="{{ 'APP.BROWSE.SEARCH.SAVE_SEARCH.ACTION_BUTTON' | translate }}"
[attr.aria-label]="'APP.BROWSE.SEARCH.SAVE_SEARCH.ACTION_BUTTON' | translate "
[matMenuTriggerFor]="saveSearchOptionsMenu">
{{ 'APP.BROWSE.SEARCH.SAVE_SEARCH.ACTION_BUTTON' | translate }}
<mat-icon iconPositionEnd>keyboard_arrow_down</mat-icon>
</button>
@if('isSavedSearchAvailable' | isFeatureSupportedInCurrentAcs | async) {
<button
*ngIf="initialSavedSearch !== undefined else saveSearchButton"
mat-button
[disabled]="!encodedQuery"
class="aca-content__save-search-action"
title="{{ 'APP.BROWSE.SEARCH.SAVE_SEARCH.ACTION_BUTTON' | translate }}"
[attr.aria-label]="'APP.BROWSE.SEARCH.SAVE_SEARCH.ACTION_BUTTON' | translate "
[matMenuTriggerFor]="saveSearchOptionsMenu">
{{ 'APP.BROWSE.SEARCH.SAVE_SEARCH.ACTION_BUTTON' | translate }}
<mat-icon iconPositionEnd>keyboard_arrow_down</mat-icon>
</button>
<mat-menu #saveSearchOptionsMenu="matMenu">
<button
mat-menu-item
@@ -66,6 +67,7 @@
{{ 'APP.BROWSE.SEARCH.SAVE_SEARCH.ACTION_BUTTON' | translate }}
</button>
</ng-template>
}
<button
mat-button
adf-reset-search

View File

@@ -24,13 +24,14 @@
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { SearchResultsComponent } from './search-results.component';
import { Pipe, PipeTransform } from '@angular/core';
import { AppConfigService, NotificationService, TranslationService } from '@alfresco/adf-core';
import { Store } from '@ngrx/store';
import { NavigateToFolder } from '@alfresco/aca-shared/store';
import { Pagination, SearchRequest } from '@alfresco/js-api';
import { SavedSearchesService, SearchQueryBuilderService } from '@alfresco/adf-content-services';
import { ActivatedRoute, Event, NavigationStart, Params, Router } from '@angular/router';
import { BehaviorSubject, of, Subject, throwError } from 'rxjs';
import { BehaviorSubject, Observable, of, Subject, throwError } from 'rxjs';
import { AppTestingModule } from '../../../testing/app-testing.module';
import { AppService } from '@alfresco/aca-shared';
import { MatSnackBarModule, MatSnackBarRef } from '@angular/material/snack-bar';
@@ -42,6 +43,13 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { MatMenuModule } from '@angular/material/menu';
import { MatMenuHarness } from '@angular/material/menu/testing';
@Pipe({ name: 'isFeatureSupportedInCurrentAcs' })
class MockIsFeatureSupportedInCurrentAcsPipe implements PipeTransform {
transform(): Observable<boolean> {
return of(true);
}
}
describe('SearchComponent', () => {
let component: SearchResultsComponent;
let fixture: ComponentFixture<SearchResultsComponent>;
@@ -112,6 +120,12 @@ describe('SearchComponent', () => {
]
});
TestBed.overrideComponent(SearchResultsComponent, {
add: {
imports: [MockIsFeatureSupportedInCurrentAcsPipe]
}
});
config = TestBed.inject(AppConfigService);
store = TestBed.inject(Store);
queryBuilder = TestBed.inject(SearchQueryBuilderService);

View File

@@ -88,6 +88,7 @@ import { SaveSearchDirective } from '../search-save/directive/save-search.direct
import { combineLatest, of } from 'rxjs';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { MatMenuModule } from '@angular/material/menu';
import { IsFeatureSupportedInCurrentAcsPipe } from '../../../pipes/is-feature-supported.pipe';
@Component({
imports: [
@@ -121,7 +122,8 @@ import { MatMenuModule } from '@angular/material/menu';
ViewerToolbarComponent,
BulkActionsDropdownComponent,
SearchAiInputContainerComponent,
SaveSearchDirective
SaveSearchDirective,
IsFeatureSupportedInCurrentAcsPipe
],
selector: 'aca-search-results',
templateUrl: './search-results.component.html',

View File

@@ -0,0 +1,55 @@
/*!
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Alfresco Example Content Application
*
* This file is part of the Alfresco Example Content Application.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
*/
import { of } from 'rxjs';
import { IsFeatureSupportedInCurrentAcsPipe } from './is-feature-supported.pipe';
import { TestBed } from '@angular/core/testing';
import { AppExtensionService } from '@alfresco/aca-shared';
import { AppStore } from '@alfresco/aca-shared/store';
import { Store } from '@ngrx/store';
describe('IsFeatureSupportedInCurrentAcsPipe', () => {
let serviceSpy: jasmine.SpyObj<AppExtensionService>;
let storeSpy: jasmine.SpyObj<Store<AppStore>>;
let pipe: IsFeatureSupportedInCurrentAcsPipe;
beforeEach(() => {
serviceSpy = jasmine.createSpyObj('AppExtensionService', ['isFeatureSupported']);
storeSpy = jasmine.createSpyObj('Store', ['dispatch', 'select']);
TestBed.configureTestingModule({
providers: [IsFeatureSupportedInCurrentAcsPipe, { provide: AppExtensionService, useValue: serviceSpy }, { provide: Store, useValue: storeSpy }]
});
pipe = TestBed.inject(IsFeatureSupportedInCurrentAcsPipe);
});
it('should call isFeatureSupported in AppExtensionService', (done) => {
serviceSpy.isFeatureSupported.and.returnValue(false);
storeSpy.select.and.returnValue(of('7.4.0'));
pipe.transform('someFeature').subscribe((result) => {
expect(result).toBe(false);
expect(serviceSpy.isFeatureSupported).toHaveBeenCalledWith('someFeature');
done();
});
});
});

View File

@@ -0,0 +1,43 @@
/*!
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Alfresco Example Content Application
*
* This file is part of the Alfresco Example Content Application.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
*/
import { AppExtensionService } from '@alfresco/aca-shared';
import { Pipe, PipeTransform } from '@angular/core';
import { AppStore, getRepositoryStatus } from '@alfresco/aca-shared/store';
import { Store } from '@ngrx/store';
import { map, Observable } from 'rxjs';
@Pipe({
name: 'isFeatureSupportedInCurrentAcs'
})
export class IsFeatureSupportedInCurrentAcsPipe implements PipeTransform {
constructor(
private readonly appExtensionsService: AppExtensionService,
private readonly store: Store<AppStore>
) {}
transform(evaluatorId: string): Observable<boolean> {
return this.store.select(getRepositoryStatus).pipe(map(() => this.appExtensionsService.isFeatureSupported(evaluatorId)));
}
}

View File

@@ -33,3 +33,4 @@ export * from './lib/services/content-url.service';
export * from './lib/services/content-management.service';
export * from './lib/components/info-drawer/comments-tab/external-node-permission-comments-tab.service';
export * from './lib/utils/aca-search-utils';
export * from './lib/pipes/is-feature-supported.pipe';