mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-09-17 14:21:14 +00:00
[ACA-1443] prettier formatting and checks (#629)
* intergrate prettier * update settings * integrate with travis * unified formatting across all files
This commit is contained in:
@@ -4,7 +4,7 @@ root = true
|
|||||||
[*]
|
[*]
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 4
|
indent_size = 2
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
2
.prettierignore
Normal file
2
.prettierignore
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
node_modules
|
||||||
|
src/assets/i18n
|
3
.prettierrc
Normal file
3
.prettierrc
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"singleQuote": true
|
||||||
|
}
|
@@ -9,7 +9,7 @@ addons:
|
|||||||
|
|
||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- "8"
|
- '8'
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
# Disable services enabled by default
|
# Disable services enabled by default
|
||||||
@@ -24,7 +24,10 @@ before_install:
|
|||||||
jobs:
|
jobs:
|
||||||
include:
|
include:
|
||||||
- stage: test
|
- stage: test
|
||||||
script: npm run lint && npm run spellcheck
|
script:
|
||||||
|
- npm run lint
|
||||||
|
- npm run spellcheck
|
||||||
|
- npm run format:check
|
||||||
- stage: test
|
- stage: test
|
||||||
script:
|
script:
|
||||||
- npm run test:ci
|
- npm run test:ci
|
||||||
|
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
"javascript.preferences.quoteStyle": "single",
|
"javascript.preferences.quoteStyle": "single",
|
||||||
"typescript.preferences.quoteStyle": "single"
|
"typescript.preferences.quoteStyle": "single",
|
||||||
|
"editor.formatOnSave": true
|
||||||
}
|
}
|
||||||
|
6
package-lock.json
generated
6
package-lock.json
generated
@@ -11444,6 +11444,12 @@
|
|||||||
"integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=",
|
"integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"prettier": {
|
||||||
|
"version": "1.14.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-1.14.2.tgz",
|
||||||
|
"integrity": "sha512-McHPg0n1pIke+A/4VcaS2en+pTNjy4xF+Uuq86u/5dyDO59/TtFZtQ708QIRkEZ3qwKz3GVkVa6mpxK/CpB8Rg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"pretty-error": {
|
"pretty-error": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz",
|
||||||
|
@@ -22,7 +22,8 @@
|
|||||||
"stop:docker": "docker-compose stop",
|
"stop:docker": "docker-compose stop",
|
||||||
"e2e:docker": "npm run start:docker && npm run e2e && npm run stop:docker",
|
"e2e:docker": "npm run start:docker && npm run e2e && npm run stop:docker",
|
||||||
"spellcheck": "cspell 'src/**/*.ts' 'e2e/**/*.ts' 'projects/**/*.ts'",
|
"spellcheck": "cspell 'src/**/*.ts' 'e2e/**/*.ts' 'projects/**/*.ts'",
|
||||||
"inspect.bundle": "ng build app --prod --stats-json && npx webpack-bundle-analyzer dist/app/stats.json"
|
"inspect.bundle": "ng build app --prod --stats-json && npx webpack-bundle-analyzer dist/app/stats.json",
|
||||||
|
"format:check": "prettier --list-different \"src/{app,environments}/**/*{.ts,.js,.json,.css,.scss}\""
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -89,6 +90,7 @@
|
|||||||
"karma-jasmine": "~1.1.0",
|
"karma-jasmine": "~1.1.0",
|
||||||
"karma-jasmine-html-reporter": "^0.2.2",
|
"karma-jasmine-html-reporter": "^0.2.2",
|
||||||
"ng-packagr": "^4.1.1",
|
"ng-packagr": "^4.1.1",
|
||||||
|
"prettier": "^1.14.2",
|
||||||
"protractor": "^5.4.0",
|
"protractor": "^5.4.0",
|
||||||
"rimraf": "2.6.2",
|
"rimraf": "2.6.2",
|
||||||
"selenium-webdriver": "4.0.0-alpha.1",
|
"selenium-webdriver": "4.0.0-alpha.1",
|
||||||
|
@@ -41,7 +41,11 @@ import {
|
|||||||
SetCurrentUrlAction,
|
SetCurrentUrlAction,
|
||||||
SetInitialStateAction
|
SetInitialStateAction
|
||||||
} from './store/actions';
|
} from './store/actions';
|
||||||
import { AppStore, AppState, INITIAL_APP_STATE } from './store/states/app.state';
|
import {
|
||||||
|
AppStore,
|
||||||
|
AppState,
|
||||||
|
INITIAL_APP_STATE
|
||||||
|
} from './store/states/app.state';
|
||||||
import { filter } from 'rxjs/operators';
|
import { filter } from 'rxjs/operators';
|
||||||
import { MatDialog } from '@angular/material';
|
import { MatDialog } from '@angular/material';
|
||||||
|
|
||||||
@@ -68,7 +72,10 @@ export class AppComponent implements OnInit {
|
|||||||
this.alfrescoApiService.getInstance().on('error', error => {
|
this.alfrescoApiService.getInstance().on('error', error => {
|
||||||
if (error.status === 401) {
|
if (error.status === 401) {
|
||||||
if (!this.authenticationService.isLoggedIn()) {
|
if (!this.authenticationService.isLoggedIn()) {
|
||||||
this.authenticationService.setRedirect({ provider: 'ECM', url: this.router.url });
|
this.authenticationService.setRedirect({
|
||||||
|
provider: 'ECM',
|
||||||
|
url: this.router.url
|
||||||
|
});
|
||||||
this.router.navigate(['/login']);
|
this.router.navigate(['/login']);
|
||||||
|
|
||||||
this.dialogRef.closeAll();
|
this.dialogRef.closeAll();
|
||||||
|
@@ -28,7 +28,12 @@ import { NgModule } from '@angular/core';
|
|||||||
import { RouterModule, RouteReuseStrategy } from '@angular/router';
|
import { RouterModule, RouteReuseStrategy } from '@angular/router';
|
||||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
import { TRANSLATION_PROVIDER, CoreModule, AppConfigService, DebugAppConfigService } from '@alfresco/adf-core';
|
import {
|
||||||
|
TRANSLATION_PROVIDER,
|
||||||
|
CoreModule,
|
||||||
|
AppConfigService,
|
||||||
|
DebugAppConfigService
|
||||||
|
} from '@alfresco/adf-core';
|
||||||
import { ContentModule } from '@alfresco/adf-content-services';
|
import { ContentModule } from '@alfresco/adf-content-services';
|
||||||
|
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
|
@@ -119,8 +119,6 @@ export class AppRouteReuseStrategy implements RouteReuseStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getRouteData(route: ActivatedRouteSnapshot): RouteData {
|
private getRouteData(route: ActivatedRouteSnapshot): RouteData {
|
||||||
return (
|
return route.routeConfig && (route.routeConfig.data as RouteData);
|
||||||
route.routeConfig && (route.routeConfig.data as RouteData)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -52,7 +52,8 @@ export const APP_ROUTES: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'settings',
|
path: 'settings',
|
||||||
loadChildren: 'src/app/components/settings/settings.module#AppSettingsModule',
|
loadChildren:
|
||||||
|
'src/app/components/settings/settings.module#AppSettingsModule',
|
||||||
data: {
|
data: {
|
||||||
title: 'Settings'
|
title: 'Settings'
|
||||||
}
|
}
|
||||||
@@ -61,7 +62,7 @@ export const APP_ROUTES: Routes = [
|
|||||||
path: 'preview/s/:id',
|
path: 'preview/s/:id',
|
||||||
component: SharedLinkViewComponent,
|
component: SharedLinkViewComponent,
|
||||||
data: {
|
data: {
|
||||||
title: 'APP.PREVIEW.TITLE',
|
title: 'APP.PREVIEW.TITLE'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -89,7 +90,8 @@ export const APP_ROUTES: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'preview/:nodeId',
|
path: 'preview/:nodeId',
|
||||||
loadChildren: 'src/app/components/preview/preview.module#PreviewModule',
|
loadChildren:
|
||||||
|
'src/app/components/preview/preview.module#PreviewModule',
|
||||||
data: {
|
data: {
|
||||||
title: 'APP.PREVIEW.TITLE',
|
title: 'APP.PREVIEW.TITLE',
|
||||||
navigateMultiple: true,
|
navigateMultiple: true,
|
||||||
@@ -103,13 +105,15 @@ export const APP_ROUTES: Routes = [
|
|||||||
data: {
|
data: {
|
||||||
sortingPreferenceKey: 'libraries'
|
sortingPreferenceKey: 'libraries'
|
||||||
},
|
},
|
||||||
children: [{
|
children: [
|
||||||
|
{
|
||||||
path: '',
|
path: '',
|
||||||
component: LibrariesComponent,
|
component: LibrariesComponent,
|
||||||
data: {
|
data: {
|
||||||
title: 'APP.BROWSE.LIBRARIES.TITLE'
|
title: 'APP.BROWSE.LIBRARIES.TITLE'
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
path: ':folderId',
|
path: ':folderId',
|
||||||
component: FilesComponent,
|
component: FilesComponent,
|
||||||
data: {
|
data: {
|
||||||
@@ -119,7 +123,8 @@ export const APP_ROUTES: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: ':folderId/preview/:nodeId',
|
path: ':folderId/preview/:nodeId',
|
||||||
loadChildren: 'src/app/components/preview/preview.module#PreviewModule',
|
loadChildren:
|
||||||
|
'src/app/components/preview/preview.module#PreviewModule',
|
||||||
data: {
|
data: {
|
||||||
title: 'APP.PREVIEW.TITLE',
|
title: 'APP.PREVIEW.TITLE',
|
||||||
navigateMultiple: true,
|
navigateMultiple: true,
|
||||||
@@ -151,7 +156,8 @@ export const APP_ROUTES: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'preview/:nodeId',
|
path: 'preview/:nodeId',
|
||||||
loadChildren: 'src/app/components/preview/preview.module#PreviewModule',
|
loadChildren:
|
||||||
|
'src/app/components/preview/preview.module#PreviewModule',
|
||||||
data: {
|
data: {
|
||||||
title: 'APP.PREVIEW.TITLE',
|
title: 'APP.PREVIEW.TITLE',
|
||||||
navigateMultiple: true,
|
navigateMultiple: true,
|
||||||
@@ -160,7 +166,8 @@ export const APP_ROUTES: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: ':folderId/preview/:nodeId',
|
path: ':folderId/preview/:nodeId',
|
||||||
loadChildren: 'src/app/components/preview/preview.module#PreviewModule',
|
loadChildren:
|
||||||
|
'src/app/components/preview/preview.module#PreviewModule',
|
||||||
data: {
|
data: {
|
||||||
title: 'APP.PREVIEW.TITLE',
|
title: 'APP.PREVIEW.TITLE',
|
||||||
navigateMultiple: true,
|
navigateMultiple: true,
|
||||||
@@ -184,7 +191,8 @@ export const APP_ROUTES: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'preview/:nodeId',
|
path: 'preview/:nodeId',
|
||||||
loadChildren: 'src/app/components/preview/preview.module#PreviewModule',
|
loadChildren:
|
||||||
|
'src/app/components/preview/preview.module#PreviewModule',
|
||||||
data: {
|
data: {
|
||||||
title: 'APP.PREVIEW.TITLE',
|
title: 'APP.PREVIEW.TITLE',
|
||||||
navigateMultiple: true,
|
navigateMultiple: true,
|
||||||
@@ -208,7 +216,8 @@ export const APP_ROUTES: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'preview/:nodeId',
|
path: 'preview/:nodeId',
|
||||||
loadChildren: 'src/app/components/preview/preview.module#PreviewModule',
|
loadChildren:
|
||||||
|
'src/app/components/preview/preview.module#PreviewModule',
|
||||||
data: {
|
data: {
|
||||||
title: 'APP.PREVIEW.TITLE',
|
title: 'APP.PREVIEW.TITLE',
|
||||||
navigateMultiple: true,
|
navigateMultiple: true,
|
||||||
@@ -245,7 +254,8 @@ export const APP_ROUTES: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'preview/:nodeId',
|
path: 'preview/:nodeId',
|
||||||
loadChildren: 'src/app/components/preview/preview.module#PreviewModule',
|
loadChildren:
|
||||||
|
'src/app/components/preview/preview.module#PreviewModule',
|
||||||
data: {
|
data: {
|
||||||
title: 'APP.PREVIEW.TITLE',
|
title: 'APP.PREVIEW.TITLE',
|
||||||
navigateMultiple: true,
|
navigateMultiple: true,
|
||||||
@@ -263,4 +273,3 @@ export const APP_ROUTES: Routes = [
|
|||||||
canActivate: [AuthGuardEcm]
|
canActivate: [AuthGuardEcm]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@@ -40,7 +40,8 @@ export class AboutComponent implements OnInit {
|
|||||||
status: ObjectDataTableAdapter;
|
status: ObjectDataTableAdapter;
|
||||||
license: ObjectDataTableAdapter;
|
license: ObjectDataTableAdapter;
|
||||||
modules: ObjectDataTableAdapter;
|
modules: ObjectDataTableAdapter;
|
||||||
githubUrlCommitAlpha = 'https://github.com/Alfresco/alfresco-content-app/commits';
|
githubUrlCommitAlpha =
|
||||||
|
'https://github.com/Alfresco/alfresco-content-app/commits';
|
||||||
releaseVersion = '';
|
releaseVersion = '';
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@@ -49,7 +50,8 @@ export class AboutComponent implements OnInit {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.contentApi.getRepositoryInformation()
|
this.contentApi
|
||||||
|
.getRepositoryInformation()
|
||||||
.pipe(map(node => node.entry.repository))
|
.pipe(map(node => node.entry.repository))
|
||||||
.subscribe(repository => {
|
.subscribe(repository => {
|
||||||
this.repository = repository;
|
this.repository = repository;
|
||||||
@@ -57,49 +59,128 @@ export class AboutComponent implements OnInit {
|
|||||||
this.modules = new ObjectDataTableAdapter(repository.modules, [
|
this.modules = new ObjectDataTableAdapter(repository.modules, [
|
||||||
{ type: 'text', key: 'id', title: 'ID', sortable: true },
|
{ type: 'text', key: 'id', title: 'ID', sortable: true },
|
||||||
{ type: 'text', key: 'title', title: 'Title', sortable: true },
|
{ type: 'text', key: 'title', title: 'Title', sortable: true },
|
||||||
{type: 'text', key: 'version', title: 'Description', sortable: true},
|
{
|
||||||
{type: 'date', key: 'installDate', title: 'Install Date', sortable: true},
|
type: 'text',
|
||||||
{type: 'text', key: 'installState', title: 'Install State', sortable: true},
|
key: 'version',
|
||||||
{type: 'text', key: 'versionMin', title: 'Version Minor', sortable: true},
|
title: 'Description',
|
||||||
{type: 'text', key: 'versionMax', title: 'Version Max', sortable: true}
|
sortable: true
|
||||||
]);
|
},
|
||||||
|
{
|
||||||
this.status = new ObjectDataTableAdapter([repository.status], [
|
type: 'date',
|
||||||
{type: 'text', key: 'isReadOnly', title: 'Read Only', sortable: true},
|
key: 'installDate',
|
||||||
{type: 'text', key: 'isAuditEnabled', title: 'Audit Enable', sortable: true},
|
title: 'Install Date',
|
||||||
{type: 'text', key: 'isQuickShareEnabled', title: 'Quick Shared Enable', sortable: true},
|
sortable: true
|
||||||
{type: 'text', key: 'isThumbnailGenerationEnabled', title: 'Thumbnail Generation', sortable: true}
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
key: 'installState',
|
||||||
|
title: 'Install State',
|
||||||
|
sortable: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
key: 'versionMin',
|
||||||
|
title: 'Version Minor',
|
||||||
|
sortable: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
key: 'versionMax',
|
||||||
|
title: 'Version Max',
|
||||||
|
sortable: true
|
||||||
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
this.status = new ObjectDataTableAdapter(
|
||||||
|
[repository.status],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
key: 'isReadOnly',
|
||||||
|
title: 'Read Only',
|
||||||
|
sortable: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
key: 'isAuditEnabled',
|
||||||
|
title: 'Audit Enable',
|
||||||
|
sortable: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
key: 'isQuickShareEnabled',
|
||||||
|
title: 'Quick Shared Enable',
|
||||||
|
sortable: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
key: 'isThumbnailGenerationEnabled',
|
||||||
|
title: 'Thumbnail Generation',
|
||||||
|
sortable: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
if (repository.license) {
|
if (repository.license) {
|
||||||
this.license = new ObjectDataTableAdapter([repository.license], [
|
this.license = new ObjectDataTableAdapter(
|
||||||
{type: 'date', key: 'issuedAt', title: 'Issued At', sortable: true},
|
[repository.license],
|
||||||
{type: 'date', key: 'expiresAt', title: 'Expires At', sortable: true},
|
[
|
||||||
{type: 'text', key: 'remainingDays', title: 'Remaining Days', sortable: true},
|
{
|
||||||
|
type: 'date',
|
||||||
|
key: 'issuedAt',
|
||||||
|
title: 'Issued At',
|
||||||
|
sortable: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'date',
|
||||||
|
key: 'expiresAt',
|
||||||
|
title: 'Expires At',
|
||||||
|
sortable: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
key: 'remainingDays',
|
||||||
|
title: 'Remaining Days',
|
||||||
|
sortable: true
|
||||||
|
},
|
||||||
{ type: 'text', key: 'holder', title: 'Holder', sortable: true },
|
{ type: 'text', key: 'holder', title: 'Holder', sortable: true },
|
||||||
{ type: 'text', key: 'mode', title: 'Type', sortable: true },
|
{ type: 'text', key: 'mode', title: 'Type', sortable: true },
|
||||||
{type: 'text', key: 'isClusterEnabled', title: 'Cluster Enabled', sortable: true},
|
{
|
||||||
{type: 'text', key: 'isCryptodocEnabled', title: 'Cryptodoc Enable', sortable: true}
|
type: 'text',
|
||||||
]);
|
key: 'isClusterEnabled',
|
||||||
|
title: 'Cluster Enabled',
|
||||||
|
sortable: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
key: 'isCryptodocEnabled',
|
||||||
|
title: 'Cryptodoc Enable',
|
||||||
|
sortable: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.http.get('/versions.json')
|
this.http.get('/versions.json').subscribe((response: any) => {
|
||||||
.subscribe((response: any) => {
|
|
||||||
const regexp = new RegExp('^(@alfresco|alfresco-)');
|
const regexp = new RegExp('^(@alfresco|alfresco-)');
|
||||||
|
|
||||||
const alfrescoPackagesTableRepresentation = Object.keys(response.dependencies)
|
const alfrescoPackagesTableRepresentation = Object.keys(
|
||||||
.filter((val) => regexp.test(val))
|
response.dependencies
|
||||||
.map((val) => ({
|
)
|
||||||
|
.filter(val => regexp.test(val))
|
||||||
|
.map(val => ({
|
||||||
name: val,
|
name: val,
|
||||||
version: response.dependencies[val].version
|
version: response.dependencies[val].version
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.data = new ObjectDataTableAdapter(alfrescoPackagesTableRepresentation, [
|
this.data = new ObjectDataTableAdapter(
|
||||||
|
alfrescoPackagesTableRepresentation,
|
||||||
|
[
|
||||||
{ type: 'text', key: 'name', title: 'Name', sortable: true },
|
{ type: 'text', key: 'name', title: 'Name', sortable: true },
|
||||||
{ type: 'text', key: 'version', title: 'Version', sortable: true }
|
{ type: 'text', key: 'version', title: 'Version', sortable: true }
|
||||||
]);
|
]
|
||||||
|
);
|
||||||
|
|
||||||
this.releaseVersion = response.version;
|
this.releaseVersion = response.version;
|
||||||
});
|
});
|
||||||
|
@@ -37,12 +37,7 @@ const routes: Routes = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [CommonModule, CoreModule.forChild(), RouterModule.forChild(routes)],
|
||||||
CommonModule,
|
|
||||||
CoreModule.forChild(),
|
|
||||||
RouterModule.forChild(routes)
|
|
||||||
],
|
|
||||||
declarations: [AboutComponent]
|
declarations: [AboutComponent]
|
||||||
})
|
})
|
||||||
export class AboutModule {
|
export class AboutModule {}
|
||||||
}
|
|
||||||
|
@@ -34,19 +34,35 @@ import {
|
|||||||
} from '@angular/animations';
|
} from '@angular/animations';
|
||||||
|
|
||||||
export const contextMenuAnimation = [
|
export const contextMenuAnimation = [
|
||||||
state('void', style({
|
state(
|
||||||
|
'void',
|
||||||
|
style({
|
||||||
opacity: 0,
|
opacity: 0,
|
||||||
transform: 'scale(0.01, 0.01)'
|
transform: 'scale(0.01, 0.01)'
|
||||||
})),
|
})
|
||||||
transition('void => *', sequence([
|
),
|
||||||
|
transition(
|
||||||
|
'void => *',
|
||||||
|
sequence([
|
||||||
query('.mat-menu-content', style({ opacity: 0 })),
|
query('.mat-menu-content', style({ opacity: 0 })),
|
||||||
animate('100ms linear', style({ opacity: 1, transform: 'scale(1, 0.5)' })),
|
animate(
|
||||||
|
'100ms linear',
|
||||||
|
style({ opacity: 1, transform: 'scale(1, 0.5)' })
|
||||||
|
),
|
||||||
group([
|
group([
|
||||||
query('.mat-menu-content', animate('400ms cubic-bezier(0.55, 0, 0.55, 0.2)',
|
query(
|
||||||
|
'.mat-menu-content',
|
||||||
|
animate(
|
||||||
|
'400ms cubic-bezier(0.55, 0, 0.55, 0.2)',
|
||||||
style({ opacity: 1 })
|
style({ opacity: 1 })
|
||||||
)),
|
)
|
||||||
animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({ transform: 'scale(1, 1)' })),
|
),
|
||||||
|
animate(
|
||||||
|
'300ms cubic-bezier(0.25, 0.8, 0.25, 1)',
|
||||||
|
style({ transform: 'scale(1, 1)' })
|
||||||
|
)
|
||||||
])
|
])
|
||||||
])),
|
])
|
||||||
|
),
|
||||||
transition('* => void', animate('150ms 50ms linear', style({ opacity: 0 })))
|
transition('* => void', animate('150ms 50ms linear', style({ opacity: 0 })))
|
||||||
];
|
];
|
||||||
|
@@ -27,13 +27,13 @@ import { Directive, ElementRef, OnDestroy } from '@angular/core';
|
|||||||
import { FocusableOption, FocusMonitor, FocusOrigin } from '@angular/cdk/a11y';
|
import { FocusableOption, FocusMonitor, FocusOrigin } from '@angular/cdk/a11y';
|
||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: '[acaContextMenuItem]',
|
selector: '[acaContextMenuItem]'
|
||||||
})
|
})
|
||||||
export class ContextMenuItemDirective implements OnDestroy, FocusableOption {
|
export class ContextMenuItemDirective implements OnDestroy, FocusableOption {
|
||||||
constructor(
|
constructor(
|
||||||
private elementRef: ElementRef,
|
private elementRef: ElementRef,
|
||||||
private focusMonitor: FocusMonitor) {
|
private focusMonitor: FocusMonitor
|
||||||
|
) {
|
||||||
focusMonitor.monitor(this.getHostElement(), false);
|
focusMonitor.monitor(this.getHostElement(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,15 +1,21 @@
|
|||||||
import { Directive, Output, EventEmitter, OnInit, OnDestroy } from '@angular/core';
|
import {
|
||||||
|
Directive,
|
||||||
|
Output,
|
||||||
|
EventEmitter,
|
||||||
|
OnInit,
|
||||||
|
OnDestroy
|
||||||
|
} from '@angular/core';
|
||||||
import { fromEvent, Subscription } from 'rxjs';
|
import { fromEvent, Subscription } from 'rxjs';
|
||||||
import { delay } from 'rxjs/operators';
|
import { delay } from 'rxjs/operators';
|
||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: '[acaContextMenuOutsideEvent]'
|
selector: '[acaContextMenuOutsideEvent]'
|
||||||
})
|
})
|
||||||
|
|
||||||
export class OutsideEventDirective implements OnInit, OnDestroy {
|
export class OutsideEventDirective implements OnInit, OnDestroy {
|
||||||
private subscriptions: Subscription[] = [];
|
private subscriptions: Subscription[] = [];
|
||||||
|
|
||||||
@Output() clickOutside: EventEmitter<null> = new EventEmitter();
|
@Output()
|
||||||
|
clickOutside: EventEmitter<null> = new EventEmitter();
|
||||||
|
|
||||||
constructor() {}
|
constructor() {}
|
||||||
|
|
||||||
|
@@ -26,7 +26,6 @@
|
|||||||
import { OverlayRef } from '@angular/cdk/overlay';
|
import { OverlayRef } from '@angular/cdk/overlay';
|
||||||
|
|
||||||
export class ContextMenuOverlayRef {
|
export class ContextMenuOverlayRef {
|
||||||
|
|
||||||
constructor(private overlayRef: OverlayRef) {}
|
constructor(private overlayRef: OverlayRef) {}
|
||||||
|
|
||||||
close(): void {
|
close(): void {
|
||||||
|
@@ -24,8 +24,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Component, ViewEncapsulation, OnInit, OnDestroy, HostListener,
|
Component,
|
||||||
ViewChildren, QueryList, AfterViewInit
|
ViewEncapsulation,
|
||||||
|
OnInit,
|
||||||
|
OnDestroy,
|
||||||
|
HostListener,
|
||||||
|
ViewChildren,
|
||||||
|
QueryList,
|
||||||
|
AfterViewInit
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { trigger } from '@angular/animations';
|
import { trigger } from '@angular/animations';
|
||||||
import { FocusKeyManager } from '@angular/cdk/a11y';
|
import { FocusKeyManager } from '@angular/cdk/a11y';
|
||||||
@@ -55,9 +61,7 @@ import { ContextMenuItemDirective } from './context-menu-item.directive';
|
|||||||
class: 'aca-context-menu'
|
class: 'aca-context-menu'
|
||||||
},
|
},
|
||||||
encapsulation: ViewEncapsulation.None,
|
encapsulation: ViewEncapsulation.None,
|
||||||
animations: [
|
animations: [trigger('panelAnimation', contextMenuAnimation)]
|
||||||
trigger('panelAnimation', contextMenuAnimation)
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
export class ContextMenuComponent implements OnInit, OnDestroy, AfterViewInit {
|
export class ContextMenuComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
private onDestroy$: Subject<boolean> = new Subject<boolean>();
|
private onDestroy$: Subject<boolean> = new Subject<boolean>();
|
||||||
@@ -100,7 +104,7 @@ export class ContextMenuComponent implements OnInit, OnDestroy, AfterViewInit {
|
|||||||
constructor(
|
constructor(
|
||||||
private contextMenuOverlayRef: ContextMenuOverlayRef,
|
private contextMenuOverlayRef: ContextMenuOverlayRef,
|
||||||
private extensions: AppExtensionService,
|
private extensions: AppExtensionService,
|
||||||
private store: Store<AppStore>,
|
private store: Store<AppStore>
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
onClickOutsideEvent() {
|
onClickOutsideEvent() {
|
||||||
@@ -136,7 +140,9 @@ export class ContextMenuComponent implements OnInit, OnDestroy, AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngAfterViewInit() {
|
ngAfterViewInit() {
|
||||||
this._keyManager = new FocusKeyManager<ContextMenuItemDirective>(this.contextMenuItems);
|
this._keyManager = new FocusKeyManager<ContextMenuItemDirective>(
|
||||||
|
this.contextMenuItems
|
||||||
|
);
|
||||||
this._keyManager.setFirstItemActive();
|
this._keyManager.setFirstItemActive();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -40,7 +40,8 @@ export class ContextActionsDirective {
|
|||||||
private overlayRef: ContextMenuOverlayRef = null;
|
private overlayRef: ContextMenuOverlayRef = null;
|
||||||
|
|
||||||
// tslint:disable-next-line:no-input-rename
|
// tslint:disable-next-line:no-input-rename
|
||||||
@Input('acaContextEnable') enabled = true;
|
@Input('acaContextEnable')
|
||||||
|
enabled = true;
|
||||||
|
|
||||||
@HostListener('window:resize', ['$event'])
|
@HostListener('window:resize', ['$event'])
|
||||||
onResize(event) {
|
onResize(event) {
|
||||||
@@ -93,7 +94,7 @@ export class ContextActionsDirective {
|
|||||||
source: event,
|
source: event,
|
||||||
hasBackdrop: false,
|
hasBackdrop: false,
|
||||||
backdropClass: 'cdk-overlay-transparent-backdrop',
|
backdropClass: 'cdk-overlay-transparent-backdrop',
|
||||||
panelClass: 'cdk-overlay-pane',
|
panelClass: 'cdk-overlay-pane'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,22 +105,27 @@ export class ContextActionsDirective {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private isInSelection(row: DataRow): MinimalNodeEntity {
|
private isInSelection(row: DataRow): MinimalNodeEntity {
|
||||||
return this.documentList.selection.find((selected) =>
|
return this.documentList.selection.find(
|
||||||
row.getValue('name') === selected.entry.name);
|
selected => row.getValue('name') === selected.entry.name
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getSelectedRow(event): DataRow {
|
private getSelectedRow(event): DataRow {
|
||||||
const rowElement = this.findAncestor(<HTMLElement>event.target, 'adf-datatable-row');
|
const rowElement = this.findAncestor(
|
||||||
|
<HTMLElement>event.target,
|
||||||
|
'adf-datatable-row'
|
||||||
|
);
|
||||||
|
|
||||||
if (!rowElement) {
|
if (!rowElement) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const rowName = rowElement.querySelector('.adf-data-table-cell--text .adf-datatable-cell')
|
const rowName = rowElement
|
||||||
.textContent
|
.querySelector('.adf-data-table-cell--text .adf-datatable-cell')
|
||||||
.trim();
|
.textContent.trim();
|
||||||
|
|
||||||
return this.documentList.data.getRows()
|
return this.documentList.data
|
||||||
|
.getRows()
|
||||||
.find((row: DataRow) => row.getValue('name') === rowName);
|
.find((row: DataRow) => row.getValue('name') === rowName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -24,7 +24,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { NgModule, ModuleWithProviders } from '@angular/core';
|
import { NgModule, ModuleWithProviders } from '@angular/core';
|
||||||
import { MatMenuModule, MatListModule, MatIconModule, MatButtonModule } from '@angular/material';
|
import {
|
||||||
|
MatMenuModule,
|
||||||
|
MatListModule,
|
||||||
|
MatIconModule,
|
||||||
|
MatButtonModule
|
||||||
|
} from '@angular/material';
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
import { CoreModule } from '@alfresco/adf-core';
|
import { CoreModule } from '@alfresco/adf-core';
|
||||||
import { CoreExtensionsModule } from '../../extensions/core.extensions.module';
|
import { CoreExtensionsModule } from '../../extensions/core.extensions.module';
|
||||||
@@ -58,17 +63,13 @@ import { OutsideEventDirective } from './context-menu-outside-event.directive';
|
|||||||
ContextActionsDirective,
|
ContextActionsDirective,
|
||||||
ContextMenuComponent
|
ContextMenuComponent
|
||||||
],
|
],
|
||||||
entryComponents: [
|
entryComponents: [ContextMenuComponent]
|
||||||
ContextMenuComponent
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
export class ContextMenuModule {
|
export class ContextMenuModule {
|
||||||
static forRoot(): ModuleWithProviders {
|
static forRoot(): ModuleWithProviders {
|
||||||
return {
|
return {
|
||||||
ngModule: ContextMenuModule,
|
ngModule: ContextMenuModule,
|
||||||
providers: [
|
providers: [ContextMenuService]
|
||||||
ContextMenuService
|
|
||||||
]
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -7,12 +7,9 @@ import { ContextmenuOverlayConfig } from './interfaces';
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ContextMenuService {
|
export class ContextMenuService {
|
||||||
constructor(
|
constructor(private injector: Injector, private overlay: Overlay) {}
|
||||||
private injector: Injector,
|
|
||||||
private overlay: Overlay) { }
|
|
||||||
|
|
||||||
open(config: ContextmenuOverlayConfig) {
|
open(config: ContextmenuOverlayConfig) {
|
||||||
|
|
||||||
const overlay = this.createOverlay(config);
|
const overlay = this.createOverlay(config);
|
||||||
|
|
||||||
const overlayRef = new ContextMenuOverlayRef(overlay);
|
const overlayRef = new ContextMenuOverlayRef(overlay);
|
||||||
@@ -23,11 +20,14 @@ export class ContextMenuService {
|
|||||||
|
|
||||||
// prevent native contextmenu on overlay element if config.hasBackdrop is true
|
// prevent native contextmenu on overlay element if config.hasBackdrop is true
|
||||||
if (config.hasBackdrop) {
|
if (config.hasBackdrop) {
|
||||||
(<any>overlay)._backdropElement
|
(<any>overlay)._backdropElement.addEventListener(
|
||||||
.addEventListener('contextmenu', () => {
|
'contextmenu',
|
||||||
|
() => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
(<any>overlay)._backdropClick.next(null);
|
(<any>overlay)._backdropClick.next(null);
|
||||||
}, true);
|
},
|
||||||
|
true
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return overlayRef;
|
return overlayRef;
|
||||||
@@ -38,16 +38,29 @@ export class ContextMenuService {
|
|||||||
return this.overlay.create(overlayConfig);
|
return this.overlay.create(overlayConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
private attachDialogContainer(overlay: OverlayRef, config: ContextmenuOverlayConfig, contextmenuOverlayRef: ContextMenuOverlayRef) {
|
private attachDialogContainer(
|
||||||
|
overlay: OverlayRef,
|
||||||
|
config: ContextmenuOverlayConfig,
|
||||||
|
contextmenuOverlayRef: ContextMenuOverlayRef
|
||||||
|
) {
|
||||||
const injector = this.createInjector(config, contextmenuOverlayRef);
|
const injector = this.createInjector(config, contextmenuOverlayRef);
|
||||||
|
|
||||||
const containerPortal = new ComponentPortal(ContextMenuComponent, null, injector);
|
const containerPortal = new ComponentPortal(
|
||||||
const containerRef: ComponentRef<ContextMenuComponent> = overlay.attach(containerPortal);
|
ContextMenuComponent,
|
||||||
|
null,
|
||||||
|
injector
|
||||||
|
);
|
||||||
|
const containerRef: ComponentRef<ContextMenuComponent> = overlay.attach(
|
||||||
|
containerPortal
|
||||||
|
);
|
||||||
|
|
||||||
return containerRef.instance;
|
return containerRef.instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private createInjector(config: ContextmenuOverlayConfig, contextmenuOverlayRef: ContextMenuOverlayRef): PortalInjector {
|
private createInjector(
|
||||||
|
config: ContextmenuOverlayConfig,
|
||||||
|
contextmenuOverlayRef: ContextMenuOverlayRef
|
||||||
|
): PortalInjector {
|
||||||
const injectionTokens = new WeakMap();
|
const injectionTokens = new WeakMap();
|
||||||
|
|
||||||
injectionTokens.set(ContextMenuOverlayRef, contextmenuOverlayRef);
|
injectionTokens.set(ContextMenuOverlayRef, contextmenuOverlayRef);
|
||||||
@@ -67,23 +80,29 @@ export class ContextMenuService {
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
const positionStrategy = this.overlay.position()
|
const positionStrategy = this.overlay
|
||||||
|
.position()
|
||||||
.connectedTo(
|
.connectedTo(
|
||||||
new ElementRef(fakeElement),
|
new ElementRef(fakeElement),
|
||||||
{ originX: 'start', originY: 'bottom' },
|
{ originX: 'start', originY: 'bottom' },
|
||||||
{ overlayX: 'start', overlayY: 'top' })
|
{ overlayX: 'start', overlayY: 'top' }
|
||||||
|
)
|
||||||
.withFallbackPosition(
|
.withFallbackPosition(
|
||||||
{ originX: 'start', originY: 'top' },
|
{ originX: 'start', originY: 'top' },
|
||||||
{ overlayX: 'start', overlayY: 'bottom' })
|
{ overlayX: 'start', overlayY: 'bottom' }
|
||||||
|
)
|
||||||
.withFallbackPosition(
|
.withFallbackPosition(
|
||||||
{ originX: 'end', originY: 'top' },
|
{ originX: 'end', originY: 'top' },
|
||||||
{ overlayX: 'start', overlayY: 'top' })
|
{ overlayX: 'start', overlayY: 'top' }
|
||||||
|
)
|
||||||
.withFallbackPosition(
|
.withFallbackPosition(
|
||||||
{ originX: 'start', originY: 'top' },
|
{ originX: 'start', originY: 'top' },
|
||||||
{ overlayX: 'end', overlayY: 'top' })
|
{ overlayX: 'end', overlayY: 'top' }
|
||||||
|
)
|
||||||
.withFallbackPosition(
|
.withFallbackPosition(
|
||||||
{ originX: 'end', originY: 'center' },
|
{ originX: 'end', originY: 'center' },
|
||||||
{ overlayX: 'start', overlayY: 'center' })
|
{ overlayX: 'start', overlayY: 'center' }
|
||||||
|
)
|
||||||
.withFallbackPosition(
|
.withFallbackPosition(
|
||||||
{ originX: 'start', originY: 'center' },
|
{ originX: 'start', originY: 'center' },
|
||||||
{ overlayX: 'end', overlayY: 'center' }
|
{ overlayX: 'end', overlayY: 'center' }
|
||||||
|
@@ -18,7 +18,7 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
background-color: mat-color($background, card, .15);
|
background-color: mat-color($background, card, 0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
.current-user__full-name {
|
.current-user__full-name {
|
||||||
|
@@ -26,7 +26,10 @@
|
|||||||
import { Component, ViewEncapsulation } from '@angular/core';
|
import { Component, ViewEncapsulation } from '@angular/core';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { selectUser, appLanguagePicker } from '../../store/selectors/app.selectors';
|
import {
|
||||||
|
selectUser,
|
||||||
|
appLanguagePicker
|
||||||
|
} from '../../store/selectors/app.selectors';
|
||||||
import { AppStore } from '../../store/states';
|
import { AppStore } from '../../store/states';
|
||||||
import { ProfileState } from '@alfresco/adf-extensions';
|
import { ProfileState } from '@alfresco/adf-extensions';
|
||||||
import { SetSelectedNodesAction } from '../../store/actions';
|
import { SetSelectedNodesAction } from '../../store/actions';
|
||||||
|
@@ -28,8 +28,11 @@ import { Router } from '@angular/router';
|
|||||||
import { TestBed, ComponentFixture } from '@angular/core/testing';
|
import { TestBed, ComponentFixture } from '@angular/core/testing';
|
||||||
import {
|
import {
|
||||||
AlfrescoApiService,
|
AlfrescoApiService,
|
||||||
TimeAgoPipe, NodeNameTooltipPipe,
|
TimeAgoPipe,
|
||||||
NodeFavoriteDirective, DataTableComponent, AppConfigPipe
|
NodeNameTooltipPipe,
|
||||||
|
NodeFavoriteDirective,
|
||||||
|
DataTableComponent,
|
||||||
|
AppConfigPipe
|
||||||
} from '@alfresco/adf-core';
|
} from '@alfresco/adf-core';
|
||||||
import { DocumentListComponent } from '@alfresco/adf-content-services';
|
import { DocumentListComponent } from '@alfresco/adf-content-services';
|
||||||
import { ContentManagementService } from '../../services/content-management.service';
|
import { ContentManagementService } from '../../services/content-management.service';
|
||||||
@@ -91,7 +94,9 @@ describe('FavoritesComponent', () => {
|
|||||||
|
|
||||||
alfrescoApi = TestBed.get(AlfrescoApiService);
|
alfrescoApi = TestBed.get(AlfrescoApiService);
|
||||||
alfrescoApi.reset();
|
alfrescoApi.reset();
|
||||||
spyOn(alfrescoApi.favoritesApi, 'getFavorites').and.returnValue(Promise.resolve(page));
|
spyOn(alfrescoApi.favoritesApi, 'getFavorites').and.returnValue(
|
||||||
|
Promise.resolve(page)
|
||||||
|
);
|
||||||
|
|
||||||
contentApi = TestBed.get(ContentApiService);
|
contentApi = TestBed.get(ContentApiService);
|
||||||
|
|
||||||
@@ -142,7 +147,10 @@ describe('FavoritesComponent', () => {
|
|||||||
|
|
||||||
component.navigate(node);
|
component.navigate(node);
|
||||||
|
|
||||||
expect(router.navigate).toHaveBeenCalledWith([ '/libraries', 'folder-node' ]);
|
expect(router.navigate).toHaveBeenCalledWith([
|
||||||
|
'/libraries',
|
||||||
|
'folder-node'
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('navigates to `/personal-files` if node path has no `Sites`', () => {
|
it('navigates to `/personal-files` if node path has no `Sites`', () => {
|
||||||
@@ -150,7 +158,10 @@ describe('FavoritesComponent', () => {
|
|||||||
|
|
||||||
component.navigate(node);
|
component.navigate(node);
|
||||||
|
|
||||||
expect(router.navigate).toHaveBeenCalledWith([ '/personal-files', 'folder-node' ]);
|
expect(router.navigate).toHaveBeenCalledWith([
|
||||||
|
'/personal-files',
|
||||||
|
'folder-node'
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not navigate when node is not folder', () => {
|
it('does not navigate when node is not folder', () => {
|
||||||
|
@@ -69,10 +69,7 @@ export class FavoritesComponent extends PageComponent implements OnInit {
|
|||||||
this.content.favoriteToggle.subscribe(() => this.reload()),
|
this.content.favoriteToggle.subscribe(() => this.reload()),
|
||||||
|
|
||||||
this.breakpointObserver
|
this.breakpointObserver
|
||||||
.observe([
|
.observe([Breakpoints.HandsetPortrait, Breakpoints.HandsetLandscape])
|
||||||
Breakpoints.HandsetPortrait,
|
|
||||||
Breakpoints.HandsetLandscape
|
|
||||||
])
|
|
||||||
.subscribe(result => {
|
.subscribe(result => {
|
||||||
this.isSmallScreen = result.matches;
|
this.isSmallScreen = result.matches;
|
||||||
})
|
})
|
||||||
@@ -94,9 +91,7 @@ export class FavoritesComponent extends PageComponent implements OnInit {
|
|||||||
.getNode(id)
|
.getNode(id)
|
||||||
.pipe(map(node => node.entry))
|
.pipe(map(node => node.entry))
|
||||||
.subscribe(({ path }: MinimalNodeEntryEntity) => {
|
.subscribe(({ path }: MinimalNodeEntryEntity) => {
|
||||||
const routeUrl = isSitePath(path)
|
const routeUrl = isSitePath(path) ? '/libraries' : '/personal-files';
|
||||||
? '/libraries'
|
|
||||||
: '/personal-files';
|
|
||||||
this.router.navigate([routeUrl, id]);
|
this.router.navigate([routeUrl, id]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -23,11 +23,19 @@
|
|||||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { TestBed, fakeAsync, tick, ComponentFixture } from '@angular/core/testing';
|
import {
|
||||||
|
TestBed,
|
||||||
|
fakeAsync,
|
||||||
|
tick,
|
||||||
|
ComponentFixture
|
||||||
|
} from '@angular/core/testing';
|
||||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import { Router, ActivatedRoute } from '@angular/router';
|
import { Router, ActivatedRoute } from '@angular/router';
|
||||||
import {
|
import {
|
||||||
TimeAgoPipe, NodeNameTooltipPipe, FileSizePipe, NodeFavoriteDirective,
|
TimeAgoPipe,
|
||||||
|
NodeNameTooltipPipe,
|
||||||
|
FileSizePipe,
|
||||||
|
NodeFavoriteDirective,
|
||||||
DataTableComponent,
|
DataTableComponent,
|
||||||
UploadService,
|
UploadService,
|
||||||
AppConfigPipe
|
AppConfigPipe
|
||||||
@@ -66,10 +74,13 @@ describe('FilesComponent', () => {
|
|||||||
ExperimentalDirective
|
ExperimentalDirective
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: ActivatedRoute, useValue: {
|
{
|
||||||
|
provide: ActivatedRoute,
|
||||||
|
useValue: {
|
||||||
snapshot: { data: { preferencePrefix: 'prefix' } },
|
snapshot: { data: { preferencePrefix: 'prefix' } },
|
||||||
params: of({ folderId: 'someId' })
|
params: of({ folderId: 'someId' })
|
||||||
} }
|
}
|
||||||
|
}
|
||||||
],
|
],
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
});
|
});
|
||||||
@@ -126,7 +137,10 @@ describe('FilesComponent', () => {
|
|||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
expect(router.navigate['calls'].argsFor(0)[0]).toEqual(['/personal-files', 'parent-id']);
|
expect(router.navigate['calls'].argsFor(0)[0]).toEqual([
|
||||||
|
'/personal-files',
|
||||||
|
'parent-id'
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -239,7 +253,6 @@ describe('FilesComponent', () => {
|
|||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
describe('onBreadcrumbNavigate()', () => {
|
describe('onBreadcrumbNavigate()', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
spyOn(contentApi, 'getNode').and.returnValue(of({ entry: node }));
|
spyOn(contentApi, 'getNode').and.returnValue(of({ entry: node }));
|
||||||
@@ -267,7 +280,10 @@ describe('FilesComponent', () => {
|
|||||||
it('should navigates to node when id provided', () => {
|
it('should navigates to node when id provided', () => {
|
||||||
component.navigate(node.id);
|
component.navigate(node.id);
|
||||||
|
|
||||||
expect(router.navigate).toHaveBeenCalledWith(['./', node.id], jasmine.any(Object));
|
expect(router.navigate).toHaveBeenCalledWith(
|
||||||
|
['./', node.id],
|
||||||
|
jasmine.any(Object)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should navigates to home when id not provided', () => {
|
it('should navigates to home when id not provided', () => {
|
||||||
|
@@ -27,7 +27,12 @@ import { FileUploadEvent, UploadService } from '@alfresco/adf-core';
|
|||||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { ActivatedRoute, Params, Router } from '@angular/router';
|
import { ActivatedRoute, Params, Router } from '@angular/router';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { MinimalNodeEntity, MinimalNodeEntryEntity, PathElement, PathElementEntity } from 'alfresco-js-api';
|
import {
|
||||||
|
MinimalNodeEntity,
|
||||||
|
MinimalNodeEntryEntity,
|
||||||
|
PathElement,
|
||||||
|
PathElementEntity
|
||||||
|
} from 'alfresco-js-api';
|
||||||
import { ContentManagementService } from '../../services/content-management.service';
|
import { ContentManagementService } from '../../services/content-management.service';
|
||||||
import { NodeActionsService } from '../../services/node-actions.service';
|
import { NodeActionsService } from '../../services/node-actions.service';
|
||||||
import { AppStore } from '../../store/states/app.state';
|
import { AppStore } from '../../store/states/app.state';
|
||||||
@@ -42,13 +47,13 @@ import { debounceTime } from 'rxjs/operators';
|
|||||||
templateUrl: './files.component.html'
|
templateUrl: './files.component.html'
|
||||||
})
|
})
|
||||||
export class FilesComponent extends PageComponent implements OnInit, OnDestroy {
|
export class FilesComponent extends PageComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
isValidPath = true;
|
isValidPath = true;
|
||||||
isSmallScreen = false;
|
isSmallScreen = false;
|
||||||
|
|
||||||
private nodePath: PathElement[];
|
private nodePath: PathElement[];
|
||||||
|
|
||||||
constructor(private router: Router,
|
constructor(
|
||||||
|
private router: Router,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private contentApi: ContentApiService,
|
private contentApi: ContentApiService,
|
||||||
store: Store<AppStore>,
|
store: Store<AppStore>,
|
||||||
@@ -56,7 +61,8 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy {
|
|||||||
private uploadService: UploadService,
|
private uploadService: UploadService,
|
||||||
content: ContentManagementService,
|
content: ContentManagementService,
|
||||||
extensions: AppExtensionService,
|
extensions: AppExtensionService,
|
||||||
private breakpointObserver: BreakpointObserver) {
|
private breakpointObserver: BreakpointObserver
|
||||||
|
) {
|
||||||
super(store, extensions, content);
|
super(store, extensions, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,40 +77,40 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy {
|
|||||||
route.params.subscribe(({ folderId }: Params) => {
|
route.params.subscribe(({ folderId }: Params) => {
|
||||||
const nodeId = folderId || data.defaultNodeId;
|
const nodeId = folderId || data.defaultNodeId;
|
||||||
|
|
||||||
this.contentApi
|
this.contentApi.getNode(nodeId).subscribe(
|
||||||
.getNode(nodeId)
|
|
||||||
.subscribe(
|
|
||||||
node => {
|
node => {
|
||||||
this.isValidPath = true;
|
this.isValidPath = true;
|
||||||
|
|
||||||
if (node.entry && node.entry.isFolder) {
|
if (node.entry && node.entry.isFolder) {
|
||||||
this.updateCurrentNode(node.entry);
|
this.updateCurrentNode(node.entry);
|
||||||
} else {
|
} else {
|
||||||
this.router.navigate(
|
this.router.navigate(['/personal-files', node.entry.parentId], {
|
||||||
['/personal-files', node.entry.parentId],
|
replaceUrl: true
|
||||||
{ replaceUrl: true }
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
() => this.isValidPath = false
|
() => (this.isValidPath = false)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.subscriptions = this.subscriptions.concat([
|
this.subscriptions = this.subscriptions.concat([
|
||||||
nodeActionsService.contentCopied.subscribe((nodes) => this.onContentCopied(nodes)),
|
nodeActionsService.contentCopied.subscribe(nodes =>
|
||||||
|
this.onContentCopied(nodes)
|
||||||
|
),
|
||||||
content.folderCreated.subscribe(() => this.documentList.reload()),
|
content.folderCreated.subscribe(() => this.documentList.reload()),
|
||||||
content.folderEdited.subscribe(() => this.documentList.reload()),
|
content.folderEdited.subscribe(() => this.documentList.reload()),
|
||||||
content.nodesDeleted.subscribe(() => this.documentList.reload()),
|
content.nodesDeleted.subscribe(() => this.documentList.reload()),
|
||||||
content.nodesMoved.subscribe(() => this.documentList.reload()),
|
content.nodesMoved.subscribe(() => this.documentList.reload()),
|
||||||
content.nodesRestored.subscribe(() => this.documentList.reload()),
|
content.nodesRestored.subscribe(() => this.documentList.reload()),
|
||||||
uploadService.fileUploadComplete.pipe(debounceTime(300)).subscribe(file => this.onFileUploadedEvent(file)),
|
uploadService.fileUploadComplete
|
||||||
uploadService.fileUploadDeleted.pipe(debounceTime(300)).subscribe((file) => this.onFileUploadedEvent(file)),
|
.pipe(debounceTime(300))
|
||||||
|
.subscribe(file => this.onFileUploadedEvent(file)),
|
||||||
|
uploadService.fileUploadDeleted
|
||||||
|
.pipe(debounceTime(300))
|
||||||
|
.subscribe(file => this.onFileUploadedEvent(file)),
|
||||||
|
|
||||||
this.breakpointObserver
|
this.breakpointObserver
|
||||||
.observe([
|
.observe([Breakpoints.HandsetPortrait, Breakpoints.HandsetLandscape])
|
||||||
Breakpoints.HandsetPortrait,
|
|
||||||
Breakpoints.HandsetLandscape
|
|
||||||
])
|
|
||||||
.subscribe(result => {
|
.subscribe(result => {
|
||||||
this.isSmallScreen = result.matches;
|
this.isSmallScreen = result.matches;
|
||||||
})
|
})
|
||||||
@@ -149,7 +155,10 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy {
|
|||||||
onBreadcrumbNavigate(route: PathElementEntity) {
|
onBreadcrumbNavigate(route: PathElementEntity) {
|
||||||
// todo: review this approach once 5.2.3 is out
|
// todo: review this approach once 5.2.3 is out
|
||||||
if (this.nodePath && this.nodePath.length > 2) {
|
if (this.nodePath && this.nodePath.length > 2) {
|
||||||
if (this.nodePath[1].name === 'Sites' && this.nodePath[2].id === route.id) {
|
if (
|
||||||
|
this.nodePath[1].name === 'Sites' &&
|
||||||
|
this.nodePath[2].id === route.id
|
||||||
|
) {
|
||||||
return this.navigate(this.nodePath[3].id);
|
return this.navigate(this.nodePath[3].id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,11 +182,14 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
if (event && event.file.options.parentId) {
|
if (event && event.file.options.parentId) {
|
||||||
if (this.nodePath) {
|
if (this.nodePath) {
|
||||||
const correspondingNodePath = this.nodePath.find(pathItem => pathItem.id === event.file.options.parentId);
|
const correspondingNodePath = this.nodePath.find(
|
||||||
|
pathItem => pathItem.id === event.file.options.parentId
|
||||||
|
);
|
||||||
|
|
||||||
// check if the current folder has the 'trigger-upload-folder' as one of its parents
|
// check if the current folder has the 'trigger-upload-folder' as one of its parents
|
||||||
if (correspondingNodePath) {
|
if (correspondingNodePath) {
|
||||||
const correspondingIndex = this.nodePath.length - this.nodePath.indexOf(correspondingNodePath);
|
const correspondingIndex =
|
||||||
|
this.nodePath.length - this.nodePath.indexOf(correspondingNodePath);
|
||||||
this.displayFolderParent(event.file.options.path, correspondingIndex);
|
this.displayFolderParent(event.file.options.path, correspondingIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -189,7 +201,8 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy {
|
|||||||
const currentFoldersDisplayed: any = this.documentList.data.getRows() || [];
|
const currentFoldersDisplayed: any = this.documentList.data.getRows() || [];
|
||||||
|
|
||||||
const alreadyDisplayedParentFolder = currentFoldersDisplayed.find(
|
const alreadyDisplayedParentFolder = currentFoldersDisplayed.find(
|
||||||
row => row.node.entry.isFolder && row.node.entry.name === parentName);
|
row => row.node.entry.isFolder && row.node.entry.name === parentName
|
||||||
|
);
|
||||||
|
|
||||||
if (alreadyDisplayedParentFolder) {
|
if (alreadyDisplayedParentFolder) {
|
||||||
return;
|
return;
|
||||||
@@ -198,9 +211,10 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onContentCopied(nodes: MinimalNodeEntity[]) {
|
onContentCopied(nodes: MinimalNodeEntity[]) {
|
||||||
const newNode = nodes
|
const newNode = nodes.find(node => {
|
||||||
.find((node) => {
|
return (
|
||||||
return node && node.entry && node.entry.parentId === this.getParentNodeId();
|
node && node.entry && node.entry.parentId === this.getParentNodeId()
|
||||||
|
);
|
||||||
});
|
});
|
||||||
if (newNode) {
|
if (newNode) {
|
||||||
this.documentList.reload();
|
this.documentList.reload();
|
||||||
@@ -241,7 +255,9 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy {
|
|||||||
if (this.isSiteContainer(node)) {
|
if (this.isSiteContainer(node)) {
|
||||||
// rename 'documentLibrary' entry to the target site display name
|
// rename 'documentLibrary' entry to the target site display name
|
||||||
// clicking on the breadcrumb entry loads the site content
|
// clicking on the breadcrumb entry loads the site content
|
||||||
const parentNode = await this.contentApi.getNodeInfo(node.parentId).toPromise();
|
const parentNode = await this.contentApi
|
||||||
|
.getNodeInfo(node.parentId)
|
||||||
|
.toPromise();
|
||||||
node.name = parentNode.properties['cm:title'] || parentNode.name;
|
node.name = parentNode.properties['cm:title'] || parentNode.name;
|
||||||
|
|
||||||
// remove the site entry
|
// remove the site entry
|
||||||
@@ -251,7 +267,9 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy {
|
|||||||
const docLib = elements.findIndex(el => el.name === 'documentLibrary');
|
const docLib = elements.findIndex(el => el.name === 'documentLibrary');
|
||||||
if (docLib > -1) {
|
if (docLib > -1) {
|
||||||
const siteFragment = elements[docLib - 1];
|
const siteFragment = elements[docLib - 1];
|
||||||
const siteNode = await this.contentApi.getNodeInfo(siteFragment.id).toPromise();
|
const siteNode = await this.contentApi
|
||||||
|
.getNodeInfo(siteFragment.id)
|
||||||
|
.toPromise();
|
||||||
|
|
||||||
// apply Site Name to the parent fragment
|
// apply Site Name to the parent fragment
|
||||||
siteFragment.name = siteNode.properties['cm:title'] || siteNode.name;
|
siteFragment.name = siteNode.properties['cm:title'] || siteNode.name;
|
||||||
@@ -268,7 +286,12 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isRootNode(nodeId: string): boolean {
|
isRootNode(nodeId: string): boolean {
|
||||||
if (this.node && this.node.path && this.node.path.elements && this.node.path.elements.length > 0) {
|
if (
|
||||||
|
this.node &&
|
||||||
|
this.node.path &&
|
||||||
|
this.node.path.elements &&
|
||||||
|
this.node.path.elements.length > 0
|
||||||
|
) {
|
||||||
return this.node.path.elements[0].id === nodeId;
|
return this.node.path.elements[0].id === nodeId;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@@ -23,7 +23,11 @@
|
|||||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Component, ViewEncapsulation, ChangeDetectionStrategy } from '@angular/core';
|
import {
|
||||||
|
Component,
|
||||||
|
ViewEncapsulation,
|
||||||
|
ChangeDetectionStrategy
|
||||||
|
} from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'aca-generic-error',
|
selector: 'aca-generic-error',
|
||||||
@@ -33,4 +37,3 @@ import { Component, ViewEncapsulation, ChangeDetectionStrategy } from '@angular/
|
|||||||
host: { class: 'aca-generic-error' }
|
host: { class: 'aca-generic-error' }
|
||||||
})
|
})
|
||||||
export class GenericErrorComponent {}
|
export class GenericErrorComponent {}
|
||||||
|
|
||||||
|
@@ -34,8 +34,10 @@ import { SidebarTabRef } from '@alfresco/adf-extensions';
|
|||||||
templateUrl: './info-drawer.component.html'
|
templateUrl: './info-drawer.component.html'
|
||||||
})
|
})
|
||||||
export class InfoDrawerComponent implements OnChanges, OnInit {
|
export class InfoDrawerComponent implements OnChanges, OnInit {
|
||||||
@Input() nodeId: string;
|
@Input()
|
||||||
@Input() node: MinimalNodeEntity;
|
nodeId: string;
|
||||||
|
@Input()
|
||||||
|
node: MinimalNodeEntity;
|
||||||
|
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
displayNode: MinimalNodeEntryEntity;
|
displayNode: MinimalNodeEntryEntity;
|
||||||
@@ -89,7 +91,7 @@ export class InfoDrawerComponent implements OnChanges, OnInit {
|
|||||||
this.setDisplayNode(entity);
|
this.setDisplayNode(entity);
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
},
|
},
|
||||||
() => this.isLoading = false
|
() => (this.isLoading = false)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -38,7 +38,7 @@ import { NodePermissionService } from '../../../services/node-permission.service
|
|||||||
</adf-content-metadata-card>
|
</adf-content-metadata-card>
|
||||||
`,
|
`,
|
||||||
encapsulation: ViewEncapsulation.None,
|
encapsulation: ViewEncapsulation.None,
|
||||||
host: { 'class': 'app-metadata-tab' }
|
host: { class: 'app-metadata-tab' }
|
||||||
})
|
})
|
||||||
export class MetadataTabComponent {
|
export class MetadataTabComponent {
|
||||||
@Input()
|
@Input()
|
||||||
|
@@ -39,10 +39,7 @@ describe('LayoutComponent', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [AppTestingModule],
|
imports: [AppTestingModule],
|
||||||
declarations: [
|
declarations: [LayoutComponent, SidenavViewsManagerDirective],
|
||||||
LayoutComponent,
|
|
||||||
SidenavViewsManagerDirective
|
|
||||||
],
|
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -91,15 +91,11 @@ export class LayoutComponent implements OnInit, OnDestroy {
|
|||||||
.pipe(takeUntil(this.onDestroy$))
|
.pipe(takeUntil(this.onDestroy$))
|
||||||
.subscribe(node => {
|
.subscribe(node => {
|
||||||
this.node = node;
|
this.node = node;
|
||||||
this.canUpload =
|
this.canUpload = node && this.permission.check(node, ['create']);
|
||||||
node && this.permission.check(node, ['create']);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.breakpointObserver
|
this.breakpointObserver
|
||||||
.observe([
|
.observe([Breakpoints.HandsetPortrait, Breakpoints.HandsetLandscape])
|
||||||
Breakpoints.HandsetPortrait,
|
|
||||||
Breakpoints.HandsetLandscape
|
|
||||||
])
|
|
||||||
.subscribe(result => {
|
.subscribe(result => {
|
||||||
this.isSmallScreen = result.matches;
|
this.isSmallScreen = result.matches;
|
||||||
});
|
});
|
||||||
|
@@ -12,7 +12,8 @@ import { filter } from 'rxjs/operators';
|
|||||||
exportAs: 'acaSidenavManager'
|
exportAs: 'acaSidenavManager'
|
||||||
})
|
})
|
||||||
export class SidenavViewsManagerDirective {
|
export class SidenavViewsManagerDirective {
|
||||||
@ContentChild(SidenavLayoutComponent) sidenavLayout: SidenavLayoutComponent;
|
@ContentChild(SidenavLayoutComponent)
|
||||||
|
sidenavLayout: SidenavLayoutComponent;
|
||||||
|
|
||||||
minimizeSidenav = false;
|
minimizeSidenav = false;
|
||||||
hideSidenav = false;
|
hideSidenav = false;
|
||||||
@@ -81,10 +82,8 @@ export class SidenavViewsManagerDirective {
|
|||||||
|
|
||||||
if (preserveState) {
|
if (preserveState) {
|
||||||
return (
|
return (
|
||||||
this.userPreferenceService.get(
|
this.userPreferenceService.get('expandedSidenav', expand.toString()) ===
|
||||||
'expandedSidenav',
|
'true'
|
||||||
expand.toString()
|
|
||||||
) === 'true'
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -29,7 +29,11 @@ import { NO_ERRORS_SCHEMA } from '@angular/core';
|
|||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import {
|
import {
|
||||||
AlfrescoApiService,
|
AlfrescoApiService,
|
||||||
TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, DataTableComponent, AppConfigPipe
|
TimeAgoPipe,
|
||||||
|
NodeNameTooltipPipe,
|
||||||
|
NodeFavoriteDirective,
|
||||||
|
DataTableComponent,
|
||||||
|
AppConfigPipe
|
||||||
} from '@alfresco/adf-core';
|
} from '@alfresco/adf-core';
|
||||||
import { DocumentListComponent } from '@alfresco/adf-content-services';
|
import { DocumentListComponent } from '@alfresco/adf-content-services';
|
||||||
import { ShareDataTableAdapter } from '@alfresco/adf-content-services';
|
import { ShareDataTableAdapter } from '@alfresco/adf-content-services';
|
||||||
@@ -86,8 +90,12 @@ describe('LibrariesComponent', () => {
|
|||||||
alfrescoApi.reset();
|
alfrescoApi.reset();
|
||||||
router = TestBed.get(Router);
|
router = TestBed.get(Router);
|
||||||
|
|
||||||
spyOn(alfrescoApi.sitesApi, 'getSites').and.returnValue((Promise.resolve(page)));
|
spyOn(alfrescoApi.sitesApi, 'getSites').and.returnValue(
|
||||||
spyOn(alfrescoApi.peopleApi, 'getSiteMembership').and.returnValue((Promise.resolve({})));
|
Promise.resolve(page)
|
||||||
|
);
|
||||||
|
spyOn(alfrescoApi.peopleApi, 'getSiteMembership').and.returnValue(
|
||||||
|
Promise.resolve({})
|
||||||
|
);
|
||||||
|
|
||||||
contentApi = TestBed.get(ContentApiService);
|
contentApi = TestBed.get(ContentApiService);
|
||||||
});
|
});
|
||||||
@@ -119,7 +127,9 @@ describe('LibrariesComponent', () => {
|
|||||||
node.title = 'title';
|
node.title = 'title';
|
||||||
|
|
||||||
const data = new ShareDataTableAdapter(null, null);
|
const data = new ShareDataTableAdapter(null, null);
|
||||||
data.setRows([<any>{ node: { entry: { id: 'some-id', title: 'title' } } }]);
|
data.setRows([
|
||||||
|
<any>{ node: { entry: { id: 'some-id', title: 'title' } } }
|
||||||
|
]);
|
||||||
|
|
||||||
component.documentList.data = data;
|
component.documentList.data = data;
|
||||||
|
|
||||||
@@ -131,7 +141,9 @@ describe('LibrariesComponent', () => {
|
|||||||
node.title = 'title';
|
node.title = 'title';
|
||||||
|
|
||||||
const data = new ShareDataTableAdapter(null, null);
|
const data = new ShareDataTableAdapter(null, null);
|
||||||
data.setRows([<any>{ node: { entry: { id: 'some-id', title: 'title-some-id' } } }]);
|
data.setRows([
|
||||||
|
<any>{ node: { entry: { id: 'some-id', title: 'title-some-id' } } }
|
||||||
|
]);
|
||||||
|
|
||||||
component.documentList.data = data;
|
component.documentList.data = data;
|
||||||
const title = component.makeLibraryTitle(node);
|
const title = component.makeLibraryTitle(node);
|
||||||
|
@@ -41,16 +41,17 @@ import { map } from 'rxjs/operators';
|
|||||||
templateUrl: './libraries.component.html'
|
templateUrl: './libraries.component.html'
|
||||||
})
|
})
|
||||||
export class LibrariesComponent extends PageComponent implements OnInit {
|
export class LibrariesComponent extends PageComponent implements OnInit {
|
||||||
|
|
||||||
isSmallScreen = false;
|
isSmallScreen = false;
|
||||||
|
|
||||||
constructor(private route: ActivatedRoute,
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
content: ContentManagementService,
|
content: ContentManagementService,
|
||||||
private contentApi: ContentApiService,
|
private contentApi: ContentApiService,
|
||||||
store: Store<AppStore>,
|
store: Store<AppStore>,
|
||||||
extensions: AppExtensionService,
|
extensions: AppExtensionService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private breakpointObserver: BreakpointObserver) {
|
private breakpointObserver: BreakpointObserver
|
||||||
|
) {
|
||||||
super(store, extensions, content);
|
super(store, extensions, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,10 +65,7 @@ export class LibrariesComponent extends PageComponent implements OnInit {
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
this.breakpointObserver
|
this.breakpointObserver
|
||||||
.observe([
|
.observe([Breakpoints.HandsetPortrait, Breakpoints.HandsetLandscape])
|
||||||
Breakpoints.HandsetPortrait,
|
|
||||||
Breakpoints.HandsetLandscape
|
|
||||||
])
|
|
||||||
.subscribe(result => {
|
.subscribe(result => {
|
||||||
this.isSmallScreen = result.matches;
|
this.isSmallScreen = result.matches;
|
||||||
})
|
})
|
||||||
@@ -88,9 +86,8 @@ export class LibrariesComponent extends PageComponent implements OnInit {
|
|||||||
let isDuplicate = false;
|
let isDuplicate = false;
|
||||||
|
|
||||||
if (entries) {
|
if (entries) {
|
||||||
isDuplicate = entries
|
isDuplicate = entries.some((entry: any) => {
|
||||||
.some((entry: any) => {
|
return entry.id !== id && entry.title === title;
|
||||||
return (entry.id !== id && entry.title === title);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +106,9 @@ export class LibrariesComponent extends PageComponent implements OnInit {
|
|||||||
.getNode(libraryId, { relativePath: '/documentLibrary' })
|
.getNode(libraryId, { relativePath: '/documentLibrary' })
|
||||||
.pipe(map(node => node.entry))
|
.pipe(map(node => node.entry))
|
||||||
.subscribe(documentLibrary => {
|
.subscribe(documentLibrary => {
|
||||||
this.router.navigate([ './', documentLibrary.id ], { relativeTo: this.route });
|
this.router.navigate(['./', documentLibrary.id], {
|
||||||
|
relativeTo: this.route
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -23,7 +23,14 @@
|
|||||||
* 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, ChangeDetectionStrategy, OnInit, ViewEncapsulation, HostListener } from '@angular/core';
|
import {
|
||||||
|
Component,
|
||||||
|
Input,
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
OnInit,
|
||||||
|
ViewEncapsulation,
|
||||||
|
HostListener
|
||||||
|
} from '@angular/core';
|
||||||
import { PathInfo, MinimalNodeEntity } from 'alfresco-js-api';
|
import { PathInfo, MinimalNodeEntity } from 'alfresco-js-api';
|
||||||
import { Observable, BehaviorSubject, of } from 'rxjs';
|
import { Observable, BehaviorSubject, of } from 'rxjs';
|
||||||
|
|
||||||
@@ -41,7 +48,7 @@ import { ContentApiService } from '../../services/content-api.service';
|
|||||||
`,
|
`,
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
encapsulation: ViewEncapsulation.None,
|
encapsulation: ViewEncapsulation.None,
|
||||||
host: { 'class': 'aca-location-link adf-location-cell' }
|
host: { class: 'aca-location-link adf-location-cell' }
|
||||||
})
|
})
|
||||||
export class LocationLinkComponent implements OnInit {
|
export class LocationLinkComponent implements OnInit {
|
||||||
private _path: PathInfo;
|
private _path: PathInfo;
|
||||||
@@ -60,14 +67,15 @@ export class LocationLinkComponent implements OnInit {
|
|||||||
@Input()
|
@Input()
|
||||||
tooltip: Observable<string>;
|
tooltip: Observable<string>;
|
||||||
|
|
||||||
@HostListener('mouseenter') onMouseEnter() {
|
@HostListener('mouseenter')
|
||||||
|
onMouseEnter() {
|
||||||
this.getTooltip(this._path);
|
this.getTooltip(this._path);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private store: Store<AppStore>,
|
private store: Store<AppStore>,
|
||||||
private contentApi: ContentApiService) {
|
private contentApi: ContentApiService
|
||||||
}
|
) {}
|
||||||
|
|
||||||
goToLocation() {
|
goToLocation() {
|
||||||
if (this.context) {
|
if (this.context) {
|
||||||
@@ -100,7 +108,11 @@ export class LocationLinkComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// for non-admin users
|
// for non-admin users
|
||||||
if (elements.length === 3 && elements[0] === 'Company Home' && elements[1] === 'User Homes') {
|
if (
|
||||||
|
elements.length === 3 &&
|
||||||
|
elements[0] === 'Company Home' &&
|
||||||
|
elements[1] === 'User Homes'
|
||||||
|
) {
|
||||||
return of('Personal Files');
|
return of('Personal Files');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +124,9 @@ export class LocationLinkComponent implements OnInit {
|
|||||||
return new Observable<string>(observer => {
|
return new Observable<string>(observer => {
|
||||||
this.contentApi.getNodeInfo(fragment.id).subscribe(
|
this.contentApi.getNodeInfo(fragment.id).subscribe(
|
||||||
node => {
|
node => {
|
||||||
observer.next(node.properties['cm:title'] || node.name || fragment.name);
|
observer.next(
|
||||||
|
node.properties['cm:title'] || node.name || fragment.name
|
||||||
|
);
|
||||||
observer.complete();
|
observer.complete();
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
@@ -141,7 +155,8 @@ export class LocationLinkComponent implements OnInit {
|
|||||||
this.contentApi.getNodeInfo(fragment.id).subscribe(
|
this.contentApi.getNodeInfo(fragment.id).subscribe(
|
||||||
node => {
|
node => {
|
||||||
elements.splice(0, 2);
|
elements.splice(0, 2);
|
||||||
elements[0].name = node.properties['cm:title'] || node.name || fragment.name;
|
elements[0].name =
|
||||||
|
node.properties['cm:title'] || node.name || fragment.name;
|
||||||
elements.splice(1, 1);
|
elements.splice(1, 1);
|
||||||
elements.unshift({ id: null, name: 'File Libraries' });
|
elements.unshift({ id: null, name: 'File Libraries' });
|
||||||
|
|
||||||
|
@@ -27,7 +27,11 @@ import { NO_ERRORS_SCHEMA } from '@angular/core';
|
|||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { Location } from '@angular/common';
|
import { Location } from '@angular/common';
|
||||||
import { TestBed, ComponentFixture } from '@angular/core/testing';
|
import { TestBed, ComponentFixture } from '@angular/core/testing';
|
||||||
import { AuthenticationService, UserPreferencesService, AppConfigPipe } from '@alfresco/adf-core';
|
import {
|
||||||
|
AuthenticationService,
|
||||||
|
UserPreferencesService,
|
||||||
|
AppConfigPipe
|
||||||
|
} from '@alfresco/adf-core';
|
||||||
import { LoginComponent } from './login.component';
|
import { LoginComponent } from './login.component';
|
||||||
import { AppTestingModule } from '../../testing/app-testing.module';
|
import { AppTestingModule } from '../../testing/app-testing.module';
|
||||||
|
|
||||||
@@ -41,13 +45,8 @@ describe('LoginComponent', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [AppTestingModule],
|
imports: [AppTestingModule],
|
||||||
declarations: [
|
declarations: [LoginComponent, AppConfigPipe],
|
||||||
LoginComponent,
|
providers: [Location],
|
||||||
AppConfigPipe
|
|
||||||
],
|
|
||||||
providers: [
|
|
||||||
Location
|
|
||||||
],
|
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -33,7 +33,7 @@ import { AuthenticationService } from '@alfresco/adf-core';
|
|||||||
export class LoginComponent implements OnInit {
|
export class LoginComponent implements OnInit {
|
||||||
constructor(
|
constructor(
|
||||||
private location: Location,
|
private location: Location,
|
||||||
private auth: AuthenticationService,
|
private auth: AuthenticationService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
@@ -23,7 +23,10 @@
|
|||||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { DocumentListComponent, ShareDataRow } from '@alfresco/adf-content-services';
|
import {
|
||||||
|
DocumentListComponent,
|
||||||
|
ShareDataRow
|
||||||
|
} from '@alfresco/adf-content-services';
|
||||||
import { ContentActionRef, SelectionState } from '@alfresco/adf-extensions';
|
import { ContentActionRef, SelectionState } from '@alfresco/adf-extensions';
|
||||||
import { OnDestroy, OnInit, ViewChild } from '@angular/core';
|
import { OnDestroy, OnInit, ViewChild } from '@angular/core';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
@@ -33,11 +36,16 @@ import { takeUntil } from 'rxjs/operators';
|
|||||||
import { AppExtensionService } from '../extensions/extension.service';
|
import { AppExtensionService } from '../extensions/extension.service';
|
||||||
import { ContentManagementService } from '../services/content-management.service';
|
import { ContentManagementService } from '../services/content-management.service';
|
||||||
import { SetSelectedNodesAction, ViewFileAction } from '../store/actions';
|
import { SetSelectedNodesAction, ViewFileAction } from '../store/actions';
|
||||||
import { appSelection, currentFolder, documentDisplayMode, infoDrawerOpened, sharedUrl } from '../store/selectors/app.selectors';
|
import {
|
||||||
|
appSelection,
|
||||||
|
currentFolder,
|
||||||
|
documentDisplayMode,
|
||||||
|
infoDrawerOpened,
|
||||||
|
sharedUrl
|
||||||
|
} from '../store/selectors/app.selectors';
|
||||||
import { AppStore } from '../store/states/app.state';
|
import { AppStore } from '../store/states/app.state';
|
||||||
|
|
||||||
export abstract class PageComponent implements OnInit, OnDestroy {
|
export abstract class PageComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
onDestroy$: Subject<boolean> = new Subject<boolean>();
|
onDestroy$: Subject<boolean> = new Subject<boolean>();
|
||||||
|
|
||||||
@ViewChild(DocumentListComponent)
|
@ViewChild(DocumentListComponent)
|
||||||
@@ -57,13 +65,17 @@ export abstract class PageComponent implements OnInit, OnDestroy {
|
|||||||
protected subscriptions: Subscription[] = [];
|
protected subscriptions: Subscription[] = [];
|
||||||
|
|
||||||
static isLockedNode(node) {
|
static isLockedNode(node) {
|
||||||
return node.isLocked || (node.properties && node.properties['cm:lockType'] === 'READ_ONLY_LOCK');
|
return (
|
||||||
|
node.isLocked ||
|
||||||
|
(node.properties && node.properties['cm:lockType'] === 'READ_ONLY_LOCK')
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected store: Store<AppStore>,
|
protected store: Store<AppStore>,
|
||||||
protected extensions: AppExtensionService,
|
protected extensions: AppExtensionService,
|
||||||
protected content: ContentManagementService) {}
|
protected content: ContentManagementService
|
||||||
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.sharedPreviewUrl$ = this.store.select(sharedUrl);
|
this.sharedPreviewUrl$ = this.store.select(sharedUrl);
|
||||||
@@ -77,10 +89,13 @@ export abstract class PageComponent implements OnInit, OnDestroy {
|
|||||||
this.selection = selection;
|
this.selection = selection;
|
||||||
this.actions = this.extensions.getAllowedToolbarActions();
|
this.actions = this.extensions.getAllowedToolbarActions();
|
||||||
this.viewerToolbarActions = this.extensions.getViewerToolbarActions();
|
this.viewerToolbarActions = this.extensions.getViewerToolbarActions();
|
||||||
this.canUpdateNode = this.selection.count === 1 && this.content.canUpdateNode(selection.first);
|
this.canUpdateNode =
|
||||||
|
this.selection.count === 1 &&
|
||||||
|
this.content.canUpdateNode(selection.first);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.store.select(currentFolder)
|
this.store
|
||||||
|
.select(currentFolder)
|
||||||
.pipe(takeUntil(this.onDestroy$))
|
.pipe(takeUntil(this.onDestroy$))
|
||||||
.subscribe(node => {
|
.subscribe(node => {
|
||||||
this.canUpload = node && this.content.canUploadContent(node);
|
this.canUpload = node && this.content.canUploadContent(node);
|
||||||
|
@@ -24,7 +24,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Component, Input, OnInit, ViewChild } from '@angular/core';
|
import { Component, Input, OnInit, ViewChild } from '@angular/core';
|
||||||
import { NodePermissionDialogService, PermissionListComponent } from '@alfresco/adf-content-services';
|
import {
|
||||||
|
NodePermissionDialogService,
|
||||||
|
PermissionListComponent
|
||||||
|
} from '@alfresco/adf-content-services';
|
||||||
import { MinimalNodeEntryEntity } from 'alfresco-js-api';
|
import { MinimalNodeEntryEntity } from 'alfresco-js-api';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { AppStore } from '../../store/states/app.state';
|
import { AppStore } from '../../store/states/app.state';
|
||||||
@@ -51,11 +54,12 @@ export class PermissionsManagerComponent implements OnInit {
|
|||||||
private dialog: MatDialog,
|
private dialog: MatDialog,
|
||||||
private contentApi: ContentApiService,
|
private contentApi: ContentApiService,
|
||||||
private nodePermissionDialogService: NodePermissionDialogService
|
private nodePermissionDialogService: NodePermissionDialogService
|
||||||
) {
|
) {}
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.contentApi.getNodeInfo(this.nodeId, {include: ['permissions'] }).subscribe( (currentNode: MinimalNodeEntryEntity) => {
|
this.contentApi
|
||||||
|
.getNodeInfo(this.nodeId, { include: ['permissions'] })
|
||||||
|
.subscribe((currentNode: MinimalNodeEntryEntity) => {
|
||||||
this.toggleStatus = currentNode.permissions.isInheritanceEnabled;
|
this.toggleStatus = currentNode.permissions.isInheritanceEnabled;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -74,16 +78,17 @@ export class PermissionsManagerComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
openAddPermissionDialog(event: Event) {
|
openAddPermissionDialog(event: Event) {
|
||||||
this.nodePermissionDialogService.updateNodePermissionByDialog(this.nodeId)
|
this.nodePermissionDialogService
|
||||||
.subscribe(() => {
|
.updateNodePermissionByDialog(this.nodeId)
|
||||||
|
.subscribe(
|
||||||
|
() => {
|
||||||
this.dialog.open(NodePermissionsDialogComponent, {
|
this.dialog.open(NodePermissionsDialogComponent, {
|
||||||
data: { nodeId: this.nodeId },
|
data: { nodeId: this.nodeId },
|
||||||
panelClass: 'aca-permissions-dialog-panel',
|
panelClass: 'aca-permissions-dialog-panel',
|
||||||
width: '800px'
|
width: '800px'
|
||||||
}
|
});
|
||||||
);
|
|
||||||
},
|
},
|
||||||
(error) => {
|
error => {
|
||||||
this.store.dispatch(new SnackbarErrorAction(error));
|
this.store.dispatch(new SnackbarErrorAction(error));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@@ -26,7 +26,11 @@
|
|||||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import { Router, ActivatedRoute } from '@angular/router';
|
import { Router, ActivatedRoute } from '@angular/router';
|
||||||
import { TestBed, ComponentFixture } from '@angular/core/testing';
|
import { TestBed, ComponentFixture } from '@angular/core/testing';
|
||||||
import { UserPreferencesService, AppConfigPipe, NodeFavoriteDirective } from '@alfresco/adf-core';
|
import {
|
||||||
|
UserPreferencesService,
|
||||||
|
AppConfigPipe,
|
||||||
|
NodeFavoriteDirective
|
||||||
|
} from '@alfresco/adf-core';
|
||||||
import { PreviewComponent } from './preview.component';
|
import { PreviewComponent } from './preview.component';
|
||||||
import { of, throwError } from 'rxjs';
|
import { of, throwError } from 'rxjs';
|
||||||
import { EffectsModule } from '@ngrx/effects';
|
import { EffectsModule } from '@ngrx/effects';
|
||||||
@@ -36,7 +40,6 @@ import { AppTestingModule } from '../../testing/app-testing.module';
|
|||||||
import { ContentApiService } from '../../services/content-api.service';
|
import { ContentApiService } from '../../services/content-api.service';
|
||||||
|
|
||||||
describe('PreviewComponent', () => {
|
describe('PreviewComponent', () => {
|
||||||
|
|
||||||
let fixture: ComponentFixture<PreviewComponent>;
|
let fixture: ComponentFixture<PreviewComponent>;
|
||||||
let component: PreviewComponent;
|
let component: PreviewComponent;
|
||||||
let router: Router;
|
let router: Router;
|
||||||
@@ -46,10 +49,7 @@ describe('PreviewComponent', () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [AppTestingModule, EffectsModule.forRoot([NodeEffects])],
|
||||||
AppTestingModule,
|
|
||||||
EffectsModule.forRoot([NodeEffects])
|
|
||||||
],
|
|
||||||
declarations: [
|
declarations: [
|
||||||
AppConfigPipe,
|
AppConfigPipe,
|
||||||
PreviewComponent,
|
PreviewComponent,
|
||||||
@@ -83,9 +83,12 @@ describe('PreviewComponent', () => {
|
|||||||
component.previousNodeId = 'previous1';
|
component.previousNodeId = 'previous1';
|
||||||
component.onNavigateBefore();
|
component.onNavigateBefore();
|
||||||
|
|
||||||
expect(router.navigate).toHaveBeenCalledWith(
|
expect(router.navigate).toHaveBeenCalledWith([
|
||||||
['personal-files', 'folder1', 'preview', 'previous1']
|
'personal-files',
|
||||||
);
|
'folder1',
|
||||||
|
'preview',
|
||||||
|
'previous1'
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should navigate back to previous node in the root path', () => {
|
it('should navigate back to previous node in the root path', () => {
|
||||||
@@ -96,9 +99,11 @@ describe('PreviewComponent', () => {
|
|||||||
component.previousNodeId = 'previous1';
|
component.previousNodeId = 'previous1';
|
||||||
component.onNavigateBefore();
|
component.onNavigateBefore();
|
||||||
|
|
||||||
expect(router.navigate).toHaveBeenCalledWith(
|
expect(router.navigate).toHaveBeenCalledWith([
|
||||||
['personal-files', 'preview', 'previous1']
|
'personal-files',
|
||||||
);
|
'preview',
|
||||||
|
'previous1'
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not navigate back if node unset', () => {
|
it('should not navigate back if node unset', () => {
|
||||||
@@ -118,9 +123,12 @@ describe('PreviewComponent', () => {
|
|||||||
component.nextNodeId = 'next1';
|
component.nextNodeId = 'next1';
|
||||||
component.onNavigateNext();
|
component.onNavigateNext();
|
||||||
|
|
||||||
expect(router.navigate).toHaveBeenCalledWith(
|
expect(router.navigate).toHaveBeenCalledWith([
|
||||||
['personal-files', 'folder1', 'preview', 'next1']
|
'personal-files',
|
||||||
);
|
'folder1',
|
||||||
|
'preview',
|
||||||
|
'next1'
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should navigate to next node in the root path', () => {
|
it('should navigate to next node in the root path', () => {
|
||||||
@@ -131,9 +139,11 @@ describe('PreviewComponent', () => {
|
|||||||
component.nextNodeId = 'next1';
|
component.nextNodeId = 'next1';
|
||||||
component.onNavigateNext();
|
component.onNavigateNext();
|
||||||
|
|
||||||
expect(router.navigate).toHaveBeenCalledWith(
|
expect(router.navigate).toHaveBeenCalledWith([
|
||||||
['personal-files', 'preview', 'next1']
|
'personal-files',
|
||||||
);
|
'preview',
|
||||||
|
'next1'
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not navigate back if node unset', () => {
|
it('should not navigate back if node unset', () => {
|
||||||
@@ -148,33 +158,37 @@ describe('PreviewComponent', () => {
|
|||||||
it('should generate preview path for a folder only', () => {
|
it('should generate preview path for a folder only', () => {
|
||||||
component.previewLocation = 'personal-files';
|
component.previewLocation = 'personal-files';
|
||||||
|
|
||||||
expect(component.getPreviewPath('folder1', null)).toEqual(
|
expect(component.getPreviewPath('folder1', null)).toEqual([
|
||||||
['personal-files', 'folder1']
|
'personal-files',
|
||||||
);
|
'folder1'
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should generate preview path for a folder and a node', () => {
|
it('should generate preview path for a folder and a node', () => {
|
||||||
component.previewLocation = 'personal-files';
|
component.previewLocation = 'personal-files';
|
||||||
|
|
||||||
expect(component.getPreviewPath('folder1', 'node1')).toEqual(
|
expect(component.getPreviewPath('folder1', 'node1')).toEqual([
|
||||||
['personal-files', 'folder1', 'preview', 'node1']
|
'personal-files',
|
||||||
);
|
'folder1',
|
||||||
|
'preview',
|
||||||
|
'node1'
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should generate preview path for a node only', () => {
|
it('should generate preview path for a node only', () => {
|
||||||
component.previewLocation = 'personal-files';
|
component.previewLocation = 'personal-files';
|
||||||
|
|
||||||
expect(component.getPreviewPath(null, 'node1')).toEqual(
|
expect(component.getPreviewPath(null, 'node1')).toEqual([
|
||||||
['personal-files', 'preview', 'node1']
|
'personal-files',
|
||||||
);
|
'preview',
|
||||||
|
'node1'
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should generate preview for the location only', () => {
|
it('should generate preview for the location only', () => {
|
||||||
component.previewLocation = 'personal-files';
|
component.previewLocation = 'personal-files';
|
||||||
|
|
||||||
expect(component.getPreviewPath(null, null)).toEqual(
|
expect(component.getPreviewPath(null, null)).toEqual(['personal-files']);
|
||||||
['personal-files']
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should navigate back to root path upon close', () => {
|
it('should navigate back to root path upon close', () => {
|
||||||
@@ -186,9 +200,7 @@ describe('PreviewComponent', () => {
|
|||||||
|
|
||||||
component.onVisibilityChanged(false);
|
component.onVisibilityChanged(false);
|
||||||
|
|
||||||
expect(router.navigate).toHaveBeenCalledWith(
|
expect(router.navigate).toHaveBeenCalledWith(['libraries', {}]);
|
||||||
['libraries', {}]
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should navigate back to folder path upon close', () => {
|
it('should navigate back to folder path upon close', () => {
|
||||||
@@ -200,9 +212,7 @@ describe('PreviewComponent', () => {
|
|||||||
|
|
||||||
component.onVisibilityChanged(false);
|
component.onVisibilityChanged(false);
|
||||||
|
|
||||||
expect(router.navigate).toHaveBeenCalledWith(
|
expect(router.navigate).toHaveBeenCalledWith(['libraries', {}, 'site1']);
|
||||||
['libraries', {}, 'site1']
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not navigate to root path for certain routes upon close', () => {
|
it('should not navigate to root path for certain routes upon close', () => {
|
||||||
@@ -214,9 +224,7 @@ describe('PreviewComponent', () => {
|
|||||||
|
|
||||||
component.onVisibilityChanged(false);
|
component.onVisibilityChanged(false);
|
||||||
|
|
||||||
expect(router.navigate).toHaveBeenCalledWith(
|
expect(router.navigate).toHaveBeenCalledWith(['shared', {}]);
|
||||||
['shared', {}]
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not navigate back if viewer is still visible', () => {
|
it('should not navigate back if viewer is still visible', () => {
|
||||||
@@ -315,9 +323,9 @@ describe('PreviewComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should return nearest nodes', async () => {
|
it('should return nearest nodes', async () => {
|
||||||
spyOn(component, 'getFileIds').and.returnValue(Promise.resolve(
|
spyOn(component, 'getFileIds').and.returnValue(
|
||||||
[ 'node1', 'node2', 'node3', 'node4', 'node5' ]
|
Promise.resolve(['node1', 'node2', 'node3', 'node4', 'node5'])
|
||||||
));
|
);
|
||||||
|
|
||||||
let nearest = await component.getNearestNodes('node1', 'folder1');
|
let nearest = await component.getNearestNodes('node1', 'folder1');
|
||||||
expect(nearest).toEqual({ left: null, right: 'node2' });
|
expect(nearest).toEqual({ left: null, right: 'node2' });
|
||||||
@@ -330,9 +338,9 @@ describe('PreviewComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should return empty nearest nodes if node is already deleted', async () => {
|
it('should return empty nearest nodes if node is already deleted', async () => {
|
||||||
spyOn(component, 'getFileIds').and.returnValue(Promise.resolve(
|
spyOn(component, 'getFileIds').and.returnValue(
|
||||||
[ 'node1', 'node2', 'node3', 'node4', 'node5' ]
|
Promise.resolve(['node1', 'node2', 'node3', 'node4', 'node5'])
|
||||||
));
|
);
|
||||||
|
|
||||||
const nearest = await component.getNearestNodes('node9', 'folder1');
|
const nearest = await component.getNearestNodes('node9', 'folder1');
|
||||||
expect(nearest).toEqual({ left: null, right: null });
|
expect(nearest).toEqual({ left: null, right: null });
|
||||||
@@ -340,9 +348,7 @@ describe('PreviewComponent', () => {
|
|||||||
|
|
||||||
it('should not display node when id is missing', async () => {
|
it('should not display node when id is missing', async () => {
|
||||||
spyOn(router, 'navigate').and.stub();
|
spyOn(router, 'navigate').and.stub();
|
||||||
spyOn(contentApi, 'getNodeInfo').and.returnValue(
|
spyOn(contentApi, 'getNodeInfo').and.returnValue(of(null));
|
||||||
of(null)
|
|
||||||
);
|
|
||||||
|
|
||||||
await component.displayNode(null);
|
await component.displayNode(null);
|
||||||
|
|
||||||
@@ -352,9 +358,7 @@ describe('PreviewComponent', () => {
|
|||||||
|
|
||||||
it('should navigate to original location if node not found', async () => {
|
it('should navigate to original location if node not found', async () => {
|
||||||
spyOn(router, 'navigate').and.stub();
|
spyOn(router, 'navigate').and.stub();
|
||||||
spyOn(contentApi, 'getNodeInfo').and.returnValue(
|
spyOn(contentApi, 'getNodeInfo').and.returnValue(of(null));
|
||||||
of(null)
|
|
||||||
);
|
|
||||||
|
|
||||||
component.previewLocation = 'personal-files';
|
component.previewLocation = 'personal-files';
|
||||||
await component.displayNode('folder1');
|
await component.displayNode('folder1');
|
||||||
@@ -380,9 +384,7 @@ describe('PreviewComponent', () => {
|
|||||||
|
|
||||||
it('should navigate to original location in case of Alfresco API errors', async () => {
|
it('should navigate to original location in case of Alfresco API errors', async () => {
|
||||||
spyOn(router, 'navigate').and.stub();
|
spyOn(router, 'navigate').and.stub();
|
||||||
spyOn(contentApi, 'getNodeInfo').and.returnValue(
|
spyOn(contentApi, 'getNodeInfo').and.returnValue(throwError('error'));
|
||||||
throwError('error')
|
|
||||||
);
|
|
||||||
|
|
||||||
component.previewLocation = 'personal-files';
|
component.previewLocation = 'personal-files';
|
||||||
await component.displayNode('folder1');
|
await component.displayNode('folder1');
|
||||||
@@ -412,7 +414,10 @@ describe('PreviewComponent', () => {
|
|||||||
|
|
||||||
it('should setup node for displaying', async () => {
|
it('should setup node for displaying', async () => {
|
||||||
spyOn(router, 'navigate').and.stub();
|
spyOn(router, 'navigate').and.stub();
|
||||||
spyOn(component, 'getNearestNodes').and.returnValue({ left: 'node1', right: 'node3' });
|
spyOn(component, 'getNearestNodes').and.returnValue({
|
||||||
|
left: 'node1',
|
||||||
|
right: 'node3'
|
||||||
|
});
|
||||||
spyOn(contentApi, 'getNodeInfo').and.returnValue(
|
spyOn(contentApi, 'getNodeInfo').and.returnValue(
|
||||||
of({
|
of({
|
||||||
id: 'node2',
|
id: 'node2',
|
||||||
@@ -559,9 +564,21 @@ describe('PreviewComponent', () => {
|
|||||||
of({
|
of({
|
||||||
list: {
|
list: {
|
||||||
entries: [
|
entries: [
|
||||||
{ entry: { target: { file: { id: 'file3', modifiedAt: new Date(3) } } } },
|
{
|
||||||
{ entry: { target: { file: { id: 'file1', modifiedAt: new Date(1) } } } },
|
entry: {
|
||||||
{ entry: { target: { file: { id: 'file2', modifiedAt: new Date(2) } } } }
|
target: { file: { id: 'file3', modifiedAt: new Date(3) } }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
entry: {
|
||||||
|
target: { file: { id: 'file1', modifiedAt: new Date(1) } }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
entry: {
|
||||||
|
target: { file: { id: 'file2', modifiedAt: new Date(2) } }
|
||||||
|
}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -579,8 +596,20 @@ describe('PreviewComponent', () => {
|
|||||||
of({
|
of({
|
||||||
list: {
|
list: {
|
||||||
entries: [
|
entries: [
|
||||||
{ entry: { nodeId: 'node2', name: 'node 2', modifiedAt: new Date(2) } },
|
{
|
||||||
{ entry: { nodeId: 'node1', name: 'node 1', modifiedAt: new Date(1) } }
|
entry: {
|
||||||
|
nodeId: 'node2',
|
||||||
|
name: 'node 2',
|
||||||
|
modifiedAt: new Date(2)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
entry: {
|
||||||
|
nodeId: 'node1',
|
||||||
|
name: 'node 1',
|
||||||
|
modifiedAt: new Date(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -597,8 +626,20 @@ describe('PreviewComponent', () => {
|
|||||||
of({
|
of({
|
||||||
list: {
|
list: {
|
||||||
entries: [
|
entries: [
|
||||||
{ entry: { nodeId: 'node2', name: 'node 2', modifiedAt: new Date(2) } },
|
{
|
||||||
{ entry: { nodeId: 'node1', name: 'node 1', modifiedAt: new Date(1) } }
|
entry: {
|
||||||
|
nodeId: 'node2',
|
||||||
|
name: 'node 2',
|
||||||
|
modifiedAt: new Date(2)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
entry: {
|
||||||
|
nodeId: 'node1',
|
||||||
|
name: 'node 1',
|
||||||
|
modifiedAt: new Date(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@@ -24,7 +24,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
|
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||||
import { ActivatedRoute, Router, UrlTree, UrlSegmentGroup, UrlSegment, PRIMARY_OUTLET } from '@angular/router';
|
import {
|
||||||
|
ActivatedRoute,
|
||||||
|
Router,
|
||||||
|
UrlTree,
|
||||||
|
UrlSegmentGroup,
|
||||||
|
UrlSegment,
|
||||||
|
PRIMARY_OUTLET
|
||||||
|
} from '@angular/router';
|
||||||
import { UserPreferencesService, ObjectUtils } from '@alfresco/adf-core';
|
import { UserPreferencesService, ObjectUtils } from '@alfresco/adf-core';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { AppStore } from '../../store/states/app.state';
|
import { AppStore } from '../../store/states/app.state';
|
||||||
@@ -41,14 +48,19 @@ import { ViewUtilService } from './view-util.service';
|
|||||||
templateUrl: 'preview.component.html',
|
templateUrl: 'preview.component.html',
|
||||||
styleUrls: ['preview.component.scss'],
|
styleUrls: ['preview.component.scss'],
|
||||||
encapsulation: ViewEncapsulation.None,
|
encapsulation: ViewEncapsulation.None,
|
||||||
host: { 'class': 'app-preview' }
|
host: { class: 'app-preview' }
|
||||||
})
|
})
|
||||||
export class PreviewComponent extends PageComponent implements OnInit {
|
export class PreviewComponent extends PageComponent implements OnInit {
|
||||||
|
|
||||||
previewLocation: string = null;
|
previewLocation: string = null;
|
||||||
routesSkipNavigation = ['shared', 'recent-files', 'favorites'];
|
routesSkipNavigation = ['shared', 'recent-files', 'favorites'];
|
||||||
navigateSource: string = null;
|
navigateSource: string = null;
|
||||||
navigationSources = ['favorites', 'libraries', 'personal-files', 'recent-files', 'shared'];
|
navigationSources = [
|
||||||
|
'favorites',
|
||||||
|
'libraries',
|
||||||
|
'personal-files',
|
||||||
|
'recent-files',
|
||||||
|
'shared'
|
||||||
|
];
|
||||||
folderId: string = null;
|
folderId: string = null;
|
||||||
nodeId: string = null;
|
nodeId: string = null;
|
||||||
previousNodeId: string;
|
previousNodeId: string;
|
||||||
@@ -65,7 +77,8 @@ export class PreviewComponent extends PageComponent implements OnInit {
|
|||||||
private viewUtils: ViewUtilService,
|
private viewUtils: ViewUtilService,
|
||||||
store: Store<AppStore>,
|
store: Store<AppStore>,
|
||||||
extensions: AppExtensionService,
|
extensions: AppExtensionService,
|
||||||
content: ContentManagementService) {
|
content: ContentManagementService
|
||||||
|
) {
|
||||||
super(store, extensions, content);
|
super(store, extensions, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +125,10 @@ export class PreviewComponent extends PageComponent implements OnInit {
|
|||||||
this.store.dispatch(new SetSelectedNodesAction([{ entry: this.node }]));
|
this.store.dispatch(new SetSelectedNodesAction([{ entry: this.node }]));
|
||||||
|
|
||||||
if (this.node && this.node.isFile) {
|
if (this.node && this.node.isFile) {
|
||||||
const nearest = await this.getNearestNodes(this.node.id, this.node.parentId);
|
const nearest = await this.getNearestNodes(
|
||||||
|
this.node.id,
|
||||||
|
this.node.parentId
|
||||||
|
);
|
||||||
|
|
||||||
this.previousNodeId = nearest.left;
|
this.previousNodeId = nearest.left;
|
||||||
this.nextNodeId = nearest.right;
|
this.nextNodeId = nearest.right;
|
||||||
@@ -133,7 +149,9 @@ export class PreviewComponent extends PageComponent implements OnInit {
|
|||||||
* @param isVisible Indicator whether Viewer is visible or hidden.
|
* @param isVisible Indicator whether Viewer is visible or hidden.
|
||||||
*/
|
*/
|
||||||
onVisibilityChanged(isVisible: boolean): void {
|
onVisibilityChanged(isVisible: boolean): void {
|
||||||
const shouldSkipNavigation = this.routesSkipNavigation.includes(this.previewLocation);
|
const shouldSkipNavigation = this.routesSkipNavigation.includes(
|
||||||
|
this.previewLocation
|
||||||
|
);
|
||||||
|
|
||||||
if (!isVisible) {
|
if (!isVisible) {
|
||||||
const route = this.getNavigationCommands(this.previewLocation);
|
const route = this.getNavigationCommands(this.previewLocation);
|
||||||
@@ -158,9 +176,7 @@ export class PreviewComponent extends PageComponent implements OnInit {
|
|||||||
/** Handles navigation to a next document */
|
/** Handles navigation to a next document */
|
||||||
onNavigateNext(): void {
|
onNavigateNext(): void {
|
||||||
if (this.nextNodeId) {
|
if (this.nextNodeId) {
|
||||||
this.router.navigate(
|
this.router.navigate(this.getPreviewPath(this.folderId, this.nextNodeId));
|
||||||
this.getPreviewPath(this.folderId, this.nextNodeId)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,13 +199,15 @@ export class PreviewComponent extends PageComponent implements OnInit {
|
|||||||
return route;
|
return route;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves nearest node information for the given node and folder.
|
* Retrieves nearest node information for the given node and folder.
|
||||||
* @param nodeId Unique identifier of the document node
|
* @param nodeId Unique identifier of the document node
|
||||||
* @param folderId Unique identifier of the containing folder node.
|
* @param folderId Unique identifier of the containing folder node.
|
||||||
*/
|
*/
|
||||||
async getNearestNodes(nodeId: string, folderId: string): Promise<{ left: string, right: string }> {
|
async getNearestNodes(
|
||||||
|
nodeId: string,
|
||||||
|
folderId: string
|
||||||
|
): Promise<{ left: string; right: string }> {
|
||||||
const empty = {
|
const empty = {
|
||||||
left: null,
|
left: null,
|
||||||
right: null
|
right: null
|
||||||
@@ -223,13 +241,17 @@ export class PreviewComponent extends PageComponent implements OnInit {
|
|||||||
*/
|
*/
|
||||||
async getFileIds(source: string, folderId?: string): Promise<string[]> {
|
async getFileIds(source: string, folderId?: string): Promise<string[]> {
|
||||||
if ((source === 'personal-files' || source === 'libraries') && folderId) {
|
if ((source === 'personal-files' || source === 'libraries') && folderId) {
|
||||||
const sortKey = this.preferences.get('personal-files.sorting.key') || 'modifiedAt';
|
const sortKey =
|
||||||
const sortDirection = this.preferences.get('personal-files.sorting.direction') || 'desc';
|
this.preferences.get('personal-files.sorting.key') || 'modifiedAt';
|
||||||
const nodes = await this.contentApi.getNodeChildren(folderId, {
|
const sortDirection =
|
||||||
|
this.preferences.get('personal-files.sorting.direction') || 'desc';
|
||||||
|
const nodes = await this.contentApi
|
||||||
|
.getNodeChildren(folderId, {
|
||||||
// orderBy: `${sortKey} ${sortDirection}`,
|
// orderBy: `${sortKey} ${sortDirection}`,
|
||||||
fields: ['id', this.getRootField(sortKey)],
|
fields: ['id', this.getRootField(sortKey)],
|
||||||
where: '(isFile=true)'
|
where: '(isFile=true)'
|
||||||
}).toPromise();
|
})
|
||||||
|
.toPromise();
|
||||||
|
|
||||||
const entries = nodes.list.entries.map(obj => obj.entry);
|
const entries = nodes.list.entries.map(obj => obj.entry);
|
||||||
this.sort(entries, sortKey, sortDirection);
|
this.sort(entries, sortKey, sortDirection);
|
||||||
@@ -238,13 +260,17 @@ export class PreviewComponent extends PageComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (source === 'favorites') {
|
if (source === 'favorites') {
|
||||||
const nodes = await this.contentApi.getFavorites('-me-', {
|
const nodes = await this.contentApi
|
||||||
|
.getFavorites('-me-', {
|
||||||
where: '(EXISTS(target/file))',
|
where: '(EXISTS(target/file))',
|
||||||
fields: ['target']
|
fields: ['target']
|
||||||
}).toPromise();
|
})
|
||||||
|
.toPromise();
|
||||||
|
|
||||||
const sortKey = this.preferences.get('favorites.sorting.key') || 'modifiedAt';
|
const sortKey =
|
||||||
const sortDirection = this.preferences.get('favorites.sorting.direction') || 'desc';
|
this.preferences.get('favorites.sorting.key') || 'modifiedAt';
|
||||||
|
const sortDirection =
|
||||||
|
this.preferences.get('favorites.sorting.direction') || 'desc';
|
||||||
const files = nodes.list.entries.map(obj => obj.entry.target.file);
|
const files = nodes.list.entries.map(obj => obj.entry.target.file);
|
||||||
this.sort(files, sortKey, sortDirection);
|
this.sort(files, sortKey, sortDirection);
|
||||||
|
|
||||||
@@ -252,12 +278,16 @@ export class PreviewComponent extends PageComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (source === 'shared') {
|
if (source === 'shared') {
|
||||||
const sortingKey = this.preferences.get('shared.sorting.key') || 'modifiedAt';
|
const sortingKey =
|
||||||
const sortingDirection = this.preferences.get('shared.sorting.direction') || 'desc';
|
this.preferences.get('shared.sorting.key') || 'modifiedAt';
|
||||||
|
const sortingDirection =
|
||||||
|
this.preferences.get('shared.sorting.direction') || 'desc';
|
||||||
|
|
||||||
const nodes = await this.contentApi.findSharedLinks({
|
const nodes = await this.contentApi
|
||||||
|
.findSharedLinks({
|
||||||
fields: ['nodeId', this.getRootField(sortingKey)]
|
fields: ['nodeId', this.getRootField(sortingKey)]
|
||||||
}).toPromise();
|
})
|
||||||
|
.toPromise();
|
||||||
|
|
||||||
const entries = nodes.list.entries.map(obj => obj.entry);
|
const entries = nodes.list.entries.map(obj => obj.entry);
|
||||||
this.sort(entries, sortingKey, sortingDirection);
|
this.sort(entries, sortingKey, sortingDirection);
|
||||||
@@ -268,10 +298,13 @@ export class PreviewComponent extends PageComponent implements OnInit {
|
|||||||
if (source === 'recent-files') {
|
if (source === 'recent-files') {
|
||||||
const person = await this.contentApi.getPerson('-me-').toPromise();
|
const person = await this.contentApi.getPerson('-me-').toPromise();
|
||||||
const username = person.entry.id;
|
const username = person.entry.id;
|
||||||
const sortingKey = this.preferences.get('recent-files.sorting.key') || 'modifiedAt';
|
const sortingKey =
|
||||||
const sortingDirection = this.preferences.get('recent-files.sorting.direction') || 'desc';
|
this.preferences.get('recent-files.sorting.key') || 'modifiedAt';
|
||||||
|
const sortingDirection =
|
||||||
|
this.preferences.get('recent-files.sorting.direction') || 'desc';
|
||||||
|
|
||||||
const nodes = await this.contentApi.search({
|
const nodes = await this.contentApi
|
||||||
|
.search({
|
||||||
query: {
|
query: {
|
||||||
query: '*',
|
query: '*',
|
||||||
language: 'afts'
|
language: 'afts'
|
||||||
@@ -279,15 +312,20 @@ export class PreviewComponent extends PageComponent implements OnInit {
|
|||||||
filterQueries: [
|
filterQueries: [
|
||||||
{ query: `cm:modified:[NOW/DAY-30DAYS TO NOW/DAY+1DAY]` },
|
{ query: `cm:modified:[NOW/DAY-30DAYS TO NOW/DAY+1DAY]` },
|
||||||
{ query: `cm:modifier:${username} OR cm:creator:${username}` },
|
{ query: `cm:modifier:${username} OR cm:creator:${username}` },
|
||||||
{ query: `TYPE:"content" AND -TYPE:"app:filelink" AND -TYPE:"fm:post"` }
|
{
|
||||||
|
query: `TYPE:"content" AND -TYPE:"app:filelink" AND -TYPE:"fm:post"`
|
||||||
|
}
|
||||||
],
|
],
|
||||||
fields: ['id', this.getRootField(sortingKey)],
|
fields: ['id', this.getRootField(sortingKey)],
|
||||||
sort: [{
|
sort: [
|
||||||
|
{
|
||||||
type: 'FIELD',
|
type: 'FIELD',
|
||||||
field: 'cm:modified',
|
field: 'cm:modified',
|
||||||
ascending: false
|
ascending: false
|
||||||
}]
|
}
|
||||||
}).toPromise();
|
]
|
||||||
|
})
|
||||||
|
.toPromise();
|
||||||
|
|
||||||
const entries = nodes.list.entries.map(obj => obj.entry);
|
const entries = nodes.list.entries.map(obj => obj.entry);
|
||||||
this.sort(entries, sortingKey, sortingDirection);
|
this.sort(entries, sortingKey, sortingDirection);
|
||||||
@@ -308,14 +346,16 @@ export class PreviewComponent extends PageComponent implements OnInit {
|
|||||||
items.sort((a: any, b: any) => {
|
items.sort((a: any, b: any) => {
|
||||||
let left = ObjectUtils.getValue(a, key);
|
let left = ObjectUtils.getValue(a, key);
|
||||||
if (left) {
|
if (left) {
|
||||||
left = (left instanceof Date) ? left.valueOf().toString() : left.toString();
|
left =
|
||||||
|
left instanceof Date ? left.valueOf().toString() : left.toString();
|
||||||
} else {
|
} else {
|
||||||
left = '';
|
left = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
let right = ObjectUtils.getValue(b, key);
|
let right = ObjectUtils.getValue(b, key);
|
||||||
if (right) {
|
if (right) {
|
||||||
right = (right instanceof Date) ? right.valueOf().toString() : right.toString();
|
right =
|
||||||
|
right instanceof Date ? right.valueOf().toString() : right.toString();
|
||||||
} else {
|
} else {
|
||||||
right = '';
|
right = '';
|
||||||
}
|
}
|
||||||
@@ -344,7 +384,8 @@ export class PreviewComponent extends PageComponent implements OnInit {
|
|||||||
|
|
||||||
private getNavigationCommands(url: string): any[] {
|
private getNavigationCommands(url: string): any[] {
|
||||||
const urlTree: UrlTree = this.router.parseUrl(url);
|
const urlTree: UrlTree = this.router.parseUrl(url);
|
||||||
const urlSegmentGroup: UrlSegmentGroup = urlTree.root.children[PRIMARY_OUTLET];
|
const urlSegmentGroup: UrlSegmentGroup =
|
||||||
|
urlTree.root.children[PRIMARY_OUTLET];
|
||||||
|
|
||||||
if (!urlSegmentGroup) {
|
if (!urlSegmentGroup) {
|
||||||
return [url];
|
return [url];
|
||||||
|
@@ -54,15 +54,8 @@ const routes: Routes = [
|
|||||||
CoreExtensionsModule.forChild(),
|
CoreExtensionsModule.forChild(),
|
||||||
AppToolbarModule
|
AppToolbarModule
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [PreviewComponent, PreviewExtensionComponent],
|
||||||
PreviewComponent,
|
providers: [ViewUtilService],
|
||||||
PreviewExtensionComponent
|
exports: [PreviewComponent]
|
||||||
],
|
|
||||||
providers: [
|
|
||||||
ViewUtilService
|
|
||||||
],
|
|
||||||
exports: [
|
|
||||||
PreviewComponent
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
export class PreviewModule {}
|
export class PreviewModule {}
|
||||||
|
@@ -29,16 +29,36 @@ export class ViewUtilService {
|
|||||||
* Mime-type grouping based on the ViewerComponent.
|
* Mime-type grouping based on the ViewerComponent.
|
||||||
*/
|
*/
|
||||||
private mimeTypes = {
|
private mimeTypes = {
|
||||||
text: ['text/plain', 'text/csv', 'text/xml', 'text/html', 'application/x-javascript'],
|
text: [
|
||||||
|
'text/plain',
|
||||||
|
'text/csv',
|
||||||
|
'text/xml',
|
||||||
|
'text/html',
|
||||||
|
'application/x-javascript'
|
||||||
|
],
|
||||||
pdf: ['application/pdf'],
|
pdf: ['application/pdf'],
|
||||||
image: ['image/png', 'image/jpeg', 'image/gif', 'image/bmp', 'image/svg+xml'],
|
image: [
|
||||||
media: ['video/mp4', 'video/webm', 'video/ogg', 'audio/mpeg', 'audio/ogg', 'audio/wav']
|
'image/png',
|
||||||
|
'image/jpeg',
|
||||||
|
'image/gif',
|
||||||
|
'image/bmp',
|
||||||
|
'image/svg+xml'
|
||||||
|
],
|
||||||
|
media: [
|
||||||
|
'video/mp4',
|
||||||
|
'video/webm',
|
||||||
|
'video/ogg',
|
||||||
|
'audio/mpeg',
|
||||||
|
'audio/ogg',
|
||||||
|
'audio/wav'
|
||||||
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(private apiService: AlfrescoApiService,
|
constructor(
|
||||||
|
private apiService: AlfrescoApiService,
|
||||||
private contentApi: ContentApiService,
|
private contentApi: ContentApiService,
|
||||||
private logService: LogService) {
|
private logService: LogService
|
||||||
}
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method takes a url to trigger the print dialog against, and the type of artifact that it
|
* This method takes a url to trigger the print dialog against, and the type of artifact that it
|
||||||
@@ -86,10 +106,16 @@ export class ViewUtilService {
|
|||||||
|
|
||||||
this.getRendition(nodeId, ViewUtilService.ContentGroup.PDF)
|
this.getRendition(nodeId, ViewUtilService.ContentGroup.PDF)
|
||||||
.then(value => {
|
.then(value => {
|
||||||
const url: string = this.getRenditionUrl(nodeId, type, (value ? true : false));
|
const url: string = this.getRenditionUrl(
|
||||||
const printType = (type === ViewUtilService.ContentGroup.PDF
|
nodeId,
|
||||||
|| type === ViewUtilService.ContentGroup.TEXT)
|
type,
|
||||||
? ViewUtilService.ContentGroup.PDF : type;
|
value ? true : false
|
||||||
|
);
|
||||||
|
const printType =
|
||||||
|
type === ViewUtilService.ContentGroup.PDF ||
|
||||||
|
type === ViewUtilService.ContentGroup.TEXT
|
||||||
|
? ViewUtilService.ContentGroup.PDF
|
||||||
|
: type;
|
||||||
this.printFile(url, printType);
|
this.printFile(url, printType);
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
@@ -98,10 +124,17 @@ export class ViewUtilService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public getRenditionUrl(nodeId: string, type: string, renditionExists: boolean): string {
|
public getRenditionUrl(
|
||||||
return (renditionExists && type !== ViewUtilService.ContentGroup.IMAGE) ?
|
nodeId: string,
|
||||||
this.apiService.contentApi.getRenditionUrl(nodeId, ViewUtilService.ContentGroup.PDF) :
|
type: string,
|
||||||
this.contentApi.getContentUrl(nodeId, false);
|
renditionExists: boolean
|
||||||
|
): string {
|
||||||
|
return renditionExists && type !== ViewUtilService.ContentGroup.IMAGE
|
||||||
|
? this.apiService.contentApi.getRenditionUrl(
|
||||||
|
nodeId,
|
||||||
|
ViewUtilService.ContentGroup.PDF
|
||||||
|
)
|
||||||
|
: this.contentApi.getContentUrl(nodeId, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -111,8 +144,15 @@ export class ViewUtilService {
|
|||||||
* @param {number} retries
|
* @param {number} retries
|
||||||
* @returns {Promise<AlfrescoApi.RenditionEntry>}
|
* @returns {Promise<AlfrescoApi.RenditionEntry>}
|
||||||
*/
|
*/
|
||||||
private async waitRendition(nodeId: string, renditionId: string, retries: number): Promise<RenditionEntry> {
|
private async waitRendition(
|
||||||
const rendition = await this.apiService.renditionsApi.getRendition(nodeId, renditionId);
|
nodeId: string,
|
||||||
|
renditionId: string,
|
||||||
|
retries: number
|
||||||
|
): Promise<RenditionEntry> {
|
||||||
|
const rendition = await this.apiService.renditionsApi.getRendition(
|
||||||
|
nodeId,
|
||||||
|
renditionId
|
||||||
|
);
|
||||||
|
|
||||||
if (this.maxRetries < retries) {
|
if (this.maxRetries < retries) {
|
||||||
const status = rendition.entry.status.toString();
|
const status = rendition.entry.status.toString();
|
||||||
@@ -127,7 +167,6 @@ export class ViewUtilService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* From ViewerComponent
|
* From ViewerComponent
|
||||||
* @param {string} mimeType
|
* @param {string} mimeType
|
||||||
@@ -161,16 +200,23 @@ export class ViewUtilService {
|
|||||||
* @param {string} nodeId
|
* @param {string} nodeId
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
public async getRendition(nodeId: string, renditionId: string): Promise<RenditionEntry> {
|
public async getRendition(
|
||||||
|
nodeId: string,
|
||||||
|
renditionId: string
|
||||||
|
): Promise<RenditionEntry> {
|
||||||
const supported = await this.apiService.renditionsApi.getRenditions(nodeId);
|
const supported = await this.apiService.renditionsApi.getRenditions(nodeId);
|
||||||
let rendition = supported.list.entries.find(obj => obj.entry.id.toLowerCase() === renditionId);
|
let rendition = supported.list.entries.find(
|
||||||
|
obj => obj.entry.id.toLowerCase() === renditionId
|
||||||
|
);
|
||||||
|
|
||||||
if (rendition) {
|
if (rendition) {
|
||||||
const status = rendition.entry.status.toString();
|
const status = rendition.entry.status.toString();
|
||||||
|
|
||||||
if (status === 'NOT_CREATED') {
|
if (status === 'NOT_CREATED') {
|
||||||
try {
|
try {
|
||||||
await this.apiService.renditionsApi.createRendition(nodeId, {id: renditionId});
|
await this.apiService.renditionsApi.createRendition(nodeId, {
|
||||||
|
id: renditionId
|
||||||
|
});
|
||||||
rendition = await this.waitRendition(nodeId, renditionId, 0);
|
rendition = await this.waitRendition(nodeId, renditionId, 0);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.logService.error(err);
|
this.logService.error(err);
|
||||||
@@ -179,5 +225,4 @@ export class ViewUtilService {
|
|||||||
}
|
}
|
||||||
return new Promise(resolve => resolve(rendition));
|
return new Promise(resolve => resolve(rendition));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -27,7 +27,11 @@ import { TestBed, ComponentFixture } from '@angular/core/testing';
|
|||||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import {
|
import {
|
||||||
AlfrescoApiService,
|
AlfrescoApiService,
|
||||||
TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, DataTableComponent, AppConfigPipe
|
TimeAgoPipe,
|
||||||
|
NodeNameTooltipPipe,
|
||||||
|
NodeFavoriteDirective,
|
||||||
|
DataTableComponent,
|
||||||
|
AppConfigPipe
|
||||||
} from '@alfresco/adf-core';
|
} from '@alfresco/adf-core';
|
||||||
import { DocumentListComponent } from '@alfresco/adf-content-services';
|
import { DocumentListComponent } from '@alfresco/adf-content-services';
|
||||||
import { ContentManagementService } from '../../services/content-management.service';
|
import { ContentManagementService } from '../../services/content-management.service';
|
||||||
@@ -54,9 +58,7 @@ describe('RecentFilesComponent', () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [AppTestingModule],
|
||||||
AppTestingModule
|
|
||||||
],
|
|
||||||
declarations: [
|
declarations: [
|
||||||
DataTableComponent,
|
DataTableComponent,
|
||||||
TimeAgoPipe,
|
TimeAgoPipe,
|
||||||
@@ -77,11 +79,15 @@ describe('RecentFilesComponent', () => {
|
|||||||
alfrescoApi = TestBed.get(AlfrescoApiService);
|
alfrescoApi = TestBed.get(AlfrescoApiService);
|
||||||
alfrescoApi.reset();
|
alfrescoApi.reset();
|
||||||
|
|
||||||
spyOn(alfrescoApi.peopleApi, 'getPerson').and.returnValue(Promise.resolve({
|
spyOn(alfrescoApi.peopleApi, 'getPerson').and.returnValue(
|
||||||
|
Promise.resolve({
|
||||||
entry: { id: 'personId' }
|
entry: { id: 'personId' }
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
|
|
||||||
spyOn(alfrescoApi.searchApi, 'search').and.returnValue(Promise.resolve(page));
|
spyOn(alfrescoApi.searchApi, 'search').and.returnValue(
|
||||||
|
Promise.resolve(page)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('OnInit()', () => {
|
describe('OnInit()', () => {
|
||||||
|
@@ -56,10 +56,7 @@ export class RecentFilesComponent extends PageComponent implements OnInit {
|
|||||||
this.content.nodesRestored.subscribe(() => this.reload()),
|
this.content.nodesRestored.subscribe(() => this.reload()),
|
||||||
|
|
||||||
this.breakpointObserver
|
this.breakpointObserver
|
||||||
.observe([
|
.observe([Breakpoints.HandsetPortrait, Breakpoints.HandsetLandscape])
|
||||||
Breakpoints.HandsetPortrait,
|
|
||||||
Breakpoints.HandsetLandscape
|
|
||||||
])
|
|
||||||
.subscribe(result => {
|
.subscribe(result => {
|
||||||
this.isSmallScreen = result.matches;
|
this.isSmallScreen = result.matches;
|
||||||
})
|
})
|
||||||
|
@@ -24,14 +24,36 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { ThumbnailService } from '@alfresco/adf-core';
|
import { ThumbnailService } from '@alfresco/adf-core';
|
||||||
import { animate, state, style, transition, trigger } from '@angular/animations';
|
import {
|
||||||
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output,
|
animate,
|
||||||
QueryList, ViewEncapsulation, ViewChild, ViewChildren, ElementRef, TemplateRef, ContentChild } from '@angular/core';
|
state,
|
||||||
|
style,
|
||||||
|
transition,
|
||||||
|
trigger
|
||||||
|
} from '@angular/animations';
|
||||||
|
import {
|
||||||
|
Component,
|
||||||
|
EventEmitter,
|
||||||
|
Input,
|
||||||
|
OnDestroy,
|
||||||
|
OnInit,
|
||||||
|
Output,
|
||||||
|
QueryList,
|
||||||
|
ViewEncapsulation,
|
||||||
|
ViewChild,
|
||||||
|
ViewChildren,
|
||||||
|
ElementRef,
|
||||||
|
TemplateRef,
|
||||||
|
ContentChild
|
||||||
|
} from '@angular/core';
|
||||||
import { MinimalNodeEntity, QueryBody } from 'alfresco-js-api';
|
import { MinimalNodeEntity, QueryBody } from 'alfresco-js-api';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
import { MatListItem } from '@angular/material';
|
import { MatListItem } from '@angular/material';
|
||||||
import { debounceTime, filter } from 'rxjs/operators';
|
import { debounceTime, filter } from 'rxjs/operators';
|
||||||
import { EmptySearchResultComponent, SearchComponent } from '@alfresco/adf-content-services';
|
import {
|
||||||
|
EmptySearchResultComponent,
|
||||||
|
SearchComponent
|
||||||
|
} from '@alfresco/adf-content-services';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-search-input-control',
|
selector: 'app-search-input-control',
|
||||||
@@ -39,20 +61,29 @@ import { EmptySearchResultComponent, SearchComponent } from '@alfresco/adf-conte
|
|||||||
styleUrls: ['./search-input-control.component.scss'],
|
styleUrls: ['./search-input-control.component.scss'],
|
||||||
animations: [
|
animations: [
|
||||||
trigger('transitionMessages', [
|
trigger('transitionMessages', [
|
||||||
state('active', style({ transform: 'translateX(0%)', 'margin-left': '13px' })),
|
state(
|
||||||
|
'active',
|
||||||
|
style({ transform: 'translateX(0%)', 'margin-left': '13px' })
|
||||||
|
),
|
||||||
state('inactive', style({ transform: 'translateX(81%)' })),
|
state('inactive', style({ transform: 'translateX(81%)' })),
|
||||||
state('no-animation', style({ transform: 'translateX(0%)', width: '100%' })),
|
state(
|
||||||
transition('inactive => active',
|
'no-animation',
|
||||||
animate('300ms cubic-bezier(0.55, 0, 0.55, 0.2)')),
|
style({ transform: 'translateX(0%)', width: '100%' })
|
||||||
transition('active => inactive',
|
),
|
||||||
animate('300ms cubic-bezier(0.55, 0, 0.55, 0.2)'))
|
transition(
|
||||||
|
'inactive => active',
|
||||||
|
animate('300ms cubic-bezier(0.55, 0, 0.55, 0.2)')
|
||||||
|
),
|
||||||
|
transition(
|
||||||
|
'active => inactive',
|
||||||
|
animate('300ms cubic-bezier(0.55, 0, 0.55, 0.2)')
|
||||||
|
)
|
||||||
])
|
])
|
||||||
],
|
],
|
||||||
encapsulation: ViewEncapsulation.None,
|
encapsulation: ViewEncapsulation.None,
|
||||||
host: { class: 'adf-search-control' }
|
host: { class: 'adf-search-control' }
|
||||||
})
|
})
|
||||||
export class SearchInputControlComponent implements OnInit, OnDestroy {
|
export class SearchInputControlComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
/** Toggles whether to use an expanding search control. If false
|
/** Toggles whether to use an expanding search control. If false
|
||||||
* then a regular input is used.
|
* then a regular input is used.
|
||||||
*/
|
*/
|
||||||
@@ -123,15 +154,20 @@ export class SearchInputControlComponent implements OnInit, OnDestroy {
|
|||||||
private focusSubject = new Subject<FocusEvent>();
|
private focusSubject = new Subject<FocusEvent>();
|
||||||
|
|
||||||
constructor(private thumbnailService: ThumbnailService) {
|
constructor(private thumbnailService: ThumbnailService) {
|
||||||
|
this.toggleSearch
|
||||||
this.toggleSearch.asObservable().pipe(debounceTime(this.toggleDebounceTime)).subscribe(() => {
|
.asObservable()
|
||||||
|
.pipe(debounceTime(this.toggleDebounceTime))
|
||||||
|
.subscribe(() => {
|
||||||
if (this.expandable && !this.skipToggle) {
|
if (this.expandable && !this.skipToggle) {
|
||||||
this.subscriptAnimationState = this.subscriptAnimationState === 'inactive' ? 'active' : 'inactive';
|
this.subscriptAnimationState =
|
||||||
|
this.subscriptAnimationState === 'inactive' ? 'active' : 'inactive';
|
||||||
|
|
||||||
if (this.subscriptAnimationState === 'inactive') {
|
if (this.subscriptAnimationState === 'inactive') {
|
||||||
this.searchTerm = '';
|
this.searchTerm = '';
|
||||||
this.searchAutocomplete.resetResults();
|
this.searchAutocomplete.resetResults();
|
||||||
if ( document.activeElement.id === this.searchInput.nativeElement.id) {
|
if (
|
||||||
|
document.activeElement.id === this.searchInput.nativeElement.id
|
||||||
|
) {
|
||||||
this.searchInput.nativeElement.blur();
|
this.searchInput.nativeElement.blur();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -147,7 +183,9 @@ export class SearchInputControlComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.subscriptAnimationState = this.expandable ? 'inactive' : 'no-animation';
|
this.subscriptAnimationState = this.expandable
|
||||||
|
? 'inactive'
|
||||||
|
: 'no-animation';
|
||||||
this.setupFocusEventHandlers();
|
this.setupFocusEventHandlers();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,7 +264,9 @@ export class SearchInputControlComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
selectFirstResult() {
|
selectFirstResult() {
|
||||||
if (this.listResultElement && this.listResultElement.length > 0) {
|
if (this.listResultElement && this.listResultElement.length > 0) {
|
||||||
const firstElement: MatListItem = <MatListItem> this.listResultElement.first;
|
const firstElement: MatListItem = <MatListItem>(
|
||||||
|
this.listResultElement.first
|
||||||
|
);
|
||||||
firstElement._getHostElement().focus();
|
firstElement._getHostElement().focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -239,7 +279,9 @@ export class SearchInputControlComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onRowArrowUp($event: KeyboardEvent): void {
|
onRowArrowUp($event: KeyboardEvent): void {
|
||||||
const previousElement: any = this.getPreviousElementSibling(<Element> $event.target);
|
const previousElement: any = this.getPreviousElementSibling(<Element>(
|
||||||
|
$event.target
|
||||||
|
));
|
||||||
if (previousElement) {
|
if (previousElement) {
|
||||||
previousElement.focus();
|
previousElement.focus();
|
||||||
} else {
|
} else {
|
||||||
@@ -249,12 +291,17 @@ export class SearchInputControlComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private setupFocusEventHandlers() {
|
private setupFocusEventHandlers() {
|
||||||
this.focusSubject.pipe(
|
this.focusSubject
|
||||||
|
.pipe(
|
||||||
debounceTime(50),
|
debounceTime(50),
|
||||||
filter(($event: any) => {
|
filter(($event: any) => {
|
||||||
return this.isSearchBarActive() && ($event.type === 'blur' || $event.type === 'focusout');
|
return (
|
||||||
|
this.isSearchBarActive() &&
|
||||||
|
($event.type === 'blur' || $event.type === 'focusout')
|
||||||
|
);
|
||||||
})
|
})
|
||||||
).subscribe(() => {
|
)
|
||||||
|
.subscribe(() => {
|
||||||
this.toggleSearchBar();
|
this.toggleSearchBar();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -272,5 +319,4 @@ export class SearchInputControlComponent implements OnInit, OnDestroy {
|
|||||||
private getPreviousElementSibling(node: Element): Element {
|
private getPreviousElementSibling(node: Element): Element {
|
||||||
return node.previousElementSibling;
|
return node.previousElementSibling;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -24,12 +24,23 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import { TestBed, async, ComponentFixture, fakeAsync, tick } from '@angular/core/testing';
|
import {
|
||||||
|
TestBed,
|
||||||
|
async,
|
||||||
|
ComponentFixture,
|
||||||
|
fakeAsync,
|
||||||
|
tick
|
||||||
|
} from '@angular/core/testing';
|
||||||
|
|
||||||
import { SearchInputComponent } from './search-input.component';
|
import { SearchInputComponent } from './search-input.component';
|
||||||
import { AppTestingModule } from '../../../testing/app-testing.module';
|
import { AppTestingModule } from '../../../testing/app-testing.module';
|
||||||
import { Actions, ofType } from '@ngrx/effects';
|
import { Actions, ofType } from '@ngrx/effects';
|
||||||
import { NAVIGATE_FOLDER, NavigateToFolder, VIEW_FILE, ViewFileAction } from '../../../store/actions';
|
import {
|
||||||
|
NAVIGATE_FOLDER,
|
||||||
|
NavigateToFolder,
|
||||||
|
VIEW_FILE,
|
||||||
|
ViewFileAction
|
||||||
|
} from '../../../store/actions';
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
describe('SearchInputComponent', () => {
|
describe('SearchInputComponent', () => {
|
||||||
@@ -39,12 +50,8 @@ describe('SearchInputComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [AppTestingModule],
|
||||||
AppTestingModule
|
declarations: [SearchInputComponent],
|
||||||
],
|
|
||||||
declarations: [
|
|
||||||
SearchInputComponent
|
|
||||||
],
|
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
})
|
})
|
||||||
.compileComponents()
|
.compileComponents()
|
||||||
@@ -66,7 +73,9 @@ describe('SearchInputComponent', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const node = { entry: { isFile: true, id: 'node-id', parentId: 'parent-id' } };
|
const node = {
|
||||||
|
entry: { isFile: true, id: 'node-id', parentId: 'parent-id' }
|
||||||
|
};
|
||||||
|
|
||||||
component.onItemClicked(node);
|
component.onItemClicked(node);
|
||||||
tick();
|
tick();
|
||||||
|
@@ -25,14 +25,23 @@
|
|||||||
|
|
||||||
import { Component, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
|
import { Component, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||||
import {
|
import {
|
||||||
NavigationEnd, PRIMARY_OUTLET, Router, RouterEvent, UrlSegment, UrlSegmentGroup,
|
NavigationEnd,
|
||||||
|
PRIMARY_OUTLET,
|
||||||
|
Router,
|
||||||
|
RouterEvent,
|
||||||
|
UrlSegment,
|
||||||
|
UrlSegmentGroup,
|
||||||
UrlTree
|
UrlTree
|
||||||
} from '@angular/router';
|
} from '@angular/router';
|
||||||
import { MinimalNodeEntity } from 'alfresco-js-api';
|
import { MinimalNodeEntity } from 'alfresco-js-api';
|
||||||
import { SearchInputControlComponent } from '../search-input-control/search-input-control.component';
|
import { SearchInputControlComponent } from '../search-input-control/search-input-control.component';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { AppStore } from '../../../store/states/app.state';
|
import { AppStore } from '../../../store/states/app.state';
|
||||||
import { SearchByTermAction, NavigateToFolder, ViewFileAction } from '../../../store/actions';
|
import {
|
||||||
|
SearchByTermAction,
|
||||||
|
NavigateToFolder,
|
||||||
|
ViewFileAction
|
||||||
|
} from '../../../store/actions';
|
||||||
import { filter } from 'rxjs/operators';
|
import { filter } from 'rxjs/operators';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -42,7 +51,6 @@ import { filter } from 'rxjs/operators';
|
|||||||
host: { class: 'aca-search-input' }
|
host: { class: 'aca-search-input' }
|
||||||
})
|
})
|
||||||
export class SearchInputComponent implements OnInit {
|
export class SearchInputComponent implements OnInit {
|
||||||
|
|
||||||
hasOneChange = false;
|
hasOneChange = false;
|
||||||
hasNewChange = false;
|
hasNewChange = false;
|
||||||
navigationTimer: any;
|
navigationTimer: any;
|
||||||
@@ -51,8 +59,7 @@ export class SearchInputComponent implements OnInit {
|
|||||||
@ViewChild('searchInputControl')
|
@ViewChild('searchInputControl')
|
||||||
searchInputControl: SearchInputControlComponent;
|
searchInputControl: SearchInputControlComponent;
|
||||||
|
|
||||||
constructor(private router: Router, private store: Store<AppStore>) {
|
constructor(private router: Router, private store: Store<AppStore>) {}
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.showInputValue();
|
this.showInputValue();
|
||||||
@@ -68,10 +75,10 @@ export class SearchInputComponent implements OnInit {
|
|||||||
|
|
||||||
showInputValue() {
|
showInputValue() {
|
||||||
if (this.onSearchResults) {
|
if (this.onSearchResults) {
|
||||||
|
|
||||||
let searchedWord = null;
|
let searchedWord = null;
|
||||||
const urlTree: UrlTree = this.router.parseUrl(this.router.url);
|
const urlTree: UrlTree = this.router.parseUrl(this.router.url);
|
||||||
const urlSegmentGroup: UrlSegmentGroup = urlTree.root.children[PRIMARY_OUTLET];
|
const urlSegmentGroup: UrlSegmentGroup =
|
||||||
|
urlTree.root.children[PRIMARY_OUTLET];
|
||||||
|
|
||||||
if (urlSegmentGroup) {
|
if (urlSegmentGroup) {
|
||||||
const urlSegments: UrlSegment[] = urlSegmentGroup.segments;
|
const urlSegments: UrlSegment[] = urlSegmentGroup.segments;
|
||||||
@@ -83,7 +90,6 @@ export class SearchInputComponent implements OnInit {
|
|||||||
this.searchInputControl.searchTerm = searchedWord;
|
this.searchInputControl.searchTerm = searchedWord;
|
||||||
this.searchInputControl.subscriptAnimationState = 'no-animation';
|
this.searchInputControl.subscriptAnimationState = 'no-animation';
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (this.searchInputControl.subscriptAnimationState === 'no-animation') {
|
if (this.searchInputControl.subscriptAnimationState === 'no-animation') {
|
||||||
this.searchInputControl.subscriptAnimationState = 'active';
|
this.searchInputControl.subscriptAnimationState = 'active';
|
||||||
@@ -124,7 +130,6 @@ export class SearchInputComponent implements OnInit {
|
|||||||
|
|
||||||
onSearchChange(searchTerm: string) {
|
onSearchChange(searchTerm: string) {
|
||||||
if (this.onSearchResults) {
|
if (this.onSearchResults) {
|
||||||
|
|
||||||
if (this.hasOneChange) {
|
if (this.hasOneChange) {
|
||||||
this.hasNewChange = true;
|
this.hasNewChange = true;
|
||||||
} else {
|
} else {
|
||||||
|
@@ -19,6 +19,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.link:hover {
|
.link:hover {
|
||||||
color: #2196F3;
|
color: #2196f3;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
@@ -23,7 +23,13 @@
|
|||||||
* 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, OnInit, ViewEncapsulation, ChangeDetectionStrategy } from '@angular/core';
|
import {
|
||||||
|
Component,
|
||||||
|
Input,
|
||||||
|
OnInit,
|
||||||
|
ViewEncapsulation,
|
||||||
|
ChangeDetectionStrategy
|
||||||
|
} from '@angular/core';
|
||||||
import { MinimalNodeEntity } from 'alfresco-js-api';
|
import { MinimalNodeEntity } from 'alfresco-js-api';
|
||||||
import { ViewFileAction } from '../../../store/actions';
|
import { ViewFileAction } from '../../../store/actions';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
@@ -41,7 +47,8 @@ import { NavigateToFolder } from '../../../store/actions';
|
|||||||
export class SearchResultsRowComponent implements OnInit {
|
export class SearchResultsRowComponent implements OnInit {
|
||||||
private node: MinimalNodeEntity;
|
private node: MinimalNodeEntity;
|
||||||
|
|
||||||
@Input() context: any;
|
@Input()
|
||||||
|
context: any;
|
||||||
|
|
||||||
constructor(private store: Store<AppStore>) {}
|
constructor(private store: Store<AppStore>) {}
|
||||||
|
|
||||||
@@ -94,9 +101,7 @@ export class SearchResultsRowComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
showPreview() {
|
showPreview() {
|
||||||
this.store.dispatch(
|
this.store.dispatch(new ViewFileAction(this.node));
|
||||||
new ViewFileAction(this.node)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
navigate() {
|
navigate() {
|
||||||
|
@@ -9,8 +9,7 @@ describe('SearchComponent', () => {
|
|||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [SearchResultsComponent]
|
declarations: [SearchResultsComponent]
|
||||||
})
|
}).compileComponents();
|
||||||
.compileComponents();
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@@ -26,7 +26,11 @@
|
|||||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||||
import { NodePaging, Pagination, MinimalNodeEntity } from 'alfresco-js-api';
|
import { NodePaging, Pagination, MinimalNodeEntity } from 'alfresco-js-api';
|
||||||
import { ActivatedRoute, Params } from '@angular/router';
|
import { ActivatedRoute, Params } from '@angular/router';
|
||||||
import { SearchQueryBuilderService, SearchComponent as AdfSearchComponent, SearchFilterComponent } from '@alfresco/adf-content-services';
|
import {
|
||||||
|
SearchQueryBuilderService,
|
||||||
|
SearchComponent as AdfSearchComponent,
|
||||||
|
SearchFilterComponent
|
||||||
|
} from '@alfresco/adf-content-services';
|
||||||
import { PageComponent } from '../../page.component';
|
import { PageComponent } from '../../page.component';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { AppStore } from '../../../store/states/app.state';
|
import { AppStore } from '../../../store/states/app.state';
|
||||||
@@ -41,7 +45,6 @@ import { ContentManagementService } from '../../../services/content-management.s
|
|||||||
providers: [SearchQueryBuilderService]
|
providers: [SearchQueryBuilderService]
|
||||||
})
|
})
|
||||||
export class SearchResultsComponent extends PageComponent implements OnInit {
|
export class SearchResultsComponent extends PageComponent implements OnInit {
|
||||||
|
|
||||||
@ViewChild('search')
|
@ViewChild('search')
|
||||||
search: AdfSearchComponent;
|
search: AdfSearchComponent;
|
||||||
|
|
||||||
@@ -90,7 +93,9 @@ export class SearchResultsComponent extends PageComponent implements OnInit {
|
|||||||
|
|
||||||
if (this.route) {
|
if (this.route) {
|
||||||
this.route.params.forEach((params: Params) => {
|
this.route.params.forEach((params: Params) => {
|
||||||
this.searchedWord = params.hasOwnProperty(this.queryParamName) ? params[this.queryParamName] : null;
|
this.searchedWord = params.hasOwnProperty(this.queryParamName)
|
||||||
|
? params[this.queryParamName]
|
||||||
|
: null;
|
||||||
const query = this.formatSearchQuery(this.searchedWord);
|
const query = this.formatSearchQuery(this.searchedWord);
|
||||||
|
|
||||||
if (query) {
|
if (query) {
|
||||||
@@ -98,7 +103,9 @@ export class SearchResultsComponent extends PageComponent implements OnInit {
|
|||||||
this.queryBuilder.update();
|
this.queryBuilder.update();
|
||||||
} else {
|
} else {
|
||||||
this.queryBuilder.userQuery = null;
|
this.queryBuilder.userQuery = null;
|
||||||
this.queryBuilder.executed.next( {list: { pagination: { totalItems: 0 }, entries: []}} );
|
this.queryBuilder.executed.next({
|
||||||
|
list: { pagination: { totalItems: 0 }, entries: [] }
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -129,14 +136,17 @@ export class SearchResultsComponent extends PageComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isFiltered(): boolean {
|
isFiltered(): boolean {
|
||||||
return this.searchFilter.selectedFacetQueries.length > 0
|
return (
|
||||||
|| this.searchFilter.selectedBuckets.length > 0
|
this.searchFilter.selectedFacetQueries.length > 0 ||
|
||||||
|| this.hasCheckedCategories();
|
this.searchFilter.selectedBuckets.length > 0 ||
|
||||||
|
this.hasCheckedCategories()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
hasCheckedCategories() {
|
hasCheckedCategories() {
|
||||||
const checkedCategory = this.queryBuilder.categories
|
const checkedCategory = this.queryBuilder.categories.find(
|
||||||
.find(category => !!this.queryBuilder.queryFragments[category.id]);
|
category => !!this.queryBuilder.queryFragments[category.id]
|
||||||
|
);
|
||||||
return !!checkedCategory;
|
return !!checkedCategory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -24,12 +24,21 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Component, ViewEncapsulation, OnInit } from '@angular/core';
|
import { Component, ViewEncapsulation, OnInit } from '@angular/core';
|
||||||
import { AppConfigService, StorageService, SettingsService } from '@alfresco/adf-core';
|
import {
|
||||||
|
AppConfigService,
|
||||||
|
StorageService,
|
||||||
|
SettingsService
|
||||||
|
} from '@alfresco/adf-core';
|
||||||
import { Validators, FormGroup, FormBuilder } from '@angular/forms';
|
import { Validators, FormGroup, FormBuilder } from '@angular/forms';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { AppStore } from '../../store/states';
|
import { AppStore } from '../../store/states';
|
||||||
import { appLanguagePicker, selectHeaderColor, selectAppName, selectUser } from '../../store/selectors/app.selectors';
|
import {
|
||||||
|
appLanguagePicker,
|
||||||
|
selectHeaderColor,
|
||||||
|
selectAppName,
|
||||||
|
selectUser
|
||||||
|
} from '../../store/selectors/app.selectors';
|
||||||
import { MatCheckboxChange } from '@angular/material';
|
import { MatCheckboxChange } from '@angular/material';
|
||||||
import { SetLanguagePickerAction } from '../../store/actions';
|
import { SetLanguagePickerAction } from '../../store/actions';
|
||||||
import { ProfileState } from '@alfresco/adf-extensions';
|
import { ProfileState } from '@alfresco/adf-extensions';
|
||||||
@@ -41,7 +50,6 @@ import { ProfileState } from '@alfresco/adf-extensions';
|
|||||||
host: { class: 'aca-settings' }
|
host: { class: 'aca-settings' }
|
||||||
})
|
})
|
||||||
export class SettingsComponent implements OnInit {
|
export class SettingsComponent implements OnInit {
|
||||||
|
|
||||||
private defaultPath = '/assets/images/alfresco-logo-white.svg';
|
private defaultPath = '/assets/images/alfresco-logo-white.svg';
|
||||||
|
|
||||||
form: FormGroup;
|
form: FormGroup;
|
||||||
@@ -50,14 +58,15 @@ export class SettingsComponent implements OnInit {
|
|||||||
appName$: Observable<string>;
|
appName$: Observable<string>;
|
||||||
headerColor$: Observable<string>;
|
headerColor$: Observable<string>;
|
||||||
languagePicker$: Observable<boolean>;
|
languagePicker$: Observable<boolean>;
|
||||||
experimental: Array<{ key: string, value: boolean }> = [];
|
experimental: Array<{ key: string; value: boolean }> = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private store: Store<AppStore>,
|
private store: Store<AppStore>,
|
||||||
private appConfig: AppConfigService,
|
private appConfig: AppConfigService,
|
||||||
private settingsService: SettingsService,
|
private settingsService: SettingsService,
|
||||||
private storage: StorageService,
|
private storage: StorageService,
|
||||||
private fb: FormBuilder) {
|
private fb: FormBuilder
|
||||||
|
) {
|
||||||
this.profile$ = store.select(selectUser);
|
this.profile$ = store.select(selectUser);
|
||||||
this.appName$ = store.select(selectAppName);
|
this.appName$ = store.select(selectAppName);
|
||||||
this.languagePicker$ = store.select(appLanguagePicker);
|
this.languagePicker$ = store.select(appLanguagePicker);
|
||||||
@@ -70,7 +79,10 @@ export class SettingsComponent implements OnInit {
|
|||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.form = this.fb.group({
|
this.form = this.fb.group({
|
||||||
ecmHost: ['', [Validators.required, Validators.pattern('^(http|https):\/\/.*[^/]$')]]
|
ecmHost: [
|
||||||
|
'',
|
||||||
|
[Validators.required, Validators.pattern('^(http|https)://.*[^/]$')]
|
||||||
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
this.reset();
|
this.reset();
|
||||||
@@ -80,7 +92,7 @@ export class SettingsComponent implements OnInit {
|
|||||||
const value = this.appConfig.get(`experimental.${key}`);
|
const value = this.appConfig.get(`experimental.${key}`);
|
||||||
return {
|
return {
|
||||||
key,
|
key,
|
||||||
value: (value === true || value === 'true')
|
value: value === true || value === 'true'
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -37,11 +37,7 @@ const routes: Routes = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [CommonModule, CoreModule.forChild(), RouterModule.forChild(routes)],
|
||||||
CommonModule,
|
|
||||||
CoreModule.forChild(),
|
|
||||||
RouterModule.forChild(routes)
|
|
||||||
],
|
|
||||||
declarations: [SettingsComponent]
|
declarations: [SettingsComponent]
|
||||||
})
|
})
|
||||||
export class AppSettingsModule {}
|
export class AppSettingsModule {}
|
||||||
|
@@ -27,7 +27,11 @@ import { TestBed, ComponentFixture } from '@angular/core/testing';
|
|||||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import {
|
import {
|
||||||
AlfrescoApiService,
|
AlfrescoApiService,
|
||||||
TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, DataTableComponent, AppConfigPipe
|
TimeAgoPipe,
|
||||||
|
NodeNameTooltipPipe,
|
||||||
|
NodeFavoriteDirective,
|
||||||
|
DataTableComponent,
|
||||||
|
AppConfigPipe
|
||||||
} from '@alfresco/adf-core';
|
} from '@alfresco/adf-core';
|
||||||
import { DocumentListComponent } from '@alfresco/adf-content-services';
|
import { DocumentListComponent } from '@alfresco/adf-content-services';
|
||||||
import { ContentManagementService } from '../../services/content-management.service';
|
import { ContentManagementService } from '../../services/content-management.service';
|
||||||
@@ -52,8 +56,7 @@ describe('SharedFilesComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed
|
TestBed.configureTestingModule({
|
||||||
.configureTestingModule({
|
|
||||||
imports: [AppTestingModule],
|
imports: [AppTestingModule],
|
||||||
declarations: [
|
declarations: [
|
||||||
DataTableComponent,
|
DataTableComponent,
|
||||||
@@ -75,7 +78,9 @@ describe('SharedFilesComponent', () => {
|
|||||||
alfrescoApi = TestBed.get(AlfrescoApiService);
|
alfrescoApi = TestBed.get(AlfrescoApiService);
|
||||||
alfrescoApi.reset();
|
alfrescoApi.reset();
|
||||||
|
|
||||||
spyOn(alfrescoApi.sharedLinksApi, 'findSharedLinks').and.returnValue(Promise.resolve(page));
|
spyOn(alfrescoApi.sharedLinksApi, 'findSharedLinks').and.returnValue(
|
||||||
|
Promise.resolve(page)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('OnInit', () => {
|
describe('OnInit', () => {
|
||||||
|
@@ -56,10 +56,7 @@ export class SharedFilesComponent extends PageComponent implements OnInit {
|
|||||||
this.content.linksUnshared.subscribe(() => this.reload()),
|
this.content.linksUnshared.subscribe(() => this.reload()),
|
||||||
|
|
||||||
this.breakpointObserver
|
this.breakpointObserver
|
||||||
.observe([
|
.observe([Breakpoints.HandsetPortrait, Breakpoints.HandsetLandscape])
|
||||||
Breakpoints.HandsetPortrait,
|
|
||||||
Breakpoints.HandsetLandscape
|
|
||||||
])
|
|
||||||
.subscribe(result => {
|
.subscribe(result => {
|
||||||
this.isSmallScreen = result.matches;
|
this.isSmallScreen = result.matches;
|
||||||
})
|
})
|
||||||
|
@@ -7,10 +7,9 @@ import { ActivatedRoute } from '@angular/router';
|
|||||||
styleUrls: ['shared-link-view.component.scss'],
|
styleUrls: ['shared-link-view.component.scss'],
|
||||||
encapsulation: ViewEncapsulation.None,
|
encapsulation: ViewEncapsulation.None,
|
||||||
// tslint:disable-next-line:use-host-property-decorator
|
// tslint:disable-next-line:use-host-property-decorator
|
||||||
host: { 'class': 'app-shared-link-view' }
|
host: { class: 'app-shared-link-view' }
|
||||||
})
|
})
|
||||||
export class SharedLinkViewComponent implements OnInit {
|
export class SharedLinkViewComponent implements OnInit {
|
||||||
|
|
||||||
sharedLinkId: string = null;
|
sharedLinkId: string = null;
|
||||||
|
|
||||||
constructor(private route: ActivatedRoute) {}
|
constructor(private route: ActivatedRoute) {}
|
||||||
@@ -20,5 +19,4 @@ export class SharedLinkViewComponent implements OnInit {
|
|||||||
this.sharedLinkId = params.id;
|
this.sharedLinkId = params.id;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -37,14 +37,8 @@ describe('SidenavComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [AppTestingModule, EffectsModule.forRoot([NodeEffects])],
|
||||||
AppTestingModule,
|
declarations: [SidenavComponent, ExperimentalDirective],
|
||||||
EffectsModule.forRoot([NodeEffects])
|
|
||||||
],
|
|
||||||
declarations: [
|
|
||||||
SidenavComponent,
|
|
||||||
ExperimentalDirective
|
|
||||||
],
|
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
})
|
})
|
||||||
.compileComponents()
|
.compileComponents()
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
$foreground: map-get($theme, foreground);
|
$foreground: map-get($theme, foreground);
|
||||||
$background: map-get($theme, background);
|
$background: map-get($theme, background);
|
||||||
|
|
||||||
$border: 1px solid mat-color($foreground, divider, .07);
|
$border: 1px solid mat-color($foreground, divider, 0.07);
|
||||||
|
|
||||||
.sidenav {
|
.sidenav {
|
||||||
@include angular-material-theme($theme);
|
@include angular-material-theme($theme);
|
||||||
@@ -28,8 +28,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.menu__item--default {
|
.menu__item--default {
|
||||||
color: mat-color($primary, .87);
|
color: mat-color($primary, 0.87);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -38,7 +38,8 @@ import { ContentActionRef, NavBarGroupRef } from '@alfresco/adf-extensions';
|
|||||||
styleUrls: ['./sidenav.component.scss']
|
styleUrls: ['./sidenav.component.scss']
|
||||||
})
|
})
|
||||||
export class SidenavComponent implements OnInit, OnDestroy {
|
export class SidenavComponent implements OnInit, OnDestroy {
|
||||||
@Input() showLabel: boolean;
|
@Input()
|
||||||
|
showLabel: boolean;
|
||||||
|
|
||||||
groups: Array<NavBarGroupRef> = [];
|
groups: Array<NavBarGroupRef> = [];
|
||||||
createActions: Array<ContentActionRef> = [];
|
createActions: Array<ContentActionRef> = [];
|
||||||
|
@@ -43,7 +43,6 @@ import { ToggleDocumentDisplayMode } from '../../../store/actions';
|
|||||||
`
|
`
|
||||||
})
|
})
|
||||||
export class DocumentDisplayModeComponent {
|
export class DocumentDisplayModeComponent {
|
||||||
|
|
||||||
displayMode$: Observable<string>;
|
displayMode$: Observable<string>;
|
||||||
|
|
||||||
constructor(private store: Store<AppStore>) {
|
constructor(private store: Store<AppStore>) {
|
||||||
|
@@ -46,12 +46,12 @@ import { ContentManagementService } from '../../../services/content-management.s
|
|||||||
`
|
`
|
||||||
})
|
})
|
||||||
export class ToggleFavoriteComponent {
|
export class ToggleFavoriteComponent {
|
||||||
|
|
||||||
selection$: Observable<SelectionState>;
|
selection$: Observable<SelectionState>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private store: Store<AppStore>,
|
private store: Store<AppStore>,
|
||||||
private content: ContentManagementService) {
|
private content: ContentManagementService
|
||||||
|
) {
|
||||||
this.selection$ = this.store.select(appSelection);
|
this.selection$ = this.store.select(appSelection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -42,8 +42,10 @@ import { AppExtensionService } from '../../../extensions/extension.service';
|
|||||||
host: { class: 'aca-toolbar-action' }
|
host: { class: 'aca-toolbar-action' }
|
||||||
})
|
})
|
||||||
export class ToolbarActionComponent {
|
export class ToolbarActionComponent {
|
||||||
@Input() type = 'icon-button';
|
@Input()
|
||||||
@Input() entry: ContentActionRef;
|
type = 'icon-button';
|
||||||
|
@Input()
|
||||||
|
entry: ContentActionRef;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected store: Store<AppStore>,
|
protected store: Store<AppStore>,
|
||||||
|
@@ -41,8 +41,10 @@ export enum ToolbarButtonType {
|
|||||||
templateUrl: 'toolbar-button.component.html'
|
templateUrl: 'toolbar-button.component.html'
|
||||||
})
|
})
|
||||||
export class ToolbarButtonComponent {
|
export class ToolbarButtonComponent {
|
||||||
@Input() type: ToolbarButtonType = ToolbarButtonType.ICON_BUTTON;
|
@Input()
|
||||||
@Input() actionRef: ContentActionRef;
|
type: ToolbarButtonType = ToolbarButtonType.ICON_BUTTON;
|
||||||
|
@Input()
|
||||||
|
actionRef: ContentActionRef;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected store: Store<AppStore>,
|
protected store: Store<AppStore>,
|
||||||
|
@@ -44,11 +44,7 @@ export function components() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [CommonModule, CoreModule.forChild(), ExtensionsModule.forChild()],
|
||||||
CommonModule,
|
|
||||||
CoreModule.forChild(),
|
|
||||||
ExtensionsModule.forChild()
|
|
||||||
],
|
|
||||||
declarations: components(),
|
declarations: components(),
|
||||||
exports: components(),
|
exports: components(),
|
||||||
entryComponents: components()
|
entryComponents: components()
|
||||||
|
@@ -26,8 +26,11 @@ import { NO_ERRORS_SCHEMA } from '@angular/core';
|
|||||||
import { TestBed, ComponentFixture } from '@angular/core/testing';
|
import { TestBed, ComponentFixture } from '@angular/core/testing';
|
||||||
import {
|
import {
|
||||||
AlfrescoApiService,
|
AlfrescoApiService,
|
||||||
TimeAgoPipe, NodeNameTooltipPipe,
|
TimeAgoPipe,
|
||||||
NodeFavoriteDirective, DataTableComponent, AppConfigPipe
|
NodeNameTooltipPipe,
|
||||||
|
NodeFavoriteDirective,
|
||||||
|
DataTableComponent,
|
||||||
|
AppConfigPipe
|
||||||
} from '@alfresco/adf-core';
|
} from '@alfresco/adf-core';
|
||||||
import { DocumentListComponent } from '@alfresco/adf-content-services';
|
import { DocumentListComponent } from '@alfresco/adf-content-services';
|
||||||
import { ContentManagementService } from '../../services/content-management.service';
|
import { ContentManagementService } from '../../services/content-management.service';
|
||||||
@@ -81,7 +84,9 @@ describe('TrashcanComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
spyOn(alfrescoApi.nodesApi, 'getDeletedNodes').and.returnValue(Promise.resolve(page));
|
spyOn(alfrescoApi.nodesApi, 'getDeletedNodes').and.returnValue(
|
||||||
|
Promise.resolve(page)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('onRestoreNode()', () => {
|
describe('onRestoreNode()', () => {
|
||||||
|
@@ -41,10 +41,12 @@ export class TrashcanComponent extends PageComponent implements OnInit {
|
|||||||
isSmallScreen = false;
|
isSmallScreen = false;
|
||||||
user$: Observable<ProfileState>;
|
user$: Observable<ProfileState>;
|
||||||
|
|
||||||
constructor(content: ContentManagementService,
|
constructor(
|
||||||
|
content: ContentManagementService,
|
||||||
extensions: AppExtensionService,
|
extensions: AppExtensionService,
|
||||||
store: Store<AppStore>,
|
store: Store<AppStore>,
|
||||||
private breakpointObserver: BreakpointObserver) {
|
private breakpointObserver: BreakpointObserver
|
||||||
|
) {
|
||||||
super(store, extensions, content);
|
super(store, extensions, content);
|
||||||
this.user$ = this.store.select(selectUser);
|
this.user$ = this.store.select(selectUser);
|
||||||
}
|
}
|
||||||
@@ -58,10 +60,7 @@ export class TrashcanComponent extends PageComponent implements OnInit {
|
|||||||
this.content.nodesRestored.subscribe(() => this.reload()),
|
this.content.nodesRestored.subscribe(() => this.reload()),
|
||||||
|
|
||||||
this.breakpointObserver
|
this.breakpointObserver
|
||||||
.observe([
|
.observe([Breakpoints.HandsetPortrait, Breakpoints.HandsetLandscape])
|
||||||
Breakpoints.HandsetPortrait,
|
|
||||||
Breakpoints.HandsetLandscape
|
|
||||||
])
|
|
||||||
.subscribe(result => {
|
.subscribe(result => {
|
||||||
this.isSmallScreen = result.matches;
|
this.isSmallScreen = result.matches;
|
||||||
})
|
})
|
||||||
|
@@ -45,7 +45,9 @@ export function forbidSpecialCharacters({ value }: FormControl) {
|
|||||||
const validCharacters: RegExp = /[^A-Za-z0-9-]/;
|
const validCharacters: RegExp = /[^A-Za-z0-9-]/;
|
||||||
const isValid: boolean = !validCharacters.test(value);
|
const isValid: boolean = !validCharacters.test(value);
|
||||||
|
|
||||||
return (isValid) ? null : {
|
return isValid
|
||||||
|
? null
|
||||||
|
: {
|
||||||
message: 'LIBRARY.ERRORS.ILLEGAL_CHARACTERS'
|
message: 'LIBRARY.ERRORS.ILLEGAL_CHARACTERS'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
.mat-radio-group {
|
.mat-radio-group {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@@ -24,7 +24,6 @@ import { ContentApiService } from '../../services/content-api.service';
|
|||||||
import { SiteIdValidator, forbidSpecialCharacters } from './form.validators';
|
import { SiteIdValidator, forbidSpecialCharacters } from './form.validators';
|
||||||
import { debounceTime } from 'rxjs/operators';
|
import { debounceTime } from 'rxjs/operators';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-library-dialog',
|
selector: 'app-library-dialog',
|
||||||
styleUrls: ['./library.dialog.scss'],
|
styleUrls: ['./library.dialog.scss'],
|
||||||
@@ -43,7 +42,11 @@ export class LibraryDialogComponent implements OnInit {
|
|||||||
visibilityOptions = [
|
visibilityOptions = [
|
||||||
{ value: 'PUBLIC', label: 'LIBRARY.VISIBILITY.PUBLIC', disabled: false },
|
{ value: 'PUBLIC', label: 'LIBRARY.VISIBILITY.PUBLIC', disabled: false },
|
||||||
{ value: 'PRIVATE', label: 'LIBRARY.VISIBILITY.PRIVATE', disabled: false },
|
{ value: 'PRIVATE', label: 'LIBRARY.VISIBILITY.PRIVATE', disabled: false },
|
||||||
{ value: 'MODERATED', label: 'LIBRARY.VISIBILITY.MODERATED', disabled: false }
|
{
|
||||||
|
value: 'MODERATED',
|
||||||
|
label: 'LIBRARY.VISIBILITY.MODERATED',
|
||||||
|
disabled: false
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@@ -54,7 +57,11 @@ export class LibraryDialogComponent implements OnInit {
|
|||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
const validators = {
|
const validators = {
|
||||||
id: [ Validators.required, Validators.maxLength(72), forbidSpecialCharacters ],
|
id: [
|
||||||
|
Validators.required,
|
||||||
|
Validators.maxLength(72),
|
||||||
|
forbidSpecialCharacters
|
||||||
|
],
|
||||||
title: [Validators.required, Validators.maxLength(256)],
|
title: [Validators.required, Validators.maxLength(256)],
|
||||||
description: [Validators.maxLength(512)]
|
description: [Validators.maxLength(512)]
|
||||||
};
|
};
|
||||||
@@ -62,7 +69,7 @@ export class LibraryDialogComponent implements OnInit {
|
|||||||
this.form = this.formBuilder.group({
|
this.form = this.formBuilder.group({
|
||||||
title: ['', validators.title],
|
title: ['', validators.title],
|
||||||
id: ['', validators.id, SiteIdValidator.createValidator(this.contentApi)],
|
id: ['', validators.id, SiteIdValidator.createValidator(this.contentApi)],
|
||||||
description: [ '', validators.description ],
|
description: ['', validators.description]
|
||||||
});
|
});
|
||||||
|
|
||||||
this.visibilityOption = this.visibilityOptions[0].value;
|
this.visibilityOption = this.visibilityOptions[0].value;
|
||||||
@@ -106,15 +113,16 @@ export class LibraryDialogComponent implements OnInit {
|
|||||||
submit() {
|
submit() {
|
||||||
const { form, dialog } = this;
|
const { form, dialog } = this;
|
||||||
|
|
||||||
if (!form.valid) { return; }
|
if (!form.valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.create().subscribe(
|
this.create().subscribe(
|
||||||
(node: SiteEntry) => {
|
(node: SiteEntry) => {
|
||||||
|
|
||||||
this.success.emit(node);
|
this.success.emit(node);
|
||||||
dialog.close(node);
|
dialog.close(node);
|
||||||
},
|
},
|
||||||
(error) => this.handleError(error)
|
error => this.handleError(error)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,16 +143,18 @@ export class LibraryDialogComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private sanitize(input: string) {
|
private sanitize(input: string) {
|
||||||
return input
|
return input.replace(/[\s]/g, '-').replace(/[^A-Za-z0-9-]/g, '');
|
||||||
.replace(/[\s]/g, '-')
|
|
||||||
.replace(/[^A-Za-z0-9-]/g, '');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleError(error: any): any {
|
private handleError(error: any): any {
|
||||||
const { error: { statusCode } } = JSON.parse(error.message);
|
const {
|
||||||
|
error: { statusCode }
|
||||||
|
} = JSON.parse(error.message);
|
||||||
|
|
||||||
if (statusCode === 409) {
|
if (statusCode === 409) {
|
||||||
this.form.controls['id'].setErrors({ message: 'LIBRARY.ERRORS.CONFLICT' });
|
this.form.controls['id'].setErrors({
|
||||||
|
message: 'LIBRARY.ERRORS.CONFLICT'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
|
@@ -34,9 +34,7 @@ import { MAT_DIALOG_DATA } from '@angular/material';
|
|||||||
export class NodePermissionsDialogComponent {
|
export class NodePermissionsDialogComponent {
|
||||||
nodeId: string;
|
nodeId: string;
|
||||||
|
|
||||||
constructor(
|
constructor(@Inject(MAT_DIALOG_DATA) data: any) {
|
||||||
@Inject(MAT_DIALOG_DATA) data: any,
|
|
||||||
) {
|
|
||||||
this.nodeId = data.nodeId;
|
this.nodeId = data.nodeId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -21,7 +21,6 @@
|
|||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.mat-dialog-title {
|
.mat-dialog-title {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
@@ -33,7 +32,6 @@
|
|||||||
color: mat-color($foreground, text, 0.87);
|
color: mat-color($foreground, text, 0.87);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.mat-dialog-actions {
|
.mat-dialog-actions {
|
||||||
padding: 8px 8px 24px 8px;
|
padding: 8px 8px 24px 8px;
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
|
@@ -34,10 +34,6 @@ import { PaginationDirective } from './pagination.directive';
|
|||||||
DocumentListDirective,
|
DocumentListDirective,
|
||||||
PaginationDirective
|
PaginationDirective
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [ExperimentalDirective, DocumentListDirective, PaginationDirective]
|
||||||
ExperimentalDirective,
|
|
||||||
DocumentListDirective,
|
|
||||||
PaginationDirective
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
export class DirectivesModule {}
|
export class DirectivesModule {}
|
||||||
|
@@ -124,16 +124,13 @@ export class DocumentListDirective implements OnInit, OnDestroy {
|
|||||||
return entry;
|
return entry;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.store.dispatch(
|
this.store.dispatch(new SetSelectedNodesAction(selection));
|
||||||
new SetSelectedNodesAction(selection)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private isLockedNode(node): boolean {
|
private isLockedNode(node): boolean {
|
||||||
return (
|
return (
|
||||||
node.isLocked ||
|
node.isLocked ||
|
||||||
(node.properties &&
|
(node.properties && node.properties['cm:lockType'] === 'READ_ONLY_LOCK')
|
||||||
node.properties['cm:lockType'] === 'READ_ONLY_LOCK')
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -23,7 +23,13 @@
|
|||||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Directive, TemplateRef, ViewContainerRef, Input, EmbeddedViewRef } from '@angular/core';
|
import {
|
||||||
|
Directive,
|
||||||
|
TemplateRef,
|
||||||
|
ViewContainerRef,
|
||||||
|
Input,
|
||||||
|
EmbeddedViewRef
|
||||||
|
} from '@angular/core';
|
||||||
import { AppConfigService, StorageService } from '@alfresco/adf-core';
|
import { AppConfigService, StorageService } from '@alfresco/adf-core';
|
||||||
import { environment } from '../../environments/environment';
|
import { environment } from '../../environments/environment';
|
||||||
|
|
||||||
@@ -43,7 +49,8 @@ export class ExperimentalDirective {
|
|||||||
private config: AppConfigService
|
private config: AppConfigService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@Input() set ifExperimental(featureKey: string) {
|
@Input()
|
||||||
|
set ifExperimental(featureKey: string) {
|
||||||
const key = `experimental.${featureKey}`;
|
const key = `experimental.${featureKey}`;
|
||||||
|
|
||||||
const override = this.storage.getItem(key);
|
const override = this.storage.getItem(key);
|
||||||
@@ -66,7 +73,8 @@ export class ExperimentalDirective {
|
|||||||
this.updateView();
|
this.updateView();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Input() set ifExperimentalElse(templateRef: TemplateRef<any>) {
|
@Input()
|
||||||
|
set ifExperimentalElse(templateRef: TemplateRef<any>) {
|
||||||
this.elseTemplateRef = templateRef;
|
this.elseTemplateRef = templateRef;
|
||||||
this.elseViewRef = null;
|
this.elseViewRef = null;
|
||||||
this.updateView();
|
this.updateView();
|
||||||
@@ -88,7 +96,9 @@ export class ExperimentalDirective {
|
|||||||
this.viewContainerRef.clear();
|
this.viewContainerRef.clear();
|
||||||
|
|
||||||
if (this.elseTemplateRef) {
|
if (this.elseTemplateRef) {
|
||||||
this.elseViewRef = this.viewContainerRef.createEmbeddedView(this.elseTemplateRef);
|
this.elseViewRef = this.viewContainerRef.createEmbeddedView(
|
||||||
|
this.elseTemplateRef
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -50,11 +50,9 @@ export class PaginationDirective implements OnInit, OnDestroy {
|
|||||||
);
|
);
|
||||||
|
|
||||||
this.subscriptions.push(
|
this.subscriptions.push(
|
||||||
this.pagination.changePageSize.subscribe(
|
this.pagination.changePageSize.subscribe((event: PaginationModel) => {
|
||||||
(event: PaginationModel) => {
|
|
||||||
this.preferences.paginationSize = event.maxItems;
|
this.preferences.paginationSize = event.maxItems;
|
||||||
}
|
})
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -43,11 +43,7 @@ export function setupExtensions(service: AppExtensionService): Function {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [CommonModule, CoreModule.forChild(), ExtensionsModule.forChild()]
|
||||||
CommonModule,
|
|
||||||
CoreModule.forChild(),
|
|
||||||
ExtensionsModule.forChild()
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
export class CoreExtensionsModule {
|
export class CoreExtensionsModule {
|
||||||
static forRoot(): ModuleWithProviders {
|
static forRoot(): ModuleWithProviders {
|
||||||
|
@@ -96,18 +96,14 @@ export function canDeleteSelection(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isPreview(context, ...args)) {
|
if (isPreview(context, ...args)) {
|
||||||
return context.permissions.check(context.selection.nodes, [
|
return context.permissions.check(context.selection.nodes, ['delete']);
|
||||||
'delete'
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// workaround for Shared Files
|
// workaround for Shared Files
|
||||||
if (isSharedFiles(context, ...args)) {
|
if (isSharedFiles(context, ...args)) {
|
||||||
return context.permissions.check(
|
return context.permissions.check(context.selection.nodes, ['delete'], {
|
||||||
context.selection.nodes,
|
target: 'allowableOperationsOnTarget'
|
||||||
['delete'],
|
});
|
||||||
{ target: 'allowableOperationsOnTarget' }
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return context.permissions.check(context.selection.nodes, ['delete']);
|
return context.permissions.check(context.selection.nodes, ['delete']);
|
||||||
@@ -164,9 +160,7 @@ export function canDownloadSelection(
|
|||||||
return context.selection.nodes.every(node => {
|
return context.selection.nodes.every(node => {
|
||||||
return (
|
return (
|
||||||
node.entry &&
|
node.entry &&
|
||||||
(node.entry.isFile ||
|
(node.entry.isFile || node.entry.isFolder || !!node.entry.nodeId)
|
||||||
node.entry.isFolder ||
|
|
||||||
!!node.entry.nodeId)
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -28,8 +28,16 @@ import { AppTestingModule } from '../testing/app-testing.module';
|
|||||||
import { AppExtensionService } from './extension.service';
|
import { AppExtensionService } from './extension.service';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { AppStore } from '../store/states';
|
import { AppStore } from '../store/states';
|
||||||
import { ContentActionType, mergeArrays,
|
import {
|
||||||
sortByOrder, filterEnabled, reduceSeparators, reduceEmptyMenus, ExtensionService, ExtensionConfig } from '@alfresco/adf-extensions';
|
ContentActionType,
|
||||||
|
mergeArrays,
|
||||||
|
sortByOrder,
|
||||||
|
filterEnabled,
|
||||||
|
reduceSeparators,
|
||||||
|
reduceEmptyMenus,
|
||||||
|
ExtensionService,
|
||||||
|
ExtensionConfig
|
||||||
|
} from '@alfresco/adf-extensions';
|
||||||
|
|
||||||
describe('AppExtensionService', () => {
|
describe('AppExtensionService', () => {
|
||||||
let service: AppExtensionService;
|
let service: AppExtensionService;
|
||||||
@@ -38,9 +46,7 @@ describe('AppExtensionService', () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [AppTestingModule]
|
||||||
AppTestingModule
|
|
||||||
]
|
|
||||||
});
|
});
|
||||||
|
|
||||||
store = TestBed.get(Store);
|
store = TestBed.get(Store);
|
||||||
@@ -96,7 +102,7 @@ describe('AppExtensionService', () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'extra-1'
|
name: 'extra-1'
|
||||||
},
|
}
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -121,9 +127,7 @@ describe('AppExtensionService', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should find action by id', () => {
|
it('should find action by id', () => {
|
||||||
const action = extensions.getActionById(
|
const action = extensions.getActionById('aca:actions/create-folder');
|
||||||
'aca:actions/create-folder'
|
|
||||||
);
|
|
||||||
expect(action).toBeTruthy();
|
expect(action).toBeTruthy();
|
||||||
expect(action.type).toBe('CREATE_FOLDER');
|
expect(action.type).toBe('CREATE_FOLDER');
|
||||||
expect(action.payload).toBe('folder-name');
|
expect(action.payload).toBe('folder-name');
|
||||||
@@ -305,7 +309,7 @@ describe('AppExtensionService', () => {
|
|||||||
id: 'aca:toolbar/separator-1',
|
id: 'aca:toolbar/separator-1',
|
||||||
order: 1,
|
order: 1,
|
||||||
type: ContentActionType.separator,
|
type: ContentActionType.separator,
|
||||||
title: 'action1',
|
title: 'action1'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'aca:toolbar/separator-2',
|
id: 'aca:toolbar/separator-2',
|
||||||
@@ -343,12 +347,8 @@ describe('AppExtensionService', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(service.toolbarActions.length).toBe(2);
|
expect(service.toolbarActions.length).toBe(2);
|
||||||
expect(service.toolbarActions[0].id).toBe(
|
expect(service.toolbarActions[0].id).toBe('aca:toolbar/separator-1');
|
||||||
'aca:toolbar/separator-1'
|
expect(service.toolbarActions[1].id).toBe('aca:toolbar/separator-2');
|
||||||
);
|
|
||||||
expect(service.toolbarActions[1].id).toBe(
|
|
||||||
'aca:toolbar/separator-2'
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -519,11 +519,9 @@ describe('AppExtensionService', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should use implicit order', () => {
|
it('should use implicit order', () => {
|
||||||
const sorted = [
|
const sorted = [{ id: '3' }, { id: '2' }, { id: '1', order: 1 }].sort(
|
||||||
{ id: '3'},
|
sortByOrder
|
||||||
{ id: '2' },
|
);
|
||||||
{ id: '1', order: 1 }
|
|
||||||
].sort(sortByOrder);
|
|
||||||
|
|
||||||
expect(sorted[0].id).toBe('1');
|
expect(sorted[0].id).toBe('1');
|
||||||
expect(sorted[1].id).toBe('3');
|
expect(sorted[1].id).toBe('3');
|
||||||
|
@@ -31,12 +31,20 @@ import { ruleContext } from '../store/selectors/app.selectors';
|
|||||||
import { NodePermissionService } from '../services/node-permission.service';
|
import { NodePermissionService } from '../services/node-permission.service';
|
||||||
import { ProfileResolver } from '../services/profile.resolver';
|
import { ProfileResolver } from '../services/profile.resolver';
|
||||||
import {
|
import {
|
||||||
SelectionState, NavigationState, ExtensionConfig,
|
SelectionState,
|
||||||
RuleContext, RuleEvaluator, ViewerExtensionRef,
|
NavigationState,
|
||||||
ContentActionRef, ContentActionType,
|
ExtensionConfig,
|
||||||
|
RuleContext,
|
||||||
|
RuleEvaluator,
|
||||||
|
ViewerExtensionRef,
|
||||||
|
ContentActionRef,
|
||||||
|
ContentActionType,
|
||||||
ExtensionLoaderService,
|
ExtensionLoaderService,
|
||||||
SidebarTabRef, NavBarGroupRef,
|
SidebarTabRef,
|
||||||
sortByOrder, reduceSeparators, reduceEmptyMenus,
|
NavBarGroupRef,
|
||||||
|
sortByOrder,
|
||||||
|
reduceSeparators,
|
||||||
|
reduceEmptyMenus,
|
||||||
ExtensionService,
|
ExtensionService,
|
||||||
ProfileState
|
ProfileState
|
||||||
} from '@alfresco/adf-extensions';
|
} from '@alfresco/adf-extensions';
|
||||||
@@ -65,8 +73,8 @@ export class AppExtensionService implements RuleContext {
|
|||||||
private store: Store<AppStore>,
|
private store: Store<AppStore>,
|
||||||
private loader: ExtensionLoaderService,
|
private loader: ExtensionLoaderService,
|
||||||
private extensions: ExtensionService,
|
private extensions: ExtensionService,
|
||||||
public permissions: NodePermissionService) {
|
public permissions: NodePermissionService
|
||||||
|
) {
|
||||||
this.store.select(ruleContext).subscribe(result => {
|
this.store.select(ruleContext).subscribe(result => {
|
||||||
this.selection = result.selection;
|
this.selection = result.selection;
|
||||||
this.navigation = result.navigation;
|
this.navigation = result.navigation;
|
||||||
@@ -85,18 +93,42 @@ export class AppExtensionService implements RuleContext {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.toolbarActions = this.loader.getContentActions(config, 'features.toolbar');
|
this.toolbarActions = this.loader.getContentActions(
|
||||||
this.viewerToolbarActions = this.loader.getContentActions(config, 'features.viewer.toolbar');
|
config,
|
||||||
this.viewerContentExtensions = this.loader.getElements<ViewerExtensionRef>(config, 'features.viewer.content');
|
'features.toolbar'
|
||||||
this.contextMenuActions = this.loader.getContentActions(config, 'features.contextMenu');
|
);
|
||||||
this.openWithActions = this.loader.getContentActions(config, 'features.viewer.openWith');
|
this.viewerToolbarActions = this.loader.getContentActions(
|
||||||
this.createActions = this.loader.getElements<ContentActionRef>(config, 'features.create');
|
config,
|
||||||
|
'features.viewer.toolbar'
|
||||||
|
);
|
||||||
|
this.viewerContentExtensions = this.loader.getElements<ViewerExtensionRef>(
|
||||||
|
config,
|
||||||
|
'features.viewer.content'
|
||||||
|
);
|
||||||
|
this.contextMenuActions = this.loader.getContentActions(
|
||||||
|
config,
|
||||||
|
'features.contextMenu'
|
||||||
|
);
|
||||||
|
this.openWithActions = this.loader.getContentActions(
|
||||||
|
config,
|
||||||
|
'features.viewer.openWith'
|
||||||
|
);
|
||||||
|
this.createActions = this.loader.getElements<ContentActionRef>(
|
||||||
|
config,
|
||||||
|
'features.create'
|
||||||
|
);
|
||||||
this.navbar = this.loadNavBar(config);
|
this.navbar = this.loadNavBar(config);
|
||||||
this.sidebar = this.loader.getElements<SidebarTabRef>(config, 'features.sidebar');
|
this.sidebar = this.loader.getElements<SidebarTabRef>(
|
||||||
|
config,
|
||||||
|
'features.sidebar'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected loadNavBar(config: ExtensionConfig): Array<NavBarGroupRef> {
|
protected loadNavBar(config: ExtensionConfig): Array<NavBarGroupRef> {
|
||||||
const elements = this.loader.getElements<NavBarGroupRef>(config, 'features.navbar');
|
const elements = this.loader.getElements<NavBarGroupRef>(
|
||||||
|
config,
|
||||||
|
'features.navbar'
|
||||||
|
);
|
||||||
|
|
||||||
return elements.map(group => {
|
return elements.map(group => {
|
||||||
return {
|
return {
|
||||||
@@ -131,9 +163,7 @@ export class AppExtensionService implements RuleContext {
|
|||||||
getApplicationRoutes(): Array<Route> {
|
getApplicationRoutes(): Array<Route> {
|
||||||
return this.extensions.routes.map(route => {
|
return this.extensions.routes.map(route => {
|
||||||
const guards = this.extensions.getAuthGuards(
|
const guards = this.extensions.getAuthGuards(
|
||||||
route.auth && route.auth.length > 0
|
route.auth && route.auth.length > 0 ? route.auth : this.defaults.auth
|
||||||
? route.auth
|
|
||||||
: this.defaults.auth
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -179,9 +209,7 @@ export class AppExtensionService implements RuleContext {
|
|||||||
const copy = this.copyAction(action);
|
const copy = this.copyAction(action);
|
||||||
if (copy.children && copy.children.length > 0) {
|
if (copy.children && copy.children.length > 0) {
|
||||||
copy.children = copy.children
|
copy.children = copy.children
|
||||||
.filter(childAction =>
|
.filter(childAction => this.filterByRules(childAction))
|
||||||
this.filterByRules(childAction)
|
|
||||||
)
|
|
||||||
.reduce(reduceSeparators, []);
|
.reduce(reduceSeparators, []);
|
||||||
}
|
}
|
||||||
return copy;
|
return copy;
|
||||||
@@ -193,21 +221,19 @@ export class AppExtensionService implements RuleContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getViewerToolbarActions(): Array<ContentActionRef> {
|
getViewerToolbarActions(): Array<ContentActionRef> {
|
||||||
return this.viewerToolbarActions
|
return this.viewerToolbarActions.filter(action =>
|
||||||
.filter(action => this.filterByRules(action));
|
this.filterByRules(action)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getAllowedContextMenuActions(): Array<ContentActionRef> {
|
getAllowedContextMenuActions(): Array<ContentActionRef> {
|
||||||
return this.contextMenuActions
|
return this.contextMenuActions.filter(action => this.filterByRules(action));
|
||||||
.filter(action => this.filterByRules(action));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
copyAction(action: ContentActionRef): ContentActionRef {
|
copyAction(action: ContentActionRef): ContentActionRef {
|
||||||
return {
|
return {
|
||||||
...action,
|
...action,
|
||||||
children: (action.children || []).map(child =>
|
children: (action.children || []).map(child => this.copyAction(child))
|
||||||
this.copyAction(child)
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -71,12 +71,7 @@ export class ContentApiService {
|
|||||||
*/
|
*/
|
||||||
getNode(nodeId: string, options: any = {}): Observable<MinimalNodeEntity> {
|
getNode(nodeId: string, options: any = {}): Observable<MinimalNodeEntity> {
|
||||||
const defaults = {
|
const defaults = {
|
||||||
include: [
|
include: ['path', 'properties', 'allowableOperations', 'permissions']
|
||||||
'path',
|
|
||||||
'properties',
|
|
||||||
'allowableOperations',
|
|
||||||
'permissions'
|
|
||||||
]
|
|
||||||
};
|
};
|
||||||
const queryOptions = Object.assign(defaults, options);
|
const queryOptions = Object.assign(defaults, options);
|
||||||
|
|
||||||
@@ -172,9 +167,7 @@ export class ContentApiService {
|
|||||||
*/
|
*/
|
||||||
getRepositoryInformation(): Observable<DiscoveryEntry> {
|
getRepositoryInformation(): Observable<DiscoveryEntry> {
|
||||||
return from(
|
return from(
|
||||||
this.api
|
this.api.getInstance().discovery.discoveryApi.getRepositoryInformation()
|
||||||
.getInstance()
|
|
||||||
.discovery.discoveryApi.getRepositoryInformation()
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,10 +195,7 @@ export class ContentApiService {
|
|||||||
return this.api.contentApi.getContentUrl(nodeId, attachment);
|
return this.api.contentApi.getContentUrl(nodeId, attachment);
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteSite(
|
deleteSite(siteId?: string, opts?: { permanent?: boolean }): Observable<any> {
|
||||||
siteId?: string,
|
|
||||||
opts?: { permanent?: boolean }
|
|
||||||
): Observable<any> {
|
|
||||||
return from(this.api.sitesApi.deleteSite(siteId, opts));
|
return from(this.api.sitesApi.deleteSite(siteId, opts));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -23,15 +23,24 @@
|
|||||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
import { TestBed, fakeAsync } from '@angular/core/testing';
|
import { TestBed, fakeAsync } from '@angular/core/testing';
|
||||||
import { of, throwError } from 'rxjs';
|
import { of, throwError } from 'rxjs';
|
||||||
import { MatDialog, MatSnackBar } from '@angular/material';
|
import { MatDialog, MatSnackBar } from '@angular/material';
|
||||||
import { Actions, ofType, EffectsModule } from '@ngrx/effects';
|
import { Actions, ofType, EffectsModule } from '@ngrx/effects';
|
||||||
import {
|
import {
|
||||||
SNACKBAR_INFO, SnackbarWarningAction, SnackbarInfoAction,
|
SNACKBAR_INFO,
|
||||||
SnackbarErrorAction, SNACKBAR_ERROR, SNACKBAR_WARNING, PurgeDeletedNodesAction,
|
SnackbarWarningAction,
|
||||||
RestoreDeletedNodesAction, NavigateRouteAction, NAVIGATE_ROUTE, DeleteNodesAction, MoveNodesAction, CopyNodesAction
|
SnackbarInfoAction,
|
||||||
|
SnackbarErrorAction,
|
||||||
|
SNACKBAR_ERROR,
|
||||||
|
SNACKBAR_WARNING,
|
||||||
|
PurgeDeletedNodesAction,
|
||||||
|
RestoreDeletedNodesAction,
|
||||||
|
NavigateRouteAction,
|
||||||
|
NAVIGATE_ROUTE,
|
||||||
|
DeleteNodesAction,
|
||||||
|
MoveNodesAction,
|
||||||
|
CopyNodesAction
|
||||||
} from '../store/actions';
|
} from '../store/actions';
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
import { NodeEffects } from '../store/effects/node.effects';
|
import { NodeEffects } from '../store/effects/node.effects';
|
||||||
@@ -44,7 +53,6 @@ import { NodeActionsService } from './node-actions.service';
|
|||||||
import { TranslationService } from '@alfresco/adf-core';
|
import { TranslationService } from '@alfresco/adf-core';
|
||||||
|
|
||||||
describe('ContentManagementService', () => {
|
describe('ContentManagementService', () => {
|
||||||
|
|
||||||
let dialog: MatDialog;
|
let dialog: MatDialog;
|
||||||
let actions$: Actions;
|
let actions$: Actions;
|
||||||
let contentApi: ContentApiService;
|
let contentApi: ContentApiService;
|
||||||
@@ -56,10 +64,7 @@ describe('ContentManagementService', () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [AppTestingModule, EffectsModule.forRoot([NodeEffects])]
|
||||||
AppTestingModule,
|
|
||||||
EffectsModule.forRoot([NodeEffects])
|
|
||||||
]
|
|
||||||
});
|
});
|
||||||
|
|
||||||
contentApi = TestBed.get(ContentApiService);
|
contentApi = TestBed.get(ContentApiService);
|
||||||
@@ -84,7 +89,9 @@ describe('ContentManagementService', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('notifies successful copy of a node', () => {
|
it('notifies successful copy of a node', () => {
|
||||||
spyOn(nodeActions, 'copyNodes').and.returnValue(of('OPERATION.SUCCES.CONTENT.COPY'));
|
spyOn(nodeActions, 'copyNodes').and.returnValue(
|
||||||
|
of('OPERATION.SUCCES.CONTENT.COPY')
|
||||||
|
);
|
||||||
|
|
||||||
const selection = [{ entry: { id: 'node-to-copy-id', name: 'name' } }];
|
const selection = [{ entry: { id: 'node-to-copy-id', name: 'name' } }];
|
||||||
const createdItems = [{ entry: { id: 'copy-id', name: 'name' } }];
|
const createdItems = [{ entry: { id: 'copy-id', name: 'name' } }];
|
||||||
@@ -93,88 +100,114 @@ describe('ContentManagementService', () => {
|
|||||||
nodeActions.contentCopied.next(<any>createdItems);
|
nodeActions.contentCopied.next(<any>createdItems);
|
||||||
|
|
||||||
expect(nodeActions.copyNodes).toHaveBeenCalled();
|
expect(nodeActions.copyNodes).toHaveBeenCalled();
|
||||||
expect(snackBar.open['calls'].argsFor(0)[0]).toBe('APP.MESSAGES.INFO.NODE_COPY.SINGULAR');
|
expect(snackBar.open['calls'].argsFor(0)[0]).toBe(
|
||||||
|
'APP.MESSAGES.INFO.NODE_COPY.SINGULAR'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('notifies successful copy of multiple nodes', () => {
|
it('notifies successful copy of multiple nodes', () => {
|
||||||
spyOn(nodeActions, 'copyNodes').and.returnValue(of('OPERATION.SUCCES.CONTENT.COPY'));
|
spyOn(nodeActions, 'copyNodes').and.returnValue(
|
||||||
|
of('OPERATION.SUCCES.CONTENT.COPY')
|
||||||
|
);
|
||||||
|
|
||||||
const selection = [
|
const selection = [
|
||||||
{ entry: { id: 'node-to-copy-1', name: 'name1' } },
|
{ entry: { id: 'node-to-copy-1', name: 'name1' } },
|
||||||
{ entry: { id: 'node-to-copy-2', name: 'name2' } }];
|
{ entry: { id: 'node-to-copy-2', name: 'name2' } }
|
||||||
|
];
|
||||||
const createdItems = [
|
const createdItems = [
|
||||||
{ entry: { id: 'copy-of-node-1', name: 'name1' } },
|
{ entry: { id: 'copy-of-node-1', name: 'name1' } },
|
||||||
{ entry: { id: 'copy-of-node-2', name: 'name2' } }];
|
{ entry: { id: 'copy-of-node-2', name: 'name2' } }
|
||||||
|
];
|
||||||
|
|
||||||
store.dispatch(new CopyNodesAction(selection));
|
store.dispatch(new CopyNodesAction(selection));
|
||||||
nodeActions.contentCopied.next(<any>createdItems);
|
nodeActions.contentCopied.next(<any>createdItems);
|
||||||
|
|
||||||
expect(nodeActions.copyNodes).toHaveBeenCalled();
|
expect(nodeActions.copyNodes).toHaveBeenCalled();
|
||||||
expect(snackBar.open['calls'].argsFor(0)[0]).toBe('APP.MESSAGES.INFO.NODE_COPY.PLURAL');
|
expect(snackBar.open['calls'].argsFor(0)[0]).toBe(
|
||||||
|
'APP.MESSAGES.INFO.NODE_COPY.PLURAL'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('notifies partially copy of one node out of a multiple selection of nodes', () => {
|
it('notifies partially copy of one node out of a multiple selection of nodes', () => {
|
||||||
spyOn(nodeActions, 'copyNodes').and.returnValue(of('OPERATION.SUCCES.CONTENT.COPY'));
|
spyOn(nodeActions, 'copyNodes').and.returnValue(
|
||||||
|
of('OPERATION.SUCCES.CONTENT.COPY')
|
||||||
|
);
|
||||||
|
|
||||||
const selection = [
|
const selection = [
|
||||||
{ entry: { id: 'node-to-copy-1', name: 'name1' } },
|
{ entry: { id: 'node-to-copy-1', name: 'name1' } },
|
||||||
{ entry: { id: 'node-to-copy-2', name: 'name2' } }];
|
{ entry: { id: 'node-to-copy-2', name: 'name2' } }
|
||||||
const createdItems = [
|
];
|
||||||
{ entry: { id: 'copy-of-node-1', name: 'name1' } }];
|
const createdItems = [{ entry: { id: 'copy-of-node-1', name: 'name1' } }];
|
||||||
|
|
||||||
store.dispatch(new CopyNodesAction(selection));
|
store.dispatch(new CopyNodesAction(selection));
|
||||||
nodeActions.contentCopied.next(<any>createdItems);
|
nodeActions.contentCopied.next(<any>createdItems);
|
||||||
|
|
||||||
expect(nodeActions.copyNodes).toHaveBeenCalled();
|
expect(nodeActions.copyNodes).toHaveBeenCalled();
|
||||||
expect(snackBar.open['calls'].argsFor(0)[0]).toBe('APP.MESSAGES.INFO.NODE_COPY.PARTIAL_SINGULAR');
|
expect(snackBar.open['calls'].argsFor(0)[0]).toBe(
|
||||||
|
'APP.MESSAGES.INFO.NODE_COPY.PARTIAL_SINGULAR'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('notifies partially copy of more nodes out of a multiple selection of nodes', () => {
|
it('notifies partially copy of more nodes out of a multiple selection of nodes', () => {
|
||||||
spyOn(nodeActions, 'copyNodes').and.returnValue(of('OPERATION.SUCCES.CONTENT.COPY'));
|
spyOn(nodeActions, 'copyNodes').and.returnValue(
|
||||||
|
of('OPERATION.SUCCES.CONTENT.COPY')
|
||||||
|
);
|
||||||
|
|
||||||
const selection = [
|
const selection = [
|
||||||
{ entry: { id: 'node-to-copy-0', name: 'name0' } },
|
{ entry: { id: 'node-to-copy-0', name: 'name0' } },
|
||||||
{ entry: { id: 'node-to-copy-1', name: 'name1' } },
|
{ entry: { id: 'node-to-copy-1', name: 'name1' } },
|
||||||
{ entry: { id: 'node-to-copy-2', name: 'name2' } }];
|
{ entry: { id: 'node-to-copy-2', name: 'name2' } }
|
||||||
|
];
|
||||||
const createdItems = [
|
const createdItems = [
|
||||||
{ entry: { id: 'copy-of-node-0', name: 'name0' } },
|
{ entry: { id: 'copy-of-node-0', name: 'name0' } },
|
||||||
{ entry: { id: 'copy-of-node-1', name: 'name1' } }];
|
{ entry: { id: 'copy-of-node-1', name: 'name1' } }
|
||||||
|
];
|
||||||
|
|
||||||
store.dispatch(new CopyNodesAction(selection));
|
store.dispatch(new CopyNodesAction(selection));
|
||||||
nodeActions.contentCopied.next(<any>createdItems);
|
nodeActions.contentCopied.next(<any>createdItems);
|
||||||
|
|
||||||
expect(nodeActions.copyNodes).toHaveBeenCalled();
|
expect(nodeActions.copyNodes).toHaveBeenCalled();
|
||||||
expect(snackBar.open['calls'].argsFor(0)[0]).toBe('APP.MESSAGES.INFO.NODE_COPY.PARTIAL_PLURAL');
|
expect(snackBar.open['calls'].argsFor(0)[0]).toBe(
|
||||||
|
'APP.MESSAGES.INFO.NODE_COPY.PARTIAL_PLURAL'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('notifies of failed copy of multiple nodes', () => {
|
it('notifies of failed copy of multiple nodes', () => {
|
||||||
spyOn(nodeActions, 'copyNodes').and.returnValue(of('OPERATION.SUCCES.CONTENT.COPY'));
|
spyOn(nodeActions, 'copyNodes').and.returnValue(
|
||||||
|
of('OPERATION.SUCCES.CONTENT.COPY')
|
||||||
|
);
|
||||||
|
|
||||||
const selection = [
|
const selection = [
|
||||||
{ entry: { id: 'node-to-copy-0', name: 'name0' } },
|
{ entry: { id: 'node-to-copy-0', name: 'name0' } },
|
||||||
{ entry: { id: 'node-to-copy-1', name: 'name1' } },
|
{ entry: { id: 'node-to-copy-1', name: 'name1' } },
|
||||||
{ entry: { id: 'node-to-copy-2', name: 'name2' } }];
|
{ entry: { id: 'node-to-copy-2', name: 'name2' } }
|
||||||
|
];
|
||||||
const createdItems = [];
|
const createdItems = [];
|
||||||
|
|
||||||
store.dispatch(new CopyNodesAction(selection));
|
store.dispatch(new CopyNodesAction(selection));
|
||||||
nodeActions.contentCopied.next(<any>createdItems);
|
nodeActions.contentCopied.next(<any>createdItems);
|
||||||
|
|
||||||
expect(nodeActions.copyNodes).toHaveBeenCalled();
|
expect(nodeActions.copyNodes).toHaveBeenCalled();
|
||||||
expect(snackBar.open['calls'].argsFor(0)[0]).toBe('APP.MESSAGES.INFO.NODE_COPY.FAIL_PLURAL');
|
expect(snackBar.open['calls'].argsFor(0)[0]).toBe(
|
||||||
|
'APP.MESSAGES.INFO.NODE_COPY.FAIL_PLURAL'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('notifies of failed copy of one node', () => {
|
it('notifies of failed copy of one node', () => {
|
||||||
spyOn(nodeActions, 'copyNodes').and.returnValue(of('OPERATION.SUCCES.CONTENT.COPY'));
|
spyOn(nodeActions, 'copyNodes').and.returnValue(
|
||||||
|
of('OPERATION.SUCCES.CONTENT.COPY')
|
||||||
|
);
|
||||||
|
|
||||||
const selection = [
|
const selection = [{ entry: { id: 'node-to-copy', name: 'name' } }];
|
||||||
{ entry: { id: 'node-to-copy', name: 'name' } }];
|
|
||||||
const createdItems = [];
|
const createdItems = [];
|
||||||
|
|
||||||
store.dispatch(new CopyNodesAction(selection));
|
store.dispatch(new CopyNodesAction(selection));
|
||||||
nodeActions.contentCopied.next(<any>createdItems);
|
nodeActions.contentCopied.next(<any>createdItems);
|
||||||
|
|
||||||
expect(nodeActions.copyNodes).toHaveBeenCalled();
|
expect(nodeActions.copyNodes).toHaveBeenCalled();
|
||||||
expect(snackBar.open['calls'].argsFor(0)[0]).toBe('APP.MESSAGES.INFO.NODE_COPY.FAIL_SINGULAR');
|
expect(snackBar.open['calls'].argsFor(0)[0]).toBe(
|
||||||
|
'APP.MESSAGES.INFO.NODE_COPY.FAIL_SINGULAR'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('notifies error if success message was not emitted', () => {
|
it('notifies error if success message was not emitted', () => {
|
||||||
@@ -186,34 +219,46 @@ describe('ContentManagementService', () => {
|
|||||||
nodeActions.contentCopied.next();
|
nodeActions.contentCopied.next();
|
||||||
|
|
||||||
expect(nodeActions.copyNodes).toHaveBeenCalled();
|
expect(nodeActions.copyNodes).toHaveBeenCalled();
|
||||||
expect(snackBar.open['calls'].argsFor(0)[0]).toBe('APP.MESSAGES.ERRORS.GENERIC');
|
expect(snackBar.open['calls'].argsFor(0)[0]).toBe(
|
||||||
|
'APP.MESSAGES.ERRORS.GENERIC'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('notifies permission error on copy of node', () => {
|
it('notifies permission error on copy of node', () => {
|
||||||
spyOn(nodeActions, 'copyNodes').and.returnValue(throwError(new Error(JSON.stringify({error: {statusCode: 403}}))));
|
spyOn(nodeActions, 'copyNodes').and.returnValue(
|
||||||
|
throwError(new Error(JSON.stringify({ error: { statusCode: 403 } })))
|
||||||
|
);
|
||||||
|
|
||||||
const selection = [{ entry: { id: '1', name: 'name' } }];
|
const selection = [{ entry: { id: '1', name: 'name' } }];
|
||||||
store.dispatch(new CopyNodesAction(selection));
|
store.dispatch(new CopyNodesAction(selection));
|
||||||
|
|
||||||
expect(nodeActions.copyNodes).toHaveBeenCalled();
|
expect(nodeActions.copyNodes).toHaveBeenCalled();
|
||||||
expect(snackBar.open['calls'].argsFor(0)[0]).toBe('APP.MESSAGES.ERRORS.PERMISSION');
|
expect(snackBar.open['calls'].argsFor(0)[0]).toBe(
|
||||||
|
'APP.MESSAGES.ERRORS.PERMISSION'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('notifies generic error message on all errors, but 403', () => {
|
it('notifies generic error message on all errors, but 403', () => {
|
||||||
spyOn(nodeActions, 'copyNodes').and.returnValue(throwError(new Error(JSON.stringify({error: {statusCode: 404}}))));
|
spyOn(nodeActions, 'copyNodes').and.returnValue(
|
||||||
|
throwError(new Error(JSON.stringify({ error: { statusCode: 404 } })))
|
||||||
|
);
|
||||||
|
|
||||||
const selection = [{ entry: { id: '1', name: 'name' } }];
|
const selection = [{ entry: { id: '1', name: 'name' } }];
|
||||||
|
|
||||||
store.dispatch(new CopyNodesAction(selection));
|
store.dispatch(new CopyNodesAction(selection));
|
||||||
|
|
||||||
expect(nodeActions.copyNodes).toHaveBeenCalled();
|
expect(nodeActions.copyNodes).toHaveBeenCalled();
|
||||||
expect(snackBar.open['calls'].argsFor(0)[0]).toBe('APP.MESSAGES.ERRORS.GENERIC');
|
expect(snackBar.open['calls'].argsFor(0)[0]).toBe(
|
||||||
|
'APP.MESSAGES.ERRORS.GENERIC'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Undo Copy action', () => {
|
describe('Undo Copy action', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
spyOn(nodeActions, 'copyNodes').and.returnValue(of('OPERATION.SUCCES.CONTENT.COPY'));
|
spyOn(nodeActions, 'copyNodes').and.returnValue(
|
||||||
|
of('OPERATION.SUCCES.CONTENT.COPY')
|
||||||
|
);
|
||||||
|
|
||||||
spyOn(snackBar, 'open').and.returnValue({
|
spyOn(snackBar, 'open').and.returnValue({
|
||||||
onAction: () => of({})
|
onAction: () => of({})
|
||||||
@@ -230,32 +275,58 @@ describe('ContentManagementService', () => {
|
|||||||
nodeActions.contentCopied.next(<any>createdItems);
|
nodeActions.contentCopied.next(<any>createdItems);
|
||||||
|
|
||||||
expect(nodeActions.copyNodes).toHaveBeenCalled();
|
expect(nodeActions.copyNodes).toHaveBeenCalled();
|
||||||
expect(snackBar.open['calls'].argsFor(0)[0]).toBe('APP.MESSAGES.INFO.NODE_COPY.SINGULAR');
|
expect(snackBar.open['calls'].argsFor(0)[0]).toBe(
|
||||||
|
'APP.MESSAGES.INFO.NODE_COPY.SINGULAR'
|
||||||
|
);
|
||||||
|
|
||||||
expect(contentApi.deleteNode).toHaveBeenCalledWith(createdItems[0].entry.id, { permanent: true });
|
expect(contentApi.deleteNode).toHaveBeenCalledWith(
|
||||||
|
createdItems[0].entry.id,
|
||||||
|
{ permanent: true }
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should delete also the node created inside an already existing folder from destination', () => {
|
it('should delete also the node created inside an already existing folder from destination', () => {
|
||||||
const spyOnDeleteNode = spyOn(contentApi, 'deleteNode').and.returnValue(of(null));
|
const spyOnDeleteNode = spyOn(contentApi, 'deleteNode').and.returnValue(
|
||||||
|
of(null)
|
||||||
|
);
|
||||||
|
|
||||||
const selection = [
|
const selection = [
|
||||||
{ entry: { id: 'node-to-copy-1', name: 'name1' } },
|
{ entry: { id: 'node-to-copy-1', name: 'name1' } },
|
||||||
{ entry: { id: 'node-to-copy-2', name: 'folder-with-name-already-existing-on-destination' } }];
|
{
|
||||||
|
entry: {
|
||||||
|
id: 'node-to-copy-2',
|
||||||
|
name: 'folder-with-name-already-existing-on-destination'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
const id1 = 'copy-of-node-1';
|
const id1 = 'copy-of-node-1';
|
||||||
const id2 = 'copy-of-child-of-node-2';
|
const id2 = 'copy-of-child-of-node-2';
|
||||||
const createdItems = [
|
const createdItems = [
|
||||||
{ entry: { id: id1, name: 'name1' } },
|
{ entry: { id: id1, name: 'name1' } },
|
||||||
[ { entry: { id: id2, name: 'name-of-child-of-node-2' , parentId: 'the-folder-already-on-destination' } }] ];
|
[
|
||||||
|
{
|
||||||
|
entry: {
|
||||||
|
id: id2,
|
||||||
|
name: 'name-of-child-of-node-2',
|
||||||
|
parentId: 'the-folder-already-on-destination'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
store.dispatch(new CopyNodesAction(selection));
|
store.dispatch(new CopyNodesAction(selection));
|
||||||
nodeActions.contentCopied.next(<any>createdItems);
|
nodeActions.contentCopied.next(<any>createdItems);
|
||||||
|
|
||||||
expect(nodeActions.copyNodes).toHaveBeenCalled();
|
expect(nodeActions.copyNodes).toHaveBeenCalled();
|
||||||
expect(snackBar.open['calls'].argsFor(0)[0]).toBe('APP.MESSAGES.INFO.NODE_COPY.PLURAL');
|
expect(snackBar.open['calls'].argsFor(0)[0]).toBe(
|
||||||
|
'APP.MESSAGES.INFO.NODE_COPY.PLURAL'
|
||||||
|
);
|
||||||
|
|
||||||
expect(spyOnDeleteNode).toHaveBeenCalled();
|
expect(spyOnDeleteNode).toHaveBeenCalled();
|
||||||
expect(spyOnDeleteNode.calls.allArgs())
|
expect(spyOnDeleteNode.calls.allArgs()).toEqual([
|
||||||
.toEqual([[id1, { permanent: true }], [id2, { permanent: true }]]);
|
[id1, { permanent: true }],
|
||||||
|
[id2, { permanent: true }]
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('notifies when error occurs on Undo action', () => {
|
it('notifies when error occurs on Undo action', () => {
|
||||||
@@ -269,11 +340,15 @@ describe('ContentManagementService', () => {
|
|||||||
|
|
||||||
expect(nodeActions.copyNodes).toHaveBeenCalled();
|
expect(nodeActions.copyNodes).toHaveBeenCalled();
|
||||||
expect(contentApi.deleteNode).toHaveBeenCalled();
|
expect(contentApi.deleteNode).toHaveBeenCalled();
|
||||||
expect(snackBar.open['calls'].argsFor(0)[0]).toEqual('APP.MESSAGES.INFO.NODE_COPY.SINGULAR');
|
expect(snackBar.open['calls'].argsFor(0)[0]).toEqual(
|
||||||
|
'APP.MESSAGES.INFO.NODE_COPY.SINGULAR'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('notifies when some error of type Error occurs on Undo action', () => {
|
it('notifies when some error of type Error occurs on Undo action', () => {
|
||||||
spyOn(contentApi, 'deleteNode').and.returnValue(throwError(new Error('oops!')));
|
spyOn(contentApi, 'deleteNode').and.returnValue(
|
||||||
|
throwError(new Error('oops!'))
|
||||||
|
);
|
||||||
|
|
||||||
const selection = [{ entry: { id: 'node-to-copy-id', name: 'name' } }];
|
const selection = [{ entry: { id: 'node-to-copy-id', name: 'name' } }];
|
||||||
const createdItems = [{ entry: { id: 'copy-id', name: 'name' } }];
|
const createdItems = [{ entry: { id: 'copy-id', name: 'name' } }];
|
||||||
@@ -283,11 +358,15 @@ describe('ContentManagementService', () => {
|
|||||||
|
|
||||||
expect(nodeActions.copyNodes).toHaveBeenCalled();
|
expect(nodeActions.copyNodes).toHaveBeenCalled();
|
||||||
expect(contentApi.deleteNode).toHaveBeenCalled();
|
expect(contentApi.deleteNode).toHaveBeenCalled();
|
||||||
expect(snackBar.open['calls'].argsFor(0)[0]).toEqual('APP.MESSAGES.INFO.NODE_COPY.SINGULAR');
|
expect(snackBar.open['calls'].argsFor(0)[0]).toEqual(
|
||||||
|
'APP.MESSAGES.INFO.NODE_COPY.SINGULAR'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('notifies permission error when it occurs on Undo action', () => {
|
it('notifies permission error when it occurs on Undo action', () => {
|
||||||
spyOn(contentApi, 'deleteNode').and.returnValue(throwError(new Error(JSON.stringify({error: {statusCode: 403}}))));
|
spyOn(contentApi, 'deleteNode').and.returnValue(
|
||||||
|
throwError(new Error(JSON.stringify({ error: { statusCode: 403 } })))
|
||||||
|
);
|
||||||
|
|
||||||
const selection = [{ entry: { id: 'node-to-copy-id', name: 'name' } }];
|
const selection = [{ entry: { id: 'node-to-copy-id', name: 'name' } }];
|
||||||
const createdItems = [{ entry: { id: 'copy-id', name: 'name' } }];
|
const createdItems = [{ entry: { id: 'copy-id', name: 'name' } }];
|
||||||
@@ -297,16 +376,18 @@ describe('ContentManagementService', () => {
|
|||||||
|
|
||||||
expect(nodeActions.copyNodes).toHaveBeenCalled();
|
expect(nodeActions.copyNodes).toHaveBeenCalled();
|
||||||
expect(contentApi.deleteNode).toHaveBeenCalled();
|
expect(contentApi.deleteNode).toHaveBeenCalled();
|
||||||
expect(snackBar.open['calls'].argsFor(0)[0]).toEqual('APP.MESSAGES.INFO.NODE_COPY.SINGULAR');
|
expect(snackBar.open['calls'].argsFor(0)[0]).toEqual(
|
||||||
|
'APP.MESSAGES.INFO.NODE_COPY.SINGULAR'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Move node action', () => {
|
describe('Move node action', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
spyOn(translationService, 'instant').and.callFake((keysArray) => {
|
spyOn(translationService, 'instant').and.callFake(keysArray => {
|
||||||
if (Array.isArray(keysArray)) {
|
if (Array.isArray(keysArray)) {
|
||||||
const processedKeys = {};
|
const processedKeys = {};
|
||||||
keysArray.forEach((key) => {
|
keysArray.forEach(key => {
|
||||||
processedKeys[key] = key;
|
processedKeys[key] = key;
|
||||||
});
|
});
|
||||||
return processedKeys;
|
return processedKeys;
|
||||||
@@ -328,7 +409,9 @@ describe('ContentManagementService', () => {
|
|||||||
partiallySucceeded: []
|
partiallySucceeded: []
|
||||||
};
|
};
|
||||||
|
|
||||||
spyOn(nodeActions, 'moveNodes').and.returnValue(of('OPERATION.SUCCES.CONTENT.MOVE'));
|
spyOn(nodeActions, 'moveNodes').and.returnValue(
|
||||||
|
of('OPERATION.SUCCES.CONTENT.MOVE')
|
||||||
|
);
|
||||||
spyOn(nodeActions, 'processResponse').and.returnValue(moveResponse);
|
spyOn(nodeActions, 'processResponse').and.returnValue(moveResponse);
|
||||||
|
|
||||||
const selection = node;
|
const selection = node;
|
||||||
@@ -337,20 +420,25 @@ describe('ContentManagementService', () => {
|
|||||||
nodeActions.contentMoved.next(moveResponse);
|
nodeActions.contentMoved.next(moveResponse);
|
||||||
|
|
||||||
expect(nodeActions.moveNodes).toHaveBeenCalled();
|
expect(nodeActions.moveNodes).toHaveBeenCalled();
|
||||||
expect(snackBar.open['calls'].argsFor(0)[0]).toBe('APP.MESSAGES.INFO.NODE_MOVE.SINGULAR');
|
expect(snackBar.open['calls'].argsFor(0)[0]).toBe(
|
||||||
|
'APP.MESSAGES.INFO.NODE_MOVE.SINGULAR'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('notifies successful move of multiple nodes', () => {
|
it('notifies successful move of multiple nodes', () => {
|
||||||
const nodes = [
|
const nodes = [
|
||||||
{ entry: { id: '1', name: 'name1' } },
|
{ entry: { id: '1', name: 'name1' } },
|
||||||
{ entry: { id: '2', name: 'name2' } }];
|
{ entry: { id: '2', name: 'name2' } }
|
||||||
|
];
|
||||||
const moveResponse = {
|
const moveResponse = {
|
||||||
succeeded: nodes,
|
succeeded: nodes,
|
||||||
failed: [],
|
failed: [],
|
||||||
partiallySucceeded: []
|
partiallySucceeded: []
|
||||||
};
|
};
|
||||||
|
|
||||||
spyOn(nodeActions, 'moveNodes').and.returnValue(of('OPERATION.SUCCES.CONTENT.MOVE'));
|
spyOn(nodeActions, 'moveNodes').and.returnValue(
|
||||||
|
of('OPERATION.SUCCES.CONTENT.MOVE')
|
||||||
|
);
|
||||||
spyOn(nodeActions, 'processResponse').and.returnValue(moveResponse);
|
spyOn(nodeActions, 'processResponse').and.returnValue(moveResponse);
|
||||||
|
|
||||||
const selection = nodes;
|
const selection = nodes;
|
||||||
@@ -359,7 +447,9 @@ describe('ContentManagementService', () => {
|
|||||||
nodeActions.contentMoved.next(moveResponse);
|
nodeActions.contentMoved.next(moveResponse);
|
||||||
|
|
||||||
expect(nodeActions.moveNodes).toHaveBeenCalled();
|
expect(nodeActions.moveNodes).toHaveBeenCalled();
|
||||||
expect(snackBar.open['calls'].argsFor(0)[0]).toBe('APP.MESSAGES.INFO.NODE_MOVE.PLURAL');
|
expect(snackBar.open['calls'].argsFor(0)[0]).toBe(
|
||||||
|
'APP.MESSAGES.INFO.NODE_MOVE.PLURAL'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('notifies partial move of a node', () => {
|
it('notifies partial move of a node', () => {
|
||||||
@@ -370,7 +460,9 @@ describe('ContentManagementService', () => {
|
|||||||
partiallySucceeded: nodes
|
partiallySucceeded: nodes
|
||||||
};
|
};
|
||||||
|
|
||||||
spyOn(nodeActions, 'moveNodes').and.returnValue(of('OPERATION.SUCCES.CONTENT.MOVE'));
|
spyOn(nodeActions, 'moveNodes').and.returnValue(
|
||||||
|
of('OPERATION.SUCCES.CONTENT.MOVE')
|
||||||
|
);
|
||||||
spyOn(nodeActions, 'processResponse').and.returnValue(moveResponse);
|
spyOn(nodeActions, 'processResponse').and.returnValue(moveResponse);
|
||||||
|
|
||||||
const selection = nodes;
|
const selection = nodes;
|
||||||
@@ -379,20 +471,25 @@ describe('ContentManagementService', () => {
|
|||||||
nodeActions.contentMoved.next(moveResponse);
|
nodeActions.contentMoved.next(moveResponse);
|
||||||
|
|
||||||
expect(nodeActions.moveNodes).toHaveBeenCalled();
|
expect(nodeActions.moveNodes).toHaveBeenCalled();
|
||||||
expect(snackBar.open['calls'].argsFor(0)[0]).toBe('APP.MESSAGES.INFO.NODE_MOVE.PARTIAL.SINGULAR');
|
expect(snackBar.open['calls'].argsFor(0)[0]).toBe(
|
||||||
|
'APP.MESSAGES.INFO.NODE_MOVE.PARTIAL.SINGULAR'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('notifies partial move of multiple nodes', () => {
|
it('notifies partial move of multiple nodes', () => {
|
||||||
const nodes = [
|
const nodes = [
|
||||||
{ entry: { id: '1', name: 'name' } },
|
{ entry: { id: '1', name: 'name' } },
|
||||||
{ entry: { id: '2', name: 'name2' } } ];
|
{ entry: { id: '2', name: 'name2' } }
|
||||||
|
];
|
||||||
const moveResponse = {
|
const moveResponse = {
|
||||||
succeeded: [],
|
succeeded: [],
|
||||||
failed: [],
|
failed: [],
|
||||||
partiallySucceeded: nodes
|
partiallySucceeded: nodes
|
||||||
};
|
};
|
||||||
|
|
||||||
spyOn(nodeActions, 'moveNodes').and.returnValue(of('OPERATION.SUCCES.CONTENT.MOVE'));
|
spyOn(nodeActions, 'moveNodes').and.returnValue(
|
||||||
|
of('OPERATION.SUCCES.CONTENT.MOVE')
|
||||||
|
);
|
||||||
spyOn(nodeActions, 'processResponse').and.returnValue(moveResponse);
|
spyOn(nodeActions, 'processResponse').and.returnValue(moveResponse);
|
||||||
|
|
||||||
const selection = nodes;
|
const selection = nodes;
|
||||||
@@ -401,19 +498,25 @@ describe('ContentManagementService', () => {
|
|||||||
nodeActions.contentMoved.next(moveResponse);
|
nodeActions.contentMoved.next(moveResponse);
|
||||||
|
|
||||||
expect(nodeActions.moveNodes).toHaveBeenCalled();
|
expect(nodeActions.moveNodes).toHaveBeenCalled();
|
||||||
expect(snackBar.open['calls'].argsFor(0)[0]).toBe('APP.MESSAGES.INFO.NODE_MOVE.PARTIAL.PLURAL');
|
expect(snackBar.open['calls'].argsFor(0)[0]).toBe(
|
||||||
|
'APP.MESSAGES.INFO.NODE_MOVE.PARTIAL.PLURAL'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('notifies successful move and the number of nodes that could not be moved', () => {
|
it('notifies successful move and the number of nodes that could not be moved', () => {
|
||||||
const nodes = [ { entry: { id: '1', name: 'name' } },
|
const nodes = [
|
||||||
{ entry: { id: '2', name: 'name2' } } ];
|
{ entry: { id: '1', name: 'name' } },
|
||||||
|
{ entry: { id: '2', name: 'name2' } }
|
||||||
|
];
|
||||||
const moveResponse = {
|
const moveResponse = {
|
||||||
succeeded: [nodes[0]],
|
succeeded: [nodes[0]],
|
||||||
failed: [nodes[1]],
|
failed: [nodes[1]],
|
||||||
partiallySucceeded: []
|
partiallySucceeded: []
|
||||||
};
|
};
|
||||||
|
|
||||||
spyOn(nodeActions, 'moveNodes').and.returnValue(of('OPERATION.SUCCES.CONTENT.MOVE'));
|
spyOn(nodeActions, 'moveNodes').and.returnValue(
|
||||||
|
of('OPERATION.SUCCES.CONTENT.MOVE')
|
||||||
|
);
|
||||||
spyOn(nodeActions, 'processResponse').and.returnValue(moveResponse);
|
spyOn(nodeActions, 'processResponse').and.returnValue(moveResponse);
|
||||||
|
|
||||||
store.dispatch(new MoveNodesAction(nodes));
|
store.dispatch(new MoveNodesAction(nodes));
|
||||||
@@ -421,28 +524,34 @@ describe('ContentManagementService', () => {
|
|||||||
nodeActions.contentMoved.next(moveResponse);
|
nodeActions.contentMoved.next(moveResponse);
|
||||||
|
|
||||||
expect(nodeActions.moveNodes).toHaveBeenCalled();
|
expect(nodeActions.moveNodes).toHaveBeenCalled();
|
||||||
expect(snackBar.open['calls'].argsFor(0)[0])
|
expect(snackBar.open['calls'].argsFor(0)[0]).toBe(
|
||||||
.toBe('APP.MESSAGES.INFO.NODE_MOVE.SINGULAR APP.MESSAGES.INFO.NODE_MOVE.PARTIAL.FAIL');
|
'APP.MESSAGES.INFO.NODE_MOVE.SINGULAR APP.MESSAGES.INFO.NODE_MOVE.PARTIAL.FAIL'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('notifies successful move and the number of partially moved ones', () => {
|
it('notifies successful move and the number of partially moved ones', () => {
|
||||||
const nodes = [ { entry: { id: '1', name: 'name' } },
|
const nodes = [
|
||||||
{ entry: { id: '2', name: 'name2' } } ];
|
{ entry: { id: '1', name: 'name' } },
|
||||||
|
{ entry: { id: '2', name: 'name2' } }
|
||||||
|
];
|
||||||
const moveResponse = {
|
const moveResponse = {
|
||||||
succeeded: [nodes[0]],
|
succeeded: [nodes[0]],
|
||||||
failed: [],
|
failed: [],
|
||||||
partiallySucceeded: [nodes[1]]
|
partiallySucceeded: [nodes[1]]
|
||||||
};
|
};
|
||||||
|
|
||||||
spyOn(nodeActions, 'moveNodes').and.returnValue(of('OPERATION.SUCCES.CONTENT.MOVE'));
|
spyOn(nodeActions, 'moveNodes').and.returnValue(
|
||||||
|
of('OPERATION.SUCCES.CONTENT.MOVE')
|
||||||
|
);
|
||||||
spyOn(nodeActions, 'processResponse').and.returnValue(moveResponse);
|
spyOn(nodeActions, 'processResponse').and.returnValue(moveResponse);
|
||||||
|
|
||||||
store.dispatch(new MoveNodesAction(nodes));
|
store.dispatch(new MoveNodesAction(nodes));
|
||||||
nodeActions.contentMoved.next(moveResponse);
|
nodeActions.contentMoved.next(moveResponse);
|
||||||
|
|
||||||
expect(nodeActions.moveNodes).toHaveBeenCalled();
|
expect(nodeActions.moveNodes).toHaveBeenCalled();
|
||||||
expect(snackBar.open['calls'].argsFor(0)[0])
|
expect(snackBar.open['calls'].argsFor(0)[0]).toBe(
|
||||||
.toBe('APP.MESSAGES.INFO.NODE_MOVE.SINGULAR APP.MESSAGES.INFO.NODE_MOVE.PARTIAL.SINGULAR');
|
'APP.MESSAGES.INFO.NODE_MOVE.SINGULAR APP.MESSAGES.INFO.NODE_MOVE.PARTIAL.SINGULAR'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('notifies error if success message was not emitted', () => {
|
it('notifies error if success message was not emitted', () => {
|
||||||
@@ -459,37 +568,51 @@ describe('ContentManagementService', () => {
|
|||||||
nodeActions.contentMoved.next(moveResponse);
|
nodeActions.contentMoved.next(moveResponse);
|
||||||
|
|
||||||
expect(nodeActions.moveNodes).toHaveBeenCalled();
|
expect(nodeActions.moveNodes).toHaveBeenCalled();
|
||||||
expect(snackBar.open['calls'].argsFor(0)[0]).toBe('APP.MESSAGES.ERRORS.GENERIC');
|
expect(snackBar.open['calls'].argsFor(0)[0]).toBe(
|
||||||
|
'APP.MESSAGES.ERRORS.GENERIC'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('notifies permission error on move of node', () => {
|
it('notifies permission error on move of node', () => {
|
||||||
spyOn(nodeActions, 'moveNodes').and.returnValue(throwError(new Error(JSON.stringify({error: {statusCode: 403}}))));
|
spyOn(nodeActions, 'moveNodes').and.returnValue(
|
||||||
|
throwError(new Error(JSON.stringify({ error: { statusCode: 403 } })))
|
||||||
|
);
|
||||||
|
|
||||||
const selection = [{ entry: { id: '1', name: 'name' } }];
|
const selection = [{ entry: { id: '1', name: 'name' } }];
|
||||||
store.dispatch(new MoveNodesAction(selection));
|
store.dispatch(new MoveNodesAction(selection));
|
||||||
|
|
||||||
expect(nodeActions.moveNodes).toHaveBeenCalled();
|
expect(nodeActions.moveNodes).toHaveBeenCalled();
|
||||||
expect(snackBar.open['calls'].argsFor(0)[0]).toBe('APP.MESSAGES.ERRORS.PERMISSION');
|
expect(snackBar.open['calls'].argsFor(0)[0]).toBe(
|
||||||
|
'APP.MESSAGES.ERRORS.PERMISSION'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('notifies generic error message on all errors, but 403', () => {
|
it('notifies generic error message on all errors, but 403', () => {
|
||||||
spyOn(nodeActions, 'moveNodes').and.returnValue(throwError(new Error(JSON.stringify({error: {statusCode: 404}}))));
|
spyOn(nodeActions, 'moveNodes').and.returnValue(
|
||||||
|
throwError(new Error(JSON.stringify({ error: { statusCode: 404 } })))
|
||||||
|
);
|
||||||
|
|
||||||
const selection = [{ entry: { id: '1', name: 'name' } }];
|
const selection = [{ entry: { id: '1', name: 'name' } }];
|
||||||
store.dispatch(new MoveNodesAction(selection));
|
store.dispatch(new MoveNodesAction(selection));
|
||||||
|
|
||||||
expect(nodeActions.moveNodes).toHaveBeenCalled();
|
expect(nodeActions.moveNodes).toHaveBeenCalled();
|
||||||
expect(snackBar.open['calls'].argsFor(0)[0]).toBe('APP.MESSAGES.ERRORS.GENERIC');
|
expect(snackBar.open['calls'].argsFor(0)[0]).toBe(
|
||||||
|
'APP.MESSAGES.ERRORS.GENERIC'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('notifies conflict error message on 409', () => {
|
it('notifies conflict error message on 409', () => {
|
||||||
spyOn(nodeActions, 'moveNodes').and.returnValue(throwError(new Error(JSON.stringify({error: {statusCode: 409}}))));
|
spyOn(nodeActions, 'moveNodes').and.returnValue(
|
||||||
|
throwError(new Error(JSON.stringify({ error: { statusCode: 409 } })))
|
||||||
|
);
|
||||||
|
|
||||||
const selection = [{ entry: { id: '1', name: 'name' } }];
|
const selection = [{ entry: { id: '1', name: 'name' } }];
|
||||||
store.dispatch(new MoveNodesAction(selection));
|
store.dispatch(new MoveNodesAction(selection));
|
||||||
|
|
||||||
expect(nodeActions.moveNodes).toHaveBeenCalled();
|
expect(nodeActions.moveNodes).toHaveBeenCalled();
|
||||||
expect(snackBar.open['calls'].argsFor(0)[0]).toBe('APP.MESSAGES.ERRORS.NODE_MOVE');
|
expect(snackBar.open['calls'].argsFor(0)[0]).toBe(
|
||||||
|
'APP.MESSAGES.ERRORS.NODE_MOVE'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('notifies error if move response has only failed items', () => {
|
it('notifies error if move response has only failed items', () => {
|
||||||
@@ -500,23 +623,27 @@ describe('ContentManagementService', () => {
|
|||||||
partiallySucceeded: []
|
partiallySucceeded: []
|
||||||
};
|
};
|
||||||
|
|
||||||
spyOn(nodeActions, 'moveNodes').and.returnValue(of('OPERATION.SUCCES.CONTENT.MOVE'));
|
spyOn(nodeActions, 'moveNodes').and.returnValue(
|
||||||
|
of('OPERATION.SUCCES.CONTENT.MOVE')
|
||||||
|
);
|
||||||
spyOn(nodeActions, 'processResponse').and.returnValue(moveResponse);
|
spyOn(nodeActions, 'processResponse').and.returnValue(moveResponse);
|
||||||
|
|
||||||
store.dispatch(new MoveNodesAction(nodes));
|
store.dispatch(new MoveNodesAction(nodes));
|
||||||
nodeActions.contentMoved.next(moveResponse);
|
nodeActions.contentMoved.next(moveResponse);
|
||||||
|
|
||||||
expect(nodeActions.moveNodes).toHaveBeenCalled();
|
expect(nodeActions.moveNodes).toHaveBeenCalled();
|
||||||
expect(snackBar.open['calls'].argsFor(0)[0]).toBe('APP.MESSAGES.ERRORS.GENERIC');
|
expect(snackBar.open['calls'].argsFor(0)[0]).toBe(
|
||||||
|
'APP.MESSAGES.ERRORS.GENERIC'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Undo Move action', () => {
|
describe('Undo Move action', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
spyOn(translationService, 'instant').and.callFake((keysArray) => {
|
spyOn(translationService, 'instant').and.callFake(keysArray => {
|
||||||
if (Array.isArray(keysArray)) {
|
if (Array.isArray(keysArray)) {
|
||||||
const processedKeys = {};
|
const processedKeys = {};
|
||||||
keysArray.forEach((key) => {
|
keysArray.forEach(key => {
|
||||||
processedKeys[key] = key;
|
processedKeys[key] = key;
|
||||||
});
|
});
|
||||||
return processedKeys;
|
return processedKeys;
|
||||||
@@ -527,7 +654,9 @@ describe('ContentManagementService', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
spyOn(nodeActions, 'moveNodes').and.returnValue(of('OPERATION.SUCCES.CONTENT.MOVE'));
|
spyOn(nodeActions, 'moveNodes').and.returnValue(
|
||||||
|
of('OPERATION.SUCCES.CONTENT.MOVE')
|
||||||
|
);
|
||||||
|
|
||||||
spyOn(snackBar, 'open').and.returnValue({
|
spyOn(snackBar, 'open').and.returnValue({
|
||||||
onAction: () => of({})
|
onAction: () => of({})
|
||||||
@@ -538,7 +667,9 @@ describe('ContentManagementService', () => {
|
|||||||
|
|
||||||
it('should move node back to initial parent, after succeeded move', () => {
|
it('should move node back to initial parent, after succeeded move', () => {
|
||||||
const initialParent = 'parent-id-0';
|
const initialParent = 'parent-id-0';
|
||||||
const node = { entry: { id: 'node-to-move-id', name: 'name', parentId: initialParent } };
|
const node = {
|
||||||
|
entry: { id: 'node-to-move-id', name: 'name', parentId: initialParent }
|
||||||
|
};
|
||||||
const selection = [node];
|
const selection = [node];
|
||||||
|
|
||||||
spyOn(nodeActions, 'moveNodeAction').and.returnValue(of({}));
|
spyOn(nodeActions, 'moveNodeAction').and.returnValue(of({}));
|
||||||
@@ -551,14 +682,25 @@ describe('ContentManagementService', () => {
|
|||||||
};
|
};
|
||||||
nodeActions.contentMoved.next(<any>movedItems);
|
nodeActions.contentMoved.next(<any>movedItems);
|
||||||
|
|
||||||
expect(nodeActions.moveNodeAction)
|
expect(nodeActions.moveNodeAction).toHaveBeenCalledWith(
|
||||||
.toHaveBeenCalledWith(movedItems.succeeded[0].itemMoved.entry, movedItems.succeeded[0].initialParentId);
|
movedItems.succeeded[0].itemMoved.entry,
|
||||||
expect(snackBar.open['calls'].argsFor(0)[0]).toBe('APP.MESSAGES.INFO.NODE_MOVE.SINGULAR');
|
movedItems.succeeded[0].initialParentId
|
||||||
|
);
|
||||||
|
expect(snackBar.open['calls'].argsFor(0)[0]).toBe(
|
||||||
|
'APP.MESSAGES.INFO.NODE_MOVE.SINGULAR'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should move node back to initial parent, after succeeded move of a single file', () => {
|
it('should move node back to initial parent, after succeeded move of a single file', () => {
|
||||||
const initialParent = 'parent-id-0';
|
const initialParent = 'parent-id-0';
|
||||||
const node = { entry: { id: 'node-to-move-id', name: 'name', isFolder: false, parentId: initialParent } };
|
const node = {
|
||||||
|
entry: {
|
||||||
|
id: 'node-to-move-id',
|
||||||
|
name: 'name',
|
||||||
|
isFolder: false,
|
||||||
|
parentId: initialParent
|
||||||
|
}
|
||||||
|
};
|
||||||
const selection = [node];
|
const selection = [node];
|
||||||
|
|
||||||
spyOn(nodeActions, 'moveNodeAction').and.returnValue(of({}));
|
spyOn(nodeActions, 'moveNodeAction').and.returnValue(of({}));
|
||||||
@@ -572,8 +714,13 @@ describe('ContentManagementService', () => {
|
|||||||
store.dispatch(new MoveNodesAction(selection));
|
store.dispatch(new MoveNodesAction(selection));
|
||||||
nodeActions.contentMoved.next(<any>movedItems);
|
nodeActions.contentMoved.next(<any>movedItems);
|
||||||
|
|
||||||
expect(nodeActions.moveNodeAction).toHaveBeenCalledWith(node.entry, initialParent);
|
expect(nodeActions.moveNodeAction).toHaveBeenCalledWith(
|
||||||
expect(snackBar.open['calls'].argsFor(0)[0]).toBe('APP.MESSAGES.INFO.NODE_MOVE.SINGULAR');
|
node.entry,
|
||||||
|
initialParent
|
||||||
|
);
|
||||||
|
expect(snackBar.open['calls'].argsFor(0)[0]).toBe(
|
||||||
|
'APP.MESSAGES.INFO.NODE_MOVE.SINGULAR'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should restore deleted folder back to initial parent, after succeeded moving all its files', () => {
|
it('should restore deleted folder back to initial parent, after succeeded moving all its files', () => {
|
||||||
@@ -581,7 +728,14 @@ describe('ContentManagementService', () => {
|
|||||||
spyOn(contentApi, 'restoreNode').and.returnValue(of(null));
|
spyOn(contentApi, 'restoreNode').and.returnValue(of(null));
|
||||||
|
|
||||||
const initialParent = 'parent-id-0';
|
const initialParent = 'parent-id-0';
|
||||||
const node = { entry: { id: 'folder-to-move-id', name: 'conflicting-name', parentId: initialParent, isFolder: true } };
|
const node = {
|
||||||
|
entry: {
|
||||||
|
id: 'folder-to-move-id',
|
||||||
|
name: 'conflicting-name',
|
||||||
|
parentId: initialParent,
|
||||||
|
isFolder: true
|
||||||
|
}
|
||||||
|
};
|
||||||
const selection = [node];
|
const selection = [node];
|
||||||
|
|
||||||
const itemMoved = {}; // folder was empty
|
const itemMoved = {}; // folder was empty
|
||||||
@@ -597,7 +751,9 @@ describe('ContentManagementService', () => {
|
|||||||
nodeActions.contentMoved.next(<any>movedItems);
|
nodeActions.contentMoved.next(<any>movedItems);
|
||||||
|
|
||||||
expect(contentApi.restoreNode).toHaveBeenCalled();
|
expect(contentApi.restoreNode).toHaveBeenCalled();
|
||||||
expect(snackBar.open['calls'].argsFor(0)[0]).toBe('APP.MESSAGES.INFO.NODE_MOVE.SINGULAR');
|
expect(snackBar.open['calls'].argsFor(0)[0]).toBe(
|
||||||
|
'APP.MESSAGES.INFO.NODE_MOVE.SINGULAR'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should notify when error occurs on Undo Move action', fakeAsync(done => {
|
it('should notify when error occurs on Undo Move action', fakeAsync(done => {
|
||||||
@@ -609,11 +765,23 @@ describe('ContentManagementService', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const initialParent = 'parent-id-0';
|
const initialParent = 'parent-id-0';
|
||||||
const node = { entry: { id: 'node-to-move-id', name: 'conflicting-name', parentId: initialParent } };
|
const node = {
|
||||||
|
entry: {
|
||||||
|
id: 'node-to-move-id',
|
||||||
|
name: 'conflicting-name',
|
||||||
|
parentId: initialParent
|
||||||
|
}
|
||||||
|
};
|
||||||
const selection = [node];
|
const selection = [node];
|
||||||
|
|
||||||
const afterMoveParentId = 'parent-id-1';
|
const afterMoveParentId = 'parent-id-1';
|
||||||
const childMoved = { entry: { id: 'child-of-node-to-move-id', name: 'child-name', parentId: afterMoveParentId } };
|
const childMoved = {
|
||||||
|
entry: {
|
||||||
|
id: 'child-of-node-to-move-id',
|
||||||
|
name: 'child-name',
|
||||||
|
parentId: afterMoveParentId
|
||||||
|
}
|
||||||
|
};
|
||||||
nodeActions.moveDeletedEntries = [node]; // folder got deleted
|
nodeActions.moveDeletedEntries = [node]; // folder got deleted
|
||||||
|
|
||||||
const movedItems = {
|
const movedItems = {
|
||||||
@@ -629,7 +797,9 @@ describe('ContentManagementService', () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should notify when some error of type Error occurs on Undo Move action', fakeAsync(done => {
|
it('should notify when some error of type Error occurs on Undo Move action', fakeAsync(done => {
|
||||||
spyOn(contentApi, 'restoreNode').and.returnValue(throwError(new Error('oops!')));
|
spyOn(contentApi, 'restoreNode').and.returnValue(
|
||||||
|
throwError(new Error('oops!'))
|
||||||
|
);
|
||||||
|
|
||||||
actions$.pipe(
|
actions$.pipe(
|
||||||
ofType<SnackbarErrorAction>(SNACKBAR_ERROR),
|
ofType<SnackbarErrorAction>(SNACKBAR_ERROR),
|
||||||
@@ -637,10 +807,14 @@ describe('ContentManagementService', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const initialParent = 'parent-id-0';
|
const initialParent = 'parent-id-0';
|
||||||
const node = { entry: { id: 'node-to-move-id', name: 'name', parentId: initialParent } };
|
const node = {
|
||||||
|
entry: { id: 'node-to-move-id', name: 'name', parentId: initialParent }
|
||||||
|
};
|
||||||
const selection = [node];
|
const selection = [node];
|
||||||
|
|
||||||
const childMoved = { entry: { id: 'child-of-node-to-move-id', name: 'child-name' } };
|
const childMoved = {
|
||||||
|
entry: { id: 'child-of-node-to-move-id', name: 'child-name' }
|
||||||
|
};
|
||||||
nodeActions.moveDeletedEntries = [node]; // folder got deleted
|
nodeActions.moveDeletedEntries = [node]; // folder got deleted
|
||||||
|
|
||||||
const movedItems = {
|
const movedItems = {
|
||||||
@@ -656,7 +830,9 @@ describe('ContentManagementService', () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should notify permission error when it occurs on Undo Move action', fakeAsync(done => {
|
it('should notify permission error when it occurs on Undo Move action', fakeAsync(done => {
|
||||||
spyOn(contentApi, 'restoreNode').and.returnValue(throwError(new Error(JSON.stringify({error: {statusCode: 403}}))));
|
spyOn(contentApi, 'restoreNode').and.returnValue(
|
||||||
|
throwError(new Error(JSON.stringify({ error: { statusCode: 403 } })))
|
||||||
|
);
|
||||||
|
|
||||||
actions$.pipe(
|
actions$.pipe(
|
||||||
ofType<SnackbarErrorAction>(SNACKBAR_ERROR),
|
ofType<SnackbarErrorAction>(SNACKBAR_ERROR),
|
||||||
@@ -664,10 +840,14 @@ describe('ContentManagementService', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const initialParent = 'parent-id-0';
|
const initialParent = 'parent-id-0';
|
||||||
const node = { entry: { id: 'node-to-move-id', name: 'name', parentId: initialParent } };
|
const node = {
|
||||||
|
entry: { id: 'node-to-move-id', name: 'name', parentId: initialParent }
|
||||||
|
};
|
||||||
const selection = [node];
|
const selection = [node];
|
||||||
|
|
||||||
const childMoved = { entry: { id: 'child-of-node-to-move-id', name: 'child-name' } };
|
const childMoved = {
|
||||||
|
entry: { id: 'child-of-node-to-move-id', name: 'child-name' }
|
||||||
|
};
|
||||||
nodeActions.moveDeletedEntries = [node]; // folder got deleted
|
nodeActions.moveDeletedEntries = [node]; // folder got deleted
|
||||||
|
|
||||||
const movedItems = {
|
const movedItems = {
|
||||||
@@ -752,7 +932,7 @@ describe('ContentManagementService', () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should raise warning message when only one file is successful', fakeAsync(done => {
|
it('should raise warning message when only one file is successful', fakeAsync(done => {
|
||||||
spyOn(contentApi, 'deleteNode').and.callFake((id) => {
|
spyOn(contentApi, 'deleteNode').and.callFake(id => {
|
||||||
if (id === '1') {
|
if (id === '1') {
|
||||||
return throwError(null);
|
return throwError(null);
|
||||||
} else {
|
} else {
|
||||||
@@ -776,7 +956,7 @@ describe('ContentManagementService', () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should raise warning message when some files are successfully deleted', fakeAsync(done => {
|
it('should raise warning message when some files are successfully deleted', fakeAsync(done => {
|
||||||
spyOn(contentApi, 'deleteNode').and.callFake((id) => {
|
spyOn(contentApi, 'deleteNode').and.callFake(id => {
|
||||||
if (id === '1') {
|
if (id === '1') {
|
||||||
return throwError(null);
|
return throwError(null);
|
||||||
}
|
}
|
||||||
@@ -807,7 +987,6 @@ describe('ContentManagementService', () => {
|
|||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
describe('Permanent Delete', () => {
|
describe('Permanent Delete', () => {
|
||||||
it('does not purge nodes if no selection', () => {
|
it('does not purge nodes if no selection', () => {
|
||||||
spyOn(contentApi, 'purgeDeletedNode');
|
spyOn(contentApi, 'purgeDeletedNode');
|
||||||
@@ -834,7 +1013,7 @@ describe('ContentManagementService', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
spyOn(contentApi, 'purgeDeletedNode').and.callFake((id) => {
|
spyOn(contentApi, 'purgeDeletedNode').and.callFake(id => {
|
||||||
if (id === '1') {
|
if (id === '1') {
|
||||||
return of({});
|
return of({});
|
||||||
}
|
}
|
||||||
@@ -865,7 +1044,7 @@ describe('ContentManagementService', () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
spyOn(contentApi, 'purgeDeletedNode').and.callFake((id) => {
|
spyOn(contentApi, 'purgeDeletedNode').and.callFake(id => {
|
||||||
if (id === '1') {
|
if (id === '1') {
|
||||||
return of({});
|
return of({});
|
||||||
}
|
}
|
||||||
@@ -903,9 +1082,7 @@ describe('ContentManagementService', () => {
|
|||||||
|
|
||||||
spyOn(contentApi, 'purgeDeletedNode').and.returnValue(of({}));
|
spyOn(contentApi, 'purgeDeletedNode').and.returnValue(of({}));
|
||||||
|
|
||||||
const selection = [
|
const selection = [{ entry: { id: '1', name: 'name1' } }];
|
||||||
{ entry: { id: '1', name: 'name1' } }
|
|
||||||
];
|
|
||||||
|
|
||||||
store.dispatch(new PurgeDeletedNodesAction(selection));
|
store.dispatch(new PurgeDeletedNodesAction(selection));
|
||||||
}));
|
}));
|
||||||
@@ -920,9 +1097,7 @@ describe('ContentManagementService', () => {
|
|||||||
|
|
||||||
spyOn(contentApi, 'purgeDeletedNode').and.returnValue(throwError({}));
|
spyOn(contentApi, 'purgeDeletedNode').and.returnValue(throwError({}));
|
||||||
|
|
||||||
const selection = [
|
const selection = [{ entry: { id: '1', name: 'name1' } }];
|
||||||
{ entry: { id: '1', name: 'name1' } }
|
|
||||||
];
|
|
||||||
|
|
||||||
store.dispatch(new PurgeDeletedNodesAction(selection));
|
store.dispatch(new PurgeDeletedNodesAction(selection));
|
||||||
}));
|
}));
|
||||||
@@ -934,7 +1109,7 @@ describe('ContentManagementService', () => {
|
|||||||
done();
|
done();
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
spyOn(contentApi, 'purgeDeletedNode').and.callFake((id) => {
|
spyOn(contentApi, 'purgeDeletedNode').and.callFake(id => {
|
||||||
if (id === '1') {
|
if (id === '1') {
|
||||||
return of({});
|
return of({});
|
||||||
}
|
}
|
||||||
@@ -959,7 +1134,7 @@ describe('ContentManagementService', () => {
|
|||||||
done();
|
done();
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
spyOn(contentApi, 'purgeDeletedNode').and.callFake((id) => {
|
spyOn(contentApi, 'purgeDeletedNode').and.callFake(id => {
|
||||||
if (id === '1') {
|
if (id === '1') {
|
||||||
return throwError({});
|
return throwError({});
|
||||||
}
|
}
|
||||||
@@ -1001,9 +1176,11 @@ describe('ContentManagementService', () => {
|
|||||||
|
|
||||||
it('call restore nodes if selection has nodes with path', fakeAsync(() => {
|
it('call restore nodes if selection has nodes with path', fakeAsync(() => {
|
||||||
spyOn(contentApi, 'restoreNode').and.returnValue(of({}));
|
spyOn(contentApi, 'restoreNode').and.returnValue(of({}));
|
||||||
spyOn(contentApi, 'getDeletedNodes').and.returnValue(of({
|
spyOn(contentApi, 'getDeletedNodes').and.returnValue(
|
||||||
|
of({
|
||||||
list: { entries: [] }
|
list: { entries: [] }
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
|
|
||||||
const path = {
|
const path = {
|
||||||
elements: [
|
elements: [
|
||||||
@@ -1031,9 +1208,11 @@ describe('ContentManagementService', () => {
|
|||||||
describe('refresh()', () => {
|
describe('refresh()', () => {
|
||||||
it('dispatch event on finish', fakeAsync(done => {
|
it('dispatch event on finish', fakeAsync(done => {
|
||||||
spyOn(contentApi, 'restoreNode').and.returnValue(of({}));
|
spyOn(contentApi, 'restoreNode').and.returnValue(of({}));
|
||||||
spyOn(contentApi, 'getDeletedNodes').and.returnValue(of({
|
spyOn(contentApi, 'getDeletedNodes').and.returnValue(
|
||||||
|
of({
|
||||||
list: { entries: [] }
|
list: { entries: [] }
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
|
|
||||||
const path = {
|
const path = {
|
||||||
elements: [
|
elements: [
|
||||||
@@ -1061,9 +1240,11 @@ describe('ContentManagementService', () => {
|
|||||||
|
|
||||||
describe('notification', () => {
|
describe('notification', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
spyOn(contentApi, 'getDeletedNodes').and.returnValue(of({
|
spyOn(contentApi, 'getDeletedNodes').and.returnValue(
|
||||||
|
of({
|
||||||
list: { entries: [] }
|
list: { entries: [] }
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should raise error message on partial multiple fail ', fakeAsync(done => {
|
it('should raise error message on partial multiple fail ', fakeAsync(done => {
|
||||||
@@ -1074,7 +1255,7 @@ describe('ContentManagementService', () => {
|
|||||||
map(action => done())
|
map(action => done())
|
||||||
);
|
);
|
||||||
|
|
||||||
spyOn(contentApi, 'restoreNode').and.callFake((id) => {
|
spyOn(contentApi, 'restoreNode').and.callFake(id => {
|
||||||
if (id === '1') {
|
if (id === '1') {
|
||||||
return of({});
|
return of({});
|
||||||
}
|
}
|
||||||
@@ -1124,9 +1305,7 @@ describe('ContentManagementService', () => {
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
const selection = [
|
const selection = [{ entry: { id: '1', name: 'name1', path } }];
|
||||||
{ entry: { id: '1', name: 'name1', path } }
|
|
||||||
];
|
|
||||||
|
|
||||||
store.dispatch(new RestoreDeletedNodesAction(selection));
|
store.dispatch(new RestoreDeletedNodesAction(selection));
|
||||||
}));
|
}));
|
||||||
@@ -1150,9 +1329,7 @@ describe('ContentManagementService', () => {
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
const selection = [
|
const selection = [{ entry: { id: '1', name: 'name1', path } }];
|
||||||
{ entry: { id: '1', name: 'name1', path } }
|
|
||||||
];
|
|
||||||
|
|
||||||
store.dispatch(new RestoreDeletedNodesAction(selection));
|
store.dispatch(new RestoreDeletedNodesAction(selection));
|
||||||
}));
|
}));
|
||||||
@@ -1176,15 +1353,13 @@ describe('ContentManagementService', () => {
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
const selection = [
|
const selection = [{ entry: { id: '1', name: 'name1', path } }];
|
||||||
{ entry: { id: '1', name: 'name1', path } }
|
|
||||||
];
|
|
||||||
|
|
||||||
store.dispatch(new RestoreDeletedNodesAction(selection));
|
store.dispatch(new RestoreDeletedNodesAction(selection));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should raise info message when restore multiple nodes', fakeAsync(done => {
|
it('should raise info message when restore multiple nodes', fakeAsync(done => {
|
||||||
spyOn(contentApi, 'restoreNode').and.callFake((id) => {
|
spyOn(contentApi, 'restoreNode').and.callFake(id => {
|
||||||
if (id === '1') {
|
if (id === '1') {
|
||||||
return of({});
|
return of({});
|
||||||
}
|
}
|
||||||
@@ -1233,9 +1408,7 @@ describe('ContentManagementService', () => {
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
const selection = [
|
const selection = [{ entry: { id: '1', name: 'name1', path } }];
|
||||||
{ entry: { id: '1', name: 'name1', path } }
|
|
||||||
];
|
|
||||||
|
|
||||||
store.dispatch(new RestoreDeletedNodesAction(selection));
|
store.dispatch(new RestoreDeletedNodesAction(selection));
|
||||||
}));
|
}));
|
||||||
@@ -1271,5 +1444,4 @@ describe('ContentManagementService', () => {
|
|||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@@ -26,10 +26,22 @@
|
|||||||
import { Subject, Observable, forkJoin, of, zip } from 'rxjs';
|
import { Subject, Observable, forkJoin, of, zip } from 'rxjs';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { MatDialog, MatSnackBar } from '@angular/material';
|
import { MatDialog, MatSnackBar } from '@angular/material';
|
||||||
import { FolderDialogComponent, ConfirmDialogComponent, ShareDialogComponent } from '@alfresco/adf-content-services';
|
import {
|
||||||
|
FolderDialogComponent,
|
||||||
|
ConfirmDialogComponent,
|
||||||
|
ShareDialogComponent
|
||||||
|
} from '@alfresco/adf-content-services';
|
||||||
import { LibraryDialogComponent } from '../dialogs/library/library.dialog';
|
import { LibraryDialogComponent } from '../dialogs/library/library.dialog';
|
||||||
import { SnackbarErrorAction, SnackbarInfoAction, SnackbarAction, SnackbarWarningAction,
|
import {
|
||||||
NavigateRouteAction, SnackbarUserAction, UndoDeleteNodesAction, SetSelectedNodesAction } from '../store/actions';
|
SnackbarErrorAction,
|
||||||
|
SnackbarInfoAction,
|
||||||
|
SnackbarAction,
|
||||||
|
SnackbarWarningAction,
|
||||||
|
NavigateRouteAction,
|
||||||
|
SnackbarUserAction,
|
||||||
|
UndoDeleteNodesAction,
|
||||||
|
SetSelectedNodesAction
|
||||||
|
} from '../store/actions';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { AppStore } from '../store/states';
|
import { AppStore } from '../store/states';
|
||||||
import {
|
import {
|
||||||
@@ -133,12 +145,9 @@ export class ContentManagementService {
|
|||||||
const id = node.entry.nodeId || (<any>node).entry.guid;
|
const id = node.entry.nodeId || (<any>node).entry.guid;
|
||||||
|
|
||||||
if (id) {
|
if (id) {
|
||||||
this.contentApi
|
this.contentApi.getNodeInfo(id).subscribe(entry => {
|
||||||
.getNodeInfo(id)
|
|
||||||
.subscribe(entry => {
|
|
||||||
this.openVersionManagerDialog(entry);
|
this.openVersionManagerDialog(entry);
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
this.openVersionManagerDialog(node.entry);
|
this.openVersionManagerDialog(node.entry);
|
||||||
}
|
}
|
||||||
@@ -162,7 +171,6 @@ export class ContentManagementService {
|
|||||||
|
|
||||||
shareNode(node: MinimalNodeEntity): void {
|
shareNode(node: MinimalNodeEntity): void {
|
||||||
if (node && node.entry && node.entry.isFile) {
|
if (node && node.entry && node.entry.isFile) {
|
||||||
|
|
||||||
this.store
|
this.store
|
||||||
.select(sharedUrl)
|
.select(sharedUrl)
|
||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
@@ -244,23 +252,21 @@ export class ContentManagementService {
|
|||||||
() => {
|
() => {
|
||||||
this.libraryDeleted.next(id);
|
this.libraryDeleted.next(id);
|
||||||
this.store.dispatch(
|
this.store.dispatch(
|
||||||
new SnackbarInfoAction(
|
new SnackbarInfoAction('APP.MESSAGES.INFO.LIBRARY_DELETED')
|
||||||
'APP.MESSAGES.INFO.LIBRARY_DELETED'
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
this.store.dispatch(
|
this.store.dispatch(
|
||||||
new SnackbarErrorAction(
|
new SnackbarErrorAction('APP.MESSAGES.ERRORS.DELETE_LIBRARY_FAILED')
|
||||||
'APP.MESSAGES.ERRORS.DELETE_LIBRARY_FAILED'
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async unshareNodes(links: Array<MinimalNodeEntity>) {
|
async unshareNodes(links: Array<MinimalNodeEntity>) {
|
||||||
const promises = links.map(link => this.contentApi.deleteSharedLink(link.entry.id).toPromise());
|
const promises = links.map(link =>
|
||||||
|
this.contentApi.deleteSharedLink(link.entry.id).toPromise()
|
||||||
|
);
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
this.linksUnshared.next();
|
this.linksUnshared.next();
|
||||||
}
|
}
|
||||||
@@ -330,10 +336,7 @@ export class ContentManagementService {
|
|||||||
)
|
)
|
||||||
.subscribe((nodes: DeletedNodesPaging) => {
|
.subscribe((nodes: DeletedNodesPaging) => {
|
||||||
const selectedNodes = this.diff(status.fail, selection, false);
|
const selectedNodes = this.diff(status.fail, selection, false);
|
||||||
const remainingNodes = this.diff(
|
const remainingNodes = this.diff(selectedNodes, nodes.list.entries);
|
||||||
selectedNodes,
|
|
||||||
nodes.list.entries
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!remainingNodes.length) {
|
if (!remainingNodes.length) {
|
||||||
this.showRestoreNotification(status);
|
this.showRestoreNotification(status);
|
||||||
@@ -376,16 +379,13 @@ export class ContentManagementService {
|
|||||||
if (failedItems) {
|
if (failedItems) {
|
||||||
if (numberOfCopiedItems) {
|
if (numberOfCopiedItems) {
|
||||||
i18MessageSuffix =
|
i18MessageSuffix =
|
||||||
numberOfCopiedItems === 1
|
numberOfCopiedItems === 1 ? 'PARTIAL_SINGULAR' : 'PARTIAL_PLURAL';
|
||||||
? 'PARTIAL_SINGULAR'
|
|
||||||
: 'PARTIAL_PLURAL';
|
|
||||||
} else {
|
} else {
|
||||||
i18MessageSuffix =
|
i18MessageSuffix =
|
||||||
failedItems === 1 ? 'FAIL_SINGULAR' : 'FAIL_PLURAL';
|
failedItems === 1 ? 'FAIL_SINGULAR' : 'FAIL_PLURAL';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
i18MessageSuffix =
|
i18MessageSuffix = numberOfCopiedItems === 1 ? 'SINGULAR' : 'PLURAL';
|
||||||
numberOfCopiedItems === 1 ? 'SINGULAR' : 'PLURAL';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
i18nMessageString = `APP.MESSAGES.INFO.NODE_COPY.${i18MessageSuffix}`;
|
i18nMessageString = `APP.MESSAGES.INFO.NODE_COPY.${i18MessageSuffix}`;
|
||||||
@@ -461,47 +461,63 @@ export class ContentManagementService {
|
|||||||
this.nodeActionsService.moveNodes(nodes, permissionForMove),
|
this.nodeActionsService.moveNodes(nodes, permissionForMove),
|
||||||
this.nodeActionsService.contentMoved
|
this.nodeActionsService.contentMoved
|
||||||
).subscribe(
|
).subscribe(
|
||||||
(result) => {
|
result => {
|
||||||
const [operationResult, moveResponse] = result;
|
const [operationResult, moveResponse] = result;
|
||||||
this.showMoveMessage(nodes, operationResult, moveResponse);
|
this.showMoveMessage(nodes, operationResult, moveResponse);
|
||||||
|
|
||||||
this.nodesMoved.next(null);
|
this.nodesMoved.next(null);
|
||||||
},
|
},
|
||||||
(error) => {
|
error => {
|
||||||
this.showMoveMessage(nodes, error);
|
this.showMoveMessage(nodes, error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private undoMoveNodes(moveResponse, selectionParentId) {
|
private undoMoveNodes(moveResponse, selectionParentId) {
|
||||||
const movedNodes = (moveResponse && moveResponse['succeeded']) ? moveResponse['succeeded'] : [];
|
const movedNodes =
|
||||||
const partiallyMovedNodes = (moveResponse && moveResponse['partiallySucceeded']) ? moveResponse['partiallySucceeded'] : [];
|
moveResponse && moveResponse['succeeded']
|
||||||
|
? moveResponse['succeeded']
|
||||||
|
: [];
|
||||||
|
const partiallyMovedNodes =
|
||||||
|
moveResponse && moveResponse['partiallySucceeded']
|
||||||
|
? moveResponse['partiallySucceeded']
|
||||||
|
: [];
|
||||||
|
|
||||||
const restoreDeletedNodesBatch = this.nodeActionsService.moveDeletedEntries
|
const restoreDeletedNodesBatch = this.nodeActionsService.moveDeletedEntries.map(
|
||||||
.map((folderEntry) => {
|
folderEntry => {
|
||||||
return this.contentApi
|
return this.contentApi
|
||||||
.restoreNode(folderEntry.nodeId || folderEntry.id)
|
.restoreNode(folderEntry.nodeId || folderEntry.id)
|
||||||
.pipe(map(node => node.entry));
|
.pipe(map(node => node.entry));
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
zip(...restoreDeletedNodesBatch, of(null))
|
zip(...restoreDeletedNodesBatch, of(null))
|
||||||
.pipe(mergeMap(() => {
|
.pipe(
|
||||||
|
mergeMap(() => {
|
||||||
const nodesToBeMovedBack = [...partiallyMovedNodes, ...movedNodes];
|
const nodesToBeMovedBack = [...partiallyMovedNodes, ...movedNodes];
|
||||||
|
|
||||||
const revertMoveBatch = this.nodeActionsService
|
const revertMoveBatch = this.nodeActionsService
|
||||||
.flatten(nodesToBeMovedBack)
|
.flatten(nodesToBeMovedBack)
|
||||||
.filter(node => node.entry || (node.itemMoved && node.itemMoved.entry))
|
.filter(
|
||||||
.map((node) => {
|
node => node.entry || (node.itemMoved && node.itemMoved.entry)
|
||||||
|
)
|
||||||
|
.map(node => {
|
||||||
if (node.itemMoved) {
|
if (node.itemMoved) {
|
||||||
return this.nodeActionsService.moveNodeAction(node.itemMoved.entry, node.initialParentId);
|
return this.nodeActionsService.moveNodeAction(
|
||||||
|
node.itemMoved.entry,
|
||||||
|
node.initialParentId
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
return this.nodeActionsService.moveNodeAction(node.entry, selectionParentId);
|
return this.nodeActionsService.moveNodeAction(
|
||||||
|
node.entry,
|
||||||
|
selectionParentId
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return zip(...revertMoveBatch, of(null));
|
return zip(...revertMoveBatch, of(null));
|
||||||
}))
|
})
|
||||||
|
)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
() => {
|
() => {
|
||||||
this.nodesMoved.next(null);
|
this.nodesMoved.next(null);
|
||||||
@@ -514,7 +530,11 @@ export class ContentManagementService {
|
|||||||
errorJson = JSON.parse(error.message);
|
errorJson = JSON.parse(error.message);
|
||||||
} catch {}
|
} catch {}
|
||||||
|
|
||||||
if (errorJson && errorJson.error && errorJson.error.statusCode === 403) {
|
if (
|
||||||
|
errorJson &&
|
||||||
|
errorJson.error &&
|
||||||
|
errorJson.error.statusCode === 403
|
||||||
|
) {
|
||||||
message = 'APP.MESSAGES.ERRORS.PERMISSION';
|
message = 'APP.MESSAGES.ERRORS.PERMISSION';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -574,9 +594,7 @@ export class ContentManagementService {
|
|||||||
private undoDeleteNode(item: DeletedNodeInfo): Observable<DeletedNodeInfo> {
|
private undoDeleteNode(item: DeletedNodeInfo): Observable<DeletedNodeInfo> {
|
||||||
const { id, name } = item;
|
const { id, name } = item;
|
||||||
|
|
||||||
return this.contentApi
|
return this.contentApi.restoreNode(id).pipe(
|
||||||
.restoreNode(id)
|
|
||||||
.pipe(
|
|
||||||
map(() => {
|
map(() => {
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
@@ -614,8 +632,7 @@ export class ContentManagementService {
|
|||||||
private restoreNode(node: MinimalNodeEntity): Observable<RestoredNode> {
|
private restoreNode(node: MinimalNodeEntity): Observable<RestoredNode> {
|
||||||
const { entry } = node;
|
const { entry } = node;
|
||||||
|
|
||||||
return this.contentApi.restoreNode(entry.id)
|
return this.contentApi.restoreNode(entry.id).pipe(
|
||||||
.pipe(
|
|
||||||
map(() => ({
|
map(() => ({
|
||||||
status: 1,
|
status: 1,
|
||||||
entry
|
entry
|
||||||
@@ -655,9 +672,7 @@ export class ContentManagementService {
|
|||||||
private purgeDeletedNode(node: NodeInfo): Observable<DeletedNodeInfo> {
|
private purgeDeletedNode(node: NodeInfo): Observable<DeletedNodeInfo> {
|
||||||
const { id, name } = node;
|
const { id, name } = node;
|
||||||
|
|
||||||
return this.contentApi
|
return this.contentApi.purgeDeletedNode(id).pipe(
|
||||||
.purgeDeletedNode(id)
|
|
||||||
.pipe(
|
|
||||||
map(() => ({
|
map(() => ({
|
||||||
status: 1,
|
status: 1,
|
||||||
id,
|
id,
|
||||||
@@ -851,10 +866,7 @@ export class ContentManagementService {
|
|||||||
const { name } = node.entry;
|
const { name } = node.entry;
|
||||||
const id = node.entry.nodeId || node.entry.id;
|
const id = node.entry.nodeId || node.entry.id;
|
||||||
|
|
||||||
|
return this.contentApi.deleteNode(id).pipe(
|
||||||
return this.contentApi
|
|
||||||
.deleteNode(id)
|
|
||||||
.pipe(
|
|
||||||
map(() => {
|
map(() => {
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
@@ -881,10 +893,9 @@ export class ContentManagementService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (status.allSucceeded && !status.oneSucceeded) {
|
if (status.allSucceeded && !status.oneSucceeded) {
|
||||||
return new SnackbarInfoAction(
|
return new SnackbarInfoAction('APP.MESSAGES.INFO.NODE_DELETION.PLURAL', {
|
||||||
'APP.MESSAGES.INFO.NODE_DELETION.PLURAL',
|
number: status.success.length
|
||||||
{ number: status.success.length }
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status.someFailed && status.someSucceeded && !status.oneSucceeded) {
|
if (status.someFailed && status.someSucceeded && !status.oneSucceeded) {
|
||||||
@@ -908,10 +919,9 @@ export class ContentManagementService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (status.oneFailed && !status.someSucceeded) {
|
if (status.oneFailed && !status.someSucceeded) {
|
||||||
return new SnackbarErrorAction(
|
return new SnackbarErrorAction('APP.MESSAGES.ERRORS.NODE_DELETION', {
|
||||||
'APP.MESSAGES.ERRORS.NODE_DELETION',
|
name: status.fail[0].name
|
||||||
{ name: status.fail[0].name }
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status.oneSucceeded && !status.someFailed) {
|
if (status.oneSucceeded && !status.someFailed) {
|
||||||
@@ -924,10 +934,23 @@ export class ContentManagementService {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private showMoveMessage(nodes: Array<MinimalNodeEntity>, info: any, moveResponse?: any) {
|
private showMoveMessage(
|
||||||
const succeeded = (moveResponse && moveResponse['succeeded']) ? moveResponse['succeeded'].length : 0;
|
nodes: Array<MinimalNodeEntity>,
|
||||||
const partiallySucceeded = (moveResponse && moveResponse['partiallySucceeded']) ? moveResponse['partiallySucceeded'].length : 0;
|
info: any,
|
||||||
const failures = (moveResponse && moveResponse['failed']) ? moveResponse['failed'].length : 0;
|
moveResponse?: any
|
||||||
|
) {
|
||||||
|
const succeeded =
|
||||||
|
moveResponse && moveResponse['succeeded']
|
||||||
|
? moveResponse['succeeded'].length
|
||||||
|
: 0;
|
||||||
|
const partiallySucceeded =
|
||||||
|
moveResponse && moveResponse['partiallySucceeded']
|
||||||
|
? moveResponse['partiallySucceeded'].length
|
||||||
|
: 0;
|
||||||
|
const failures =
|
||||||
|
moveResponse && moveResponse['failed']
|
||||||
|
? moveResponse['failed'].length
|
||||||
|
: 0;
|
||||||
|
|
||||||
let successMessage = '';
|
let successMessage = '';
|
||||||
let partialSuccessMessage = '';
|
let partialSuccessMessage = '';
|
||||||
@@ -935,28 +958,29 @@ export class ContentManagementService {
|
|||||||
let errorMessage = '';
|
let errorMessage = '';
|
||||||
|
|
||||||
if (typeof info === 'string') {
|
if (typeof info === 'string') {
|
||||||
|
|
||||||
// in case of success
|
// in case of success
|
||||||
if (info.toLowerCase().indexOf('succes') !== -1) {
|
if (info.toLowerCase().indexOf('succes') !== -1) {
|
||||||
const i18nMessageString = 'APP.MESSAGES.INFO.NODE_MOVE.';
|
const i18nMessageString = 'APP.MESSAGES.INFO.NODE_MOVE.';
|
||||||
let i18MessageSuffix = '';
|
let i18MessageSuffix = '';
|
||||||
|
|
||||||
if (succeeded) {
|
if (succeeded) {
|
||||||
i18MessageSuffix = ( succeeded === 1 ) ? 'SINGULAR' : 'PLURAL';
|
i18MessageSuffix = succeeded === 1 ? 'SINGULAR' : 'PLURAL';
|
||||||
successMessage = `${i18nMessageString}${i18MessageSuffix}`;
|
successMessage = `${i18nMessageString}${i18MessageSuffix}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (partiallySucceeded) {
|
if (partiallySucceeded) {
|
||||||
i18MessageSuffix = ( partiallySucceeded === 1 ) ? 'PARTIAL.SINGULAR' : 'PARTIAL.PLURAL';
|
i18MessageSuffix =
|
||||||
|
partiallySucceeded === 1 ? 'PARTIAL.SINGULAR' : 'PARTIAL.PLURAL';
|
||||||
partialSuccessMessage = `${i18nMessageString}${i18MessageSuffix}`;
|
partialSuccessMessage = `${i18nMessageString}${i18MessageSuffix}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (failures) {
|
if (failures) {
|
||||||
// if moving failed for ALL nodes, emit error
|
// if moving failed for ALL nodes, emit error
|
||||||
if (failures === nodes.length) {
|
if (failures === nodes.length) {
|
||||||
const errors = this.nodeActionsService.flatten(moveResponse['failed']);
|
const errors = this.nodeActionsService.flatten(
|
||||||
|
moveResponse['failed']
|
||||||
|
);
|
||||||
errorMessage = this.getErrorMessage(errors[0]);
|
errorMessage = this.getErrorMessage(errors[0]);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
i18MessageSuffix = 'PARTIAL.FAIL';
|
i18MessageSuffix = 'PARTIAL.FAIL';
|
||||||
failedMessage = `${i18nMessageString}${i18MessageSuffix}`;
|
failedMessage = `${i18nMessageString}${i18MessageSuffix}`;
|
||||||
@@ -965,18 +989,24 @@ export class ContentManagementService {
|
|||||||
} else {
|
} else {
|
||||||
errorMessage = 'APP.MESSAGES.ERRORS.GENERIC';
|
errorMessage = 'APP.MESSAGES.ERRORS.GENERIC';
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
errorMessage = this.getErrorMessage(info);
|
errorMessage = this.getErrorMessage(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
const undo = (succeeded + partiallySucceeded > 0) ? this.translation.instant('APP.ACTIONS.UNDO') : '';
|
const undo =
|
||||||
|
succeeded + partiallySucceeded > 0
|
||||||
|
? this.translation.instant('APP.ACTIONS.UNDO')
|
||||||
|
: '';
|
||||||
failedMessage = errorMessage ? errorMessage : failedMessage;
|
failedMessage = errorMessage ? errorMessage : failedMessage;
|
||||||
|
|
||||||
const beforePartialSuccessMessage = (successMessage && partialSuccessMessage) ? ' ' : '';
|
const beforePartialSuccessMessage =
|
||||||
const beforeFailedMessage = ((successMessage || partialSuccessMessage) && failedMessage) ? ' ' : '';
|
successMessage && partialSuccessMessage ? ' ' : '';
|
||||||
|
const beforeFailedMessage =
|
||||||
|
(successMessage || partialSuccessMessage) && failedMessage ? ' ' : '';
|
||||||
|
|
||||||
const initialParentId = this.nodeActionsService.getEntryParentId(nodes[0].entry);
|
const initialParentId = this.nodeActionsService.getEntryParentId(
|
||||||
|
nodes[0].entry
|
||||||
|
);
|
||||||
|
|
||||||
const messages = this.translation.instant(
|
const messages = this.translation.instant(
|
||||||
[successMessage, partialSuccessMessage, failedMessage],
|
[successMessage, partialSuccessMessage, failedMessage],
|
||||||
@@ -986,13 +1016,17 @@ export class ContentManagementService {
|
|||||||
// TODO: review in terms of i18n
|
// TODO: review in terms of i18n
|
||||||
this.snackBar
|
this.snackBar
|
||||||
.open(
|
.open(
|
||||||
messages[successMessage]
|
messages[successMessage] +
|
||||||
+ beforePartialSuccessMessage + messages[partialSuccessMessage]
|
beforePartialSuccessMessage +
|
||||||
+ beforeFailedMessage + messages[failedMessage]
|
messages[partialSuccessMessage] +
|
||||||
, undo, {
|
beforeFailedMessage +
|
||||||
|
messages[failedMessage],
|
||||||
|
undo,
|
||||||
|
{
|
||||||
panelClass: 'info-snackbar',
|
panelClass: 'info-snackbar',
|
||||||
duration: 3000
|
duration: 3000
|
||||||
})
|
}
|
||||||
|
)
|
||||||
.onAction()
|
.onAction()
|
||||||
.subscribe(() => this.undoMoveNodes(moveResponse, initialParentId));
|
.subscribe(() => this.undoMoveNodes(moveResponse, initialParentId));
|
||||||
}
|
}
|
||||||
@@ -1001,16 +1035,18 @@ export class ContentManagementService {
|
|||||||
let i18nMessageString = 'APP.MESSAGES.ERRORS.GENERIC';
|
let i18nMessageString = 'APP.MESSAGES.ERRORS.GENERIC';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { error: { statusCode } } = JSON.parse(errorObject.message);
|
const {
|
||||||
|
error: { statusCode }
|
||||||
|
} = JSON.parse(errorObject.message);
|
||||||
|
|
||||||
if (statusCode === 409) {
|
if (statusCode === 409) {
|
||||||
i18nMessageString = 'APP.MESSAGES.ERRORS.NODE_MOVE';
|
i18nMessageString = 'APP.MESSAGES.ERRORS.NODE_MOVE';
|
||||||
|
|
||||||
} else if (statusCode === 403) {
|
} else if (statusCode === 403) {
|
||||||
i18nMessageString = 'APP.MESSAGES.ERRORS.PERMISSION';
|
i18nMessageString = 'APP.MESSAGES.ERRORS.PERMISSION';
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
} catch (err) { /* Do nothing, keep the original message */ }
|
/* Do nothing, keep the original message */
|
||||||
|
}
|
||||||
|
|
||||||
return i18nMessageString;
|
return i18nMessageString;
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -27,9 +27,22 @@ import { Injectable } from '@angular/core';
|
|||||||
import { MatDialog } from '@angular/material';
|
import { MatDialog } from '@angular/material';
|
||||||
import { Observable, Subject, of, zip, from } from 'rxjs';
|
import { Observable, Subject, of, zip, from } from 'rxjs';
|
||||||
|
|
||||||
import { AlfrescoApiService, ContentService, DataColumn, TranslationService } from '@alfresco/adf-core';
|
import {
|
||||||
import { DocumentListService, ContentNodeSelectorComponent, ContentNodeSelectorComponentData } from '@alfresco/adf-content-services';
|
AlfrescoApiService,
|
||||||
import { MinimalNodeEntity, MinimalNodeEntryEntity, SitePaging } from 'alfresco-js-api';
|
ContentService,
|
||||||
|
DataColumn,
|
||||||
|
TranslationService
|
||||||
|
} from '@alfresco/adf-core';
|
||||||
|
import {
|
||||||
|
DocumentListService,
|
||||||
|
ContentNodeSelectorComponent,
|
||||||
|
ContentNodeSelectorComponentData
|
||||||
|
} from '@alfresco/adf-content-services';
|
||||||
|
import {
|
||||||
|
MinimalNodeEntity,
|
||||||
|
MinimalNodeEntryEntity,
|
||||||
|
SitePaging
|
||||||
|
} from 'alfresco-js-api';
|
||||||
import { ContentApiService } from '../services/content-api.service';
|
import { ContentApiService } from '../services/content-api.service';
|
||||||
import { catchError, map, mergeMap } from 'rxjs/operators';
|
import { catchError, map, mergeMap } from 'rxjs/operators';
|
||||||
|
|
||||||
@@ -38,17 +51,21 @@ export class NodeActionsService {
|
|||||||
static SNACK_MESSAGE_DURATION_WITH_UNDO = 10000;
|
static SNACK_MESSAGE_DURATION_WITH_UNDO = 10000;
|
||||||
static SNACK_MESSAGE_DURATION = 3000;
|
static SNACK_MESSAGE_DURATION = 3000;
|
||||||
|
|
||||||
contentCopied: Subject<MinimalNodeEntity[]> = new Subject<MinimalNodeEntity[]>();
|
contentCopied: Subject<MinimalNodeEntity[]> = new Subject<
|
||||||
|
MinimalNodeEntity[]
|
||||||
|
>();
|
||||||
contentMoved: Subject<any> = new Subject<any>();
|
contentMoved: Subject<any> = new Subject<any>();
|
||||||
moveDeletedEntries: any[] = [];
|
moveDeletedEntries: any[] = [];
|
||||||
isSitesDestinationAvailable = false;
|
isSitesDestinationAvailable = false;
|
||||||
|
|
||||||
constructor(private contentService: ContentService,
|
constructor(
|
||||||
|
private contentService: ContentService,
|
||||||
private contentApi: ContentApiService,
|
private contentApi: ContentApiService,
|
||||||
private dialog: MatDialog,
|
private dialog: MatDialog,
|
||||||
private documentListService: DocumentListService,
|
private documentListService: DocumentListService,
|
||||||
private apiService: AlfrescoApiService,
|
private apiService: AlfrescoApiService,
|
||||||
private translation: TranslationService) {}
|
private translation: TranslationService
|
||||||
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy node list
|
* Copy node list
|
||||||
@@ -56,7 +73,10 @@ export class NodeActionsService {
|
|||||||
* @param contentEntities nodes to copy
|
* @param contentEntities nodes to copy
|
||||||
* @param permission permission which is needed to apply the action
|
* @param permission permission which is needed to apply the action
|
||||||
*/
|
*/
|
||||||
public copyNodes(contentEntities: any[], permission?: string): Subject<string> {
|
public copyNodes(
|
||||||
|
contentEntities: any[],
|
||||||
|
permission?: string
|
||||||
|
): Subject<string> {
|
||||||
return this.doBatchOperation('copy', contentEntities, permission);
|
return this.doBatchOperation('copy', contentEntities, permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +86,10 @@ export class NodeActionsService {
|
|||||||
* @param contentEntities nodes to move
|
* @param contentEntities nodes to move
|
||||||
* @param permission permission which is needed to apply the action
|
* @param permission permission which is needed to apply the action
|
||||||
*/
|
*/
|
||||||
public moveNodes(contentEntities: any[], permission?: string): Subject<string> {
|
public moveNodes(
|
||||||
|
contentEntities: any[],
|
||||||
|
permission?: string
|
||||||
|
): Subject<string> {
|
||||||
return this.doBatchOperation('move', contentEntities, permission);
|
return this.doBatchOperation('move', contentEntities, permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,17 +100,23 @@ export class NodeActionsService {
|
|||||||
* @param contentEntities the contentEntities which have to have the action performed on
|
* @param contentEntities the contentEntities which have to have the action performed on
|
||||||
* @param permission permission which is needed to apply the action
|
* @param permission permission which is needed to apply the action
|
||||||
*/
|
*/
|
||||||
doBatchOperation(action: string, contentEntities: any[], permission?: string): Subject<string> {
|
doBatchOperation(
|
||||||
|
action: string,
|
||||||
|
contentEntities: any[],
|
||||||
|
permission?: string
|
||||||
|
): Subject<string> {
|
||||||
const observable: Subject<string> = new Subject<string>();
|
const observable: Subject<string> = new Subject<string>();
|
||||||
|
|
||||||
if (!this.isEntryEntitiesArray(contentEntities)) {
|
if (!this.isEntryEntitiesArray(contentEntities)) {
|
||||||
observable.error(new Error(JSON.stringify({error: {statusCode: 400}})));
|
observable.error(
|
||||||
|
new Error(JSON.stringify({ error: { statusCode: 400 } }))
|
||||||
|
);
|
||||||
} else if (this.checkPermission(action, contentEntities, permission)) {
|
} else if (this.checkPermission(action, contentEntities, permission)) {
|
||||||
|
const destinationSelection = this.getContentNodeSelection(
|
||||||
const destinationSelection = this.getContentNodeSelection(action, contentEntities);
|
action,
|
||||||
|
contentEntities
|
||||||
|
);
|
||||||
destinationSelection.subscribe((selections: MinimalNodeEntryEntity[]) => {
|
destinationSelection.subscribe((selections: MinimalNodeEntryEntity[]) => {
|
||||||
|
|
||||||
const contentEntry = contentEntities[0].entry;
|
const contentEntry = contentEntities[0].entry;
|
||||||
// Check if there's nodeId for Shared Files
|
// Check if there's nodeId for Shared Files
|
||||||
const contentEntryId = contentEntry.nodeId || contentEntry.id;
|
const contentEntryId = contentEntry.nodeId || contentEntry.id;
|
||||||
@@ -98,35 +127,39 @@ export class NodeActionsService {
|
|||||||
const selection = selections[0];
|
const selection = selections[0];
|
||||||
let action$: Observable<any>;
|
let action$: Observable<any>;
|
||||||
|
|
||||||
if (action === 'move' && contentEntities.length === 1 && type === 'content') {
|
if (
|
||||||
action$ = this.documentListService.moveNode(contentEntryId, selection.id);
|
action === 'move' &&
|
||||||
|
contentEntities.length === 1 &&
|
||||||
|
type === 'content'
|
||||||
|
) {
|
||||||
|
action$ = this.documentListService.moveNode(
|
||||||
|
contentEntryId,
|
||||||
|
selection.id
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
contentEntities.forEach((node) => {
|
contentEntities.forEach(node => {
|
||||||
batch.push(this[`${action}NodeAction`](node.entry, selection.id));
|
batch.push(this[`${action}NodeAction`](node.entry, selection.id));
|
||||||
});
|
});
|
||||||
action$ = zip(...batch);
|
action$ = zip(...batch);
|
||||||
}
|
}
|
||||||
|
|
||||||
action$
|
action$.subscribe(newContent => {
|
||||||
.subscribe(
|
observable.next(
|
||||||
(newContent) => {
|
`OPERATION.SUCCES.${type.toUpperCase()}.${action.toUpperCase()}`
|
||||||
observable.next(`OPERATION.SUCCES.${type.toUpperCase()}.${action.toUpperCase()}`);
|
);
|
||||||
|
|
||||||
const processedData = this.processResponse(newContent);
|
const processedData = this.processResponse(newContent);
|
||||||
if (action === 'copy') {
|
if (action === 'copy') {
|
||||||
this.contentCopied.next(processedData.succeeded);
|
this.contentCopied.next(processedData.succeeded);
|
||||||
|
|
||||||
} else if (action === 'move') {
|
} else if (action === 'move') {
|
||||||
this.contentMoved.next(processedData);
|
this.contentMoved.next(processedData);
|
||||||
}
|
}
|
||||||
|
}, observable.error.bind(observable));
|
||||||
},
|
|
||||||
observable.error.bind(observable)
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
observable.error(new Error(JSON.stringify({error: {statusCode: 403}})));
|
observable.error(
|
||||||
|
new Error(JSON.stringify({ error: { statusCode: 403 } }))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return observable;
|
return observable;
|
||||||
@@ -134,14 +167,18 @@ export class NodeActionsService {
|
|||||||
|
|
||||||
isEntryEntitiesArray(contentEntities: any[]): boolean {
|
isEntryEntitiesArray(contentEntities: any[]): boolean {
|
||||||
if (contentEntities && contentEntities.length) {
|
if (contentEntities && contentEntities.length) {
|
||||||
const nonEntryNode = contentEntities.find(node => (!node || !node.entry || !(node.entry.nodeId || node.entry.id)));
|
const nonEntryNode = contentEntities.find(
|
||||||
|
node => !node || !node.entry || !(node.entry.nodeId || node.entry.id)
|
||||||
|
);
|
||||||
return !nonEntryNode;
|
return !nonEntryNode;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
checkPermission(action: string, contentEntities: any[], permission?: string) {
|
checkPermission(action: string, contentEntities: any[], permission?: string) {
|
||||||
const notAllowedNode = contentEntities.find(node => !this.isActionAllowed(action, node.entry, permission));
|
const notAllowedNode = contentEntities.find(
|
||||||
|
node => !this.isActionAllowed(action, node.entry, permission)
|
||||||
|
);
|
||||||
return !notAllowedNode;
|
return !notAllowedNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,16 +187,25 @@ export class NodeActionsService {
|
|||||||
|
|
||||||
if (nodeEntry.parentId) {
|
if (nodeEntry.parentId) {
|
||||||
entryParentId = nodeEntry.parentId;
|
entryParentId = nodeEntry.parentId;
|
||||||
|
} else if (
|
||||||
} else if (nodeEntry.path && nodeEntry.path.elements && nodeEntry.path.elements.length) {
|
nodeEntry.path &&
|
||||||
entryParentId = nodeEntry.path.elements[nodeEntry.path.elements.length - 1].id;
|
nodeEntry.path.elements &&
|
||||||
|
nodeEntry.path.elements.length
|
||||||
|
) {
|
||||||
|
entryParentId =
|
||||||
|
nodeEntry.path.elements[nodeEntry.path.elements.length - 1].id;
|
||||||
}
|
}
|
||||||
|
|
||||||
return entryParentId;
|
return entryParentId;
|
||||||
}
|
}
|
||||||
|
|
||||||
getContentNodeSelection(action: string, contentEntities: MinimalNodeEntity[]): Subject<MinimalNodeEntryEntity[]> {
|
getContentNodeSelection(
|
||||||
const currentParentFolderId = this.getEntryParentId(contentEntities[0].entry);
|
action: string,
|
||||||
|
contentEntities: MinimalNodeEntity[]
|
||||||
|
): Subject<MinimalNodeEntryEntity[]> {
|
||||||
|
const currentParentFolderId = this.getEntryParentId(
|
||||||
|
contentEntities[0].entry
|
||||||
|
);
|
||||||
|
|
||||||
const customDropdown: SitePaging = {
|
const customDropdown: SitePaging = {
|
||||||
list: {
|
list: {
|
||||||
@@ -219,7 +265,10 @@ export class NodeActionsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const number = nodes.length;
|
const number = nodes.length;
|
||||||
return this.translation.instant(`NODE_SELECTOR.${action.toUpperCase()}_${keyPrefix}`, {name, number});
|
return this.translation.instant(
|
||||||
|
`NODE_SELECTOR.${action.toUpperCase()}_${keyPrefix}`,
|
||||||
|
{ name, number }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private canCopyMoveInsideIt(entry: MinimalNodeEntryEntity): boolean {
|
private canCopyMoveInsideIt(entry: MinimalNodeEntryEntity): boolean {
|
||||||
@@ -231,7 +280,11 @@ export class NodeActionsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private isSite(entry) {
|
private isSite(entry) {
|
||||||
return !!entry.guid || entry.nodeType === 'st:site' || entry.nodeType === 'st:sites';
|
return (
|
||||||
|
!!entry.guid ||
|
||||||
|
entry.nodeType === 'st:site' ||
|
||||||
|
entry.nodeType === 'st:sites'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
@@ -240,7 +293,6 @@ export class NodeActionsService {
|
|||||||
|
|
||||||
// todo: review this approach once 5.2.3 is out
|
// todo: review this approach once 5.2.3 is out
|
||||||
private customizeBreadcrumb(node: MinimalNodeEntryEntity) {
|
private customizeBreadcrumb(node: MinimalNodeEntryEntity) {
|
||||||
|
|
||||||
if (node && node.path && node.path.elements) {
|
if (node && node.path && node.path.elements) {
|
||||||
const elements = node.path.elements;
|
const elements = node.path.elements;
|
||||||
|
|
||||||
@@ -250,16 +302,16 @@ export class NodeActionsService {
|
|||||||
|
|
||||||
// make sure first item is 'Personal Files'
|
// make sure first item is 'Personal Files'
|
||||||
if (elements[0]) {
|
if (elements[0]) {
|
||||||
elements[0].name = this.translation.instant('APP.BROWSE.PERSONAL.TITLE');
|
elements[0].name = this.translation.instant(
|
||||||
|
'APP.BROWSE.PERSONAL.TITLE'
|
||||||
|
);
|
||||||
elements[0].id = '-my-';
|
elements[0].id = '-my-';
|
||||||
} else {
|
} else {
|
||||||
node.name = this.translation.instant('APP.BROWSE.PERSONAL.TITLE');
|
node.name = this.translation.instant('APP.BROWSE.PERSONAL.TITLE');
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (elements[1].name === 'Sites') {
|
} else if (elements[1].name === 'Sites') {
|
||||||
this.normalizeSitePath(node);
|
this.normalizeSitePath(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (elements.length === 1) {
|
} else if (elements.length === 1) {
|
||||||
if (node.name === 'Sites') {
|
if (node.name === 'Sites') {
|
||||||
node.name = this.translation.instant('APP.BROWSE.LIBRARIES.TITLE');
|
node.name = this.translation.instant('APP.BROWSE.LIBRARIES.TITLE');
|
||||||
@@ -313,7 +365,6 @@ export class NodeActionsService {
|
|||||||
copyNodeAction(nodeEntry, selectionId): Observable<any> {
|
copyNodeAction(nodeEntry, selectionId): Observable<any> {
|
||||||
if (nodeEntry.isFolder) {
|
if (nodeEntry.isFolder) {
|
||||||
return this.copyFolderAction(nodeEntry, selectionId);
|
return this.copyFolderAction(nodeEntry, selectionId);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// any other type is treated as 'content'
|
// any other type is treated as 'content'
|
||||||
return this.copyContentAction(nodeEntry, selectionId);
|
return this.copyContentAction(nodeEntry, selectionId);
|
||||||
@@ -326,22 +377,30 @@ export class NodeActionsService {
|
|||||||
const contentEntryId = contentEntry.nodeId || contentEntry.id;
|
const contentEntryId = contentEntry.nodeId || contentEntry.id;
|
||||||
|
|
||||||
// use local method until new name parameter is added on ADF copyNode
|
// use local method until new name parameter is added on ADF copyNode
|
||||||
return this.copyNode(contentEntryId, selectionId, _oldName)
|
return this.copyNode(contentEntryId, selectionId, _oldName).pipe(
|
||||||
.pipe(catchError((err) => {
|
catchError(err => {
|
||||||
let errStatusCode;
|
let errStatusCode;
|
||||||
try {
|
try {
|
||||||
const {error: {statusCode}} = JSON.parse(err.message);
|
const {
|
||||||
|
error: { statusCode }
|
||||||
|
} = JSON.parse(err.message);
|
||||||
errStatusCode = statusCode;
|
errStatusCode = statusCode;
|
||||||
} catch (e) { //
|
} catch (e) {
|
||||||
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errStatusCode && errStatusCode === 409) {
|
if (errStatusCode && errStatusCode === 409) {
|
||||||
return this.copyContentAction(contentEntry, selectionId, this.getNewNameFrom(_oldName, contentEntry.name));
|
return this.copyContentAction(
|
||||||
|
contentEntry,
|
||||||
|
selectionId,
|
||||||
|
this.getNewNameFrom(_oldName, contentEntry.name)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
// do not throw error, to be able to show message in case of partial copy of files
|
// do not throw error, to be able to show message in case of partial copy of files
|
||||||
return of(err || 'Server error');
|
return of(err || 'Server error');
|
||||||
}
|
}
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
copyFolderAction(contentEntry, selectionId): Observable<any> {
|
copyFolderAction(contentEntry, selectionId): Observable<any> {
|
||||||
@@ -351,33 +410,45 @@ export class NodeActionsService {
|
|||||||
let $childrenToCopy: Observable<any>;
|
let $childrenToCopy: Observable<any>;
|
||||||
let newDestinationFolder;
|
let newDestinationFolder;
|
||||||
|
|
||||||
return this.copyNode(contentEntryId, selectionId, contentEntry.name)
|
return this.copyNode(contentEntryId, selectionId, contentEntry.name).pipe(
|
||||||
.pipe(
|
catchError(err => {
|
||||||
catchError((err) => {
|
|
||||||
let errStatusCode;
|
let errStatusCode;
|
||||||
try {
|
try {
|
||||||
const {error: {statusCode}} = JSON.parse(err.message);
|
const {
|
||||||
|
error: { statusCode }
|
||||||
|
} = JSON.parse(err.message);
|
||||||
errStatusCode = statusCode;
|
errStatusCode = statusCode;
|
||||||
} catch {}
|
} catch {}
|
||||||
|
|
||||||
if (errStatusCode && errStatusCode === 409) {
|
if (errStatusCode && errStatusCode === 409) {
|
||||||
|
$destinationFolder = this.getChildByName(
|
||||||
$destinationFolder = this.getChildByName(selectionId, contentEntry.name);
|
selectionId,
|
||||||
|
contentEntry.name
|
||||||
|
);
|
||||||
$childrenToCopy = this.getNodeChildren(contentEntryId);
|
$childrenToCopy = this.getNodeChildren(contentEntryId);
|
||||||
|
|
||||||
return $destinationFolder
|
return $destinationFolder.pipe(
|
||||||
.pipe(
|
mergeMap(destination => {
|
||||||
mergeMap((destination) => {
|
|
||||||
newDestinationFolder = destination;
|
newDestinationFolder = destination;
|
||||||
return $childrenToCopy;
|
return $childrenToCopy;
|
||||||
}),
|
}),
|
||||||
mergeMap((nodesToCopy) => {
|
mergeMap(nodesToCopy => {
|
||||||
const batch = [];
|
const batch = [];
|
||||||
nodesToCopy.list.entries.forEach((node) => {
|
nodesToCopy.list.entries.forEach(node => {
|
||||||
if (node.entry.isFolder) {
|
if (node.entry.isFolder) {
|
||||||
batch.push(this.copyFolderAction(node.entry, newDestinationFolder.entry.id));
|
batch.push(
|
||||||
|
this.copyFolderAction(
|
||||||
|
node.entry,
|
||||||
|
newDestinationFolder.entry.id
|
||||||
|
)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
batch.push(this.copyContentAction(node.entry, newDestinationFolder.entry.id));
|
batch.push(
|
||||||
|
this.copyContentAction(
|
||||||
|
node.entry,
|
||||||
|
newDestinationFolder.entry.id
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -387,7 +458,6 @@ export class NodeActionsService {
|
|||||||
return zip(...batch);
|
return zip(...batch);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// do not throw error, to be able to show message in case of partial copy of files
|
// do not throw error, to be able to show message in case of partial copy of files
|
||||||
return of(err || 'Server error');
|
return of(err || 'Server error');
|
||||||
@@ -402,9 +472,8 @@ export class NodeActionsService {
|
|||||||
if (nodeEntry.isFolder) {
|
if (nodeEntry.isFolder) {
|
||||||
const initialParentId = nodeEntry.parentId;
|
const initialParentId = nodeEntry.parentId;
|
||||||
|
|
||||||
return this.moveFolderAction(nodeEntry, selectionId)
|
return this.moveFolderAction(nodeEntry, selectionId).pipe(
|
||||||
.pipe(mergeMap((newContent) => {
|
mergeMap(newContent => {
|
||||||
|
|
||||||
// take no extra action, if folder is moved to the same location
|
// take no extra action, if folder is moved to the same location
|
||||||
if (initialParentId === selectionId) {
|
if (initialParentId === selectionId) {
|
||||||
return of(newContent);
|
return of(newContent);
|
||||||
@@ -415,18 +484,14 @@ export class NodeActionsService {
|
|||||||
|
|
||||||
// else, check if moving this nodeEntry succeeded for ALL of its nodes
|
// else, check if moving this nodeEntry succeeded for ALL of its nodes
|
||||||
if (processedData.failed.length === 0) {
|
if (processedData.failed.length === 0) {
|
||||||
|
|
||||||
// check if folder still exists on location
|
// check if folder still exists on location
|
||||||
return this.getChildByName(initialParentId, nodeEntry.name)
|
return this.getChildByName(initialParentId, nodeEntry.name).pipe(
|
||||||
.pipe(
|
|
||||||
mergeMap(folderOnInitialLocation => {
|
mergeMap(folderOnInitialLocation => {
|
||||||
if (folderOnInitialLocation) {
|
if (folderOnInitialLocation) {
|
||||||
// Check if there's nodeId for Shared Files
|
// Check if there's nodeId for Shared Files
|
||||||
const nodeEntryId = nodeEntry.nodeId || nodeEntry.id;
|
const nodeEntryId = nodeEntry.nodeId || nodeEntry.id;
|
||||||
// delete it from location
|
// delete it from location
|
||||||
return this.contentApi
|
return this.contentApi.deleteNode(nodeEntryId).pipe(
|
||||||
.deleteNode(nodeEntryId)
|
|
||||||
.pipe(
|
|
||||||
mergeMap(() => {
|
mergeMap(() => {
|
||||||
this.moveDeletedEntries.push(nodeEntry);
|
this.moveDeletedEntries.push(nodeEntry);
|
||||||
return of(newContent);
|
return of(newContent);
|
||||||
@@ -436,11 +501,10 @@ export class NodeActionsService {
|
|||||||
return of(newContent);
|
return of(newContent);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
return of(newContent);
|
return of(newContent);
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
// any other type is treated as 'content'
|
// any other type is treated as 'content'
|
||||||
return this.moveContentAction(nodeEntry, selectionId);
|
return this.moveContentAction(nodeEntry, selectionId);
|
||||||
@@ -455,37 +519,50 @@ export class NodeActionsService {
|
|||||||
let $childrenToMove: Observable<any>;
|
let $childrenToMove: Observable<any>;
|
||||||
let newDestinationFolder;
|
let newDestinationFolder;
|
||||||
|
|
||||||
return this.documentListService.moveNode(contentEntryId, selectionId)
|
return this.documentListService.moveNode(contentEntryId, selectionId).pipe(
|
||||||
.pipe(
|
map(itemMoved => {
|
||||||
map((itemMoved) => {
|
|
||||||
return { itemMoved, initialParentId };
|
return { itemMoved, initialParentId };
|
||||||
}),
|
}),
|
||||||
catchError(err => {
|
catchError(err => {
|
||||||
let errStatusCode;
|
let errStatusCode;
|
||||||
try {
|
try {
|
||||||
const {error: {statusCode}} = JSON.parse(err.message);
|
const {
|
||||||
|
error: { statusCode }
|
||||||
|
} = JSON.parse(err.message);
|
||||||
errStatusCode = statusCode;
|
errStatusCode = statusCode;
|
||||||
} catch (e) { //
|
} catch (e) {
|
||||||
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errStatusCode && errStatusCode === 409) {
|
if (errStatusCode && errStatusCode === 409) {
|
||||||
|
$destinationFolder = this.getChildByName(
|
||||||
$destinationFolder = this.getChildByName(selectionId, contentEntry.name);
|
selectionId,
|
||||||
|
contentEntry.name
|
||||||
|
);
|
||||||
$childrenToMove = this.getNodeChildren(contentEntryId);
|
$childrenToMove = this.getNodeChildren(contentEntryId);
|
||||||
|
|
||||||
return $destinationFolder
|
return $destinationFolder.pipe(
|
||||||
.pipe(
|
mergeMap(destination => {
|
||||||
mergeMap((destination) => {
|
|
||||||
newDestinationFolder = destination;
|
newDestinationFolder = destination;
|
||||||
return $childrenToMove;
|
return $childrenToMove;
|
||||||
}),
|
}),
|
||||||
mergeMap((childrenToMove) => {
|
mergeMap(childrenToMove => {
|
||||||
const batch = [];
|
const batch = [];
|
||||||
childrenToMove.list.entries.forEach((node) => {
|
childrenToMove.list.entries.forEach(node => {
|
||||||
if (node.entry.isFolder) {
|
if (node.entry.isFolder) {
|
||||||
batch.push(this.moveFolderAction(node.entry, newDestinationFolder.entry.id));
|
batch.push(
|
||||||
|
this.moveFolderAction(
|
||||||
|
node.entry,
|
||||||
|
newDestinationFolder.entry.id
|
||||||
|
)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
batch.push(this.moveContentAction(node.entry, newDestinationFolder.entry.id));
|
batch.push(
|
||||||
|
this.moveContentAction(
|
||||||
|
node.entry,
|
||||||
|
newDestinationFolder.entry.id
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -508,13 +585,11 @@ export class NodeActionsService {
|
|||||||
const contentEntryId = contentEntry.nodeId || contentEntry.id;
|
const contentEntryId = contentEntry.nodeId || contentEntry.id;
|
||||||
const initialParentId = this.getEntryParentId(contentEntry);
|
const initialParentId = this.getEntryParentId(contentEntry);
|
||||||
|
|
||||||
return this.documentListService
|
return this.documentListService.moveNode(contentEntryId, selectionId).pipe(
|
||||||
.moveNode(contentEntryId, selectionId)
|
map(itemMoved => {
|
||||||
.pipe(
|
|
||||||
map((itemMoved) => {
|
|
||||||
return { itemMoved, initialParentId };
|
return { itemMoved, initialParentId };
|
||||||
}),
|
}),
|
||||||
catchError((err) => {
|
catchError(err => {
|
||||||
// do not throw error, to be able to show message in case of partial move of files
|
// do not throw error, to be able to show message in case of partial move of files
|
||||||
return of(err);
|
return of(err);
|
||||||
})
|
})
|
||||||
@@ -526,22 +601,28 @@ export class NodeActionsService {
|
|||||||
|
|
||||||
this.getNodeChildren(parentId).subscribe(
|
this.getNodeChildren(parentId).subscribe(
|
||||||
(childrenNodes: any) => {
|
(childrenNodes: any) => {
|
||||||
const result = childrenNodes.list.entries.find(node => (node.entry.name === name));
|
const result = childrenNodes.list.entries.find(
|
||||||
|
node => node.entry.name === name
|
||||||
|
);
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
matchedNodes.next(result);
|
matchedNodes.next(result);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
matchedNodes.next(null);
|
matchedNodes.next(null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(err) => {
|
err => {
|
||||||
return of(err || 'Server error');
|
return of(err || 'Server error');
|
||||||
});
|
}
|
||||||
|
);
|
||||||
return matchedNodes;
|
return matchedNodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
private isActionAllowed(action: string, node: MinimalNodeEntryEntity, permission?: string): boolean {
|
private isActionAllowed(
|
||||||
|
action: string,
|
||||||
|
node: MinimalNodeEntryEntity,
|
||||||
|
permission?: string
|
||||||
|
): boolean {
|
||||||
if (action === 'copy') {
|
if (action === 'copy') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -553,11 +634,14 @@ export class NodeActionsService {
|
|||||||
const node: MinimalNodeEntryEntity = row.node.entry;
|
const node: MinimalNodeEntryEntity = row.node.entry;
|
||||||
|
|
||||||
this.isSitesDestinationAvailable = !!node['guid'];
|
this.isSitesDestinationAvailable = !!node['guid'];
|
||||||
return (!node.isFile && (node.nodeType !== 'app:folderlink'));
|
return !node.isFile && node.nodeType !== 'app:folderlink';
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: review once 1.10-beta6 is out
|
// todo: review once 1.10-beta6 is out
|
||||||
private imageResolver(row: /*ShareDataRow*/ any, col: DataColumn): string | null {
|
private imageResolver(
|
||||||
|
row: /*ShareDataRow*/ any,
|
||||||
|
col: DataColumn
|
||||||
|
): string | null {
|
||||||
const entry: MinimalNodeEntryEntity = row.node.entry;
|
const entry: MinimalNodeEntryEntity = row.node.entry;
|
||||||
if (!this.contentService.hasPermission(entry, 'update')) {
|
if (!this.contentService.hasPermission(entry, 'update')) {
|
||||||
return this.documentListService.getMimeTypeIcon('disable/folder');
|
return this.documentListService.getMimeTypeIcon('disable/folder');
|
||||||
@@ -571,7 +655,9 @@ export class NodeActionsService {
|
|||||||
|
|
||||||
// remove extension in case there is one
|
// remove extension in case there is one
|
||||||
const fileExtension = extensionMatch ? extensionMatch[0] : '';
|
const fileExtension = extensionMatch ? extensionMatch[0] : '';
|
||||||
let extensionFree = extensionMatch ? name.slice(0, extensionMatch.index) : name;
|
let extensionFree = extensionMatch
|
||||||
|
? name.slice(0, extensionMatch.index)
|
||||||
|
: name;
|
||||||
|
|
||||||
let prefixNumber = 1;
|
let prefixNumber = 1;
|
||||||
let baseExtensionFree;
|
let baseExtensionFree;
|
||||||
@@ -580,25 +666,22 @@ export class NodeActionsService {
|
|||||||
const baseExtensionMatch = baseName.match(/\.[^/.]+$/);
|
const baseExtensionMatch = baseName.match(/\.[^/.]+$/);
|
||||||
|
|
||||||
// remove extension in case there is one
|
// remove extension in case there is one
|
||||||
baseExtensionFree = baseExtensionMatch ? baseName.slice(0, baseExtensionMatch.index) : baseName;
|
baseExtensionFree = baseExtensionMatch
|
||||||
|
? baseName.slice(0, baseExtensionMatch.index)
|
||||||
|
: baseName;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!baseExtensionFree || baseExtensionFree !== extensionFree) {
|
if (!baseExtensionFree || baseExtensionFree !== extensionFree) {
|
||||||
|
|
||||||
// check if name already has integer appended on end:
|
// check if name already has integer appended on end:
|
||||||
const oldPrefix = extensionFree.match('-[0-9]+$');
|
const oldPrefix = extensionFree.match('-[0-9]+$');
|
||||||
if (oldPrefix) {
|
if (oldPrefix) {
|
||||||
|
|
||||||
// if so, try to get the number at the end
|
// if so, try to get the number at the end
|
||||||
const oldPrefixNumber = parseInt(oldPrefix[0].slice(1), 10);
|
const oldPrefixNumber = parseInt(oldPrefix[0].slice(1), 10);
|
||||||
if (oldPrefixNumber.toString() === oldPrefix[0].slice(1)) {
|
if (oldPrefixNumber.toString() === oldPrefix[0].slice(1)) {
|
||||||
|
|
||||||
extensionFree = extensionFree.slice(0, oldPrefix.index);
|
extensionFree = extensionFree.slice(0, oldPrefix.index);
|
||||||
prefixNumber = oldPrefixNumber + 1;
|
prefixNumber = oldPrefixNumber + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return extensionFree + '-' + prefixNumber + fileExtension;
|
return extensionFree + '-' + prefixNumber + fileExtension;
|
||||||
}
|
}
|
||||||
@@ -610,7 +693,9 @@ export class NodeActionsService {
|
|||||||
* @param params optional parameters
|
* @param params optional parameters
|
||||||
*/
|
*/
|
||||||
getNodeChildren(nodeId: string, params?) {
|
getNodeChildren(nodeId: string, params?) {
|
||||||
return from(this.apiService.getInstance().nodes.getNodeChildren(nodeId, params));
|
return from(
|
||||||
|
this.apiService.getInstance().nodes.getNodeChildren(nodeId, params)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copied from ADF document-list.service, and added the name parameter
|
// Copied from ADF document-list.service, and added the name parameter
|
||||||
@@ -622,7 +707,11 @@ export class NodeActionsService {
|
|||||||
* @param name The new name for the copy that would be added on the destination folder
|
* @param name The new name for the copy that would be added on the destination folder
|
||||||
*/
|
*/
|
||||||
copyNode(nodeId: string, targetParentId: string, name?: string) {
|
copyNode(nodeId: string, targetParentId: string, name?: string) {
|
||||||
return from(this.apiService.getInstance().nodes.copyNode(nodeId, {targetParentId, name}));
|
return from(
|
||||||
|
this.apiService
|
||||||
|
.getInstance()
|
||||||
|
.nodes.copyNode(nodeId, { targetParentId, name })
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public flatten(nDimArray) {
|
public flatten(nDimArray) {
|
||||||
@@ -634,8 +723,7 @@ export class NodeActionsService {
|
|||||||
const resultingArray = [];
|
const resultingArray = [];
|
||||||
|
|
||||||
do {
|
do {
|
||||||
nodeQueue.forEach(
|
nodeQueue.forEach(node => {
|
||||||
(node) => {
|
|
||||||
if (Array.isArray(node)) {
|
if (Array.isArray(node)) {
|
||||||
nodeQueue.push(...node);
|
nodeQueue.push(...node);
|
||||||
} else {
|
} else {
|
||||||
@@ -644,8 +732,7 @@ export class NodeActionsService {
|
|||||||
|
|
||||||
const nodeIndex = nodeQueue.indexOf(node);
|
const nodeIndex = nodeQueue.indexOf(node);
|
||||||
nodeQueue.splice(nodeIndex, 1);
|
nodeQueue.splice(nodeIndex, 1);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
} while (nodeQueue.length);
|
} while (nodeQueue.length);
|
||||||
|
|
||||||
return resultingArray;
|
return resultingArray;
|
||||||
@@ -659,43 +746,38 @@ export class NodeActionsService {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (Array.isArray(data)) {
|
if (Array.isArray(data)) {
|
||||||
return data.reduce(
|
return data.reduce((acc, next) => {
|
||||||
(acc, next) => {
|
|
||||||
|
|
||||||
if (next instanceof Error) {
|
if (next instanceof Error) {
|
||||||
acc.failed.push(next);
|
acc.failed.push(next);
|
||||||
|
|
||||||
} else if (Array.isArray(next)) {
|
} else if (Array.isArray(next)) {
|
||||||
// if content of a folder was moved
|
// if content of a folder was moved
|
||||||
|
|
||||||
const folderMoveResponseData = this.flatten(next);
|
const folderMoveResponseData = this.flatten(next);
|
||||||
const foundError = folderMoveResponseData.find(node => node instanceof Error);
|
const foundError = folderMoveResponseData.find(
|
||||||
|
node => node instanceof Error
|
||||||
|
);
|
||||||
// data might contain also items of form: { itemMoved, initialParentId }
|
// data might contain also items of form: { itemMoved, initialParentId }
|
||||||
const foundEntry = folderMoveResponseData.find(
|
const foundEntry = folderMoveResponseData.find(
|
||||||
node => (node.itemMoved && node.itemMoved.entry) || (node && node.entry)
|
node =>
|
||||||
|
(node.itemMoved && node.itemMoved.entry) || (node && node.entry)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!foundError) {
|
if (!foundError) {
|
||||||
// consider success if NONE of the items from the folder move response is an error
|
// consider success if NONE of the items from the folder move response is an error
|
||||||
acc.succeeded.push(next);
|
acc.succeeded.push(next);
|
||||||
|
|
||||||
} else if (!foundEntry) {
|
} else if (!foundEntry) {
|
||||||
// consider failed if NONE of the items has an entry
|
// consider failed if NONE of the items has an entry
|
||||||
acc.failed.push(next);
|
acc.failed.push(next);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// partially move folder
|
// partially move folder
|
||||||
acc.partiallySucceeded.push(next);
|
acc.partiallySucceeded.push(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
acc.succeeded.push(next);
|
acc.succeeded.push(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
},
|
}, moveStatus);
|
||||||
moveStatus
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
if ((data.itemMoved && data.itemMoved.entry) || (data && data.entry)) {
|
if ((data.itemMoved && data.itemMoved.entry) || (data && data.entry)) {
|
||||||
moveStatus.succeeded.push(data);
|
moveStatus.succeeded.push(data);
|
||||||
|
@@ -32,7 +32,6 @@ describe('NodePermissionService', () => {
|
|||||||
permission = new NodePermissionService();
|
permission = new NodePermissionService();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should return false when source is null', () => {
|
it('should return false when source is null', () => {
|
||||||
const source = null;
|
const source = null;
|
||||||
|
|
||||||
@@ -57,7 +56,11 @@ describe('NodePermissionService', () => {
|
|||||||
{ entry: { allowableOperationsOnTarget: ['update'] } }
|
{ entry: { allowableOperationsOnTarget: ['update'] } }
|
||||||
];
|
];
|
||||||
|
|
||||||
expect(permission.check(source, ['update'], { target: 'allowableOperationsOnTarget' })).toBe(true);
|
expect(
|
||||||
|
permission.check(source, ['update'], {
|
||||||
|
target: 'allowableOperationsOnTarget'
|
||||||
|
})
|
||||||
|
).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return false when source does not have allowableOperations permission', () => {
|
it('should return false when source does not have allowableOperations permission', () => {
|
||||||
@@ -67,7 +70,11 @@ describe('NodePermissionService', () => {
|
|||||||
{ entry: { allowableOperations: ['delete'] } }
|
{ entry: { allowableOperations: ['delete'] } }
|
||||||
];
|
];
|
||||||
|
|
||||||
expect(permission.check(source, ['update'], { target: 'allowableOperationsOnTarget' })).toBe(false);
|
expect(
|
||||||
|
permission.check(source, ['update'], {
|
||||||
|
target: 'allowableOperationsOnTarget'
|
||||||
|
})
|
||||||
|
).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return false when source does not have allowableOperationsOnTarget permission', () => {
|
it('should return false when source does not have allowableOperationsOnTarget permission', () => {
|
||||||
@@ -77,7 +84,11 @@ describe('NodePermissionService', () => {
|
|||||||
{ entry: { allowableOperationsOnTarget: ['delete'] } }
|
{ entry: { allowableOperationsOnTarget: ['delete'] } }
|
||||||
];
|
];
|
||||||
|
|
||||||
expect(permission.check(source, ['update'], { target: 'allowableOperationsOnTarget' })).toBe(false);
|
expect(
|
||||||
|
permission.check(source, ['update'], {
|
||||||
|
target: 'allowableOperationsOnTarget'
|
||||||
|
})
|
||||||
|
).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return true when source has `OR` allowableOperations permission', () => {
|
it('should return true when source has `OR` allowableOperations permission', () => {
|
||||||
@@ -94,20 +105,32 @@ describe('NodePermissionService', () => {
|
|||||||
const source = [
|
const source = [
|
||||||
{ entry: { allowableOperations: ['update', 'delete', 'other'] } },
|
{ entry: { allowableOperations: ['update', 'delete', 'other'] } },
|
||||||
{ entry: { allowableOperations: ['update', 'create', 'other'] } },
|
{ entry: { allowableOperations: ['update', 'create', 'other'] } },
|
||||||
{ entry: { allowableOperations: ['update', 'updatePermissions', 'other'] } }
|
{
|
||||||
|
entry: {
|
||||||
|
allowableOperations: ['update', 'updatePermissions', 'other']
|
||||||
|
}
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
expect(permission.check(source, ['update', 'other'], { operation: 'AND' })).toBe(true);
|
expect(
|
||||||
|
permission.check(source, ['update', 'other'], { operation: 'AND' })
|
||||||
|
).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return false when source has no `AND` allowableOperations permission', () => {
|
it('should return false when source has no `AND` allowableOperations permission', () => {
|
||||||
const source = [
|
const source = [
|
||||||
{ entry: { allowableOperations: ['update', 'delete', 'other'] } },
|
{ entry: { allowableOperations: ['update', 'delete', 'other'] } },
|
||||||
{ entry: { allowableOperations: ['update', 'create', 'other'] } },
|
{ entry: { allowableOperations: ['update', 'create', 'other'] } },
|
||||||
{ entry: { allowableOperations: ['update', 'updatePermissions', 'other'] } }
|
{
|
||||||
|
entry: {
|
||||||
|
allowableOperations: ['update', 'updatePermissions', 'other']
|
||||||
|
}
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
expect(permission.check(source, ['update', 'bogus'], { operation: 'AND' })).toBe(false);
|
expect(
|
||||||
|
permission.check(source, ['update', 'bogus'], { operation: 'AND' })
|
||||||
|
).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return false when source has no allowableOperations', () => {
|
it('should return false when source has no allowableOperations', () => {
|
||||||
@@ -131,7 +154,6 @@ describe('NodePermissionService', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
describe('Single source permission', () => {
|
describe('Single source permission', () => {
|
||||||
it('should return true when source has allowableOperations permission', () => {
|
it('should return true when source has allowableOperations permission', () => {
|
||||||
const source = { entry: { allowableOperations: ['update'] } };
|
const source = { entry: { allowableOperations: ['update'] } };
|
||||||
@@ -142,7 +164,11 @@ describe('NodePermissionService', () => {
|
|||||||
it('should return true when source has allowableOperationsOnTarget permission', () => {
|
it('should return true when source has allowableOperationsOnTarget permission', () => {
|
||||||
const source = { entry: { allowableOperationsOnTarget: ['update'] } };
|
const source = { entry: { allowableOperationsOnTarget: ['update'] } };
|
||||||
|
|
||||||
expect(permission.check(source, ['update'], { target: 'allowableOperationsOnTarget' })).toBe(true);
|
expect(
|
||||||
|
permission.check(source, ['update'], {
|
||||||
|
target: 'allowableOperationsOnTarget'
|
||||||
|
})
|
||||||
|
).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return false when source does not have allowableOperations permission', () => {
|
it('should return false when source does not have allowableOperations permission', () => {
|
||||||
@@ -154,7 +180,11 @@ describe('NodePermissionService', () => {
|
|||||||
it('should return false when source does not have allowableOperationsOnTarget permission', () => {
|
it('should return false when source does not have allowableOperationsOnTarget permission', () => {
|
||||||
const source = { entry: { allowableOperationsOnTarget: ['delete'] } };
|
const source = { entry: { allowableOperationsOnTarget: ['delete'] } };
|
||||||
|
|
||||||
expect(permission.check(source, ['update'], { target: 'allowableOperationsOnTarget' })).toBe(false);
|
expect(
|
||||||
|
permission.check(source, ['update'], {
|
||||||
|
target: 'allowableOperationsOnTarget'
|
||||||
|
})
|
||||||
|
).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return true when source has `OR` allowableOperations permission', () => {
|
it('should return true when source has `OR` allowableOperations permission', () => {
|
||||||
@@ -166,13 +196,19 @@ describe('NodePermissionService', () => {
|
|||||||
it('should return true when source has `AND` allowableOperations permission', () => {
|
it('should return true when source has `AND` allowableOperations permission', () => {
|
||||||
const source = { entry: { allowableOperations: ['update', 'other'] } };
|
const source = { entry: { allowableOperations: ['update', 'other'] } };
|
||||||
|
|
||||||
expect(permission.check(source, ['update', 'other'], { operation: 'AND' })).toBe(true);
|
expect(
|
||||||
|
permission.check(source, ['update', 'other'], { operation: 'AND' })
|
||||||
|
).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return false when source has no `AND` allowableOperations permission', () => {
|
it('should return false when source has no `AND` allowableOperations permission', () => {
|
||||||
const source = { entry: { allowableOperations: ['update', 'updatePermissions', 'other'] } };
|
const source = {
|
||||||
|
entry: { allowableOperations: ['update', 'updatePermissions', 'other'] }
|
||||||
|
};
|
||||||
|
|
||||||
expect(permission.check(source, ['update', 'bogus'], { operation: 'AND' })).toBe(false);
|
expect(
|
||||||
|
permission.check(source, ['update', 'bogus'], { operation: 'AND' })
|
||||||
|
).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return false when source has no allowableOperations', () => {
|
it('should return false when source has no allowableOperations', () => {
|
||||||
|
@@ -42,7 +42,10 @@ export class NodePermissionService implements NodePermissions {
|
|||||||
if (Array.isArray(source) && source.length) {
|
if (Array.isArray(source) && source.length) {
|
||||||
const arr = this.sanitize(source);
|
const arr = this.sanitize(source);
|
||||||
|
|
||||||
return !!arr.length && source.every(node => this.hasPermission(node, permissions, opts));
|
return (
|
||||||
|
!!arr.length &&
|
||||||
|
source.every(node => this.hasPermission(node, permissions, opts))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.hasPermission(source, permissions, opts);
|
return this.hasPermission(source, permissions, opts);
|
||||||
@@ -52,13 +55,20 @@ export class NodePermissionService implements NodePermissions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private hasPermission(node, permissions, options): boolean {
|
private hasPermission(node, permissions, options): boolean {
|
||||||
const allowableOperations = this.getAllowableOperations(node, options.target);
|
const allowableOperations = this.getAllowableOperations(
|
||||||
|
node,
|
||||||
|
options.target
|
||||||
|
);
|
||||||
|
|
||||||
if (allowableOperations.length) {
|
if (allowableOperations.length) {
|
||||||
if (options.operation === NodePermissionService.DEFAULT_OPERATION) {
|
if (options.operation === NodePermissionService.DEFAULT_OPERATION) {
|
||||||
return permissions.some(permission => allowableOperations.includes(permission));
|
return permissions.some(permission =>
|
||||||
|
allowableOperations.includes(permission)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
return permissions.every(permission => allowableOperations.includes(permission));
|
return permissions.every(permission =>
|
||||||
|
allowableOperations.includes(permission)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -45,10 +45,7 @@ import {
|
|||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
StoreModule.forRoot(
|
StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }),
|
||||||
{ app: appReducer },
|
|
||||||
{ initialState: INITIAL_STATE }
|
|
||||||
),
|
|
||||||
StoreRouterConnectingModule.forRoot({ stateKey: 'router' }),
|
StoreRouterConnectingModule.forRoot({ stateKey: 'router' }),
|
||||||
EffectsModule.forRoot([
|
EffectsModule.forRoot([
|
||||||
SnackbarEffects,
|
SnackbarEffects,
|
||||||
|
@@ -99,10 +99,7 @@ export class DownloadEffects {
|
|||||||
|
|
||||||
private downloadFile(node: NodeInfo) {
|
private downloadFile(node: NodeInfo) {
|
||||||
if (node) {
|
if (node) {
|
||||||
this.download(
|
this.download(this.contentApi.getContentUrl(node.id, true), node.name);
|
||||||
this.contentApi.getContentUrl(node.id, true),
|
|
||||||
node.name
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -26,7 +26,12 @@
|
|||||||
import { Effect, Actions, ofType } from '@ngrx/effects';
|
import { Effect, Actions, ofType } from '@ngrx/effects';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { map, take } from 'rxjs/operators';
|
import { map, take } from 'rxjs/operators';
|
||||||
import { ADD_FAVORITE, AddFavoriteAction, RemoveFavoriteAction, REMOVE_FAVORITE } from '../actions/favorite.actions';
|
import {
|
||||||
|
ADD_FAVORITE,
|
||||||
|
AddFavoriteAction,
|
||||||
|
RemoveFavoriteAction,
|
||||||
|
REMOVE_FAVORITE
|
||||||
|
} from '../actions/favorite.actions';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { AppStore } from '../states';
|
import { AppStore } from '../states';
|
||||||
import { appSelection } from '../selectors/app.selectors';
|
import { appSelection } from '../selectors/app.selectors';
|
||||||
@@ -77,6 +82,4 @@ export class FavoriteEffects {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -27,8 +27,10 @@ import { Effect, Actions, ofType } from '@ngrx/effects';
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { map, take } from 'rxjs/operators';
|
import { map, take } from 'rxjs/operators';
|
||||||
import {
|
import {
|
||||||
DeleteLibraryAction, DELETE_LIBRARY,
|
DeleteLibraryAction,
|
||||||
CreateLibraryAction, CREATE_LIBRARY
|
DELETE_LIBRARY,
|
||||||
|
CreateLibraryAction,
|
||||||
|
CREATE_LIBRARY
|
||||||
} 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';
|
||||||
|
@@ -117,9 +117,7 @@ export class NodeEffects {
|
|||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
.subscribe(selection => {
|
.subscribe(selection => {
|
||||||
if (selection && selection.count > 0) {
|
if (selection && selection.count > 0) {
|
||||||
this.contentService.purgeDeletedNodes(
|
this.contentService.purgeDeletedNodes(selection.nodes);
|
||||||
selection.nodes
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -138,9 +136,7 @@ export class NodeEffects {
|
|||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
.subscribe(selection => {
|
.subscribe(selection => {
|
||||||
if (selection && selection.count > 0) {
|
if (selection && selection.count > 0) {
|
||||||
this.contentService.restoreDeletedNodes(
|
this.contentService.restoreDeletedNodes(selection.nodes);
|
||||||
selection.nodes
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -264,9 +260,7 @@ export class NodeEffects {
|
|||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
.subscribe(selection => {
|
.subscribe(selection => {
|
||||||
if (selection && !selection.isEmpty) {
|
if (selection && !selection.isEmpty) {
|
||||||
this.contentService.managePermissions(
|
this.contentService.managePermissions(selection.first);
|
||||||
selection.first
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -285,9 +279,7 @@ export class NodeEffects {
|
|||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
.subscribe(selection => {
|
.subscribe(selection => {
|
||||||
if (selection && selection.file) {
|
if (selection && selection.file) {
|
||||||
this.contentService.manageVersions(
|
this.contentService.manageVersions(selection.file);
|
||||||
selection.file
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -55,7 +55,6 @@ export class UploadEffects {
|
|||||||
this.fileInput.addEventListener('change', event => this.upload(event));
|
this.fileInput.addEventListener('change', event => this.upload(event));
|
||||||
renderer.appendChild(document.body, this.fileInput);
|
renderer.appendChild(document.body, this.fileInput);
|
||||||
|
|
||||||
|
|
||||||
this.folderInput = renderer.createElement('input') as HTMLInputElement;
|
this.folderInput = renderer.createElement('input') as HTMLInputElement;
|
||||||
this.folderInput.id = 'app-upload-folder';
|
this.folderInput.id = 'app-upload-folder';
|
||||||
this.folderInput.type = 'file';
|
this.folderInput.type = 'file';
|
||||||
@@ -89,15 +88,13 @@ export class UploadEffects {
|
|||||||
.subscribe(node => {
|
.subscribe(node => {
|
||||||
if (node && node.id) {
|
if (node && node.id) {
|
||||||
const input = <HTMLInputElement>event.currentTarget;
|
const input = <HTMLInputElement>event.currentTarget;
|
||||||
const files = FileUtils.toFileArray(input.files).map(
|
const files = FileUtils.toFileArray(input.files).map(file => {
|
||||||
file => {
|
|
||||||
return new FileModel(file, {
|
return new FileModel(file, {
|
||||||
parentId: node.id,
|
parentId: node.id,
|
||||||
path: (file.webkitRelativePath || '').replace(/\/[^\/]*$/, ''),
|
path: (file.webkitRelativePath || '').replace(/\/[^\/]*$/, ''),
|
||||||
nodeType: 'cm:content'
|
nodeType: 'cm:content'
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
this.uploadQueue(files);
|
this.uploadQueue(files);
|
||||||
event.target.value = '';
|
event.target.value = '';
|
||||||
|
@@ -67,16 +67,10 @@ export class ViewerEffects {
|
|||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
.subscribe(result => {
|
.subscribe(result => {
|
||||||
if (result.selection && result.selection.file) {
|
if (result.selection && result.selection.file) {
|
||||||
const {
|
const { id, nodeId, isFile } = result.selection.file.entry;
|
||||||
id,
|
|
||||||
nodeId,
|
|
||||||
isFile
|
|
||||||
} = result.selection.file.entry;
|
|
||||||
|
|
||||||
if (isFile || nodeId) {
|
if (isFile || nodeId) {
|
||||||
const parentId = result.folder
|
const parentId = result.folder ? result.folder.id : null;
|
||||||
? result.folder.id
|
|
||||||
: null;
|
|
||||||
this.displayPreview(nodeId || id, parentId);
|
this.displayPreview(nodeId || id, parentId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -57,22 +57,16 @@ export function appReducer(
|
|||||||
newState = Object.assign({}, (<SetInitialStateAction>action).payload);
|
newState = Object.assign({}, (<SetInitialStateAction>action).payload);
|
||||||
break;
|
break;
|
||||||
case SET_SELECTED_NODES:
|
case SET_SELECTED_NODES:
|
||||||
newState = updateSelectedNodes(state, <SetSelectedNodesAction>(
|
newState = updateSelectedNodes(state, <SetSelectedNodesAction>action);
|
||||||
action
|
|
||||||
));
|
|
||||||
break;
|
break;
|
||||||
case SET_USER_PROFILE:
|
case SET_USER_PROFILE:
|
||||||
newState = updateUser(state, <SetUserProfileAction>action);
|
newState = updateUser(state, <SetUserProfileAction>action);
|
||||||
break;
|
break;
|
||||||
case SET_LANGUAGE_PICKER:
|
case SET_LANGUAGE_PICKER:
|
||||||
newState = updateLanguagePicker(state, <SetLanguagePickerAction>(
|
newState = updateLanguagePicker(state, <SetLanguagePickerAction>action);
|
||||||
action
|
|
||||||
));
|
|
||||||
break;
|
break;
|
||||||
case SET_CURRENT_FOLDER:
|
case SET_CURRENT_FOLDER:
|
||||||
newState = updateCurrentFolder(state, <SetCurrentFolderAction>(
|
newState = updateCurrentFolder(state, <SetCurrentFolderAction>action);
|
||||||
action
|
|
||||||
));
|
|
||||||
break;
|
break;
|
||||||
case SET_CURRENT_URL:
|
case SET_CURRENT_URL:
|
||||||
newState = updateCurrentUrl(state, <SetCurrentUrlAction>action);
|
newState = updateCurrentUrl(state, <SetCurrentUrlAction>action);
|
||||||
@@ -81,9 +75,9 @@ export function appReducer(
|
|||||||
newState = updateInfoDrawer(state, <ToggleInfoDrawerAction>action);
|
newState = updateInfoDrawer(state, <ToggleInfoDrawerAction>action);
|
||||||
break;
|
break;
|
||||||
case TOGGLE_DOCUMENT_DISPLAY_MODE:
|
case TOGGLE_DOCUMENT_DISPLAY_MODE:
|
||||||
newState = updateDocumentDisplayMode(state, <
|
newState = updateDocumentDisplayMode(state, <ToggleDocumentDisplayMode>(
|
||||||
ToggleDocumentDisplayMode
|
action
|
||||||
>action);
|
));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
newState = Object.assign({}, state);
|
newState = Object.assign({}, state);
|
||||||
@@ -185,9 +179,7 @@ function updateSelectedNodes(
|
|||||||
if (nodes.length === 1) {
|
if (nodes.length === 1) {
|
||||||
file = nodes.find(entity => {
|
file = nodes.find(entity => {
|
||||||
// workaround Shared
|
// workaround Shared
|
||||||
return entity.entry.isFile || entity.entry.nodeId
|
return entity.entry.isFile || entity.entry.nodeId ? true : false;
|
||||||
? true
|
|
||||||
: false;
|
|
||||||
});
|
});
|
||||||
folder = nodes.find(entity => entity.entry.isFolder);
|
folder = nodes.find(entity => entity.entry.isFolder);
|
||||||
}
|
}
|
||||||
|
@@ -27,17 +27,38 @@ import { createSelector } from '@ngrx/store';
|
|||||||
import { AppStore } from '../states/app.state';
|
import { AppStore } from '../states/app.state';
|
||||||
|
|
||||||
export const selectApp = (state: AppStore) => state.app;
|
export const selectApp = (state: AppStore) => state.app;
|
||||||
export const selectHeaderColor = createSelector(selectApp, state => state.headerColor);
|
export const selectHeaderColor = createSelector(
|
||||||
|
selectApp,
|
||||||
|
state => state.headerColor
|
||||||
|
);
|
||||||
export const selectAppName = createSelector(selectApp, state => state.appName);
|
export const selectAppName = createSelector(selectApp, state => state.appName);
|
||||||
export const selectLogoPath = createSelector(selectApp, state => state.logoPath);
|
export const selectLogoPath = createSelector(
|
||||||
|
selectApp,
|
||||||
|
state => state.logoPath
|
||||||
|
);
|
||||||
export const appSelection = createSelector(selectApp, state => state.selection);
|
export const appSelection = createSelector(selectApp, state => state.selection);
|
||||||
export const appLanguagePicker = createSelector(selectApp, state => state.languagePicker);
|
export const appLanguagePicker = createSelector(
|
||||||
|
selectApp,
|
||||||
|
state => state.languagePicker
|
||||||
|
);
|
||||||
export const selectUser = createSelector(selectApp, state => state.user);
|
export const selectUser = createSelector(selectApp, state => state.user);
|
||||||
export const sharedUrl = createSelector(selectApp, state => state.sharedUrl);
|
export const sharedUrl = createSelector(selectApp, state => state.sharedUrl);
|
||||||
export const appNavigation = createSelector(selectApp, state => state.navigation);
|
export const appNavigation = createSelector(
|
||||||
export const currentFolder = createSelector(selectApp, state => state.navigation.currentFolder);
|
selectApp,
|
||||||
export const infoDrawerOpened = createSelector(selectApp, state => state.infoDrawerOpened);
|
state => state.navigation
|
||||||
export const documentDisplayMode = createSelector(selectApp, state => state.documentDisplayMode);
|
);
|
||||||
|
export const currentFolder = createSelector(
|
||||||
|
selectApp,
|
||||||
|
state => state.navigation.currentFolder
|
||||||
|
);
|
||||||
|
export const infoDrawerOpened = createSelector(
|
||||||
|
selectApp,
|
||||||
|
state => state.infoDrawerOpened
|
||||||
|
);
|
||||||
|
export const documentDisplayMode = createSelector(
|
||||||
|
selectApp,
|
||||||
|
state => state.documentDisplayMode
|
||||||
|
);
|
||||||
|
|
||||||
export const ruleContext = createSelector(
|
export const ruleContext = createSelector(
|
||||||
appSelection,
|
appSelection,
|
||||||
|
@@ -23,7 +23,11 @@
|
|||||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { SelectionState, ProfileState, NavigationState } from '@alfresco/adf-extensions';
|
import {
|
||||||
|
SelectionState,
|
||||||
|
ProfileState,
|
||||||
|
NavigationState
|
||||||
|
} from '@alfresco/adf-extensions';
|
||||||
|
|
||||||
export interface AppState {
|
export interface AppState {
|
||||||
appName: string;
|
appName: string;
|
||||||
|
@@ -61,7 +61,10 @@ import { NodePermissionService } from '../services/node-permission.service';
|
|||||||
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 { ViewUtilService } from '../components/preview/view-util.service';
|
import { ViewUtilService } from '../components/preview/view-util.service';
|
||||||
import { ExtensionLoaderService, ExtensionService } from '@alfresco/adf-extensions';
|
import {
|
||||||
|
ExtensionLoaderService,
|
||||||
|
ExtensionService
|
||||||
|
} from '@alfresco/adf-extensions';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -69,18 +72,11 @@ import { ExtensionLoaderService, ExtensionService } from '@alfresco/adf-extensio
|
|||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
RouterTestingModule,
|
RouterTestingModule,
|
||||||
MaterialModule,
|
MaterialModule,
|
||||||
StoreModule.forRoot(
|
StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }),
|
||||||
{ app: appReducer },
|
|
||||||
{ initialState: INITIAL_STATE }
|
|
||||||
),
|
|
||||||
EffectsModule.forRoot([])
|
EffectsModule.forRoot([])
|
||||||
],
|
],
|
||||||
declarations: [TranslatePipeMock],
|
declarations: [TranslatePipeMock],
|
||||||
exports: [
|
exports: [TranslatePipeMock, RouterTestingModule, MaterialModule],
|
||||||
TranslatePipeMock,
|
|
||||||
RouterTestingModule,
|
|
||||||
MaterialModule,
|
|
||||||
],
|
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: AlfrescoApiService, useClass: AlfrescoApiMock },
|
{ provide: AlfrescoApiService, useClass: AlfrescoApiMock },
|
||||||
{ provide: TranslationService, useClass: TranslationMock },
|
{ provide: TranslationService, useClass: TranslationMock },
|
||||||
|
@@ -33,11 +33,17 @@ export class TranslateServiceMock extends TranslateService {
|
|||||||
super(null, null, null, null, null);
|
super(null, null, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
get(key: string | Array<string>, interpolateParams?: Object): Observable<string | any> {
|
get(
|
||||||
|
key: string | Array<string>,
|
||||||
|
interpolateParams?: Object
|
||||||
|
): Observable<string | any> {
|
||||||
return of(key);
|
return of(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
instant(key: string | Array<string>, interpolateParams?: Object): string | any {
|
instant(
|
||||||
|
key: string | Array<string>,
|
||||||
|
interpolateParams?: Object
|
||||||
|
): string | any {
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user