Commit 25fd2983 authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch 'ide-commit-actions-update' into 'master'

Improve commit flow in Web IDE

Closes #46122

See merge request gitlab-org/gitlab-ce!19735
parents 6d4a0325 7e8e5229
...@@ -34,6 +34,10 @@ export default { ...@@ -34,6 +34,10 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
actionBtnIcon: {
type: String,
required: true,
},
itemActionComponent: { itemActionComponent: {
type: String, type: String,
required: true, required: true,
...@@ -53,26 +57,21 @@ export default { ...@@ -53,26 +57,21 @@ export default {
required: true, required: true,
}, },
}, },
data() {
return {
showActionButton: false,
};
},
computed: { computed: {
titleText() { titleText() {
return sprintf(__('%{title} changes'), { return sprintf(__('%{title} changes'), {
title: this.title, title: this.title,
}); });
}, },
filesLength() {
return this.fileList.length;
},
}, },
methods: { methods: {
...mapActions(['stageAllChanges', 'unstageAllChanges']), ...mapActions(['stageAllChanges', 'unstageAllChanges']),
actionBtnClicked() { actionBtnClicked() {
this[this.action](); this[this.action]();
}, },
setShowActionButton(show) {
this.showActionButton = show;
},
}, },
}; };
</script> </script>
...@@ -83,8 +82,6 @@ export default { ...@@ -83,8 +82,6 @@ export default {
> >
<header <header
class="multi-file-commit-panel-header" class="multi-file-commit-panel-header"
@mouseenter="setShowActionButton(true)"
@mouseleave="setShowActionButton(false)"
> >
<div <div
class="multi-file-commit-panel-header-title" class="multi-file-commit-panel-header-title"
...@@ -95,24 +92,40 @@ export default { ...@@ -95,24 +92,40 @@ export default {
:size="18" :size="18"
/> />
{{ titleText }} {{ titleText }}
<span <div class="d-flex ml-auto">
v-show="!showActionButton" <button
class="ide-commit-file-count" v-tooltip
> v-show="filesLength"
{{ fileList.length }} :class="{
</span> 'd-flex': filesLength
<button }"
v-show="showActionButton" :title="actionBtnText"
type="button" type="button"
class="btn btn-blank btn-link ide-staged-action-btn" class="btn btn-default ide-staged-action-btn p-0 order-1 align-items-center"
@click="actionBtnClicked" data-placement="bottom"
> data-container="body"
{{ actionBtnText }} data-boundary="viewport"
</button> @click="actionBtnClicked"
>
<icon
:name="actionBtnIcon"
:size="12"
class="ml-auto mr-auto"
/>
</button>
<span
:class="{
'rounded-right': !filesLength
}"
class="ide-commit-file-count order-0 rounded-left text-center"
>
{{ filesLength }}
</span>
</div>
</div> </div>
</header> </header>
<ul <ul
v-if="fileList.length" v-if="filesLength"
class="multi-file-commit-list list-unstyled append-bottom-0" class="multi-file-commit-list list-unstyled append-bottom-0"
> >
<li <li
......
<script> <script>
import { mapActions } from 'vuex'; import { mapActions } from 'vuex';
import tooltip from '~/vue_shared/directives/tooltip';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import StageButton from './stage_button.vue'; import StageButton from './stage_button.vue';
import UnstageButton from './unstage_button.vue'; import UnstageButton from './unstage_button.vue';
...@@ -11,6 +12,9 @@ export default { ...@@ -11,6 +12,9 @@ export default {
StageButton, StageButton,
UnstageButton, UnstageButton,
}, },
directives: {
tooltip,
},
props: { props: {
file: { file: {
type: Object, type: Object,
...@@ -50,6 +54,9 @@ export default { ...@@ -50,6 +54,9 @@ export default {
isActive() { isActive() {
return this.activeFileKey === this.fullKey; return this.activeFileKey === this.fullKey;
}, },
tooltipTitle() {
return this.file.path === this.file.name ? '' : this.file.path;
},
}, },
methods: { methods: {
...mapActions([ ...mapActions([
...@@ -81,29 +88,30 @@ export default { ...@@ -81,29 +88,30 @@ export default {
</script> </script>
<template> <template>
<div <div class="multi-file-commit-list-item position-relative">
:class="{
'is-active': isActive
}"
class="multi-file-commit-list-item"
>
<button <button
v-tooltip
:title="tooltipTitle"
:class="{
'is-active': isActive
}"
type="button" type="button"
class="multi-file-commit-list-path" class="multi-file-commit-list-path w-100 border-0 ml-0 mr-0"
@dblclick="fileAction" @dblclick="fileAction"
@click="openFileInEditor" @click="openFileInEditor"
> >
<span class="multi-file-commit-list-file-path"> <span class="multi-file-commit-list-file-path d-flex align-items-center">
<icon <icon
:name="iconName" :name="iconName"
:size="16" :size="16"
:css-classes="iconClass" :css-classes="iconClass"
/>{{ file.path }} />{{ file.name }}
</span> </span>
</button> </button>
<component <component
:is="actionComponent" :is="actionComponent"
:path="file.path" :path="file.path"
class="d-flex position-absolute"
/> />
</div> </div>
</template> </template>
...@@ -25,15 +25,17 @@ export default { ...@@ -25,15 +25,17 @@ export default {
<template> <template>
<div <div
v-once v-once
class="multi-file-discard-btn" class="multi-file-discard-btn dropdown"
> >
<button <button
v-tooltip v-tooltip
:aria-label="__('Stage changes')" :aria-label="__('Stage changes')"
:title="__('Stage changes')" :title="__('Stage changes')"
type="button" type="button"
class="btn btn-blank append-right-5" class="btn btn-blank append-right-5 d-flex align-items-center"
data-container="body" data-container="body"
data-boundary="viewport"
data-placement="bottom"
@click.stop="stageChange(path)" @click.stop="stageChange(path)"
> >
<icon <icon
...@@ -43,17 +45,31 @@ export default { ...@@ -43,17 +45,31 @@ export default {
</button> </button>
<button <button
v-tooltip v-tooltip
:aria-label="__('Discard changes')" :title="__('More actions')"
:title="__('Discard changes')"
type="button" type="button"
class="btn btn-blank" class="btn btn-blank d-flex align-items-center"
data-container="body" data-container="body"
@click.stop="discardFileChanges(path)" data-boundary="viewport"
data-placement="bottom"
data-toggle="dropdown"
data-display="static"
> >
<icon <icon
:size="12" :size="12"
name="remove" name="more"
/> />
</button> </button>
<div class="dropdown-menu dropdown-menu-right">
<ul>
<li>
<button
type="button"
@click.stop="discardFileChanges(path)"
>
{{ __('Discard changes') }}
</button>
</li>
</ul>
</div>
</div> </div>
</template> </template>
...@@ -32,8 +32,10 @@ export default { ...@@ -32,8 +32,10 @@ export default {
:aria-label="__('Unstage changes')" :aria-label="__('Unstage changes')"
:title="__('Unstage changes')" :title="__('Unstage changes')"
type="button" type="button"
class="btn btn-blank" class="btn btn-blank d-flex align-items-center"
data-container="body" data-container="body"
data-boundary="viewport"
data-placement="bottom"
@click="unstageChange(path)" @click="unstageChange(path)"
> >
<icon <icon
......
...@@ -93,23 +93,25 @@ export default { ...@@ -93,23 +93,25 @@ export default {
:title="__('Unstaged')" :title="__('Unstaged')"
:key-prefix="$options.stageKeys.unstaged" :key-prefix="$options.stageKeys.unstaged"
:file-list="changedFiles" :file-list="changedFiles"
:action-btn-text="__('Stage all')" :action-btn-text="__('Stage all changes')"
:active-file-key="activeFileKey" :active-file-key="activeFileKey"
class="is-first"
icon-name="unstaged"
action="stageAllChanges" action="stageAllChanges"
action-btn-icon="mobile-issue-close"
item-action-component="stage-button" item-action-component="stage-button"
class="is-first"
icon-name="unstaged"
/> />
<commit-files-list <commit-files-list
:title="__('Staged')" :title="__('Staged')"
:key-prefix="$options.stageKeys.staged" :key-prefix="$options.stageKeys.staged"
:file-list="stagedFiles" :file-list="stagedFiles"
:action-btn-text="__('Unstage all')" :action-btn-text="__('Unstage all changes')"
:staged-list="true" :staged-list="true"
:active-file-key="activeFileKey" :active-file-key="activeFileKey"
icon-name="staged"
action="unstageAllChanges" action="unstageAllChanges"
action-btn-icon="history"
item-action-component="unstage-button" item-action-component="unstage-button"
icon-name="staged"
/> />
</template> </template>
<empty-state <empty-state
......
...@@ -540,36 +540,12 @@ ...@@ -540,36 +540,12 @@
margin-right: -$grid-size; margin-right: -$grid-size;
min-height: 60px; min-height: 60px;
.multi-file-commit-list-item {
margin-left: 0;
margin-right: 0;
}
&.form-text.text-muted { &.form-text.text-muted {
margin-left: 0; margin-left: 0;
right: 0; right: 0;
} }
} }
.multi-file-commit-list-item {
&.is-active {
background-color: $white-normal;
}
.multi-file-discard-btn {
display: none;
margin-top: -2px;
margin-left: auto;
color: $gl-link-color;
}
&:hover {
.multi-file-discard-btn {
display: flex;
}
}
}
.multi-file-addition, .multi-file-addition,
.multi-file-addition-solid { .multi-file-addition-solid {
color: $green-500; color: $green-500;
...@@ -599,7 +575,7 @@ ...@@ -599,7 +575,7 @@
} }
} }
.multi-file-commit-list-item, .multi-file-commit-list-path,
.ide-file-list .file { .ide-file-list .file {
display: flex; display: flex;
align-items: center; align-items: center;
...@@ -616,11 +592,9 @@ ...@@ -616,11 +592,9 @@
} }
.multi-file-commit-list-path { .multi-file-commit-list-path {
padding: 0; &.is-active {
background: none; background-color: $white-normal;
border: 0; }
text-align: left;
width: 100%;
&:hover, &:hover,
&:focus { &:focus {
...@@ -635,7 +609,7 @@ ...@@ -635,7 +609,7 @@
} }
.multi-file-commit-list-file-path { .multi-file-commit-list-file-path {
@include str-truncated(100%); @include str-truncated(calc(100% - 30px));
&:hover { &:hover {
text-decoration: underline; text-decoration: underline;
...@@ -646,6 +620,16 @@ ...@@ -646,6 +620,16 @@
} }
} }
.multi-file-discard-btn {
top: 4px;
right: 8px;
bottom: 4px;
svg {
top: 0;
}
}
.multi-file-commit-form { .multi-file-commit-form {
position: relative; position: relative;
background-color: $white-light; background-color: $white-light;
...@@ -840,18 +824,20 @@ ...@@ -840,18 +824,20 @@
} }
.ide-staged-action-btn { .ide-staged-action-btn {
margin-left: auto; width: 22px;
line-height: 22px; margin-left: -1px;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
> svg {
top: 0;
}
} }
.ide-commit-file-count { .ide-commit-file-count {
min-width: 22px; min-width: 22px;
margin-left: auto;
background-color: $gray-light; background-color: $gray-light;
border-radius: $border-radius-default;
border: 1px solid $white-dark; border: 1px solid $white-dark;
line-height: 20px;
text-align: center;
} }
.ide-commit-radios { .ide-commit-radios {
......
---
title: Improve Web IDE commit flow
merge_request:
author:
type: changed
...@@ -93,14 +93,14 @@ describe('Multi-file editor commit sidebar list item', () => { ...@@ -93,14 +93,14 @@ describe('Multi-file editor commit sidebar list item', () => {
describe('is active', () => { describe('is active', () => {
it('does not add active class when dont keys match', () => { it('does not add active class when dont keys match', () => {
expect(vm.$el.classList).not.toContain('is-active'); expect(vm.$el.querySelector('.is-active')).toBe(null);
}); });
it('adds active class when keys match', done => { it('adds active class when keys match', done => {
vm.keyPrefix = 'staged'; vm.keyPrefix = 'staged';
vm.$nextTick(() => { vm.$nextTick(() => {
expect(vm.$el.classList).toContain('is-active'); expect(vm.$el.querySelector('.is-active')).not.toBe(null);
done(); done();
}); });
......
...@@ -16,6 +16,7 @@ describe('Multi-file editor commit sidebar list', () => { ...@@ -16,6 +16,7 @@ describe('Multi-file editor commit sidebar list', () => {
iconName: 'staged', iconName: 'staged',
action: 'stageAllChanges', action: 'stageAllChanges',
actionBtnText: 'stage all', actionBtnText: 'stage all',
actionBtnIcon: 'history',
itemActionComponent: 'stage-button', itemActionComponent: 'stage-button',
activeFileKey: 'staged-testing', activeFileKey: 'staged-testing',
keyPrefix: 'staged', keyPrefix: 'staged',
...@@ -42,7 +43,7 @@ describe('Multi-file editor commit sidebar list', () => { ...@@ -42,7 +43,7 @@ describe('Multi-file editor commit sidebar list', () => {
}); });
it('renders list', () => { it('renders list', () => {
expect(vm.$el.querySelectorAll('li').length).toBe(1); expect(vm.$el.querySelectorAll('.multi-file-commit-list > li').length).toBe(1);
}); });
}); });
......
...@@ -39,7 +39,7 @@ describe('IDE stage file button', () => { ...@@ -39,7 +39,7 @@ describe('IDE stage file button', () => {
}); });
it('calls store with discard button', () => { it('calls store with discard button', () => {
vm.$el.querySelectorAll('.btn')[1].click(); vm.$el.querySelector('.dropdown-menu button').click();
expect(vm.discardFileChanges).toHaveBeenCalledWith(f.path); expect(vm.discardFileChanges).toHaveBeenCalledWith(f.path);
}); });
......
...@@ -111,7 +111,7 @@ describe('RepoCommitSection', () => { ...@@ -111,7 +111,7 @@ describe('RepoCommitSection', () => {
}); });
it('renders a commit section', () => { it('renders a commit section', () => {
const changedFileElements = [...vm.$el.querySelectorAll('.multi-file-commit-list li')]; const changedFileElements = [...vm.$el.querySelectorAll('.multi-file-commit-list > li')];
const allFiles = vm.$store.state.changedFiles.concat(vm.$store.state.stagedFiles); const allFiles = vm.$store.state.changedFiles.concat(vm.$store.state.stagedFiles);
expect(changedFileElements.length).toEqual(4); expect(changedFileElements.length).toEqual(4);
...@@ -140,22 +140,26 @@ describe('RepoCommitSection', () => { ...@@ -140,22 +140,26 @@ describe('RepoCommitSection', () => {
vm.$el.querySelector('.multi-file-discard-btn .btn').click(); vm.$el.querySelector('.multi-file-discard-btn .btn').click();
Vue.nextTick(() => { Vue.nextTick(() => {
expect(vm.$el.querySelector('.ide-commit-list-container').querySelectorAll('li').length).toBe( expect(
1, vm.$el
); .querySelector('.ide-commit-list-container')
.querySelectorAll('.multi-file-commit-list > li').length,
).toBe(1);
done(); done();
}); });
}); });
it('discards a single file', done => { it('discards a single file', done => {
vm.$el.querySelectorAll('.multi-file-discard-btn .btn')[1].click(); vm.$el.querySelector('.multi-file-discard-btn .dropdown-menu button').click();
Vue.nextTick(() => { Vue.nextTick(() => {
expect(vm.$el.querySelector('.ide-commit-list-container').textContent).not.toContain('file1'); expect(vm.$el.querySelector('.ide-commit-list-container').textContent).not.toContain('file1');
expect(vm.$el.querySelector('.ide-commit-list-container').querySelectorAll('li').length).toBe( expect(
1, vm.$el
); .querySelector('.ide-commit-list-container')
.querySelectorAll('.multi-file-commit-list > li').length,
).toBe(1);
done(); done();
}); });
......
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