diff --git a/projects/aca-content/assets/app.extensions.json b/projects/aca-content/assets/app.extensions.json index 9c0d7fff4d..51de285a05 100644 --- a/projects/aca-content/assets/app.extensions.json +++ b/projects/aca-content/assets/app.extensions.json @@ -1240,6 +1240,18 @@ "visible": "showInfoSelectionButton" } }, + { + "id": "app.toolbar.aspects", + "order": 160, + "title": "APP.ACTIONS.ADD_ASPECTS", + "icon": "playlist_add", + "actions": { + "click": "ASPECT_LIST" + }, + "rules": { + "visible": "canEditAspects" + } + }, { "id": "app.sidebar.expand", "order": 200, @@ -1249,7 +1261,7 @@ "click": "EXPAND_INFO_DRAWER" }, "rules": { - "visible": "app.navigation.isNotLibraries" + "visible": "canShowExpand" } } ], diff --git a/projects/aca-content/assets/i18n/en.json b/projects/aca-content/assets/i18n/en.json index bab98e67e3..faf977f981 100644 --- a/projects/aca-content/assets/i18n/en.json +++ b/projects/aca-content/assets/i18n/en.json @@ -259,7 +259,8 @@ "LEAVE": "Leave Library", "EDIT_OFFLINE": "Edit Offline", "EDIT_OFFLINE_CANCEL": "Cancel Editing", - "CHANGE_ASPECT": "Edit Aspects" + "CHANGE_ASPECT": "Edit Aspects", + "ADD_ASPECTS": "Add Aspects" }, "DIALOGS": { "CONFIRM_PURGE": { @@ -394,7 +395,7 @@ }, "INFO_DRAWER": { "TITLE": "Details", - "CLOSE": "Close", + "REDUCE_PANEL": "Reduce panel", "DATA_LOADING": "Data is loading", "TABS": { "PROPERTIES": "Properties", @@ -402,7 +403,7 @@ "VERSIONS": "Versions", "COMMENTS": "Comments", "PERMISSIONS": "Permissions", - "EXPAND": "Expand" + "EXPAND": "Expand panel" } }, "TOOLTIPS": { diff --git a/projects/aca-content/src/lib/aca-content.module.ts b/projects/aca-content/src/lib/aca-content.module.ts index 47dd3bc2f7..c0163de6c7 100644 --- a/projects/aca-content/src/lib/aca-content.module.ts +++ b/projects/aca-content/src/lib/aca-content.module.ts @@ -192,6 +192,7 @@ export class ContentServiceExtensionModule { canToggleFavorite: rules.canToggleFavorite, isLibraryManager: rules.isLibraryManager, canEditAspects: rules.canEditAspects, + canShowExpand: rules.canShowExpand, canInfoPreview: rules.canInfoPreview, showInfoSelectionButton: rules.showInfoSelectionButton, diff --git a/projects/aca-content/src/lib/components/details/details.component.html b/projects/aca-content/src/lib/components/details/details.component.html index 2d9dda876a..d2b2b752b5 100644 --- a/projects/aca-content/src/lib/components/details/details.component.html +++ b/projects/aca-content/src/lib/components/details/details.component.html @@ -12,14 +12,17 @@ - {{ 'APP.INFO_DRAWER.TITLE' | translate }} - +
+ + +
diff --git a/projects/aca-content/src/lib/components/details/details.component.scss b/projects/aca-content/src/lib/components/details/details.component.scss index 778bead773..4e76575e86 100644 --- a/projects/aca-content/src/lib/components/details/details.component.scss +++ b/projects/aca-content/src/lib/components/details/details.component.scss @@ -1,19 +1,29 @@ app-details-manager { - .aca-close-details-button { - margin-right: 15px; - margin-top: 2px; - outline: none; - border-radius: 4px; - - &:focus { - background-color: var(--theme-selected-background-color); - outline: 2px solid var(--theme-blue-button-color); - border-radius: 4px; - } + .acs-details-buttons { + display: flex; - &:focus-visible { - outline: 2px solid var(--theme-blue-button-color); + .aca-close-details-button { + margin-right: 15px; + margin-top: 12px; + outline: none; border-radius: 4px; + + &:focus { + background-color: var(--theme-selected-background-color); + outline: 2px solid var(--theme-blue-button-color); + border-radius: 4px; + } + + &:focus-visible { + outline: 2px solid var(--theme-blue-button-color); + border-radius: 4px; + margin-top: 12px; + + &:focus-visible { + outline: 2px solid var(--theme-blue-button-color); + border-radius: 4px; + } + } } } } diff --git a/projects/aca-content/src/lib/components/details/details.component.spec.ts b/projects/aca-content/src/lib/components/details/details.component.spec.ts index 0988ca7033..6911afef2e 100644 --- a/projects/aca-content/src/lib/components/details/details.component.spec.ts +++ b/projects/aca-content/src/lib/components/details/details.component.spec.ts @@ -26,7 +26,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { AppTestingModule } from '../../testing/app-testing.module'; import { DetailsComponent } from './details.component'; import { ActivatedRoute } from '@angular/router'; -import { of, Subject } from 'rxjs'; +import { BehaviorSubject, of, Subject } from 'rxjs'; import { NO_ERRORS_SCHEMA } from '@angular/core'; import { Store } from '@ngrx/store'; import { ContentApiService } from '@alfresco/aca-shared'; @@ -49,6 +49,15 @@ describe('DetailsComponent', () => { select: () => mockStream }; + const extensionsServiceMock = { + getAllowedSidebarActions: jasmine.createSpy('getAllowedSidebarActions') + }; + + const mockAspectActions = []; + + const mockObservable = new BehaviorSubject(mockAspectActions); + extensionsServiceMock.getAllowedSidebarActions.and.returnValue(mockObservable); + beforeEach(() => { TestBed.configureTestingModule({ imports: [AppTestingModule, DetailsComponent], @@ -128,4 +137,12 @@ describe('DetailsComponent', () => { fixture.detectChanges(); expect(store.dispatch).toHaveBeenCalledWith(new SetSelectedNodesAction([node])); }); + + it('should set aspectActions from extensions', () => { + extensionsServiceMock.getAllowedSidebarActions.and.returnValue(of(mockAspectActions)); + fixture.detectChanges(); + fixture.whenStable().then(() => { + expect(component.aspectActions).toEqual(mockAspectActions); + }); + }); }); diff --git a/projects/aca-content/src/lib/components/details/details.component.ts b/projects/aca-content/src/lib/components/details/details.component.ts index a025c0409c..07a364e846 100644 --- a/projects/aca-content/src/lib/components/details/details.component.ts +++ b/projects/aca-content/src/lib/components/details/details.component.ts @@ -36,6 +36,8 @@ import { MatProgressBarModule } from '@angular/material/progress-bar'; import { MatButtonModule } from '@angular/material/button'; import { MetadataTabComponent } from '../info-drawer/metadata-tab/metadata-tab.component'; import { CommentsTabComponent } from '../info-drawer/comments-tab/comments-tab.component'; +import { takeUntil } from 'rxjs/operators'; +import { ContentActionRef } from '@alfresco/adf-extensions'; @Component({ standalone: true, @@ -63,6 +65,7 @@ export class DetailsComponent extends PageComponent implements OnInit, OnDestroy isLoading: boolean; onDestroy$ = new Subject(); activeTab = 1; + aspectActions: Array = []; constructor(private route: ActivatedRoute, private contentApi: ContentApiService) { super(); @@ -85,6 +88,12 @@ export class DetailsComponent extends PageComponent implements OnInit, OnDestroy this.store.dispatch(new SetSelectedNodesAction([{ entry: this.node }])); }); }); + this.extensions + .getAllowedSidebarActions() + .pipe(takeUntil(this.onDestroy$)) + .subscribe((aspectActions) => { + this.aspectActions = aspectActions; + }); } setActiveTab(tabName: string) { diff --git a/projects/aca-content/src/lib/components/info-drawer/metadata-tab/metadata-tab.component.spec.ts b/projects/aca-content/src/lib/components/info-drawer/metadata-tab/metadata-tab.component.spec.ts index f990d7b3d5..4d01789afc 100644 --- a/projects/aca-content/src/lib/components/info-drawer/metadata-tab/metadata-tab.component.spec.ts +++ b/projects/aca-content/src/lib/components/info-drawer/metadata-tab/metadata-tab.component.spec.ts @@ -256,7 +256,7 @@ describe('MetadataTabComponent', () => { }); it('show pass empty when store is in initial state', () => { - const initialState = fixture.debugElement.query(By.css('adf-content-metadata-card')); + const initialState = fixture.debugElement.query(By.css('adf-content-metadata')); expect(initialState.componentInstance.displayAspect).toBeFalsy(); }); @@ -266,7 +266,7 @@ describe('MetadataTabComponent', () => { expect(aspect).toBe('EXIF'); }); fixture.detectChanges(); - const initialState = fixture.debugElement.query(By.css('adf-content-metadata-card')); + const initialState = fixture.debugElement.query(By.css('adf-content-metadata')); expect(initialState.componentInstance.displayAspect).toBe('EXIF'); }); }); diff --git a/projects/aca-content/src/lib/components/info-drawer/metadata-tab/metadata-tab.component.ts b/projects/aca-content/src/lib/components/info-drawer/metadata-tab/metadata-tab.component.ts index dfcaad995f..2a5654fae3 100644 --- a/projects/aca-content/src/lib/components/info-drawer/metadata-tab/metadata-tab.component.ts +++ b/projects/aca-content/src/lib/components/info-drawer/metadata-tab/metadata-tab.component.ts @@ -39,27 +39,36 @@ import { Actions, ofType } from '@ngrx/effects'; imports: [CommonModule, ContentMetadataModule], selector: 'app-metadata-tab', template: ` - - + `, encapsulation: ViewEncapsulation.None, host: { class: 'app-metadata-tab' } }) export class MetadataTabComponent implements OnInit, OnDestroy { protected onDestroy$ = new Subject(); - @Input() node: Node; displayAspect$: Observable; canUpdateNode = false; editable = false; + editableTags = false; + editableCategories = false; + group: any = { + editable: false + }; constructor( private permission: NodePermissionService, @@ -91,6 +100,9 @@ export class MetadataTabComponent implements OnInit, OnDestroy { this.checkIfNodeIsUpdatable(updatedNode?.payload.entry); if (!this.canUpdateNode) { this.editable = false; + this.editableTags = false; + this.editableCategories = false; + this.group.editable = false; } }); } diff --git a/projects/aca-content/src/lib/components/toolbar/toggle-edit-offline/toggle-edit-offline.component.spec.ts b/projects/aca-content/src/lib/components/toolbar/toggle-edit-offline/toggle-edit-offline.component.spec.ts index e061c2a599..c1dc90e3e8 100644 --- a/projects/aca-content/src/lib/components/toolbar/toggle-edit-offline/toggle-edit-offline.component.spec.ts +++ b/projects/aca-content/src/lib/components/toolbar/toggle-edit-offline/toggle-edit-offline.component.spec.ts @@ -29,6 +29,7 @@ import { Store } from '@ngrx/store'; import { NodeEntry } from '@alfresco/js-api'; import { DownloadNodesAction, EditOfflineAction, SnackbarErrorAction } from '@alfresco/aca-shared/store'; import { AppTestingModule } from '../../../testing/app-testing.module'; +import { AppExtensionService } from '@alfresco/aca-shared'; describe('ToggleEditOfflineComponent', () => { let fixture: ComponentFixture; @@ -38,6 +39,10 @@ describe('ToggleEditOfflineComponent', () => { let selectSpy: jasmine.Spy; let selection: any; + const extensionsMock = { + updateSidebarActions: jasmine.createSpy('updateSidebarActions') + }; + beforeEach(() => { TestBed.configureTestingModule({ imports: [AppTestingModule, ToggleEditOfflineComponent], @@ -48,6 +53,10 @@ describe('ToggleEditOfflineComponent', () => { select: () => {}, dispatch: () => {} } + }, + { + provide: AppExtensionService, + useValue: extensionsMock } ] }); @@ -133,4 +142,14 @@ describe('ToggleEditOfflineComponent', () => { }) ]); }); + + it('should call updateSidebarActions on click', async () => { + selectSpy.and.returnValue(of(selection)); + fixture.detectChanges(); + + await component.onClick(); + fixture.detectChanges(); + + expect(extensionsMock.updateSidebarActions).toHaveBeenCalled(); + }); }); diff --git a/projects/aca-content/src/lib/components/toolbar/toggle-edit-offline/toggle-edit-offline.component.ts b/projects/aca-content/src/lib/components/toolbar/toggle-edit-offline/toggle-edit-offline.component.ts index 2862777322..40410b94b5 100644 --- a/projects/aca-content/src/lib/components/toolbar/toggle-edit-offline/toggle-edit-offline.component.ts +++ b/projects/aca-content/src/lib/components/toolbar/toggle-edit-offline/toggle-edit-offline.component.ts @@ -33,7 +33,7 @@ import { import { NodeEntry, SharedLinkEntry, Node, NodesApi } from '@alfresco/js-api'; import { Component, OnInit, ViewEncapsulation } from '@angular/core'; import { Store } from '@ngrx/store'; -import { isLocked } from '@alfresco/aca-shared'; +import { AppExtensionService, isLocked } from '@alfresco/aca-shared'; import { AlfrescoApiService } from '@alfresco/adf-core'; import { CommonModule } from '@angular/common'; import { TranslateModule } from '@ngx-translate/core'; @@ -59,7 +59,7 @@ export class ToggleEditOfflineComponent implements OnInit { nodeTitle = ''; isNodeLocked = false; - constructor(private store: Store, private alfrescoApiService: AlfrescoApiService) { + constructor(private store: Store, private alfrescoApiService: AlfrescoApiService, private extensions: AppExtensionService) { this.nodesApi = new NodesApi(this.alfrescoApiService.getInstance()); } @@ -73,6 +73,7 @@ export class ToggleEditOfflineComponent implements OnInit { async onClick() { await this.toggleLock(this.selection); + this.extensions.updateSidebarActions(); } private async toggleLock(node: NodeEntry | SharedLinkEntry) { diff --git a/projects/aca-content/src/lib/ui/overrides/adf-style-fixes.theme.scss b/projects/aca-content/src/lib/ui/overrides/adf-style-fixes.theme.scss index 5a3514d2dd..0daf5ea047 100644 --- a/projects/aca-content/src/lib/ui/overrides/adf-style-fixes.theme.scss +++ b/projects/aca-content/src/lib/ui/overrides/adf-style-fixes.theme.scss @@ -12,3 +12,34 @@ } } } + +.adf-info-drawer-layout-content .app-metadata-tab .adf-metadata-properties .mat-expansion-panel { + border: 1px solid var(--theme-metadata-property-panel-border-color); + border-radius: 12px; + margin-bottom: 12px; + + .mat-expansion-panel-header { + border-radius: 12px; + } +} + +.acs-details-container { + .mat-tab-body-content { + .adf-metadata-properties { + .mat-expansion-panel { + width: 755px; + border: 1px solid var(--theme-metadata-property-panel-border-color); + margin: 24px; + border-radius: 12px; + + .mat-expansion-panel-header { + border-radius: 12px; + } + + .adf-metadata-properties-group-title { + width: 548px; + } + } + } + } +} diff --git a/projects/aca-content/src/lib/ui/variables/variables.scss b/projects/aca-content/src/lib/ui/variables/variables.scss index 8a11c08041..45bcc8ecd8 100644 --- a/projects/aca-content/src/lib/ui/variables/variables.scss +++ b/projects/aca-content/src/lib/ui/variables/variables.scss @@ -36,6 +36,9 @@ $page-layout-header-background-color: #fff; $search-chip-icon-color: #757575; $disabled-chip-background-color: #f5f5f5; $contrast-gray: #646569; +$metadata-property-panel-border-color: rgba(0, 0, 0, 0.12); +$metadata-buttons-background-color: rgba(33, 33, 33, 0.05); +$metadata-action-button-clear-color: #212328b2; // CSS Variables $defaults: ( @@ -76,7 +79,10 @@ $defaults: ( --theme-page-layout-header-background-color: $page-layout-header-background-color, --theme-search-chip-icon-color: $search-chip-icon-color, --theme-disabled-chip-background-color: $disabled-chip-background-color, - --theme-contrast-gray: $contrast-gray + --theme-contrast-gray: $contrast-gray, + --theme-metadata-property-panel-border-color: $metadata-property-panel-border-color, + --theme-metadata-buttons-background-color: $metadata-buttons-background-color, + --theme-metadata-action-button-clear-color: $metadata-action-button-clear-color ); // propagates SCSS variables into the CSS variables scope diff --git a/projects/aca-shared/rules/src/app.rules.spec.ts b/projects/aca-shared/rules/src/app.rules.spec.ts index 6e5d538d1f..68713f275e 100644 --- a/projects/aca-shared/rules/src/app.rules.spec.ts +++ b/projects/aca-shared/rules/src/app.rules.spec.ts @@ -121,6 +121,28 @@ describe('app.evaluators', () => { }); }); + describe('canShowExpand', () => { + it('should return false when isLibraries returns true', () => { + const context: any = { + navigation: { + url: '/libraries' + } + }; + + expect(app.canShowExpand(context)).toBe(false); + }); + + it('should return false when isDetails returns true', () => { + const context: any = { + navigation: { + url: '/details' + } + }; + + expect(app.canShowExpand(context)).toBe(false); + }); + }); + describe('hasLockedFiles', () => { it('should return [false] if selection not present', () => { const context: any = {}; diff --git a/projects/aca-shared/rules/src/app.rules.ts b/projects/aca-shared/rules/src/app.rules.ts index 71333f4bc6..bf06469f2d 100644 --- a/projects/aca-shared/rules/src/app.rules.ts +++ b/projects/aca-shared/rules/src/app.rules.ts @@ -511,6 +511,8 @@ export const canEditAspects = (context: RuleContext): boolean => repository.isMajorVersionAvailable(context, '7') ].every(Boolean); +export const canShowExpand = (context: RuleContext): boolean => [!navigation.isLibraries(context), !navigation.isDetails(context)].every(Boolean); + /** * Checks if user can manage permissions for the selected node. * JSON ref: `canManagePermissions` diff --git a/projects/aca-shared/rules/src/navigation.rules.spec.ts b/projects/aca-shared/rules/src/navigation.rules.spec.ts index b0cae7b299..9582223e44 100644 --- a/projects/aca-shared/rules/src/navigation.rules.spec.ts +++ b/projects/aca-shared/rules/src/navigation.rules.spec.ts @@ -225,6 +225,28 @@ describe('navigation.evaluators', () => { }); }); + describe('isDetails', () => { + it('should return true if url includes with `/details`', () => { + const context: any = { + navigation: { + url: '/details/path' + } + }; + + expect(app.isDetails(context)).toBe(true); + }); + + it('should return false if url not includes with `/details`', () => { + const context: any = { + navigation: { + url: '/path' + } + }; + + expect(app.isDetails(context)).toBe(false); + }); + }); + describe('isRecentFiles', () => { it('should return [true] if url starts with `/recent-files`', () => { const context: any = { diff --git a/projects/aca-shared/rules/src/navigation.rules.ts b/projects/aca-shared/rules/src/navigation.rules.ts index 02d6a6df93..a26d8a2366 100644 --- a/projects/aca-shared/rules/src/navigation.rules.ts +++ b/projects/aca-shared/rules/src/navigation.rules.ts @@ -110,6 +110,11 @@ export function isLibraryContent(context: RuleContext): boolean { return url && (url.endsWith('/libraries') || url.includes('/libraries/') || url.startsWith('/search-libraries')); } +export function isDetails(context: RuleContext): boolean { + const { url } = context.navigation; + return url?.includes('/details'); +} + /** * Checks if the activated route is neither **Libraries** nor **Library Search Results**. * JSON ref: `app.navigation.isNotLibraries` diff --git a/projects/aca-shared/src/lib/services/app.extension.service.ts b/projects/aca-shared/src/lib/services/app.extension.service.ts index 393c0339e7..0677bd9ad2 100644 --- a/projects/aca-shared/src/lib/services/app.extension.service.ts +++ b/projects/aca-shared/src/lib/services/app.extension.service.ts @@ -348,6 +348,10 @@ export class AppExtensionService implements RuleContext { }; } + updateSidebarActions() { + this._sidebarActions.next(this.loader.getContentActions(this.config, 'features.sidebar.toolbar')); + } + getCreateActions(): Observable> { return this._createActions.pipe( map((createActions) =>