mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2026-09-09 18:02:54 +00:00
[ACS-10421] Add support for legacy config.json based approach for saved-searches (#4863)
* [ACS-9166]: introduces saved searches context service * [ACS-9166]: migrates to context service * [ACS-9166]: fixes tests * [ACS-9166]: removes prev approach artifacts * [ACS-9166]: fixes falsy emissions form pipe * [ACS-9166]: adds reactive strategy option * [ACS-9166]: tests fixes * [ACS-9166]: minor fix
This commit is contained in:
@@ -82,6 +82,6 @@ Rules/Evaluators created for specific features in ADW to be checked if supported
|
|||||||
|
|
||||||
| Version | Key | Description |
|
| Version | Key | Description |
|
||||||
|---------|---------------------------------|---------------------------------------------------------------------------|
|
|---------|---------------------------------|---------------------------------------------------------------------------|
|
||||||
| 8.1.0 | isSavedSearchAvailable | Checks whether current ACS version supports PUT method in Preferences API |
|
| 8.1.0 | isPreferencesApiAvailable | Checks whether current ACS version supports PUT method in Preferences API |
|
||||||
| 8.1.0 | isFolderInfoAvailable | Checks whether current ACS version supports folder size calculation API |
|
| 8.1.0 | isFolderInfoAvailable | Checks whether current ACS version supports folder size calculation API |
|
||||||
| 8.1.0 | isBulkActionsAvailable | Checks whether current ACS version supports bulk update feature |
|
| 8.1.0 | isBulkActionsAvailable | Checks whether current ACS version supports bulk update feature |
|
||||||
@@ -219,10 +219,7 @@
|
|||||||
"items": [
|
"items": [
|
||||||
{
|
{
|
||||||
"id": "app.search.navbar",
|
"id": "app.search.navbar",
|
||||||
"component": "app.search.navbar",
|
"component": "app.search.navbar"
|
||||||
"rules": {
|
|
||||||
"visible": "isSavedSearchAvailable"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ import { SearchResultsRowComponent } from './components/search/search-results-ro
|
|||||||
import { BulkActionsDropdownComponent } from './components/bulk-actions-dropdown/bulk-actions-dropdown.component';
|
import { BulkActionsDropdownComponent } from './components/bulk-actions-dropdown/bulk-actions-dropdown.component';
|
||||||
import { AgentsButtonComponent } from './components/knowledge-retrieval/search-ai/agents-button/agents-button.component';
|
import { AgentsButtonComponent } from './components/knowledge-retrieval/search-ai/agents-button/agents-button.component';
|
||||||
import { SaveSearchSidenavComponent } from './components/search/search-save/sidenav/save-search-sidenav.component';
|
import { SaveSearchSidenavComponent } from './components/search/search-save/sidenav/save-search-sidenav.component';
|
||||||
|
import { IsFeatureSupportedInCurrentAcsPipe } from './pipes/is-feature-supported.pipe';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [ContentModule.forRoot(), AppStoreModule, HammerModule],
|
imports: [ContentModule.forRoot(), AppStoreModule, HammerModule],
|
||||||
@@ -134,7 +135,7 @@ import { SaveSearchSidenavComponent } from './components/search/search-save/side
|
|||||||
isSmartFolder: rules.isSmartFolder,
|
isSmartFolder: rules.isSmartFolder,
|
||||||
isMultiSelection: rules.isMultiselection,
|
isMultiSelection: rules.isMultiselection,
|
||||||
canPrintFile: rules.canPrintFile,
|
canPrintFile: rules.canPrintFile,
|
||||||
isSavedSearchAvailable: rules.isSavedSearchAvailable,
|
isPreferencesApiAvailable: rules.isPreferencesApiAvailable,
|
||||||
isFolderInfoAvailable: rules.isFolderInfoAvailable,
|
isFolderInfoAvailable: rules.isFolderInfoAvailable,
|
||||||
isBulkActionsAvailable: rules.isBulkActionsAvailable,
|
isBulkActionsAvailable: rules.isBulkActionsAvailable,
|
||||||
|
|
||||||
@@ -169,7 +170,8 @@ import { SaveSearchSidenavComponent } from './components/search/search-save/side
|
|||||||
'app.areCategoriesEnabled': rules.areCategoriesEnabled,
|
'app.areCategoriesEnabled': rules.areCategoriesEnabled,
|
||||||
'app.isSSOEnabled': rules.isSSOEnabled
|
'app.isSSOEnabled': rules.isSSOEnabled
|
||||||
}
|
}
|
||||||
})
|
}),
|
||||||
|
IsFeatureSupportedInCurrentAcsPipe
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class ContentServiceExtensionModule {}
|
export class ContentServiceExtensionModule {}
|
||||||
|
|||||||
-2
@@ -26,7 +26,6 @@
|
|||||||
<div class="aca-content__advanced-filters--header">
|
<div class="aca-content__advanced-filters--header">
|
||||||
<p>{{ 'APP.BROWSE.SEARCH.ADVANCED_FILTERS' | translate }}</p>
|
<p>{{ 'APP.BROWSE.SEARCH.ADVANCED_FILTERS' | translate }}</p>
|
||||||
<div class="aca-content__advanced-filters--header--action-buttons">
|
<div class="aca-content__advanced-filters--header--action-buttons">
|
||||||
@if('isSavedSearchAvailable' | isFeatureSupportedInCurrentAcs | async) {
|
|
||||||
<button
|
<button
|
||||||
*ngIf="initialSavedSearch !== undefined else saveSearchButton"
|
*ngIf="initialSavedSearch !== undefined else saveSearchButton"
|
||||||
mat-button
|
mat-button
|
||||||
@@ -67,7 +66,6 @@
|
|||||||
{{ 'APP.BROWSE.SEARCH.SAVE_SEARCH.ACTION_BUTTON' | translate }}
|
{{ 'APP.BROWSE.SEARCH.SAVE_SEARCH.ACTION_BUTTON' | translate }}
|
||||||
</button>
|
</button>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
}
|
|
||||||
<button
|
<button
|
||||||
mat-button
|
mat-button
|
||||||
adf-reset-search
|
adf-reset-search
|
||||||
|
|||||||
+3
-2
@@ -29,7 +29,7 @@ import { AppConfigService, NotificationService, TranslationService } from '@alfr
|
|||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { NavigateToFolder } from '@alfresco/aca-shared/store';
|
import { NavigateToFolder } from '@alfresco/aca-shared/store';
|
||||||
import { Pagination, SearchRequest } from '@alfresco/js-api';
|
import { Pagination, SearchRequest } from '@alfresco/js-api';
|
||||||
import { SavedSearchesService, SearchQueryBuilderService } from '@alfresco/adf-content-services';
|
import { SearchQueryBuilderService } from '@alfresco/adf-content-services';
|
||||||
import { ActivatedRoute, Event, NavigationStart, Params, Router } from '@angular/router';
|
import { ActivatedRoute, Event, NavigationStart, Params, Router } from '@angular/router';
|
||||||
import { BehaviorSubject, Observable, of, Subject, throwError } from 'rxjs';
|
import { BehaviorSubject, Observable, of, Subject, throwError } from 'rxjs';
|
||||||
import { AppTestingModule } from '../../../testing/app-testing.module';
|
import { AppTestingModule } from '../../../testing/app-testing.module';
|
||||||
@@ -42,6 +42,7 @@ import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
|||||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
import { MatMenuModule } from '@angular/material/menu';
|
import { MatMenuModule } from '@angular/material/menu';
|
||||||
import { MatMenuHarness } from '@angular/material/menu/testing';
|
import { MatMenuHarness } from '@angular/material/menu/testing';
|
||||||
|
import { SavedSearchesContextService } from '../../../services/saved-searches-context.service';
|
||||||
|
|
||||||
@Pipe({ name: 'isFeatureSupportedInCurrentAcs' })
|
@Pipe({ name: 'isFeatureSupportedInCurrentAcs' })
|
||||||
class MockIsFeatureSupportedInCurrentAcsPipe implements PipeTransform {
|
class MockIsFeatureSupportedInCurrentAcsPipe implements PipeTransform {
|
||||||
@@ -96,7 +97,7 @@ describe('SearchComponent', () => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: SavedSearchesService,
|
provide: SavedSearchesContextService,
|
||||||
useValue: {
|
useValue: {
|
||||||
getSavedSearches: jasmine
|
getSavedSearches: jasmine
|
||||||
.createSpy('getSavedSearches')
|
.createSpy('getSavedSearches')
|
||||||
|
|||||||
+2
-2
@@ -30,7 +30,6 @@ import {
|
|||||||
DocumentListComponent,
|
DocumentListComponent,
|
||||||
ResetSearchDirective,
|
ResetSearchDirective,
|
||||||
SavedSearch,
|
SavedSearch,
|
||||||
SavedSearchesService,
|
|
||||||
SearchConfiguration,
|
SearchConfiguration,
|
||||||
SearchFilterChipsComponent,
|
SearchFilterChipsComponent,
|
||||||
SearchFormComponent,
|
SearchFormComponent,
|
||||||
@@ -89,6 +88,7 @@ import { combineLatest, of } from 'rxjs';
|
|||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
import { MatMenuModule } from '@angular/material/menu';
|
import { MatMenuModule } from '@angular/material/menu';
|
||||||
import { IsFeatureSupportedInCurrentAcsPipe } from '../../../pipes/is-feature-supported.pipe';
|
import { IsFeatureSupportedInCurrentAcsPipe } from '../../../pipes/is-feature-supported.pipe';
|
||||||
|
import { SavedSearchesContextService } from '../../../services/saved-searches-context.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -155,7 +155,7 @@ export class SearchResultsComponent extends PageComponent implements OnInit {
|
|||||||
private readonly changeDetectorRef: ChangeDetectorRef,
|
private readonly changeDetectorRef: ChangeDetectorRef,
|
||||||
private readonly route: ActivatedRoute,
|
private readonly route: ActivatedRoute,
|
||||||
private readonly translationService: TranslationService,
|
private readonly translationService: TranslationService,
|
||||||
private readonly savedSearchesService: SavedSearchesService
|
private readonly savedSearchesService: SavedSearchesContextService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
|||||||
+5
-4
@@ -26,14 +26,15 @@ import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testin
|
|||||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||||
import { of, throwError } from 'rxjs';
|
import { of, throwError } from 'rxjs';
|
||||||
import { SavedSearchDeleteDialogComponent } from './saved-search-delete-dialog.component';
|
import { SavedSearchDeleteDialogComponent } from './saved-search-delete-dialog.component';
|
||||||
import { SavedSearch, SavedSearchesService } from '@alfresco/adf-content-services';
|
import { SavedSearch } from '@alfresco/adf-content-services';
|
||||||
import { NotificationService } from '@alfresco/adf-core';
|
import { NotificationService } from '@alfresco/adf-core';
|
||||||
import { AppTestingModule } from '../../../../../testing/app-testing.module';
|
import { AppTestingModule } from '../../../../../testing/app-testing.module';
|
||||||
|
import { SavedSearchesContextService } from '../../../../../services/saved-searches-context.service';
|
||||||
|
|
||||||
describe('SaveSearchDeleteDialogComponent', () => {
|
describe('SaveSearchDeleteDialogComponent', () => {
|
||||||
let fixture: ComponentFixture<SavedSearchDeleteDialogComponent>;
|
let fixture: ComponentFixture<SavedSearchDeleteDialogComponent>;
|
||||||
let notificationService: NotificationService;
|
let notificationService: NotificationService;
|
||||||
let savedSearchesService: SavedSearchesService;
|
let savedSearchesService: SavedSearchesContextService;
|
||||||
let submitButton: HTMLButtonElement;
|
let submitButton: HTMLButtonElement;
|
||||||
let cancelButton: HTMLButtonElement;
|
let cancelButton: HTMLButtonElement;
|
||||||
|
|
||||||
@@ -52,13 +53,13 @@ describe('SaveSearchDeleteDialogComponent', () => {
|
|||||||
imports: [AppTestingModule, SavedSearchDeleteDialogComponent],
|
imports: [AppTestingModule, SavedSearchDeleteDialogComponent],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: MatDialogRef, useValue: dialogRef },
|
{ provide: MatDialogRef, useValue: dialogRef },
|
||||||
{ provide: SavedSearchesService, useValue: { deleteSavedSearch: () => of({}) } },
|
{ provide: SavedSearchesContextService, useValue: { deleteSavedSearch: () => of({}) } },
|
||||||
{ provide: MAT_DIALOG_DATA, useValue: savedSearchToDelete }
|
{ provide: MAT_DIALOG_DATA, useValue: savedSearchToDelete }
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
dialogRef.close.calls.reset();
|
dialogRef.close.calls.reset();
|
||||||
fixture = TestBed.createComponent(SavedSearchDeleteDialogComponent);
|
fixture = TestBed.createComponent(SavedSearchDeleteDialogComponent);
|
||||||
savedSearchesService = TestBed.inject(SavedSearchesService);
|
savedSearchesService = TestBed.inject(SavedSearchesContextService);
|
||||||
notificationService = TestBed.inject(NotificationService);
|
notificationService = TestBed.inject(NotificationService);
|
||||||
|
|
||||||
submitButton = fixture.nativeElement.querySelector('#aca-save-search-delete-dialog-submit-button');
|
submitButton = fixture.nativeElement.querySelector('#aca-save-search-delete-dialog-submit-button');
|
||||||
|
|||||||
+3
-2
@@ -23,7 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Component, Inject, ViewEncapsulation } from '@angular/core';
|
import { Component, Inject, ViewEncapsulation } from '@angular/core';
|
||||||
import { SavedSearch, SavedSearchesService } from '@alfresco/adf-content-services';
|
import { SavedSearch } from '@alfresco/adf-content-services';
|
||||||
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
|
||||||
import { take } from 'rxjs/operators';
|
import { take } from 'rxjs/operators';
|
||||||
import { NotificationService } from '@alfresco/adf-core';
|
import { NotificationService } from '@alfresco/adf-core';
|
||||||
@@ -31,6 +31,7 @@ import { TranslatePipe } from '@ngx-translate/core';
|
|||||||
import { TitleCasePipe } from '@angular/common';
|
import { TitleCasePipe } from '@angular/common';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { SavedSearchesContextService } from '../../../../../services/saved-searches-context.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
imports: [TranslatePipe, TitleCasePipe, MatIconModule, MatButtonModule, MatDialogModule],
|
imports: [TranslatePipe, TitleCasePipe, MatIconModule, MatButtonModule, MatDialogModule],
|
||||||
@@ -46,7 +47,7 @@ export class SavedSearchDeleteDialogComponent {
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly dialog: MatDialogRef<SavedSearchDeleteDialogComponent>,
|
private readonly dialog: MatDialogRef<SavedSearchDeleteDialogComponent>,
|
||||||
private readonly notificationService: NotificationService,
|
private readonly notificationService: NotificationService,
|
||||||
private readonly savedSearchesService: SavedSearchesService,
|
private readonly savedSearchesService: SavedSearchesContextService,
|
||||||
@Inject(MAT_DIALOG_DATA) private readonly data: SavedSearch
|
@Inject(MAT_DIALOG_DATA) private readonly data: SavedSearch
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
|||||||
+5
-4
@@ -26,16 +26,17 @@ import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testin
|
|||||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||||
import { of, throwError } from 'rxjs';
|
import { of, throwError } from 'rxjs';
|
||||||
import { SavedSearchEditDialogComponent } from './saved-search-edit-dialog.component';
|
import { SavedSearchEditDialogComponent } from './saved-search-edit-dialog.component';
|
||||||
import { SavedSearch, SavedSearchesService } from '@alfresco/adf-content-services';
|
import { SavedSearch } from '@alfresco/adf-content-services';
|
||||||
import { provideMockStore } from '@ngrx/store/testing';
|
import { provideMockStore } from '@ngrx/store/testing';
|
||||||
import { NotificationService } from '@alfresco/adf-core';
|
import { NotificationService } from '@alfresco/adf-core';
|
||||||
import { AppTestingModule } from '../../../../../testing/app-testing.module';
|
import { AppTestingModule } from '../../../../../testing/app-testing.module';
|
||||||
|
import { SavedSearchesContextService } from '../../../../../services/saved-searches-context.service';
|
||||||
|
|
||||||
describe('SaveSearchEditDialogComponent', () => {
|
describe('SaveSearchEditDialogComponent', () => {
|
||||||
let fixture: ComponentFixture<SavedSearchEditDialogComponent>;
|
let fixture: ComponentFixture<SavedSearchEditDialogComponent>;
|
||||||
let component: SavedSearchEditDialogComponent;
|
let component: SavedSearchEditDialogComponent;
|
||||||
let notificationService: NotificationService;
|
let notificationService: NotificationService;
|
||||||
let savedSearchesService: SavedSearchesService;
|
let savedSearchesService: SavedSearchesContextService;
|
||||||
let submitButton: HTMLButtonElement;
|
let submitButton: HTMLButtonElement;
|
||||||
|
|
||||||
const savedSearchToDelete: SavedSearch = {
|
const savedSearchToDelete: SavedSearch = {
|
||||||
@@ -54,7 +55,7 @@ describe('SaveSearchEditDialogComponent', () => {
|
|||||||
providers: [
|
providers: [
|
||||||
{ provide: MatDialogRef, useValue: dialogRef },
|
{ provide: MatDialogRef, useValue: dialogRef },
|
||||||
provideMockStore(),
|
provideMockStore(),
|
||||||
{ provide: SavedSearchesService, useValue: { editSavedSearch: () => of({}), getSavedSearches: () => of([]) } },
|
{ provide: SavedSearchesContextService, useValue: { editSavedSearch: () => of({}), getSavedSearches: () => of([]) } },
|
||||||
{ provide: MAT_DIALOG_DATA, useValue: savedSearchToDelete }
|
{ provide: MAT_DIALOG_DATA, useValue: savedSearchToDelete }
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
@@ -62,7 +63,7 @@ describe('SaveSearchEditDialogComponent', () => {
|
|||||||
fixture = TestBed.createComponent(SavedSearchEditDialogComponent);
|
fixture = TestBed.createComponent(SavedSearchEditDialogComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
notificationService = TestBed.inject(NotificationService);
|
notificationService = TestBed.inject(NotificationService);
|
||||||
savedSearchesService = TestBed.inject(SavedSearchesService);
|
savedSearchesService = TestBed.inject(SavedSearchesContextService);
|
||||||
|
|
||||||
submitButton = fixture.nativeElement.querySelector('#aca-saved-search-edit-dialog-submit-button');
|
submitButton = fixture.nativeElement.querySelector('#aca-saved-search-edit-dialog-submit-button');
|
||||||
});
|
});
|
||||||
|
|||||||
+3
-2
@@ -23,7 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Component, Inject, ViewEncapsulation } from '@angular/core';
|
import { Component, Inject, ViewEncapsulation } from '@angular/core';
|
||||||
import { AutoFocusDirective, forbidOnlySpaces, SavedSearch, SavedSearchesService } from '@alfresco/adf-content-services';
|
import { AutoFocusDirective, forbidOnlySpaces, SavedSearch } from '@alfresco/adf-content-services';
|
||||||
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
|
||||||
import { take } from 'rxjs/operators';
|
import { take } from 'rxjs/operators';
|
||||||
import { NotificationService } from '@alfresco/adf-core';
|
import { NotificationService } from '@alfresco/adf-core';
|
||||||
@@ -36,6 +36,7 @@ import { MatButtonModule } from '@angular/material/button';
|
|||||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { TitleCasePipe } from '@angular/common';
|
import { TitleCasePipe } from '@angular/common';
|
||||||
|
import { SavedSearchesContextService } from '../../../../../services/saved-searches-context.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -62,7 +63,7 @@ export class SavedSearchEditDialogComponent {
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly dialog: MatDialogRef<SavedSearchEditDialogComponent>,
|
private readonly dialog: MatDialogRef<SavedSearchEditDialogComponent>,
|
||||||
private readonly notificationService: NotificationService,
|
private readonly notificationService: NotificationService,
|
||||||
private readonly savedSearchesService: SavedSearchesService,
|
private readonly savedSearchesService: SavedSearchesContextService,
|
||||||
private readonly uniqueSearchNameValidator: UniqueSearchNameValidator,
|
private readonly uniqueSearchNameValidator: UniqueSearchNameValidator,
|
||||||
@Inject(MAT_DIALOG_DATA) private readonly data: SavedSearch
|
@Inject(MAT_DIALOG_DATA) private readonly data: SavedSearch
|
||||||
) {
|
) {
|
||||||
|
|||||||
+4
-4
@@ -26,16 +26,16 @@ import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testin
|
|||||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||||
import { of, throwError } from 'rxjs';
|
import { of, throwError } from 'rxjs';
|
||||||
import { SaveSearchDialogComponent } from './save-search-dialog.component';
|
import { SaveSearchDialogComponent } from './save-search-dialog.component';
|
||||||
import { SavedSearchesService } from '@alfresco/adf-content-services';
|
|
||||||
import { provideMockStore } from '@ngrx/store/testing';
|
import { provideMockStore } from '@ngrx/store/testing';
|
||||||
import { AppTestingModule } from '../../../../testing/app-testing.module';
|
import { AppTestingModule } from '../../../../testing/app-testing.module';
|
||||||
import { NoopTranslateModule, NotificationService } from '@alfresco/adf-core';
|
import { NoopTranslateModule, NotificationService } from '@alfresco/adf-core';
|
||||||
|
import { SavedSearchesContextService } from '../../../../services/saved-searches-context.service';
|
||||||
|
|
||||||
describe('SaveSearchDialogComponent', () => {
|
describe('SaveSearchDialogComponent', () => {
|
||||||
let fixture: ComponentFixture<SaveSearchDialogComponent>;
|
let fixture: ComponentFixture<SaveSearchDialogComponent>;
|
||||||
let component: SaveSearchDialogComponent;
|
let component: SaveSearchDialogComponent;
|
||||||
let notificationService: NotificationService;
|
let notificationService: NotificationService;
|
||||||
let savedSearchesService: SavedSearchesService;
|
let savedSearchesService: SavedSearchesContextService;
|
||||||
let submitButton: HTMLButtonElement;
|
let submitButton: HTMLButtonElement;
|
||||||
|
|
||||||
const dialogRef = {
|
const dialogRef = {
|
||||||
@@ -48,7 +48,7 @@ describe('SaveSearchDialogComponent', () => {
|
|||||||
providers: [
|
providers: [
|
||||||
{ provide: MatDialogRef, useValue: dialogRef },
|
{ provide: MatDialogRef, useValue: dialogRef },
|
||||||
provideMockStore(),
|
provideMockStore(),
|
||||||
{ provide: SavedSearchesService, useValue: { saveSearch: () => of({}), getSavedSearches: () => of([]) } },
|
{ provide: SavedSearchesContextService, useValue: { saveSearch: () => of({}), getSavedSearches: () => of([]) } },
|
||||||
{ provide: MAT_DIALOG_DATA, useValue: { searchUrl: 'abcdef' } }
|
{ provide: MAT_DIALOG_DATA, useValue: { searchUrl: 'abcdef' } }
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
@@ -56,7 +56,7 @@ describe('SaveSearchDialogComponent', () => {
|
|||||||
fixture = TestBed.createComponent(SaveSearchDialogComponent);
|
fixture = TestBed.createComponent(SaveSearchDialogComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
notificationService = TestBed.inject(NotificationService);
|
notificationService = TestBed.inject(NotificationService);
|
||||||
savedSearchesService = TestBed.inject(SavedSearchesService);
|
savedSearchesService = TestBed.inject(SavedSearchesContextService);
|
||||||
|
|
||||||
submitButton = fixture.nativeElement.querySelector('#aca-save-search-dialog-save-button');
|
submitButton = fixture.nativeElement.querySelector('#aca-save-search-dialog-save-button');
|
||||||
});
|
});
|
||||||
|
|||||||
+3
-2
@@ -34,11 +34,12 @@ import { A11yModule } from '@angular/cdk/a11y';
|
|||||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||||
import { FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
|
import { FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||||
import { NotificationService } from '@alfresco/adf-core';
|
import { NotificationService } from '@alfresco/adf-core';
|
||||||
import { AutoFocusDirective, forbidOnlySpaces, SavedSearchesService } from '@alfresco/adf-content-services';
|
import { AutoFocusDirective, forbidOnlySpaces } from '@alfresco/adf-content-services';
|
||||||
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
|
||||||
import { take } from 'rxjs/operators';
|
import { take } from 'rxjs/operators';
|
||||||
import { UniqueSearchNameValidator } from './unique-search-name-validator';
|
import { UniqueSearchNameValidator } from './unique-search-name-validator';
|
||||||
import { SavedSearchForm } from './saved-search-form.interface';
|
import { SavedSearchForm } from './saved-search-form.interface';
|
||||||
|
import { SavedSearchesContextService } from '../../../../services/saved-searches-context.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -69,7 +70,7 @@ export class SaveSearchDialogComponent {
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly dialog: MatDialogRef<SaveSearchDialogComponent>,
|
private readonly dialog: MatDialogRef<SaveSearchDialogComponent>,
|
||||||
private readonly notificationService: NotificationService,
|
private readonly notificationService: NotificationService,
|
||||||
private readonly savedSearchesService: SavedSearchesService,
|
private readonly savedSearchesService: SavedSearchesContextService,
|
||||||
private readonly uniqueSearchNameValidator: UniqueSearchNameValidator,
|
private readonly uniqueSearchNameValidator: UniqueSearchNameValidator,
|
||||||
@Inject(MAT_DIALOG_DATA) private readonly data: { searchUrl: string }
|
@Inject(MAT_DIALOG_DATA) private readonly data: { searchUrl: string }
|
||||||
) {
|
) {
|
||||||
|
|||||||
+3
-3
@@ -24,10 +24,10 @@
|
|||||||
|
|
||||||
import { TestBed } from '@angular/core/testing';
|
import { TestBed } from '@angular/core/testing';
|
||||||
import { UniqueSearchNameValidator } from './unique-search-name-validator';
|
import { UniqueSearchNameValidator } from './unique-search-name-validator';
|
||||||
import { SavedSearchesService } from '@alfresco/adf-content-services';
|
|
||||||
import { of } from 'rxjs';
|
import { of } from 'rxjs';
|
||||||
import { FormControl } from '@angular/forms';
|
import { FormControl } from '@angular/forms';
|
||||||
import { NoopTranslateModule } from '@alfresco/adf-core';
|
import { NoopTranslateModule } from '@alfresco/adf-core';
|
||||||
|
import { SavedSearchesContextService } from '../../../../services/saved-searches-context.service';
|
||||||
|
|
||||||
describe('UniqueSearchNameValidator', () => {
|
describe('UniqueSearchNameValidator', () => {
|
||||||
let validator: UniqueSearchNameValidator;
|
let validator: UniqueSearchNameValidator;
|
||||||
@@ -40,7 +40,7 @@ describe('UniqueSearchNameValidator', () => {
|
|||||||
|
|
||||||
describe('Save searches returns results', () => {
|
describe('Save searches returns results', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.overrideProvider(SavedSearchesService, { useValue: { getSavedSearches: () => of([{ name: 'test' }]) } });
|
TestBed.overrideProvider(SavedSearchesContextService, { useValue: { getSavedSearches: () => of([{ name: 'test' }]) } });
|
||||||
validator = TestBed.inject(UniqueSearchNameValidator);
|
validator = TestBed.inject(UniqueSearchNameValidator);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ describe('UniqueSearchNameValidator', () => {
|
|||||||
|
|
||||||
describe('Save searches returns error', () => {
|
describe('Save searches returns error', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.overrideProvider(SavedSearchesService, { useValue: { getSavedSearches: () => of(null) } });
|
TestBed.overrideProvider(SavedSearchesContextService, { useValue: { getSavedSearches: () => of(null) } });
|
||||||
validator = TestBed.inject(UniqueSearchNameValidator);
|
validator = TestBed.inject(UniqueSearchNameValidator);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -22,14 +22,14 @@
|
|||||||
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
|
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { SavedSearchesService } from '@alfresco/adf-content-services';
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { AbstractControl, AsyncValidator, ValidationErrors } from '@angular/forms';
|
import { AbstractControl, AsyncValidator, ValidationErrors } from '@angular/forms';
|
||||||
import { catchError, map, Observable, of } from 'rxjs';
|
import { catchError, map, Observable, of } from 'rxjs';
|
||||||
|
import { SavedSearchesContextService } from '../../../../services/saved-searches-context.service';
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class UniqueSearchNameValidator implements AsyncValidator {
|
export class UniqueSearchNameValidator implements AsyncValidator {
|
||||||
constructor(private readonly savedSearchesService: SavedSearchesService) {}
|
constructor(private readonly savedSearchesService: SavedSearchesContextService) {}
|
||||||
|
|
||||||
validate(control: AbstractControl): Observable<ValidationErrors | null> {
|
validate(control: AbstractControl): Observable<ValidationErrors | null> {
|
||||||
return this.savedSearchesService.getSavedSearches().pipe(
|
return this.savedSearchesService.getSavedSearches().pipe(
|
||||||
|
|||||||
+3
-2
@@ -26,11 +26,12 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|||||||
import { NoopTranslateModule, provideCoreAuthTesting } from '@alfresco/adf-core';
|
import { NoopTranslateModule, provideCoreAuthTesting } from '@alfresco/adf-core';
|
||||||
import { BehaviorSubject, ReplaySubject, Subject } from 'rxjs';
|
import { BehaviorSubject, ReplaySubject, Subject } from 'rxjs';
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
import { SavedSearchesService, SavedSearch } from '@alfresco/adf-content-services';
|
import { SavedSearch } from '@alfresco/adf-content-services';
|
||||||
import { SavedSearchesSmartListComponent } from './saved-searches-smart-list.component';
|
import { SavedSearchesSmartListComponent } from './saved-searches-smart-list.component';
|
||||||
import { AppService, DocumentBasePageService, DocumentBasePageServiceMock } from '@alfresco/aca-shared';
|
import { AppService, DocumentBasePageService, DocumentBasePageServiceMock } from '@alfresco/aca-shared';
|
||||||
import { AppState } from '@alfresco/aca-shared/store';
|
import { AppState } from '@alfresco/aca-shared/store';
|
||||||
import { provideMockStore } from '@ngrx/store/testing';
|
import { provideMockStore } from '@ngrx/store/testing';
|
||||||
|
import { SavedSearchesContextService } from '../../../../../services/saved-searches-context.service';
|
||||||
|
|
||||||
const appServiceMock = {
|
const appServiceMock = {
|
||||||
appNavNarMode$: new BehaviorSubject('collapsed'),
|
appNavNarMode$: new BehaviorSubject('collapsed'),
|
||||||
@@ -63,7 +64,7 @@ describe('SavedSearchesSmartListComponent', () => {
|
|||||||
initialState: { app: appState }
|
initialState: { app: appState }
|
||||||
}),
|
}),
|
||||||
{ provide: DocumentBasePageService, useClass: DocumentBasePageServiceMock },
|
{ provide: DocumentBasePageService, useClass: DocumentBasePageServiceMock },
|
||||||
{ provide: SavedSearchesService, useValue: { savedSearches$: fakeSavedSearches$ } },
|
{ provide: SavedSearchesContextService, useValue: { savedSearches$: fakeSavedSearches$ } },
|
||||||
{ provide: AppService, useValue: appServiceMock }
|
{ provide: AppService, useValue: appServiceMock }
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|||||||
+2
-2
@@ -27,9 +27,9 @@ import { CommonModule } from '@angular/common';
|
|||||||
import { TranslatePipe } from '@ngx-translate/core';
|
import { TranslatePipe } from '@ngx-translate/core';
|
||||||
import { SavedSearchesListUiComponent } from '../ui-list/saved-searches-list.ui-component';
|
import { SavedSearchesListUiComponent } from '../ui-list/saved-searches-list.ui-component';
|
||||||
import { PageComponent, PageLayoutComponent } from '@alfresco/aca-shared';
|
import { PageComponent, PageLayoutComponent } from '@alfresco/aca-shared';
|
||||||
import { SavedSearchesService } from '@alfresco/adf-content-services';
|
|
||||||
import { EmptyContentComponent } from '@alfresco/adf-core';
|
import { EmptyContentComponent } from '@alfresco/adf-core';
|
||||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||||
|
import { SavedSearchesContextService } from '../../../../../services/saved-searches-context.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'aca-saved-searches-smart-list',
|
selector: 'aca-saved-searches-smart-list',
|
||||||
@@ -39,7 +39,7 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class SavedSearchesSmartListComponent extends PageComponent {
|
export class SavedSearchesSmartListComponent extends PageComponent {
|
||||||
savedSearchesService = inject(SavedSearchesService);
|
savedSearchesService = inject(SavedSearchesContextService);
|
||||||
|
|
||||||
savedSearches$ = this.savedSearchesService.savedSearches$;
|
savedSearches$ = this.savedSearchesService.savedSearches$;
|
||||||
|
|
||||||
|
|||||||
+14
-19
@@ -24,26 +24,29 @@
|
|||||||
|
|
||||||
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
|
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
|
||||||
import { SaveSearchSidenavComponent } from './save-search-sidenav.component';
|
import { SaveSearchSidenavComponent } from './save-search-sidenav.component';
|
||||||
import { SavedSearchesService } from '@alfresco/adf-content-services';
|
|
||||||
import { AppTestingModule } from '../../../../testing/app-testing.module';
|
import { AppTestingModule } from '../../../../testing/app-testing.module';
|
||||||
import { of, ReplaySubject } from 'rxjs';
|
import { Observable, of } from 'rxjs';
|
||||||
|
import { SavedSearchesContextService } from '../../../../services/saved-searches-context.service';
|
||||||
|
import { SavedSearch } from '@alfresco/adf-content-services';
|
||||||
|
|
||||||
describe('SaveSearchSidenavComponent', () => {
|
describe('SaveSearchSidenavComponent', () => {
|
||||||
let fixture: ComponentFixture<SaveSearchSidenavComponent>;
|
let fixture: ComponentFixture<SaveSearchSidenavComponent>;
|
||||||
let component: SaveSearchSidenavComponent;
|
let component: SaveSearchSidenavComponent;
|
||||||
let savedSearchesService: SavedSearchesService;
|
let savedSearchesService: SavedSearchesContextService;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const mockService = {
|
const mockService: Partial<SavedSearchesContextService> = {
|
||||||
init: () => {},
|
init: (): void => {},
|
||||||
getSavedSearches: () => of(),
|
|
||||||
savedSearches$: new ReplaySubject(1)
|
get savedSearches$(): Observable<SavedSearch[]> {
|
||||||
|
return of([]);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [AppTestingModule, SaveSearchSidenavComponent],
|
imports: [AppTestingModule, SaveSearchSidenavComponent],
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: SavedSearchesService,
|
provide: SavedSearchesContextService,
|
||||||
useValue: mockService
|
useValue: mockService
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -51,15 +54,11 @@ describe('SaveSearchSidenavComponent', () => {
|
|||||||
|
|
||||||
fixture = TestBed.createComponent(SaveSearchSidenavComponent);
|
fixture = TestBed.createComponent(SaveSearchSidenavComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
savedSearchesService = TestBed.inject(SavedSearchesService);
|
savedSearchesService = TestBed.inject(SavedSearchesContextService);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set navbar object if no search is saved', async () => {
|
it('should set navbar object if no search is saved', async () => {
|
||||||
Object.defineProperty(savedSearchesService, 'savedSearches$', {
|
spyOnProperty(savedSearchesService, 'savedSearches$', 'get').and.returnValue(of([]));
|
||||||
value: of([]),
|
|
||||||
writable: true,
|
|
||||||
configurable: true
|
|
||||||
});
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
await fixture.whenStable();
|
await fixture.whenStable();
|
||||||
|
|
||||||
@@ -82,11 +81,7 @@ describe('SaveSearchSidenavComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should set navbar object with children is searches are saved', fakeAsync(() => {
|
it('should set navbar object with children is searches are saved', fakeAsync(() => {
|
||||||
Object.defineProperty(savedSearchesService, 'savedSearches$', {
|
spyOnProperty(savedSearchesService, 'savedSearches$', 'get').and.returnValue(of([{ name: '1', order: 0, encodedUrl: 'abc' }]));
|
||||||
value: of([{ name: '1', order: 0, encodedUrl: 'abc' }]),
|
|
||||||
writable: true,
|
|
||||||
configurable: true
|
|
||||||
});
|
|
||||||
component.ngOnInit();
|
component.ngOnInit();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
tick(100);
|
tick(100);
|
||||||
|
|||||||
+3
-2
@@ -23,13 +23,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Component, DestroyRef, inject, OnInit, ViewEncapsulation } from '@angular/core';
|
import { Component, DestroyRef, inject, OnInit, ViewEncapsulation } from '@angular/core';
|
||||||
import { SavedSearch, SavedSearchesService } from '@alfresco/adf-content-services';
|
import { SavedSearch } from '@alfresco/adf-content-services';
|
||||||
import { TranslationService, UserPreferencesService, UserPreferenceValues } from '@alfresco/adf-core';
|
import { TranslationService, UserPreferencesService, UserPreferenceValues } from '@alfresco/adf-core';
|
||||||
import { NavBarLinkRef } from '@alfresco/adf-extensions';
|
import { NavBarLinkRef } from '@alfresco/adf-extensions';
|
||||||
import { ExpandMenuComponent } from '../../../sidenav/components/expand-menu.component';
|
import { ExpandMenuComponent } from '../../../sidenav/components/expand-menu.component';
|
||||||
import { AppService } from '@alfresco/aca-shared';
|
import { AppService } from '@alfresco/aca-shared';
|
||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
import { delay } from 'rxjs/operators';
|
import { delay } from 'rxjs/operators';
|
||||||
|
import { SavedSearchesContextService } from '../../../../services/saved-searches-context.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'aca-save-search-sidenav',
|
selector: 'aca-save-search-sidenav',
|
||||||
@@ -38,7 +39,7 @@ import { delay } from 'rxjs/operators';
|
|||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class SaveSearchSidenavComponent implements OnInit {
|
export class SaveSearchSidenavComponent implements OnInit {
|
||||||
savedSearchesService = inject(SavedSearchesService);
|
savedSearchesService = inject(SavedSearchesContextService);
|
||||||
appService = inject(AppService);
|
appService = inject(AppService);
|
||||||
translationService = inject(TranslationService);
|
translationService = inject(TranslationService);
|
||||||
item: NavBarLinkRef;
|
item: NavBarLinkRef;
|
||||||
|
|||||||
@@ -22,34 +22,48 @@
|
|||||||
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
|
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { of } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
import { IsFeatureSupportedInCurrentAcsPipe } from './is-feature-supported.pipe';
|
import { IsFeatureSupportedInCurrentAcsPipe } from './is-feature-supported.pipe';
|
||||||
import { TestBed } from '@angular/core/testing';
|
import { TestBed } from '@angular/core/testing';
|
||||||
import { AppExtensionService } from '@alfresco/aca-shared';
|
import { AppExtensionService } from '@alfresco/aca-shared';
|
||||||
import { AppStore } from '@alfresco/aca-shared/store';
|
import { AppStore } from '@alfresco/aca-shared/store';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
|
import { RepositoryInfo, VersionInfo } from '@alfresco/js-api';
|
||||||
|
|
||||||
describe('IsFeatureSupportedInCurrentAcsPipe', () => {
|
describe('IsFeatureSupportedInCurrentAcsPipe', () => {
|
||||||
let serviceSpy: jasmine.SpyObj<AppExtensionService>;
|
let serviceSpy: jasmine.SpyObj<AppExtensionService>;
|
||||||
let storeSpy: jasmine.SpyObj<Store<AppStore>>;
|
let storeSpy: jasmine.SpyObj<Store<AppStore>>;
|
||||||
let pipe: IsFeatureSupportedInCurrentAcsPipe;
|
let pipe: IsFeatureSupportedInCurrentAcsPipe;
|
||||||
|
let repoStatusSubject: Subject<Partial<RepositoryInfo>>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
serviceSpy = jasmine.createSpyObj('AppExtensionService', ['isFeatureSupported']);
|
serviceSpy = jasmine.createSpyObj('AppExtensionService', ['isFeatureSupported']);
|
||||||
storeSpy = jasmine.createSpyObj('Store', ['dispatch', 'select']);
|
storeSpy = jasmine.createSpyObj('Store', ['dispatch', 'select']);
|
||||||
|
repoStatusSubject = new Subject<Partial<RepositoryInfo>>();
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
providers: [IsFeatureSupportedInCurrentAcsPipe, { provide: AppExtensionService, useValue: serviceSpy }, { provide: Store, useValue: storeSpy }]
|
providers: [IsFeatureSupportedInCurrentAcsPipe, { provide: AppExtensionService, useValue: serviceSpy }, { provide: Store, useValue: storeSpy }]
|
||||||
});
|
});
|
||||||
pipe = TestBed.inject(IsFeatureSupportedInCurrentAcsPipe);
|
pipe = TestBed.inject(IsFeatureSupportedInCurrentAcsPipe);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call isFeatureSupported in AppExtensionService', (done) => {
|
it('should wait until the version property is available before calling isFeatureSupported', (done) => {
|
||||||
serviceSpy.isFeatureSupported.and.returnValue(false);
|
const featureId = 'someFeature';
|
||||||
storeSpy.select.and.returnValue(of('7.4.0'));
|
serviceSpy.isFeatureSupported.and.returnValue(true);
|
||||||
pipe.transform('someFeature').subscribe((result) => {
|
|
||||||
expect(result).toBe(false);
|
storeSpy.select.and.returnValue(repoStatusSubject.asObservable());
|
||||||
expect(serviceSpy.isFeatureSupported).toHaveBeenCalledWith('someFeature');
|
|
||||||
done();
|
pipe.transform(featureId).subscribe({
|
||||||
|
next: (result) => {
|
||||||
|
expect(result).toBe(true);
|
||||||
|
expect(serviceSpy.isFeatureSupported).toHaveBeenCalledWith(featureId);
|
||||||
|
done();
|
||||||
|
},
|
||||||
|
error: done.fail
|
||||||
});
|
});
|
||||||
|
|
||||||
|
repoStatusSubject.next({});
|
||||||
|
expect(serviceSpy.isFeatureSupported).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
repoStatusSubject.next({ version: {} as VersionInfo });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import { AppExtensionService } from '@alfresco/aca-shared';
|
|||||||
import { Pipe, PipeTransform } from '@angular/core';
|
import { Pipe, PipeTransform } from '@angular/core';
|
||||||
import { AppStore, getRepositoryStatus } from '@alfresco/aca-shared/store';
|
import { AppStore, getRepositoryStatus } from '@alfresco/aca-shared/store';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { map, Observable } from 'rxjs';
|
import { filter, map, Observable } from 'rxjs';
|
||||||
|
|
||||||
@Pipe({
|
@Pipe({
|
||||||
name: 'isFeatureSupportedInCurrentAcs'
|
name: 'isFeatureSupportedInCurrentAcs'
|
||||||
@@ -38,6 +38,9 @@ export class IsFeatureSupportedInCurrentAcsPipe implements PipeTransform {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
transform(evaluatorId: string): Observable<boolean> {
|
transform(evaluatorId: string): Observable<boolean> {
|
||||||
return this.store.select(getRepositoryStatus).pipe(map(() => this.appExtensionsService.isFeatureSupported(evaluatorId)));
|
return this.store.select(getRepositoryStatus).pipe(
|
||||||
|
filter((repoStatus) => 'version' in repoStatus),
|
||||||
|
map(() => this.appExtensionsService.isFeatureSupported(evaluatorId))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,186 @@
|
|||||||
|
/*!
|
||||||
|
* 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 { TestBed } from '@angular/core/testing';
|
||||||
|
import { Subject } from 'rxjs';
|
||||||
|
|
||||||
|
import { SavedSearchesContextService } from './saved-searches-context.service';
|
||||||
|
import { SavedSearch, SavedSearchesLegacyService, SavedSearchesService } from '@alfresco/adf-content-services';
|
||||||
|
import { IsFeatureSupportedInCurrentAcsPipe } from '../pipes/is-feature-supported.pipe';
|
||||||
|
|
||||||
|
describe('SavedSearchesContextService', () => {
|
||||||
|
let legacySpy: jasmine.SpyObj<SavedSearchesLegacyService>;
|
||||||
|
let modernSpy: jasmine.SpyObj<SavedSearchesService>;
|
||||||
|
let isSupportedPipeMock: Partial<IsFeatureSupportedInCurrentAcsPipe>;
|
||||||
|
let service: SavedSearchesContextService;
|
||||||
|
let isSupported: Subject<boolean>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
legacySpy = jasmine.createSpyObj('SavedSearchesLegacyService', [
|
||||||
|
'savedSearches$',
|
||||||
|
'init',
|
||||||
|
'getSavedSearches',
|
||||||
|
'saveSearch',
|
||||||
|
'editSavedSearch',
|
||||||
|
'deleteSavedSearch',
|
||||||
|
'changeOrder'
|
||||||
|
]);
|
||||||
|
|
||||||
|
modernSpy = jasmine.createSpyObj('SavedSearchesService', [
|
||||||
|
'savedSearches$',
|
||||||
|
'init',
|
||||||
|
'getSavedSearches',
|
||||||
|
'saveSearch',
|
||||||
|
'editSavedSearch',
|
||||||
|
'deleteSavedSearch',
|
||||||
|
'changeOrder'
|
||||||
|
]);
|
||||||
|
|
||||||
|
isSupported = new Subject<boolean>();
|
||||||
|
|
||||||
|
isSupportedPipeMock = {
|
||||||
|
transform: () => isSupported
|
||||||
|
};
|
||||||
|
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
providers: [
|
||||||
|
{ provide: IsFeatureSupportedInCurrentAcsPipe, useValue: isSupportedPipeMock },
|
||||||
|
{ provide: SavedSearchesLegacyService, useValue: legacySpy },
|
||||||
|
{ provide: SavedSearchesService, useValue: modernSpy }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
service = TestBed.inject(SavedSearchesContextService);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('modern strategy', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
isSupported.next(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use modern service when feature is supported', () => {
|
||||||
|
service.init();
|
||||||
|
expect(legacySpy.init).not.toHaveBeenCalled();
|
||||||
|
expect(modernSpy.init).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delegate init() call to a current strategy', () => {
|
||||||
|
service.init();
|
||||||
|
expect(modernSpy.init).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delegate getSavedSearches() call to a current strategy', () => {
|
||||||
|
service.getSavedSearches();
|
||||||
|
expect(modernSpy.getSavedSearches).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delegate saveSearch() call to a current strategy', () => {
|
||||||
|
const newSavedSearch = { name: 'Test Search', description: 'Test Description', encodedUrl: 'http://example.com' };
|
||||||
|
service.saveSearch(newSavedSearch);
|
||||||
|
expect(modernSpy.saveSearch).toHaveBeenCalledWith(newSavedSearch);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delegate editSavedSearch() call to a current strategy', () => {
|
||||||
|
const updatedSavedSearch = {
|
||||||
|
name: 'Updated Search',
|
||||||
|
description: 'Updated Description',
|
||||||
|
encodedUrl: 'http://example.com',
|
||||||
|
order: 1
|
||||||
|
};
|
||||||
|
service.editSavedSearch(updatedSavedSearch);
|
||||||
|
expect(modernSpy.editSavedSearch).toHaveBeenCalledWith(updatedSavedSearch);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delegate deleteSavedSearch() call to a current strategy', () => {
|
||||||
|
const deletedSavedSearch = {
|
||||||
|
name: 'Deleted Search',
|
||||||
|
description: 'Deleted Description',
|
||||||
|
encodedUrl: 'http://example.com',
|
||||||
|
order: 2
|
||||||
|
};
|
||||||
|
service.deleteSavedSearch(deletedSavedSearch);
|
||||||
|
expect(modernSpy.deleteSavedSearch).toHaveBeenCalledWith(deletedSavedSearch);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delegate changeOrder() call to a current strategy', () => {
|
||||||
|
service.changeOrder(0, 1);
|
||||||
|
expect(modernSpy.changeOrder).toHaveBeenCalledWith(0, 1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('legacy strategy', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
isSupported.next(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use legacy service when feature is NOT supported', () => {
|
||||||
|
service.init();
|
||||||
|
expect(legacySpy.init).toHaveBeenCalled();
|
||||||
|
expect(modernSpy.init).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delegate init() call to a current strategy', () => {
|
||||||
|
service.init();
|
||||||
|
expect(legacySpy.init).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delegate getSavedSearches() call to a current strategy', () => {
|
||||||
|
service.getSavedSearches();
|
||||||
|
expect(legacySpy.getSavedSearches).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delegate saveSearch() call to a current strategy', () => {
|
||||||
|
const newSavedSearch = { name: 'Test Search', description: 'Test Description', encodedUrl: 'http://example.com' } as SavedSearch;
|
||||||
|
service.saveSearch(newSavedSearch);
|
||||||
|
expect(legacySpy.saveSearch).toHaveBeenCalledWith(newSavedSearch);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delegate editSavedSearch() call to a current strategy', () => {
|
||||||
|
const updatedSavedSearch: SavedSearch = {
|
||||||
|
name: 'Updated Search',
|
||||||
|
description: 'Updated Description',
|
||||||
|
encodedUrl: 'http://example.com',
|
||||||
|
order: 1
|
||||||
|
};
|
||||||
|
service.editSavedSearch(updatedSavedSearch);
|
||||||
|
expect(legacySpy.editSavedSearch).toHaveBeenCalledWith(updatedSavedSearch);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delegate deleteSavedSearch() call to a current strategy', () => {
|
||||||
|
const deletedSavedSearch: SavedSearch = {
|
||||||
|
name: 'Deleted Search',
|
||||||
|
description: 'Deleted Description',
|
||||||
|
encodedUrl: 'http://example.com',
|
||||||
|
order: 2
|
||||||
|
};
|
||||||
|
service.deleteSavedSearch(deletedSavedSearch);
|
||||||
|
expect(legacySpy.deleteSavedSearch).toHaveBeenCalledWith(deletedSavedSearch);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delegate changeOrder() call to a current strategy', () => {
|
||||||
|
service.changeOrder(0, 1);
|
||||||
|
expect(legacySpy.changeOrder).toHaveBeenCalledWith(0, 1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
/*!
|
||||||
|
* 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 { Injectable } from '@angular/core';
|
||||||
|
import { Observable, ReplaySubject, switchMap, take } from 'rxjs';
|
||||||
|
import { NodeEntry } from '@alfresco/js-api';
|
||||||
|
import { SavedSearch, SavedSearchesLegacyService, SavedSearchesService, SavedSearchStrategy } from '@alfresco/adf-content-services';
|
||||||
|
import { IsFeatureSupportedInCurrentAcsPipe } from '../pipes/is-feature-supported.pipe';
|
||||||
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class SavedSearchesContextService implements SavedSearchStrategy {
|
||||||
|
private readonly strategy$ = new ReplaySubject<SavedSearchStrategy>(1);
|
||||||
|
private strategy: SavedSearchStrategy;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly legacyService: SavedSearchesLegacyService,
|
||||||
|
private readonly modernService: SavedSearchesService,
|
||||||
|
isFeatureSupported: IsFeatureSupportedInCurrentAcsPipe
|
||||||
|
) {
|
||||||
|
isFeatureSupported
|
||||||
|
.transform('isPreferencesApiAvailable')
|
||||||
|
.pipe(takeUntilDestroyed())
|
||||||
|
.subscribe((isSupported) => {
|
||||||
|
this.strategy = isSupported ? this.modernService : this.legacyService;
|
||||||
|
this.strategy$.next(this.strategy);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get savedSearches$(): Observable<SavedSearch[]> {
|
||||||
|
return this.strategy$.pipe(switchMap((strategy) => strategy.savedSearches$));
|
||||||
|
}
|
||||||
|
|
||||||
|
init(): void {
|
||||||
|
this.strategy$.pipe(take(1)).subscribe((strategy) => strategy.init());
|
||||||
|
}
|
||||||
|
|
||||||
|
getSavedSearches(): Observable<SavedSearch[]> {
|
||||||
|
return this.strategy.getSavedSearches();
|
||||||
|
}
|
||||||
|
|
||||||
|
saveSearch(newSaveSearch: Pick<SavedSearch, 'name' | 'description' | 'encodedUrl'>): Observable<NodeEntry> {
|
||||||
|
return this.strategy.saveSearch(newSaveSearch);
|
||||||
|
}
|
||||||
|
|
||||||
|
editSavedSearch(updatedSavedSearch: SavedSearch): Observable<NodeEntry> {
|
||||||
|
return this.strategy.editSavedSearch(updatedSavedSearch);
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteSavedSearch(deletedSavedSearch: SavedSearch): Observable<NodeEntry> {
|
||||||
|
return this.strategy.deleteSavedSearch(deletedSavedSearch);
|
||||||
|
}
|
||||||
|
|
||||||
|
changeOrder(previousIndex: number, currentIndex: number): void {
|
||||||
|
this.strategy.changeOrder(previousIndex, currentIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import * as app from './app.rules';
|
import * as app from './app.rules';
|
||||||
import { createVersionRule, getFileExtension, isSavedSearchAvailable, isFolderInfoAvailable, isBulkActionsAvailable } from './app.rules';
|
import { createVersionRule, getFileExtension, isPreferencesApiAvailable, isFolderInfoAvailable, isBulkActionsAvailable } from './app.rules';
|
||||||
import { TestRuleContext } from './test-rule-context';
|
import { TestRuleContext } from './test-rule-context';
|
||||||
import { NodeEntry, RepositoryInfo, StatusInfo } from '@alfresco/js-api';
|
import { NodeEntry, RepositoryInfo, StatusInfo } from '@alfresco/js-api';
|
||||||
import { ProfileState, RuleContext } from '@alfresco/adf-extensions';
|
import { ProfileState, RuleContext } from '@alfresco/adf-extensions';
|
||||||
@@ -1219,24 +1219,24 @@ describe('Versions compatibility', () => {
|
|||||||
} as RuleContext;
|
} as RuleContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('isSavedSearchAvailable', () => {
|
describe('isPreferencesApiAvailable', () => {
|
||||||
it('should return true if ACS version is equal to minimal version', () => {
|
it('should return true if ACS version is equal to minimal version', () => {
|
||||||
expect(isSavedSearchAvailable(makeContext('25.1.0'))).toBe(true);
|
expect(isPreferencesApiAvailable(makeContext('25.1.0'))).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return true if ACS version is greater than minimal version', () => {
|
it('should return true if ACS version is greater than minimal version', () => {
|
||||||
expect(isSavedSearchAvailable(makeContext('25.2.0'))).toBe(true);
|
expect(isPreferencesApiAvailable(makeContext('25.2.0'))).toBe(true);
|
||||||
expect(isSavedSearchAvailable(makeContext('26.0.0'))).toBe(true);
|
expect(isPreferencesApiAvailable(makeContext('26.0.0'))).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return false if ACS version is less than minimal version', () => {
|
it('should return false if ACS version is less than minimal version', () => {
|
||||||
expect(isSavedSearchAvailable(makeContext('24.4.0'))).toBe(false);
|
expect(isPreferencesApiAvailable(makeContext('24.4.0'))).toBe(false);
|
||||||
expect(isSavedSearchAvailable(makeContext('25.0.9'))).toBe(false);
|
expect(isPreferencesApiAvailable(makeContext('25.0.9'))).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return false if ACS version is missing', () => {
|
it('should return false if ACS version is missing', () => {
|
||||||
expect(isSavedSearchAvailable(makeContext())).toBe(false);
|
expect(isPreferencesApiAvailable(makeContext())).toBe(false);
|
||||||
expect(isSavedSearchAvailable({ repository: {} } as any)).toBe(false);
|
expect(isPreferencesApiAvailable({ repository: {} } as any)).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -485,9 +485,9 @@ export function canOpenWithOffice(context: AcaRuleContext): boolean {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if user savedSearches are supported by current ACS version.
|
* Checks if user savedSearches are supported by current ACS version.
|
||||||
* JSON ref: `isSavedSearchAvailable`
|
* JSON ref: `isPreferencesApiAvailable`
|
||||||
*/
|
*/
|
||||||
export const isSavedSearchAvailable = createVersionRule('25.1.0');
|
export const isPreferencesApiAvailable = createVersionRule('25.1.0');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if folder info modal is supported by current ACS version.
|
* Checks if folder info modal is supported by current ACS version.
|
||||||
|
|||||||
Reference in New Issue
Block a user