[ACS-8746] use notification service instead of store, yellow warnings, warning on no library permission (#4577)

* [ACS-8746] use notification service instead of store, yellow warnings, warning on no library permissions

* [ACS-8746] move snackbar bg styling to app level, review comments

* [ACS-8746] change warning color for improved accessibility

* [ACS-8746] fix wrong css class for copy and move notifications

* [ACS-8746] completely replace SnackbarActions with notifications service, update warning color

* [ACS-8746] improve copy and move nodes notifications

* ACS-8746 fix undo delete notification action

* ACS-8746 review comments

* ACS-8746 review comments
This commit is contained in:
Grzegorz Jaśkowski
2025-06-16 10:14:27 +02:00
committed by GitHub
parent 1072c7d2f3
commit f48fc8c2d7
45 changed files with 476 additions and 786 deletions

View File

@@ -1,78 +0,0 @@
/*!
* 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 { Action } from '@ngrx/store';
export enum SnackbarActionTypes {
Info = 'SNACKBAR_INFO',
Warning = 'SNACKBAR_WARNING',
Error = 'SNACKBAR_ERROR'
}
export interface SnackbarAction extends Action {
payload: string;
params?: any;
userAction?: SnackbarUserAction;
duration?: number;
}
export class SnackbarUserAction {
constructor(
public title: string,
public action: Action
) {}
}
export class SnackbarInfoAction implements SnackbarAction {
readonly type = SnackbarActionTypes.Info;
userAction?: SnackbarUserAction;
constructor(
public payload: string,
public params?: any
) {}
}
export class SnackbarWarningAction implements SnackbarAction {
readonly type = SnackbarActionTypes.Warning;
userAction?: SnackbarUserAction;
constructor(
public payload: string,
public params?: any
) {}
}
export class SnackbarErrorAction implements SnackbarAction {
readonly type = SnackbarActionTypes.Error;
userAction?: SnackbarUserAction;
constructor(
public payload: string,
public params?: any
) {}
}

View File

@@ -1,98 +0,0 @@
/*!
* 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 { EffectsModule } from '@ngrx/effects';
import { Store, StoreModule } from '@ngrx/store';
import { MatSnackBar } from '@angular/material/snack-bar';
import { CoreTestingModule, SnackbarContentComponent } from '@alfresco/adf-core';
import { SnackbarEffects } from './snackbar.effects';
import { SnackbarErrorAction, SnackbarInfoAction, SnackbarWarningAction } from '../actions/snackbar.actions';
import { AppStore } from '@alfresco/aca-shared/store';
describe('NodeEffects', () => {
let store: Store<AppStore>;
let matSnackBar: MatSnackBar;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [CoreTestingModule, StoreModule.forRoot({}), EffectsModule.forRoot([SnackbarEffects])]
});
store = TestBed.inject(Store);
matSnackBar = TestBed.inject(MatSnackBar);
spyOn(matSnackBar, 'openFromComponent');
});
describe('infoEffect', () => {
it('should open snackbar with adf-info-snackbar panel class', () => {
store.dispatch(new SnackbarInfoAction('test-snackbar-message'));
expect(matSnackBar.openFromComponent).toHaveBeenCalledWith(SnackbarContentComponent, {
panelClass: 'adf-info-snackbar',
data: {
message: 'test-snackbar-message',
actionLabel: null,
actionIcon: 'close',
actionIconAriaLabel: 'CLOSE',
showAction: true,
callActionOnIconClick: false
}
});
});
});
describe('warningEffect', () => {
it('should open snackbar with adf-info-snackbar panel class', () => {
store.dispatch(new SnackbarWarningAction('test-snackbar-message'));
expect(matSnackBar.openFromComponent).toHaveBeenCalledWith(SnackbarContentComponent, {
panelClass: 'adf-warning-snackbar',
data: {
message: 'test-snackbar-message',
actionLabel: null,
actionIcon: 'close',
actionIconAriaLabel: 'CLOSE',
showAction: true,
callActionOnIconClick: false
}
});
});
});
describe('errorEffect', () => {
it('should open snackbar with adf-info-snackbar panel class', () => {
store.dispatch(new SnackbarErrorAction('test-snackbar-message'));
expect(matSnackBar.openFromComponent).toHaveBeenCalledWith(SnackbarContentComponent, {
panelClass: 'adf-error-snackbar',
data: {
message: 'test-snackbar-message',
actionLabel: null,
actionIcon: 'close',
actionIconAriaLabel: 'CLOSE',
showAction: true,
callActionOnIconClick: false
}
});
});
});
});

View File

@@ -1,104 +0,0 @@
/*!
* 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 { SnackbarContentComponent, SnackBarData, TranslationService } from '@alfresco/adf-core';
import { inject, Injectable } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { Store } from '@ngrx/store';
import { map } from 'rxjs/operators';
import { AppStore } from '../states/app.state';
import { SnackbarAction, SnackbarActionTypes, SnackbarErrorAction, SnackbarInfoAction, SnackbarWarningAction } from '../actions/snackbar.actions';
@Injectable()
export class SnackbarEffects {
private store = inject(Store<AppStore>);
private actions$ = inject(Actions);
private snackBar = inject(MatSnackBar);
private translationService = inject(TranslationService);
infoEffect = createEffect(
() =>
this.actions$.pipe(
ofType<SnackbarInfoAction>(SnackbarActionTypes.Info),
map((action: SnackbarInfoAction) => {
this.showSnackBar(action, 'adf-info-snackbar');
})
),
{ dispatch: false }
);
warningEffect = createEffect(
() =>
this.actions$.pipe(
ofType<SnackbarWarningAction>(SnackbarActionTypes.Warning),
map((action: SnackbarWarningAction) => {
this.showSnackBar(action, 'adf-warning-snackbar');
})
),
{ dispatch: false }
);
errorEffect = createEffect(
() =>
this.actions$.pipe(
ofType<SnackbarErrorAction>(SnackbarActionTypes.Error),
map((action: SnackbarErrorAction) => {
this.showSnackBar(action, 'adf-error-snackbar');
})
),
{ dispatch: false }
);
private showSnackBar(action: SnackbarAction, panelClass: string) {
const message = this.translate(action.payload, action.params);
let actionName: string = null;
if (action.userAction) {
actionName = this.translate(action.userAction.title);
}
const snackBarRef = this.snackBar.openFromComponent<SnackbarContentComponent, SnackBarData>(SnackbarContentComponent, {
...(action.duration !== undefined && action.duration !== null && { duration: action.duration }),
panelClass,
data: {
message,
actionLabel: actionName,
actionIcon: 'close',
actionIconAriaLabel: 'CLOSE',
showAction: true,
callActionOnIconClick: false
}
});
if (action.userAction) {
snackBarRef.onAction().subscribe(() => {
this.store.dispatch(action.userAction.action);
});
}
}
private translate(message: string, params?: any): string {
return this.translationService.instant(message, params);
}
}

View File

@@ -31,7 +31,6 @@ export * from './actions/library.actions';
export * from './actions/node.actions';
export * from './actions/router.actions';
export * from './actions/search.actions';
export * from './actions/snackbar.actions';
export * from './actions/upload.actions';
export * from './actions/viewer.actions';
export * from './actions/metadata-aspect.actions';
@@ -40,7 +39,6 @@ export * from './actions/contextmenu.actions';
export * from './actions/search-ai.actions';
export * from './effects/router.effects';
export * from './effects/snackbar.effects';
export * from './models/ai-search-by-term-payload';
export * from './models/delete-status.model';