diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-12-20 16:37:47 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-12-20 16:37:47 +0300 |
commit | aee0a117a889461ce8ced6fcf73207fe017f1d99 (patch) | |
tree | 891d9ef189227a8445d83f35c1b0fc99573f4380 /app/assets/javascripts/integrations | |
parent | 8d46af3258650d305f53b819eabf7ab18d22f59e (diff) |
Add latest changes from gitlab-org/gitlab@14-6-stable-eev14.6.0-rc42
Diffstat (limited to 'app/assets/javascripts/integrations')
15 files changed, 187 insertions, 253 deletions
diff --git a/app/assets/javascripts/integrations/constants.js b/app/assets/javascripts/integrations/constants.js index d214ee4ded6..84656bd41bb 100644 --- a/app/assets/javascripts/integrations/constants.js +++ b/app/assets/javascripts/integrations/constants.js @@ -1,9 +1,5 @@ import { s__, __ } from '~/locale'; -export const TEST_INTEGRATION_EVENT = 'testIntegration'; -export const SAVE_INTEGRATION_EVENT = 'saveIntegration'; -export const GET_JIRA_ISSUE_TYPES_EVENT = 'getJiraIssueTypes'; -export const TOGGLE_INTEGRATION_EVENT = 'toggleIntegration'; export const VALIDATE_INTEGRATION_FORM_EVENT = 'validateIntegrationForm'; export const integrationLevels = { diff --git a/app/assets/javascripts/integrations/edit/api.js b/app/assets/javascripts/integrations/edit/api.js new file mode 100644 index 00000000000..7bce5604f9d --- /dev/null +++ b/app/assets/javascripts/integrations/edit/api.js @@ -0,0 +1,9 @@ +import axios from '~/lib/utils/axios_utils'; + +/** + * Test the validity of [integrationFormData]. + * @return Promise<{ issuetypes: []String }> - issuetypes contains valid Jira issue types. + */ +export const testIntegrationSettings = (testPath, integrationFormData) => { + return axios.put(testPath, integrationFormData); +}; diff --git a/app/assets/javascripts/integrations/edit/components/active_checkbox.vue b/app/assets/javascripts/integrations/edit/components/active_checkbox.vue index 9804a9e15f6..5ddf3aeb639 100644 --- a/app/assets/javascripts/integrations/edit/components/active_checkbox.vue +++ b/app/assets/javascripts/integrations/edit/components/active_checkbox.vue @@ -1,8 +1,6 @@ <script> import { GlFormGroup, GlFormCheckbox } from '@gitlab/ui'; import { mapGetters } from 'vuex'; -import { TOGGLE_INTEGRATION_EVENT } from '~/integrations/constants'; -import eventHub from '../event_hub'; export default { name: 'ActiveCheckbox', @@ -20,14 +18,11 @@ export default { }, mounted() { this.activated = this.propsSource.initialActivated; - // Initialize view - this.$nextTick(() => { - this.onChange(this.activated); - }); + this.onChange(this.activated); }, methods: { - onChange(e) { - eventHub.$emit(TOGGLE_INTEGRATION_EVENT, e); + onChange(isChecked) { + this.$emit('toggle-integration-active', isChecked); }, }, }; diff --git a/app/assets/javascripts/integrations/edit/components/confirmation_modal.vue b/app/assets/javascripts/integrations/edit/components/confirmation_modal.vue index 89f7e3b7a89..bc6aa231a93 100644 --- a/app/assets/javascripts/integrations/edit/components/confirmation_modal.vue +++ b/app/assets/javascripts/integrations/edit/components/confirmation_modal.vue @@ -1,22 +1,17 @@ <script> import { GlModal } from '@gitlab/ui'; -import { mapGetters } from 'vuex'; import { __ } from '~/locale'; export default { components: { GlModal, }, + computed: { - ...mapGetters(['isDisabled']), primaryProps() { return { text: __('Save'), - attributes: [ - { variant: 'confirm' }, - { category: 'primary' }, - { disabled: this.isDisabled }, - ], + attributes: [{ variant: 'confirm' }, { category: 'primary' }], }; }, cancelProps() { diff --git a/app/assets/javascripts/integrations/edit/components/integration_form.vue b/app/assets/javascripts/integrations/edit/components/integration_form.vue index ba1aeb28616..e570a468944 100644 --- a/app/assets/javascripts/integrations/edit/components/integration_form.vue +++ b/app/assets/javascripts/integrations/edit/components/integration_form.vue @@ -1,14 +1,17 @@ <script> import { GlButton, GlModalDirective, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui'; +import * as Sentry from '@sentry/browser'; import { mapState, mapActions, mapGetters } from 'vuex'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import { - TEST_INTEGRATION_EVENT, - SAVE_INTEGRATION_EVENT, + VALIDATE_INTEGRATION_FORM_EVENT, + I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE, + I18N_DEFAULT_ERROR_MESSAGE, + I18N_SUCCESSFUL_CONNECTION_MESSAGE, integrationLevels, } from '~/integrations/constants'; import eventHub from '../event_hub'; - +import { testIntegrationSettings } from '../api'; import ActiveCheckbox from './active_checkbox.vue'; import ConfirmationModal from './confirmation_modal.vue'; import DynamicField from './dynamic_field.vue'; @@ -37,22 +40,26 @@ export default { }, mixins: [glFeatureFlagsMixin()], props: { + formSelector: { + type: String, + required: true, + }, helpHtml: { type: String, required: false, default: '', }, }, + data() { + return { + integrationActive: false, + isTesting: false, + isSaving: false, + }; + }, computed: { - ...mapGetters(['currentKey', 'propsSource', 'isDisabled']), - ...mapState([ - 'defaultState', - 'customState', - 'override', - 'isSaving', - 'isTesting', - 'isResetting', - ]), + ...mapGetters(['currentKey', 'propsSource']), + ...mapState(['defaultState', 'customState', 'override', 'isResetting']), isEditable() { return this.propsSource.editable; }, @@ -65,29 +72,81 @@ export default { this.customState.integrationLevel === integrationLevels.GROUP ); }, - showReset() { + showResetButton() { return this.isInstanceOrGroupLevel && this.propsSource.resetPath; }, + showTestButton() { + return this.propsSource.canTest; + }, + disableButtons() { + return Boolean(this.isSaving || this.isResetting || this.isTesting); + }, + }, + mounted() { + // this form element is defined in Haml + this.form = document.querySelector(this.formSelector); }, methods: { - ...mapActions([ - 'setOverride', - 'setIsSaving', - 'setIsTesting', - 'setIsResetting', - 'fetchResetIntegration', - ]), + ...mapActions(['setOverride', 'fetchResetIntegration', 'requestJiraIssueTypes']), onSaveClick() { - this.setIsSaving(true); - eventHub.$emit(SAVE_INTEGRATION_EVENT); + this.isSaving = true; + + if (this.integrationActive && !this.form.checkValidity()) { + this.isSaving = false; + eventHub.$emit(VALIDATE_INTEGRATION_FORM_EVENT); + return; + } + + this.form.submit(); }, onTestClick() { - this.setIsTesting(true); - eventHub.$emit(TEST_INTEGRATION_EVENT); + this.isTesting = true; + + if (!this.form.checkValidity()) { + eventHub.$emit(VALIDATE_INTEGRATION_FORM_EVENT); + return; + } + + testIntegrationSettings(this.propsSource.testPath, this.getFormData()) + .then(({ data: { error, message = I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE } }) => { + if (error) { + eventHub.$emit(VALIDATE_INTEGRATION_FORM_EVENT); + this.$toast.show(message); + return; + } + + this.$toast.show(I18N_SUCCESSFUL_CONNECTION_MESSAGE); + }) + .catch((error) => { + this.$toast.show(I18N_DEFAULT_ERROR_MESSAGE); + Sentry.captureException(error); + }) + .finally(() => { + this.isTesting = false; + }); }, onResetClick() { this.fetchResetIntegration(); }, + onRequestJiraIssueTypes() { + this.requestJiraIssueTypes(this.getFormData()); + }, + getFormData() { + return new FormData(this.form); + }, + onToggleIntegrationState(integrationActive) { + this.integrationActive = integrationActive; + if (!this.form) { + return; + } + + // If integration will be active, enable form validation. + if (integrationActive) { + this.form.removeAttribute('novalidate'); + } else { + this.form.setAttribute('novalidate', true); + } + }, }, helpHtmlConfig: { ADD_ATTR: ['target'], // allow external links, can be removed after https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1427 is implemented @@ -114,7 +173,11 @@ export default { <!-- helpHtml is trusted input --> <div v-if="helpHtml" v-safe-html:[$options.helpHtmlConfig]="helpHtml"></div> - <active-checkbox v-if="propsSource.showActive" :key="`${currentKey}-active-checkbox`" /> + <active-checkbox + v-if="propsSource.showActive" + :key="`${currentKey}-active-checkbox`" + @toggle-integration-active="onToggleIntegrationState" + /> <jira-trigger-fields v-if="isJira" :key="`${currentKey}-jira-trigger-fields`" @@ -135,6 +198,7 @@ export default { v-if="isJira && !isInstanceOrGroupLevel" :key="`${currentKey}-jira-issues-fields`" v-bind="propsSource.jiraIssuesProps" + @request-jira-issue-types="onRequestJiraIssueTypes" /> <div v-if="isEditable" class="footer-block row-content-block"> <template v-if="isInstanceOrGroupLevel"> @@ -143,7 +207,7 @@ export default { category="primary" variant="confirm" :loading="isSaving" - :disabled="isDisabled" + :disabled="disableButtons" data-qa-selector="save_changes_button" > {{ __('Save changes') }} @@ -156,7 +220,8 @@ export default { variant="confirm" type="submit" :loading="isSaving" - :disabled="isDisabled" + :disabled="disableButtons" + data-testid="save-button" data-qa-selector="save_changes_button" @click.prevent="onSaveClick" > @@ -164,24 +229,24 @@ export default { </gl-button> <gl-button - v-if="propsSource.canTest" + v-if="showTestButton" category="secondary" variant="confirm" :loading="isTesting" - :disabled="isDisabled" - :href="propsSource.testPath" + :disabled="disableButtons" + data-testid="test-button" @click.prevent="onTestClick" > {{ __('Test settings') }} </gl-button> - <template v-if="showReset"> + <template v-if="showResetButton"> <gl-button v-gl-modal.confirmResetIntegration category="secondary" variant="confirm" :loading="isResetting" - :disabled="isDisabled" + :disabled="disableButtons" data-testid="reset-button" > {{ __('Reset') }} diff --git a/app/assets/javascripts/integrations/edit/components/jira_issues_fields.vue b/app/assets/javascripts/integrations/edit/components/jira_issues_fields.vue index 7cbfb35aeaa..99498501f6c 100644 --- a/app/assets/javascripts/integrations/edit/components/jira_issues_fields.vue +++ b/app/assets/javascripts/integrations/edit/components/jira_issues_fields.vue @@ -1,10 +1,7 @@ <script> import { GlFormGroup, GlFormCheckbox, GlFormInput, GlSprintf, GlLink } from '@gitlab/ui'; import { mapGetters } from 'vuex'; -import { - VALIDATE_INTEGRATION_FORM_EVENT, - GET_JIRA_ISSUE_TYPES_EVENT, -} from '~/integrations/constants'; +import { VALIDATE_INTEGRATION_FORM_EVENT } from '~/integrations/constants'; import { s__, __ } from '~/locale'; import eventHub from '../event_hub'; import JiraUpgradeCta from './jira_upgrade_cta.vue'; @@ -91,9 +88,6 @@ export default { validateForm() { this.validated = true; }, - getJiraIssueTypes() { - eventHub.$emit(GET_JIRA_ISSUE_TYPES_EVENT); - }, }, i18n: { sectionTitle: s__('JiraService|View Jira issues in GitLab'), @@ -123,7 +117,11 @@ export default { </p> <template v-if="showJiraIssuesIntegration"> <input name="service[issues_enabled]" type="hidden" :value="enableJiraIssues || false" /> - <gl-form-checkbox v-model="enableJiraIssues" :disabled="isInheriting"> + <gl-form-checkbox + v-model="enableJiraIssues" + :disabled="isInheriting" + data-qa-selector="service_jira_issues_enabled_checkbox" + > {{ $options.i18n.enableCheckboxLabel }} <template #help> {{ $options.i18n.enableCheckboxHelp }} @@ -136,7 +134,7 @@ export default { :initial-issue-type-id="initialVulnerabilitiesIssuetype" :show-full-feature="showJiraVulnerabilitiesIntegration" data-testid="jira-for-vulnerabilities" - @request-get-issue-types="getJiraIssueTypes" + @request-jira-issue-types="$emit('request-jira-issue-types')" /> <jira-upgrade-cta v-if="!showJiraVulnerabilitiesIntegration" @@ -168,6 +166,7 @@ export default { id="service_project_key" v-model="projectKey" name="service[project_key]" + data-qa-selector="service_jira_project_key_field" :placeholder="$options.i18n.projectKeyPlaceholder" :required="enableJiraIssues" :state="validProjectKey" 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 9472a3eeafe..5a445235219 100644 --- a/app/assets/javascripts/integrations/edit/components/reset_confirmation_modal.vue +++ b/app/assets/javascripts/integrations/edit/components/reset_confirmation_modal.vue @@ -1,6 +1,5 @@ <script> import { GlModal } from '@gitlab/ui'; -import { mapGetters } from 'vuex'; import { __ } from '~/locale'; @@ -9,15 +8,10 @@ export default { GlModal, }, computed: { - ...mapGetters(['isDisabled']), primaryProps() { return { text: __('Reset'), - attributes: [ - { variant: 'warning' }, - { category: 'primary' }, - { disabled: this.isDisabled }, - ], + attributes: [{ variant: 'warning' }, { category: 'primary' }], }; }, cancelProps() { diff --git a/app/assets/javascripts/integrations/edit/index.js b/app/assets/javascripts/integrations/edit/index.js index 792e7d8e85e..9c9e3edbeb8 100644 --- a/app/assets/javascripts/integrations/edit/index.js +++ b/app/assets/javascripts/integrations/edit/index.js @@ -85,35 +85,39 @@ function parseDatasetToProps(data) { }; } -export default (el, defaultEl) => { - if (!el) { +export default function initIntegrationSettingsForm(formSelector) { + const customSettingsEl = document.querySelector('.js-vue-integration-settings'); + const defaultSettingsEl = document.querySelector('.js-vue-default-integration-settings'); + + if (!customSettingsEl) { return null; } - const props = parseDatasetToProps(el.dataset); + const customSettingsProps = parseDatasetToProps(customSettingsEl.dataset); const initialState = { defaultState: null, - customState: props, + customState: customSettingsProps, }; - if (defaultEl) { - initialState.defaultState = Object.freeze(parseDatasetToProps(defaultEl.dataset)); + if (defaultSettingsEl) { + initialState.defaultState = Object.freeze(parseDatasetToProps(defaultSettingsEl.dataset)); } // Here, we capture the "helpHtml", so we can pass it to the Vue component // to position it where ever it wants. // Because this node is a _child_ of `el`, it will be removed when the Vue component is mounted, // so we don't need to manually remove it. - const helpHtml = el.querySelector('.js-integration-help-html')?.innerHTML; + const helpHtml = customSettingsEl.querySelector('.js-integration-help-html')?.innerHTML; return new Vue({ - el, + el: customSettingsEl, store: createStore(initialState), render(createElement) { 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 400397c050c..97565a3a69c 100644 --- a/app/assets/javascripts/integrations/edit/store/actions.js +++ b/app/assets/javascripts/integrations/edit/store/actions.js @@ -1,10 +1,15 @@ import axios from 'axios'; import { refreshCurrentPage } from '~/lib/utils/url_utility'; +import { + VALIDATE_INTEGRATION_FORM_EVENT, + I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE, + I18N_DEFAULT_ERROR_MESSAGE, +} from '~/integrations/constants'; +import { testIntegrationSettings } from '../api'; +import eventHub from '../event_hub'; import * as types from './mutation_types'; export const setOverride = ({ commit }, override) => commit(types.SET_OVERRIDE, override); -export const setIsSaving = ({ commit }, isSaving) => commit(types.SET_IS_SAVING, isSaving); -export const setIsTesting = ({ commit }, isTesting) => commit(types.SET_IS_TESTING, isTesting); export const setIsResetting = ({ commit }, isResetting) => commit(types.SET_IS_RESETTING, isResetting); @@ -27,10 +32,28 @@ export const fetchResetIntegration = ({ dispatch, getters }) => { .catch(() => dispatch('receiveResetIntegrationError')); }; -export const requestJiraIssueTypes = ({ commit }) => { +export const requestJiraIssueTypes = ({ commit, dispatch, getters }, formData) => { commit(types.SET_JIRA_ISSUE_TYPES_ERROR_MESSAGE, ''); commit(types.SET_IS_LOADING_JIRA_ISSUE_TYPES, true); + + return testIntegrationSettings(getters.propsSource.testPath, formData) + .then( + ({ + data: { issuetypes, error, message = I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE }, + }) => { + if (error || !issuetypes?.length) { + eventHub.$emit(VALIDATE_INTEGRATION_FORM_EVENT); + throw new Error(message); + } + + dispatch('receiveJiraIssueTypesSuccess', issuetypes); + }, + ) + .catch(({ message = I18N_DEFAULT_ERROR_MESSAGE }) => { + dispatch('receiveJiraIssueTypesError', message); + }); }; + export const receiveJiraIssueTypesSuccess = ({ commit }, issueTypes = []) => { commit(types.SET_IS_LOADING_JIRA_ISSUE_TYPES, false); commit(types.SET_JIRA_ISSUE_TYPES, issueTypes); diff --git a/app/assets/javascripts/integrations/edit/store/getters.js b/app/assets/javascripts/integrations/edit/store/getters.js index 39e14de2d0d..b79132128cc 100644 --- a/app/assets/javascripts/integrations/edit/store/getters.js +++ b/app/assets/javascripts/integrations/edit/store/getters.js @@ -1,7 +1,5 @@ export const isInheriting = (state) => (state.defaultState === null ? false : !state.override); -export const isDisabled = (state) => state.isSaving || state.isTesting || state.isResetting; - export const propsSource = (state, getters) => getters.isInheriting ? state.defaultState : state.customState; diff --git a/app/assets/javascripts/integrations/edit/store/mutation_types.js b/app/assets/javascripts/integrations/edit/store/mutation_types.js index c681056a515..ddf6bef7554 100644 --- a/app/assets/javascripts/integrations/edit/store/mutation_types.js +++ b/app/assets/javascripts/integrations/edit/store/mutation_types.js @@ -1,6 +1,4 @@ export const SET_OVERRIDE = 'SET_OVERRIDE'; -export const SET_IS_SAVING = 'SET_IS_SAVING'; -export const SET_IS_TESTING = 'SET_IS_TESTING'; export const SET_IS_RESETTING = 'SET_IS_RESETTING'; export const SET_IS_LOADING_JIRA_ISSUE_TYPES = 'SET_IS_LOADING_JIRA_ISSUE_TYPES'; diff --git a/app/assets/javascripts/integrations/edit/store/mutations.js b/app/assets/javascripts/integrations/edit/store/mutations.js index 279df1b9266..e7e312ce650 100644 --- a/app/assets/javascripts/integrations/edit/store/mutations.js +++ b/app/assets/javascripts/integrations/edit/store/mutations.js @@ -4,12 +4,6 @@ export default { [types.SET_OVERRIDE](state, override) { state.override = override; }, - [types.SET_IS_SAVING](state, isSaving) { - state.isSaving = isSaving; - }, - [types.SET_IS_TESTING](state, isTesting) { - state.isTesting = isTesting; - }, [types.SET_IS_RESETTING](state, isResetting) { state.isResetting = isResetting; }, diff --git a/app/assets/javascripts/integrations/edit/store/state.js b/app/assets/javascripts/integrations/edit/store/state.js index 1c0b274e4ef..3d40d1b90d5 100644 --- a/app/assets/javascripts/integrations/edit/store/state.js +++ b/app/assets/javascripts/integrations/edit/store/state.js @@ -6,7 +6,6 @@ export default ({ defaultState = null, customState = {} } = {}) => { defaultState, customState, isSaving: false, - isTesting: false, isResetting: false, isLoadingJiraIssueTypes: false, loadingJiraIssueTypesErrorMessage: '', diff --git a/app/assets/javascripts/integrations/integration_settings_form.js b/app/assets/javascripts/integrations/integration_settings_form.js deleted file mode 100644 index f519fc87c46..00000000000 --- a/app/assets/javascripts/integrations/integration_settings_form.js +++ /dev/null @@ -1,151 +0,0 @@ -import { delay } from 'lodash'; -import toast from '~/vue_shared/plugins/global_toast'; -import axios from '../lib/utils/axios_utils'; -import initForm from './edit'; -import eventHub from './edit/event_hub'; -import { - TEST_INTEGRATION_EVENT, - SAVE_INTEGRATION_EVENT, - GET_JIRA_ISSUE_TYPES_EVENT, - TOGGLE_INTEGRATION_EVENT, - VALIDATE_INTEGRATION_FORM_EVENT, - I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE, - I18N_DEFAULT_ERROR_MESSAGE, - I18N_SUCCESSFUL_CONNECTION_MESSAGE, -} from './constants'; - -export default class IntegrationSettingsForm { - constructor(formSelector) { - this.$form = document.querySelector(formSelector); - this.formActive = false; - - this.vue = null; - - // Form Metadata - this.testEndPoint = this.$form.dataset.testUrl; - } - - init() { - // Init Vue component - this.vue = initForm( - document.querySelector('.js-vue-integration-settings'), - document.querySelector('.js-vue-default-integration-settings'), - ); - eventHub.$on(TOGGLE_INTEGRATION_EVENT, (active) => { - this.formActive = active; - this.toggleServiceState(); - }); - eventHub.$on(TEST_INTEGRATION_EVENT, () => { - this.testIntegration(); - }); - eventHub.$on(SAVE_INTEGRATION_EVENT, () => { - this.saveIntegration(); - }); - eventHub.$on(GET_JIRA_ISSUE_TYPES_EVENT, () => { - this.getJiraIssueTypes(new FormData(this.$form)); - }); - } - - saveIntegration() { - // Save Service if not active and check the following if active; - // 1) If form contents are valid - // 2) If this service can be saved - // If both conditions are true, we override form submission - // and save the service using provided configuration. - const formValid = this.$form.checkValidity() || this.formActive === false; - - if (formValid) { - delay(() => { - this.$form.submit(); - }, 100); - } else { - eventHub.$emit(VALIDATE_INTEGRATION_FORM_EVENT); - this.vue.$store.dispatch('setIsSaving', false); - } - } - - testIntegration() { - // Service was marked active so now we check; - // 1) If form contents are valid - // 2) If this service can be tested - // If both conditions are true, we override form submission - // and test the service using provided configuration. - if (this.$form.checkValidity()) { - this.testSettings(new FormData(this.$form)); - } else { - eventHub.$emit(VALIDATE_INTEGRATION_FORM_EVENT); - this.vue.$store.dispatch('setIsTesting', false); - } - } - - /** - * Change Form's validation enforcement based on service status (active/inactive) - */ - toggleServiceState() { - if (this.formActive) { - this.$form.removeAttribute('novalidate'); - } else if (!this.$form.getAttribute('novalidate')) { - this.$form.setAttribute('novalidate', 'novalidate'); - } - } - - /** - * Get a list of Jira issue types for the currently configured project - * - * @param {string} formData - URL encoded string containing the form data - * - * @return {Promise} - */ - getJiraIssueTypes(formData) { - const { - $store: { dispatch }, - } = this.vue; - - dispatch('requestJiraIssueTypes'); - - return this.fetchTestSettings(formData) - .then( - ({ - data: { issuetypes, error, message = I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE }, - }) => { - if (error || !issuetypes?.length) { - eventHub.$emit(VALIDATE_INTEGRATION_FORM_EVENT); - throw new Error(message); - } - - dispatch('receiveJiraIssueTypesSuccess', issuetypes); - }, - ) - .catch(({ message = I18N_DEFAULT_ERROR_MESSAGE }) => { - dispatch('receiveJiraIssueTypesError', message); - }); - } - - /** - * Send request to the test endpoint which checks if the current config is valid - */ - fetchTestSettings(formData) { - return axios.put(this.testEndPoint, formData); - } - - /** - * Test Integration config - */ - testSettings(formData) { - return this.fetchTestSettings(formData) - .then(({ data }) => { - if (data.error) { - toast(`${data.message} ${data.service_response}`); - } else { - this.vue.$store.dispatch('receiveJiraIssueTypesSuccess', data.issuetypes); - toast(I18N_SUCCESSFUL_CONNECTION_MESSAGE); - } - }) - .catch(() => { - toast(I18N_DEFAULT_ERROR_MESSAGE); - }) - .finally(() => { - this.vue.$store.dispatch('setIsTesting', false); - }); - } -} diff --git a/app/assets/javascripts/integrations/overrides/components/integration_overrides.vue b/app/assets/javascripts/integrations/overrides/components/integration_overrides.vue index 85018f133cb..3fc554c5371 100644 --- a/app/assets/javascripts/integrations/overrides/components/integration_overrides.vue +++ b/app/assets/javascripts/integrations/overrides/components/integration_overrides.vue @@ -6,8 +6,12 @@ import { DEFAULT_PER_PAGE } from '~/api'; import { fetchOverrides } from '~/integrations/overrides/api'; import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils'; import { truncateNamespace } from '~/lib/utils/text_utility'; +import { getParameterByName } from '~/lib/utils/url_utility'; import { __, s__ } from '~/locale'; import ProjectAvatar from '~/vue_shared/components/project_avatar.vue'; +import UrlSync from '~/vue_shared/components/url_sync.vue'; + +const DEFAULT_PAGE = 1; export default { name: 'IntegrationOverrides', @@ -18,6 +22,7 @@ export default { GlTable, GlAlert, ProjectAvatar, + UrlSync, }, props: { overridesPath: { @@ -35,7 +40,7 @@ export default { return { isLoading: true, overrides: [], - page: 1, + page: DEFAULT_PAGE, totalItems: 0, errorMessage: null, }; @@ -44,12 +49,21 @@ export default { showPagination() { return this.totalItems > this.$options.DEFAULT_PER_PAGE && this.overrides.length > 0; }, + query() { + return { + page: this.page, + }; + }, }, - mounted() { - this.loadOverrides(); + created() { + const initialPage = this.getInitialPage(); + this.loadOverrides(initialPage); }, methods: { - loadOverrides(page = this.page) { + getInitialPage() { + return getParameterByName('page') ?? DEFAULT_PAGE; + }, + loadOverrides(page) { this.isLoading = true; this.errorMessage = null; @@ -119,14 +133,16 @@ export default { </template> </gl-table> <div class="gl-display-flex gl-justify-content-center gl-mt-5"> - <gl-pagination - v-if="showPagination" - :per-page="$options.DEFAULT_PER_PAGE" - :total-items="totalItems" - :value="page" - :disabled="isLoading" - @input="loadOverrides" - /> + <template v-if="showPagination"> + <gl-pagination + :per-page="$options.DEFAULT_PER_PAGE" + :total-items="totalItems" + :value="page" + :disabled="isLoading" + @input="loadOverrides" + /> + <url-sync :query="query" /> + </template> </div> </div> </template> |