diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-11-12 12:08:57 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-11-12 12:08:57 +0300 |
commit | 1fdf76252e8fdf1a30826fe3f32a6216e50c563c (patch) | |
tree | 949a5db75031f54dafa48b31a89546bbff8182f3 /app/assets/javascripts/boards | |
parent | 5f362c717e637ba18d04d2ed6722098455c8b571 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/boards')
9 files changed, 209 insertions, 43 deletions
diff --git a/app/assets/javascripts/boards/components/board_list_new.vue b/app/assets/javascripts/boards/components/board_list_new.vue index 0a495d05122..396aedcc557 100644 --- a/app/assets/javascripts/boards/components/board_list_new.vue +++ b/app/assets/javascripts/boards/components/board_list_new.vue @@ -1,7 +1,7 @@ <script> import { mapActions, mapState } from 'vuex'; import { GlLoadingIcon } from '@gitlab/ui'; -import BoardNewIssue from './board_new_issue.vue'; +import BoardNewIssue from './board_new_issue_new.vue'; import BoardCard from './board_card.vue'; import eventHub from '../eventhub'; import boardsStore from '../stores/boards_store'; diff --git a/app/assets/javascripts/boards/components/board_new_issue.vue b/app/assets/javascripts/boards/components/board_new_issue.vue index 0a665b82880..a9e6d768656 100644 --- a/app/assets/javascripts/boards/components/board_new_issue.vue +++ b/app/assets/javascripts/boards/components/board_new_issue.vue @@ -1,6 +1,4 @@ <script> -import $ from 'jquery'; -import { mapActions, mapGetters } from 'vuex'; import { GlButton } from '@gitlab/ui'; import { getMilestone } from 'ee_else_ce/boards/boards_util'; import ListIssue from 'ee_else_ce/boards/models/issue'; @@ -9,6 +7,8 @@ import ProjectSelect from './project_select.vue'; import boardsStore from '../stores/boards_store'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; +// This component is being replaced in favor of './board_new_issue_new.vue' for GraphQL boards + export default { name: 'BoardNewIssue', components: { @@ -31,23 +31,18 @@ export default { }; }, computed: { - ...mapGetters(['isSwimlanesOn']), disabled() { if (this.groupId) { return this.title === '' || !this.selectedProject.name; } return this.title === ''; }, - shouldDisplaySwimlanes() { - return this.glFeatures.boardsWithSwimlanes && this.isSwimlanesOn; - }, }, mounted() { this.$refs.input.focus(); eventHub.$on('setSelectedProject', this.setSelectedProject); }, methods: { - ...mapActions(['addListIssue', 'addListIssueFailure']), submit(e) { e.preventDefault(); if (this.title.trim() === '') return Promise.resolve(); @@ -74,31 +69,14 @@ export default { eventHub.$emit(`scroll-board-list-${this.list.id}`); this.cancel(); - if (this.shouldDisplaySwimlanes || this.glFeatures.graphqlBoardLists) { - this.addListIssue({ list: this.list, issue, position: 0 }); - } - return this.list .newIssue(issue) .then(() => { - // Need this because our jQuery very kindly disables buttons on ALL form submissions - $(this.$refs.submitButton).enable(); - - if (!this.shouldDisplaySwimlanes && !this.glFeatures.graphqlBoardLists) { - boardsStore.setIssueDetail(issue); - boardsStore.setListDetail(this.list); - } + boardsStore.setIssueDetail(issue); + boardsStore.setListDetail(this.list); }) .catch(() => { - // Need this because our jQuery very kindly disables buttons on ALL form submissions - $(this.$refs.submitButton).enable(); - - // Remove the issue - if (this.shouldDisplaySwimlanes || this.glFeatures.graphqlBoardLists) { - this.addListIssueFailure({ list: this.list, issue }); - } else { - this.list.removeIssue(issue); - } + this.list.removeIssue(issue); // Show error message this.error = true; @@ -137,7 +115,7 @@ export default { <gl-button ref="submitButton" :disabled="disabled" - class="float-left" + class="float-left js-no-auto-disable" variant="success" category="primary" type="submit" diff --git a/app/assets/javascripts/boards/components/board_new_issue_new.vue b/app/assets/javascripts/boards/components/board_new_issue_new.vue new file mode 100644 index 00000000000..969c84ddb59 --- /dev/null +++ b/app/assets/javascripts/boards/components/board_new_issue_new.vue @@ -0,0 +1,129 @@ +<script> +import { mapActions } from 'vuex'; +import { GlButton } from '@gitlab/ui'; +import { getMilestone } from 'ee_else_ce/boards/boards_util'; +import eventHub from '../eventhub'; +import ProjectSelect from './project_select.vue'; +import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; +import { __ } from '~/locale'; + +export default { + name: 'BoardNewIssue', + i18n: { + submit: __('Submit issue'), + cancel: __('Cancel'), + }, + components: { + ProjectSelect, + GlButton, + }, + mixins: [glFeatureFlagMixin()], + props: { + list: { + type: Object, + required: true, + }, + }, + inject: ['groupId', 'weightFeatureAvailable', 'boardWeight'], + data() { + return { + title: '', + selectedProject: {}, + }; + }, + computed: { + disabled() { + if (this.groupId) { + return this.title === '' || !this.selectedProject.name; + } + return this.title === ''; + }, + inputFieldId() { + // eslint-disable-next-line @gitlab/require-i18n-strings + return `${this.list.id}-title`; + }, + }, + mounted() { + this.$refs.input.focus(); + eventHub.$on('setSelectedProject', this.setSelectedProject); + }, + methods: { + ...mapActions(['addListNewIssue']), + submit(e) { + e.preventDefault(); + + const labels = this.list.label ? [this.list.label] : []; + const assignees = this.list.assignee ? [this.list.assignee] : []; + const milestone = getMilestone(this.list); + + const weight = this.weightFeatureAvailable ? this.boardWeight : undefined; + + const { title } = this; + + eventHub.$emit(`scroll-board-list-${this.list.id}`); + + return this.addListNewIssue({ + issueInput: { + title, + labelIds: labels?.map(l => l.id), + assigneeIds: assignees?.map(a => a?.id), + milestoneId: milestone?.id, + projectPath: this.selectedProject.path, + weight: weight >= 0 ? weight : null, + }, + list: this.list, + }).then(() => { + this.reset(); + }); + }, + reset() { + this.title = ''; + eventHub.$emit(`toggle-issue-form-${this.list.id}`); + }, + setSelectedProject(selectedProject) { + this.selectedProject = selectedProject; + }, + }, +}; +</script> + +<template> + <div class="board-new-issue-form"> + <div class="board-card position-relative p-3 rounded"> + <form ref="submitForm" @submit="submit"> + <label :for="inputFieldId" class="label-bold">{{ __('Title') }}</label> + <input + :id="inputFieldId" + ref="input" + v-model="title" + class="form-control" + type="text" + name="issue_title" + autocomplete="off" + /> + <project-select v-if="groupId" :group-id="groupId" :list="list" /> + <div class="clearfix gl-mt-3"> + <gl-button + ref="submitButton" + :disabled="disabled" + class="float-left js-no-auto-disable" + variant="success" + category="primary" + type="submit" + > + {{ $options.i18n.submit }} + </gl-button> + <gl-button + ref="cancelButton" + class="float-right" + type="button" + variant="default" + @click="reset" + > + {{ $options.i18n.cancel }} + </gl-button> + </div> + </form> + </div> + </div> +</template> diff --git a/app/assets/javascripts/boards/components/project_select.vue b/app/assets/javascripts/boards/components/project_select.vue index 566c0081b9d..f90fe582566 100644 --- a/app/assets/javascripts/boards/components/project_select.vue +++ b/app/assets/javascripts/boards/components/project_select.vue @@ -44,6 +44,7 @@ export default { this.selectedProject = { id: $el.data('project-id'), name: $el.data('project-name'), + path: $el.data('project-path'), }; eventHub.$emit('setSelectedProject', this.selectedProject); }, @@ -75,11 +76,12 @@ export default { renderRow(project) { return ` <li> - <a href='#' class='dropdown-menu-link' data-project-id="${ - project.id - }" data-project-name="${project.name}" data-project-name-with-namespace="${ - project.name_with_namespace - }"> + <a href='#' class='dropdown-menu-link' + data-project-id="${project.id}" + data-project-name="${project.name}" + data-project-name-with-namespace="${project.name_with_namespace}" + data-project-path="${project.path_with_namespace}" + > ${escape(project.name_with_namespace)} </a> </li> diff --git a/app/assets/javascripts/boards/index.js b/app/assets/javascripts/boards/index.js index e82730773fd..395a27b42d3 100644 --- a/app/assets/javascripts/boards/index.js +++ b/app/assets/javascripts/boards/index.js @@ -91,6 +91,10 @@ export default () => { labelsManagePath: $boardApp.dataset.labelsManagePath, labelsFilterBasePath: $boardApp.dataset.labelsFilterBasePath, timeTrackingLimitToHours: parseBoolean($boardApp.dataset.timeTrackingLimitToHours), + weightFeatureAvailable: parseBoolean($boardApp.dataset.weightFeatureAvailable), + boardWeight: $boardApp.dataset.boardWeight + ? parseInt($boardApp.dataset.boardWeight, 10) + : null, }, store, apolloProvider, diff --git a/app/assets/javascripts/boards/queries/issue_create.mutation.graphql b/app/assets/javascripts/boards/queries/issue_create.mutation.graphql new file mode 100644 index 00000000000..65be147be07 --- /dev/null +++ b/app/assets/javascripts/boards/queries/issue_create.mutation.graphql @@ -0,0 +1,10 @@ +#import "ee_else_ce/boards/queries/issue.fragment.graphql" + +mutation CreateIssue($input: CreateIssueInput!) { + createIssue(input: $input) { + issue { + ...IssueNode + } + errors + } +} diff --git a/app/assets/javascripts/boards/stores/actions.js b/app/assets/javascripts/boards/stores/actions.js index 54a03b82be0..92c93323a33 100644 --- a/app/assets/javascripts/boards/stores/actions.js +++ b/app/assets/javascripts/boards/stores/actions.js @@ -10,16 +10,18 @@ import { formatListIssues, fullBoardId, formatListsPageInfo, + formatIssue, } from '../boards_util'; import boardStore from '~/boards/stores/boards_store'; +import updateAssignees from '~/vue_shared/components/sidebar/queries/updateAssignees.mutation.graphql'; import listsIssuesQuery from '../queries/lists_issues.query.graphql'; import boardLabelsQuery from '../queries/board_labels.query.graphql'; import createBoardListMutation from '../queries/board_list_create.mutation.graphql'; import updateBoardListMutation from '../queries/board_list_update.mutation.graphql'; import issueMoveListMutation from '../queries/issue_move_list.mutation.graphql'; import destroyBoardListMutation from '../queries/board_list_destroy.mutation.graphql'; -import updateAssignees from '~/vue_shared/components/sidebar/queries/updateAssignees.mutation.graphql'; +import issueCreateMutation from '../queries/issue_create.mutation.graphql'; import issueSetLabels from '../queries/issue_set_labels.mutation.graphql'; import issueSetDueDate from '../queries/issue_set_due_date.mutation.graphql'; @@ -330,16 +332,43 @@ export default { }); }, - createNewIssue: () => { - notImplemented(); + createNewIssue: ({ commit, state }, issueInput) => { + const input = issueInput; + const { boardType, endpoints } = state; + if (boardType === BoardType.project) { + input.projectPath = endpoints.fullPath; + } + + return gqlClient + .mutate({ + mutation: issueCreateMutation, + variables: { input }, + }) + .then(({ data }) => { + if (data.createIssue.errors.length) { + commit(types.CREATE_ISSUE_FAILURE); + } else { + return data.createIssue?.issue; + } + return null; + }) + .catch(() => commit(types.CREATE_ISSUE_FAILURE)); }, addListIssue: ({ commit }, { list, issue, position }) => { commit(types.ADD_ISSUE_TO_LIST, { list, issue, position }); }, - addListIssueFailure: ({ commit }, { list, issue }) => { - commit(types.ADD_ISSUE_TO_LIST_FAILURE, { list, issue }); + addListNewIssue: ({ commit, dispatch }, { issueInput, list }) => { + const issue = formatIssue({ ...issueInput, id: 'tmp' }); + commit(types.ADD_ISSUE_TO_LIST, { list, issue, position: 0 }); + + dispatch('createNewIssue', issueInput) + .then(res => { + commit(types.ADD_ISSUE_TO_LIST, { list, issue: formatIssue(res) }); + commit(types.REMOVE_ISSUE_FROM_LIST, { list, issue }); + }) + .catch(() => commit(types.ADD_ISSUE_TO_LIST_FAILURE, { list, issueId: issueInput.id })); }, setActiveIssueLabels: async ({ commit, getters }, input) => { diff --git a/app/assets/javascripts/boards/stores/mutation_types.js b/app/assets/javascripts/boards/stores/mutation_types.js index 29468105b5c..3a57cb9b5e1 100644 --- a/app/assets/javascripts/boards/stores/mutation_types.js +++ b/app/assets/javascripts/boards/stores/mutation_types.js @@ -17,6 +17,7 @@ export const REMOVE_LIST_FAILURE = 'REMOVE_LIST_FAILURE'; export const REQUEST_ISSUES_FOR_LIST = 'REQUEST_ISSUES_FOR_LIST'; export const RECEIVE_ISSUES_FOR_LIST_FAILURE = 'RECEIVE_ISSUES_FOR_LIST_FAILURE'; export const RECEIVE_ISSUES_FOR_LIST_SUCCESS = 'RECEIVE_ISSUES_FOR_LIST_SUCCESS'; +export const CREATE_ISSUE_FAILURE = 'CREATE_ISSUE_FAILURE'; export const REQUEST_ADD_ISSUE = 'REQUEST_ADD_ISSUE'; export const RECEIVE_ADD_ISSUE_SUCCESS = 'RECEIVE_ADD_ISSUE_SUCCESS'; export const RECEIVE_ADD_ISSUE_ERROR = 'RECEIVE_ADD_ISSUE_ERROR'; @@ -28,6 +29,7 @@ export const RECEIVE_UPDATE_ISSUE_SUCCESS = 'RECEIVE_UPDATE_ISSUE_SUCCESS'; export const RECEIVE_UPDATE_ISSUE_ERROR = 'RECEIVE_UPDATE_ISSUE_ERROR'; export const ADD_ISSUE_TO_LIST = 'ADD_ISSUE_TO_LIST'; export const ADD_ISSUE_TO_LIST_FAILURE = 'ADD_ISSUE_TO_LIST_FAILURE'; +export const REMOVE_ISSUE_FROM_LIST = 'REMOVE_ISSUE_FROM_LIST'; export const SET_CURRENT_PAGE = 'SET_CURRENT_PAGE'; export const TOGGLE_EMPTY_STATE = 'TOGGLE_EMPTY_STATE'; export const SET_ACTIVE_ID = 'SET_ACTIVE_ID'; diff --git a/app/assets/javascripts/boards/stores/mutations.js b/app/assets/javascripts/boards/stores/mutations.js index eb2003a6ed3..bb083158c8f 100644 --- a/app/assets/javascripts/boards/stores/mutations.js +++ b/app/assets/javascripts/boards/stores/mutations.js @@ -201,16 +201,28 @@ export default { notImplemented(); }, + [mutationTypes.CREATE_ISSUE_FAILURE]: state => { + state.error = s__('Boards|An error occurred while creating the issue. Please try again.'); + }, + [mutationTypes.ADD_ISSUE_TO_LIST]: (state, { list, issue, position }) => { - const listIssues = state.issuesByListId[list.id]; - listIssues.splice(position, 0, issue.id); - Vue.set(state.issuesByListId, list.id, listIssues); + addIssueToList({ + state, + listId: list.id, + issueId: issue.id, + atIndex: position, + }); Vue.set(state.issues, issue.id, issue); }, - [mutationTypes.ADD_ISSUE_TO_LIST_FAILURE]: (state, { list, issue }) => { + [mutationTypes.ADD_ISSUE_TO_LIST_FAILURE]: (state, { list, issueId }) => { state.error = s__('Boards|An error occurred while creating the issue. Please try again.'); + removeIssueFromList({ state, listId: list.id, issueId }); + }, + + [mutationTypes.REMOVE_ISSUE_FROM_LIST]: (state, { list, issue }) => { removeIssueFromList({ state, listId: list.id, issueId: issue.id }); + Vue.delete(state.issues, issue.id); }, [mutationTypes.SET_CURRENT_PAGE]: () => { |