diff options
Diffstat (limited to 'app/assets/javascripts/integrations/edit')
7 files changed, 108 insertions, 83 deletions
diff --git a/app/assets/javascripts/integrations/edit/components/dynamic_field.vue b/app/assets/javascripts/integrations/edit/components/dynamic_field.vue index 258cd1bf365..4b0579a5beb 100644 --- a/app/assets/javascripts/integrations/edit/components/dynamic_field.vue +++ b/app/assets/javascripts/integrations/edit/components/dynamic_field.vue @@ -153,7 +153,7 @@ export default { :invalid-feedback="__('This field is required.')" :state="valid" > - <template #description> + <template v-if="!isCheckbox" #description> <span v-safe-html:[$options.helpHtmlConfig]="help"></span> </template> @@ -161,6 +161,9 @@ export default { <input :name="fieldName" type="hidden" :value="model || false" /> <gl-form-checkbox :id="fieldId" v-model="model" :disabled="isInheriting"> {{ checkboxLabel || humanizedTitle }} + <template #help> + <span v-safe-html:[$options.helpHtmlConfig]="help"></span> + </template> </gl-form-checkbox> </template> <template v-else-if="isSelect"> diff --git a/app/assets/javascripts/integrations/edit/components/integration_form.vue b/app/assets/javascripts/integrations/edit/components/integration_form.vue index e570a468944..c3cc35adfa5 100644 --- a/app/assets/javascripts/integrations/edit/components/integration_form.vue +++ b/app/assets/javascripts/integrations/edit/components/integration_form.vue @@ -1,5 +1,6 @@ <script> -import { GlButton, GlModalDirective, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui'; +import { GlButton, GlModalDirective, GlSafeHtmlDirective as SafeHtml, GlForm } from '@gitlab/ui'; +import axios from 'axios'; import * as Sentry from '@sentry/browser'; import { mapState, mapActions, mapGetters } from 'vuex'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; @@ -8,8 +9,11 @@ import { I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE, I18N_DEFAULT_ERROR_MESSAGE, I18N_SUCCESSFUL_CONNECTION_MESSAGE, + INTEGRATION_FORM_SELECTOR, integrationLevels, } from '~/integrations/constants'; +import { refreshCurrentPage } from '~/lib/utils/url_utility'; +import csrf from '~/lib/utils/csrf'; import eventHub from '../event_hub'; import { testIntegrationSettings } from '../api'; import ActiveCheckbox from './active_checkbox.vue'; @@ -33,6 +37,7 @@ export default { ConfirmationModal, ResetConfirmationModal, GlButton, + GlForm, }, directives: { GlModal: GlModalDirective, @@ -40,10 +45,6 @@ export default { }, mixins: [glFeatureFlagsMixin()], props: { - formSelector: { - type: String, - required: true, - }, helpHtml: { type: String, required: false, @@ -55,11 +56,12 @@ export default { integrationActive: false, isTesting: false, isSaving: false, + isResetting: false, }; }, computed: { ...mapGetters(['currentKey', 'propsSource']), - ...mapState(['defaultState', 'customState', 'override', 'isResetting']), + ...mapState(['defaultState', 'customState', 'override']), isEditable() { return this.propsSource.editable; }, @@ -81,10 +83,28 @@ export default { disableButtons() { return Boolean(this.isSaving || this.isResetting || this.isTesting); }, + useVueForm() { + return this.glFeatures?.vueIntegrationForm; + }, + formContainerProps() { + return this.useVueForm + ? { + ref: 'integrationForm', + method: 'post', + class: 'gl-mb-3 gl-show-field-errors integration-settings-form', + action: this.propsSource.formPath, + novalidate: !this.integrationActive, + } + : {}; + }, + formContainer() { + return this.useVueForm ? GlForm : 'div'; + }, }, mounted() { - // this form element is defined in Haml - this.form = document.querySelector(this.formSelector); + this.form = this.useVueForm + ? this.$refs.integrationForm.$el + : document.querySelector(INTEGRATION_FORM_SELECTOR); }, methods: { ...mapActions(['setOverride', 'fetchResetIntegration', 'requestJiraIssueTypes']), @@ -126,7 +146,20 @@ export default { }); }, onResetClick() { - this.fetchResetIntegration(); + this.isResetting = true; + + return axios + .post(this.propsSource.resetPath) + .then(() => { + refreshCurrentPage(); + }) + .catch((error) => { + this.$toast.show(I18N_DEFAULT_ERROR_MESSAGE); + Sentry.captureException(error); + }) + .finally(() => { + this.isResetting = false; + }); }, onRequestJiraIssueTypes() { this.requestJiraIssueTypes(this.getFormData()); @@ -136,7 +169,7 @@ export default { }, onToggleIntegrationState(integrationActive) { this.integrationActive = integrationActive; - if (!this.form) { + if (!this.form || this.useVueForm) { return; } @@ -153,11 +186,23 @@ export default { ADD_TAGS: ['use'], // to support icon SVGs FORBID_ATTR: [], // This is trusted input so we can override the default config to allow data-* attributes }, + csrf, }; </script> <template> - <div class="gl-mb-3"> + <component :is="formContainer" v-bind="formContainerProps"> + <template v-if="useVueForm"> + <input type="hidden" name="_method" value="put" /> + <input type="hidden" name="authenticity_token" :value="$options.csrf.token" /> + <input + type="hidden" + name="redirect_to" + :value="propsSource.redirectTo" + data-testid="redirect-to-field" + /> + </template> + <override-dropdown v-if="defaultState !== null" :inherit-from-id="defaultState.id" @@ -200,63 +245,71 @@ export default { v-bind="propsSource.jiraIssuesProps" @request-jira-issue-types="onRequestJiraIssueTypes" /> - <div v-if="isEditable" class="footer-block row-content-block"> - <template v-if="isInstanceOrGroupLevel"> + + <div + v-if="isEditable" + class="footer-block row-content-block gl-display-flex gl-justify-content-space-between" + > + <div> + <template v-if="isInstanceOrGroupLevel"> + <gl-button + v-gl-modal.confirmSaveIntegration + category="primary" + variant="confirm" + :loading="isSaving" + :disabled="disableButtons" + data-testid="save-button-instance-group" + data-qa-selector="save_changes_button" + > + {{ __('Save changes') }} + </gl-button> + <confirmation-modal @submit="onSaveClick" /> + </template> <gl-button - v-gl-modal.confirmSaveIntegration + v-else category="primary" variant="confirm" + type="submit" :loading="isSaving" :disabled="disableButtons" + data-testid="save-button" data-qa-selector="save_changes_button" + @click.prevent="onSaveClick" > {{ __('Save changes') }} </gl-button> - <confirmation-modal @submit="onSaveClick" /> - </template> - <gl-button - v-else - category="primary" - variant="confirm" - type="submit" - :loading="isSaving" - :disabled="disableButtons" - data-testid="save-button" - data-qa-selector="save_changes_button" - @click.prevent="onSaveClick" - > - {{ __('Save changes') }} - </gl-button> - <gl-button - v-if="showTestButton" - category="secondary" - variant="confirm" - :loading="isTesting" - :disabled="disableButtons" - data-testid="test-button" - @click.prevent="onTestClick" - > - {{ __('Test settings') }} - </gl-button> + <gl-button + v-if="showTestButton" + category="secondary" + variant="confirm" + :loading="isTesting" + :disabled="disableButtons" + data-testid="test-button" + @click.prevent="onTestClick" + > + {{ __('Test settings') }} + </gl-button> + + <gl-button :href="propsSource.cancelPath">{{ __('Cancel') }}</gl-button> + </div> <template v-if="showResetButton"> <gl-button v-gl-modal.confirmResetIntegration - category="secondary" - variant="confirm" + category="tertiary" + variant="danger" :loading="isResetting" :disabled="disableButtons" data-testid="reset-button" > {{ __('Reset') }} </gl-button> + <reset-confirmation-modal @reset="onResetClick" /> </template> - - <gl-button :href="propsSource.cancelPath">{{ __('Cancel') }}</gl-button> </div> </div> </div> - </div> + </component> </template> diff --git a/app/assets/javascripts/integrations/edit/components/reset_confirmation_modal.vue b/app/assets/javascripts/integrations/edit/components/reset_confirmation_modal.vue index 5a445235219..403bad3db11 100644 --- a/app/assets/javascripts/integrations/edit/components/reset_confirmation_modal.vue +++ b/app/assets/javascripts/integrations/edit/components/reset_confirmation_modal.vue @@ -11,7 +11,7 @@ export default { primaryProps() { return { text: __('Reset'), - attributes: [{ variant: 'warning' }, { category: 'primary' }], + attributes: [{ variant: 'danger' }, { category: 'primary' }], }; }, cancelProps() { diff --git a/app/assets/javascripts/integrations/edit/index.js b/app/assets/javascripts/integrations/edit/index.js index 9c9e3edbeb8..fbda8c1e3d0 100644 --- a/app/assets/javascripts/integrations/edit/index.js +++ b/app/assets/javascripts/integrations/edit/index.js @@ -28,9 +28,11 @@ function parseDatasetToProps(data) { cancelPath, testPath, resetPath, + formPath, vulnerabilitiesIssuetype, jiraIssueTransitionAutomatic, jiraIssueTransitionId, + redirectTo, ...booleanAttributes } = data; const { @@ -57,6 +59,7 @@ function parseDatasetToProps(data) { canTest, testPath, resetPath, + formPath, triggerFieldsProps: { initialTriggerCommit: commitEvents, initialTriggerMergeRequest: mergeRequestEvents, @@ -82,10 +85,11 @@ function parseDatasetToProps(data) { inheritFromId: parseInt(inheritFromId, 10), integrationLevel, id: parseInt(id, 10), + redirectTo, }; } -export default function initIntegrationSettingsForm(formSelector) { +export default function initIntegrationSettingsForm() { const customSettingsEl = document.querySelector('.js-vue-integration-settings'); const defaultSettingsEl = document.querySelector('.js-vue-default-integration-settings'); @@ -115,7 +119,6 @@ export default function initIntegrationSettingsForm(formSelector) { return createElement(IntegrationForm, { props: { helpHtml, - formSelector, }, }); }, diff --git a/app/assets/javascripts/integrations/edit/store/actions.js b/app/assets/javascripts/integrations/edit/store/actions.js index 97565a3a69c..1398b710d1d 100644 --- a/app/assets/javascripts/integrations/edit/store/actions.js +++ b/app/assets/javascripts/integrations/edit/store/actions.js @@ -1,5 +1,3 @@ -import axios from 'axios'; -import { refreshCurrentPage } from '~/lib/utils/url_utility'; import { VALIDATE_INTEGRATION_FORM_EVENT, I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE, @@ -10,27 +8,6 @@ import eventHub from '../event_hub'; import * as types from './mutation_types'; export const setOverride = ({ commit }, override) => commit(types.SET_OVERRIDE, override); -export const setIsResetting = ({ commit }, isResetting) => - commit(types.SET_IS_RESETTING, isResetting); - -export const requestResetIntegration = ({ commit }) => { - commit(types.REQUEST_RESET_INTEGRATION); -}; -export const receiveResetIntegrationSuccess = () => { - refreshCurrentPage(); -}; -export const receiveResetIntegrationError = ({ commit }) => { - commit(types.RECEIVE_RESET_INTEGRATION_ERROR); -}; - -export const fetchResetIntegration = ({ dispatch, getters }) => { - dispatch('requestResetIntegration'); - - return axios - .post(getters.propsSource.resetPath, { params: { format: 'json' } }) - .then(() => dispatch('receiveResetIntegrationSuccess')) - .catch(() => dispatch('receiveResetIntegrationError')); -}; export const requestJiraIssueTypes = ({ commit, dispatch, getters }, formData) => { commit(types.SET_JIRA_ISSUE_TYPES_ERROR_MESSAGE, ''); diff --git a/app/assets/javascripts/integrations/edit/store/mutations.js b/app/assets/javascripts/integrations/edit/store/mutations.js index e7e312ce650..6ca644f8821 100644 --- a/app/assets/javascripts/integrations/edit/store/mutations.js +++ b/app/assets/javascripts/integrations/edit/store/mutations.js @@ -4,15 +4,6 @@ export default { [types.SET_OVERRIDE](state, override) { state.override = override; }, - [types.SET_IS_RESETTING](state, isResetting) { - state.isResetting = isResetting; - }, - [types.REQUEST_RESET_INTEGRATION](state) { - state.isResetting = true; - }, - [types.RECEIVE_RESET_INTEGRATION_ERROR](state) { - state.isResetting = false; - }, [types.SET_JIRA_ISSUE_TYPES](state, jiraIssueTypes) { state.jiraIssueTypes = jiraIssueTypes; }, diff --git a/app/assets/javascripts/integrations/edit/store/state.js b/app/assets/javascripts/integrations/edit/store/state.js index 3d40d1b90d5..088476b2b37 100644 --- a/app/assets/javascripts/integrations/edit/store/state.js +++ b/app/assets/javascripts/integrations/edit/store/state.js @@ -5,8 +5,6 @@ export default ({ defaultState = null, customState = {} } = {}) => { override, defaultState, customState, - isSaving: false, - isResetting: false, isLoadingJiraIssueTypes: false, loadingJiraIssueTypesErrorMessage: '', jiraIssueTypes: [], |