mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-05-19 17:14:45 +00:00
[ACA-1917] Extensions - evaluate actions for locked files (#858)
* locked file evaluator * add extension reference * update docs * disable versioning for locked files * disable metadata edit for locked files * update e2e
This commit is contained in:
parent
db66c72a06
commit
4c274acb3c
@ -143,6 +143,7 @@ The button will be visible only when the linked rule evaluates to `true`.
|
|||||||
| app.selection.file | A single File node is selected. |
|
| app.selection.file | A single File node is selected. |
|
||||||
| app.selection.file.canShare | User is able to share the selected file. |
|
| app.selection.file.canShare | User is able to share the selected file. |
|
||||||
| app.selection.file.isShared | A shared node is selected |
|
| app.selection.file.isShared | A shared node is selected |
|
||||||
|
| app.selection.file.isLocked | File is locked for editing |
|
||||||
| app.selection.library | A single Library node is selected. |
|
| app.selection.library | A single Library node is selected. |
|
||||||
| app.selection.isPrivateLibrary | A private Library node is selected. |
|
| app.selection.isPrivateLibrary | A private Library node is selected. |
|
||||||
| app.selection.hasLibraryRole | The selected Library node has a role property. |
|
| app.selection.hasLibraryRole | The selected Library node has a role property. |
|
||||||
|
@ -59,17 +59,24 @@ describe('Delete and undo delete', () => {
|
|||||||
const file4 = `file4-${Utils.random()}.txt`; let file4Id;
|
const file4 = `file4-${Utils.random()}.txt`; let file4Id;
|
||||||
const folder1 = `folder1-${Utils.random()}`; let folder1Id;
|
const folder1 = `folder1-${Utils.random()}`; let folder1Id;
|
||||||
const folder2 = `folder2-${Utils.random()}`; let folder2Id;
|
const folder2 = `folder2-${Utils.random()}`; let folder2Id;
|
||||||
const fileLocked1 = `fileLocked-${Utils.random()}.txt`; let fileLocked1Id;
|
const folder3 = `folder3-${Utils.random()}`; let folder3Id;
|
||||||
|
const fileLocked1 = `fileLocked1-${Utils.random()}.txt`; let fileLocked1Id;
|
||||||
|
const fileLocked2 = `fileLocked2-${Utils.random()}.txt`; let fileLocked2Id;
|
||||||
|
|
||||||
beforeAll(async (done) => {
|
beforeAll(async (done) => {
|
||||||
file1Id = (await apis.user.nodes.createFile(file1)).entry.id;
|
file1Id = (await apis.user.nodes.createFile(file1)).entry.id;
|
||||||
file2Id = (await apis.user.nodes.createFile(file2)).entry.id;
|
file2Id = (await apis.user.nodes.createFile(file2)).entry.id;
|
||||||
folder1Id = (await apis.user.nodes.createFolder(folder1)).entry.id;
|
folder1Id = (await apis.user.nodes.createFolder(folder1)).entry.id;
|
||||||
|
|
||||||
folder2Id = (await apis.user.nodes.createFolder(folder2)).entry.id;
|
folder2Id = (await apis.user.nodes.createFolder(folder2)).entry.id;
|
||||||
await apis.user.nodes.createFile(file3, folder1Id);
|
await apis.user.nodes.createFile(file3, folder1Id);
|
||||||
file4Id = (await apis.user.nodes.createFile(file4, folder2Id)).entry.id;
|
file4Id = (await apis.user.nodes.createFile(file4, folder2Id)).entry.id;
|
||||||
await apis.user.nodes.lockFile(file4Id);
|
await apis.user.nodes.lockFile(file4Id);
|
||||||
|
|
||||||
|
folder3Id = (await apis.user.nodes.createFolder(folder3)).entry.id;
|
||||||
|
fileLocked2Id = (await apis.user.nodes.createFile(fileLocked2, folder3Id)).entry.id;
|
||||||
|
await apis.user.nodes.lockFile(fileLocked2Id);
|
||||||
|
|
||||||
fileLocked1Id = (await apis.user.nodes.createFile(fileLocked1)).entry.id;
|
fileLocked1Id = (await apis.user.nodes.createFile(fileLocked1)).entry.id;
|
||||||
await apis.user.nodes.lockFile(fileLocked1Id);
|
await apis.user.nodes.lockFile(fileLocked1Id);
|
||||||
|
|
||||||
@ -90,7 +97,8 @@ describe('Delete and undo delete', () => {
|
|||||||
afterAll(async (done) => {
|
afterAll(async (done) => {
|
||||||
await apis.user.nodes.unlockFile(file4Id);
|
await apis.user.nodes.unlockFile(file4Id);
|
||||||
await apis.user.nodes.unlockFile(fileLocked1Id);
|
await apis.user.nodes.unlockFile(fileLocked1Id);
|
||||||
await apis.user.nodes.deleteNodesById([file1Id, file2Id, folder1Id, folder2Id, fileLocked1Id]);
|
await apis.user.nodes.unlockFile(fileLocked2Id);
|
||||||
|
await apis.user.nodes.deleteNodesById([file1Id, file2Id, folder1Id, folder2Id, folder3Id, fileLocked1Id]);
|
||||||
await apis.user.search.waitForApi(username, {expect: 0});
|
await apis.user.search.waitForApi(username, {expect: 0});
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -171,7 +179,7 @@ describe('Delete and undo delete', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('notification on multiple items deletion - all items fail to delete - [C217130]', async () => {
|
it('notification on multiple items deletion - all items fail to delete - [C217130]', async () => {
|
||||||
await dataTable.selectMultipleItems([fileLocked1, folder2]);
|
await dataTable.selectMultipleItems([folder3, folder2]);
|
||||||
await toolbar.openMoreMenu();
|
await toolbar.openMoreMenu();
|
||||||
await toolbar.menu.clickMenuItem('Delete');
|
await toolbar.menu.clickMenuItem('Delete');
|
||||||
const message = await page.getSnackBarMessage();
|
const message = await page.getSnackBarMessage();
|
||||||
@ -339,23 +347,28 @@ describe('Delete and undo delete', () => {
|
|||||||
const favoriteFile4 = `favFile4-${Utils.random()}.txt`; let favoriteFile4Id;
|
const favoriteFile4 = `favFile4-${Utils.random()}.txt`; let favoriteFile4Id;
|
||||||
const favoriteFolder1 = `favFolder1-${Utils.random()}`; let favoriteFolder1Id;
|
const favoriteFolder1 = `favFolder1-${Utils.random()}`; let favoriteFolder1Id;
|
||||||
const favoriteFolder2 = `favFolder2-${Utils.random()}`; let favoriteFolder2Id;
|
const favoriteFolder2 = `favFolder2-${Utils.random()}`; let favoriteFolder2Id;
|
||||||
const favoriteFileLocked1 = `favFileLocked-${Utils.random()}.txt`; let favoriteFileLocked1Id;
|
const favoriteFolder3 = `favFolder3-${Utils.random()}`; let favoriteFolder3Id;
|
||||||
|
const favoriteFileLocked1 = `favFileLocked1-${Utils.random()}.txt`; let favoriteFileLocked1Id;
|
||||||
|
const favoriteFileLocked2 = `favFileLocked2-${Utils.random()}.txt`; let favoriteFileLocked2Id;
|
||||||
|
|
||||||
beforeAll(async (done) => {
|
beforeAll(async (done) => {
|
||||||
favoriteFile1Id = (await apis.user.nodes.createFile(favoriteFile1)).entry.id;
|
favoriteFile1Id = (await apis.user.nodes.createFile(favoriteFile1)).entry.id;
|
||||||
favoriteFile2Id = (await apis.user.nodes.createFile(favoriteFile2)).entry.id;
|
favoriteFile2Id = (await apis.user.nodes.createFile(favoriteFile2)).entry.id;
|
||||||
favoriteFolder1Id = (await apis.user.nodes.createFolder(favoriteFolder1)).entry.id;
|
favoriteFolder1Id = (await apis.user.nodes.createFolder(favoriteFolder1)).entry.id;
|
||||||
favoriteFolder2Id = (await apis.user.nodes.createFolder(favoriteFolder2)).entry.id;
|
favoriteFolder2Id = (await apis.user.nodes.createFolder(favoriteFolder2)).entry.id;
|
||||||
|
favoriteFolder3Id = (await apis.user.nodes.createFolder(favoriteFolder3)).entry.id;
|
||||||
await apis.user.nodes.createFile(favoriteFile3, favoriteFolder1Id);
|
await apis.user.nodes.createFile(favoriteFile3, favoriteFolder1Id);
|
||||||
favoriteFile4Id = (await apis.user.nodes.createFile(favoriteFile4, favoriteFolder2Id)).entry.id;
|
favoriteFile4Id = (await apis.user.nodes.createFile(favoriteFile4, favoriteFolder2Id)).entry.id;
|
||||||
|
favoriteFileLocked2Id = (await apis.user.nodes.createFile(favoriteFileLocked2, favoriteFolder3Id)).entry.id;
|
||||||
await apis.user.nodes.lockFile(favoriteFile4Id);
|
await apis.user.nodes.lockFile(favoriteFile4Id);
|
||||||
|
await apis.user.nodes.lockFile(favoriteFileLocked2Id);
|
||||||
|
|
||||||
favoriteFileLocked1Id = (await apis.user.nodes.createFile(favoriteFileLocked1)).entry.id;
|
favoriteFileLocked1Id = (await apis.user.nodes.createFile(favoriteFileLocked1)).entry.id;
|
||||||
await apis.user.nodes.lockFile(favoriteFileLocked1Id);
|
await apis.user.nodes.lockFile(favoriteFileLocked1Id);
|
||||||
|
|
||||||
await apis.user.favorites.addFavoritesByIds('file', [ favoriteFile1Id, favoriteFile2Id, favoriteFileLocked1Id ]);
|
await apis.user.favorites.addFavoritesByIds('file', [ favoriteFile1Id, favoriteFile2Id, favoriteFileLocked1Id ]);
|
||||||
await apis.user.favorites.addFavoritesByIds('folder', [ favoriteFolder1Id, favoriteFolder2Id ]);
|
await apis.user.favorites.addFavoritesByIds('folder', [ favoriteFolder1Id, favoriteFolder2Id, favoriteFolder3Id ]);
|
||||||
await apis.user.favorites.waitForApi({ expect: 5 });
|
await apis.user.favorites.waitForApi({ expect: 6 });
|
||||||
|
|
||||||
await loginPage.loginWith(username);
|
await loginPage.loginWith(username);
|
||||||
done();
|
done();
|
||||||
@ -374,8 +387,9 @@ describe('Delete and undo delete', () => {
|
|||||||
afterAll(async (done) => {
|
afterAll(async (done) => {
|
||||||
await apis.user.nodes.unlockFile(favoriteFile4Id);
|
await apis.user.nodes.unlockFile(favoriteFile4Id);
|
||||||
await apis.user.nodes.unlockFile(favoriteFileLocked1Id);
|
await apis.user.nodes.unlockFile(favoriteFileLocked1Id);
|
||||||
|
await apis.user.nodes.unlockFile(favoriteFileLocked2Id);
|
||||||
await apis.user.nodes.deleteNodesById([
|
await apis.user.nodes.deleteNodesById([
|
||||||
favoriteFile1Id, favoriteFile2Id, favoriteFolder1Id, favoriteFolder2Id, favoriteFileLocked1Id
|
favoriteFile1Id, favoriteFile2Id, favoriteFolder1Id, favoriteFolder2Id, favoriteFileLocked1Id, favoriteFolder3Id
|
||||||
]);
|
]);
|
||||||
await apis.user.search.waitForApi(username, {expect: 0});
|
await apis.user.search.waitForApi(username, {expect: 0});
|
||||||
done();
|
done();
|
||||||
@ -456,7 +470,7 @@ describe('Delete and undo delete', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('notification on multiple items deletion - all items fail to delete - [C280521]', async () => {
|
it('notification on multiple items deletion - all items fail to delete - [C280521]', async () => {
|
||||||
await dataTable.selectMultipleItems([favoriteFileLocked1, favoriteFolder2]);
|
await dataTable.selectMultipleItems([favoriteFolder3, favoriteFolder2]);
|
||||||
await toolbar.openMoreMenu();
|
await toolbar.openMoreMenu();
|
||||||
await toolbar.menu.clickMenuItem('Delete');
|
await toolbar.menu.clickMenuItem('Delete');
|
||||||
const message = await page.getSnackBarMessage();
|
const message = await page.getSnackBarMessage();
|
||||||
|
@ -65,6 +65,25 @@ export class MetadataTabComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get canUpdateNode() {
|
get canUpdateNode() {
|
||||||
return this.node && this.permission.check(this.node, ['update']);
|
if (this.node) {
|
||||||
|
if (this.fileIsLocked()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return this.permission.check(this.node, ['update']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private fileIsLocked() {
|
||||||
|
if (!this.node.isFile) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
this.node.isLocked ||
|
||||||
|
(this.node.properties &&
|
||||||
|
this.node.properties['cm:lockType'] === 'READ_ONLY_LOCK')
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,6 +114,7 @@ export class CoreExtensionsModule {
|
|||||||
'app.selection.file': app.hasFileSelected,
|
'app.selection.file': app.hasFileSelected,
|
||||||
'app.selection.file.canShare': app.canShareFile,
|
'app.selection.file.canShare': app.canShareFile,
|
||||||
'app.selection.file.isShared': app.isShared,
|
'app.selection.file.isShared': app.isShared,
|
||||||
|
'app.selection.file.isLocked': app.hasLockedFiles,
|
||||||
'app.selection.library': app.hasLibrarySelected,
|
'app.selection.library': app.hasLibrarySelected,
|
||||||
'app.selection.isPrivateLibrary': app.isPrivateLibrary,
|
'app.selection.isPrivateLibrary': app.isPrivateLibrary,
|
||||||
'app.selection.hasLibraryRole': app.hasLibraryRole,
|
'app.selection.hasLibraryRole': app.hasLibraryRole,
|
||||||
|
@ -107,6 +107,10 @@ export function canDeleteSelection(
|
|||||||
isNotSearchResults(context, ...args) &&
|
isNotSearchResults(context, ...args) &&
|
||||||
!context.selection.isEmpty
|
!context.selection.isEmpty
|
||||||
) {
|
) {
|
||||||
|
if (hasLockedFiles(context, ...args)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// temp workaround for Search api
|
// temp workaround for Search api
|
||||||
if (isFavorites(context, ...args)) {
|
if (isFavorites(context, ...args)) {
|
||||||
return true;
|
return true;
|
||||||
@ -244,6 +248,10 @@ export function canUpdateSelectedNode(
|
|||||||
if (context.selection && !context.selection.isEmpty) {
|
if (context.selection && !context.selection.isEmpty) {
|
||||||
const node = context.selection.first;
|
const node = context.selection.first;
|
||||||
|
|
||||||
|
if (node.entry.isFile && hasLockedFiles(context, ...args)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (node.entry.hasOwnProperty('allowableOperationsOnTarget')) {
|
if (node.entry.hasOwnProperty('allowableOperationsOnTarget')) {
|
||||||
return context.permissions.check(node, ['update'], {
|
return context.permissions.check(node, ['update'], {
|
||||||
target: 'allowableOperationsOnTarget'
|
target: 'allowableOperationsOnTarget'
|
||||||
@ -269,3 +277,20 @@ export function canUpdateSelectedFolder(
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function hasLockedFiles(
|
||||||
|
context: RuleContext,
|
||||||
|
...args: RuleParameter[]
|
||||||
|
): boolean {
|
||||||
|
return context.selection.nodes.some(node => {
|
||||||
|
if (!node.entry.isFile) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
node.entry.isLocked ||
|
||||||
|
(node.entry.properties &&
|
||||||
|
node.entry.properties['cm:lockType'] === 'READ_ONLY_LOCK')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -165,7 +165,14 @@
|
|||||||
"type": "core.every",
|
"type": "core.every",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{ "type": "rule", "value": "app.selection.file" },
|
{ "type": "rule", "value": "app.selection.file" },
|
||||||
{ "type": "rule", "value": "app.navigation.isNotTrashcan" }
|
{ "type": "rule", "value": "app.navigation.isNotTrashcan" },
|
||||||
|
{
|
||||||
|
"type": "rule",
|
||||||
|
"value": "core.not",
|
||||||
|
"parameters": [
|
||||||
|
{ "type": "rule", "value": "app.selection.file.isLocked" }
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user