280 lines
8.5 KiB
Vue
280 lines
8.5 KiB
Vue
|
<script>
|
||
|
import { mapState, mapActions } from 'vuex';
|
||
|
import { GlModal, GlTabs, GlTab, GlSearchBoxByType, GlSprintf } from '@gitlab/ui';
|
||
|
import ReviewTabContainer from '~/add_context_commits_modal/components/review_tab_container.vue';
|
||
|
import { s__ } from '~/locale';
|
||
|
import eventHub from '../event_hub';
|
||
|
import { deprecatedCreateFlash as createFlash } from '~/flash';
|
||
|
import {
|
||
|
findCommitIndex,
|
||
|
setCommitStatus,
|
||
|
removeIfReadyToBeRemoved,
|
||
|
removeIfPresent,
|
||
|
} from '../utils';
|
||
|
|
||
|
export default {
|
||
|
components: {
|
||
|
GlModal,
|
||
|
GlTabs,
|
||
|
GlTab,
|
||
|
ReviewTabContainer,
|
||
|
GlSearchBoxByType,
|
||
|
GlSprintf,
|
||
|
},
|
||
|
props: {
|
||
|
contextCommitsPath: {
|
||
|
type: String,
|
||
|
required: true,
|
||
|
},
|
||
|
targetBranch: {
|
||
|
type: String,
|
||
|
required: true,
|
||
|
},
|
||
|
mergeRequestIid: {
|
||
|
type: Number,
|
||
|
required: true,
|
||
|
},
|
||
|
projectId: {
|
||
|
type: Number,
|
||
|
required: true,
|
||
|
},
|
||
|
},
|
||
|
computed: {
|
||
|
...mapState([
|
||
|
'tabIndex',
|
||
|
'isLoadingCommits',
|
||
|
'commits',
|
||
|
'commitsLoadingError',
|
||
|
'isLoadingContextCommits',
|
||
|
'contextCommits',
|
||
|
'contextCommitsLoadingError',
|
||
|
'selectedCommits',
|
||
|
'searchText',
|
||
|
'toRemoveCommits',
|
||
|
]),
|
||
|
currentTabIndex: {
|
||
|
get() {
|
||
|
return this.tabIndex;
|
||
|
},
|
||
|
set(newTabIndex) {
|
||
|
this.setTabIndex(newTabIndex);
|
||
|
},
|
||
|
},
|
||
|
selectedCommitsCount() {
|
||
|
return this.selectedCommits.filter(selectedCommit => selectedCommit.isSelected).length;
|
||
|
},
|
||
|
shouldPurge() {
|
||
|
return this.selectedCommitsCount !== this.selectedCommits.length;
|
||
|
},
|
||
|
uniqueCommits() {
|
||
|
return this.selectedCommits.filter(
|
||
|
selectedCommit =>
|
||
|
selectedCommit.isSelected &&
|
||
|
findCommitIndex(this.contextCommits, selectedCommit.short_id) === -1,
|
||
|
);
|
||
|
},
|
||
|
disableSaveButton() {
|
||
|
// We should have a minimum of one commit selected and that should not be in the context commits list or we should have a context commit to delete
|
||
|
return (
|
||
|
(this.selectedCommitsCount.length === 0 || this.uniqueCommits.length === 0) &&
|
||
|
this.toRemoveCommits.length === 0
|
||
|
);
|
||
|
},
|
||
|
},
|
||
|
watch: {
|
||
|
tabIndex(newTabIndex) {
|
||
|
this.handleTabChange(newTabIndex);
|
||
|
},
|
||
|
},
|
||
|
mounted() {
|
||
|
eventHub.$on('openModal', this.openModal);
|
||
|
this.setBaseConfig({
|
||
|
contextCommitsPath: this.contextCommitsPath,
|
||
|
mergeRequestIid: this.mergeRequestIid,
|
||
|
projectId: this.projectId,
|
||
|
});
|
||
|
},
|
||
|
beforeDestroy() {
|
||
|
eventHub.$off('openModal', this.openModal);
|
||
|
clearTimeout(this.timeout);
|
||
|
this.timeout = null;
|
||
|
},
|
||
|
methods: {
|
||
|
...mapActions([
|
||
|
'setBaseConfig',
|
||
|
'setTabIndex',
|
||
|
'searchCommits',
|
||
|
'setCommits',
|
||
|
'createContextCommits',
|
||
|
'fetchContextCommits',
|
||
|
'removeContextCommits',
|
||
|
'setSelectedCommits',
|
||
|
'setSearchText',
|
||
|
'setToRemoveCommits',
|
||
|
'resetModalState',
|
||
|
]),
|
||
|
focusSearch() {
|
||
|
this.$refs.searchInput.focusInput();
|
||
|
},
|
||
|
openModal() {
|
||
|
this.searchCommits();
|
||
|
this.fetchContextCommits();
|
||
|
this.$root.$emit('bv::show::modal', 'add-review-item');
|
||
|
},
|
||
|
handleTabChange(tabIndex) {
|
||
|
if (tabIndex === 0) {
|
||
|
this.focusSearch();
|
||
|
if (this.shouldPurge) {
|
||
|
this.setSelectedCommits(
|
||
|
[...this.commits, ...this.selectedCommits].filter(commit => commit.isSelected),
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
handleSearchCommits(value) {
|
||
|
// We only call the service, if we have 3 characters or we don't have any characters
|
||
|
if (value.length >= 3) {
|
||
|
clearTimeout(this.timeout);
|
||
|
this.timeout = setTimeout(() => {
|
||
|
this.searchCommits(value);
|
||
|
}, 500);
|
||
|
} else if (value.length === 0) {
|
||
|
this.searchCommits();
|
||
|
}
|
||
|
this.setSearchText(value);
|
||
|
},
|
||
|
handleCommitRowSelect(event) {
|
||
|
const index = event[0];
|
||
|
const selected = event[1];
|
||
|
const tempCommit = this.tabIndex === 0 ? this.commits[index] : this.selectedCommits[index];
|
||
|
const commitIndex = findCommitIndex(this.commits, tempCommit.short_id);
|
||
|
const tempCommits = setCommitStatus(this.commits, commitIndex, selected);
|
||
|
const selectedCommitIndex = findCommitIndex(this.selectedCommits, tempCommit.short_id);
|
||
|
let tempSelectedCommits = setCommitStatus(
|
||
|
this.selectedCommits,
|
||
|
selectedCommitIndex,
|
||
|
selected,
|
||
|
);
|
||
|
|
||
|
if (selected) {
|
||
|
// If user deselects a commit which is already present in previously merged commits, then user adds it again.
|
||
|
// Then the state is neutral, so we remove it from the list
|
||
|
this.setToRemoveCommits(
|
||
|
removeIfReadyToBeRemoved(this.toRemoveCommits, tempCommit.short_id),
|
||
|
);
|
||
|
} else {
|
||
|
// If user is present in first tab and deselects a commit, remove it directly
|
||
|
if (this.tabIndex === 0) {
|
||
|
tempSelectedCommits = removeIfPresent(tempSelectedCommits, tempCommit.short_id);
|
||
|
}
|
||
|
|
||
|
// If user deselects a commit which is already present in previously merged commits, we keep track of it in a list to remove
|
||
|
const contextCommitsIndex = findCommitIndex(this.contextCommits, tempCommit.short_id);
|
||
|
if (contextCommitsIndex !== -1) {
|
||
|
this.setToRemoveCommits([...this.toRemoveCommits, tempCommit.short_id]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.setCommits({ commits: tempCommits });
|
||
|
this.setSelectedCommits([
|
||
|
...tempSelectedCommits,
|
||
|
...tempCommits.filter(commit => commit.isSelected),
|
||
|
]);
|
||
|
},
|
||
|
handleCreateContextCommits() {
|
||
|
if (this.uniqueCommits.length > 0 && this.toRemoveCommits.length > 0) {
|
||
|
return Promise.all([
|
||
|
this.createContextCommits({ commits: this.uniqueCommits }),
|
||
|
this.removeContextCommits(),
|
||
|
]).then(values => {
|
||
|
if (values[0] || values[1]) {
|
||
|
window.location.reload();
|
||
|
}
|
||
|
if (!values[0] && !values[1]) {
|
||
|
createFlash(
|
||
|
s__('ContextCommits|Failed to create/remove context commits. Please try again.'),
|
||
|
);
|
||
|
}
|
||
|
});
|
||
|
} else if (this.uniqueCommits.length > 0) {
|
||
|
return this.createContextCommits({ commits: this.uniqueCommits, forceReload: true });
|
||
|
}
|
||
|
|
||
|
return this.removeContextCommits(true);
|
||
|
},
|
||
|
handleModalClose() {
|
||
|
this.resetModalState();
|
||
|
clearTimeout(this.timeout);
|
||
|
},
|
||
|
handleModalHide() {
|
||
|
this.resetModalState();
|
||
|
clearTimeout(this.timeout);
|
||
|
},
|
||
|
},
|
||
|
};
|
||
|
</script>
|
||
|
|
||
|
<template>
|
||
|
<gl-modal
|
||
|
ref="modal"
|
||
|
cancel-variant="light"
|
||
|
size="md"
|
||
|
body-class="add-review-item pt-0"
|
||
|
:scrollable="true"
|
||
|
:ok-title="__('Save changes')"
|
||
|
modal-id="add-review-item"
|
||
|
:title="__('Add or remove previously merged commits')"
|
||
|
:ok-disabled="disableSaveButton"
|
||
|
@shown="focusSearch"
|
||
|
@ok="handleCreateContextCommits"
|
||
|
@cancel="handleModalClose"
|
||
|
@close="handleModalClose"
|
||
|
@hide="handleModalHide"
|
||
|
>
|
||
|
<gl-tabs v-model="currentTabIndex" content-class="pt-0">
|
||
|
<gl-tab>
|
||
|
<template #title>
|
||
|
<gl-sprintf :message="__(`Commits in %{codeStart}${targetBranch}%{codeEnd}`)">
|
||
|
<template #code="{ content }">
|
||
|
<code>{{ content }}</code>
|
||
|
</template>
|
||
|
</gl-sprintf>
|
||
|
</template>
|
||
|
<div class="mt-2">
|
||
|
<gl-search-box-by-type
|
||
|
ref="searchInput"
|
||
|
:placeholder="__(`Search by commit title or SHA`)"
|
||
|
@input="handleSearchCommits"
|
||
|
/>
|
||
|
<review-tab-container
|
||
|
:is-loading="isLoadingCommits"
|
||
|
:loading-error="commitsLoadingError"
|
||
|
:loading-failed-text="__('Unable to load commits. Try again later.')"
|
||
|
:commits="commits"
|
||
|
:empty-list-text="__('Your search didn\'t match any commits. Try a different query.')"
|
||
|
@handleCommitSelect="handleCommitRowSelect"
|
||
|
/>
|
||
|
</div>
|
||
|
</gl-tab>
|
||
|
<gl-tab>
|
||
|
<template #title>
|
||
|
{{ __('Selected commits') }}
|
||
|
<span class="badge badge-pill">{{ selectedCommitsCount }}</span>
|
||
|
</template>
|
||
|
<review-tab-container
|
||
|
:is-loading="isLoadingContextCommits"
|
||
|
:loading-error="contextCommitsLoadingError"
|
||
|
:loading-failed-text="__('Unable to load commits. Try again later.')"
|
||
|
:commits="selectedCommits"
|
||
|
:empty-list-text="
|
||
|
__(
|
||
|
'Commits you select appear here. Go to the first tab and select commits to add to this merge request.',
|
||
|
)
|
||
|
"
|
||
|
@handleCommitSelect="handleCommitRowSelect"
|
||
|
/>
|
||
|
</gl-tab>
|
||
|
</gl-tabs>
|
||
|
</gl-modal>
|
||
|
</template>
|