mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-05-12 17:04:46 +00:00
[ACA-1432] unified selection and single info drawer (#385)
* track document list selection state * selection management enhancements * (fix) hide info drawer on selection reset * use store selection * remove event handler * upgrade info drawer for personal files * upgrade favorties * upgrade recent files * move info drawer to a separate component * test fixes * update tests * test fixes * remove obsolete directive * use last selection entry * switch back to first selected node * selection improvements, versioning uses same node * optimised toolbar visibility evaluation * upgrade libs * update js api * test fixes * test fixes * test updates * test fixes * fix e2e tests * show metadata for last clicked node
This commit is contained in:
parent
a67dd43ad6
commit
f0c0fe162b
@ -135,11 +135,6 @@ describe('Toolbar actions - multiple selection : ', () => {
|
||||
|
||||
it('correct actions appear when multiple files are selected', () => {
|
||||
dataTable.selectMultipleItems([file1, file2])
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files');
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`);
|
||||
@ -154,11 +149,6 @@ describe('Toolbar actions - multiple selection : ', () => {
|
||||
|
||||
it('correct actions appear when multiple folders are selected', () => {
|
||||
dataTable.selectMultipleItems([folder1, folder2])
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files');
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`);
|
||||
@ -171,13 +161,39 @@ describe('Toolbar actions - multiple selection : ', () => {
|
||||
.then(() => dataTable.clearSelection());
|
||||
});
|
||||
|
||||
it('should display View action when at least one file selected', async () => {
|
||||
await dataTable.selectMultipleItems([folder1, file1, folder2]);
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(true, 'Action is not displayed');
|
||||
});
|
||||
|
||||
it('should not display View action when only folders selected', async () => {
|
||||
await dataTable.selectMultipleItems([folder1, folder2]);
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'Action is displayed');
|
||||
});
|
||||
|
||||
it('should display Download action for selected items', async () => {
|
||||
await dataTable.selectMultipleItems([folder1, file1, folder2]);
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Action is not displayed');
|
||||
});
|
||||
|
||||
it('should not display Download action for empty selection', async () => {
|
||||
await dataTable.selectMultipleItems([folder1, file1, folder2]);
|
||||
await dataTable.clearSelection();
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(false, 'Action is displayed');
|
||||
});
|
||||
|
||||
it('should display Edit action when at least one folder selected', async () => {
|
||||
await dataTable.selectMultipleItems([folder1, file1, folder2]);
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(true, 'Action is not displayed');
|
||||
});
|
||||
|
||||
it('should not display Edit action if no folders selected', async () => {
|
||||
await dataTable.selectMultipleItems([file1, file2]);
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Action is displayed');
|
||||
});
|
||||
|
||||
it('correct actions appear when both files and folders are selected', () => {
|
||||
dataTable.selectMultipleItems([file1, file2, folder1, folder2])
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files');
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`);
|
||||
@ -228,7 +244,7 @@ describe('Toolbar actions - multiple selection : ', () => {
|
||||
it('correct actions appear when multiple files are selected', () => {
|
||||
dataTable.selectMultipleItems([file1Admin, file2Admin])
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(true, 'View not displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files');
|
||||
})
|
||||
@ -247,9 +263,9 @@ describe('Toolbar actions - multiple selection : ', () => {
|
||||
it('correct actions appear when multiple folders are selected', () => {
|
||||
dataTable.selectMultipleItems([folder1Admin, folder2Admin])
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(true, 'Edit is not displayed');
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
@ -266,9 +282,9 @@ describe('Toolbar actions - multiple selection : ', () => {
|
||||
it('correct actions appear when both files and folders are selected', () => {
|
||||
dataTable.selectMultipleItems([file1Admin, file2Admin, folder1Admin, folder2Admin])
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(true, 'View is not displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(true, 'Edit is not displayed');
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
@ -295,7 +311,7 @@ describe('Toolbar actions - multiple selection : ', () => {
|
||||
it('correct actions appear when multiple files are selected', () => {
|
||||
dataTable.selectMultipleItems([file1Admin, file2Admin])
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(true, 'View is not displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files');
|
||||
})
|
||||
@ -314,16 +330,16 @@ describe('Toolbar actions - multiple selection : ', () => {
|
||||
it('correct actions appear when multiple folders are selected', () => {
|
||||
dataTable.selectMultipleItems([folder1Admin, folder2Admin])
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed');
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(false, `Delete is displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(false, `Move is displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed for selected files`);
|
||||
expect(menu.isMenuItemPresent('Copy')).toBe(true, `Copy is not displayed`);
|
||||
expect(menu.isMenuItemPresent('Delete')).toBe(false, `Delete is displayed`);
|
||||
expect(menu.isMenuItemPresent('Move')).toBe(false, `Move is displayed`);
|
||||
expect(menu.isMenuItemPresent('Favorite')).toBe(true, `Favorite is not displayed`);
|
||||
})
|
||||
// .then(() => browser.$('body').click())
|
||||
.then(() => browser.actions().mouseMove(browser.$('body'), { x: 0, y: 0 }).click().perform())
|
||||
@ -333,9 +349,9 @@ describe('Toolbar actions - multiple selection : ', () => {
|
||||
it('correct actions appear when both files and folders are selected', () => {
|
||||
dataTable.selectMultipleItems([file1Admin, file2Admin, folder1Admin, folder2Admin])
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(true, 'View is not displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed');
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
@ -369,7 +385,7 @@ describe('Toolbar actions - multiple selection : ', () => {
|
||||
it('correct actions appear when multiple files are selected', () => {
|
||||
dataTable.selectMultipleItems([file1, file2])
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(true, 'View is not displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files');
|
||||
})
|
||||
@ -404,9 +420,9 @@ describe('Toolbar actions - multiple selection : ', () => {
|
||||
it('correct actions appear when multiple files are selected', () => {
|
||||
dataTable.selectMultipleItems([file1, file2])
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(true, 'View is not displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed');
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
@ -439,9 +455,9 @@ describe('Toolbar actions - multiple selection : ', () => {
|
||||
it('correct actions appear when multiple files are selected', () => {
|
||||
dataTable.selectMultipleItems([file1, file2])
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(true, 'View is not displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed');
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
@ -458,9 +474,9 @@ describe('Toolbar actions - multiple selection : ', () => {
|
||||
it('correct actions appear when multiple folders are selected', () => {
|
||||
dataTable.selectMultipleItems([folder1, folder2])
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(true, 'Edit is not displayed');
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
@ -477,9 +493,9 @@ describe('Toolbar actions - multiple selection : ', () => {
|
||||
it('correct actions appear when both files and folders are selected', () => {
|
||||
dataTable.selectMultipleItems([file1, file2, folder1, folder2])
|
||||
.then(() => {
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(false, 'View is displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('View')).toBe(true, 'View is not displayed');
|
||||
expect(toolbar.actions.isButtonPresent('Download')).toBe(true, 'Download is not displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(false, 'Edit is displayed for selected files');
|
||||
expect(toolbar.actions.isButtonPresent('Edit')).toBe(true, 'Edit is not displayed');
|
||||
})
|
||||
.then(() => toolbar.actions.openMoreMenu())
|
||||
.then(menu => {
|
||||
|
48
package-lock.json
generated
48
package-lock.json
generated
@ -5,11 +5,11 @@
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@alfresco/adf-content-services": {
|
||||
"version": "2.4.0-beta10",
|
||||
"resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-beta10.tgz",
|
||||
"integrity": "sha512-uBHkDrp60oeen770MjCh8aCFZm/g8nOIdilruB26EXaj9KOE3ZJ2ptGrHVGf51qrWRyDjnne/dwKvHW2O+kxvA==",
|
||||
"version": "2.4.0-24b573b08f3a072327efefc0196bd949cbca3766",
|
||||
"resolved": "https://registry.npmjs.org/@alfresco/adf-content-services/-/adf-content-services-2.4.0-24b573b08f3a072327efefc0196bd949cbca3766.tgz",
|
||||
"integrity": "sha512-5B/JHEsCdvksEP16TyS5yHtOT/zCOLj7uHS8lqGhu7Z20Cj5K7RTBwco4flTh3T8OSyoUBzdmp3HQgfqJk/QrQ==",
|
||||
"requires": {
|
||||
"@alfresco/adf-core": "2.4.0-beta10",
|
||||
"@alfresco/adf-core": "2.4.0-24b573b08f3a072327efefc0196bd949cbca3766",
|
||||
"@angular/animations": "5.1.1",
|
||||
"@angular/cdk": "5.0.1",
|
||||
"@angular/common": "5.1.1",
|
||||
@ -24,7 +24,7 @@
|
||||
"@angular/platform-browser-dynamic": "5.1.1",
|
||||
"@angular/router": "5.1.1",
|
||||
"@ngx-translate/core": "9.1.1",
|
||||
"alfresco-js-api": "2.4.0-beta9",
|
||||
"alfresco-js-api": "2.4.0-fed4e011ee70eb36b5e2015859e719153d70b6c2",
|
||||
"chart.js": "2.5.0",
|
||||
"core-js": "2.4.1",
|
||||
"hammerjs": "2.0.8",
|
||||
@ -40,15 +40,6 @@
|
||||
"zone.js": "0.8.14"
|
||||
},
|
||||
"dependencies": {
|
||||
"alfresco-js-api": {
|
||||
"version": "2.4.0-beta9",
|
||||
"resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-beta9.tgz",
|
||||
"integrity": "sha512-4SlaFerEucx+Gnusf4dwhEfrCvwWTKBxJm1kwe7eoKnPJO0I6B/Zx1I/Dkvvw4GVqO2f5WYoab+XGQSdMNyOng==",
|
||||
"requires": {
|
||||
"event-emitter": "0.3.4",
|
||||
"superagent": "3.8.2"
|
||||
}
|
||||
},
|
||||
"core-js": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz",
|
||||
@ -70,9 +61,9 @@
|
||||
}
|
||||
},
|
||||
"@alfresco/adf-core": {
|
||||
"version": "2.4.0-beta10",
|
||||
"resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-beta10.tgz",
|
||||
"integrity": "sha512-w8W6Uv9QfLOWojF+2zpvnjlYsAhJErawc77rIFPROQIN81nibSQ8Y6Xm3NdsrCz2drlrKbx5XD8yzia+2QKeyw==",
|
||||
"version": "2.4.0-24b573b08f3a072327efefc0196bd949cbca3766",
|
||||
"resolved": "https://registry.npmjs.org/@alfresco/adf-core/-/adf-core-2.4.0-24b573b08f3a072327efefc0196bd949cbca3766.tgz",
|
||||
"integrity": "sha512-vDC4Wz+j6uSEMzdZUhy5xB0Sm63brb360o+uiPXs0uMyL9agMEh5wUPAl4Zfic0alnlww8OGADA8r6sFwb7HhQ==",
|
||||
"requires": {
|
||||
"@angular/animations": "5.1.1",
|
||||
"@angular/cdk": "5.0.1",
|
||||
@ -88,7 +79,7 @@
|
||||
"@angular/platform-browser-dynamic": "5.1.1",
|
||||
"@angular/router": "5.1.1",
|
||||
"@ngx-translate/core": "9.1.1",
|
||||
"alfresco-js-api": "2.4.0-beta9",
|
||||
"alfresco-js-api": "2.4.0-fed4e011ee70eb36b5e2015859e719153d70b6c2",
|
||||
"chart.js": "2.5.0",
|
||||
"core-js": "2.4.1",
|
||||
"hammerjs": "2.0.8",
|
||||
@ -104,15 +95,6 @@
|
||||
"zone.js": "0.8.14"
|
||||
},
|
||||
"dependencies": {
|
||||
"alfresco-js-api": {
|
||||
"version": "2.4.0-beta9",
|
||||
"resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-beta9.tgz",
|
||||
"integrity": "sha512-4SlaFerEucx+Gnusf4dwhEfrCvwWTKBxJm1kwe7eoKnPJO0I6B/Zx1I/Dkvvw4GVqO2f5WYoab+XGQSdMNyOng==",
|
||||
"requires": {
|
||||
"event-emitter": "0.3.4",
|
||||
"superagent": "3.8.2"
|
||||
}
|
||||
},
|
||||
"core-js": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz",
|
||||
@ -674,9 +656,9 @@
|
||||
"integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo="
|
||||
},
|
||||
"alfresco-js-api": {
|
||||
"version": "2.4.0-beta9",
|
||||
"resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-beta9.tgz",
|
||||
"integrity": "sha512-4SlaFerEucx+Gnusf4dwhEfrCvwWTKBxJm1kwe7eoKnPJO0I6B/Zx1I/Dkvvw4GVqO2f5WYoab+XGQSdMNyOng==",
|
||||
"version": "2.4.0-fed4e011ee70eb36b5e2015859e719153d70b6c2",
|
||||
"resolved": "https://registry.npmjs.org/alfresco-js-api/-/alfresco-js-api-2.4.0-fed4e011ee70eb36b5e2015859e719153d70b6c2.tgz",
|
||||
"integrity": "sha512-HWA2zLbuRTi1mjIoaEW2ZSWKMDfOWcYOgplFZovQgXUOaFZuPJH1AQ7RbImq/G5/NKwe9AJSUAnkg5vpuKEBTg==",
|
||||
"requires": {
|
||||
"event-emitter": "0.3.4",
|
||||
"superagent": "3.8.2"
|
||||
@ -2400,9 +2382,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"cookiejar": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.1.tgz",
|
||||
"integrity": "sha1-Qa1XsbVVlR7BcUEqgZQrHoIA00o="
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz",
|
||||
"integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA=="
|
||||
},
|
||||
"copy-concurrently": {
|
||||
"version": "1.0.5",
|
||||
|
@ -25,8 +25,8 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@alfresco/adf-content-services": "2.4.0-beta10",
|
||||
"@alfresco/adf-core": "2.4.0-beta10",
|
||||
"@alfresco/adf-content-services": "2.4.0-24b573b08f3a072327efefc0196bd949cbca3766",
|
||||
"@alfresco/adf-core": "2.4.0-24b573b08f3a072327efefc0196bd949cbca3766",
|
||||
"@angular/animations": "5.1.1",
|
||||
"@angular/cdk": "5.0.1",
|
||||
"@angular/common": "5.1.1",
|
||||
@ -48,7 +48,7 @@
|
||||
"@ngrx/store-devtools": "^5.2.0",
|
||||
"@ngstack/electron": "0.1.0",
|
||||
"@ngx-translate/core": "9.1.1",
|
||||
"alfresco-js-api": "2.4.0-beta9",
|
||||
"alfresco-js-api": "2.4.0-fed4e011ee70eb36b5e2015859e719153d70b6c2",
|
||||
"core-js": "2.5.3",
|
||||
"cspell": "^2.1.12",
|
||||
"hammerjs": "2.0.8",
|
||||
|
@ -62,7 +62,6 @@ import { NodeMoveDirective } from './common/directives/node-move.directive';
|
||||
import { NodeRestoreDirective } from './common/directives/node-restore.directive';
|
||||
import { NodePermanentDeleteDirective } from './common/directives/node-permanent-delete.directive';
|
||||
import { NodeUnshareDirective } from './common/directives/node-unshare.directive';
|
||||
import { NodeInfoDirective } from './common/directives/node-info.directive';
|
||||
import { NodeVersionsDirective } from './common/directives/node-versions.directive';
|
||||
import { VersionManagerDialogAdapterComponent } from './components/versions-dialog/version-manager-dialog-adapter.component';
|
||||
import { BrowsingFilesService } from './common/services/browsing-files.service';
|
||||
@ -77,6 +76,7 @@ import { SortingPreferenceKeyDirective } from './directives/sorting-preference-k
|
||||
|
||||
import { INITIAL_STATE } from './store/states/app.state';
|
||||
import { appReducer } from './store/reducers/app.reducer';
|
||||
import { InfoDrawerComponent } from './components/info-drawer/info-drawer.component';
|
||||
|
||||
|
||||
@NgModule({
|
||||
@ -127,12 +127,12 @@ import { appReducer } from './store/reducers/app.reducer';
|
||||
NodeRestoreDirective,
|
||||
NodePermanentDeleteDirective,
|
||||
NodeUnshareDirective,
|
||||
NodeInfoDirective,
|
||||
NodeVersionsDirective,
|
||||
VersionManagerDialogAdapterComponent,
|
||||
SearchComponent,
|
||||
SettingsComponent,
|
||||
SortingPreferenceKeyDirective
|
||||
SortingPreferenceKeyDirective,
|
||||
InfoDrawerComponent
|
||||
],
|
||||
providers: [
|
||||
{ provide: AppConfigService, useClass: HybridAppConfigService },
|
||||
|
@ -1,121 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { ComponentFixture, TestBed, async, fakeAsync, tick } from '@angular/core/testing';
|
||||
import { AlfrescoApiService, CoreModule } from '@alfresco/adf-core';
|
||||
import { NodeInfoDirective } from './node-info.directive';
|
||||
|
||||
@Component({
|
||||
template: '<div [acaNodeInfo]="selection"></div>'
|
||||
})
|
||||
class TestComponent {
|
||||
selection;
|
||||
}
|
||||
|
||||
describe('NodeInfoDirective', () => {
|
||||
let fixture: ComponentFixture<TestComponent>;
|
||||
let component: TestComponent;
|
||||
let apiService: AlfrescoApiService;
|
||||
let nodeService;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
CoreModule
|
||||
],
|
||||
declarations: [
|
||||
TestComponent,
|
||||
NodeInfoDirective
|
||||
]
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(TestComponent);
|
||||
component = fixture.componentInstance;
|
||||
apiService = TestBed.get(AlfrescoApiService);
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
nodeService = apiService.getInstance().nodes;
|
||||
|
||||
spyOn(nodeService, 'getNodeInfo').and.returnValue(Promise.resolve({
|
||||
entry: { name: 'borg' }
|
||||
}));
|
||||
});
|
||||
|
||||
it('should not get node info onInit when selection is empty', () => {
|
||||
component.selection = [];
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(nodeService.getNodeInfo).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should get node info onInit when selection is not empty', () => {
|
||||
component.selection = [{ entry: { id: 'id' } }];
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(nodeService.getNodeInfo).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not get node info on event when selection is empty', () => {
|
||||
component.selection = [];
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
document.dispatchEvent(new CustomEvent('click'));
|
||||
|
||||
expect(nodeService.getNodeInfo).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should get node info on event from selection', () => {
|
||||
component.selection = [{ entry: { id: 'id' } }];
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
document.dispatchEvent(new CustomEvent('click'));
|
||||
|
||||
expect(nodeService.getNodeInfo).toHaveBeenCalledWith('id', { include: [ 'allowableOperations' ] });
|
||||
});
|
||||
|
||||
|
||||
it('should get node info of last entry when selecting multiple nodes', fakeAsync(() => {
|
||||
component.selection = [
|
||||
{ entry: { id: 'id1', isFile: true } },
|
||||
{ entry: { id: 'id2', isFile: true } },
|
||||
{ entry: { id: 'id3', isFile: true } }
|
||||
];
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
document.dispatchEvent(new CustomEvent('click'));
|
||||
|
||||
fixture.detectChanges();
|
||||
tick();
|
||||
|
||||
expect(nodeService.getNodeInfo).toHaveBeenCalledWith('id3', { include: [ 'allowableOperations' ] });
|
||||
}));
|
||||
});
|
@ -1,83 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Directive, HostListener, Input, Output, EventEmitter, OnInit } from '@angular/core';
|
||||
import { AlfrescoApiService } from '@alfresco/adf-core';
|
||||
import { MinimalNodeEntity, MinimalNodeEntryEntity } from 'alfresco-js-api';
|
||||
|
||||
@Directive({
|
||||
selector: '[acaNodeInfo]',
|
||||
exportAs: 'nodeInfo'
|
||||
})
|
||||
|
||||
export class NodeInfoDirective implements OnInit {
|
||||
// tslint:disable-next-line:no-input-rename
|
||||
@Input('acaNodeInfo') selection: MinimalNodeEntity[];
|
||||
@Output() changed: EventEmitter<null|MinimalNodeEntryEntity> = new EventEmitter<null|MinimalNodeEntryEntity>();
|
||||
@Output() error: EventEmitter<null> = new EventEmitter<null>();
|
||||
|
||||
node: MinimalNodeEntryEntity;
|
||||
loading: boolean = null;
|
||||
|
||||
@HostListener('document:node-click', ['$event'])
|
||||
onClick(event) {
|
||||
this.getNodeInfo();
|
||||
}
|
||||
|
||||
constructor(private apiService: AlfrescoApiService) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.getNodeInfo();
|
||||
}
|
||||
|
||||
getNodeInfo() {
|
||||
if (!this.selection.length) {
|
||||
this.node = null;
|
||||
this.loading = false;
|
||||
this.changed.emit(null);
|
||||
return;
|
||||
}
|
||||
|
||||
const node = this.selection[this.selection.length - 1];
|
||||
|
||||
if (node) {
|
||||
this.loading = true;
|
||||
|
||||
this.apiService.getInstance().nodes
|
||||
.getNodeInfo((<any>node.entry).nodeId || node.entry.id, {
|
||||
include: ['allowableOperations']
|
||||
})
|
||||
.then((data: MinimalNodeEntryEntity) => {
|
||||
this.node = data;
|
||||
this.changed.emit(data);
|
||||
this.loading = false;
|
||||
})
|
||||
.catch(() => {
|
||||
this.error.emit();
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -31,6 +31,7 @@ import { AlfrescoApiService, TranslationService, NotificationService, CoreModule
|
||||
|
||||
import { NodePermanentDeleteDirective } from './node-permanent-delete.directive';
|
||||
import { MatDialogModule, MatDialog } from '@angular/material';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
@Component({
|
||||
template: `<div [app-permanent-delete-node]="selection"></div>`
|
||||
@ -53,6 +54,7 @@ describe('NodePermanentDeleteDirective', () => {
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
NoopAnimationsModule,
|
||||
CoreModule,
|
||||
MatDialogModule
|
||||
],
|
||||
@ -69,7 +71,10 @@ describe('NodePermanentDeleteDirective', () => {
|
||||
directiveInstance = element.injector.get(NodePermanentDeleteDirective);
|
||||
|
||||
dialog = TestBed.get(MatDialog);
|
||||
|
||||
alfrescoService = TestBed.get(AlfrescoApiService);
|
||||
alfrescoService.reset();
|
||||
|
||||
translation = TestBed.get(TranslationService);
|
||||
notificationService = TestBed.get(NotificationService);
|
||||
});
|
||||
|
@ -33,7 +33,7 @@ import { Observable } from 'rxjs/Rx';
|
||||
import { AlfrescoApiService, TranslationService, NotificationService, CoreModule } from '@alfresco/adf-core';
|
||||
|
||||
import { NodeRestoreDirective } from './node-restore.directive';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
@Component({
|
||||
template: `<div [acaRestoreNode]="selection"></div>`
|
||||
@ -57,7 +57,7 @@ describe('NodeRestoreDirective', () => {
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
BrowserAnimationsModule,
|
||||
NoopAnimationsModule,
|
||||
RouterTestingModule,
|
||||
CoreModule
|
||||
],
|
||||
@ -74,6 +74,8 @@ describe('NodeRestoreDirective', () => {
|
||||
directiveInstance = element.injector.get(NodeRestoreDirective);
|
||||
|
||||
alfrescoService = TestBed.get(AlfrescoApiService);
|
||||
alfrescoService.reset();
|
||||
|
||||
translation = TestBed.get(TranslationService);
|
||||
notificationService = TestBed.get(NotificationService);
|
||||
router = TestBed.get(Router);
|
||||
|
@ -26,7 +26,7 @@
|
||||
import { Directive, EventEmitter, HostListener, Input, Output } from '@angular/core';
|
||||
|
||||
import { TranslationService, NotificationService, AlfrescoApiService } from '@alfresco/adf-core';
|
||||
import { MinimalNodeEntity } from 'alfresco-js-api';
|
||||
import { MinimalNodeEntity, MinimalNodeEntryEntity } from 'alfresco-js-api';
|
||||
|
||||
import { VersionManagerDialogAdapterComponent } from '../../components/versions-dialog/version-manager-dialog-adapter.component';
|
||||
import { MatDialog } from '@angular/material';
|
||||
@ -38,7 +38,7 @@ export class NodeVersionsDirective {
|
||||
|
||||
// tslint:disable-next-line:no-input-rename
|
||||
@Input('acaNodeVersions')
|
||||
selection: MinimalNodeEntity[];
|
||||
node: MinimalNodeEntity;
|
||||
|
||||
@Output()
|
||||
nodeVersionError: EventEmitter<any> = new EventEmitter();
|
||||
@ -55,17 +55,23 @@ export class NodeVersionsDirective {
|
||||
private translation: TranslationService
|
||||
) {}
|
||||
|
||||
onManageVersions() {
|
||||
const contentEntry = this.selection[0].entry;
|
||||
const nodeId = (<any>contentEntry).nodeId;
|
||||
|
||||
this.apiService.getInstance().nodes.getNodeInfo(nodeId || contentEntry.id, {
|
||||
include: ['allowableOperations']
|
||||
}).then(entry => this.openVersionManagerDialog(entry));
|
||||
async onManageVersions() {
|
||||
if (this.node && this.node.entry) {
|
||||
let entry = this.node.entry;
|
||||
|
||||
if (entry.nodeId) {
|
||||
entry = await this.apiService.nodesApi.getNodeInfo(
|
||||
entry.nodeId,
|
||||
{ include: ['allowableOperations'] }
|
||||
);
|
||||
this.openVersionManagerDialog(entry);
|
||||
} else {
|
||||
this.openVersionManagerDialog(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
openVersionManagerDialog(contentEntry) {
|
||||
openVersionManagerDialog(contentEntry: MinimalNodeEntryEntity) {
|
||||
if (contentEntry.isFile) {
|
||||
this.dialog.open(
|
||||
VersionManagerDialogAdapterComponent,
|
||||
|
@ -3,39 +3,37 @@
|
||||
<adf-breadcrumb root="APP.BROWSE.FAVORITES.TITLE">
|
||||
</adf-breadcrumb>
|
||||
|
||||
<adf-toolbar class="inline">
|
||||
<adf-toolbar class="inline" *ngIf="hasSelection">
|
||||
|
||||
<button
|
||||
mat-icon-button
|
||||
color="primary"
|
||||
*ngIf="isFileSelected(documentList.selection)"
|
||||
*ngIf="firstSelectedDocument"
|
||||
title="{{ 'APP.ACTIONS.VIEW' | translate }}"
|
||||
(click)="onNodeDoubleClick(documentList.selection[0]?.entry)">
|
||||
(click)="showPreview(firstSelectedDocument)">
|
||||
<mat-icon>open_in_browser</mat-icon>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-icon-button
|
||||
color="primary"
|
||||
*ngIf="hasSelection(documentList.selection)"
|
||||
title="{{ 'APP.ACTIONS.DOWNLOAD' | translate }}"
|
||||
[adfNodeDownload]="documentList.selection">
|
||||
[adfNodeDownload]="selectedNodes">
|
||||
<mat-icon>get_app</mat-icon>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-icon-button
|
||||
color="primary"
|
||||
*ngIf="showEditOption(documentList.selection)"
|
||||
*ngIf="firstSelectedFolder"
|
||||
[attr.title]="'APP.ACTIONS.EDIT' | translate"
|
||||
(error)="openSnackMessage($event)"
|
||||
[adf-edit-folder]="documentList.selection[0]?.entry">
|
||||
[adf-edit-folder]="firstSelectedFolder?.entry">
|
||||
<mat-icon>create</mat-icon>
|
||||
</button>
|
||||
|
||||
<button mat-icon-button
|
||||
[color]="infoDrawerOpened ? 'accent' : 'primary'"
|
||||
*ngIf="hasSelection(documentList.selection)"
|
||||
title="{{ 'APP.ACTIONS.DETAILS' | translate }}"
|
||||
(click)="toggleSidebar()">
|
||||
<mat-icon>info_outline</mat-icon>
|
||||
@ -44,7 +42,6 @@
|
||||
<button
|
||||
color="primary"
|
||||
mat-icon-button
|
||||
*ngIf="hasSelection(documentList.selection)"
|
||||
title="{{ 'APP.ACTIONS.MORE' | translate }}"
|
||||
[matMenuTriggerFor]="actionsMenu">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
@ -55,7 +52,7 @@
|
||||
mat-menu-item
|
||||
#selection="adfFavorite"
|
||||
(toggle)="reload()"
|
||||
[adf-node-favorite]="documentList.selection">
|
||||
[adf-node-favorite]="selectedNodes">
|
||||
<mat-icon color="primary" *ngIf="selection.hasFavorites()">star</mat-icon>
|
||||
<mat-icon *ngIf="!selection.hasFavorites()">star_border</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.FAVORITE' | translate }}</span>
|
||||
@ -63,29 +60,29 @@
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
[acaCopyNode]="documentList.selection">
|
||||
[acaCopyNode]="selectedNodes">
|
||||
<mat-icon>content_copy</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.COPY' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
[acaMoveNode]="documentList.selection">
|
||||
[acaMoveNode]="selectedNodes">
|
||||
<mat-icon>library_books</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.MOVE' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
[acaDeleteNode]="documentList.selection">
|
||||
[acaDeleteNode]="selectedNodes">
|
||||
<mat-icon>delete</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.DELETE' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="isFileSelected(documentList.selection)"
|
||||
[acaNodeVersions]="documentList.selection">
|
||||
*ngIf="firstSelectedDocument"
|
||||
[acaNodeVersions]="firstSelectedDocument">
|
||||
<mat-icon>history</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.VERSIONS' | translate }}</span>
|
||||
</button>
|
||||
@ -100,7 +97,10 @@
|
||||
[navigate]="false"
|
||||
[sorting]="[ 'modifiedAt', 'desc' ]"
|
||||
[acaSortingPreferenceKey]="sortingPreferenceKey"
|
||||
(node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)">
|
||||
(node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)"
|
||||
(ready)="onDocumentListReady($event, documentList)"
|
||||
(node-select)="onNodeSelect($event, documentList)"
|
||||
(node-unselect)="onNodeUnselect($event, documentList)">
|
||||
|
||||
<empty-folder-content>
|
||||
<ng-template>
|
||||
@ -168,39 +168,8 @@
|
||||
</adf-pagination>
|
||||
</div>
|
||||
|
||||
<div class="inner-layout__side-panel"
|
||||
*ngIf="infoDrawerOpened"
|
||||
[acaNodeInfo]="documentList.selection"
|
||||
(changed)="toggleSidebar($event)"
|
||||
#infoInstance=nodeInfo>
|
||||
|
||||
<adf-info-drawer [title]="'APP.INFO_DRAWER.TITLE' | translate">
|
||||
<adf-info-drawer-tab [label]="'APP.INFO_DRAWER.TABS.PROPERTIES' | translate">
|
||||
<div *ngIf="infoInstance.loading">
|
||||
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
|
||||
</div>
|
||||
|
||||
<adf-content-metadata-card
|
||||
[readOnly]="!permission.check(infoInstance.node, ['update'])"
|
||||
[displayEmpty]="permission.check(infoInstance.node, ['update'])"
|
||||
[preset]="'custom'"
|
||||
[node]="infoInstance.node">
|
||||
</adf-content-metadata-card>
|
||||
</adf-info-drawer-tab>
|
||||
|
||||
<adf-info-drawer-tab [label]="'APP.INFO_DRAWER.TABS.VERSIONS' | translate">
|
||||
<ng-container *ngIf="infoInstance.node?.isFile;else choose_document_template">
|
||||
<adf-version-manager [node]="infoInstance.node"></adf-version-manager>
|
||||
</ng-container>
|
||||
|
||||
<ng-template #choose_document_template>
|
||||
<div class="adf-manage-versions-empty">
|
||||
<mat-icon class="adf-manage-versions-empty-icon">face</mat-icon>
|
||||
{{ 'VERSION.SELECTION.EMPTY' | translate }}
|
||||
</div>
|
||||
</ng-template>
|
||||
</adf-info-drawer-tab>
|
||||
</adf-info-drawer>
|
||||
<div class="inner-layout__side-panel" *ngIf="infoDrawerOpened">
|
||||
<aca-info-drawer [node]="lastSelectedNode"></aca-info-drawer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -44,10 +44,12 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material';
|
||||
import { DocumentListService } from '@alfresco/adf-content-services';
|
||||
import { ContentManagementService } from '../../common/services/content-management.service';
|
||||
import { NodeInfoDirective } from '../../common/directives/node-info.directive';
|
||||
import { NodePermissionService } from '../../common/services/node-permission.service';
|
||||
|
||||
import { FavoritesComponent } from './favorites.component';
|
||||
import { StoreModule } from '@ngrx/store';
|
||||
import { appReducer } from '../../store/reducers/app.reducer';
|
||||
import { INITIAL_STATE } from '../../store/states/app.state';
|
||||
|
||||
describe('Favorites Routed Component', () => {
|
||||
let fixture: ComponentFixture<FavoritesComponent>;
|
||||
@ -95,14 +97,14 @@ describe('Favorites Routed Component', () => {
|
||||
HttpClientModule,
|
||||
TranslateModule.forRoot(),
|
||||
RouterTestingModule,
|
||||
MatSnackBarModule, MatIconModule
|
||||
MatSnackBarModule, MatIconModule,
|
||||
StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE })
|
||||
],
|
||||
declarations: [
|
||||
DataTableComponent,
|
||||
TimeAgoPipe,
|
||||
NodeNameTooltipPipe,
|
||||
NodeFavoriteDirective,
|
||||
NodeInfoDirective,
|
||||
DocumentListComponent,
|
||||
FavoritesComponent,
|
||||
AppConfigPipe
|
||||
@ -232,56 +234,6 @@ describe('Favorites Routed Component', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('edit option', () => {
|
||||
it('should return false if a file node is selected', () => {
|
||||
const selection = [
|
||||
{
|
||||
entry: {
|
||||
isFolder: false,
|
||||
isFile: true
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
const result = component.showEditOption(selection);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false if multiple nodes are selected', () => {
|
||||
const selection = [
|
||||
{
|
||||
entry: {
|
||||
isFolder: true,
|
||||
isFile: false
|
||||
}
|
||||
},
|
||||
{
|
||||
entry: {
|
||||
isFolder: true,
|
||||
isFile: false
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
const result = component.showEditOption(selection);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true if selected node is a folder', () => {
|
||||
const selection = [
|
||||
{
|
||||
entry: {
|
||||
isFolder: true,
|
||||
isFile: false
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
const result = component.showEditOption(selection);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('refresh', () => {
|
||||
it('should call document list reload', () => {
|
||||
spyOn(component.documentList, 'reload');
|
||||
|
@ -25,30 +25,35 @@
|
||||
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router, ActivatedRoute } from '@angular/router';
|
||||
import { MinimalNodeEntryEntity, MinimalNodeEntity, PathElementEntity, PathInfo } from 'alfresco-js-api';
|
||||
import { MinimalNodeEntryEntity, PathElementEntity, PathInfo } from 'alfresco-js-api';
|
||||
import { ContentService, NodesApiService, UserPreferencesService, NotificationService } from '@alfresco/adf-core';
|
||||
|
||||
import { ContentManagementService } from '../../common/services/content-management.service';
|
||||
import { NodePermissionService } from '../../common/services/node-permission.service';
|
||||
import { PageComponent } from '../page.component';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AcaState } from '../../store/states/app.state';
|
||||
|
||||
@Component({
|
||||
templateUrl: './favorites.component.html'
|
||||
})
|
||||
export class FavoritesComponent extends PageComponent implements OnInit {
|
||||
|
||||
constructor(private router: Router,
|
||||
constructor(router: Router,
|
||||
route: ActivatedRoute,
|
||||
store: Store<AcaState>,
|
||||
private nodesApi: NodesApiService,
|
||||
private contentService: ContentService,
|
||||
private content: ContentManagementService,
|
||||
private notificationService: NotificationService,
|
||||
public permission: NodePermissionService,
|
||||
preferences: UserPreferencesService) {
|
||||
super(preferences, route);
|
||||
super(preferences, router, route, store);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
super.ngOnInit();
|
||||
|
||||
this.subscriptions = this.subscriptions.concat([
|
||||
this.content.nodeDeleted.subscribe(() => this.reload()),
|
||||
this.content.nodeRestored.subscribe(() => this.reload()),
|
||||
@ -87,10 +92,6 @@ export class FavoritesComponent extends PageComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
showEditOption(selection: MinimalNodeEntity[]) {
|
||||
return selection && selection.length === 1 && selection[0].entry.isFolder;
|
||||
}
|
||||
|
||||
openSnackMessage(event: any) {
|
||||
this.notificationService.openSnackMessage(
|
||||
event,
|
||||
|
@ -6,39 +6,36 @@
|
||||
(navigate)="onBreadcrumbNavigate($event)">
|
||||
</adf-breadcrumb>
|
||||
|
||||
<adf-toolbar class="inline">
|
||||
<adf-toolbar class="inline" *ngIf="hasSelection">
|
||||
<button
|
||||
color="primary"
|
||||
mat-icon-button
|
||||
*ngIf="isFileSelected(documentList.selection)"
|
||||
*ngIf="firstSelectedDocument"
|
||||
title="{{ 'APP.ACTIONS.VIEW' | translate }}"
|
||||
(click)="showPreview(documentList.selection[0]?.entry)">
|
||||
(click)="showPreview(firstSelectedDocument)">
|
||||
<mat-icon>open_in_browser</mat-icon>
|
||||
</button>
|
||||
|
||||
<button
|
||||
color="primary"
|
||||
mat-icon-button
|
||||
*ngIf="hasSelection(documentList.selection)"
|
||||
title="{{ 'APP.ACTIONS.DOWNLOAD' | translate }}"
|
||||
[adfNodeDownload]="documentList.selection">
|
||||
[adfNodeDownload]="selectedNodes">
|
||||
<mat-icon>get_app</mat-icon>
|
||||
</button>
|
||||
|
||||
<button
|
||||
color="primary"
|
||||
mat-icon-button
|
||||
*ngIf="isFolderSelected(documentList.selection)
|
||||
&& permission.check(documentList.selection, ['update'])"
|
||||
*ngIf="firstSelectedFolder && permission.check(firstSelectedFolder, ['update'])"
|
||||
[attr.title]="'APP.ACTIONS.EDIT' | translate"
|
||||
(error)="openSnackMessage($event)"
|
||||
[adf-edit-folder]="documentList.selection[0]?.entry">
|
||||
[adf-edit-folder]="firstSelectedFolder?.entry">
|
||||
<mat-icon>create</mat-icon>
|
||||
</button>
|
||||
|
||||
<button mat-icon-button
|
||||
[color]="infoDrawerOpened ? 'accent' : 'primary'"
|
||||
*ngIf="hasSelection(documentList.selection)"
|
||||
title="{{ 'APP.ACTIONS.DETAILS' | translate }}"
|
||||
(click)="toggleSidebar()">
|
||||
<mat-icon>info_outline</mat-icon>
|
||||
@ -47,7 +44,6 @@
|
||||
<button
|
||||
color="primary"
|
||||
mat-icon-button
|
||||
*ngIf="hasSelection(documentList.selection)"
|
||||
title="{{ 'APP.ACTIONS.MORE' | translate }}"
|
||||
[matMenuTriggerFor]="actionsMenu">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
@ -58,7 +54,7 @@
|
||||
<button
|
||||
mat-menu-item
|
||||
#selection="adfFavorite"
|
||||
[adf-node-favorite]="documentList.selection">
|
||||
[adf-node-favorite]="selectedNodes">
|
||||
<mat-icon color="primary" *ngIf="selection.hasFavorites()">star</mat-icon>
|
||||
<mat-icon *ngIf="!selection.hasFavorites()">star_border</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.FAVORITE' | translate }}</span>
|
||||
@ -66,31 +62,31 @@
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
[acaCopyNode]="documentList.selection">
|
||||
[acaCopyNode]="selectedNodes">
|
||||
<mat-icon>content_copy</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.COPY' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="permission.check(documentList.selection, ['delete'])"
|
||||
[acaMoveNode]="documentList.selection">
|
||||
*ngIf="permission.check(selectedNodes, ['delete'])"
|
||||
[acaMoveNode]="selectedNodes">
|
||||
<mat-icon>library_books</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.MOVE' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="permission.check(documentList.selection, ['delete'])"
|
||||
[acaDeleteNode]="documentList.selection">
|
||||
*ngIf="permission.check(selectedNodes, ['delete'])"
|
||||
[acaDeleteNode]="selectedNodes">
|
||||
<mat-icon>delete</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.DELETE' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="isFileSelected(documentList.selection)"
|
||||
[acaNodeVersions]="documentList.selection">
|
||||
*ngIf="firstSelectedDocument"
|
||||
[acaNodeVersions]="firstSelectedDocument">
|
||||
<mat-icon>history</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.VERSIONS' | translate }}</span>
|
||||
</button>
|
||||
@ -117,7 +113,9 @@
|
||||
[navigate]="false"
|
||||
[imageResolver]="imageResolver"
|
||||
(node-dblclick)="onNodeDoubleClick($event)"
|
||||
(node-select)="onNodeSelect($event, documentList)">
|
||||
(ready)="onDocumentListReady($event, documentList)"
|
||||
(node-select)="onNodeSelect($event, documentList)"
|
||||
(node-unselect)="onNodeUnselect($event, documentList)">
|
||||
|
||||
<data-columns>
|
||||
<data-column
|
||||
@ -168,41 +166,8 @@
|
||||
</adf-upload-drag-area>
|
||||
</div>
|
||||
|
||||
<div class="inner-layout__side-panel"
|
||||
*ngIf="infoDrawerOpened"
|
||||
[acaNodeInfo]="documentList.selection"
|
||||
(changed)="toggleSidebar($event)"
|
||||
#infoInstance=nodeInfo>
|
||||
|
||||
<adf-info-drawer [title]="'APP.INFO_DRAWER.TITLE' | translate">
|
||||
<adf-info-drawer-tab [label]="'APP.INFO_DRAWER.TABS.PROPERTIES' | translate">
|
||||
<div *ngIf="infoInstance.loading">
|
||||
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
|
||||
</div>
|
||||
|
||||
<adf-content-metadata-card
|
||||
[readOnly]="!permission.check(infoInstance.node, ['update'])"
|
||||
[displayEmpty]="permission.check(infoInstance.node, ['update'])"
|
||||
[preset]="'custom'"
|
||||
[node]="infoInstance.node">
|
||||
</adf-content-metadata-card>
|
||||
</adf-info-drawer-tab>
|
||||
|
||||
<adf-info-drawer-tab [label]="'APP.INFO_DRAWER.TABS.VERSIONS' | translate">
|
||||
<ng-container *ngIf="isFileSelected(documentList.selection);else choose_document_template">
|
||||
<adf-version-manager
|
||||
*ngIf="infoInstance.node"
|
||||
[node]="infoInstance.node">
|
||||
</adf-version-manager>
|
||||
</ng-container>
|
||||
<ng-template #choose_document_template>
|
||||
<div class="adf-manage-versions-empty">
|
||||
<mat-icon class="adf-manage-versions-empty-icon">face</mat-icon>
|
||||
{{ 'VERSION.SELECTION.EMPTY' | translate }}
|
||||
</div>
|
||||
</ng-template>
|
||||
</adf-info-drawer-tab>
|
||||
</adf-info-drawer>
|
||||
<div class="inner-layout__side-panel" *ngIf="infoDrawerOpened">
|
||||
<aca-info-drawer [node]="lastSelectedNode"></aca-info-drawer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -46,9 +46,11 @@ import { ContentManagementService } from '../../common/services/content-manageme
|
||||
import { BrowsingFilesService } from '../../common/services/browsing-files.service';
|
||||
import { NodeActionsService } from '../../common/services/node-actions.service';
|
||||
import { NodePermissionService } from '../../common/services/node-permission.service';
|
||||
import { NodeInfoDirective } from '../../common/directives/node-info.directive';
|
||||
|
||||
import { FilesComponent } from './files.component';
|
||||
import { StoreModule } from '@ngrx/store';
|
||||
import { appReducer } from '../../store/reducers/app.reducer';
|
||||
import { INITIAL_STATE } from '../../store/states/app.state';
|
||||
|
||||
describe('FilesComponent', () => {
|
||||
let node;
|
||||
@ -73,7 +75,8 @@ describe('FilesComponent', () => {
|
||||
TranslateModule.forRoot(),
|
||||
RouterTestingModule,
|
||||
MatSnackBarModule, MatIconModule,
|
||||
MatDialogModule
|
||||
MatDialogModule,
|
||||
StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE })
|
||||
],
|
||||
declarations: [
|
||||
FilesComponent,
|
||||
@ -81,7 +84,6 @@ describe('FilesComponent', () => {
|
||||
TimeAgoPipe,
|
||||
NodeNameTooltipPipe,
|
||||
NodeFavoriteDirective,
|
||||
NodeInfoDirective,
|
||||
DocumentListComponent,
|
||||
FileSizePipe,
|
||||
AppConfigPipe
|
||||
|
@ -38,6 +38,8 @@ import { NodeActionsService } from '../../common/services/node-actions.service';
|
||||
import { NodePermissionService } from '../../common/services/node-permission.service';
|
||||
|
||||
import { PageComponent } from '../page.component';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AcaState } from '../../store/states/app.state';
|
||||
|
||||
@Component({
|
||||
templateUrl: './files.component.html'
|
||||
@ -48,8 +50,9 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy {
|
||||
|
||||
private nodePath: PathElement[];
|
||||
|
||||
constructor(private router: Router,
|
||||
constructor(router: Router,
|
||||
route: ActivatedRoute,
|
||||
store: Store<AcaState>,
|
||||
private nodesApi: NodesApiService,
|
||||
private nodeActionsService: NodeActionsService,
|
||||
private uploadService: UploadService,
|
||||
@ -60,10 +63,12 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy {
|
||||
private notificationService: NotificationService,
|
||||
public permission: NodePermissionService,
|
||||
preferences: UserPreferencesService) {
|
||||
super(preferences, route);
|
||||
super(preferences, router, route, store);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
super.ngOnInit();
|
||||
|
||||
const { route, contentManagementService, contentService, nodeActionsService, uploadService } = this;
|
||||
const { data } = route.snapshot;
|
||||
|
||||
@ -156,14 +161,6 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
showPreview(node: MinimalNodeEntryEntity) {
|
||||
if (node) {
|
||||
if (node.isFile) {
|
||||
this.router.navigate(['./preview', node.id], { relativeTo: this.route });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onBreadcrumbNavigate(route: PathElementEntity) {
|
||||
// todo: review this approach once 5.2.3 is out
|
||||
if (this.nodePath && this.nodePath.length > 2) {
|
||||
|
@ -50,7 +50,7 @@ describe('HeaderComponent', () => {
|
||||
HttpClientModule,
|
||||
RouterTestingModule,
|
||||
TranslateModule.forRoot(),
|
||||
StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE }),
|
||||
StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE })
|
||||
],
|
||||
declarations: [
|
||||
HeaderComponent
|
||||
|
28
src/app/components/info-drawer/info-drawer.component.html
Normal file
28
src/app/components/info-drawer/info-drawer.component.html
Normal file
@ -0,0 +1,28 @@
|
||||
<div *ngIf="isLoading">
|
||||
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
|
||||
</div>
|
||||
<ng-container *ngIf="node">
|
||||
<adf-info-drawer [title]="'APP.INFO_DRAWER.TITLE' | translate">
|
||||
<adf-info-drawer-tab [label]="'APP.INFO_DRAWER.TABS.PROPERTIES' | translate">
|
||||
<adf-content-metadata-card
|
||||
[readOnly]="!canUpdateNode()"
|
||||
[displayEmpty]="canUpdateNode()"
|
||||
[preset]="'custom'"
|
||||
[node]="displayNode">
|
||||
</adf-content-metadata-card>
|
||||
</adf-info-drawer-tab>
|
||||
|
||||
<adf-info-drawer-tab [label]="'APP.INFO_DRAWER.TABS.VERSIONS' | translate">
|
||||
<ng-container *ngIf="isFileSelected;else empty">
|
||||
<adf-version-manager [node]="displayNode"></adf-version-manager>
|
||||
</ng-container>
|
||||
|
||||
<ng-template #empty>
|
||||
<div class="adf-manage-versions-empty">
|
||||
<mat-icon class="adf-manage-versions-empty-icon">face</mat-icon>
|
||||
{{ 'VERSION.SELECTION.EMPTY' | translate }}
|
||||
</div>
|
||||
</ng-template>
|
||||
</adf-info-drawer-tab>
|
||||
</adf-info-drawer>
|
||||
</ng-container>
|
94
src/app/components/info-drawer/info-drawer.component.ts
Normal file
94
src/app/components/info-drawer/info-drawer.component.ts
Normal file
@ -0,0 +1,94 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
|
||||
import { MinimalNodeEntity, MinimalNodeEntryEntity } from 'alfresco-js-api';
|
||||
import { NodePermissionService } from '../../common/services/node-permission.service';
|
||||
import { AlfrescoApiService } from '@alfresco/adf-core';
|
||||
|
||||
@Component({
|
||||
selector: 'aca-info-drawer',
|
||||
templateUrl: './info-drawer.component.html'
|
||||
})
|
||||
export class InfoDrawerComponent implements OnChanges {
|
||||
@Input() nodeId: string;
|
||||
|
||||
@Input() node: MinimalNodeEntity;
|
||||
|
||||
isLoading = false;
|
||||
displayNode: MinimalNodeEntryEntity;
|
||||
|
||||
canUpdateNode(): boolean {
|
||||
if (this.node) {
|
||||
if ((<any>this.node.entry).nodeId) {
|
||||
return this.permission.check(this.node.entry, ['update'], {
|
||||
target: 'allowableOperationsOnTarget'
|
||||
});
|
||||
}
|
||||
return this.permission.check(this.node.entry, ['update']);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
get isFileSelected(): boolean {
|
||||
if (this.node && this.node.entry) {
|
||||
return this.node.entry.isFile;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
constructor(
|
||||
public permission: NodePermissionService,
|
||||
private apiService: AlfrescoApiService
|
||||
) {}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (this.node) {
|
||||
const entry = this.node.entry;
|
||||
if (entry.nodeId) {
|
||||
this.loadNodeInfo(entry.nodeId);
|
||||
} else {
|
||||
this.displayNode = this.node.entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private loadNodeInfo(nodeId: string) {
|
||||
if (nodeId) {
|
||||
this.isLoading = true;
|
||||
|
||||
this.apiService.nodesApi
|
||||
.getNodeInfo(nodeId, { include: ['allowableOperations'] })
|
||||
.then((entity: MinimalNodeEntryEntity) => {
|
||||
this.displayNode = entity;
|
||||
this.isLoading = false;
|
||||
})
|
||||
.catch(() => {
|
||||
this.isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -14,6 +14,9 @@
|
||||
[navigate]="false"
|
||||
[sorting]="[ 'title', 'asc' ]"
|
||||
[acaSortingPreferenceKey]="sortingPreferenceKey"
|
||||
(ready)="onDocumentListReady($event, documentList)"
|
||||
(node-select)="onNodeSelect($event, documentList)"
|
||||
(node-unselect)="onNodeUnselect($event, documentList)"
|
||||
(node-dblclick)="onNodeDoubleClick($event)">
|
||||
|
||||
<empty-folder-content>
|
||||
|
@ -44,6 +44,9 @@ import { DocumentListService } from '@alfresco/adf-content-services';
|
||||
import { ShareDataTableAdapter } from '@alfresco/adf-content-services';
|
||||
|
||||
import { LibrariesComponent } from './libraries.component';
|
||||
import { StoreModule } from '@ngrx/store';
|
||||
import { appReducer } from '../../store/reducers/app.reducer';
|
||||
import { INITIAL_STATE } from '../../store/states/app.state';
|
||||
|
||||
describe('Libraries Routed Component', () => {
|
||||
let fixture: ComponentFixture<LibrariesComponent>;
|
||||
@ -78,7 +81,8 @@ describe('Libraries Routed Component', () => {
|
||||
HttpClientModule,
|
||||
TranslateModule.forRoot(),
|
||||
RouterTestingModule,
|
||||
MatSnackBarModule, MatIconModule
|
||||
MatSnackBarModule, MatIconModule,
|
||||
StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE })
|
||||
],
|
||||
declarations: [
|
||||
DataTableComponent,
|
||||
|
@ -29,6 +29,8 @@ import { NodesApiService, UserPreferencesService } from '@alfresco/adf-core';
|
||||
import { ShareDataRow } from '@alfresco/adf-content-services';
|
||||
|
||||
import { PageComponent } from '../page.component';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AcaState } from '../../store/states/app.state';
|
||||
|
||||
@Component({
|
||||
templateUrl: './libraries.component.html'
|
||||
@ -37,9 +39,10 @@ export class LibrariesComponent extends PageComponent {
|
||||
|
||||
constructor(private nodesApi: NodesApiService,
|
||||
route: ActivatedRoute,
|
||||
private router: Router,
|
||||
store: Store<AcaState>,
|
||||
router: Router,
|
||||
preferences: UserPreferencesService) {
|
||||
super(preferences, route);
|
||||
super(preferences, router, route, store);
|
||||
}
|
||||
|
||||
makeLibraryTooltip(library: any): string {
|
||||
|
@ -24,17 +24,22 @@
|
||||
*/
|
||||
|
||||
import { PageComponent } from './page.component';
|
||||
import { MinimalNodeEntity } from 'alfresco-js-api';
|
||||
|
||||
class TestClass extends PageComponent {
|
||||
node: any;
|
||||
|
||||
setSelection(selection: MinimalNodeEntity[] = []) {
|
||||
this.onSelectionChanged(selection);
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super(null, null);
|
||||
super(null, null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
describe('PageComponent', () => {
|
||||
let component;
|
||||
let component: TestClass;
|
||||
|
||||
beforeEach(() => {
|
||||
component = new TestClass();
|
||||
@ -56,47 +61,44 @@ describe('PageComponent', () => {
|
||||
|
||||
describe('hasSelection()', () => {
|
||||
it('returns true when it has nodes selected', () => {
|
||||
const hasSelection = component.hasSelection([ {}, {} ]);
|
||||
expect(hasSelection).toBe(true);
|
||||
component.setSelection([
|
||||
{ entry: { isFile: true } },
|
||||
{ entry: { isFile: true } }
|
||||
]);
|
||||
expect(component.hasSelection).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false when it has no selections', () => {
|
||||
const hasSelection = component.hasSelection([]);
|
||||
expect(hasSelection).toBe(false);
|
||||
component.setSelection([]);
|
||||
expect(component.hasSelection).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isFileSelected()', () => {
|
||||
describe('firstSelectedDocument', () => {
|
||||
it('returns true if selected node is file', () => {
|
||||
const selection = [ { entry: { isFile: true } } ];
|
||||
expect(component.isFileSelected(selection)).toBe(true);
|
||||
component.setSelection(selection);
|
||||
expect(component.firstSelectedDocument).toBe(selection[0]);
|
||||
});
|
||||
|
||||
it('returns false if selected node is folder', () => {
|
||||
const selection = [ { entry: { isFolder: true } } ];
|
||||
expect(component.isFileSelected(selection)).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false if there are more than one selections', () => {
|
||||
const selection = [ { entry: { isFile: true } }, { entry: { isFile: true } } ];
|
||||
expect(component.isFileSelected(selection)).toBe(false);
|
||||
const selection = [ { entry: { isFile: false, isFolder: true } } ];
|
||||
component.setSelection(selection);
|
||||
expect(component.firstSelectedDocument).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('isFolderSelected()', () => {
|
||||
describe('firstSelectedFolder', () => {
|
||||
it('returns true if selected node is folder', () => {
|
||||
const selection = [ { entry: { isFolder: true } } ];
|
||||
expect(component.isFolderSelected(selection)).toBe(true);
|
||||
const selection = [ { entry: { isFile: false, isFolder: true } } ];
|
||||
component.setSelection(selection);
|
||||
expect(component.firstSelectedFolder).toBe(selection[0]);
|
||||
});
|
||||
|
||||
it('returns false if selected node is file', () => {
|
||||
const selection = [ { entry: { isFile: true } } ];
|
||||
expect(component.isFolderSelected(selection)).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false if there are more than one selections', () => {
|
||||
const selection = [ { entry: { isFolder: true } }, { entry: { isFolder: true } } ];
|
||||
expect(component.isFolderSelected(selection)).toBe(false);
|
||||
const selection = [ { entry: { isFile: true, isFolder: false } } ];
|
||||
component.setSelection(selection);
|
||||
expect(component.firstSelectedFolder).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -26,11 +26,18 @@
|
||||
import { MinimalNodeEntity, MinimalNodeEntryEntity, Pagination } from 'alfresco-js-api';
|
||||
import { UserPreferencesService } from '@alfresco/adf-core';
|
||||
import { ShareDataRow, DocumentListComponent } from '@alfresco/adf-content-services';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { OnDestroy, ViewChild } from '@angular/core';
|
||||
import { Subscription } from 'rxjs/Rx';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { OnDestroy, ViewChild, OnInit } from '@angular/core';
|
||||
import { Subscription, Subject } from 'rxjs/Rx';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AcaState } from '../store/states/app.state';
|
||||
import { SetSelectedNodesAction } from '../store/actions/select-nodes.action';
|
||||
import { selectedNodes } from '../store/selectors/app.selectors';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
export abstract class PageComponent implements OnDestroy {
|
||||
export abstract class PageComponent implements OnInit, OnDestroy {
|
||||
|
||||
onDestroy$: Subject<void> = new Subject<void>();
|
||||
|
||||
@ViewChild(DocumentListComponent)
|
||||
documentList: DocumentListComponent;
|
||||
@ -39,6 +46,13 @@ export abstract class PageComponent implements OnDestroy {
|
||||
infoDrawerOpened = false;
|
||||
node: MinimalNodeEntryEntity;
|
||||
|
||||
hasSelection = false;
|
||||
firstSelectedDocument: MinimalNodeEntity;
|
||||
firstSelectedFolder: MinimalNodeEntity;
|
||||
firstSelectedNode: MinimalNodeEntity;
|
||||
lastSelectedNode: MinimalNodeEntity;
|
||||
selectedNodes: MinimalNodeEntity[];
|
||||
|
||||
protected subscriptions: Subscription[] = [];
|
||||
|
||||
get sortingPreferenceKey(): string {
|
||||
@ -49,59 +63,82 @@ export abstract class PageComponent implements OnDestroy {
|
||||
return node.isLocked || (node.properties && node.properties['cm:lockType'] === 'READ_ONLY_LOCK');
|
||||
}
|
||||
|
||||
constructor(protected preferences: UserPreferencesService, protected route: ActivatedRoute) {
|
||||
constructor(protected preferences: UserPreferencesService,
|
||||
protected router: Router,
|
||||
protected route: ActivatedRoute,
|
||||
protected store: Store<AcaState>) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.store
|
||||
.select(selectedNodes)
|
||||
.pipe(takeUntil(this.onDestroy$))
|
||||
.subscribe(selection => this.onSelectionChanged(selection));
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.subscriptions.forEach(subscription => subscription.unsubscribe());
|
||||
this.subscriptions = [];
|
||||
this.onDestroy$.complete();
|
||||
}
|
||||
|
||||
// Precalculates all the "static state" flags so that UI does not re-evaluate that on every tick
|
||||
protected onSelectionChanged(selection: MinimalNodeEntity[] = []) {
|
||||
this.selectedNodes = selection;
|
||||
this.hasSelection = selection.length > 0;
|
||||
|
||||
if (selection.length > 0) {
|
||||
const firstNode = selection[0];
|
||||
this.firstSelectedNode = firstNode;
|
||||
this.firstSelectedDocument = selection.find(entity => entity.entry.isFile);
|
||||
this.firstSelectedFolder = selection.find(entity => entity.entry.isFolder);
|
||||
} else {
|
||||
this.firstSelectedNode = null;
|
||||
this.firstSelectedDocument = null;
|
||||
this.firstSelectedFolder = null;
|
||||
this.lastSelectedNode = null;
|
||||
this.infoDrawerOpened = false;
|
||||
}
|
||||
}
|
||||
|
||||
showPreview(node: MinimalNodeEntity) {
|
||||
if (node && node.entry) {
|
||||
if (node.entry.isFile) {
|
||||
this.router.navigate(['./preview', node.entry.id], { relativeTo: this.route });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getParentNodeId(): string {
|
||||
return this.node ? this.node.id : null;
|
||||
}
|
||||
|
||||
hasSelection(selection: Array<MinimalNodeEntity>): boolean {
|
||||
return selection && selection.length > 0;
|
||||
}
|
||||
|
||||
isFileSelected(selection: Array<MinimalNodeEntity>): boolean {
|
||||
if (selection && selection.length === 1) {
|
||||
const entry = selection[0].entry;
|
||||
|
||||
if (entry && entry.isFile) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
isFolderSelected(selection: Array<MinimalNodeEntity>): boolean {
|
||||
if (selection && selection.length === 1) {
|
||||
const entry = selection[0].entry;
|
||||
|
||||
if (entry && entry.isFolder) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
onChangePageSize(event: Pagination): void {
|
||||
this.preferences.paginationSize = event.maxItems;
|
||||
}
|
||||
|
||||
onNodeSelect(event, documentList) {
|
||||
onNodeSelect(event: CustomEvent, documentList: DocumentListComponent) {
|
||||
if (!!event.detail && !!event.detail.node) {
|
||||
|
||||
const node: MinimalNodeEntryEntity = event.detail.node.entry;
|
||||
if (node && PageComponent.isLockedNode(node)) {
|
||||
this.unSelectLockedNodes(documentList);
|
||||
}
|
||||
|
||||
this.lastSelectedNode = event.detail.node;
|
||||
this.store.dispatch(new SetSelectedNodesAction(documentList.selection));
|
||||
}
|
||||
}
|
||||
|
||||
unSelectLockedNodes(documentList) {
|
||||
onDocumentListReady(event: CustomEvent, documentList: DocumentListComponent) {
|
||||
this.store.dispatch(new SetSelectedNodesAction(documentList.selection));
|
||||
}
|
||||
|
||||
onNodeUnselect(event: CustomEvent, documentList: DocumentListComponent) {
|
||||
this.store.dispatch(new SetSelectedNodesAction(documentList.selection));
|
||||
}
|
||||
|
||||
unSelectLockedNodes(documentList: DocumentListComponent) {
|
||||
documentList.selection = documentList.selection.filter(item => !PageComponent.isLockedNode(item.entry));
|
||||
|
||||
const dataTable = documentList.dataTable;
|
||||
@ -143,6 +180,7 @@ export abstract class PageComponent implements OnDestroy {
|
||||
reload(): void {
|
||||
if (this.documentList) {
|
||||
this.documentList.resetSelection();
|
||||
this.store.dispatch(new SetSelectedNodesAction([]));
|
||||
this.documentList.reload();
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="permission.check(node, ['update'])"
|
||||
[acaNodeVersions]="selectedEntities">
|
||||
[acaNodeVersions]="node">
|
||||
<mat-icon>history</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.VERSIONS' | translate }}</span>
|
||||
</button>
|
||||
|
@ -3,29 +3,27 @@
|
||||
<adf-breadcrumb root="APP.BROWSE.RECENT.TITLE">
|
||||
</adf-breadcrumb>
|
||||
|
||||
<adf-toolbar class="inline">
|
||||
<adf-toolbar class="inline" *ngIf="hasSelection">
|
||||
|
||||
<button
|
||||
mat-icon-button
|
||||
color="primary"
|
||||
*ngIf="isFileSelected(documentList.selection)"
|
||||
*ngIf="firstSelectedDocument"
|
||||
title="{{ 'APP.ACTIONS.VIEW' | translate }}"
|
||||
(click)="onNodeDoubleClick(documentList.selection[0]?.entry)">
|
||||
(click)="showPreview(firstSelectedDocument)">
|
||||
<mat-icon>open_in_browser</mat-icon>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-icon-button
|
||||
color="primary"
|
||||
*ngIf="hasSelection(documentList.selection)"
|
||||
title="{{ 'APP.ACTIONS.DOWNLOAD' | translate }}"
|
||||
[adfNodeDownload]="documentList.selection">
|
||||
[adfNodeDownload]="selectedNodes">
|
||||
<mat-icon>get_app</mat-icon>
|
||||
</button>
|
||||
|
||||
<button mat-icon-button
|
||||
[color]="infoDrawerOpened ? 'accent' : 'primary'"
|
||||
*ngIf="hasSelection(documentList.selection)"
|
||||
title="{{ 'APP.ACTIONS.DETAILS' | translate }}"
|
||||
(click)="toggleSidebar()">
|
||||
<mat-icon>info_outline</mat-icon>
|
||||
@ -34,7 +32,6 @@
|
||||
<button
|
||||
color="primary"
|
||||
mat-icon-button
|
||||
*ngIf="hasSelection(documentList.selection)"
|
||||
title="{{ 'APP.ACTIONS.MORE' | translate }}"
|
||||
[matMenuTriggerFor]="actionsMenu">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
@ -45,7 +42,7 @@
|
||||
<button
|
||||
mat-menu-item
|
||||
#selection="adfFavorite"
|
||||
[adf-node-favorite]="documentList.selection">
|
||||
[adf-node-favorite]="selectedNodes">
|
||||
<mat-icon color="primary" *ngIf="selection.hasFavorites()">star</mat-icon>
|
||||
<mat-icon *ngIf="!selection.hasFavorites()">star_border</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.FAVORITE' | translate }}</span>
|
||||
@ -53,31 +50,31 @@
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
[acaCopyNode]="documentList.selection">
|
||||
[acaCopyNode]="selectedNodes">
|
||||
<mat-icon>content_copy</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.COPY' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="permission.check(documentList.selection, ['delete'])"
|
||||
[acaMoveNode]="documentList.selection">
|
||||
*ngIf="permission.check(selectedNodes, ['delete'])"
|
||||
[acaMoveNode]="selectedNodes">
|
||||
<mat-icon>library_books</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.MOVE' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="permission.check(documentList.selection, ['delete'])"
|
||||
[acaDeleteNode]="documentList.selection">
|
||||
*ngIf="permission.check(selectedNodes, ['delete'])"
|
||||
[acaDeleteNode]="selectedNodes">
|
||||
<mat-icon>delete</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.DELETE' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="isFileSelected(documentList.selection)"
|
||||
[acaNodeVersions]="documentList.selection">
|
||||
*ngIf="firstSelectedDocument"
|
||||
[acaNodeVersions]="firstSelectedDocument">
|
||||
<mat-icon>history</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.VERSIONS' | translate }}</span>
|
||||
</button>
|
||||
@ -95,7 +92,9 @@
|
||||
[acaSortingPreferenceKey]="sortingPreferenceKey"
|
||||
[imageResolver]="imageResolver"
|
||||
(node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)"
|
||||
(node-select)="onNodeSelect($event, documentList)">
|
||||
(ready)="onDocumentListReady($event, documentList)"
|
||||
(node-select)="onNodeSelect($event, documentList)"
|
||||
(node-unselect)="onNodeUnselect($event, documentList)">
|
||||
|
||||
<empty-folder-content>
|
||||
<ng-template>
|
||||
@ -156,41 +155,8 @@
|
||||
</adf-pagination>
|
||||
</div>
|
||||
|
||||
<div class="inner-layout__side-panel"
|
||||
*ngIf="infoDrawerOpened"
|
||||
[acaNodeInfo]="documentList.selection"
|
||||
(changed)="toggleSidebar($event)"
|
||||
#infoInstance=nodeInfo>
|
||||
|
||||
<adf-info-drawer [title]="'APP.INFO_DRAWER.TITLE' | translate">
|
||||
<adf-info-drawer-tab [label]="'APP.INFO_DRAWER.TABS.PROPERTIES' | translate">
|
||||
<div *ngIf="infoInstance.loading">
|
||||
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
|
||||
</div>
|
||||
|
||||
<adf-content-metadata-card
|
||||
[readOnly]="!permission.check(infoInstance.node, ['update'])"
|
||||
[displayEmpty]="permission.check(infoInstance.node, ['update'])"
|
||||
[preset]="'custom'"
|
||||
[node]="infoInstance.node">
|
||||
</adf-content-metadata-card>
|
||||
</adf-info-drawer-tab>
|
||||
|
||||
<adf-info-drawer-tab [label]="'APP.INFO_DRAWER.TABS.VERSIONS' | translate">
|
||||
<ng-container *ngIf="isFileSelected(documentList.selection);else choose_document_template">
|
||||
<adf-version-manager
|
||||
*ngIf="infoInstance.node"
|
||||
[node]="infoInstance.node">
|
||||
</adf-version-manager>
|
||||
</ng-container>
|
||||
<ng-template #choose_document_template>
|
||||
<div class="adf-manage-versions-empty">
|
||||
<mat-icon class="adf-manage-versions-empty-icon">face</mat-icon>
|
||||
{{ 'VERSION.SELECTION.EMPTY' | translate }}
|
||||
</div>
|
||||
</ng-template>
|
||||
</adf-info-drawer-tab>
|
||||
</adf-info-drawer>
|
||||
<div class="inner-layout__side-panel" *ngIf="infoDrawerOpened">
|
||||
<aca-info-drawer [node]="lastSelectedNode"></aca-info-drawer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -41,10 +41,12 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material';
|
||||
import { DocumentListService } from '@alfresco/adf-content-services';
|
||||
import { ContentManagementService } from '../../common/services/content-management.service';
|
||||
import { NodeInfoDirective } from '../../common/directives/node-info.directive';
|
||||
import { NodePermissionService } from '../../common/services/node-permission.service';
|
||||
|
||||
import { RecentFilesComponent } from './recent-files.component';
|
||||
import { StoreModule } from '@ngrx/store';
|
||||
import { appReducer } from '../../store/reducers/app.reducer';
|
||||
import { INITIAL_STATE } from '../../store/states/app.state';
|
||||
|
||||
describe('RecentFiles Routed Component', () => {
|
||||
let fixture: ComponentFixture<RecentFilesComponent>;
|
||||
@ -71,14 +73,14 @@ describe('RecentFiles Routed Component', () => {
|
||||
HttpClientModule,
|
||||
TranslateModule.forRoot(),
|
||||
RouterTestingModule,
|
||||
MatSnackBarModule, MatIconModule
|
||||
MatSnackBarModule, MatIconModule,
|
||||
StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE })
|
||||
],
|
||||
declarations: [
|
||||
DataTableComponent,
|
||||
TimeAgoPipe,
|
||||
NodeNameTooltipPipe,
|
||||
NodeFavoriteDirective,
|
||||
NodeInfoDirective,
|
||||
DocumentListComponent,
|
||||
RecentFilesComponent,
|
||||
AppConfigPipe
|
||||
|
@ -31,6 +31,8 @@ import { UserPreferencesService } from '@alfresco/adf-core';
|
||||
import { ContentManagementService } from '../../common/services/content-management.service';
|
||||
import { PageComponent } from '../page.component';
|
||||
import { NodePermissionService } from '../../common/services/node-permission.service';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AcaState } from '../../store/states/app.state';
|
||||
|
||||
@Component({
|
||||
templateUrl: './recent-files.component.html'
|
||||
@ -38,15 +40,18 @@ import { NodePermissionService } from '../../common/services/node-permission.ser
|
||||
export class RecentFilesComponent extends PageComponent implements OnInit {
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
router: Router,
|
||||
route: ActivatedRoute,
|
||||
store: Store<AcaState>,
|
||||
private content: ContentManagementService,
|
||||
public permission: NodePermissionService,
|
||||
preferences: UserPreferencesService) {
|
||||
super(preferences, route);
|
||||
super(preferences, router, route, store);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
super.ngOnInit();
|
||||
|
||||
this.subscriptions = this.subscriptions.concat([
|
||||
this.content.nodeDeleted.subscribe(() => this.reload()),
|
||||
this.content.nodeMoved.subscribe(() => this.reload()),
|
||||
|
@ -3,28 +3,25 @@
|
||||
<adf-breadcrumb root="APP.BROWSE.SHARED.TITLE">
|
||||
</adf-breadcrumb>
|
||||
|
||||
<adf-toolbar class="inline">
|
||||
<adf-toolbar class="inline" *ngIf="hasSelection">
|
||||
<button
|
||||
color="primary"
|
||||
mat-icon-button
|
||||
*ngIf="isFileSelected(documentList.selection)"
|
||||
title="{{ 'APP.ACTIONS.VIEW' | translate }}"
|
||||
(click)="onNodeDoubleClick(documentList.selection[0]?.entry)">
|
||||
(click)="showPreview(selectedNodes[0])">
|
||||
<mat-icon>open_in_browser</mat-icon>
|
||||
</button>
|
||||
|
||||
<button
|
||||
color="primary"
|
||||
mat-icon-button
|
||||
*ngIf="hasSelection(documentList.selection)"
|
||||
title="{{ 'APP.ACTIONS.DOWNLOAD' | translate }}"
|
||||
[adfNodeDownload]="documentList.selection">
|
||||
[adfNodeDownload]="selectedNodes">
|
||||
<mat-icon>get_app</mat-icon>
|
||||
</button>
|
||||
|
||||
<button mat-icon-button
|
||||
[color]="infoDrawerOpened ? 'accent' : 'primary'"
|
||||
*ngIf="hasSelection(documentList.selection)"
|
||||
title="{{ 'APP.ACTIONS.DETAILS' | translate }}"
|
||||
(click)="toggleSidebar()">
|
||||
<mat-icon>info_outline</mat-icon>
|
||||
@ -33,7 +30,6 @@
|
||||
<button
|
||||
color="primary"
|
||||
mat-icon-button
|
||||
*ngIf="hasSelection(documentList.selection)"
|
||||
title="{{ 'APP.ACTIONS.MORE' | translate }}"
|
||||
[matMenuTriggerFor]="actionsMenu">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
@ -44,7 +40,7 @@
|
||||
<button
|
||||
mat-menu-item
|
||||
#selection="adfFavorite"
|
||||
[adf-node-favorite]="documentList.selection">
|
||||
[adf-node-favorite]="selectedNodes">
|
||||
<mat-icon color="primary" *ngIf="selection.hasFavorites()">star</mat-icon>
|
||||
<mat-icon *ngIf="!selection.hasFavorites()">star_border</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.FAVORITE' | translate }}</span>
|
||||
@ -52,23 +48,23 @@
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
[acaCopyNode]="documentList.selection">
|
||||
[acaCopyNode]="selectedNodes">
|
||||
<mat-icon>content_copy</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.COPY' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="permission.check(documentList.selection, ['delete'], { target: 'allowableOperationsOnTarget' })"
|
||||
[acaMoveNode]="documentList.selection">
|
||||
*ngIf="permission.check(selectedNodes, ['delete'], { target: 'allowableOperationsOnTarget' })"
|
||||
[acaMoveNode]="selectedNodes">
|
||||
<mat-icon>library_books</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.MOVE' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="permission.check(documentList.selection, ['delete'])"
|
||||
[acaUnshareNode]="documentList.selection"
|
||||
*ngIf="permission.check(selectedNodes, ['delete'])"
|
||||
[acaUnshareNode]="selectedNodes"
|
||||
(links-unshared)="reload()">
|
||||
<mat-icon>stop_screen_share</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.UNSHARE' | translate }}</span>
|
||||
@ -76,16 +72,16 @@
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="permission.check(documentList.selection, ['delete'], { target: 'allowableOperationsOnTarget' })"
|
||||
[acaDeleteNode]="documentList.selection">
|
||||
*ngIf="permission.check(selectedNodes, ['delete'], { target: 'allowableOperationsOnTarget' })"
|
||||
[acaDeleteNode]="selectedNodes">
|
||||
<mat-icon>delete</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.DELETE' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="permission.check(documentList.selection[0], ['update'], { target: 'allowableOperationsOnTarget' })"
|
||||
[acaNodeVersions]="documentList.selection">
|
||||
*ngIf="permission.check(selectedNodes, ['update'], { target: 'allowableOperationsOnTarget' })"
|
||||
[acaNodeVersions]="lastSelectedNode">
|
||||
<mat-icon>history</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.VERSIONS' | translate }}</span>
|
||||
</button>
|
||||
@ -100,7 +96,10 @@
|
||||
selectionMode="multiple"
|
||||
[sorting]="[ 'modifiedAt', 'desc' ]"
|
||||
[acaSortingPreferenceKey]="sortingPreferenceKey"
|
||||
(node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)">
|
||||
(node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)"
|
||||
(ready)="onDocumentListReady($event, documentList)"
|
||||
(node-select)="onNodeSelect($event, documentList)"
|
||||
(node-unselect)="onNodeUnselect($event, documentList)">
|
||||
|
||||
<empty-folder-content>
|
||||
<ng-template>
|
||||
@ -173,41 +172,8 @@
|
||||
</adf-pagination>
|
||||
</div>
|
||||
|
||||
<div class="inner-layout__side-panel"
|
||||
*ngIf="infoDrawerOpened"
|
||||
[acaNodeInfo]="documentList.selection"
|
||||
(changed)="toggleSidebar($event)"
|
||||
#infoInstance=nodeInfo>
|
||||
|
||||
<adf-info-drawer [title]="'APP.INFO_DRAWER.TITLE' | translate">
|
||||
<adf-info-drawer-tab [label]="'APP.INFO_DRAWER.TABS.PROPERTIES' | translate">
|
||||
<div *ngIf="infoInstance.loading">
|
||||
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
|
||||
</div>
|
||||
|
||||
<adf-content-metadata-card
|
||||
[readOnly]="!permission.check(documentList.selection, ['update'], { target: 'allowableOperationsOnTarget' })"
|
||||
[displayEmpty]="permission.check(documentList.selection, ['update'], { target: 'allowableOperationsOnTarget' })"
|
||||
[preset]="'custom'"
|
||||
[node]="infoInstance.node">
|
||||
</adf-content-metadata-card>
|
||||
</adf-info-drawer-tab>
|
||||
|
||||
<adf-info-drawer-tab [label]="'APP.INFO_DRAWER.TABS.VERSIONS' | translate">
|
||||
<ng-container *ngIf="isFileSelected(documentList.selection);else choose_document_template">
|
||||
<adf-version-manager
|
||||
*ngIf="infoInstance.node"
|
||||
[node]="infoInstance.node">
|
||||
</adf-version-manager>
|
||||
</ng-container>
|
||||
<ng-template #choose_document_template>
|
||||
<div class="adf-manage-versions-empty">
|
||||
<mat-icon class="adf-manage-versions-empty-icon">face</mat-icon>
|
||||
{{ 'VERSION.SELECTION.EMPTY' | translate }}
|
||||
</div>
|
||||
</ng-template>
|
||||
</adf-info-drawer-tab>
|
||||
</adf-info-drawer>
|
||||
<div class="inner-layout__side-panel" *ngIf="infoDrawerOpened">
|
||||
<aca-info-drawer [node]="lastSelectedNode"></aca-info-drawer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -41,10 +41,12 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material';
|
||||
import { DocumentListService } from '@alfresco/adf-content-services';
|
||||
import { ContentManagementService } from '../../common/services/content-management.service';
|
||||
import { NodeInfoDirective } from '../../common/directives/node-info.directive';
|
||||
import { NodePermissionService } from '../../common/services/node-permission.service';
|
||||
|
||||
import { SharedFilesComponent } from './shared-files.component';
|
||||
import { StoreModule } from '@ngrx/store';
|
||||
import { appReducer } from '../../store/reducers/app.reducer';
|
||||
import { INITIAL_STATE } from '../../store/states/app.state';
|
||||
|
||||
describe('SharedFilesComponent', () => {
|
||||
let fixture: ComponentFixture<SharedFilesComponent>;
|
||||
@ -73,14 +75,14 @@ describe('SharedFilesComponent', () => {
|
||||
HttpClientModule,
|
||||
TranslateModule.forRoot(),
|
||||
RouterTestingModule,
|
||||
MatSnackBarModule, MatIconModule
|
||||
MatSnackBarModule, MatIconModule,
|
||||
StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE })
|
||||
],
|
||||
declarations: [
|
||||
DataTableComponent,
|
||||
TimeAgoPipe,
|
||||
NodeNameTooltipPipe,
|
||||
NodeFavoriteDirective,
|
||||
NodeInfoDirective,
|
||||
DocumentListComponent,
|
||||
SharedFilesComponent,
|
||||
AppConfigPipe
|
||||
|
@ -31,22 +31,27 @@ import { AlfrescoApiService, UserPreferencesService } from '@alfresco/adf-core';
|
||||
import { ContentManagementService } from '../../common/services/content-management.service';
|
||||
import { NodePermissionService } from '../../common/services/node-permission.service';
|
||||
import { PageComponent } from '../page.component';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AcaState } from '../../store/states/app.state';
|
||||
|
||||
@Component({
|
||||
templateUrl: './shared-files.component.html'
|
||||
})
|
||||
export class SharedFilesComponent extends PageComponent implements OnInit {
|
||||
|
||||
constructor(private router: Router,
|
||||
constructor(router: Router,
|
||||
route: ActivatedRoute,
|
||||
store: Store<AcaState>,
|
||||
private content: ContentManagementService,
|
||||
private apiService: AlfrescoApiService,
|
||||
public permission: NodePermissionService,
|
||||
preferences: UserPreferencesService) {
|
||||
super(preferences, route);
|
||||
super(preferences, router, route, store);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
super.ngOnInit();
|
||||
|
||||
this.subscriptions = this.subscriptions.concat([
|
||||
this.content.nodeDeleted.subscribe(() => this.reload()),
|
||||
this.content.nodeMoved.subscribe(() => this.reload()),
|
||||
@ -65,9 +70,4 @@ export class SharedFilesComponent extends PageComponent implements OnInit {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/** @override */
|
||||
isFileSelected(selection: Array<MinimalNodeEntity>): boolean {
|
||||
return selection && selection.length === 1;
|
||||
}
|
||||
}
|
||||
|
@ -32,13 +32,14 @@ import { HttpClientModule } from '@angular/common/http';
|
||||
import {
|
||||
AppConfigService, AuthenticationService,
|
||||
UserPreferencesService, StorageService, AlfrescoApiService,
|
||||
CookieService, LogService, NotificationService
|
||||
CookieService, LogService, NotificationService, TranslationService, TranslationMock
|
||||
} from '@alfresco/adf-core';
|
||||
import { BrowsingFilesService } from '../../common/services/browsing-files.service';
|
||||
import { NodePermissionService } from '../../common/services/node-permission.service';
|
||||
|
||||
import { SidenavComponent } from './sidenav.component';
|
||||
import { ElectronModule } from '@ngstack/electron';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
describe('SidenavComponent', () => {
|
||||
let fixture;
|
||||
@ -58,6 +59,7 @@ describe('SidenavComponent', () => {
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
NoopAnimationsModule,
|
||||
HttpClientModule,
|
||||
MatMenuModule,
|
||||
MatSnackBarModule,
|
||||
@ -69,6 +71,7 @@ describe('SidenavComponent', () => {
|
||||
SidenavComponent
|
||||
],
|
||||
providers: [
|
||||
{ provide: TranslationService, useClass: TranslationMock },
|
||||
LogService,
|
||||
CookieService,
|
||||
AlfrescoApiService,
|
||||
|
@ -3,13 +3,12 @@
|
||||
<adf-breadcrumb root="APP.BROWSE.TRASHCAN.TITLE">
|
||||
</adf-breadcrumb>
|
||||
|
||||
<adf-toolbar class="inline">
|
||||
<adf-toolbar class="inline" *ngIf="hasSelection">
|
||||
<button
|
||||
color="primary"
|
||||
mat-icon-button
|
||||
[app-permanent-delete-node]="documentList.selection"
|
||||
[app-permanent-delete-node]="selectedNodes"
|
||||
(selection-node-deleted)="reload()"
|
||||
*ngIf="documentList.selection.length"
|
||||
title="{{ 'APP.ACTIONS.DELETE_PERMANENT' | translate }}">
|
||||
<mat-icon>delete_forever</mat-icon>
|
||||
</button>
|
||||
@ -18,8 +17,7 @@
|
||||
color="primary"
|
||||
mat-icon-button
|
||||
(selection-node-restored)="reload()"
|
||||
[acaRestoreNode]="documentList.selection"
|
||||
*ngIf="documentList.selection.length"
|
||||
[acaRestoreNode]="selectedNodes"
|
||||
title="{{ 'APP.ACTIONS.RESTORE' | translate }}">
|
||||
<mat-icon>restore</mat-icon>
|
||||
</button>
|
||||
@ -33,7 +31,10 @@
|
||||
selectionMode="multiple"
|
||||
[navigate]="false"
|
||||
[sorting]="[ 'archivedAt', 'desc' ]"
|
||||
[acaSortingPreferenceKey]="sortingPreferenceKey">
|
||||
[acaSortingPreferenceKey]="sortingPreferenceKey"
|
||||
(ready)="onDocumentListReady($event, documentList)"
|
||||
(node-select)="onNodeSelect($event, documentList)"
|
||||
(node-unselect)="onNodeUnselect($event, documentList)">
|
||||
|
||||
<empty-folder-content>
|
||||
<ng-template>
|
||||
|
@ -40,9 +40,11 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material';
|
||||
import { DocumentListService } from '@alfresco/adf-content-services';
|
||||
import { ContentManagementService } from '../../common/services/content-management.service';
|
||||
import { NodeInfoDirective } from '../../common/directives/node-info.directive';
|
||||
|
||||
import { TrashcanComponent } from './trashcan.component';
|
||||
import { StoreModule } from '@ngrx/store';
|
||||
import { appReducer } from '../../store/reducers/app.reducer';
|
||||
import { INITIAL_STATE } from '../../store/states/app.state';
|
||||
|
||||
describe('TrashcanComponent', () => {
|
||||
let fixture: ComponentFixture<TrashcanComponent>;
|
||||
@ -68,14 +70,14 @@ describe('TrashcanComponent', () => {
|
||||
HttpClientModule,
|
||||
TranslateModule.forRoot(),
|
||||
RouterTestingModule,
|
||||
MatSnackBarModule, MatIconModule
|
||||
MatSnackBarModule, MatIconModule,
|
||||
StoreModule.forRoot({ app: appReducer }, { initialState: INITIAL_STATE })
|
||||
],
|
||||
declarations: [
|
||||
DataTableComponent,
|
||||
TimeAgoPipe,
|
||||
NodeNameTooltipPipe,
|
||||
NodeFavoriteDirective,
|
||||
NodeInfoDirective,
|
||||
DocumentListComponent,
|
||||
TrashcanComponent,
|
||||
AppConfigPipe
|
||||
|
@ -24,11 +24,13 @@
|
||||
*/
|
||||
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Pagination } from 'alfresco-js-api';
|
||||
import { UserPreferencesService } from '@alfresco/adf-core';
|
||||
import { ContentManagementService } from '../../common/services/content-management.service';
|
||||
import { PageComponent } from '../page.component';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AcaState } from '../../store/states/app.state';
|
||||
|
||||
@Component({
|
||||
templateUrl: './trashcan.component.html'
|
||||
@ -37,11 +39,15 @@ export class TrashcanComponent extends PageComponent implements OnInit {
|
||||
|
||||
constructor(private contentManagementService: ContentManagementService,
|
||||
preferences: UserPreferencesService,
|
||||
store: Store<AcaState>,
|
||||
router: Router,
|
||||
route: ActivatedRoute) {
|
||||
super(preferences, route);
|
||||
super(preferences, router, route, store);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
super.ngOnInit();
|
||||
|
||||
this.subscriptions.push(
|
||||
this.contentManagementService.nodeRestored.subscribe(() => this.reload())
|
||||
);
|
||||
|
8
src/app/store/actions/select-nodes.action.ts
Normal file
8
src/app/store/actions/select-nodes.action.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { Action } from '@ngrx/store';
|
||||
|
||||
export const SET_SELECTED_NODES = 'SET_SELECTED_NODES';
|
||||
|
||||
export class SetSelectedNodesAction implements Action {
|
||||
readonly type = SET_SELECTED_NODES;
|
||||
constructor(public payload: any[] = []) {}
|
||||
}
|
@ -3,6 +3,7 @@ import { AppState, INITIAL_APP_STATE } from '../states/app.state';
|
||||
import { SET_HEADER_COLOR, SetHeaderColorAction } from '../actions/header-color.action';
|
||||
import { SET_APP_NAME, SetAppNameAction } from '../actions/app-name.action';
|
||||
import { SET_LOGO_PATH, SetLogoPathAction } from '../actions/logo-path.action';
|
||||
import { SET_SELECTED_NODES, SetSelectedNodesAction } from '../actions/select-nodes.action';
|
||||
|
||||
|
||||
export function appReducer(state: AppState = INITIAL_APP_STATE, action: Action): AppState {
|
||||
@ -18,6 +19,9 @@ export function appReducer(state: AppState = INITIAL_APP_STATE, action: Action):
|
||||
case SET_LOGO_PATH:
|
||||
newState = updateLogoPath(state, <SetLogoPathAction> action);
|
||||
break;
|
||||
case SET_SELECTED_NODES:
|
||||
newState = updateSelectedNodes(state, <SetSelectedNodesAction> action);
|
||||
break;
|
||||
default:
|
||||
newState = Object.assign({}, state);
|
||||
}
|
||||
@ -42,3 +46,9 @@ function updateLogoPath(state: AppState, action: SetLogoPathAction): AppState {
|
||||
newState.logoPath = action.payload;
|
||||
return newState;
|
||||
}
|
||||
|
||||
function updateSelectedNodes(state: AppState, action: SetSelectedNodesAction): AppState {
|
||||
const newState = Object.assign({}, state);
|
||||
newState.selectedNodes = [...action.payload];
|
||||
return newState;
|
||||
}
|
||||
|
@ -5,3 +5,4 @@ export const selectApp = (state: AcaState) => state.app;
|
||||
export const selectHeaderColor = createSelector(selectApp, (state: AppState) => state.headerColor);
|
||||
export const selectAppName = createSelector(selectApp, (state: AppState) => state.appName);
|
||||
export const selectLogoPath = createSelector(selectApp, (state: AppState) => state.logoPath);
|
||||
export const selectedNodes = createSelector(selectApp, (state: AppState) => state.selectedNodes);
|
||||
|
@ -1,13 +1,17 @@
|
||||
import { MinimalNodeEntity } from 'alfresco-js-api';
|
||||
|
||||
export interface AppState {
|
||||
appName: string;
|
||||
headerColor: string;
|
||||
logoPath: string;
|
||||
selectedNodes: MinimalNodeEntity[];
|
||||
}
|
||||
|
||||
export const INITIAL_APP_STATE: AppState = {
|
||||
appName: 'Alfresco Example Content Application',
|
||||
headerColor: '#2196F3',
|
||||
logoPath: 'assets/images/alfresco-logo-white.svg'
|
||||
logoPath: 'assets/images/alfresco-logo-white.svg',
|
||||
selectedNodes: []
|
||||
};
|
||||
|
||||
export interface AcaState {
|
||||
|
@ -122,7 +122,7 @@
|
||||
"component-selector": [
|
||||
true,
|
||||
"element",
|
||||
"app",
|
||||
[ "app", "aca"],
|
||||
"kebab-case"
|
||||
],
|
||||
"use-input-property-decorator": true,
|
||||
|
Loading…
x
Reference in New Issue
Block a user