Commit 3bbf1bb1 authored by Brandon Labuschagne's avatar Brandon Labuschagne

Merge branch '341016-lock-button-bug-fix' into 'master'

Blob refactor: Disable lock button when locked by another user

See merge request gitlab-org/gitlab!76229
parents 7714f397 9fcb7542
......@@ -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