Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-06-09 18:09:21 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-06-09 18:09:21 +0300
commitd2675fa4de909714fcc6dc1bdd7bee9ce5e3af34 (patch)
tree0c0fbdd55fbb3a1616b10775113bf8320c9529c8 /app/assets/javascripts/vue_shared/components/color_select_dropdown
parent48d25238c386a89e8a6af218eeb290936a8f7595 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/vue_shared/components/color_select_dropdown')
-rw-r--r--app/assets/javascripts/vue_shared/components/color_select_dropdown/color_item.vue25
-rw-r--r--app/assets/javascripts/vue_shared/components/color_select_dropdown/color_select_root.vue214
-rw-r--r--app/assets/javascripts/vue_shared/components/color_select_dropdown/constants.js30
-rw-r--r--app/assets/javascripts/vue_shared/components/color_select_dropdown/dropdown_contents.vue109
-rw-r--r--app/assets/javascripts/vue_shared/components/color_select_dropdown/dropdown_contents_color_view.vue53
-rw-r--r--app/assets/javascripts/vue_shared/components/color_select_dropdown/dropdown_header.vue31
-rw-r--r--app/assets/javascripts/vue_shared/components/color_select_dropdown/dropdown_value.vue43
-rw-r--r--app/assets/javascripts/vue_shared/components/color_select_dropdown/graphql/epic_color.query.graphql9
-rw-r--r--app/assets/javascripts/vue_shared/components/color_select_dropdown/graphql/epic_update_color.mutation.graphql9
-rw-r--r--app/assets/javascripts/vue_shared/components/color_select_dropdown/utils.js15
10 files changed, 538 insertions, 0 deletions
diff --git a/app/assets/javascripts/vue_shared/components/color_select_dropdown/color_item.vue b/app/assets/javascripts/vue_shared/components/color_select_dropdown/color_item.vue
new file mode 100644
index 00000000000..92817d5fa70
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/color_select_dropdown/color_item.vue
@@ -0,0 +1,25 @@
+<script>
+export default {
+ props: {
+ color: {
+ type: String,
+ required: true,
+ },
+ title: {
+ type: String,
+ required: true,
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <span
+ class="dropdown-label-box gl-flex-shrink-0 gl-top-1 gl-mr-0"
+ data-testid="color-item"
+ :style="{ backgroundColor: color }"
+ ></span>
+ <span class="hide-collapsed">{{ title }}</span>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/color_select_dropdown/color_select_root.vue b/app/assets/javascripts/vue_shared/components/color_select_dropdown/color_select_root.vue
new file mode 100644
index 00000000000..6b79883d76b
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/color_select_dropdown/color_select_root.vue
@@ -0,0 +1,214 @@
+<script>
+import createFlash from '~/flash';
+import { s__ } from '~/locale';
+import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue';
+import { DEFAULT_COLOR, COLOR_WIDGET_COLOR, DROPDOWN_VARIANT, ISSUABLE_COLORS } from './constants';
+import DropdownContents from './dropdown_contents.vue';
+import DropdownValue from './dropdown_value.vue';
+import { isDropdownVariantSidebar, isDropdownVariantEmbedded } from './utils';
+import epicColorQuery from './graphql/epic_color.query.graphql';
+import updateEpicColorMutation from './graphql/epic_update_color.mutation.graphql';
+
+export default {
+ i18n: {
+ assignColor: s__('ColorWidget|Assign epic color'),
+ dropdownButtonText: COLOR_WIDGET_COLOR,
+ fetchingError: s__('ColorWidget|Error fetching epic color.'),
+ updatingError: s__('ColorWidget|An error occurred while updating color.'),
+ widgetTitle: COLOR_WIDGET_COLOR,
+ },
+ components: {
+ DropdownValue,
+ DropdownContents,
+ SidebarEditableItem,
+ },
+ props: {
+ allowEdit: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ iid: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ fullPath: {
+ type: String,
+ required: true,
+ },
+ variant: {
+ type: String,
+ required: false,
+ default: DROPDOWN_VARIANT.Sidebar,
+ },
+ dropdownButtonText: {
+ type: String,
+ required: false,
+ default: COLOR_WIDGET_COLOR,
+ },
+ dropdownTitle: {
+ type: String,
+ required: false,
+ default: s__('ColorWidget|Assign epic color'),
+ },
+ },
+ data() {
+ return {
+ issuableColor: {
+ color: '',
+ title: '',
+ },
+ colorUpdateInProgress: false,
+ oldIid: null,
+ sidebarExpandedOnClick: false,
+ };
+ },
+ apollo: {
+ issuableColor: {
+ query: epicColorQuery,
+ skip() {
+ return !isDropdownVariantSidebar(this.variant);
+ },
+ variables() {
+ return {
+ iid: this.iid,
+ fullPath: this.fullPath,
+ };
+ },
+ update(data) {
+ const issuableColor = data.workspace?.issuable?.color;
+
+ if (issuableColor) {
+ return ISSUABLE_COLORS.find((color) => color.color === issuableColor) ?? DEFAULT_COLOR;
+ }
+
+ return DEFAULT_COLOR;
+ },
+ error() {
+ createFlash({
+ message: this.$options.i18n.fetchingError,
+ captureError: true,
+ });
+ },
+ },
+ },
+ computed: {
+ isLoading() {
+ return this.colorUpdateInProgress || this.$apollo.queries.issuableColor.loading;
+ },
+ },
+ watch: {
+ iid(_, oldVal) {
+ this.oldIid = oldVal;
+ },
+ },
+ methods: {
+ handleDropdownClose(color) {
+ if (this.iid !== '') {
+ this.updateSelectedColor(this.getUpdateVariables(color));
+ } else {
+ this.$emit('updateSelectedColor', color);
+ }
+
+ this.collapseEditableItem();
+ },
+ collapseEditableItem() {
+ this.$refs.editable?.collapse();
+ if (this.sidebarExpandedOnClick) {
+ this.sidebarExpandedOnClick = false;
+ this.$emit('toggleCollapse');
+ }
+ },
+ getUpdateVariables(color) {
+ const currentIid = this.oldIid || this.iid;
+
+ return {
+ iid: currentIid,
+ groupPath: this.fullPath,
+ color: color.color,
+ };
+ },
+ updateSelectedColor(inputVariables) {
+ this.colorUpdateInProgress = true;
+
+ this.$apollo
+ .mutate({
+ mutation: updateEpicColorMutation,
+ variables: { input: inputVariables },
+ })
+ .then(({ data }) => {
+ if (data.updateIssuableColor?.errors?.length) {
+ throw new Error();
+ }
+
+ this.$emit('updateSelectedColor', {
+ id: data.updateIssuableColor?.issuable?.id,
+ color: data.updateIssuableColor?.issuable?.color,
+ });
+ })
+ .catch((error) =>
+ createFlash({
+ message: this.$options.i18n.updatingError,
+ captureError: true,
+ error,
+ }),
+ )
+ .finally(() => {
+ this.colorUpdateInProgress = false;
+ });
+ },
+ isDropdownVariantSidebar,
+ isDropdownVariantEmbedded,
+ },
+};
+</script>
+
+<template>
+ <div
+ class="labels-select-wrapper gl-relative"
+ :class="{
+ 'is-embedded': isDropdownVariantEmbedded(variant),
+ }"
+ >
+ <template v-if="isDropdownVariantSidebar(variant)">
+ <sidebar-editable-item
+ ref="editable"
+ :title="$options.i18n.widgetTitle"
+ :loading="isLoading"
+ :can-edit="allowEdit"
+ @open="oldIid = null"
+ >
+ <template #collapsed>
+ <dropdown-value :selected-color="issuableColor">
+ <slot></slot>
+ </dropdown-value>
+ </template>
+ <template #default="{ edit }">
+ <dropdown-value :selected-color="issuableColor" class="gl-mb-2">
+ <slot></slot>
+ </dropdown-value>
+ <dropdown-contents
+ ref="dropdownContents"
+ :dropdown-button-text="dropdownButtonText"
+ :dropdown-title="dropdownTitle"
+ :selected-color="issuableColor"
+ :variant="variant"
+ :is-visible="edit"
+ @setColor="handleDropdownClose"
+ @closeDropdown="collapseEditableItem"
+ />
+ </template>
+ </sidebar-editable-item>
+ </template>
+ <dropdown-contents
+ v-else
+ ref="dropdownContents"
+ :dropdown-button-text="dropdownButtonText"
+ :dropdown-title="dropdownTitle"
+ :selected-color="issuableColor"
+ :variant="variant"
+ @setColor="handleDropdownClose"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/color_select_dropdown/constants.js b/app/assets/javascripts/vue_shared/components/color_select_dropdown/constants.js
new file mode 100644
index 00000000000..c70785abd1e
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/color_select_dropdown/constants.js
@@ -0,0 +1,30 @@
+import { __, s__ } from '~/locale';
+
+export const COLOR_WIDGET_COLOR = s__('ColorWidget|Color');
+
+export const DROPDOWN_VARIANT = {
+ Sidebar: 'sidebar',
+ Embedded: 'embedded',
+};
+
+export const DEFAULT_COLOR = { title: __('SuggestedColors|Blue'), color: '#1068bf' };
+
+export const ISSUABLE_COLORS = [
+ DEFAULT_COLOR,
+ {
+ title: s__('SuggestedColors|Green'),
+ color: '#217645',
+ },
+ {
+ title: s__('SuggestedColors|Red'),
+ color: '#c91c00',
+ },
+ {
+ title: s__('SuggestedColors|Orange'),
+ color: '#9e5400',
+ },
+ {
+ title: s__('SuggestedColors|Purple'),
+ color: '#694cc0',
+ },
+];
diff --git a/app/assets/javascripts/vue_shared/components/color_select_dropdown/dropdown_contents.vue b/app/assets/javascripts/vue_shared/components/color_select_dropdown/dropdown_contents.vue
new file mode 100644
index 00000000000..4eb1d3d08ca
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/color_select_dropdown/dropdown_contents.vue
@@ -0,0 +1,109 @@
+<script>
+import { GlDropdown } from '@gitlab/ui';
+import DropdownContentsColorView from './dropdown_contents_color_view.vue';
+import DropdownHeader from './dropdown_header.vue';
+import { isDropdownVariantSidebar } from './utils';
+
+export default {
+ components: {
+ DropdownContentsColorView,
+ DropdownHeader,
+ GlDropdown,
+ },
+ props: {
+ dropdownTitle: {
+ type: String,
+ required: true,
+ },
+ selectedColor: {
+ type: Object,
+ required: true,
+ },
+ dropdownButtonText: {
+ type: String,
+ required: true,
+ },
+ variant: {
+ type: String,
+ required: true,
+ },
+ isVisible: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ data() {
+ return {
+ showDropdownContentsCreateView: false,
+ localSelectedColor: this.selectedColor,
+ isDirty: false,
+ };
+ },
+ computed: {
+ buttonText() {
+ if (!this.localSelectedColor?.title) {
+ return this.dropdownButtonText;
+ }
+
+ return this.localSelectedColor.title;
+ },
+ },
+ watch: {
+ localSelectedColor: {
+ handler() {
+ this.isDirty = true;
+ },
+ deep: true,
+ },
+ isVisible(newVal) {
+ if (newVal) {
+ this.$refs.dropdown.show();
+ this.isDirty = false;
+ this.localSelectedColor = this.selectedColor;
+ } else {
+ this.$refs.dropdown.hide();
+ this.setColor();
+ }
+ },
+ selectedColor(newVal) {
+ if (!this.isDirty) {
+ this.localSelectedColor = newVal;
+ }
+ },
+ },
+ methods: {
+ setColor() {
+ if (!this.isDirty) {
+ return;
+ }
+ this.$emit('setColor', this.localSelectedColor);
+ },
+ handleDropdownHide() {
+ this.$emit('closeDropdown');
+ if (!isDropdownVariantSidebar(this.variant)) {
+ this.setColor();
+ }
+ this.$refs.dropdown.hide();
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-dropdown ref="dropdown" :text="buttonText" class="gl-w-full" @hide="handleDropdownHide">
+ <template #header>
+ <dropdown-header
+ ref="header"
+ :dropdown-title="dropdownTitle"
+ @closeDropdown="handleDropdownHide"
+ />
+ </template>
+ <template #default>
+ <dropdown-contents-color-view
+ v-model="localSelectedColor"
+ @closeDropdown="handleDropdownHide"
+ />
+ </template>
+ </gl-dropdown>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/color_select_dropdown/dropdown_contents_color_view.vue b/app/assets/javascripts/vue_shared/components/color_select_dropdown/dropdown_contents_color_view.vue
new file mode 100644
index 00000000000..62f4cf59c14
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/color_select_dropdown/dropdown_contents_color_view.vue
@@ -0,0 +1,53 @@
+<script>
+import { GlDropdownForm, GlDropdownItem } from '@gitlab/ui';
+import ColorItem from './color_item.vue';
+import { ISSUABLE_COLORS } from './constants';
+
+export default {
+ components: {
+ GlDropdownForm,
+ GlDropdownItem,
+ ColorItem,
+ },
+ model: {
+ prop: 'selectedColor',
+ },
+ props: {
+ selectedColor: {
+ type: Object,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ colors: ISSUABLE_COLORS,
+ };
+ },
+ methods: {
+ isColorSelected(color) {
+ return this.selectedColor.color === color.color;
+ },
+ handleColorClick(color) {
+ this.$emit('input', color);
+ this.$emit('closeDropdown', this.selectedColor);
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-dropdown-form>
+ <div>
+ <gl-dropdown-item
+ v-for="color in colors"
+ :key="color.color"
+ :is-checked="isColorSelected(color)"
+ :is-check-centered="true"
+ :is-check-item="true"
+ @click.native.capture.stop="handleColorClick(color)"
+ >
+ <color-item :color="color.color" :title="color.title" />
+ </gl-dropdown-item>
+ </div>
+ </gl-dropdown-form>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/color_select_dropdown/dropdown_header.vue b/app/assets/javascripts/vue_shared/components/color_select_dropdown/dropdown_header.vue
new file mode 100644
index 00000000000..a32b1570f5f
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/color_select_dropdown/dropdown_header.vue
@@ -0,0 +1,31 @@
+<script>
+import { GlButton } from '@gitlab/ui';
+
+export default {
+ components: {
+ GlButton,
+ },
+ props: {
+ dropdownTitle: {
+ type: String,
+ required: true,
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <div class="dropdown-title gl-display-flex gl-align-items-center gl-pt-0 gl-pb-3!">
+ <span class="gl-flex-grow-1">{{ dropdownTitle }}</span>
+ <gl-button
+ :aria-label="__('Close')"
+ variant="link"
+ size="small"
+ class="dropdown-header-button gl-p-0!"
+ icon="close"
+ @click="$emit('closeDropdown')"
+ />
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/color_select_dropdown/dropdown_value.vue b/app/assets/javascripts/vue_shared/components/color_select_dropdown/dropdown_value.vue
new file mode 100644
index 00000000000..4cba66eefd2
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/color_select_dropdown/dropdown_value.vue
@@ -0,0 +1,43 @@
+<script>
+import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
+import { COLOR_WIDGET_COLOR } from './constants';
+import ColorItem from './color_item.vue';
+
+export default {
+ i18n: {
+ dropdownTitle: COLOR_WIDGET_COLOR,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ components: {
+ GlIcon,
+ ColorItem,
+ },
+ props: {
+ selectedColor: {
+ type: Object,
+ required: true,
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="value js-value">
+ <div
+ v-gl-tooltip.left.viewport
+ :title="$options.i18n.dropdownTitle"
+ class="sidebar-collapsed-icon"
+ >
+ <gl-icon name="appearance" />
+ <color-item
+ :color="selectedColor.color"
+ :title="selectedColor.title"
+ class="gl-font-base gl-line-height-24"
+ />
+ </div>
+
+ <color-item class="hide-collapsed" :color="selectedColor.color" :title="selectedColor.title" />
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/color_select_dropdown/graphql/epic_color.query.graphql b/app/assets/javascripts/vue_shared/components/color_select_dropdown/graphql/epic_color.query.graphql
new file mode 100644
index 00000000000..959e0f8c1a5
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/color_select_dropdown/graphql/epic_color.query.graphql
@@ -0,0 +1,9 @@
+query epicColor($fullPath: ID!, $iid: ID) {
+ workspace: group(fullPath: $fullPath) {
+ id
+ issuable: epic(iid: $iid) {
+ id
+ color
+ }
+ }
+}
diff --git a/app/assets/javascripts/vue_shared/components/color_select_dropdown/graphql/epic_update_color.mutation.graphql b/app/assets/javascripts/vue_shared/components/color_select_dropdown/graphql/epic_update_color.mutation.graphql
new file mode 100644
index 00000000000..2975b42253f
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/color_select_dropdown/graphql/epic_update_color.mutation.graphql
@@ -0,0 +1,9 @@
+mutation updateEpicColor($input: UpdateEpicInput!) {
+ updateIssuableColor: updateEpic(input: $input) {
+ issuable: epic {
+ id
+ color
+ }
+ errors
+ }
+}
diff --git a/app/assets/javascripts/vue_shared/components/color_select_dropdown/utils.js b/app/assets/javascripts/vue_shared/components/color_select_dropdown/utils.js
new file mode 100644
index 00000000000..46196e793b3
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/color_select_dropdown/utils.js
@@ -0,0 +1,15 @@
+import { DROPDOWN_VARIANT } from './constants';
+
+/**
+ * Returns boolean representing whether dropdown variant
+ * is `sidebar`
+ * @param {string} variant
+ */
+export const isDropdownVariantSidebar = (variant) => variant === DROPDOWN_VARIANT.Sidebar;
+
+/**
+ * Returns boolean representing whether dropdown variant
+ * is `embedded`
+ * @param {string} variant
+ */
+export const isDropdownVariantEmbedded = (variant) => variant === DROPDOWN_VARIANT.Embedded;