shared library (#1080)

* shared project scaffold

* rules package

* move evaluators to shared lib

* add rxjs peer dependency

* use dedicated material namespaces

* create store package, move actions

* move selectors to shared library

* move generic effects to shared lib

* move routing extensions

* minor code reorg

* fix unit tests

* move content-api service

* move permission service

* update tests

* update plint config

* move page layout

* css variables

* use dedicated css property

* move generic error component to shared lib

* fix test
This commit is contained in:
Denys Vuika
2019-04-25 14:56:54 +01:00
committed by GitHub
parent f3c5ffb977
commit 9db1c2989f
175 changed files with 1552 additions and 1153 deletions

View File

@@ -27,11 +27,10 @@ import { Effect, Actions, ofType } from '@ngrx/effects';
import { Injectable } from '@angular/core';
import { map } from 'rxjs/operators';
import {
AppActionTypes,
LogoutAction,
LOGOUT,
ReloadDocumentListAction,
RELOAD_DOCUMENT_LIST
} from '../actions/app.actions';
ReloadDocumentListAction
} from '@alfresco/aca-shared/store';
import { AuthenticationService } from '@alfresco/adf-core';
import { Router } from '@angular/router';
import { ContentManagementService } from '../../services/content-management.service';
@@ -47,7 +46,7 @@ export class AppEffects {
@Effect({ dispatch: false })
reload = this.actions$.pipe(
ofType<ReloadDocumentListAction>(RELOAD_DOCUMENT_LIST),
ofType<ReloadDocumentListAction>(AppActionTypes.ReloadDocumentList),
map(action => {
this.content.reload.next(action);
})
@@ -55,7 +54,7 @@ export class AppEffects {
@Effect({ dispatch: false })
logout$ = this.actions$.pipe(
ofType<LogoutAction>(LOGOUT),
ofType<LogoutAction>(AppActionTypes.Logout),
map(() => {
this.auth
.logout()

View File

@@ -23,18 +23,21 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
import {
AppStore,
DownloadNodesAction,
NodeActionTypes,
NodeInfo,
getAppSelection
} from '@alfresco/aca-shared/store';
import { DownloadZipDialogComponent } from '@alfresco/adf-core';
import { Injectable } from '@angular/core';
import { MatDialog } from '@angular/material';
import { Actions, Effect, ofType } from '@ngrx/effects';
import { map, take } from 'rxjs/operators';
import { DownloadNodesAction, DOWNLOAD_NODES } from '../actions';
import { NodeInfo } from '../models';
import { ContentApiService } from '../../services/content-api.service';
import { MinimalNodeEntity } from '@alfresco/js-api';
import { Injectable } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { Actions, Effect, ofType } from '@ngrx/effects';
import { Store } from '@ngrx/store';
import { AppStore } from '../states';
import { appSelection } from '../selectors/app.selectors';
import { map, take } from 'rxjs/operators';
import { ContentApiService } from '@alfresco/aca-shared';
@Injectable()
export class DownloadEffects {
@@ -47,13 +50,13 @@ export class DownloadEffects {
@Effect({ dispatch: false })
downloadNode$ = this.actions$.pipe(
ofType<DownloadNodesAction>(DOWNLOAD_NODES),
ofType<DownloadNodesAction>(NodeActionTypes.Download),
map(action => {
if (action.payload && action.payload.length > 0) {
this.downloadNodes(action.payload);
} else {
this.store
.select(appSelection)
.select(getAppSelection)
.pipe(take(1))
.subscribe(selection => {
if (selection && !selection.isEmpty) {

View File

@@ -27,14 +27,13 @@ import { Effect, Actions, ofType } from '@ngrx/effects';
import { Injectable } from '@angular/core';
import { map, take } from 'rxjs/operators';
import {
ADD_FAVORITE,
AppStore,
NodeActionTypes,
AddFavoriteAction,
RemoveFavoriteAction,
REMOVE_FAVORITE
} from '../actions/favorite.actions';
getAppSelection
} from '@alfresco/aca-shared/store';
import { Store } from '@ngrx/store';
import { AppStore } from '../states';
import { appSelection } from '../selectors/app.selectors';
import { ContentManagementService } from '../../services/content-management.service';
@Injectable()
@@ -47,13 +46,13 @@ export class FavoriteEffects {
@Effect({ dispatch: false })
addFavorite$ = this.actions$.pipe(
ofType<AddFavoriteAction>(ADD_FAVORITE),
ofType<AddFavoriteAction>(NodeActionTypes.AddFavorite),
map(action => {
if (action.payload && action.payload.length > 0) {
this.content.addFavorite(action.payload);
} else {
this.store
.select(appSelection)
.select(getAppSelection)
.pipe(take(1))
.subscribe(selection => {
if (selection && !selection.isEmpty) {
@@ -66,13 +65,13 @@ export class FavoriteEffects {
@Effect({ dispatch: false })
removeFavorite$ = this.actions$.pipe(
ofType<RemoveFavoriteAction>(REMOVE_FAVORITE),
ofType<RemoveFavoriteAction>(NodeActionTypes.RemoveFavorite),
map(action => {
if (action.payload && action.payload.length > 0) {
this.content.removeFavorite(action.payload);
} else {
this.store
.select(appSelection)
.select(getAppSelection)
.pipe(take(1))
.subscribe(selection => {
if (selection && !selection.isEmpty) {

View File

@@ -23,28 +23,24 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
import { Effect, Actions, ofType } from '@ngrx/effects';
import { Injectable } from '@angular/core';
import { map, take, mergeMap } from 'rxjs/operators';
import {
DeleteLibraryAction,
DELETE_LIBRARY,
AppStore,
CreateLibraryAction,
CREATE_LIBRARY,
NavigateLibraryAction,
NAVIGATE_LIBRARY,
UpdateLibraryAction,
UPDATE_LIBRARY,
DeleteLibraryAction,
LeaveLibraryAction,
LEAVE_LIBRARY,
NavigateRouteAction
} from '../actions';
import { ContentManagementService } from '../../services/content-management.service';
LibraryActionTypes,
NavigateLibraryAction,
NavigateRouteAction,
SnackbarErrorAction,
UpdateLibraryAction,
getAppSelection
} from '@alfresco/aca-shared/store';
import { Injectable } from '@angular/core';
import { Actions, Effect, ofType } from '@ngrx/effects';
import { Store } from '@ngrx/store';
import { AppStore } from '../states';
import { appSelection } from '../selectors/app.selectors';
import { ContentApiService } from '../../services/content-api.service';
import { SnackbarErrorAction } from '../actions/snackbar.actions';
import { map, mergeMap, take } from 'rxjs/operators';
import { ContentApiService } from '@alfresco/aca-shared';
import { ContentManagementService } from '../../services/content-management.service';
@Injectable()
export class LibraryEffects {
@@ -57,13 +53,13 @@ export class LibraryEffects {
@Effect({ dispatch: false })
deleteLibrary$ = this.actions$.pipe(
ofType<DeleteLibraryAction>(DELETE_LIBRARY),
ofType<DeleteLibraryAction>(LibraryActionTypes.Delete),
map(action => {
if (action.payload) {
this.content.deleteLibrary(action.payload);
} else {
this.store
.select(appSelection)
.select(getAppSelection)
.pipe(take(1))
.subscribe(selection => {
if (selection && selection.library) {
@@ -76,13 +72,13 @@ export class LibraryEffects {
@Effect({ dispatch: false })
leaveLibrary$ = this.actions$.pipe(
ofType<LeaveLibraryAction>(LEAVE_LIBRARY),
ofType<LeaveLibraryAction>(LibraryActionTypes.Leave),
map(action => {
if (action.payload) {
this.content.leaveLibrary(action.payload);
} else {
this.store
.select(appSelection)
.select(getAppSelection)
.pipe(take(1))
.subscribe(selection => {
if (selection && selection.library) {
@@ -95,14 +91,14 @@ export class LibraryEffects {
@Effect()
createLibrary$ = this.actions$.pipe(
ofType<CreateLibraryAction>(CREATE_LIBRARY),
ofType<CreateLibraryAction>(LibraryActionTypes.Create),
mergeMap(() => this.content.createLibrary()),
map(libraryId => new NavigateLibraryAction(libraryId))
);
@Effect({ dispatch: false })
navigateLibrary$ = this.actions$.pipe(
ofType<NavigateLibraryAction>(NAVIGATE_LIBRARY),
ofType<NavigateLibraryAction>(LibraryActionTypes.Navigate),
map(action => {
const libraryId = action.payload;
if (libraryId) {
@@ -125,10 +121,10 @@ export class LibraryEffects {
@Effect({ dispatch: false })
updateLibrary$ = this.actions$.pipe(
ofType<UpdateLibraryAction>(UPDATE_LIBRARY),
ofType<UpdateLibraryAction>(LibraryActionTypes.Update),
map(action => {
this.store
.select(appSelection)
.select(getAppSelection)
.pipe(take(1))
.subscribe(selection => {
if (selection && selection.library) {

View File

@@ -1,41 +0,0 @@
/*!
* @license
* Alfresco Example Content Application
*
* Copyright (C) 2005 - 2019 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 { Effect, Actions, ofType } from '@ngrx/effects';
import { Injectable } from '@angular/core';
import { map } from 'rxjs/operators';
import { CloseModalDialogsAction, CLOSE_MODAL_DIALOGS } from '../actions';
import { MatDialog } from '@angular/material';
@Injectable()
export class ModalsEffects {
constructor(private actions$: Actions, private matDialog: MatDialog) {}
@Effect({ dispatch: false })
closeAll$ = this.actions$.pipe(
ofType<CloseModalDialogsAction>(CLOSE_MODAL_DIALOGS),
map(() => this.matDialog.closeAll())
);
}

View File

@@ -30,6 +30,7 @@ import { EffectsModule } from '@ngrx/effects';
import { Store } from '@ngrx/store';
import { ContentManagementService } from '../../services/content-management.service';
import {
SharedStoreModule,
ShareNodeAction,
SetSelectedNodesAction,
UnshareNodesAction,
@@ -44,25 +45,34 @@ import {
ManagePermissionsAction,
UnlockWriteAction,
FullscreenViewerAction,
PrintFileAction
} from '../actions/node.actions';
import { SetCurrentFolderAction } from '../actions/app.actions';
PrintFileAction,
SetCurrentFolderAction
} from '@alfresco/aca-shared/store';
import { ViewUtilService } from '@alfresco/adf-core';
import { ViewerEffects } from './viewer.effects';
describe('NodeEffects', () => {
let store: Store<any>;
// let actions$: Actions;
let contentService: ContentManagementService;
let viewUtilService: ViewUtilService;
let viewerEffects: ViewerEffects;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [AppTestingModule, EffectsModule.forRoot([NodeEffects])],
imports: [
AppTestingModule,
SharedStoreModule,
EffectsModule.forRoot([NodeEffects, ViewerEffects])
],
declarations: [],
providers: []
providers: [ViewUtilService]
});
// actions$ = TestBed.get(Actions);
store = TestBed.get(Store);
contentService = TestBed.get(ContentManagementService);
viewUtilService = TestBed.get(ViewUtilService);
viewerEffects = TestBed.get(ViewerEffects);
});
describe('shareNode$', () => {
@@ -403,17 +413,28 @@ describe('NodeEffects', () => {
describe('printFile$', () => {
it('it should print node content from payload', () => {
spyOn(contentService, 'printFile').and.stub();
const node: any = { entry: { id: 'node-id' } };
spyOn(viewUtilService, 'printFileGeneric').and.stub();
const node: any = {
entry: { id: 'node-id', content: { mimeType: 'text/json' } }
};
store.dispatch(new PrintFileAction(node));
expect(contentService.printFile).toHaveBeenCalledWith(node);
expect(viewUtilService.printFileGeneric).toHaveBeenCalledWith(
'node-id',
'text/json'
);
});
it('it should print node content from store', fakeAsync(() => {
spyOn(contentService, 'printFile').and.stub();
const node: any = { entry: { isFile: true, id: 'node-id' } };
spyOn(viewUtilService, 'printFileGeneric').and.stub();
const node: any = {
entry: {
isFile: true,
id: 'node-id',
content: { mimeType: 'text/json' }
}
};
store.dispatch(new SetSelectedNodesAction([node]));
@@ -421,17 +442,20 @@ describe('NodeEffects', () => {
store.dispatch(new PrintFileAction(null));
expect(contentService.printFile).toHaveBeenCalledWith(node);
expect(viewUtilService.printFileGeneric).toHaveBeenCalledWith(
'node-id',
'text/json'
);
}));
});
describe('fullscreenViewer$', () => {
it('should call fullscreen viewer', () => {
spyOn(contentService, 'fullscreenViewer').and.stub();
spyOn(viewerEffects, 'enterFullScreen').and.stub();
store.dispatch(new FullscreenViewerAction(null));
expect(contentService.fullscreenViewer).toHaveBeenCalled();
expect(viewerEffects.enterFullScreen).toHaveBeenCalled();
});
});

View File

@@ -27,61 +27,47 @@ import { Effect, Actions, ofType } from '@ngrx/effects';
import { Injectable } from '@angular/core';
import { map, take } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { AppStore } from '../states/app.state';
import {
AppStore,
NodeActionTypes,
PurgeDeletedNodesAction,
PURGE_DELETED_NODES,
DeleteNodesAction,
DELETE_NODES,
UndoDeleteNodesAction,
UNDO_DELETE_NODES,
CreateFolderAction,
CREATE_FOLDER,
EditFolderAction,
EDIT_FOLDER,
RestoreDeletedNodesAction,
RESTORE_DELETED_NODES,
ShareNodeAction,
SHARE_NODE,
ManageVersionsAction,
MANAGE_VERSIONS,
UnlockWriteAction,
UNLOCK_WRITE
} from '../actions';
import { ContentManagementService } from '../../services/content-management.service';
import { currentFolder, appSelection } from '../selectors/app.selectors';
import {
UnshareNodesAction,
UNSHARE_NODES,
CopyNodesAction,
COPY_NODES,
MoveNodesAction,
MOVE_NODES,
ManagePermissionsAction,
MANAGE_PERMISSIONS,
PRINT_FILE,
PrintFileAction,
FULLSCREEN_VIEWER,
FullscreenViewerAction
} from '../actions/node.actions';
getCurrentFolder,
getAppSelection
} from '@alfresco/aca-shared/store';
import { ContentManagementService } from '../../services/content-management.service';
import { ViewUtilService } from '@alfresco/adf-core';
@Injectable()
export class NodeEffects {
constructor(
private store: Store<AppStore>,
private actions$: Actions,
private contentService: ContentManagementService
private contentService: ContentManagementService,
private viewUtils: ViewUtilService
) {}
@Effect({ dispatch: false })
shareNode$ = this.actions$.pipe(
ofType<ShareNodeAction>(SHARE_NODE),
ofType<ShareNodeAction>(NodeActionTypes.Share),
map(action => {
if (action.payload) {
this.contentService.shareNode(action.payload);
} else {
this.store
.select(appSelection)
.select(getAppSelection)
.pipe(take(1))
.subscribe(selection => {
if (selection && selection.file) {
@@ -94,13 +80,13 @@ export class NodeEffects {
@Effect({ dispatch: false })
unshareNodes$ = this.actions$.pipe(
ofType<UnshareNodesAction>(UNSHARE_NODES),
ofType<UnshareNodesAction>(NodeActionTypes.Unshare),
map(action => {
if (action && action.payload && action.payload.length > 0) {
this.contentService.unshareNodes(action.payload);
} else {
this.store
.select(appSelection)
.select(getAppSelection)
.pipe(take(1))
.subscribe(selection => {
if (selection && !selection.isEmpty) {
@@ -113,13 +99,13 @@ export class NodeEffects {
@Effect({ dispatch: false })
purgeDeletedNodes$ = this.actions$.pipe(
ofType<PurgeDeletedNodesAction>(PURGE_DELETED_NODES),
ofType<PurgeDeletedNodesAction>(NodeActionTypes.PurgeDeleted),
map(action => {
if (action && action.payload && action.payload.length > 0) {
this.contentService.purgeDeletedNodes(action.payload);
} else {
this.store
.select(appSelection)
.select(getAppSelection)
.pipe(take(1))
.subscribe(selection => {
if (selection && selection.count > 0) {
@@ -132,13 +118,13 @@ export class NodeEffects {
@Effect({ dispatch: false })
restoreDeletedNodes$ = this.actions$.pipe(
ofType<RestoreDeletedNodesAction>(RESTORE_DELETED_NODES),
ofType<RestoreDeletedNodesAction>(NodeActionTypes.RestoreDeleted),
map(action => {
if (action && action.payload && action.payload.length > 0) {
this.contentService.restoreDeletedNodes(action.payload);
} else {
this.store
.select(appSelection)
.select(getAppSelection)
.pipe(take(1))
.subscribe(selection => {
if (selection && selection.count > 0) {
@@ -151,13 +137,13 @@ export class NodeEffects {
@Effect({ dispatch: false })
deleteNodes$ = this.actions$.pipe(
ofType<DeleteNodesAction>(DELETE_NODES),
ofType<DeleteNodesAction>(NodeActionTypes.Delete),
map(action => {
if (action && action.payload && action.payload.length > 0) {
this.contentService.deleteNodes(action.payload);
} else {
this.store
.select(appSelection)
.select(getAppSelection)
.pipe(take(1))
.subscribe(selection => {
if (selection && selection.count > 0) {
@@ -170,7 +156,7 @@ export class NodeEffects {
@Effect({ dispatch: false })
undoDeleteNodes$ = this.actions$.pipe(
ofType<UndoDeleteNodesAction>(UNDO_DELETE_NODES),
ofType<UndoDeleteNodesAction>(NodeActionTypes.UndoDelete),
map(action => {
if (action.payload.length > 0) {
this.contentService.undoDeleteNodes(action.payload);
@@ -180,13 +166,13 @@ export class NodeEffects {
@Effect({ dispatch: false })
createFolder$ = this.actions$.pipe(
ofType<CreateFolderAction>(CREATE_FOLDER),
ofType<CreateFolderAction>(NodeActionTypes.CreateFolder),
map(action => {
if (action.payload) {
this.contentService.createFolder(action.payload);
} else {
this.store
.select(currentFolder)
.select(getCurrentFolder)
.pipe(take(1))
.subscribe(node => {
if (node && node.id) {
@@ -199,13 +185,13 @@ export class NodeEffects {
@Effect({ dispatch: false })
editFolder$ = this.actions$.pipe(
ofType<EditFolderAction>(EDIT_FOLDER),
ofType<EditFolderAction>(NodeActionTypes.EditFolder),
map(action => {
if (action.payload) {
this.contentService.editFolder(action.payload);
} else {
this.store
.select(appSelection)
.select(getAppSelection)
.pipe(take(1))
.subscribe(selection => {
if (selection && selection.folder) {
@@ -218,13 +204,13 @@ export class NodeEffects {
@Effect({ dispatch: false })
copyNodes$ = this.actions$.pipe(
ofType<CopyNodesAction>(COPY_NODES),
ofType<CopyNodesAction>(NodeActionTypes.Copy),
map(action => {
if (action.payload && action.payload.length > 0) {
this.contentService.copyNodes(action.payload);
} else {
this.store
.select(appSelection)
.select(getAppSelection)
.pipe(take(1))
.subscribe(selection => {
if (selection && !selection.isEmpty) {
@@ -237,13 +223,13 @@ export class NodeEffects {
@Effect({ dispatch: false })
moveNodes$ = this.actions$.pipe(
ofType<MoveNodesAction>(MOVE_NODES),
ofType<MoveNodesAction>(NodeActionTypes.Move),
map(action => {
if (action.payload && action.payload.length > 0) {
this.contentService.moveNodes(action.payload);
} else {
this.store
.select(appSelection)
.select(getAppSelection)
.pipe(take(1))
.subscribe(selection => {
if (selection && !selection.isEmpty) {
@@ -256,13 +242,13 @@ export class NodeEffects {
@Effect({ dispatch: false })
managePermissions$ = this.actions$.pipe(
ofType<ManagePermissionsAction>(MANAGE_PERMISSIONS),
ofType<ManagePermissionsAction>(NodeActionTypes.ManagePermissions),
map(action => {
if (action && action.payload) {
this.contentService.managePermissions(action.payload);
} else {
this.store
.select(appSelection)
.select(getAppSelection)
.pipe(take(1))
.subscribe(selection => {
if (selection && !selection.isEmpty) {
@@ -275,13 +261,13 @@ export class NodeEffects {
@Effect({ dispatch: false })
manageVersions$ = this.actions$.pipe(
ofType<ManageVersionsAction>(MANAGE_VERSIONS),
ofType<ManageVersionsAction>(NodeActionTypes.ManageVersions),
map(action => {
if (action && action.payload) {
this.contentService.manageVersions(action.payload);
} else {
this.store
.select(appSelection)
.select(getAppSelection)
.pipe(take(1))
.subscribe(selection => {
if (selection && selection.file) {
@@ -294,40 +280,32 @@ export class NodeEffects {
@Effect({ dispatch: false })
printFile$ = this.actions$.pipe(
ofType<PrintFileAction>(PRINT_FILE),
ofType<PrintFileAction>(NodeActionTypes.PrintFile),
map(action => {
if (action && action.payload) {
this.contentService.printFile(action.payload);
this.printFile(action.payload);
} else {
this.store
.select(appSelection)
.select(getAppSelection)
.pipe(take(1))
.subscribe(selection => {
if (selection && selection.file) {
this.contentService.printFile(selection.file);
this.printFile(selection.file);
}
});
}
})
);
@Effect({ dispatch: false })
fullscreenViewer$ = this.actions$.pipe(
ofType<FullscreenViewerAction>(FULLSCREEN_VIEWER),
map(() => {
this.contentService.fullscreenViewer();
})
);
@Effect({ dispatch: false })
unlockWrite$ = this.actions$.pipe(
ofType<UnlockWriteAction>(UNLOCK_WRITE),
ofType<UnlockWriteAction>(NodeActionTypes.UnlockForWriting),
map(action => {
if (action && action.payload) {
this.contentService.unlockNode(action.payload);
} else {
this.store
.select(appSelection)
.select(getAppSelection)
.pipe(take(1))
.subscribe(selection => {
if (selection && selection.file) {
@@ -337,4 +315,16 @@ export class NodeEffects {
}
})
);
printFile(node: any) {
if (node && node.entry) {
// shared and favorite
const id = node.entry.nodeId || node.entry.guid || node.entry.id;
const mimeType = node.entry.content.mimeType;
if (id) {
this.viewUtils.printFileGeneric(id, mimeType);
}
}
}
}

View File

@@ -1,154 +0,0 @@
/*!
* @license
* Alfresco Example Content Application
*
* Copyright (C) 2005 - 2019 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 { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { Actions, Effect, ofType } from '@ngrx/effects';
import { MinimalNodeEntryEntity, PathInfoEntity } from '@alfresco/js-api';
import { map } from 'rxjs/operators';
import {
NavigateRouteAction,
NavigateToParentFolder,
NAVIGATE_PARENT_FOLDER,
NAVIGATE_ROUTE,
NavigateToFolder,
NAVIGATE_FOLDER,
NavigateUrlAction,
NAVIGATE_URL,
SnackbarErrorAction
} from '../actions';
import { AppStore } from '../states/app.state';
import { Store } from '@ngrx/store';
@Injectable()
export class RouterEffects {
constructor(
private store: Store<AppStore>,
private actions$: Actions,
private router: Router
) {}
@Effect({ dispatch: false })
navigateUrl$ = this.actions$.pipe(
ofType<NavigateUrlAction>(NAVIGATE_URL),
map(action => {
if (action.payload) {
this.router.navigateByUrl(action.payload);
}
})
);
@Effect({ dispatch: false })
navigateRoute$ = this.actions$.pipe(
ofType<NavigateRouteAction>(NAVIGATE_ROUTE),
map(action => {
this.router.navigate(action.payload);
})
);
@Effect({ dispatch: false })
navigateToFolder$ = this.actions$.pipe(
ofType<NavigateToFolder>(NAVIGATE_FOLDER),
map(action => {
if (action.payload && action.payload.entry) {
this.navigateToFolder(action.payload.entry);
}
})
);
@Effect({ dispatch: false })
navigateToParentFolder$ = this.actions$.pipe(
ofType<NavigateToParentFolder>(NAVIGATE_PARENT_FOLDER),
map(action => {
if (action.payload && action.payload.entry) {
this.navigateToParentFolder(action.payload.entry);
}
})
);
private navigateToFolder(node: MinimalNodeEntryEntity) {
let link: any[] = null;
const { path, id } = node;
if (path && path.name && path.elements) {
const isLibraryPath = this.isLibraryContent(<PathInfoEntity>path);
const parent = path.elements[path.elements.length - 1];
const area = isLibraryPath ? '/libraries' : '/personal-files';
if (!isLibraryPath) {
link = [area, id];
} else {
// parent.id could be 'Site' folder or child as 'documentLibrary'
link = [area, parent.name === 'Sites' ? {} : id];
}
setTimeout(() => {
this.router.navigate(link);
}, 10);
} else {
this.router.navigate(['/personal-files', node.id]);
}
}
private navigateToParentFolder(node: MinimalNodeEntryEntity) {
let link: any[] = null;
const { path } = node;
if (path && path.name && path.elements) {
const isLibraryPath = this.isLibraryContent(<PathInfoEntity>path);
const parent = path.elements[path.elements.length - 1];
const area = isLibraryPath ? '/libraries' : '/personal-files';
if (!isLibraryPath) {
link = [area, parent.id];
} else {
// parent.id could be 'Site' folder or child as 'documentLibrary'
link = [area, parent.name === 'Sites' ? {} : parent.id];
}
setTimeout(() => {
this.router.navigate(link);
}, 10);
} else {
this.store.dispatch(
new SnackbarErrorAction('APP.MESSAGES.ERRORS.CANNOT_NAVIGATE_LOCATION')
);
}
}
private isLibraryContent(path: PathInfoEntity): boolean {
if (
path &&
path.elements.length >= 2 &&
path.elements[1].name === 'Sites'
) {
return true;
}
return false;
}
}

View File

@@ -28,9 +28,11 @@ import { AppTestingModule } from '../../testing/app-testing.module';
import { SearchEffects } from './search.effects';
import { EffectsModule } from '@ngrx/effects';
import { Store } from '@ngrx/store';
import { SearchByTermAction } from '../actions/search.actions';
import { Router } from '@angular/router';
import { SearchOptionIds } from '../models/searchOption.model';
import {
SearchOptionIds,
SearchByTermAction
} from '@alfresco/aca-shared/store';
describe('SearchEffects', () => {
let store: Store<any>;

View File

@@ -26,9 +26,12 @@
import { Effect, Actions, ofType } from '@ngrx/effects';
import { Injectable } from '@angular/core';
import { map } from 'rxjs/operators';
import { SEARCH_BY_TERM, SearchByTermAction } from '../actions/search.actions';
import {
SearchActionTypes,
SearchByTermAction,
SearchOptionIds
} from '@alfresco/aca-shared/store';
import { Router } from '@angular/router';
import { SearchOptionIds } from '../models/searchOption.model';
@Injectable()
export class SearchEffects {
@@ -36,7 +39,7 @@ export class SearchEffects {
@Effect({ dispatch: false })
searchByTerm$ = this.actions$.pipe(
ofType<SearchByTermAction>(SEARCH_BY_TERM),
ofType<SearchByTermAction>(SearchActionTypes.SearchByTerm),
map(action => {
const query = action.payload
.replace(/[(]/g, '%28')

View File

@@ -1,99 +0,0 @@
/*!
* @license
* Alfresco Example Content Application
*
* Copyright (C) 2005 - 2019 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 { TranslationService } from '@alfresco/adf-core';
import { Injectable } from '@angular/core';
import { MatSnackBar } from '@angular/material';
import { Actions, Effect, ofType } from '@ngrx/effects';
import { Store } from '@ngrx/store';
import { map } from 'rxjs/operators';
import {
SnackbarAction,
SnackbarErrorAction,
SnackbarInfoAction,
SnackbarWarningAction,
SNACKBAR_ERROR,
SNACKBAR_INFO,
SNACKBAR_WARNING
} from '../actions';
import { AppStore } from '../states/app.state';
@Injectable()
export class SnackbarEffects {
constructor(
private store: Store<AppStore>,
private actions$: Actions,
private snackBar: MatSnackBar,
private translationService: TranslationService
) {}
@Effect({ dispatch: false })
infoEffect = this.actions$.pipe(
ofType<SnackbarInfoAction>(SNACKBAR_INFO),
map((action: SnackbarInfoAction) => {
this.showSnackBar(action, 'info-snackbar');
})
);
@Effect({ dispatch: false })
warningEffect = this.actions$.pipe(
ofType<SnackbarWarningAction>(SNACKBAR_WARNING),
map((action: SnackbarWarningAction) => {
this.showSnackBar(action, 'warning-snackbar');
})
);
@Effect({ dispatch: false })
errorEffect = this.actions$.pipe(
ofType<SnackbarErrorAction>(SNACKBAR_ERROR),
map((action: SnackbarErrorAction) => {
this.showSnackBar(action, 'error-snackbar');
})
);
private showSnackBar(action: SnackbarAction, panelClass: string) {
const message = this.translate(action.payload, action.params);
let actionName: string = null;
if (action.userAction) {
actionName = this.translate(action.userAction.title);
}
const snackBarRef = this.snackBar.open(message, actionName, {
duration: action.duration || 4000,
panelClass: panelClass
});
if (action.userAction) {
snackBarRef.onAction().subscribe(() => {
this.store.dispatch(action.userAction.action);
});
}
}
private translate(message: string, params?: Object): string {
return this.translationService.instant(message, params);
}
}

View File

@@ -34,7 +34,7 @@ import {
FileUploadCompleteEvent,
FileModel
} from '@alfresco/adf-core';
import { UnlockWriteAction } from '../actions';
import { UnlockWriteAction } from '@alfresco/aca-shared/store';
describe('UploadEffects', () => {
let store: Store<any>;

View File

@@ -23,33 +23,31 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
import { Injectable, RendererFactory2, NgZone } from '@angular/core';
import {
AppStore,
SnackbarErrorAction,
UnlockWriteAction,
UploadActionTypes,
UploadFilesAction,
UploadFileVersionAction,
UploadFolderAction,
getCurrentFolder
} from '@alfresco/aca-shared/store';
import { FileModel, FileUtils, UploadService } from '@alfresco/adf-core';
import { Injectable, NgZone, RendererFactory2 } from '@angular/core';
import { Actions, Effect, ofType } from '@ngrx/effects';
import { Store } from '@ngrx/store';
import { AppStore } from '../states';
import { forkJoin, fromEvent, of } from 'rxjs';
import {
UploadFilesAction,
UPLOAD_FILES,
UploadFolderAction,
UPLOAD_FOLDER,
UPLOAD_FILE_VERSION,
UploadFileVersionAction,
SnackbarErrorAction,
UnlockWriteAction
} from '../actions';
import {
map,
take,
flatMap,
distinctUntilChanged,
catchError,
distinctUntilChanged,
filter,
flatMap,
map,
switchMap,
tap,
filter
take,
tap
} from 'rxjs/operators';
import { FileUtils, FileModel, UploadService } from '@alfresco/adf-core';
import { currentFolder } from '../selectors/app.selectors';
import { fromEvent, of, forkJoin } from 'rxjs';
import { ContentManagementService } from '../../services/content-management.service';
@Injectable()
@@ -95,7 +93,7 @@ export class UploadEffects {
@Effect({ dispatch: false })
uploadFiles$ = this.actions$.pipe(
ofType<UploadFilesAction>(UPLOAD_FILES),
ofType<UploadFilesAction>(UploadActionTypes.UploadFiles),
map(() => {
this.fileInput.click();
})
@@ -103,7 +101,7 @@ export class UploadEffects {
@Effect({ dispatch: false })
uploadFolder$ = this.actions$.pipe(
ofType<UploadFolderAction>(UPLOAD_FOLDER),
ofType<UploadFolderAction>(UploadActionTypes.UploadFolder),
map(() => {
this.folderInput.click();
})
@@ -111,7 +109,7 @@ export class UploadEffects {
@Effect({ dispatch: false })
uploadVersion$ = this.actions$.pipe(
ofType<UploadFileVersionAction>(UPLOAD_FILE_VERSION),
ofType<UploadFileVersionAction>(UploadActionTypes.UploadFileVersion),
switchMap(() => {
this.fileVersionInput.click();
return fromEvent(this.fileVersionInput, 'change').pipe(
@@ -155,7 +153,7 @@ export class UploadEffects {
private upload(event: any): void {
this.store
.select(currentFolder)
.select(getCurrentFolder)
.pipe(take(1))
.subscribe(node => {
if (node && node.id) {

View File

@@ -26,16 +26,21 @@
import { Effect, Actions, ofType } from '@ngrx/effects';
import { Injectable } from '@angular/core';
import { map, take } from 'rxjs/operators';
import { VIEW_FILE, ViewFileAction } from '../actions';
import {
AppStore,
ViewerActionTypes,
ViewFileAction,
ViewNodeAction,
getCurrentFolder,
getAppSelection,
FullscreenViewerAction
} from '@alfresco/aca-shared/store';
import { Router } from '@angular/router';
import { Store, createSelector } from '@ngrx/store';
import { AppStore } from '../states';
import { appSelection, currentFolder } from '../selectors/app.selectors';
import { ViewNodeAction, VIEW_NODE } from '../actions/viewer.actions';
export const fileToPreview = createSelector(
appSelection,
currentFolder,
getAppSelection,
getCurrentFolder,
(selection, folder) => {
return {
selection,
@@ -52,9 +57,17 @@ export class ViewerEffects {
private router: Router
) {}
@Effect({ dispatch: false })
fullscreenViewer$ = this.actions$.pipe(
ofType<FullscreenViewerAction>(ViewerActionTypes.FullScreen),
map(() => {
this.enterFullScreen();
})
);
@Effect({ dispatch: false })
viewNode$ = this.actions$.pipe(
ofType<ViewNodeAction>(VIEW_NODE),
ofType<ViewNodeAction>(ViewerActionTypes.ViewNode),
map(action => {
if (action.location) {
this.router.navigate(
@@ -76,7 +89,7 @@ export class ViewerEffects {
@Effect({ dispatch: false })
viewFile$ = this.actions$.pipe(
ofType<ViewFileAction>(VIEW_FILE),
ofType<ViewFileAction>(ViewerActionTypes.ViewFile),
map(action => {
if (action.payload && action.payload.entry) {
const { id, nodeId, isFile } = <any>action.payload.entry;
@@ -123,4 +136,23 @@ export class ViewerEffects {
path.push('preview', nodeId);
this.router.navigateByUrl(path.join('/'));
}
enterFullScreen() {
const container = <any>(
document.documentElement.querySelector(
'.adf-viewer__fullscreen-container'
)
);
if (container) {
if (container.requestFullscreen) {
container.requestFullscreen();
} else if (container.webkitRequestFullscreen) {
container.webkitRequestFullscreen();
} else if (container.mozRequestFullScreen) {
container.mozRequestFullScreen();
} else if (container.msRequestFullscreen) {
container.msRequestFullscreen();
}
}
}
}