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-01-20 12:16:11 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-01-20 12:16:11 +0300
commitedaa33dee2ff2f7ea3fac488d41558eb5f86d68c (patch)
tree11f143effbfeba52329fb7afbd05e6e2a3790241 /app/assets/javascripts/integrations
parentd8a5691316400a0f7ec4f83832698f1988eb27c1 (diff)
Add latest changes from gitlab-org/gitlab@14-7-stable-eev14.7.0-rc42
Diffstat (limited to 'app/assets/javascripts/integrations')
-rw-r--r--app/assets/javascripts/integrations/constants.js5
-rw-r--r--app/assets/javascripts/integrations/edit/components/dynamic_field.vue5
-rw-r--r--app/assets/javascripts/integrations/edit/components/integration_form.vue143
-rw-r--r--app/assets/javascripts/integrations/edit/components/reset_confirmation_modal.vue2
-rw-r--r--app/assets/javascripts/integrations/edit/index.js7
-rw-r--r--app/assets/javascripts/integrations/edit/store/actions.js23
-rw-r--r--app/assets/javascripts/integrations/edit/store/mutations.js9
-rw-r--r--app/assets/javascripts/integrations/edit/store/state.js2
-rw-r--r--app/assets/javascripts/integrations/overrides/components/integration_overrides.vue7
-rw-r--r--app/assets/javascripts/integrations/overrides/components/integration_tabs.vue52
-rw-r--r--app/assets/javascripts/integrations/overrides/index.js5
11 files changed, 176 insertions, 84 deletions
diff --git a/app/assets/javascripts/integrations/constants.js b/app/assets/javascripts/integrations/constants.js
index 84656bd41bb..b90658fb13c 100644
--- a/app/assets/javascripts/integrations/constants.js
+++ b/app/assets/javascripts/integrations/constants.js
@@ -23,3 +23,8 @@ export const I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE = s__(
);
export const I18N_DEFAULT_ERROR_MESSAGE = __('Something went wrong on our end.');
export const I18N_SUCCESSFUL_CONNECTION_MESSAGE = s__('Integrations|Connection successful.');
+
+export const settingsTabTitle = __('Settings');
+export const overridesTabTitle = s__('Integrations|Projects using custom settings');
+
+export const INTEGRATION_FORM_SELECTOR = '.js-integration-settings-form';
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: [],
diff --git a/app/assets/javascripts/integrations/overrides/components/integration_overrides.vue b/app/assets/javascripts/integrations/overrides/components/integration_overrides.vue
index 3fc554c5371..f2d3e6489ee 100644
--- a/app/assets/javascripts/integrations/overrides/components/integration_overrides.vue
+++ b/app/assets/javascripts/integrations/overrides/components/integration_overrides.vue
@@ -11,6 +11,8 @@ import { __, s__ } from '~/locale';
import ProjectAvatar from '~/vue_shared/components/project_avatar.vue';
import UrlSync from '~/vue_shared/components/url_sync.vue';
+import IntegrationTabs from './integration_tabs.vue';
+
const DEFAULT_PAGE = 1;
export default {
@@ -23,6 +25,7 @@ export default {
GlAlert,
ProjectAvatar,
UrlSync,
+ IntegrationTabs,
},
props: {
overridesPath: {
@@ -46,6 +49,9 @@ export default {
};
},
computed: {
+ overridesCount() {
+ return this.isLoading ? null : this.totalItems;
+ },
showPagination() {
return this.totalItems > this.$options.DEFAULT_PER_PAGE && this.overrides.length > 0;
},
@@ -100,6 +106,7 @@ export default {
<template>
<div>
+ <integration-tabs :project-overrides-count="overridesCount" />
<gl-alert v-if="errorMessage" variant="danger" :dismissible="false">
{{ errorMessage }}
</gl-alert>
diff --git a/app/assets/javascripts/integrations/overrides/components/integration_tabs.vue b/app/assets/javascripts/integrations/overrides/components/integration_tabs.vue
new file mode 100644
index 00000000000..3f67c987231
--- /dev/null
+++ b/app/assets/javascripts/integrations/overrides/components/integration_tabs.vue
@@ -0,0 +1,52 @@
+<script>
+import { GlBadge, GlNavItem, GlTabs, GlTab } from '@gitlab/ui';
+import { settingsTabTitle, overridesTabTitle } from '~/integrations/constants';
+
+export default {
+ components: {
+ GlBadge,
+ GlNavItem,
+ GlTabs,
+ GlTab,
+ },
+ inject: {
+ editPath: {
+ default: '',
+ },
+ },
+ props: {
+ projectOverridesCount: {
+ type: [Number, String],
+ required: false,
+ default: null,
+ },
+ },
+ i18n: {
+ settingsTabTitle,
+ overridesTabTitle,
+ },
+};
+</script>
+
+<template>
+ <gl-tabs>
+ <template #tabs-start>
+ <gl-nav-item role="presentation" link-classes="gl-tab-nav-item" :href="editPath">{{
+ $options.i18n.settingsTabTitle
+ }}</gl-nav-item>
+ </template>
+
+ <gl-tab active>
+ <template #title>
+ {{ $options.i18n.overridesTabTitle }}
+ <gl-badge
+ v-if="projectOverridesCount !== null"
+ variant="muted"
+ size="sm"
+ class="gl-tab-counter-badge"
+ >{{ projectOverridesCount }}</gl-badge
+ >
+ </template>
+ </gl-tab>
+ </gl-tabs>
+</template>
diff --git a/app/assets/javascripts/integrations/overrides/index.js b/app/assets/javascripts/integrations/overrides/index.js
index 0f03b23ba21..f289a2d3d1a 100644
--- a/app/assets/javascripts/integrations/overrides/index.js
+++ b/app/assets/javascripts/integrations/overrides/index.js
@@ -8,10 +8,13 @@ export default () => {
return null;
}
- const { overridesPath } = el.dataset;
+ const { editPath, overridesPath } = el.dataset;
return new Vue({
el,
+ provide: {
+ editPath,
+ },
render(createElement) {
return createElement(IntegrationOverrides, {
props: {