summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget')
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents.vue44
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_create_view.vue83
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_labels_view.vue24
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_value_collapsed.vue55
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/create_label.mutation.graphql15
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue5
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/store/actions.js26
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/store/mutation_types.js4
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/store/mutations.js11
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/store/state.js1
10 files changed, 161 insertions, 107 deletions
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents.vue
index d80b66fd9be..1f0704f7308 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents.vue
@@ -1,5 +1,6 @@
<script>
-import { mapGetters, mapState } from 'vuex';
+import { GlButton } from '@gitlab/ui';
+import { mapActions, mapGetters, mapState } from 'vuex';
import DropdownContentsCreateView from './dropdown_contents_create_view.vue';
import DropdownContentsLabelsView from './dropdown_contents_labels_view.vue';
@@ -8,6 +9,7 @@ export default {
components: {
DropdownContentsLabelsView,
DropdownContentsCreateView,
+ GlButton,
},
props: {
renderOnTop: {
@@ -15,10 +17,14 @@ export default {
required: false,
default: false,
},
+ labelsCreateTitle: {
+ type: String,
+ required: true,
+ },
},
computed: {
- ...mapState(['showDropdownContentsCreateView']),
- ...mapGetters(['isDropdownVariantSidebar']),
+ ...mapState(['showDropdownContentsCreateView', 'labelsListTitle']),
+ ...mapGetters(['isDropdownVariantSidebar', 'isDropdownVariantEmbedded']),
dropdownContentsView() {
if (this.showDropdownContentsCreateView) {
return 'dropdown-contents-create-view';
@@ -29,6 +35,12 @@ export default {
const bottom = this.isDropdownVariantSidebar ? '3rem' : '2rem';
return this.renderOnTop ? { bottom } : {};
},
+ dropdownTitle() {
+ return this.showDropdownContentsCreateView ? this.labelsCreateTitle : this.labelsListTitle;
+ },
+ },
+ methods: {
+ ...mapActions(['toggleDropdownContentsCreateView', 'toggleDropdownContents']),
},
};
</script>
@@ -39,6 +51,30 @@ export default {
data-qa-selector="labels_dropdown_content"
:style="directionStyle"
>
- <component :is="dropdownContentsView" />
+ <div
+ v-if="isDropdownVariantSidebar || isDropdownVariantEmbedded"
+ class="dropdown-title gl-display-flex gl-align-items-center gl-pt-0 gl-pb-3!"
+ data-testid="dropdown-title"
+ >
+ <gl-button
+ v-if="showDropdownContentsCreateView"
+ :aria-label="__('Go back')"
+ variant="link"
+ size="small"
+ class="js-btn-back dropdown-header-button p-0"
+ icon="arrow-left"
+ @click="toggleDropdownContentsCreateView"
+ />
+ <span class="flex-grow-1">{{ dropdownTitle }}</span>
+ <gl-button
+ :aria-label="__('Close')"
+ variant="link"
+ size="small"
+ class="dropdown-header-button gl-p-0!"
+ icon="close"
+ @click="toggleDropdownContents"
+ />
+ </div>
+ <component :is="dropdownContentsView" @hideCreateView="toggleDropdownContentsCreateView" />
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_create_view.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_create_view.vue
index f8cc981ba3d..a7f20fbe851 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_create_view.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_create_view.vue
@@ -1,6 +1,10 @@
<script>
import { GlTooltipDirective, GlButton, GlFormInput, GlLink, GlLoadingIcon } from '@gitlab/ui';
-import { mapState, mapActions } from 'vuex';
+import createFlash from '~/flash';
+import { __ } from '~/locale';
+import createLabelMutation from './graphql/create_label.mutation.graphql';
+
+const errorMessage = __('Error creating label.');
export default {
components: {
@@ -12,14 +16,19 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
+ inject: {
+ projectPath: {
+ default: '',
+ },
+ },
data() {
return {
labelTitle: '',
selectedColor: '',
+ labelCreateInProgress: false,
};
},
computed: {
- ...mapState(['labelsCreateTitle', 'labelCreateInProgress']),
disableCreate() {
return !this.labelTitle.length || !this.selectedColor.length || this.labelCreateInProgress;
},
@@ -29,7 +38,6 @@ export default {
},
},
methods: {
- ...mapActions(['toggleDropdownContents', 'toggleDropdownContentsCreateView', 'createLabel']),
getColorCode(color) {
return Object.keys(color).pop();
},
@@ -39,11 +47,27 @@ export default {
handleColorClick(color) {
this.selectedColor = this.getColorCode(color);
},
- handleCreateClick() {
- this.createLabel({
- title: this.labelTitle,
- color: this.selectedColor,
- });
+ async createLabel() {
+ this.labelCreateInProgress = true;
+ try {
+ const {
+ data: { labelCreate },
+ } = await this.$apollo.mutate({
+ mutation: createLabelMutation,
+ variables: {
+ title: this.labelTitle,
+ color: this.selectedColor,
+ projectPath: this.projectPath,
+ },
+ });
+ if (labelCreate.errors.length) {
+ createFlash({ message: errorMessage });
+ }
+ } catch {
+ createFlash({ message: errorMessage });
+ }
+ this.labelCreateInProgress = false;
+ this.$emit('hideCreateView');
},
},
};
@@ -51,34 +75,16 @@ export default {
<template>
<div class="labels-select-contents-create js-labels-create">
- <div class="dropdown-title d-flex align-items-center pt-0 pb-2">
- <gl-button
- :aria-label="__('Go back')"
- variant="link"
- size="small"
- class="js-btn-back dropdown-header-button p-0"
- icon="arrow-left"
- @click="toggleDropdownContentsCreateView"
- />
- <span class="flex-grow-1">{{ labelsCreateTitle }}</span>
- <gl-button
- :aria-label="__('Close')"
- variant="link"
- size="small"
- class="dropdown-header-button p-0"
- icon="close"
- @click="toggleDropdownContents"
- />
- </div>
<div class="dropdown-input">
<gl-form-input
v-model.trim="labelTitle"
:placeholder="__('Name new label')"
:autofocus="true"
+ data-testid="label-title-input"
/>
</div>
- <div class="dropdown-content px-2">
- <div class="suggest-colors suggest-colors-dropdown mt-0 mb-2">
+ <div class="dropdown-content gl-px-3">
+ <div class="suggest-colors suggest-colors-dropdown gl-mt-0! gl-mb-3!">
<gl-link
v-for="(color, index) in suggestedColors"
:key="index"
@@ -90,28 +96,35 @@ export default {
</div>
<div class="color-input-container gl-display-flex">
<span
- class="dropdown-label-color-preview position-relative position-relative d-inline-block"
+ class="dropdown-label-color-preview gl-relative gl-display-inline-block"
+ data-testid="selected-color"
:style="{ backgroundColor: selectedColor }"
></span>
<gl-form-input
v-model.trim="selectedColor"
class="gl-rounded-top-left-none gl-rounded-bottom-left-none"
:placeholder="__('Use custom color #FF0000')"
+ data-testid="selected-color-text"
/>
</div>
</div>
- <div class="dropdown-actions clearfix pt-2 px-2">
+ <div class="dropdown-actions gl-display-flex gl-justify-content-space-between gl-pt-3 gl-px-3">
<gl-button
:disabled="disableCreate"
category="primary"
variant="success"
- class="float-left d-flex align-items-center"
- @click="handleCreateClick"
+ class="gl-display-flex gl-align-items-center"
+ data-testid="create-button"
+ @click="createLabel"
>
- <gl-loading-icon v-show="labelCreateInProgress" :inline="true" class="mr-1" />
+ <gl-loading-icon v-if="labelCreateInProgress" :inline="true" class="mr-1" />
{{ __('Create') }}
</gl-button>
- <gl-button class="float-right js-btn-cancel-create" @click="toggleDropdownContentsCreateView">
+ <gl-button
+ class="js-btn-cancel-create"
+ data-testid="cancel-button"
+ @click="$emit('hideCreateView')"
+ >
{{ __('Cancel') }}
</gl-button>
</div>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_labels_view.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_labels_view.vue
index 86788a84260..bff34743344 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_labels_view.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_labels_view.vue
@@ -1,11 +1,5 @@
<script>
-import {
- GlIntersectionObserver,
- GlLoadingIcon,
- GlButton,
- GlSearchBoxByType,
- GlLink,
-} from '@gitlab/ui';
+import { GlIntersectionObserver, GlLoadingIcon, GlSearchBoxByType, GlLink } from '@gitlab/ui';
import fuzzaldrinPlus from 'fuzzaldrin-plus';
import { mapState, mapGetters, mapActions } from 'vuex';
@@ -17,7 +11,6 @@ export default {
components: {
GlIntersectionObserver,
GlLoadingIcon,
- GlButton,
GlSearchBoxByType,
GlLink,
LabelItem,
@@ -149,21 +142,6 @@ export default {
<template>
<gl-intersection-observer @appear="handleComponentAppear" @disappear="handleComponentDisappear">
<div class="labels-select-contents-list js-labels-list" @keydown="handleKeyDown">
- <div
- v-if="isDropdownVariantSidebar || isDropdownVariantEmbedded"
- class="dropdown-title gl-display-flex gl-align-items-center gl-pt-0 gl-pb-3!"
- data-testid="dropdown-title"
- >
- <span class="flex-grow-1">{{ labelsListTitle }}</span>
- <gl-button
- :aria-label="__('Close')"
- variant="link"
- size="small"
- class="dropdown-header-button gl-p-0!"
- icon="close"
- @click="toggleDropdownContents"
- />
- </div>
<div class="dropdown-input" @click.stop="() => {}">
<gl-search-box-by-type
ref="searchInput"
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_value_collapsed.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_value_collapsed.vue
new file mode 100644
index 00000000000..122250d1ce7
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_value_collapsed.vue
@@ -0,0 +1,55 @@
+<script>
+import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
+import { s__, sprintf } from '~/locale';
+
+export default {
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ components: {
+ GlIcon,
+ },
+ props: {
+ labels: {
+ type: Array,
+ required: true,
+ },
+ },
+ computed: {
+ labelsList() {
+ const labelsString = this.labels.length
+ ? this.labels
+ .slice(0, 5)
+ .map((label) => label.title)
+ .join(', ')
+ : s__('LabelSelect|Labels');
+
+ if (this.labels.length > 5) {
+ return sprintf(s__('LabelSelect|%{labelsString}, and %{remainingLabelCount} more'), {
+ labelsString,
+ remainingLabelCount: this.labels.length - 5,
+ });
+ }
+
+ return labelsString;
+ },
+ },
+ methods: {
+ handleClick() {
+ this.$emit('onValueClick');
+ },
+ },
+};
+</script>
+
+<template>
+ <div
+ v-gl-tooltip.left.viewport
+ :title="labelsList"
+ class="sidebar-collapsed-icon"
+ @click="handleClick"
+ >
+ <gl-icon name="labels" />
+ <span>{{ labels.length }}</span>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/create_label.mutation.graphql b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/create_label.mutation.graphql
new file mode 100644
index 00000000000..9aa4f5d165e
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/create_label.mutation.graphql
@@ -0,0 +1,15 @@
+mutation createLabel($title: String!, $color: String, $projectPath: ID, $groupPath: ID) {
+ labelCreate(
+ input: { title: $title, color: $color, projectPath: $projectPath, groupPath: $groupPath }
+ ) {
+ label {
+ id
+ color
+ description
+ descriptionHtml
+ title
+ textColor
+ }
+ errors
+ }
+}
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue
index bf30e3cfac5..7728c758e18 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue
@@ -5,13 +5,12 @@ import Vuex, { mapState, mapActions, mapGetters } from 'vuex';
import { isInViewport } from '~/lib/utils/common_utils';
import { __ } from '~/locale';
-import DropdownValueCollapsed from '~/vue_shared/components/sidebar/labels_select_vue/dropdown_value_collapsed.vue';
-
import { DropdownVariant } from './constants';
import DropdownButton from './dropdown_button.vue';
import DropdownContents from './dropdown_contents.vue';
import DropdownTitle from './dropdown_title.vue';
import DropdownValue from './dropdown_value.vue';
+import DropdownValueCollapsed from './dropdown_value_collapsed.vue';
import labelsSelectModule from './store';
Vue.use(Vuex);
@@ -163,7 +162,6 @@ export default {
labelsFilterBasePath: this.labelsFilterBasePath,
labelsFilterParam: this.labelsFilterParam,
labelsListTitle: this.labelsListTitle,
- labelsCreateTitle: this.labelsCreateTitle,
footerCreateLabelTitle: this.footerCreateLabelTitle,
footerManageLabelTitle: this.footerManageLabelTitle,
});
@@ -313,6 +311,7 @@ export default {
v-show="dropdownButtonVisible && showDropdownContents"
ref="dropdownContents"
:render-on-top="!contentIsOnViewport"
+ :labels-create-title="labelsCreateTitle"
/>
</template>
<template v-if="isDropdownVariantStandalone || isDropdownVariantEmbedded">
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/store/actions.js b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/store/actions.js
index 89f96ab916b..2b96b159ca3 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/store/actions.js
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/store/actions.js
@@ -28,31 +28,5 @@ export const fetchLabels = ({ state, dispatch }) => {
.catch(() => dispatch('receiveLabelsFailure'));
};
-export const requestCreateLabel = ({ commit }) => commit(types.REQUEST_CREATE_LABEL);
-export const receiveCreateLabelSuccess = ({ commit }) => commit(types.RECEIVE_CREATE_LABEL_SUCCESS);
-export const receiveCreateLabelFailure = ({ commit }) => {
- commit(types.RECEIVE_CREATE_LABEL_FAILURE);
- flash(__('Error creating label.'));
-};
-export const createLabel = ({ state, dispatch }, label) => {
- dispatch('requestCreateLabel');
- axios
- .post(state.labelsManagePath, {
- label,
- })
- .then(({ data }) => {
- if (data.id) {
- dispatch('receiveCreateLabelSuccess');
- dispatch('toggleDropdownContentsCreateView');
- } else {
- // eslint-disable-next-line @gitlab/require-i18n-strings
- throw new Error('Error Creating Label');
- }
- })
- .catch(() => {
- dispatch('receiveCreateLabelFailure');
- });
-};
-
export const updateSelectedLabels = ({ commit }, labels) =>
commit(types.UPDATE_SELECTED_LABELS, { labels });
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/store/mutation_types.js b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/store/mutation_types.js
index 2e044dc3b3c..b8da7a90b36 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/store/mutation_types.js
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/store/mutation_types.js
@@ -8,10 +8,6 @@ export const REQUEST_SET_LABELS = 'REQUEST_SET_LABELS';
export const RECEIVE_SET_LABELS_SUCCESS = 'RECEIVE_SET_LABELS_SUCCESS';
export const RECEIVE_SET_LABELS_FAILURE = 'RECEIVE_SET_LABELS_FAILURE';
-export const REQUEST_CREATE_LABEL = 'REQUEST_CREATE_LABEL';
-export const RECEIVE_CREATE_LABEL_SUCCESS = 'RECEIVE_CREATE_LABEL_SUCCESS';
-export const RECEIVE_CREATE_LABEL_FAILURE = 'RECEIVE_CREATE_LABEL_FAILURE';
-
export const TOGGLE_DROPDOWN_BUTTON = 'TOGGLE_DROPDOWN_VISIBILITY';
export const TOGGLE_DROPDOWN_CONTENTS = 'TOGGLE_DROPDOWN_CONTENTS';
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/store/mutations.js b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/store/mutations.js
index 55716e1105e..131c6e6fb57 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/store/mutations.js
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/store/mutations.js
@@ -46,17 +46,6 @@ export default {
[types.RECEIVE_SET_LABELS_FAILURE](state) {
state.labelsFetchInProgress = false;
},
-
- [types.REQUEST_CREATE_LABEL](state) {
- state.labelCreateInProgress = true;
- },
- [types.RECEIVE_CREATE_LABEL_SUCCESS](state) {
- state.labelCreateInProgress = false;
- },
- [types.RECEIVE_CREATE_LABEL_FAILURE](state) {
- state.labelCreateInProgress = false;
- },
-
[types.UPDATE_SELECTED_LABELS](state, { labels }) {
// Find the label to update from all the labels
// and change `set` prop value to represent their current state.
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/store/state.js b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/store/state.js
index d66cfed4163..220bab05ed2 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/store/state.js
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/store/state.js
@@ -3,7 +3,6 @@ export default () => ({
labels: [],
selectedLabels: [],
labelsListTitle: '',
- labelsCreateTitle: '',
footerCreateLabelTitle: '',
footerManageLabelTitle: '',
dropdownButtonText: '',