Commit 9fcb7542 authored by Jacques's avatar Jacques

Disable lock button when locked by another user

Disables the lock button when the current file is locked by another user
parent f934bd0e
......@@ -157,11 +157,18 @@ export default {
},
canLock() {
const { pushCode, downloadCode } = this.project.userPermissions;
const currentUsername = window.gon?.current_username;
if (this.pathLockedByUser && this.pathLockedByUser.username !== currentUsername) {
return false;
}
return pushCode && downloadCode;
},
isLocked() {
return this.project.pathLocks.nodes.some((node) => node.path === this.path);
pathLockedByUser() {
const pathLock = this.project.pathLocks.nodes.find((node) => node.path === this.path);
return pathLock ? pathLock.user : null;
},
showForkSuggestion() {
const { createMergeRequestIn, forkProject } = this.project.userPermissions;
......@@ -270,7 +277,7 @@ export default {
:can-push-to-branch="blobInfo.canCurrentUserPushToBranch"
:empty-repo="project.repository.empty"
:project-path="projectPath"
:is-locked="isLocked"
:is-locked="Boolean(pathLockedByUser)"
:can-lock="canLock"
/>
</template>
......
......@@ -11,6 +11,10 @@ query getBlobInfo($projectPath: ID!, $filePath: String!, $ref: String!) {
nodes {
id
path
user {
id
username
}
}
}
repository {
......
......@@ -38,6 +38,7 @@ class ProjectsController < Projects::ApplicationController
push_frontend_feature_flag(:highlight_js, @project, default_enabled: :yaml)
push_frontend_feature_flag(:increase_page_size_exponentially, @project, default_enabled: :yaml)
push_frontend_feature_flag(:new_dir_modal, @project, default_enabled: :yaml)
push_licensed_feature(:file_locks) if @project.present? && @project.licensed_feature_available?(:file_locks)
end
layout :determine_layout
......
......@@ -37,11 +37,12 @@ export default {
data() {
return {
lockLoading: false,
locked: this.isLocked,
};
},
computed: {
lockButtonTitle() {
return this.isLocked ? this.$options.i18n.unlock : this.$options.i18n.lock;
return this.locked ? this.$options.i18n.unlock : this.$options.i18n.lock;
},
lockConfirmText() {
return sprintf(__('Are you sure you want to %{action} %{name}?'), {
......@@ -65,13 +66,14 @@ export default {
variables: {
filePath: this.path,
projectPath: this.projectPath,
lock: !this.isLocked,
lock: !this.locked,
},
})
.catch((error) => {
createFlash({ message: error, captureError: true, error });
})
.finally(() => {
this.locked = !this.locked;
this.lockLoading = false;
});
},
......@@ -80,7 +82,7 @@ export default {
</script>
<template>
<gl-button v-if="canLock" :loading="lockLoading" @click="onLockToggle">
<gl-button :disabled="!canLock" :loading="lockLoading" @click="onLockToggle">
{{ lockButtonTitle }}
</gl-button>
</template>
......@@ -51,10 +51,10 @@ describe('LockButton component', () => {
afterEach(() => confirmSpy.mockRestore());
it('does not render if canLock is set to false', () => {
it('disables the lock button if canLock is set to false', () => {
createComponent({ canLock: false });
expect(findLockButton().exists()).toBe(false);
expect(findLockButton().props('disabled')).toBe(true);
});
it.each`
......
......@@ -318,8 +318,14 @@ describe('Blob content viewer component', () => {
repository: { empty },
} = projectMock;
afterEach(() => {
delete gon.current_user_id;
delete gon.current_username;
});
it('renders component', async () => {
window.gon.current_user_id = 1;
window.gon.current_username = 'root';
await createComponent({ pushCode, downloadCode, empty }, mount);
......@@ -330,28 +336,34 @@ describe('Blob content viewer component', () => {
deletePath: webPath,
canPushCode: pushCode,
canLock: true,
isLocked: false,
isLocked: true,
emptyRepo: empty,
});
});
it.each`
canPushCode | canDownloadCode | canLock
${true} | ${true} | ${true}
${false} | ${true} | ${false}
${true} | ${false} | ${false}
`('passes the correct lock states', async ({ canPushCode, canDownloadCode, canLock }) => {
await createComponent(
{
pushCode: canPushCode,
downloadCode: canDownloadCode,
empty,
},
mount,
);
canPushCode | canDownloadCode | username | canLock
${true} | ${true} | ${'root'} | ${true}
${false} | ${true} | ${'root'} | ${false}
${true} | ${false} | ${'root'} | ${false}
${true} | ${true} | ${'peter'} | ${false}
`(
'passes the correct lock states',
async ({ canPushCode, canDownloadCode, username, canLock }) => {
gon.current_username = username;
await createComponent(
{
pushCode: canPushCode,
downloadCode: canDownloadCode,
empty,
},
mount,
);
expect(findBlobButtonGroup().props('canLock')).toBe(canLock);
});
expect(findBlobButtonGroup().props('canLock')).toBe(canLock);
},
);
it('does not render if not logged in', async () => {
isLoggedIn.mockReturnValueOnce(false);
......
......@@ -47,7 +47,13 @@ export const projectMock = {
id: '1234',
userPermissions: userPermissionsMock,
pathLocks: {
nodes: [],
nodes: [
{
id: 'test',
path: simpleViewerMock.path,
user: { id: '123', username: 'root' },
},
],
},
repository: {
empty: false,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment