mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2026-09-16 18:13:06 +00:00
Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77960e37ad | ||
|
|
3d6ac31eb0 | ||
|
|
f190795c48 | ||
|
|
b208f2e688 | ||
|
|
7e13faf645 | ||
|
|
b4e541161d | ||
|
|
1119d7f135 | ||
|
|
75d7e98dff | ||
|
|
12e98b9371 | ||
|
|
d9e3a903d1 | ||
|
|
4dbed99fd8 | ||
|
|
0a4b316c9b |
+18
-32
@@ -1,8 +1,17 @@
|
||||
<div class="adf-categories-management">
|
||||
<p *ngIf="!categories.length && !categoryNameControlVisible"
|
||||
class="adf-no-categories-message">
|
||||
{{ noCategoriesMsg | translate }}
|
||||
</p>
|
||||
<div
|
||||
class="adf-category-name-field">
|
||||
<input #categoryNameInput
|
||||
matInput
|
||||
autocomplete="off"
|
||||
[formControl]="categoryNameControl"
|
||||
(keyup.enter)="addCategory()"
|
||||
aria-labelledby="adf-category-name-input-label"
|
||||
placeholder="{{'CATEGORIES_MANAGEMENT.INPUT_PLACEHOLDER' | translate }}"
|
||||
adf-auto-focus />
|
||||
<mat-error [hidden]="!categoryNameControl.invalid">{{ categoryNameErrorMessageKey | translate }}</mat-error>
|
||||
</div>
|
||||
|
||||
<div class="adf-categories-list"
|
||||
[class.adf-categories-list-fixed]="!categoryNameControlVisible">
|
||||
<span
|
||||
@@ -21,33 +30,10 @@
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
<div *ngIf="((!categoryNameControlVisible && categories.length)) || categoryNameControlVisible"
|
||||
[hidden]="!categoryNameControlVisible"
|
||||
class="adf-category-name-field">
|
||||
<mat-form-field>
|
||||
<mat-icon matPrefix>search</mat-icon>
|
||||
<mat-label id="adf-category-name-input-label">
|
||||
{{ 'CATEGORIES_MANAGEMENT.NAME' | translate }}
|
||||
</mat-label>
|
||||
<input
|
||||
#categoryNameInput
|
||||
matInput
|
||||
autocomplete="off"
|
||||
[formControl]="categoryNameControl"
|
||||
(keyup.enter)="addCategory()"
|
||||
aria-labelledby="adf-category-name-input-label"
|
||||
adf-auto-focus
|
||||
/>
|
||||
<mat-error [hidden]="!categoryNameControl.invalid">{{ categoryNameErrorMessageKey | translate }}</mat-error>
|
||||
</mat-form-field>
|
||||
<button
|
||||
mat-icon-button
|
||||
[class.adf-btn-padded]="!isCRUDMode"
|
||||
(click)="hideNameInput()"
|
||||
[attr.title]="'CATEGORIES_MANAGEMENT.HIDE_INPUT' | translate">
|
||||
<mat-icon>remove</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<p *ngIf="!categories.length && !categoryNameControlVisible"
|
||||
class="adf-no-categories-message">
|
||||
{{ noCategoriesMsg | translate }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="adf-existing-categories-panel" *ngIf="existingCategoriesPanelVisible">
|
||||
<ng-container *ngIf="isCRUDMode && (!existingCategoriesLoading || existingCategories)">
|
||||
@@ -57,7 +43,7 @@
|
||||
{{ 'CATEGORIES_MANAGEMENT.GENERIC_CREATE' | translate : { name: categoryNameControl.value } }}
|
||||
</span>
|
||||
</ng-container>
|
||||
<div *ngIf="categoryNameControlVisible" class="adf-categories-list">
|
||||
<div class="adf-categories-list">
|
||||
<ng-container *ngIf="!existingCategoriesLoading && existingCategories">
|
||||
<p class="adf-existing-categories-label">
|
||||
{{ existingCategoriesMsg | translate }}
|
||||
|
||||
+7
-1
@@ -1,8 +1,15 @@
|
||||
.adf-categories-management {
|
||||
padding-top: 12px;
|
||||
|
||||
.adf-category-name-field {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
background: var(--adf-metadata-tags-background-color);
|
||||
height: 32px;
|
||||
border-radius: 12px;
|
||||
align-items: center;
|
||||
padding: 0 12px;
|
||||
|
||||
mat-form-field {
|
||||
width: 100%;
|
||||
@@ -34,7 +41,6 @@
|
||||
}
|
||||
|
||||
.adf-categories-list {
|
||||
padding-bottom: 10px;
|
||||
|
||||
.mat-list-base .mat-list-item,
|
||||
.mat-list-base .mat-list-option {
|
||||
|
||||
+11
-29
@@ -167,38 +167,11 @@ describe('CategoriesManagementComponent', () => {
|
||||
component.categoryNameControlVisible = true;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
it('should be hidden initially', () => {
|
||||
component.categoryNameControlVisible = false;
|
||||
fixture.detectChanges();
|
||||
const categoryControl: HTMLDivElement = fixture.debugElement.query(By.css('.adf-category-name-field')).nativeElement;
|
||||
expect(categoryControl.hidden).toBeTrue();
|
||||
});
|
||||
|
||||
it('should be visible when categoryNameControlVisible is true', () => {
|
||||
const categoryControl = fixture.debugElement.query(By.css('.adf-category-name-field'));
|
||||
expect(categoryControl).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should have correct label and hide button', () => {
|
||||
const categoryControlLabel = fixture.debugElement.query(By.css('#adf-category-name-input-label')).nativeElement;
|
||||
const categoryControlHideBtn: HTMLButtonElement = fixture.debugElement.query(By.css('.adf-category-name-field button')).nativeElement;
|
||||
expect(categoryControlHideBtn).toBeTruthy();
|
||||
expect(categoryControlHideBtn.attributes.getNamedItem('title').textContent.trim()).toBe('CATEGORIES_MANAGEMENT.HIDE_INPUT');
|
||||
expect(categoryControlLabel.textContent.trim()).toBe('CATEGORIES_MANAGEMENT.NAME');
|
||||
});
|
||||
|
||||
it('should hide category control and existing categories panel on clicking hide button', () => {
|
||||
const categoryControlHideBtn: HTMLButtonElement = fixture.debugElement.query(By.css('.adf-category-name-field button')).nativeElement;
|
||||
const controlVisibilityChangeSpy = spyOn(component.categoryNameControlVisibleChange, 'emit').and.callThrough();
|
||||
categoryControlHideBtn.click();
|
||||
fixture.detectChanges();
|
||||
|
||||
const categoryControl: HTMLDivElement = fixture.debugElement.query(By.css('.adf-category-name-field')).nativeElement;
|
||||
expect(categoryControl.hidden).toBeTrue();
|
||||
expect(component.categoryNameControlVisible).toBeFalse();
|
||||
expect(component.existingCategoriesPanelVisible).toBeFalse();
|
||||
expect(controlVisibilityChangeSpy).toHaveBeenCalledOnceWith(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Spinner', () => {
|
||||
@@ -415,9 +388,7 @@ describe('CategoriesManagementComponent', () => {
|
||||
it('should clear and hide input after category is created', fakeAsync(() => {
|
||||
const controlVisibilityChangeSpy = spyOn(component.categoryNameControlVisibleChange, 'emit');
|
||||
createCategory('test');
|
||||
const categoryControl: HTMLDivElement = fixture.debugElement.query(By.css('.adf-category-name-field')).nativeElement;
|
||||
|
||||
expect(categoryControl.hidden).toBeTrue();
|
||||
expect(controlVisibilityChangeSpy).toHaveBeenCalledOnceWith(false);
|
||||
expect(getExistingCategoriesList()).toEqual([]);
|
||||
expect(component.categoryNameControl.value).toBe('');
|
||||
@@ -484,4 +455,15 @@ describe('CategoriesManagementComponent', () => {
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
it('should remove a category', fakeAsync(() => {
|
||||
component.managementMode = CategoriesManagementMode.ASSIGN;
|
||||
const categoryToRemove: Category = { id: 'catToRemove', name: 'Category to Remove' };
|
||||
component.categories = [categoryToRemove];
|
||||
component['_existingCategories'] = [];
|
||||
component.initialCategories = [];
|
||||
component.removeCategoryTitle = 'Remove Category';
|
||||
component.removeCategory(categoryToRemove);
|
||||
expect(component.categories.length).toBe(0);
|
||||
}));
|
||||
});
|
||||
|
||||
-2
@@ -83,9 +83,7 @@ export class CategoriesManagementComponent implements OnInit, OnDestroy {
|
||||
set categoryNameControlVisible(categoryNameControlVisible: boolean) {
|
||||
this._categoryNameControlVisible = categoryNameControlVisible;
|
||||
if (categoryNameControlVisible) {
|
||||
setTimeout(() => {
|
||||
this.categoryNameInputElement.nativeElement.scrollIntoView();
|
||||
});
|
||||
this._existingCategoriesPanelVisible = true;
|
||||
} else {
|
||||
this._existingCategoriesPanelVisible = false;
|
||||
|
||||
-18
@@ -23,24 +23,6 @@
|
||||
data-automation-id="meta-data-card-edit-aspect">
|
||||
<mat-icon>menu</mat-icon>
|
||||
</button>
|
||||
<button *ngIf="!readOnly && hasAllowableOperations()"
|
||||
mat-icon-button
|
||||
(click)="toggleEdit()"
|
||||
[attr.title]="'CORE.METADATA.ACTIONS.EDIT' | translate"
|
||||
[attr.aria-label]="'CORE.METADATA.ACCESSIBILITY.EDIT' | translate"
|
||||
data-automation-id="meta-data-card-toggle-edit">
|
||||
<mat-icon>mode_edit</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<button *ngIf="displayDefaultProperties" mat-button (click)="toggleExpanded()" data-automation-id="meta-data-card-toggle-expand">
|
||||
<ng-container *ngIf="!expanded">
|
||||
<span data-automation-id="meta-data-card-toggle-expand-label">{{ 'ADF_VIEWER.SIDEBAR.METADATA.MORE_INFORMATION' | translate }}</span>
|
||||
<mat-icon>keyboard_arrow_down</mat-icon>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="expanded">
|
||||
<span data-automation-id="meta-data-card-toggle-expand-label">{{ 'ADF_VIEWER.SIDEBAR.METADATA.LESS_INFORMATION' | translate }}</span>
|
||||
<mat-icon>keyboard_arrow_up</mat-icon>
|
||||
</ng-container>
|
||||
</button>
|
||||
</mat-card-footer>
|
||||
</mat-card>
|
||||
|
||||
-66
@@ -145,72 +145,6 @@ describe('ContentMetadataCardComponent', () => {
|
||||
expect(contentMetadataComponent).toBeNull();
|
||||
});
|
||||
|
||||
it('should toggle editable by clicking on the button', () => {
|
||||
component.editable = true;
|
||||
component.node.allowableOperations = [AllowableOperationsEnum.UPDATE];
|
||||
fixture.detectChanges();
|
||||
|
||||
const button = fixture.debugElement.query(By.css('[data-automation-id="meta-data-card-toggle-edit"]'));
|
||||
button.triggerEventHandler('click', {});
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.editable).toBe(false);
|
||||
});
|
||||
|
||||
it('should toggle expanded by clicking on the button', () => {
|
||||
component.expanded = true;
|
||||
fixture.detectChanges();
|
||||
|
||||
const button = fixture.debugElement.query(By.css('[data-automation-id="meta-data-card-toggle-expand"]'));
|
||||
button.triggerEventHandler('click', {});
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.expanded).toBe(false);
|
||||
});
|
||||
|
||||
it('should have the proper text on button while collapsed', () => {
|
||||
component.expanded = false;
|
||||
fixture.detectChanges();
|
||||
|
||||
const buttonLabel = fixture.debugElement.query(By.css('[data-automation-id="meta-data-card-toggle-expand-label"]'));
|
||||
|
||||
expect(buttonLabel.nativeElement.innerText.trim()).toBe('ADF_VIEWER.SIDEBAR.METADATA.MORE_INFORMATION');
|
||||
});
|
||||
|
||||
it('should have the proper text on button while collapsed', () => {
|
||||
component.expanded = true;
|
||||
fixture.detectChanges();
|
||||
|
||||
const buttonLabel = fixture.debugElement.query(By.css('[data-automation-id="meta-data-card-toggle-expand-label"]'));
|
||||
|
||||
expect(buttonLabel.nativeElement.innerText.trim()).toBe('ADF_VIEWER.SIDEBAR.METADATA.LESS_INFORMATION');
|
||||
});
|
||||
|
||||
it('should hide the edit button in readOnly is true', () => {
|
||||
component.readOnly = true;
|
||||
fixture.detectChanges();
|
||||
|
||||
const button = fixture.debugElement.query(By.css('[data-automation-id="meta-data-card-toggle-edit"]'));
|
||||
expect(button).toBeNull();
|
||||
});
|
||||
|
||||
it('should hide the edit button if node does not have `update` permissions', () => {
|
||||
component.readOnly = false;
|
||||
component.node.allowableOperations = null;
|
||||
fixture.detectChanges();
|
||||
|
||||
const button = fixture.debugElement.query(By.css('[data-automation-id="meta-data-card-toggle-edit"]'));
|
||||
expect(button).toBeNull();
|
||||
});
|
||||
|
||||
it('should show the edit button if node does has `update` permissions', () => {
|
||||
component.readOnly = false;
|
||||
component.node.allowableOperations = [AllowableOperationsEnum.UPDATE];
|
||||
fixture.detectChanges();
|
||||
|
||||
const button = fixture.debugElement.query(By.css('[data-automation-id="meta-data-card-toggle-edit"]'));
|
||||
expect(button).not.toBeNull();
|
||||
});
|
||||
|
||||
it('should expand the card when custom display aspect is valid', () => {
|
||||
expect(component.expanded).toBeFalsy();
|
||||
|
||||
-8
@@ -109,14 +109,6 @@ export class ContentMetadataCardComponent implements OnChanges {
|
||||
this.expanded = !this._displayDefaultProperties;
|
||||
}
|
||||
|
||||
toggleEdit(): void {
|
||||
this.editable = !this.editable;
|
||||
}
|
||||
|
||||
toggleExpanded(): void {
|
||||
this.expanded = !this.expanded;
|
||||
}
|
||||
|
||||
hasAllowableOperations() {
|
||||
return this.contentService.hasAllowableOperations(this.node, AllowableOperationsEnum.UPDATE);
|
||||
}
|
||||
|
||||
+148
-108
@@ -1,131 +1,171 @@
|
||||
<div class="adf-metadata-properties">
|
||||
<mat-accordion displayMode="flat"
|
||||
[multi]="multi">
|
||||
<mat-expansion-panel *ngIf="displayDefaultProperties"
|
||||
[expanded]="canExpandProperties()"
|
||||
[attr.data-automation-id]="'adf-metadata-group-properties'">
|
||||
<mat-accordion displayMode="flat" [multi]="multi">
|
||||
<mat-expansion-panel *ngIf="displayDefaultProperties" [expanded]="true"
|
||||
[attr.data-automation-id]="'adf-metadata-group-properties'" (opened)="generalInfoPanelState = true"
|
||||
(closed)="generalInfoPanelState = false" hideToggle>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title class="adf-metadata-properties-title">
|
||||
{{ 'CORE.METADATA.BASIC.HEADER' | translate }}
|
||||
</mat-panel-title>
|
||||
<div class="adf-toggle-icons">
|
||||
<mat-icon>
|
||||
{{ generalInfoPanelState ? 'expand_more' : 'chevron_right'}}</mat-icon>
|
||||
<mat-panel-title class="adf-metadata-properties-title">
|
||||
{{ 'CORE.METADATA.HEADER_TITLE' | translate }}
|
||||
</mat-panel-title>
|
||||
</div>
|
||||
<button *ngIf="!editableGeneralInfo" mat-icon-button (click)="toggleGeneralEdit($event)"
|
||||
[attr.title]="'CORE.METADATA.ACTIONS.EDIT' | translate"
|
||||
[attr.aria-label]="'CORE.METADATA.ACCESSIBILITY.EDIT' | translate"
|
||||
data-automation-id="meta-data-card-toggle-generalInfo-edit" class="adf-edit-icon-buttons">
|
||||
<mat-icon>mode_edit</mat-icon>
|
||||
</button>
|
||||
<div class="adf-metadata-action-buttons" *ngIf="editableGeneralInfo">
|
||||
<button mat-icon-button (click)="cancelGeneralInfoChanges($event)"
|
||||
data-automation-id="reset-metadata">
|
||||
<mat-icon>clear</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button (click)="saveGeneralInfoChanges($event)" color="primary"
|
||||
data-automation-id="save-generalInfo-metadata" [disabled]="!hasMetadataChanged">
|
||||
<mat-icon>check</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</mat-expansion-panel-header>
|
||||
<adf-card-view
|
||||
(keydown)="keyDown($event)"
|
||||
[properties]="basicProperties$ | async"
|
||||
[editable]="editable"
|
||||
[displayEmpty]="displayEmpty"
|
||||
<mat-divider class="adf-mat-divider"></mat-divider>
|
||||
<adf-card-view (keydown)="keyDown($event)" [properties]="basicProperties$ | async"
|
||||
[editableGeneralInfo]="editableGeneralInfo" [displayEmpty]="displayEmpty"
|
||||
[copyToClipboardAction]="copyToClipboardAction"
|
||||
[useChipsForMultiValueProperty]="useChipsForMultiValueProperty"
|
||||
[multiValueSeparator]="multiValueSeparator">
|
||||
</adf-card-view>
|
||||
</mat-expansion-panel>
|
||||
<ng-container *ngIf="displayTags">
|
||||
<mat-expansion-panel *ngIf="!editable">
|
||||
<mat-expansion-panel (opened)="tagsPanelState = true" (closed)="tagsPanelState = false" hideToggle
|
||||
[expanded]="tagsPanelState">
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>{{ 'METADATA.BASIC.TAGS' | translate }}</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
<p *ngFor="let tag of tags" class="adf-metadata-properties-tag">{{ tag }}</p>
|
||||
</mat-expansion-panel>
|
||||
<div
|
||||
*ngIf="editable"
|
||||
class="adf-metadata-properties-tags">
|
||||
<div class="adf-metadata-properties-tags-title">
|
||||
<p>{{ 'METADATA.BASIC.TAGS' | translate }}</p>
|
||||
<button
|
||||
data-automation-id="showing-tag-input-button"
|
||||
mat-icon-button
|
||||
[attr.title]="'METADATA.BASIC.ADD_TAG_TOOLTIP' | translate"
|
||||
(click)="tagNameControlVisible = true"
|
||||
[hidden]="tagNameControlVisible || saving">
|
||||
<mat-icon>add</mat-icon>
|
||||
<div class="adf-toggle-icons">
|
||||
<mat-icon>
|
||||
{{ tagsPanelState ? 'expand_more' : 'chevron_right'}}</mat-icon>
|
||||
<mat-panel-title class="adf-metadata-properties-title">{{ 'METADATA.BASIC.TAGS' | translate
|
||||
}}</mat-panel-title>
|
||||
</div>
|
||||
<button *ngIf="!editableTags" mat-icon-button (click)="toggleTagsEdit($event)"
|
||||
[attr.title]="'CORE.METADATA.ACTIONS.EDIT' | translate"
|
||||
[attr.aria-label]="'CORE.METADATA.ACCESSIBILITY.EDIT' | translate"
|
||||
data-automation-id="meta-data-card-toggle-tags-edit" class="adf-edit-icon-buttons">
|
||||
<mat-icon>mode_edit</mat-icon>
|
||||
</button>
|
||||
<div class="adf-metadata-action-buttons" *ngIf="editableTags">
|
||||
<button mat-icon-button (click)="CancelTagsChanges($event)" data-automation-id="reset-metadata">
|
||||
<mat-icon>clear</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button (click)="saveTagsChanges($event)" color="primary"
|
||||
data-automation-id="save-tags-metadata" [disabled]="!hasMetadataChanged">
|
||||
<mat-icon>check</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</mat-expansion-panel-header>
|
||||
<mat-divider class="adf-mat-divider"></mat-divider>
|
||||
<div *ngIf="!editableTags">
|
||||
<span *ngFor="let tag of tags" class="adf-metadata-properties-tag">{{ tag }}</span>
|
||||
</div>
|
||||
<adf-tags-creator
|
||||
[(tagNameControlVisible)]="tagNameControlVisible"
|
||||
(tagsChange)="storeTagsToAssign($event)"
|
||||
[mode]="tagsCreatorMode"
|
||||
[tags]="assignedTags"
|
||||
[disabledTagsRemoving]="saving">
|
||||
</adf-tags-creator>
|
||||
</div>
|
||||
<div *ngIf="!tags.length && !editableTags" class="adf-metadata-no-tags-added">
|
||||
{{ 'METADATA.BASIC.NO_TAGS_ADDED' | translate }}
|
||||
</div>
|
||||
<div *ngIf="editableTags" class="adf-metadata-properties-tags">
|
||||
<adf-tags-creator [(tagNameControlVisible)]="tagNameControlVisible"
|
||||
(tagsChange)="storeTagsToAssign($event)" [mode]="tagsCreatorMode" [tags]="assignedTags"
|
||||
[disabledTagsRemoving]="saving">
|
||||
</adf-tags-creator>
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="displayCategories">
|
||||
<mat-expansion-panel *ngIf="!editable">
|
||||
<mat-expansion-panel (opened)="categoriesPanelState = true" (closed)="categoriesPanelState = false"
|
||||
hideToggle [expanded]="categoriesPanelState">
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>{{ 'CATEGORIES_MANAGEMENT.CATEGORIES_TITLE' | translate }}</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
<p *ngFor="let category of categories" class="adf-metadata-categories">{{ category.name }}</p>
|
||||
</mat-expansion-panel>
|
||||
<div *ngIf="editable"
|
||||
class="adf-metadata-categories-header">
|
||||
<div class="adf-metadata-categories-title">
|
||||
<p>{{ 'CATEGORIES_MANAGEMENT.CATEGORIES_TITLE' | translate }}</p>
|
||||
<button
|
||||
mat-icon-button
|
||||
[attr.title]="'CATEGORIES_MANAGEMENT.ASSIGN_CATEGORIES' | translate"
|
||||
[hidden]="categoryControlVisible || saving"
|
||||
(click)="categoryControlVisible = true">
|
||||
<mat-icon>add</mat-icon>
|
||||
<div class="adf-toggle-icons">
|
||||
<mat-icon>
|
||||
{{ categoriesPanelState ? 'expand_more' : 'chevron_right'}}</mat-icon>
|
||||
<mat-panel-title class="adf-metadata-properties-title">{{
|
||||
'CATEGORIES_MANAGEMENT.CATEGORIES_TITLE' |
|
||||
translate }}</mat-panel-title>
|
||||
</div>
|
||||
<button *ngIf="!editableCategories" mat-icon-button (click)="toggleCategoriesEdit($event)"
|
||||
[attr.title]="'CORE.METADATA.ACTIONS.EDIT' | translate"
|
||||
[attr.aria-label]="'CORE.METADATA.ACCESSIBILITY.EDIT' | translate"
|
||||
data-automation-id="meta-data-card-toggle-categoeies-edit" class="adf-edit-icon-buttons">
|
||||
<mat-icon>mode_edit</mat-icon>
|
||||
</button>
|
||||
<div class="adf-metadata-action-buttons" *ngIf="editableCategories">
|
||||
<button mat-icon-button (click)="cancelCategoriesChanges($event)"
|
||||
data-automation-id="reset-metadata">
|
||||
<mat-icon>clear</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button (click)="saveCategoriesChanges($event)" color="primary"
|
||||
data-automation-id="save-categories-metadata" [disabled]="!hasMetadataChanged">
|
||||
<mat-icon>check</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</mat-expansion-panel-header>
|
||||
<mat-divider class="adf-mat-divider"></mat-divider>
|
||||
<div *ngIf="!editableCategories">
|
||||
<p *ngFor="let category of categories" class="adf-metadata-categories">{{ category.name }}</p>
|
||||
</div>
|
||||
<adf-categories-management
|
||||
[(categoryNameControlVisible)]="categoryControlVisible"
|
||||
[disableRemoval]="saving"
|
||||
[categories]="categories"
|
||||
[managementMode]="categoriesManagementMode"
|
||||
[classifiableChanged]="classifiableChanged"
|
||||
(categoriesChange)="storeCategoriesToAssign($event)">
|
||||
</adf-categories-management>
|
||||
</div>
|
||||
<div *ngIf="!categories.length && !editableCategories" class="adf-metadata-no-catagories-added">
|
||||
{{ 'CATEGORIES_MANAGEMENT.NO_CATEGORIES_ADDED' | translate }}
|
||||
</div>
|
||||
<div *ngIf="editableCategories" class="adf-metadata-categories-header">
|
||||
<adf-categories-management [(categoryNameControlVisible)]="categoryControlVisible"
|
||||
[disableRemoval]="saving" [categories]="categories" [managementMode]="categoriesManagementMode"
|
||||
[classifiableChanged]="classifiableChanged"
|
||||
(categoriesChange)="storeCategoriesToAssign($event)">
|
||||
</adf-categories-management>
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="expanded">
|
||||
<ng-container *ngIf="groupedProperties$ | async; else loading; let groupedProperties">
|
||||
<div *ngFor="let group of groupedProperties; let first = first;"
|
||||
class="adf-metadata-grouped-properties-container">
|
||||
<mat-expansion-panel *ngIf="showGroup(group) || editable"
|
||||
[attr.data-automation-id]="'adf-metadata-group-' + group.title"
|
||||
[expanded]="canExpandTheCard(group) || !displayDefaultProperties && first">
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
<ng-container *ngIf="groupedProperties$ | async; else loading; let groupedProperties">
|
||||
<div *ngFor="let group of groupedProperties; let first = first;"
|
||||
class="adf-metadata-grouped-properties-container">
|
||||
<mat-expansion-panel [attr.data-automation-id]="'adf-metadata-group-' + group.title"
|
||||
[expanded]="group.expanded" (opened)="group.expanded= true" (closed)="group.expanded= false"
|
||||
hideToggle>
|
||||
<mat-expansion-panel-header>
|
||||
<div class="adf-toggle-icons">
|
||||
<mat-icon>
|
||||
{{ group.expanded || aspectPanelstate ? 'expand_more' : 'chevron_right'}}</mat-icon>
|
||||
<mat-panel-title class="adf-metadata-properties-title">
|
||||
{{ group.title | translate }}
|
||||
</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
<adf-card-view
|
||||
(keydown)="keyDown($event)"
|
||||
[properties]="group.properties"
|
||||
[editable]="editable"
|
||||
[displayEmpty]="displayEmpty"
|
||||
[copyToClipboardAction]="copyToClipboardAction"
|
||||
[useChipsForMultiValueProperty]="useChipsForMultiValueProperty"
|
||||
[multiValueSeparator]="multiValueSeparator">
|
||||
</adf-card-view>
|
||||
</mat-expansion-panel>
|
||||
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-template #loading>
|
||||
<mat-progress-bar mode="indeterminate" [attr.aria-label]="'DATA_LOADING' | translate">
|
||||
</mat-progress-bar>
|
||||
</ng-template>
|
||||
</div>
|
||||
<button *ngIf="!group.editable" mat-icon-button
|
||||
[attr.title]="'CORE.METADATA.ACTIONS.EDIT' | translate"
|
||||
[attr.aria-label]="'CORE.METADATA.ACCESSIBILITY.EDIT' | translate"
|
||||
data-automation-id="meta-data-card-toggle-edit" class="adf-edit-icon-buttons"
|
||||
(click)="toggleEdit(group, $event)">
|
||||
<mat-icon>mode_edit</mat-icon>
|
||||
</button>
|
||||
<div class="adf-metadata-action-buttons" *ngIf="group.editable">
|
||||
<button mat-icon-button (click)="cancelGroupChanges(group, $event)"
|
||||
data-automation-id="reset-metadata">
|
||||
<mat-icon>clear</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button (click)="saveGroupChanges(group, $event)" color="primary"
|
||||
data-automation-id="save-metadata" [disabled]="!hasMetadataChanged">
|
||||
<mat-icon>check</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</mat-expansion-panel-header>
|
||||
<mat-divider class="adf-mat-divider"></mat-divider>
|
||||
<adf-card-view (keydown)="keyDown($event)" [properties]="group.properties"
|
||||
[editable]="group.editable" [displayEmpty]="displayEmpty"
|
||||
[copyToClipboardAction]="copyToClipboardAction"
|
||||
[useChipsForMultiValueProperty]="useChipsForMultiValueProperty"
|
||||
[multiValueSeparator]="multiValueSeparator">
|
||||
</adf-card-view>
|
||||
</mat-expansion-panel>
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-template #loading>
|
||||
<mat-progress-bar mode="indeterminate" [attr.aria-label]="'DATA_LOADING' | translate">
|
||||
</mat-progress-bar>
|
||||
</ng-template>
|
||||
</mat-accordion>
|
||||
|
||||
<div class="adf-metadata-action-buttons"
|
||||
*ngIf="editable">
|
||||
<button mat-button
|
||||
(click)="cancelChanges()"
|
||||
data-automation-id="reset-metadata"
|
||||
[disabled]="!hasMetadataChanged">
|
||||
{{ 'CORE.METADATA.ACTIONS.CANCEL' | translate }}
|
||||
</button>
|
||||
<button mat-raised-button
|
||||
(click)="saveChanges()"
|
||||
color="primary"
|
||||
data-automation-id="save-metadata"
|
||||
[disabled]="!hasMetadataChanged">
|
||||
{{ 'CORE.METADATA.ACTIONS.SAVE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
+69
-20
@@ -1,37 +1,71 @@
|
||||
.adf {
|
||||
&-metadata-properties {
|
||||
.mat-expansion-panel-header.mat-expanded:hover,
|
||||
.mat-expansion-panel-header.mat-expanded:focus {
|
||||
background: var(--adf-theme-background-hover-color);
|
||||
}
|
||||
|
||||
.mat-expansion-panel {
|
||||
border: 1px solid var(--adf-metadata-property-panel-border-color);
|
||||
border-radius: 12px !important;
|
||||
margin-bottom: 12px;
|
||||
|
||||
mat-expansion-panel-header {
|
||||
height: 64px;
|
||||
height: 56px;
|
||||
|
||||
.adf-metadata-properties-title {
|
||||
font-weight: normal;
|
||||
font-size: 15px;
|
||||
padding-left: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mat-expansion-panel:not([class*='mat-elevation-z']) {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.adf-metadata-properties-tag {
|
||||
height: 40px;
|
||||
.adf-mat-divider {
|
||||
margin-left: -24px;
|
||||
margin-right: -24px;
|
||||
}
|
||||
|
||||
.adf-edit-icon-buttons {
|
||||
color: var(--adf-theme-foreground-text-color-054);
|
||||
}
|
||||
|
||||
.adf-toggle-icons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: -14px;
|
||||
margin-bottom: 1em;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&:first-of-type {
|
||||
margin-top: 5px;
|
||||
}
|
||||
.adf-metadata-properties-tag {
|
||||
height: 32px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
border-radius: 16px;
|
||||
width: fit-content;
|
||||
background: var(--adf-metadata-tags-background-color);
|
||||
margin-top: 12px;
|
||||
padding: 6px 12px;
|
||||
justify-content: center;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.adf-metadata-no-tags-added {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 15px;
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.adf-metadata-no-catagories-added {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 15px;
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
&-tags {
|
||||
padding: 0 10px 0 26px;
|
||||
|
||||
&-title {
|
||||
display: flex;
|
||||
@@ -42,15 +76,9 @@
|
||||
}
|
||||
|
||||
adf-tags-creator {
|
||||
margin-top: 19px;
|
||||
|
||||
.adf-tags-creation {
|
||||
padding-right: 0;
|
||||
padding-left: 12px;
|
||||
|
||||
.adf-tag {
|
||||
margin-top: -14px;
|
||||
}
|
||||
}
|
||||
|
||||
&.adf-creator-with-existing-tags-panel {
|
||||
@@ -73,7 +101,7 @@
|
||||
&-metadata-categories-header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0 24px;
|
||||
padding-right: 24px;
|
||||
|
||||
.adf-metadata-categories-title {
|
||||
display: flex;
|
||||
@@ -92,3 +120,24 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.acs-details-container {
|
||||
.mat-tab-body-content {
|
||||
.adf-content-metadata-card {
|
||||
.adf-metadata-properties {
|
||||
.mat-expansion-panel {
|
||||
width: 755px;
|
||||
border: 1px solid var(--adf-metadata-property-panel-border-color);
|
||||
margin: 24px;
|
||||
border-radius: 12px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.adf-content-metadata-card {
|
||||
.mat-card:not([class*=mat-elevation-z]) {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
+153
-26
@@ -34,6 +34,9 @@ import { CardViewContentUpdateService } from '../../../common/services/card-view
|
||||
import { PropertyGroup } from '../../interfaces/property-group.interface';
|
||||
import { PropertyDescriptorsService } from '../../services/property-descriptors.service';
|
||||
import { CategoriesManagementComponent, CategoriesManagementMode, CategoryService, TagsCreatorComponent, TagsCreatorMode, TagService } from '@alfresco/adf-content-services';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatExpansionModule } from '@angular/material/expansion';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
|
||||
describe('ContentMetadataComponent', () => {
|
||||
let component: ContentMetadataComponent;
|
||||
@@ -104,7 +107,10 @@ describe('ContentMetadataComponent', () => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
ContentTestingModule
|
||||
ContentTestingModule,
|
||||
MatIconModule,
|
||||
MatExpansionModule,
|
||||
MatDividerModule
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
@@ -221,7 +227,7 @@ describe('ContentMetadataComponent', () => {
|
||||
}));
|
||||
|
||||
it('should save changedProperties on save click', fakeAsync(async () => {
|
||||
component.editable = true;
|
||||
component.editableGeneralInfo = true;
|
||||
const property = { key: 'properties.property-key', value: 'original-value' } as CardViewBaseItemModel;
|
||||
const expectedNode = { ...node, name: 'some-modified-value' };
|
||||
spyOn(nodesApiService, 'updateNode').and.returnValue(of(expectedNode));
|
||||
@@ -231,15 +237,15 @@ describe('ContentMetadataComponent', () => {
|
||||
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
clickOnSave();
|
||||
|
||||
const mockEvent = new Event('click');
|
||||
component.saveGeneralInfoChanges(mockEvent);
|
||||
await fixture.whenStable();
|
||||
expect(component.node).toEqual(expectedNode);
|
||||
expect(nodesApiService.updateNode).toHaveBeenCalled();
|
||||
}));
|
||||
|
||||
it('should call removeTag and assignTagsToNode on TagService on save click', fakeAsync( () => {
|
||||
component.editable = true;
|
||||
it('should call removeTag and assignTagsToNode on TagService on save click', () => {
|
||||
component.editableTags = true;
|
||||
component.displayTags = true;
|
||||
const property = { key: 'properties.property-key', value: 'original-value' } as CardViewBaseItemModel;
|
||||
const expectedNode = { ...node, name: 'some-modified-value' };
|
||||
@@ -253,11 +259,11 @@ describe('ContentMetadataComponent', () => {
|
||||
const tagName2 = 'New tag 3';
|
||||
|
||||
updateService.update(property, 'updated-value');
|
||||
tick(600);
|
||||
|
||||
fixture.detectChanges();
|
||||
findTagsCreator().tagsChange.emit([tagName1, tagName2]);
|
||||
clickOnSave();
|
||||
const mockEvent = new Event('click');
|
||||
component.saveTagsChanges(mockEvent);
|
||||
|
||||
const tag1 = new TagBody();
|
||||
tag1.tag = tagName1;
|
||||
@@ -265,10 +271,10 @@ describe('ContentMetadataComponent', () => {
|
||||
tag2.tag = tagName2;
|
||||
expect(tagService.removeTag).toHaveBeenCalledWith(node.id, tagPaging.list.entries[1].entry.id);
|
||||
expect(tagService.assignTagsToNode).toHaveBeenCalledWith(node.id, [tag1, tag2]);
|
||||
}));
|
||||
});
|
||||
|
||||
it('should call getTagsByNodeId on TagService on save click', fakeAsync( () => {
|
||||
component.editable = true;
|
||||
it('should call getTagsByNodeId on TagService on save click', () => {
|
||||
component.editableTags = true;
|
||||
component.displayTags = true;
|
||||
const property = { key: 'properties.property-key', value: 'original-value' } as CardViewBaseItemModel;
|
||||
const expectedNode = { ...node, name: 'some-modified-value' };
|
||||
@@ -280,15 +286,15 @@ describe('ContentMetadataComponent', () => {
|
||||
spyOn(tagService, 'assignTagsToNode').and.returnValue(of({}));
|
||||
|
||||
updateService.update(property, 'updated-value');
|
||||
tick(600);
|
||||
|
||||
fixture.detectChanges();
|
||||
findTagsCreator().tagsChange.emit([tagPaging.list.entries[0].entry.tag, 'New tag 3']);
|
||||
getTagsByNodeIdSpy.calls.reset();
|
||||
clickOnSave();
|
||||
const mockEvent = new Event('click');
|
||||
component.saveTagsChanges(mockEvent);
|
||||
|
||||
expect(tagService.getTagsByNodeId).toHaveBeenCalledWith(node.id);
|
||||
}));
|
||||
});
|
||||
|
||||
it('should throw error on unsuccessful save', fakeAsync(() => {
|
||||
const logService: LogService = TestBed.inject(LogService);
|
||||
@@ -313,7 +319,7 @@ describe('ContentMetadataComponent', () => {
|
||||
}));
|
||||
|
||||
it('should open the confirm dialog when content type is changed', fakeAsync(() => {
|
||||
component.editable = true;
|
||||
component.editableGeneralInfo = true;
|
||||
const property = { key: 'nodeType', value: 'ft:sbiruli' } as CardViewBaseItemModel;
|
||||
const expectedNode = { ...node, nodeType: 'ft:sbiruli' };
|
||||
spyOn(contentMetadataService, 'openConfirmDialog').and.returnValue(of(true));
|
||||
@@ -324,8 +330,8 @@ describe('ContentMetadataComponent', () => {
|
||||
|
||||
fixture.detectChanges();
|
||||
tick(100);
|
||||
clickOnSave();
|
||||
|
||||
const mockEvent = new Event('click');
|
||||
component.saveGeneralInfoChanges(mockEvent);
|
||||
tick(100);
|
||||
expect(component.node).toEqual(expectedNode);
|
||||
expect(contentMetadataService.openConfirmDialog).toHaveBeenCalledWith({nodeType: 'ft:poppoli'});
|
||||
@@ -333,8 +339,8 @@ describe('ContentMetadataComponent', () => {
|
||||
discardPeriodicTasks();
|
||||
}));
|
||||
|
||||
it('should call removeTag and assignTagsToNode on TagService after confirming confirmation dialog when content type is changed', fakeAsync(() => {
|
||||
component.editable = true;
|
||||
it('should call removeTag and assignTagsToNode on TagService after confirming confirmation dialog when content type is changed',() => {
|
||||
component.editableTags = true;
|
||||
component.displayTags = true;
|
||||
const property = { key: 'nodeType', value: 'ft:sbiruli' } as CardViewBaseItemModel;
|
||||
const expectedNode = { ...node, nodeType: 'ft:sbiruli' };
|
||||
@@ -349,25 +355,23 @@ describe('ContentMetadataComponent', () => {
|
||||
const tagName2 = 'New tag 3';
|
||||
|
||||
updateService.update(property, 'ft:poppoli');
|
||||
tick(600);
|
||||
|
||||
fixture.detectChanges();
|
||||
findTagsCreator().tagsChange.emit([tagName1, tagName2]);
|
||||
tick(100);
|
||||
fixture.detectChanges();
|
||||
clickOnSave();
|
||||
const mockEvent = new Event('click');
|
||||
component.saveTagsChanges(mockEvent);
|
||||
|
||||
tick(100);
|
||||
const tag1 = new TagBody();
|
||||
tag1.tag = tagName1;
|
||||
const tag2 = new TagBody();
|
||||
tag2.tag = tagName2;
|
||||
expect(tagService.removeTag).toHaveBeenCalledWith(node.id, tagPaging.list.entries[1].entry.id);
|
||||
expect(tagService.assignTagsToNode).toHaveBeenCalledWith(node.id, [tag1, tag2]);
|
||||
}));
|
||||
});
|
||||
|
||||
it('should retrigger the load of the properties when the content type has changed', fakeAsync(() => {
|
||||
component.editable = true;
|
||||
component.editableGeneralInfo = true;
|
||||
const property = { key: 'nodeType', value: 'ft:sbiruli' } as CardViewBaseItemModel;
|
||||
const expectedNode = Object.assign({}, node, { nodeType: 'ft:sbiruli' });
|
||||
spyOn(contentMetadataService, 'openConfirmDialog').and.returnValue(of(true));
|
||||
@@ -379,14 +383,137 @@ describe('ContentMetadataComponent', () => {
|
||||
|
||||
fixture.detectChanges();
|
||||
tick(100);
|
||||
clickOnSave();
|
||||
const mockEvent = new Event('click');
|
||||
component.saveGeneralInfoChanges(mockEvent);
|
||||
|
||||
tick(100);
|
||||
expect(component.node).toEqual(expectedNode);
|
||||
expect(updateService.updateNodeAspect).toHaveBeenCalledWith(expectedNode);
|
||||
}));
|
||||
|
||||
it('should save general info changes and toggle editableGeneralInfo', () => {
|
||||
const event = new Event('click');
|
||||
spyOn(component, 'saveChanges');
|
||||
component.editableGeneralInfo = true;
|
||||
component.saveGeneralInfoChanges(event);
|
||||
expect(component.saveChanges).toHaveBeenCalledWith(event);
|
||||
expect(component.editableGeneralInfo).toBe(false);
|
||||
});
|
||||
|
||||
it('should save group changes and set group editable to false', () => {
|
||||
const group = { editable: true };
|
||||
const event = new Event('click');
|
||||
spyOn(component, 'saveChanges');
|
||||
component.saveGroupChanges(group, event);
|
||||
expect(component.saveChanges).toHaveBeenCalledWith(event);
|
||||
expect(group.editable).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('cancelChanges', () => {
|
||||
it('should cancel group changes and set group editable to false', () => {
|
||||
const group = { editable: true };
|
||||
const event = new Event('click');
|
||||
spyOn(component, 'cancelChanges');
|
||||
component.cancelGroupChanges(group, event);
|
||||
expect(component.cancelChanges).toHaveBeenCalledWith(event);
|
||||
expect(group.editable).toBe(false);
|
||||
});
|
||||
|
||||
it('should cancel general info changes and toggle editableGeneralInfo', () => {
|
||||
const event = new Event('click');
|
||||
spyOn(component, 'cancelChanges');
|
||||
component.editableGeneralInfo = true;
|
||||
component.cancelGeneralInfoChanges(event);
|
||||
expect(component.cancelChanges).toHaveBeenCalledWith(event);
|
||||
expect(component.editableGeneralInfo).toBe(false);
|
||||
});
|
||||
|
||||
it('should cancel tags changes and toggle editableTags', () => {
|
||||
const event = new Event('click');
|
||||
spyOn(component, 'cancelChanges');
|
||||
component.editableTags = true;
|
||||
component.CancelTagsChanges(event);
|
||||
expect(component.cancelChanges).toHaveBeenCalledWith(event);
|
||||
expect(component.editableTags).toBe(false);
|
||||
});
|
||||
|
||||
it('should cancel categories changes and toggle editableCategories', () => {
|
||||
const event = new Event('click');
|
||||
spyOn(component, 'cancelChanges');
|
||||
component.editableCategories = true;
|
||||
component.cancelCategoriesChanges(event);
|
||||
expect(component.cancelChanges).toHaveBeenCalledWith(event);
|
||||
expect(component.editableCategories).toBe(false);
|
||||
});
|
||||
})
|
||||
|
||||
describe('editing', () => {
|
||||
it('should toggle categories edit and set categoriesPanelState accordingly', () => {
|
||||
const event = new Event('click');
|
||||
spyOn(event, 'stopPropagation');
|
||||
component.editableCategories = false;
|
||||
component.categoriesPanelState = false;
|
||||
component.toggleCategoriesEdit(event);
|
||||
expect(event.stopPropagation).toHaveBeenCalled();
|
||||
expect(component.editableCategories).toBe(true);
|
||||
expect(component.categoriesPanelState).toBe(true);
|
||||
component.toggleCategoriesEdit(event);
|
||||
expect(component.editableCategories).toBe(false);
|
||||
expect(component.categoriesPanelState).toBe(false);
|
||||
});
|
||||
|
||||
it('should toggle group edit and expand the panel if editable', () => {
|
||||
const event = new Event('click');
|
||||
spyOn(event, 'stopPropagation');
|
||||
const group = { editable: false };
|
||||
component.expandePanel = jasmine.createSpy();
|
||||
component.toggleEdit(group, event);
|
||||
expect(event.stopPropagation).toHaveBeenCalled();
|
||||
expect(group.editable).toBe(true);
|
||||
expect(component.expandePanel).toHaveBeenCalledWith(group);
|
||||
});
|
||||
|
||||
it('should toggle group edit but not expand the panel if not editable', () => {
|
||||
const event = new Event('click');
|
||||
spyOn(event, 'stopPropagation');
|
||||
const group = { editable: true };
|
||||
component.expandePanel = jasmine.createSpy();
|
||||
component.toggleEdit(group, event);
|
||||
expect(event.stopPropagation).toHaveBeenCalled();
|
||||
expect(group.editable).toBe(false);
|
||||
expect(component.expandePanel).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should toggle general info edit and set generalInfoPanelState accordingly', () => {
|
||||
const event = new Event('click');
|
||||
spyOn(event, 'stopPropagation');
|
||||
component.generalInfoPanelState = true;
|
||||
component.editableGeneralInfo = false;
|
||||
component.toggleGeneralEdit(event);
|
||||
expect(event.stopPropagation).toHaveBeenCalled();
|
||||
expect(component.editableGeneralInfo).toBe(true);
|
||||
expect(component.generalInfoPanelState).toBe(true);
|
||||
component.toggleGeneralEdit(event);
|
||||
expect(component.editableGeneralInfo).toBe(false);
|
||||
expect(component.generalInfoPanelState).toBe(true);
|
||||
});
|
||||
|
||||
it('should toggle tags edit and set tagsPanelState accordingly', () => {
|
||||
const event = new Event('click');
|
||||
spyOn(event, 'stopPropagation');
|
||||
component.editableTags = false;
|
||||
component.tagsPanelState = false;
|
||||
component.toggleTagsEdit(event);
|
||||
expect(event.stopPropagation).toHaveBeenCalled();
|
||||
expect(component.editableTags).toBe(true);
|
||||
expect(component.tagsPanelState).toBe(true);
|
||||
component.toggleTagsEdit(event);
|
||||
expect(component.editableTags).toBe(false);
|
||||
expect(component.tagsPanelState).toBe(false);
|
||||
});
|
||||
})
|
||||
|
||||
describe('Reseting', () => {
|
||||
it('should reset changedProperties on reset click', async () => {
|
||||
component.changedProperties = { properties: { 'property-key': 'updated-value' } };
|
||||
|
||||
+105
-9
@@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewEncapsulation } from '@angular/core';
|
||||
import { Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||
import { Category, CategoryEntry, CategoryLinkBody, CategoryPaging, Node, TagBody, TagEntry, TagPaging } from '@alfresco/js-api';
|
||||
import { Observable, Subject, of, zip, forkJoin } from 'rxjs';
|
||||
import {
|
||||
@@ -35,6 +35,7 @@ import { TagsCreatorMode } from '../../../tag/tags-creator/tags-creator-mode';
|
||||
import { TagService } from '../../../tag/services/tag.service';
|
||||
import { CategoryService } from '../../../category/services/category.service';
|
||||
import { CategoriesManagementMode } from '../../../category/categories-management/categories-management-mode';
|
||||
import { MatExpansionPanel } from '@angular/material/expansion';
|
||||
|
||||
const DEFAULT_SEPARATOR = ', ';
|
||||
|
||||
@@ -46,6 +47,7 @@ const DEFAULT_SEPARATOR = ', ';
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class ContentMetadataComponent implements OnChanges, OnInit, OnDestroy {
|
||||
@ViewChild(MatExpansionPanel) panel: MatExpansionPanel;
|
||||
protected onDestroy$ = new Subject<boolean>();
|
||||
|
||||
/** (required) The node entity to fetch metadata about */
|
||||
@@ -126,6 +128,13 @@ export class ContentMetadataComponent implements OnChanges, OnInit, OnDestroy {
|
||||
categoriesManagementMode = CategoriesManagementMode.ASSIGN;
|
||||
categoryControlVisible = false;
|
||||
classifiableChanged = this.classifiableChangedSubject.asObservable();
|
||||
generalInfoPanelState: boolean;
|
||||
editableGeneralInfo: boolean;
|
||||
tagsPanelState: boolean;
|
||||
editableTags: boolean = false;
|
||||
categoriesPanelState: boolean;
|
||||
editableCategories: boolean = false;
|
||||
aspectPanelstate: boolean = false;
|
||||
|
||||
constructor(
|
||||
private contentMetadataService: ContentMetadataService,
|
||||
@@ -229,10 +238,10 @@ export class ContentMetadataComponent implements OnChanges, OnInit, OnDestroy {
|
||||
* Called after clicking save button. It confirms all changes done for metadata and hides both category and tag name controls.
|
||||
* Before clicking on that button they are not saved.
|
||||
*/
|
||||
saveChanges() {
|
||||
|
||||
saveChanges(event: Event) {
|
||||
event.stopPropagation();
|
||||
this._saving = true;
|
||||
this.tagNameControlVisible = false;
|
||||
this.categoryControlVisible = false;
|
||||
if (this.hasContentTypeChanged(this.changedProperties)) {
|
||||
this.contentMetadataService.openConfirmDialog(this.changedProperties).subscribe(() => {
|
||||
this.updateNode();
|
||||
@@ -242,6 +251,29 @@ export class ContentMetadataComponent implements OnChanges, OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
saveGroupChanges(group: any, event: Event) {
|
||||
this.saveChanges(event);
|
||||
group.editable = !group.editable;
|
||||
}
|
||||
|
||||
saveGeneralInfoChanges(event: Event) {
|
||||
this.saveChanges(event);
|
||||
this.editableGeneralInfo = !this.editableGeneralInfo;
|
||||
}
|
||||
|
||||
saveTagsChanges(event: Event) {
|
||||
this.saveChanges(event);
|
||||
this.tagNameControlVisible = false;
|
||||
this.editableTags = !this.editableTags;
|
||||
}
|
||||
|
||||
|
||||
saveCategoriesChanges(event: Event) {
|
||||
this.saveChanges(event);
|
||||
this.categoryControlVisible = false;
|
||||
this.editableCategories = !this.editableCategories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register all tags which should be assigned to node. Please note that they are just in "register" state and are not yet saved
|
||||
* until button for saving data is clicked. Calling that function causes that save button is enabled.
|
||||
@@ -269,11 +301,32 @@ export class ContentMetadataComponent implements OnChanges, OnInit, OnDestroy {
|
||||
this.hasMetadataChanged = false;
|
||||
}
|
||||
|
||||
cancelChanges() {
|
||||
cancelChanges(event: Event) {
|
||||
event.stopPropagation();
|
||||
this.revertChanges();
|
||||
this.loadProperties(this.node);
|
||||
}
|
||||
|
||||
cancelGroupChanges(group: any, event: Event) {
|
||||
this.cancelChanges(event);
|
||||
group.editable = !group.editable;
|
||||
}
|
||||
|
||||
cancelGeneralInfoChanges(event: Event) {
|
||||
this.cancelChanges(event);
|
||||
this.editableGeneralInfo = !this.editableGeneralInfo;
|
||||
}
|
||||
|
||||
CancelTagsChanges(event: Event) {
|
||||
this.cancelChanges(event);
|
||||
this.editableTags = !this.editableTags;
|
||||
}
|
||||
|
||||
cancelCategoriesChanges(event: Event) {
|
||||
this.cancelChanges(event);
|
||||
this.editableCategories = !this.editableCategories;
|
||||
}
|
||||
|
||||
showGroup(group: CardViewGroup): boolean {
|
||||
const properties = group.properties.filter((property) => !this.isEmpty(property.displayValue));
|
||||
|
||||
@@ -284,10 +337,6 @@ export class ContentMetadataComponent implements OnChanges, OnInit, OnDestroy {
|
||||
return group.title === this.displayAspect;
|
||||
}
|
||||
|
||||
canExpandProperties(): boolean {
|
||||
return !this.expanded || this.displayAspect === 'Properties';
|
||||
}
|
||||
|
||||
keyDown(event: KeyboardEvent) {
|
||||
if (event.keyCode === 37 || event.keyCode === 39) { // ArrowLeft && ArrowRight
|
||||
event.stopPropagation();
|
||||
@@ -420,4 +469,51 @@ export class ContentMetadataComponent implements OnChanges, OnInit, OnDestroy {
|
||||
}
|
||||
return observables;
|
||||
}
|
||||
|
||||
toggleGeneralEdit(event: Event): void {
|
||||
event.stopPropagation();
|
||||
this.editableGeneralInfo = !this.editableGeneralInfo;
|
||||
if (!this.panel.expanded) {
|
||||
this.panel.open();
|
||||
}
|
||||
}
|
||||
|
||||
toggleTagsEdit(event: Event): void {
|
||||
event.stopPropagation();
|
||||
this.editableTags = !this.editableTags;
|
||||
if (this.editableTags) {
|
||||
this.tagsPanelState = true;
|
||||
} else {
|
||||
this.tagsPanelState = false;
|
||||
}
|
||||
}
|
||||
|
||||
toggleCategoriesEdit(event: Event): void {
|
||||
event.stopPropagation();
|
||||
this.editableCategories = !this.editableCategories;
|
||||
if (this.editableCategories) {
|
||||
this.categoriesPanelState = true;
|
||||
} else {
|
||||
this.categoriesPanelState = false;
|
||||
}
|
||||
}
|
||||
|
||||
toggleEdit(group: any, event: Event): void {
|
||||
event.stopPropagation();
|
||||
group.editable = !group.editable;
|
||||
if(group.editable) {
|
||||
this.expandePanel(group);
|
||||
}
|
||||
}
|
||||
|
||||
expandePanel(group: any) {
|
||||
group.expanded = true;
|
||||
}
|
||||
|
||||
onPanelOpened(group: any): void {
|
||||
group.aspectPanelstate = true;
|
||||
}
|
||||
onPanelClosed(group: any): void {
|
||||
group.aspectPanelstate = false;
|
||||
}
|
||||
}
|
||||
|
||||
+9
-2
@@ -25,6 +25,7 @@ export const mockGroupProperties = [
|
||||
key: 'properties.exif:pixelXDimension',
|
||||
default: null,
|
||||
editable: true,
|
||||
editableTags: true,
|
||||
clickable: false,
|
||||
icon: '',
|
||||
data: null,
|
||||
@@ -40,6 +41,7 @@ export const mockGroupProperties = [
|
||||
key: 'properties.exif:pixelYDimension',
|
||||
default: null,
|
||||
editable: true,
|
||||
editableTags: true,
|
||||
clickable: false,
|
||||
icon: '',
|
||||
data: null,
|
||||
@@ -49,7 +51,9 @@ export const mockGroupProperties = [
|
||||
clickCallBack: null,
|
||||
displayValue: 400
|
||||
}
|
||||
]
|
||||
],
|
||||
editable: true,
|
||||
expanded: true,
|
||||
},
|
||||
{
|
||||
title: 'CUSTOM',
|
||||
@@ -60,6 +64,7 @@ export const mockGroupProperties = [
|
||||
key: 'properties.custom:abc',
|
||||
default: null,
|
||||
editable: true,
|
||||
editableTags: true,
|
||||
clickable: false,
|
||||
icon: '',
|
||||
data: null,
|
||||
@@ -69,6 +74,8 @@ export const mockGroupProperties = [
|
||||
clickCallBack: null,
|
||||
displayValue: 400
|
||||
}
|
||||
]
|
||||
],
|
||||
editable: true,
|
||||
expanded: true,
|
||||
}
|
||||
];
|
||||
|
||||
@@ -20,4 +20,6 @@ import { CardViewItem } from '@alfresco/adf-core';
|
||||
export interface CardViewGroup {
|
||||
title: string;
|
||||
properties: CardViewItem[];
|
||||
editable: boolean;
|
||||
expanded: boolean;
|
||||
}
|
||||
|
||||
@@ -149,6 +149,7 @@
|
||||
"TITLE": "Create Tags",
|
||||
"CREATE_TAG": "Create: {{tag}}",
|
||||
"NAME": "Name",
|
||||
"INPUT_PLACEHOLDER": "Add a tag to these items",
|
||||
"ERRORS": {
|
||||
"EXISTING_TAG": "Tag already exists",
|
||||
"ALREADY_ADDED_TAG": "Tag is already added",
|
||||
@@ -179,6 +180,8 @@
|
||||
"NAME": "Category name",
|
||||
"LOADING": "Loading",
|
||||
"HIDE_INPUT": "Hide input",
|
||||
"INPUT_PLACEHOLDER": "Add a categories to these items",
|
||||
"NO_CATEGORIES_ADDED": "There are currently no categories added",
|
||||
"ERRORS": {
|
||||
"NOT_FOUND": "Categories not found",
|
||||
"REQUIRED": "Category name is required",
|
||||
@@ -487,7 +490,9 @@
|
||||
"MODIFIED_DATE": "Modified Date",
|
||||
"CONTENT_TYPE": "Content Type",
|
||||
"TAGS": "Tags",
|
||||
"ADD_TAG_TOOLTIP": "Add tag"
|
||||
"ADD_TAG_TOOLTIP": "Add tag",
|
||||
"HEADER_TITLE": "General info",
|
||||
"NO_TAGS_ADDED": "There are currently no tags added"
|
||||
},
|
||||
"CONTENT_TYPE": {
|
||||
"DIALOG" :{
|
||||
|
||||
@@ -1,14 +1,28 @@
|
||||
<div class="adf-tags-creation">
|
||||
<p
|
||||
class="adf-no-tags-message"
|
||||
*ngIf="!tags.length && !tagNameControlVisible">
|
||||
<div class="adf-tag-name-field">
|
||||
<div class="adf-tag-search-field">
|
||||
<input
|
||||
#tagNameInput
|
||||
matInput
|
||||
autocomplete="off"
|
||||
[formControl]="tagNameControl"
|
||||
(keyup.enter)="addTag()"
|
||||
aria-labelledby="adf-tag-name-input-label"
|
||||
adf-auto-focus
|
||||
placeholder="{{'TAG.TAGS_CREATOR.INPUT_PLACEHOLDER' | translate}}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<p
|
||||
class="adf-no-tags-message"
|
||||
*ngIf="!tags.length && !tagNameControlVisible">
|
||||
{{ 'TAG.TAGS_CREATOR.NO_TAGS_CREATED' | translate }}
|
||||
</p>
|
||||
<div
|
||||
class="adf-tags-list"
|
||||
[class.adf-tags-list-fixed]="!tagNameControlVisible"
|
||||
#tagsList>
|
||||
<p
|
||||
<span
|
||||
*ngFor="let tag of tags"
|
||||
class="adf-tag adf-label-with-icon-button">
|
||||
{{ tag }}
|
||||
@@ -17,38 +31,11 @@
|
||||
mat-icon-button
|
||||
(click)="removeTag(tag)"
|
||||
[attr.title]="'TAG.TAGS_CREATOR.TOOLTIPS.DELETE_TAG' | translate"
|
||||
[disabled]="disabledTagsRemoving">
|
||||
<mat-icon>remove</mat-icon>
|
||||
[disabled]="disabledTagsRemoving"
|
||||
class="adf-remove-tag">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
class="adf-tag-name-field"
|
||||
*ngIf="(!tagNameControlVisible && tags.length) || tagNameControlVisible"
|
||||
[hidden]="!tagNameControlVisible">
|
||||
<mat-form-field *ngIf="tagNameControlVisible">
|
||||
<mat-icon matPrefix>search</mat-icon>
|
||||
<mat-label id="adf-tag-name-input-label">
|
||||
{{ 'TAG.TAGS_CREATOR.NAME' | translate }}
|
||||
</mat-label>
|
||||
<input
|
||||
#tagNameInput
|
||||
matInput
|
||||
autocomplete="off"
|
||||
[formControl]="tagNameControl"
|
||||
(keyup.enter)="addTag()"
|
||||
aria-labelledby="adf-tag-name-input-label"
|
||||
adf-auto-focus
|
||||
/>
|
||||
<mat-error [hidden]="!tagNameControl.invalid">{{ tagNameErrorMessageKey | translate }}</mat-error>
|
||||
</mat-form-field>
|
||||
<button
|
||||
data-automation-id="hide-tag-name-input-button"
|
||||
mat-icon-button
|
||||
(click)="hideNameInput()"
|
||||
[attr.title]="'TAG.TAGS_CREATOR.TOOLTIPS.HIDE_INPUT' | translate">
|
||||
<mat-icon>remove</mat-icon>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
|
||||
@@ -1,11 +1,22 @@
|
||||
adf-tags-creator {
|
||||
display: block;
|
||||
margin-left: -24px;
|
||||
|
||||
.adf-label-with-icon-button {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
background: var(--adf-metadata-tags-background-color);
|
||||
width: fit-content;
|
||||
height: 32px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 16px;
|
||||
padding: 6px 0;
|
||||
padding-left: 12px;
|
||||
margin-left: 8px;
|
||||
|
||||
.adf-remove-tag {
|
||||
line-height: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.adf-no-tags-message {
|
||||
@@ -29,6 +40,16 @@ adf-tags-creator {
|
||||
}
|
||||
}
|
||||
|
||||
.adf-tag-search-field {
|
||||
width: 752px;
|
||||
background: var(--adf-metadata-tags-background-color);
|
||||
height: 32px;
|
||||
border-radius: 12px;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.adf-create-tag-label {
|
||||
color: var(--theme-primary-color);
|
||||
cursor: pointer;
|
||||
@@ -37,30 +58,23 @@ adf-tags-creator {
|
||||
overflow-wrap: anywhere;
|
||||
display: inline-block;
|
||||
padding-right: 12px;
|
||||
overflow: auto;
|
||||
max-height: 7vh;
|
||||
}
|
||||
|
||||
.adf-tags-list {
|
||||
padding-left: 10px;
|
||||
padding-right: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.adf-tag {
|
||||
margin-top: 0;
|
||||
overflow-wrap: anywhere;
|
||||
|
||||
& + .adf-tag {
|
||||
margin-top: -14px;
|
||||
&+.adf-tag {
|
||||
margin-top: 8px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.adf-tags-creation {
|
||||
padding-left: 27px;
|
||||
padding-right: 22px;
|
||||
}
|
||||
|
||||
.adf-existing-tags-panel {
|
||||
border-top-left-radius: 6px;
|
||||
border-top-right-radius: 6px;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div [attr.data-automation-id]="'header-'+property.key" class="adf-property">
|
||||
<adf-card-view-item-dispatcher
|
||||
[property]="property"
|
||||
[editable]="editable"
|
||||
[editable]="editable || editableGeneralInfo"
|
||||
[displayEmpty]="displayEmpty"
|
||||
[displayNoneOption]="property['displayNoneOption'] !== undefined ? property['displayNoneOption'] : displayNoneOption"
|
||||
[displayClearAction]="displayClearAction"
|
||||
|
||||
@@ -34,6 +34,9 @@ export class CardViewComponent {
|
||||
@Input()
|
||||
editable: boolean;
|
||||
|
||||
@Input()
|
||||
editableGeneralInfo: boolean;
|
||||
|
||||
/** Toggles whether or not to show empty items in non-editable mode. */
|
||||
@Input()
|
||||
displayEmpty: boolean = true;
|
||||
|
||||
@@ -23,6 +23,7 @@ export interface CardViewItemProperties {
|
||||
key: any;
|
||||
default?: any;
|
||||
editable?: boolean;
|
||||
editableGeneralInfo?: boolean;
|
||||
clickable?: any;
|
||||
icon?: string;
|
||||
hint?: string;
|
||||
|
||||
@@ -23,5 +23,6 @@ export interface CardViewItem {
|
||||
type: string;
|
||||
displayValue: any;
|
||||
editable?: boolean;
|
||||
editableGeneralInfo?: boolean;
|
||||
icon?: string;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ export abstract class CardViewBaseItemModel {
|
||||
key: any;
|
||||
default: any;
|
||||
editable: boolean;
|
||||
editableGeneralInfo: boolean;
|
||||
clickable: boolean;
|
||||
icon?: string;
|
||||
hint?: string;
|
||||
@@ -38,6 +39,7 @@ export abstract class CardViewBaseItemModel {
|
||||
this.key = cardViewItemProperties.key;
|
||||
this.default = cardViewItemProperties.default;
|
||||
this.editable = !!cardViewItemProperties.editable;
|
||||
this.editableGeneralInfo = !!cardViewItemProperties.editableGeneralInfo;
|
||||
this.clickable = !!cardViewItemProperties.clickable;
|
||||
this.icon = cardViewItemProperties.icon || '';
|
||||
this.hint = cardViewItemProperties.hint || '';
|
||||
|
||||
@@ -45,6 +45,8 @@
|
||||
--adf-identity-user-info-line-height: $adf-ref-line-height,
|
||||
--adf-identity-user-info-font-size: var(--theme-adf-picture-1-font-size),
|
||||
--adf-user-info-container-margin-right: $adf-ref-margin-right,
|
||||
--adf-metadata-property-panel-border-color: $adf-metadata-property-panel-border-color,
|
||||
--$adf-metadata-tags-background-color: $adf-metadata-tags-background-color
|
||||
);
|
||||
|
||||
// propagates SCSS variables into the CSS variables scope
|
||||
|
||||
@@ -27,3 +27,5 @@ $adf-ref-height: 40px;
|
||||
$adf-ref-width: 40px;
|
||||
$adf-ref-line-height: 40px;
|
||||
$adf-ref-margin-right: 8px;
|
||||
$adf-metadata-property-panel-border-color: rgba(0, 0, 0, 0.12);
|
||||
$adf-metadata-tags-background-color: rgba(33, 33, 33, 0.05);
|
||||
|
||||
Reference in New Issue
Block a user