mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-05-26 17:24:45 +00:00
[ACA-19] Toggle join request - library action (#800)
* [ACA-19] join/cancel join library actions * [ACA-19] show the info drawer * [ACA-19] custom icon for join library * [ACA-19] css to 'see' custom icon for extension * [ACA-19] reformat with prettier * [ACA-19] better role display * [ACA-19] simplify cancel request rule * [ACA-19] refactor and use toggle join/cancel join component & directive * [ACA-19] reformat with Prettier * [ACA-19] fix title for svgIcon * [ACA-19] fix translation * [ACA-19] unit test
This commit is contained in:
parent
7734844893
commit
49e80ddce1
@ -70,6 +70,8 @@ import { AppSearchResultsModule } from './components/search/search-results.modul
|
||||
import { AppLoginModule } from './components/login/login.module';
|
||||
import { AppHeaderModule } from './components/header/header.module';
|
||||
import { environment } from '../environments/environment';
|
||||
import { LibraryMembershipDirective } from './directives/library-membership.directive';
|
||||
import { ToggleJoinLibraryComponent } from './components/toolbar/toggle-join-library/toggle-join-library.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@ -110,7 +112,9 @@ import { environment } from '../environments/environment';
|
||||
LibrariesComponent,
|
||||
FavoriteLibrariesComponent,
|
||||
NodeVersionsDialogComponent,
|
||||
LibraryDialogComponent
|
||||
LibraryDialogComponent,
|
||||
LibraryMembershipDirective,
|
||||
ToggleJoinLibraryComponent
|
||||
],
|
||||
providers: [
|
||||
{ provide: RouteReuseStrategy, useClass: AppRouteReuseStrategy },
|
||||
@ -124,7 +128,11 @@ import { environment } from '../environments/environment';
|
||||
}
|
||||
}
|
||||
],
|
||||
entryComponents: [LibraryDialogComponent, NodeVersionsDialogComponent],
|
||||
entryComponents: [
|
||||
LibraryDialogComponent,
|
||||
NodeVersionsDialogComponent,
|
||||
ToggleJoinLibraryComponent
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule {}
|
||||
|
@ -44,6 +44,8 @@ import { currentFolder } from '../../../store/selectors/app.selectors';
|
||||
import { AppStore } from '../../../store/states';
|
||||
import { BreakpointObserver } from '@angular/cdk/layout';
|
||||
import { SetSelectedNodesAction } from '../../../store/actions';
|
||||
import { MatIconRegistry } from '@angular/material';
|
||||
import { DomSanitizer } from '@angular/platform-browser';
|
||||
|
||||
@Component({
|
||||
selector: 'app-layout',
|
||||
@ -68,14 +70,25 @@ export class AppLayoutComponent implements OnInit, OnDestroy {
|
||||
private minimizeConditions: string[] = ['search'];
|
||||
private hideConditions: string[] = ['preview'];
|
||||
|
||||
customIcon: any = {
|
||||
join_library: './assets/images/join-library.svg'
|
||||
};
|
||||
|
||||
constructor(
|
||||
protected store: Store<AppStore>,
|
||||
private permission: NodePermissionService,
|
||||
private router: Router,
|
||||
private userPreferenceService: UserPreferencesService,
|
||||
private appConfigService: AppConfigService,
|
||||
private breakpointObserver: BreakpointObserver
|
||||
) {}
|
||||
private breakpointObserver: BreakpointObserver,
|
||||
matIconRegistry: MatIconRegistry,
|
||||
sanitizer: DomSanitizer
|
||||
) {
|
||||
matIconRegistry.addSvgIcon(
|
||||
'join_library',
|
||||
sanitizer.bypassSecurityTrustResourceUrl(this.customIcon['join_library'])
|
||||
);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.isSmallScreen$ = this.breakpointObserver
|
||||
|
@ -36,6 +36,7 @@ import { PageLayoutComponent } from './page-layout/page-layout.component';
|
||||
import { PageLayoutHeaderComponent } from './page-layout/page-layout-header.component';
|
||||
import { PageLayoutContentComponent } from './page-layout/page-layout-content.component';
|
||||
import { PageLayoutErrorComponent } from './page-layout/page-layout-error.component';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@ -45,7 +46,8 @@ import { PageLayoutErrorComponent } from './page-layout/page-layout-error.compon
|
||||
ContentModule.forChild(),
|
||||
AppCommonModule,
|
||||
AppSidenavModule,
|
||||
AppHeaderModule
|
||||
AppHeaderModule,
|
||||
HttpClientModule
|
||||
],
|
||||
declarations: [
|
||||
AppLayoutComponent,
|
||||
|
@ -73,6 +73,13 @@ export class SearchLibrariesResultsComponent extends PageComponent
|
||||
this.columns = this.extensions.documentListPresets.searchLibraries || [];
|
||||
|
||||
this.subscriptions.push(
|
||||
this.content.libraryJoined.subscribe(() =>
|
||||
this.librariesQueryBuilder.update()
|
||||
),
|
||||
this.content.libraryDeleted.subscribe(() =>
|
||||
this.librariesQueryBuilder.update()
|
||||
),
|
||||
|
||||
this.librariesQueryBuilder.updated.subscribe(() => {
|
||||
this.isLoading = true;
|
||||
|
||||
|
@ -0,0 +1,131 @@
|
||||
/*!
|
||||
* @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 { ToggleJoinLibraryComponent } from './toggle-join-library.component';
|
||||
import { of } from 'rxjs';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { AlfrescoApiService, AlfrescoApiServiceMock } from '@alfresco/adf-core';
|
||||
import { LibraryMembershipDirective } from '../../../directives/library-membership.directive';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import {
|
||||
SnackbarErrorAction,
|
||||
SnackbarInfoAction
|
||||
} from '../../../store/actions/snackbar.actions';
|
||||
import { AppTestingModule } from '../../../testing/app-testing.module';
|
||||
import { ContentManagementService } from '../../../services/content-management.service';
|
||||
|
||||
describe('ToggleJoinLibraryComponent', () => {
|
||||
let component: ToggleJoinLibraryComponent;
|
||||
let fixture: ComponentFixture<ToggleJoinLibraryComponent>;
|
||||
let alfrescoApi: AlfrescoApiService;
|
||||
let contentManagementService: ContentManagementService;
|
||||
let entry;
|
||||
|
||||
const storeMock = {
|
||||
select: () => of({ library: { entry, isLibrary: true } }),
|
||||
dispatch: jasmine.createSpy('dispatch')
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
entry = {
|
||||
id: 'lib-id',
|
||||
joinRequested: true,
|
||||
title: 'test',
|
||||
visibility: 'MODERATED'
|
||||
};
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
imports: [AppTestingModule],
|
||||
declarations: [ToggleJoinLibraryComponent, LibraryMembershipDirective],
|
||||
providers: [
|
||||
{ provide: Store, useValue: storeMock },
|
||||
{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA]
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(ToggleJoinLibraryComponent);
|
||||
component = fixture.componentInstance;
|
||||
alfrescoApi = TestBed.get(AlfrescoApiService);
|
||||
contentManagementService = TestBed.get(ContentManagementService);
|
||||
|
||||
spyOn(alfrescoApi.peopleApi, 'getSiteMembershipRequest').and.stub();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fixture.destroy();
|
||||
storeMock.dispatch.calls.reset();
|
||||
});
|
||||
|
||||
it('should get Store selection entry on initialization', done => {
|
||||
component.selection$.subscribe(selection => {
|
||||
expect(selection.library.entry).toEqual(entry);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should dispatch `SnackbarErrorAction` action on error', () => {
|
||||
const event = { event: {}, i18nKey: 'ERROR_i18nKey' };
|
||||
component.onErrorEvent(event);
|
||||
|
||||
expect(storeMock.dispatch).toHaveBeenCalledWith(
|
||||
new SnackbarErrorAction(event.i18nKey)
|
||||
);
|
||||
});
|
||||
|
||||
it('should dispatch `SnackbarInfoAction` action on onToggleEvent', () => {
|
||||
const event = { shouldReload: true, i18nKey: 'SOME_i18nKey' };
|
||||
component.onToggleEvent(event);
|
||||
|
||||
expect(storeMock.dispatch).toHaveBeenCalledWith(
|
||||
new SnackbarInfoAction(event.i18nKey)
|
||||
);
|
||||
});
|
||||
|
||||
it('should call libraryJoined.next on contentManagementService onToggleEvent', done => {
|
||||
spyOn(contentManagementService.libraryJoined, 'next').and.callThrough();
|
||||
|
||||
contentManagementService.libraryJoined.subscribe(() => {
|
||||
expect(contentManagementService.libraryJoined.next).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
const event = { shouldReload: true };
|
||||
component.onToggleEvent(event);
|
||||
});
|
||||
|
||||
it('should call joinLibraryToggle.next on contentManagementService onToggleEvent', done => {
|
||||
spyOn(contentManagementService.joinLibraryToggle, 'next').and.callThrough();
|
||||
|
||||
contentManagementService.joinLibraryToggle.subscribe(() => {
|
||||
expect(
|
||||
contentManagementService.joinLibraryToggle.next
|
||||
).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
const event = { shouldReload: false };
|
||||
component.onToggleEvent(event);
|
||||
});
|
||||
});
|
@ -0,0 +1,88 @@
|
||||
/*!
|
||||
* @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, ViewEncapsulation } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AppStore } from '../../../store/states';
|
||||
import { appSelection } from '../../../store/selectors/app.selectors';
|
||||
import { Observable } from 'rxjs';
|
||||
import { SelectionState } from '@alfresco/adf-extensions';
|
||||
import { ContentManagementService } from '../../../services/content-management.service';
|
||||
import {
|
||||
SnackbarErrorAction,
|
||||
SnackbarInfoAction
|
||||
} from '../../../store/actions/snackbar.actions';
|
||||
|
||||
@Component({
|
||||
selector: 'app-toggle-join-library',
|
||||
template: `
|
||||
<button
|
||||
mat-icon-button
|
||||
[color]="'primary'"
|
||||
#membership="libraryMembership"
|
||||
(toggle)="onToggleEvent($event)"
|
||||
(error)="onErrorEvent($event)"
|
||||
[acaLibraryMembership]="(selection$ | async).library"
|
||||
[attr.title]="
|
||||
(membership.isJoinRequested | async)
|
||||
? ('APP.ACTIONS.CANCEL_JOIN' | translate)
|
||||
: ('APP.ACTIONS.JOIN' | translate)
|
||||
"
|
||||
>
|
||||
<mat-icon *ngIf="(membership.isJoinRequested | async)">cancel</mat-icon>
|
||||
<mat-icon
|
||||
*ngIf="!(membership.isJoinRequested | async)"
|
||||
svgIcon="join_library"
|
||||
style="pointer-events: none;"
|
||||
></mat-icon>
|
||||
</button>
|
||||
`,
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
host: { class: 'app-toggle-join-library' }
|
||||
})
|
||||
export class ToggleJoinLibraryComponent {
|
||||
selection$: Observable<SelectionState>;
|
||||
|
||||
constructor(
|
||||
private store: Store<AppStore>,
|
||||
private content: ContentManagementService
|
||||
) {
|
||||
this.selection$ = this.store.select(appSelection);
|
||||
}
|
||||
|
||||
onToggleEvent(event) {
|
||||
this.store.dispatch(new SnackbarInfoAction(event.i18nKey));
|
||||
|
||||
if (event.shouldReload) {
|
||||
this.content.libraryJoined.next();
|
||||
} else {
|
||||
this.content.joinLibraryToggle.next();
|
||||
}
|
||||
}
|
||||
|
||||
onErrorEvent(event) {
|
||||
this.store.dispatch(new SnackbarErrorAction(event.i18nKey));
|
||||
}
|
||||
}
|
@ -58,7 +58,8 @@ export class DocumentListDirective implements OnInit, OnDestroy {
|
||||
this.isLibrary =
|
||||
this.documentList.currentFolderId === '-mysites-' ||
|
||||
// workaround for custom node list
|
||||
this.router.url.endsWith('/libraries');
|
||||
this.router.url.endsWith('/libraries') ||
|
||||
this.router.url.startsWith('/search-libraries');
|
||||
|
||||
if (this.sortingPreferenceKey) {
|
||||
const current = this.documentList.sorting;
|
||||
|
185
src/app/directives/library-membership.directive.ts
Normal file
185
src/app/directives/library-membership.directive.ts
Normal file
@ -0,0 +1,185 @@
|
||||
/*!
|
||||
* @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 {
|
||||
Directive,
|
||||
EventEmitter,
|
||||
HostListener,
|
||||
Input,
|
||||
OnChanges,
|
||||
Output
|
||||
} from '@angular/core';
|
||||
import { SiteEntry, SiteMembershipRequestBody } from 'alfresco-js-api';
|
||||
import { AlfrescoApiService } from '@alfresco/adf-core';
|
||||
import { BehaviorSubject, from } from 'rxjs';
|
||||
|
||||
@Directive({
|
||||
selector: '[acaLibraryMembership]',
|
||||
exportAs: 'libraryMembership'
|
||||
})
|
||||
export class LibraryMembershipDirective implements OnChanges {
|
||||
targetSite: any = null;
|
||||
|
||||
isJoinRequested: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(
|
||||
false
|
||||
);
|
||||
|
||||
/** Site for which to toggle the membership request. */
|
||||
@Input('acaLibraryMembership')
|
||||
selection: SiteEntry = null;
|
||||
|
||||
@Output() toggle: EventEmitter<any> = new EventEmitter();
|
||||
@Output() error: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
@HostListener('click')
|
||||
onClick() {
|
||||
this.toggleMembershipRequest();
|
||||
}
|
||||
|
||||
constructor(private alfrescoApiService: AlfrescoApiService) {}
|
||||
|
||||
ngOnChanges(changes) {
|
||||
if (
|
||||
!changes.selection.currentValue ||
|
||||
!changes.selection.currentValue.entry
|
||||
) {
|
||||
this.targetSite = null;
|
||||
|
||||
return;
|
||||
}
|
||||
this.targetSite = changes.selection.currentValue.entry;
|
||||
this.markMembershipRequest();
|
||||
}
|
||||
|
||||
toggleMembershipRequest() {
|
||||
if (!this.targetSite) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.targetSite.joinRequested) {
|
||||
this.cancelJoinRequest().subscribe(
|
||||
() => {
|
||||
this.targetSite.joinRequested = false;
|
||||
this.isJoinRequested.next(false);
|
||||
const info = {
|
||||
shouldReload: false,
|
||||
i18nKey: 'APP.MESSAGES.INFO.JOIN_CANCELED'
|
||||
};
|
||||
this.toggle.emit(info);
|
||||
},
|
||||
error => {
|
||||
const errWitMessage = {
|
||||
error,
|
||||
i18nKey: 'APP.MESSAGES.ERRORS.JOIN_CANCEL_FAILED'
|
||||
};
|
||||
this.error.emit(errWitMessage);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (!this.targetSite.joinRequested) {
|
||||
this.joinLibraryRequest().subscribe(
|
||||
createdMembership => {
|
||||
this.targetSite.joinRequested = true;
|
||||
this.isJoinRequested.next(true);
|
||||
|
||||
if (
|
||||
createdMembership.entry &&
|
||||
createdMembership.entry.site &&
|
||||
createdMembership.entry.site.role
|
||||
) {
|
||||
const info = {
|
||||
shouldReload: true,
|
||||
i18nKey: 'APP.MESSAGES.INFO.JOINED'
|
||||
};
|
||||
this.toggle.emit(info);
|
||||
} else {
|
||||
const info = {
|
||||
shouldReload: false,
|
||||
i18nKey: 'APP.MESSAGES.INFO.JOIN_REQUESTED'
|
||||
};
|
||||
this.toggle.emit(info);
|
||||
}
|
||||
},
|
||||
error => {
|
||||
const errWitMessage = {
|
||||
error,
|
||||
i18nKey: 'APP.MESSAGES.ERRORS.JOIN_REQUEST_FAILED'
|
||||
};
|
||||
this.error.emit(errWitMessage);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
markMembershipRequest() {
|
||||
if (!this.targetSite) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.getMembershipRequest().subscribe(
|
||||
data => {
|
||||
if (data.entry.id === this.targetSite.id) {
|
||||
this.targetSite.joinRequested = true;
|
||||
this.isJoinRequested.next(true);
|
||||
}
|
||||
},
|
||||
() => {
|
||||
this.targetSite.joinRequested = false;
|
||||
this.isJoinRequested.next(false);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private joinLibraryRequest() {
|
||||
const memberBody = <SiteMembershipRequestBody>{
|
||||
id: this.targetSite.id
|
||||
};
|
||||
return from(
|
||||
this.alfrescoApiService.peopleApi.addSiteMembershipRequest(
|
||||
'-me-',
|
||||
memberBody
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private cancelJoinRequest() {
|
||||
return from(
|
||||
this.alfrescoApiService.peopleApi.removeSiteMembershipRequest(
|
||||
'-me-',
|
||||
this.targetSite.id
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private getMembershipRequest() {
|
||||
return from(
|
||||
this.alfrescoApiService.peopleApi.getSiteMembershipRequest(
|
||||
'-me-',
|
||||
this.targetSite.id
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -47,6 +47,7 @@ import { LibraryStatusColumnComponent } from '../components/common/library-statu
|
||||
import { TrashcanNameColumnComponent } from '../components/common/trashcan-name-column/trashcan-name-column.component';
|
||||
import { LocationLinkComponent } from '../components/common/location-link/location-link.component';
|
||||
import { DocumentDisplayModeComponent } from '../components/toolbar/document-display-mode/document-display-mode.component';
|
||||
import { ToggleJoinLibraryComponent } from '../components/toolbar/toggle-join-library/toggle-join-library.component';
|
||||
|
||||
export function setupExtensions(service: AppExtensionService): Function {
|
||||
return () => service.load();
|
||||
@ -85,6 +86,7 @@ export class CoreExtensionsModule {
|
||||
'app.components.tabs.versions': VersionsTabComponent,
|
||||
'app.toolbar.toggleInfoDrawer': ToggleInfoDrawerComponent,
|
||||
'app.toolbar.toggleFavorite': ToggleFavoriteComponent,
|
||||
'app.toolbar.toggleJoinLibrary': ToggleJoinLibraryComponent,
|
||||
'app.toolbar.cardView': DocumentDisplayModeComponent,
|
||||
'app.shared-link.toggleSharedLink': ToggleSharedComponent,
|
||||
'app.columns.name': NameColumnComponent,
|
||||
@ -110,6 +112,9 @@ export class CoreExtensionsModule {
|
||||
'app.selection.file': app.hasFileSelected,
|
||||
'app.selection.file.canShare': app.canShareFile,
|
||||
'app.selection.library': app.hasLibrarySelected,
|
||||
'app.selection.isPrivateLibrary': app.isPrivateLibrary,
|
||||
'app.selection.hasLibraryRole': app.hasLibraryRole,
|
||||
'app.selection.hasNoLibraryRole': app.hasNoLibraryRole,
|
||||
'app.selection.folder': app.hasFolderSelected,
|
||||
'app.selection.folder.canUpdate': app.canUpdateSelectedFolder,
|
||||
|
||||
|
@ -178,6 +178,35 @@ export function hasLibrarySelected(
|
||||
return library ? true : false;
|
||||
}
|
||||
|
||||
export function isPrivateLibrary(
|
||||
context: RuleContext,
|
||||
...args: RuleParameter[]
|
||||
): boolean {
|
||||
const library = context.selection.library;
|
||||
return library
|
||||
? !!(
|
||||
library.entry &&
|
||||
library.entry.visibility &&
|
||||
library.entry.visibility === 'PRIVATE'
|
||||
)
|
||||
: false;
|
||||
}
|
||||
|
||||
export function hasLibraryRole(
|
||||
context: RuleContext,
|
||||
...args: RuleParameter[]
|
||||
): boolean {
|
||||
const library = context.selection.library;
|
||||
return library ? !!(library.entry && library.entry.role) : false;
|
||||
}
|
||||
|
||||
export function hasNoLibraryRole(
|
||||
context: RuleContext,
|
||||
...args: RuleParameter[]
|
||||
): boolean {
|
||||
return !hasLibraryRole(context, ...args);
|
||||
}
|
||||
|
||||
export function hasFileSelected(
|
||||
context: RuleContext,
|
||||
...args: RuleParameter[]
|
||||
|
@ -75,7 +75,9 @@ export function isLibraries(
|
||||
...args: RuleParameter[]
|
||||
): boolean {
|
||||
const { url } = context.navigation;
|
||||
return url && url.endsWith('/libraries');
|
||||
return (
|
||||
url && (url.endsWith('/libraries') || url.startsWith('/search-libraries'))
|
||||
);
|
||||
}
|
||||
|
||||
export function isNotLibraries(
|
||||
|
@ -82,6 +82,8 @@ export class ContentManagementService {
|
||||
libraryDeleted = new Subject<string>();
|
||||
libraryCreated = new Subject<SiteEntry>();
|
||||
libraryUpdated = new Subject<SiteEntry>();
|
||||
libraryJoined = new Subject<string>();
|
||||
joinLibraryToggle = new Subject<string>();
|
||||
linksUnshared = new Subject<any>();
|
||||
favoriteAdded = new Subject<Array<MinimalNodeEntity>>();
|
||||
favoriteRemoved = new Subject<Array<MinimalNodeEntity>>();
|
||||
|
@ -45,6 +45,7 @@ export class NavigateLibraryAction implements Action {
|
||||
readonly type = NAVIGATE_LIBRARY;
|
||||
constructor(public payload?: string) {}
|
||||
}
|
||||
|
||||
export class UpdateLibraryAction implements Action {
|
||||
readonly type = UPDATE_LIBRARY;
|
||||
constructor(public payload?: SiteBody) {}
|
||||
|
@ -33,8 +33,8 @@ import {
|
||||
CREATE_LIBRARY,
|
||||
NavigateLibraryAction,
|
||||
NAVIGATE_LIBRARY,
|
||||
UPDATE_LIBRARY,
|
||||
UpdateLibraryAction
|
||||
UpdateLibraryAction,
|
||||
UPDATE_LIBRARY
|
||||
} from '../actions';
|
||||
import { ContentManagementService } from '../../services/content-management.service';
|
||||
import { Store } from '@ngrx/store';
|
||||
|
@ -101,6 +101,20 @@
|
||||
{ "type": "rule", "value": "app.navigation.isLibraries" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "app.libraries.toolbar.canToggleJoin",
|
||||
"type": "core.every",
|
||||
"parameters": [
|
||||
{ "type": "rule", "value": "app.selection.library" },
|
||||
{ "type": "rule",
|
||||
"value": "core.not",
|
||||
"parameters": [
|
||||
{ "type": "rule", "value": "app.selection.isPrivateLibrary" }
|
||||
]
|
||||
},
|
||||
{ "type": "rule", "value": "app.selection.hasNoLibraryRole" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "app.toolbar.canCopyNode",
|
||||
"type": "core.every",
|
||||
@ -387,6 +401,15 @@
|
||||
"visible": "app.libraries.toolbar.info"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "app.toolbar.joinLibrary",
|
||||
"type": "custom",
|
||||
"order": 704,
|
||||
"component": "app.toolbar.toggleJoinLibrary",
|
||||
"rules": {
|
||||
"visible": "app.libraries.toolbar.canToggleJoin"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "app.toolbar.more",
|
||||
"type": "menu",
|
||||
@ -1277,7 +1300,8 @@
|
||||
"title": "APP.DOCUMENT_LIST.COLUMNS.ROLE",
|
||||
"type": "text",
|
||||
"sortable": true,
|
||||
"desktopOnly": true
|
||||
"template": "app.columns.libraryRole",
|
||||
"desktopOnly": false
|
||||
},
|
||||
{
|
||||
"id": "app.libraries.visibility",
|
||||
|
@ -162,7 +162,9 @@
|
||||
"SHARE": "Share",
|
||||
"SHARE_EDIT": "Shared link settings",
|
||||
"PRINT": "Print",
|
||||
"FULLSCREEN": "Activate full-screen mode"
|
||||
"FULLSCREEN": "Activate full-screen mode",
|
||||
"JOIN": "Join",
|
||||
"CANCEL_JOIN": "Cancel join request"
|
||||
},
|
||||
"DIALOGS": {
|
||||
"CONFIRM_PURGE": {
|
||||
@ -227,7 +229,9 @@
|
||||
"GENERIC": "There was a problem restoring {{ name }}"
|
||||
}
|
||||
},
|
||||
"DELETE_LIBRARY_FAILED": "Cannot delete the library"
|
||||
"DELETE_LIBRARY_FAILED": "Cannot delete the library",
|
||||
"JOIN_REQUEST_FAILED": "Cannot join the library",
|
||||
"JOIN_CANCEL_FAILED": "Cannot cancel the request to join the library"
|
||||
},
|
||||
"UPLOAD": {
|
||||
"ERROR": {
|
||||
@ -272,7 +276,10 @@
|
||||
"FAIL": "{{ failed }} couldn't be moved."
|
||||
}
|
||||
},
|
||||
"LIBRARY_DELETED": "Library deleted"
|
||||
"LIBRARY_DELETED": "Library deleted",
|
||||
"JOINED": "Library joined",
|
||||
"JOIN_REQUESTED": "Join library request sent",
|
||||
"JOIN_CANCELED": "Canceled the request to join the library"
|
||||
}
|
||||
},
|
||||
"CONTENT_METADATA": {
|
||||
|
35
src/assets/images/join-library.svg
Normal file
35
src/assets/images/join-library.svg
Normal file
@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 50.2 (55047) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>join-library</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs>
|
||||
<polygon id="path-1" points="0.0003 0 16 0 16 16 0.0003 16"></polygon>
|
||||
<polygon id="path-3" points="0 0 15.9998 0 15.9998 16 0 16"></polygon>
|
||||
</defs>
|
||||
<g id="join-library" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" opacity="0.54">
|
||||
<g id="systemicon/join_library">
|
||||
<g id="Group" transform="translate(2.000000, 2.000000)">
|
||||
<g id="Group-2">
|
||||
<g id="Group">
|
||||
<g id="Group-3" transform="translate(4.000000, 0.000000)">
|
||||
<mask id="mask-2" fill="white">
|
||||
<use xlink:href="#path-1"></use>
|
||||
</mask>
|
||||
<g id="Clip-2"></g>
|
||||
<path d="M14.0003,0 L2.0003,0 C0.9003,0 0.0003,0.9 0.0003,2 L0.0003,14 C0.0003,15.1 0.9003,16 2.0003,16 L14.0003,16 C15.1003,16 16.0003,15.1 16.0003,14 L16.0003,2 C16.0003,0.9 15.1003,0 14.0003,0" id="Fill-1" fill="#000000" mask="url(#mask-2)"></path>
|
||||
</g>
|
||||
<g id="Group-6" transform="translate(0.000000, 4.000000)">
|
||||
<mask id="mask-4" fill="white">
|
||||
<use xlink:href="#path-3"></use>
|
||||
</mask>
|
||||
<g id="Clip-5"></g>
|
||||
<path d="M1.9998,0 L-0.0002,0 L-0.0002,14 C-0.0002,15.1 0.8998,16 1.9998,16 L15.9998,16 L15.9998,14 L1.9998,14 L1.9998,0 Z" id="Fill-4" fill="#000000" mask="url(#mask-4)"></path>
|
||||
</g>
|
||||
<polygon id="Fill-7" fill="#FEFEFE" points="11 12 11 10 7 10 7 6 11 6 11 4 15 8"></polygon>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
Loading…
x
Reference in New Issue
Block a user