mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-07-31 17:38:28 +00:00
[ACA-1956] Library - metadata info (#760)
* library metadata panel * add infoDrawer component to Library * set infoDrawer state to false onDestroy * infoDrawer action * update actions index * infoDrawer set state reducer * register Library metadata component to extensions * filter infoDrawer tabs * update library api * library actions and effects * refresh library view on update event * infoDrawer tests * refactor * check permission on update * check permission on update * lint * reference selection library * add parameter type * full width
This commit is contained in:
@@ -22,11 +22,137 @@
|
|||||||
* You should have received a copy of the GNU Lesser General Public License
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import { InfoDrawerComponent } from './info-drawer.component';
|
import { InfoDrawerComponent } from './info-drawer.component';
|
||||||
|
import { TestBed, ComponentFixture, async } from '@angular/core/testing';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { SetInfoDrawerStateAction } from '../../store/actions';
|
||||||
|
import { AppTestingModule } from '../../testing/app-testing.module';
|
||||||
|
import { AppExtensionService } from '../../extensions/extension.service';
|
||||||
|
import { ContentApiService } from '../../services/content-api.service';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
|
||||||
describe('InfoDrawerComponent', () => {
|
describe('InfoDrawerComponent', () => {
|
||||||
it('should be defined', () => {
|
let fixture: ComponentFixture<InfoDrawerComponent>;
|
||||||
expect(InfoDrawerComponent).toBeDefined();
|
let component: InfoDrawerComponent;
|
||||||
|
let contentApiService;
|
||||||
|
let tab;
|
||||||
|
let appExtensionService;
|
||||||
|
const storeMock = {
|
||||||
|
dispatch: jasmine.createSpy('dispatch')
|
||||||
|
};
|
||||||
|
const extensionServiceMock = {
|
||||||
|
getSidebarTabs: () => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [AppTestingModule],
|
||||||
|
declarations: [InfoDrawerComponent],
|
||||||
|
providers: [
|
||||||
|
ContentApiService,
|
||||||
|
{ provide: AppExtensionService, useValue: extensionServiceMock },
|
||||||
|
{ provide: Store, useValue: storeMock }
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
});
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(InfoDrawerComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
appExtensionService = TestBed.get(AppExtensionService);
|
||||||
|
contentApiService = TestBed.get(ContentApiService);
|
||||||
|
|
||||||
|
tab = <any>{ title: 'tab1' };
|
||||||
|
spyOn(appExtensionService, 'getSidebarTabs').and.returnValue([tab]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should get tabs configuration on initialization', () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
expect(component.tabs).toEqual([tab]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set state to false OnDestroy event', () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
component.ngOnDestroy();
|
||||||
|
|
||||||
|
expect(storeMock.dispatch).toHaveBeenCalledWith(
|
||||||
|
new SetInfoDrawerStateAction(false)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set displayNode when node is from personal list', () => {
|
||||||
|
spyOn(contentApiService, 'getNodeInfo');
|
||||||
|
const nodeMock = { entry: { id: 'nodeId' } };
|
||||||
|
component.node = nodeMock;
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
component.ngOnChanges();
|
||||||
|
|
||||||
|
expect(component.displayNode).toBe(nodeMock.entry);
|
||||||
|
expect(contentApiService.getNodeInfo).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set displayNode when node is library', async(() => {
|
||||||
|
spyOn(contentApiService, 'getNodeInfo');
|
||||||
|
const nodeMock = <any>{
|
||||||
|
entry: { id: 'nodeId' },
|
||||||
|
isLibrary: true
|
||||||
|
};
|
||||||
|
component.node = nodeMock;
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
component.ngOnChanges();
|
||||||
|
|
||||||
|
expect(component.displayNode).toBe(nodeMock);
|
||||||
|
expect(contentApiService.getNodeInfo).not.toHaveBeenCalled();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should call getNodeInfo() when node is a shared file', async(() => {
|
||||||
|
const response = { entry: { id: 'nodeId' } };
|
||||||
|
spyOn(contentApiService, 'getNodeInfo').and.returnValue(of(response));
|
||||||
|
const nodeMock = { entry: { nodeId: 'nodeId' }, isLibrary: false };
|
||||||
|
component.node = nodeMock;
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
component.ngOnChanges();
|
||||||
|
|
||||||
|
expect(component.displayNode).toBe(response);
|
||||||
|
expect(contentApiService.getNodeInfo).toHaveBeenCalled();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should call getNodeInfo() when node is a favorite file', async(() => {
|
||||||
|
const response = { entry: { id: 'nodeId' } };
|
||||||
|
spyOn(contentApiService, 'getNodeInfo').and.returnValue(of(response));
|
||||||
|
const nodeMock = <any>{
|
||||||
|
entry: { id: 'nodeId', guid: 'guidId' },
|
||||||
|
isLibrary: false
|
||||||
|
};
|
||||||
|
component.node = nodeMock;
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
component.ngOnChanges();
|
||||||
|
|
||||||
|
expect(component.displayNode).toBe(response);
|
||||||
|
expect(contentApiService.getNodeInfo).toHaveBeenCalled();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should call getNodeInfo() when node is a recent file', async(() => {
|
||||||
|
const response = { entry: { id: 'nodeId' } };
|
||||||
|
spyOn(contentApiService, 'getNodeInfo').and.returnValue(of(response));
|
||||||
|
const nodeMock = <any>{
|
||||||
|
entry: {
|
||||||
|
id: 'nodeId',
|
||||||
|
content: { mimeType: 'image/jpeg' }
|
||||||
|
},
|
||||||
|
isLibrary: false
|
||||||
|
};
|
||||||
|
component.node = nodeMock;
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
component.ngOnChanges();
|
||||||
|
|
||||||
|
expect(component.displayNode).toBe(response);
|
||||||
|
expect(contentApiService.getNodeInfo).toHaveBeenCalled();
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
@@ -23,27 +23,35 @@
|
|||||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Component, Input, OnChanges, OnInit } from '@angular/core';
|
import { Component, Input, OnChanges, OnInit, OnDestroy } from '@angular/core';
|
||||||
import { MinimalNodeEntity, MinimalNodeEntryEntity } from 'alfresco-js-api';
|
import {
|
||||||
|
MinimalNodeEntity,
|
||||||
|
MinimalNodeEntryEntity,
|
||||||
|
SiteEntry
|
||||||
|
} from 'alfresco-js-api';
|
||||||
import { ContentApiService } from '../../services/content-api.service';
|
import { ContentApiService } from '../../services/content-api.service';
|
||||||
import { AppExtensionService } from '../../extensions/extension.service';
|
import { AppExtensionService } from '../../extensions/extension.service';
|
||||||
import { SidebarTabRef } from '@alfresco/adf-extensions';
|
import { SidebarTabRef } from '@alfresco/adf-extensions';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { AppStore } from '../../store/states/app.state';
|
||||||
|
import { SetInfoDrawerStateAction } from '../../store/actions';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'aca-info-drawer',
|
selector: 'aca-info-drawer',
|
||||||
templateUrl: './info-drawer.component.html'
|
templateUrl: './info-drawer.component.html'
|
||||||
})
|
})
|
||||||
export class InfoDrawerComponent implements OnChanges, OnInit {
|
export class InfoDrawerComponent implements OnChanges, OnInit, OnDestroy {
|
||||||
@Input()
|
@Input()
|
||||||
nodeId: string;
|
nodeId: string;
|
||||||
@Input()
|
@Input()
|
||||||
node: MinimalNodeEntity;
|
node: MinimalNodeEntity;
|
||||||
|
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
displayNode: MinimalNodeEntryEntity;
|
displayNode: MinimalNodeEntryEntity | SiteEntry;
|
||||||
tabs: Array<SidebarTabRef> = [];
|
tabs: Array<SidebarTabRef> = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
private store: Store<AppStore>,
|
||||||
private contentApi: ContentApiService,
|
private contentApi: ContentApiService,
|
||||||
private extensions: AppExtensionService
|
private extensions: AppExtensionService
|
||||||
) {}
|
) {}
|
||||||
@@ -52,22 +60,31 @@ export class InfoDrawerComponent implements OnChanges, OnInit {
|
|||||||
this.tabs = this.extensions.getSidebarTabs();
|
this.tabs = this.extensions.getSidebarTabs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
this.store.dispatch(new SetInfoDrawerStateAction(false));
|
||||||
|
}
|
||||||
|
|
||||||
ngOnChanges() {
|
ngOnChanges() {
|
||||||
if (this.node) {
|
if (this.node) {
|
||||||
const entry = this.node.entry;
|
const entry = this.node.entry;
|
||||||
if (entry.nodeId) {
|
|
||||||
this.loadNodeInfo(entry.nodeId);
|
if (this.isLibraryListNode(this.node)) {
|
||||||
} else if ((<any>entry).guid) {
|
return this.setDisplayNode(this.node);
|
||||||
// workaround for Favorite files
|
|
||||||
this.loadNodeInfo(entry.id);
|
|
||||||
} else {
|
|
||||||
// workaround Recent
|
|
||||||
if (this.isTypeImage(entry) && !this.hasAspectNames(entry)) {
|
|
||||||
this.loadNodeInfo(this.node.entry.id);
|
|
||||||
} else {
|
|
||||||
this.setDisplayNode(this.node.entry);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.isSharedFilesNode(this.node)) {
|
||||||
|
return this.loadNodeInfo(entry.nodeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isFavoriteListNode(this.node)) {
|
||||||
|
return this.loadNodeInfo(entry.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isRecentListFileNode(this.node)) {
|
||||||
|
return this.loadNodeInfo(entry.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setDisplayNode(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +113,23 @@ export class InfoDrawerComponent implements OnChanges, OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private setDisplayNode(node: MinimalNodeEntryEntity) {
|
private setDisplayNode(node: MinimalNodeEntryEntity | SiteEntry) {
|
||||||
this.displayNode = node;
|
this.displayNode = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private isLibraryListNode(node: SiteEntry): boolean {
|
||||||
|
return (<any>node).isLibrary;
|
||||||
|
}
|
||||||
|
|
||||||
|
private isFavoriteListNode(node: MinimalNodeEntity): boolean {
|
||||||
|
return !this.isLibraryListNode(node) && (<any>node).entry.guid;
|
||||||
|
}
|
||||||
|
|
||||||
|
private isSharedFilesNode(node: MinimalNodeEntity): boolean {
|
||||||
|
return !!node.entry.nodeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private isRecentListFileNode(node: MinimalNodeEntity): boolean {
|
||||||
|
return this.isTypeImage(node.entry) && !this.hasAspectNames(node.entry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -36,6 +36,8 @@ import { MaterialModule } from '../../material.module';
|
|||||||
import { CommentsTabComponent } from './comments-tab/comments-tab.component';
|
import { CommentsTabComponent } from './comments-tab/comments-tab.component';
|
||||||
import { InfoDrawerComponent } from './info-drawer.component';
|
import { InfoDrawerComponent } from './info-drawer.component';
|
||||||
import { MetadataTabComponent } from './metadata-tab/metadata-tab.component';
|
import { MetadataTabComponent } from './metadata-tab/metadata-tab.component';
|
||||||
|
import { LibraryMetadataTabComponent } from './library-metadata-tab/library-metadata-tab.component';
|
||||||
|
import { LibraryMetadataFormComponent } from './library-metadata-tab/library-metadata-form.component';
|
||||||
import { VersionsTabComponent } from './versions-tab/versions-tab.component';
|
import { VersionsTabComponent } from './versions-tab/versions-tab.component';
|
||||||
|
|
||||||
export function components() {
|
export function components() {
|
||||||
@@ -43,7 +45,9 @@ export function components() {
|
|||||||
InfoDrawerComponent,
|
InfoDrawerComponent,
|
||||||
MetadataTabComponent,
|
MetadataTabComponent,
|
||||||
CommentsTabComponent,
|
CommentsTabComponent,
|
||||||
VersionsTabComponent
|
VersionsTabComponent,
|
||||||
|
LibraryMetadataTabComponent,
|
||||||
|
LibraryMetadataFormComponent
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -0,0 +1,124 @@
|
|||||||
|
<mat-card *ngIf="node">
|
||||||
|
<mat-card-content *ngIf="!edit">
|
||||||
|
<div class="mat-form-field mat-form-field-type-mat-input mat-form-field-can-float mat-form-field-should-float adf-full-width">
|
||||||
|
<div class="mat-form-field-wrapper">
|
||||||
|
<div class="mat-form-field-flex">
|
||||||
|
<div class="mat-form-field-infix">
|
||||||
|
<span class="mat-form-field-label-wrapper">
|
||||||
|
<span class="mat-form-field-label">
|
||||||
|
{{ 'LIBRARY.DIALOG.FORM.NAME' | translate }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="mat-input-element">
|
||||||
|
{{ form.controls.title.value }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mat-form-field mat-primary mat-form-field-type-mat-input mat-form-field-can-float mat-form-field-should-float adf-full-width">
|
||||||
|
<div class="mat-form-field-wrapper">
|
||||||
|
<div class="mat-form-field-flex">
|
||||||
|
<div class="mat-form-field-infix">
|
||||||
|
<span class="mat-form-field-label-wrapper">
|
||||||
|
<span class="mat-form-field-label">
|
||||||
|
{{ 'LIBRARY.DIALOG.FORM.SITE_ID' | translate }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="mat-input-element">
|
||||||
|
{{ form.controls.id.value }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mat-form-field mat-primary mat-form-field-type-mat-input mat-form-field-can-float mat-form-field-should-float adf-full-width">
|
||||||
|
<div class="mat-form-field-wrapper">
|
||||||
|
<div class="mat-form-field-flex">
|
||||||
|
<div class="mat-form-field-infix">
|
||||||
|
<span class="mat-form-field-label-wrapper">
|
||||||
|
<span class="mat-form-field-label">
|
||||||
|
{{ 'LIBRARY.DIALOG.FORM.TYPE' | translate }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="mat-input-element">
|
||||||
|
{{ (getVisibilityLabel(form.controls.visibility.value)) | translate }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mat-form-field mat-primary mat-form-field-type-mat-input mat-form-field-can-float mat-form-field-should-float adf-full-width">
|
||||||
|
<div class="mat-form-field-wrapper">
|
||||||
|
<div class="mat-form-field-flex">
|
||||||
|
<div class="mat-form-field-infix">
|
||||||
|
<span class="mat-form-field-label-wrapper">
|
||||||
|
<span class="mat-form-field-label">
|
||||||
|
{{ 'LIBRARY.DIALOG.FORM.DESCRIPTION' | translate }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="mat-input-element">
|
||||||
|
{{ form.controls.description?.value }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mat-card-content>
|
||||||
|
|
||||||
|
<mat-card-actions align="end" *ngIf="!edit">
|
||||||
|
<button mat-button color="primary" (click)="toggleEdit()">
|
||||||
|
{{ 'LIBRARY.DIALOG.EDIT' | translate }}
|
||||||
|
</button>
|
||||||
|
</mat-card-actions>
|
||||||
|
|
||||||
|
<mat-card-content *ngIf="edit">
|
||||||
|
<form [formGroup]="form" autocomplete="off">
|
||||||
|
<mat-form-field class="adf-full-width">
|
||||||
|
<input matInput cdkFocusInitial required placeholder="{{ 'LIBRARY.DIALOG.FORM.NAME' | translate }}"
|
||||||
|
formControlName="title">
|
||||||
|
|
||||||
|
<mat-error *ngIf="form.controls['title'].hasError('maxlength')">
|
||||||
|
{{ 'LIBRARY.ERRORS.TITLE_TOO_LONG' | translate }}
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field class="adf-full-width">
|
||||||
|
<input matInput placeholder="{{ 'LIBRARY.DIALOG.FORM.SITE_ID' | translate }}" formControlName="id">
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field class="adf-full-width">
|
||||||
|
<mat-select placeholder="{{ 'LIBRARY.DIALOG.FORM.TYPE' | translate }}" formControlName="visibility">
|
||||||
|
<mat-option [value]="type.value" *ngFor="let type of libraryType">
|
||||||
|
{{ type.label | translate }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field class="adf-full-width">
|
||||||
|
<textarea matInput placeholder="{{ 'LIBRARY.DIALOG.FORM.DESCRIPTION' | translate }}" rows="3"
|
||||||
|
formControlName="description"></textarea>
|
||||||
|
|
||||||
|
<mat-error *ngIf="form.controls['description'].hasError('maxlength')">
|
||||||
|
{{ 'LIBRARY.ERRORS.DESCRIPTION_TOO_LONG' | translate }}
|
||||||
|
</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
</mat-card-content>
|
||||||
|
|
||||||
|
<mat-card-actions align="end" *ngIf="edit && canUpdateLibrary">
|
||||||
|
<button mat-button color="secondary" (click)="cancel()">
|
||||||
|
{{ 'LIBRARY.DIALOG.CANCEL' | translate }}
|
||||||
|
</button>
|
||||||
|
<button mat-button color="primary" [disabled]="form.invalid" (click)="update()">
|
||||||
|
{{ 'LIBRARY.DIALOG.UPDATE' | translate }}
|
||||||
|
</button>
|
||||||
|
</mat-card-actions>
|
||||||
|
</mat-card>
|
@@ -0,0 +1,214 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Alfresco Example Content Application
|
||||||
|
*
|
||||||
|
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
import { LibraryMetadataFormComponent } from './library-metadata-form.component';
|
||||||
|
import { TestBed, ComponentFixture } from '@angular/core/testing';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { UpdateLibraryAction } from '../../../store/actions';
|
||||||
|
import { AppTestingModule } from '../../../testing/app-testing.module';
|
||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { Site, SiteBody } from 'alfresco-js-api';
|
||||||
|
|
||||||
|
describe('LibraryMetadataFormComponent', () => {
|
||||||
|
let fixture: ComponentFixture<LibraryMetadataFormComponent>;
|
||||||
|
let component: LibraryMetadataFormComponent;
|
||||||
|
const storeMock = {
|
||||||
|
dispatch: jasmine.createSpy('dispatch')
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [AppTestingModule],
|
||||||
|
declarations: [LibraryMetadataFormComponent],
|
||||||
|
providers: [{ provide: Store, useValue: storeMock }],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
});
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(LibraryMetadataFormComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
storeMock.dispatch.calls.reset();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should initialize form with node data', () => {
|
||||||
|
const siteEntryModel = {
|
||||||
|
title: 'libraryTitle',
|
||||||
|
description: 'description',
|
||||||
|
visibility: 'PRIVATE'
|
||||||
|
};
|
||||||
|
component.node = {
|
||||||
|
entry: <Site>{
|
||||||
|
id: 'libraryId',
|
||||||
|
...siteEntryModel
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
expect(component.form.value).toEqual(siteEntryModel);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update form data when node data changes', () => {
|
||||||
|
const siteEntryModel = {
|
||||||
|
title: 'libraryTitle',
|
||||||
|
description: 'description',
|
||||||
|
visibility: 'PRIVATE'
|
||||||
|
};
|
||||||
|
|
||||||
|
const newSiteEntryModel = {
|
||||||
|
title: 'libraryTitle2',
|
||||||
|
description: 'description2',
|
||||||
|
visibility: 'PUBLIC'
|
||||||
|
};
|
||||||
|
|
||||||
|
component.node = {
|
||||||
|
entry: <Site>{
|
||||||
|
id: 'libraryId',
|
||||||
|
...siteEntryModel
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
expect(component.form.value).toEqual(siteEntryModel);
|
||||||
|
|
||||||
|
component.node = {
|
||||||
|
entry: <Site>{
|
||||||
|
id: 'libraryId',
|
||||||
|
...newSiteEntryModel
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
component.ngOnChanges();
|
||||||
|
|
||||||
|
expect(component.form.value).toEqual(newSiteEntryModel);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update library node if form is valid', () => {
|
||||||
|
const siteEntryModel = {
|
||||||
|
title: 'libraryTitle',
|
||||||
|
description: 'description',
|
||||||
|
visibility: 'PRIVATE'
|
||||||
|
};
|
||||||
|
component.node = {
|
||||||
|
entry: <Site>{
|
||||||
|
id: 'libraryId',
|
||||||
|
role: 'SiteManager',
|
||||||
|
...siteEntryModel
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
component.update();
|
||||||
|
|
||||||
|
expect(storeMock.dispatch).toHaveBeenCalledWith(
|
||||||
|
new UpdateLibraryAction(<SiteBody>siteEntryModel)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not update library node if it has no permission', () => {
|
||||||
|
const siteEntryModel = {
|
||||||
|
title: 'libraryTitle',
|
||||||
|
description: 'description',
|
||||||
|
visibility: 'PRIVATE'
|
||||||
|
};
|
||||||
|
component.node = {
|
||||||
|
entry: <Site>{
|
||||||
|
id: 'libraryId',
|
||||||
|
role: 'Consumer',
|
||||||
|
...siteEntryModel
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
component.update();
|
||||||
|
|
||||||
|
expect(storeMock.dispatch).not.toHaveBeenCalledWith(
|
||||||
|
new UpdateLibraryAction(<SiteBody>siteEntryModel)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not update library node if form is invalid', () => {
|
||||||
|
const siteEntryModel = {
|
||||||
|
title: 'libraryTitle',
|
||||||
|
description: 'description',
|
||||||
|
visibility: 'PRIVATE'
|
||||||
|
};
|
||||||
|
component.node = {
|
||||||
|
entry: <Site>{
|
||||||
|
id: 'libraryId',
|
||||||
|
role: 'SiteManager',
|
||||||
|
...siteEntryModel
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
component.form.controls['title'].setErrors({ maxlength: true });
|
||||||
|
|
||||||
|
component.update();
|
||||||
|
|
||||||
|
expect(storeMock.dispatch).not.toHaveBeenCalledWith(
|
||||||
|
new UpdateLibraryAction(<SiteBody>siteEntryModel)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should toggle edit mode', () => {
|
||||||
|
component.edit = false;
|
||||||
|
|
||||||
|
component.toggleEdit();
|
||||||
|
expect(component.edit).toBe(true);
|
||||||
|
|
||||||
|
component.toggleEdit();
|
||||||
|
expect(component.edit).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should cancel from changes', () => {
|
||||||
|
const siteEntryModel = {
|
||||||
|
title: 'libraryTitle',
|
||||||
|
description: 'description',
|
||||||
|
visibility: 'PRIVATE'
|
||||||
|
};
|
||||||
|
component.node = {
|
||||||
|
entry: <Site>{
|
||||||
|
id: 'libraryId',
|
||||||
|
...siteEntryModel
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
expect(component.form.value).toEqual(siteEntryModel);
|
||||||
|
|
||||||
|
component.form.controls.title.setValue('libraryTitle-edit');
|
||||||
|
|
||||||
|
expect(component.form.value.title).toBe('libraryTitle-edit');
|
||||||
|
|
||||||
|
component.cancel();
|
||||||
|
|
||||||
|
expect(component.form.value).toEqual(siteEntryModel);
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,104 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Alfresco Example Content Application
|
||||||
|
*
|
||||||
|
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Component, Input, OnInit, OnChanges } from '@angular/core';
|
||||||
|
import { FormGroup, FormControl, Validators } from '@angular/forms';
|
||||||
|
import { SiteEntry } from 'alfresco-js-api';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { UpdateLibraryAction } from '../../../store/actions';
|
||||||
|
import { AppStore } from '../../../store/states/app.state';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-library-metadata-form',
|
||||||
|
templateUrl: './library-metadata-form.component.html'
|
||||||
|
})
|
||||||
|
export class LibraryMetadataFormComponent implements OnInit, OnChanges {
|
||||||
|
@Input()
|
||||||
|
node: SiteEntry;
|
||||||
|
|
||||||
|
edit: boolean;
|
||||||
|
|
||||||
|
libraryType = [
|
||||||
|
{ value: 'PUBLIC', label: 'LIBRARY.VISIBILITY.PUBLIC' },
|
||||||
|
{ value: 'PRIVATE', label: 'LIBRARY.VISIBILITY.PRIVATE' },
|
||||||
|
{ value: 'MODERATED', label: 'LIBRARY.VISIBILITY.MODERATED' }
|
||||||
|
];
|
||||||
|
|
||||||
|
form: FormGroup = new FormGroup({
|
||||||
|
id: new FormControl({ value: '', disabled: true }),
|
||||||
|
title: new FormControl({ value: '' }, [
|
||||||
|
Validators.required,
|
||||||
|
Validators.maxLength(256)
|
||||||
|
]),
|
||||||
|
description: new FormControl({ value: '' }, [Validators.maxLength(512)]),
|
||||||
|
visibility: new FormControl(this.libraryType[0].value)
|
||||||
|
});
|
||||||
|
|
||||||
|
constructor(protected store: Store<AppStore>) {}
|
||||||
|
|
||||||
|
get canUpdateLibrary() {
|
||||||
|
return (
|
||||||
|
this.node && this.node.entry && this.node.entry.role === 'SiteManager'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getVisibilityLabel(value) {
|
||||||
|
return this.libraryType.find(type => type.value === value).label;
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleEdit() {
|
||||||
|
this.edit = !this.edit;
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel() {
|
||||||
|
this.updateForm(this.node);
|
||||||
|
this.toggleEdit();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.updateForm(this.node);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnChanges() {
|
||||||
|
this.updateForm(this.node);
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
if (this.canUpdateLibrary && this.form.valid) {
|
||||||
|
this.store.dispatch(new UpdateLibraryAction(this.form.value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateForm(node: SiteEntry) {
|
||||||
|
const { entry } = node;
|
||||||
|
|
||||||
|
this.form.setValue({
|
||||||
|
id: entry.id,
|
||||||
|
title: entry.title,
|
||||||
|
description: entry.description || '',
|
||||||
|
visibility: entry.visibility
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,38 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Alfresco Example Content Application
|
||||||
|
*
|
||||||
|
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
import { SiteEntry } from 'alfresco-js-api';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-metadata-tab',
|
||||||
|
template:
|
||||||
|
'<app-library-metadata-form [node]="node"></app-library-metadata-form>',
|
||||||
|
host: { class: 'app-metadata-tab' }
|
||||||
|
})
|
||||||
|
export class LibraryMetadataTabComponent {
|
||||||
|
@Input()
|
||||||
|
node: SiteEntry;
|
||||||
|
}
|
@@ -75,5 +75,9 @@
|
|||||||
<adf-pagination acaPagination [target]="documentList">
|
<adf-pagination acaPagination [target]="documentList">
|
||||||
</adf-pagination>
|
</adf-pagination>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar" *ngIf="infoDrawerOpened$ | async">
|
||||||
|
<aca-info-drawer [node]="selection.library"></aca-info-drawer>
|
||||||
|
</div>
|
||||||
</app-page-layout-content>
|
</app-page-layout-content>
|
||||||
</app-page-layout>
|
</app-page-layout>
|
||||||
|
@@ -63,6 +63,10 @@ export class LibrariesComponent extends PageComponent implements OnInit {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.subscriptions = this.subscriptions.concat([
|
||||||
|
this.content.libraryUpdated.subscribe(() => this.documentList.reload())
|
||||||
|
]);
|
||||||
|
|
||||||
this.columns = this.extensions.documentListPresets.libraries || [];
|
this.columns = this.extensions.documentListPresets.libraries || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -35,6 +35,7 @@ import { ToggleInfoDrawerComponent } from '../components/toolbar/toggle-info-dra
|
|||||||
import { ToggleFavoriteComponent } from '../components/toolbar/toggle-favorite/toggle-favorite.component';
|
import { ToggleFavoriteComponent } from '../components/toolbar/toggle-favorite/toggle-favorite.component';
|
||||||
import { ToggleSharedComponent } from '../components/shared/toggle-shared/toggle-shared.component';
|
import { ToggleSharedComponent } from '../components/shared/toggle-shared/toggle-shared.component';
|
||||||
import { MetadataTabComponent } from '../components/info-drawer/metadata-tab/metadata-tab.component';
|
import { MetadataTabComponent } from '../components/info-drawer/metadata-tab/metadata-tab.component';
|
||||||
|
import { LibraryMetadataTabComponent } from '../components/info-drawer/library-metadata-tab/library-metadata-tab.component';
|
||||||
import { CommentsTabComponent } from '../components/info-drawer/comments-tab/comments-tab.component';
|
import { CommentsTabComponent } from '../components/info-drawer/comments-tab/comments-tab.component';
|
||||||
import { VersionsTabComponent } from '../components/info-drawer/versions-tab/versions-tab.component';
|
import { VersionsTabComponent } from '../components/info-drawer/versions-tab/versions-tab.component';
|
||||||
import { ExtensionsModule, ExtensionService } from '@alfresco/adf-extensions';
|
import { ExtensionsModule, ExtensionService } from '@alfresco/adf-extensions';
|
||||||
@@ -77,6 +78,7 @@ export class CoreExtensionsModule {
|
|||||||
extensions.setComponents({
|
extensions.setComponents({
|
||||||
'app.layout.main': AppLayoutComponent,
|
'app.layout.main': AppLayoutComponent,
|
||||||
'app.components.tabs.metadata': MetadataTabComponent,
|
'app.components.tabs.metadata': MetadataTabComponent,
|
||||||
|
'app.components.tabs.library.metadata': LibraryMetadataTabComponent,
|
||||||
'app.components.tabs.comments': CommentsTabComponent,
|
'app.components.tabs.comments': CommentsTabComponent,
|
||||||
'app.components.tabs.versions': VersionsTabComponent,
|
'app.components.tabs.versions': VersionsTabComponent,
|
||||||
'app.toolbar.toggleInfoDrawer': ToggleInfoDrawerComponent,
|
'app.toolbar.toggleInfoDrawer': ToggleInfoDrawerComponent,
|
||||||
|
@@ -243,7 +243,7 @@ export class AppExtensionService implements RuleContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getSidebarTabs(): Array<SidebarTabRef> {
|
getSidebarTabs(): Array<SidebarTabRef> {
|
||||||
return this.sidebar;
|
return this.sidebar.filter(action => this.filterByRules(<any>action));
|
||||||
}
|
}
|
||||||
|
|
||||||
getComponentById(id: string): Type<{}> {
|
getComponentById(id: string): Type<{}> {
|
||||||
|
@@ -219,6 +219,10 @@ export class ContentApiService {
|
|||||||
return from(this.api.sitesApi.getSite(siteId, opts));
|
return from(this.api.sitesApi.getSite(siteId, opts));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateLibrary(siteId: string, siteBody: SiteBody): Observable<SiteEntry> {
|
||||||
|
return from(this.api.sitesApi.updateSite(siteId, siteBody));
|
||||||
|
}
|
||||||
|
|
||||||
addFavorite(nodes: Array<MinimalNodeEntity>): Observable<any> {
|
addFavorite(nodes: Array<MinimalNodeEntity>): Observable<any> {
|
||||||
const payload: FavoriteBody[] = nodes.map(node => {
|
const payload: FavoriteBody[] = nodes.map(node => {
|
||||||
const { isFolder, nodeId, id } = node.entry;
|
const { isFolder, nodeId, id } = node.entry;
|
||||||
|
@@ -49,7 +49,8 @@ import {
|
|||||||
Node,
|
Node,
|
||||||
SiteEntry,
|
SiteEntry,
|
||||||
DeletedNodesPaging,
|
DeletedNodesPaging,
|
||||||
PathInfoEntity
|
PathInfoEntity,
|
||||||
|
SiteBody
|
||||||
} from 'alfresco-js-api';
|
} from 'alfresco-js-api';
|
||||||
import { NodePermissionService } from './node-permission.service';
|
import { NodePermissionService } from './node-permission.service';
|
||||||
import { NodeInfo, DeletedNodeInfo, DeleteStatus } from '../store/models';
|
import { NodeInfo, DeletedNodeInfo, DeleteStatus } from '../store/models';
|
||||||
@@ -80,6 +81,7 @@ export class ContentManagementService {
|
|||||||
folderCreated = new Subject<any>();
|
folderCreated = new Subject<any>();
|
||||||
libraryDeleted = new Subject<string>();
|
libraryDeleted = new Subject<string>();
|
||||||
libraryCreated = new Subject<SiteEntry>();
|
libraryCreated = new Subject<SiteEntry>();
|
||||||
|
libraryUpdated = new Subject<SiteEntry>();
|
||||||
linksUnshared = new Subject<any>();
|
linksUnshared = new Subject<any>();
|
||||||
favoriteAdded = new Subject<Array<MinimalNodeEntity>>();
|
favoriteAdded = new Subject<Array<MinimalNodeEntity>>();
|
||||||
favoriteRemoved = new Subject<Array<MinimalNodeEntity>>();
|
favoriteRemoved = new Subject<Array<MinimalNodeEntity>>();
|
||||||
@@ -295,6 +297,22 @@ export class ContentManagementService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateLibrary(siteId: string, siteBody: SiteBody) {
|
||||||
|
this.contentApi.updateLibrary(siteId, siteBody).subscribe(
|
||||||
|
(siteEntry: SiteEntry) => {
|
||||||
|
this.libraryUpdated.next(siteEntry);
|
||||||
|
this.store.dispatch(
|
||||||
|
new SnackbarInfoAction('LIBRARY.SUCCESS.LIBRARY_UPDATED')
|
||||||
|
);
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
this.store.dispatch(
|
||||||
|
new SnackbarErrorAction('LIBRARY.ERRORS.LIBRARY_UPDATE_ERROR')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async unshareNodes(links: Array<MinimalNodeEntity>) {
|
async unshareNodes(links: Array<MinimalNodeEntity>) {
|
||||||
const promises = links.map(link =>
|
const promises = links.map(link =>
|
||||||
this.contentApi.deleteSharedLink(link.entry.id).toPromise()
|
this.contentApi.deleteSharedLink(link.entry.id).toPromise()
|
||||||
|
@@ -34,3 +34,4 @@ export * from './actions/library.actions';
|
|||||||
export * from './actions/upload.actions';
|
export * from './actions/upload.actions';
|
||||||
export * from './actions/modals.actions';
|
export * from './actions/modals.actions';
|
||||||
export * from './actions/repository.actions';
|
export * from './actions/repository.actions';
|
||||||
|
export * from './actions/info-drawer.actions';
|
||||||
|
33
src/app/store/actions/info-drawer.actions.ts
Normal file
33
src/app/store/actions/info-drawer.actions.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Alfresco Example Content Application
|
||||||
|
*
|
||||||
|
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Action } from '@ngrx/store';
|
||||||
|
|
||||||
|
export const SET_INFO_DRAWER_STATE = 'SET_INFO_DRAWER_STATE';
|
||||||
|
|
||||||
|
export class SetInfoDrawerStateAction implements Action {
|
||||||
|
readonly type = SET_INFO_DRAWER_STATE;
|
||||||
|
constructor(public payload: boolean) {}
|
||||||
|
}
|
@@ -24,10 +24,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Action } from '@ngrx/store';
|
import { Action } from '@ngrx/store';
|
||||||
|
import { SiteBody } from 'alfresco-js-api';
|
||||||
|
|
||||||
export const DELETE_LIBRARY = 'DELETE_LIBRARY';
|
export const DELETE_LIBRARY = 'DELETE_LIBRARY';
|
||||||
export const CREATE_LIBRARY = 'CREATE_LIBRARY';
|
export const CREATE_LIBRARY = 'CREATE_LIBRARY';
|
||||||
export const NAVIGATE_LIBRARY = 'NAVIGATE_LIBRARY';
|
export const NAVIGATE_LIBRARY = 'NAVIGATE_LIBRARY';
|
||||||
|
export const UPDATE_LIBRARY = 'UPDATE_LIBRARY';
|
||||||
|
|
||||||
export class DeleteLibraryAction implements Action {
|
export class DeleteLibraryAction implements Action {
|
||||||
readonly type = DELETE_LIBRARY;
|
readonly type = DELETE_LIBRARY;
|
||||||
@@ -43,3 +45,7 @@ export class NavigateLibraryAction implements Action {
|
|||||||
readonly type = NAVIGATE_LIBRARY;
|
readonly type = NAVIGATE_LIBRARY;
|
||||||
constructor(public payload?: string) {}
|
constructor(public payload?: string) {}
|
||||||
}
|
}
|
||||||
|
export class UpdateLibraryAction implements Action {
|
||||||
|
readonly type = UPDATE_LIBRARY;
|
||||||
|
constructor(public payload?: SiteBody) {}
|
||||||
|
}
|
||||||
|
@@ -32,7 +32,9 @@ import {
|
|||||||
CreateLibraryAction,
|
CreateLibraryAction,
|
||||||
CREATE_LIBRARY,
|
CREATE_LIBRARY,
|
||||||
NavigateLibraryAction,
|
NavigateLibraryAction,
|
||||||
NAVIGATE_LIBRARY
|
NAVIGATE_LIBRARY,
|
||||||
|
UPDATE_LIBRARY,
|
||||||
|
UpdateLibraryAction
|
||||||
} from '../actions';
|
} from '../actions';
|
||||||
import { ContentManagementService } from '../../services/content-management.service';
|
import { ContentManagementService } from '../../services/content-management.service';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
@@ -40,6 +42,7 @@ import { AppStore } from '../states';
|
|||||||
import { appSelection } from '../selectors/app.selectors';
|
import { appSelection } from '../selectors/app.selectors';
|
||||||
import { ContentApiService } from '../../services/content-api.service';
|
import { ContentApiService } from '../../services/content-api.service';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
import { SiteBody } from 'alfresco-js-api-node';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class LibraryEffects {
|
export class LibraryEffects {
|
||||||
@@ -92,4 +95,28 @@ export class LibraryEffects {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@Effect({ dispatch: false })
|
||||||
|
updateLibrary$ = this.actions$.pipe(
|
||||||
|
ofType<UpdateLibraryAction>(UPDATE_LIBRARY),
|
||||||
|
map(action => {
|
||||||
|
this.store
|
||||||
|
.select(appSelection)
|
||||||
|
.pipe(take(1))
|
||||||
|
.subscribe(selection => {
|
||||||
|
if (selection && selection.library) {
|
||||||
|
const { id } = selection.library.entry;
|
||||||
|
const { title, description, visibility } = action.payload;
|
||||||
|
|
||||||
|
const siteBody = <SiteBody>{
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
visibility
|
||||||
|
};
|
||||||
|
|
||||||
|
this.content.updateLibrary(id, siteBody);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@@ -37,7 +37,9 @@ import {
|
|||||||
SET_CURRENT_FOLDER,
|
SET_CURRENT_FOLDER,
|
||||||
SetCurrentFolderAction,
|
SetCurrentFolderAction,
|
||||||
SET_CURRENT_URL,
|
SET_CURRENT_URL,
|
||||||
SetCurrentUrlAction
|
SetCurrentUrlAction,
|
||||||
|
SET_INFO_DRAWER_STATE,
|
||||||
|
SetInfoDrawerStateAction
|
||||||
} from '../actions';
|
} from '../actions';
|
||||||
import {
|
import {
|
||||||
TOGGLE_INFO_DRAWER,
|
TOGGLE_INFO_DRAWER,
|
||||||
@@ -76,6 +78,9 @@ export function appReducer(
|
|||||||
case TOGGLE_INFO_DRAWER:
|
case TOGGLE_INFO_DRAWER:
|
||||||
newState = updateInfoDrawer(state, <ToggleInfoDrawerAction>action);
|
newState = updateInfoDrawer(state, <ToggleInfoDrawerAction>action);
|
||||||
break;
|
break;
|
||||||
|
case SET_INFO_DRAWER_STATE:
|
||||||
|
newState = setInfoDrawer(state, <SetInfoDrawerStateAction>action);
|
||||||
|
break;
|
||||||
case TOGGLE_DOCUMENT_DISPLAY_MODE:
|
case TOGGLE_DOCUMENT_DISPLAY_MODE:
|
||||||
newState = updateDocumentDisplayMode(state, <ToggleDocumentDisplayMode>(
|
newState = updateDocumentDisplayMode(state, <ToggleDocumentDisplayMode>(
|
||||||
action
|
action
|
||||||
@@ -215,6 +220,12 @@ function updateSelectedNodes(
|
|||||||
return newState;
|
return newState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setInfoDrawer(state: AppState, action: SetInfoDrawerStateAction) {
|
||||||
|
const newState = Object.assign({}, state);
|
||||||
|
newState.infoDrawerOpened = action.payload;
|
||||||
|
return newState;
|
||||||
|
}
|
||||||
|
|
||||||
function updateRepositoryStatus(
|
function updateRepositoryStatus(
|
||||||
state: AppState,
|
state: AppState,
|
||||||
action: SetRepositoryStatusAction
|
action: SetRepositoryStatusAction
|
||||||
|
@@ -99,6 +99,14 @@
|
|||||||
{ "type": "rule", "value": "app.navigation.isNotTrashcan" }
|
{ "type": "rule", "value": "app.navigation.isNotTrashcan" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "app.libraries.toolbar.info",
|
||||||
|
"type": "core.every",
|
||||||
|
"parameters": [
|
||||||
|
{ "type": "rule", "value": "app.selection.notEmpty" },
|
||||||
|
{ "type": "rule", "value": "app.navigation.isLibraries" }
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "app.toolbar.canCopyNode",
|
"id": "app.toolbar.canCopyNode",
|
||||||
"type": "core.every",
|
"type": "core.every",
|
||||||
@@ -361,6 +369,15 @@
|
|||||||
"visible": "app.toolbar.info"
|
"visible": "app.toolbar.info"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "app.libraries.toolbar.info",
|
||||||
|
"type": "custom",
|
||||||
|
"order": 701,
|
||||||
|
"component": "app.toolbar.toggleInfoDrawer",
|
||||||
|
"rules": {
|
||||||
|
"visible": "app.libraries.toolbar.info"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "app.toolbar.more",
|
"id": "app.toolbar.more",
|
||||||
"type": "menu",
|
"type": "menu",
|
||||||
@@ -827,20 +844,38 @@
|
|||||||
"id": "app.sidebar.properties",
|
"id": "app.sidebar.properties",
|
||||||
"order": 100,
|
"order": 100,
|
||||||
"title": "APP.INFO_DRAWER.TABS.PROPERTIES",
|
"title": "APP.INFO_DRAWER.TABS.PROPERTIES",
|
||||||
"component": "app.components.tabs.metadata"
|
"component": "app.components.tabs.metadata",
|
||||||
|
"rules": {
|
||||||
|
"visible": "app.navigation.isNotLibraries"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "app.sidebar.comments",
|
"id": "app.sidebar.comments",
|
||||||
"order": 200,
|
"order": 200,
|
||||||
"title": "APP.INFO_DRAWER.TABS.COMMENTS",
|
"title": "APP.INFO_DRAWER.TABS.COMMENTS",
|
||||||
"component": "app.components.tabs.comments"
|
"component": "app.components.tabs.comments",
|
||||||
|
"rules": {
|
||||||
|
"visible": "app.navigation.isNotLibraries"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "app.sidebar.versions",
|
"id": "app.sidebar.versions",
|
||||||
"order": 300,
|
"order": 300,
|
||||||
"disabled": true,
|
"disabled": true,
|
||||||
"title": "APP.INFO_DRAWER.TABS.VERSIONS",
|
"title": "APP.INFO_DRAWER.TABS.VERSIONS",
|
||||||
"component": "app.components.tabs.versions"
|
"component": "app.components.tabs.versions",
|
||||||
|
"rules": {
|
||||||
|
"visible": "app.navigation.isNotLibraries"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "test",
|
||||||
|
"order": 500,
|
||||||
|
"title": "APP.INFO_DRAWER.TABS.LIBRARY_PROPERTIES",
|
||||||
|
"component": "app.components.tabs.library.metadata",
|
||||||
|
"rules": {
|
||||||
|
"visible": "app.libraries.toolbar.info"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"content-metadata-presets": [
|
"content-metadata-presets": [
|
||||||
|
@@ -245,6 +245,7 @@
|
|||||||
"TITLE": "Details",
|
"TITLE": "Details",
|
||||||
"TABS": {
|
"TABS": {
|
||||||
"PROPERTIES": "Properties",
|
"PROPERTIES": "Properties",
|
||||||
|
"LIBRARY_PROPERTIES": "About",
|
||||||
"VERSIONS": "Versions",
|
"VERSIONS": "Versions",
|
||||||
"COMMENTS": "Comments"
|
"COMMENTS": "Comments"
|
||||||
}
|
}
|
||||||
@@ -282,11 +283,14 @@
|
|||||||
"DIALOG": {
|
"DIALOG": {
|
||||||
"CREATE_TITLE": "Create Library",
|
"CREATE_TITLE": "Create Library",
|
||||||
"CREATE": "Create",
|
"CREATE": "Create",
|
||||||
|
"UPDATE": "Update",
|
||||||
|
"EDIT": "Edit",
|
||||||
"CANCEL": "Cancel",
|
"CANCEL": "Cancel",
|
||||||
"FORM": {
|
"FORM": {
|
||||||
"DESCRIPTION": "Description",
|
"DESCRIPTION": "Description",
|
||||||
"SITE_ID": "Library ID",
|
"SITE_ID": "Library ID",
|
||||||
"NAME": "Name"
|
"NAME": "Name",
|
||||||
|
"TYPE": "Type"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"VISIBILITY": {
|
"VISIBILITY": {
|
||||||
@@ -301,7 +305,11 @@
|
|||||||
"ID_TOO_LONG": "Use 72 characters or less for the URL name",
|
"ID_TOO_LONG": "Use 72 characters or less for the URL name",
|
||||||
"DESCRIPTION_TOO_LONG": "Use 512 characters or less for description",
|
"DESCRIPTION_TOO_LONG": "Use 512 characters or less for description",
|
||||||
"TITLE_TOO_LONG": "Use 256 characters or less for title",
|
"TITLE_TOO_LONG": "Use 256 characters or less for title",
|
||||||
"ILLEGAL_CHARACTERS": "Use numbers and letters only"
|
"ILLEGAL_CHARACTERS": "Use numbers and letters only",
|
||||||
|
"LIBRARY_UPDATE_ERROR": "There was an error updating library properties"
|
||||||
|
},
|
||||||
|
"SUCCESS": {
|
||||||
|
"LIBRARY_UPDATED": "Library properties updated"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user