diff options
Diffstat (limited to 'app/assets/javascripts/integrations/edit')
4 files changed, 201 insertions, 120 deletions
diff --git a/app/assets/javascripts/integrations/edit/components/dynamic_field.vue b/app/assets/javascripts/integrations/edit/components/dynamic_field.vue index fe687ea9767..904e5639cac 100644 --- a/app/assets/javascripts/integrations/edit/components/dynamic_field.vue +++ b/app/assets/javascripts/integrations/edit/components/dynamic_field.vue @@ -1,14 +1,8 @@ <script> -import { - GlFormGroup, - GlFormCheckbox, - GlFormInput, - GlFormSelect, - GlFormTextarea, - GlSafeHtmlDirective as SafeHtml, -} from '@gitlab/ui'; +import { GlFormGroup, GlFormCheckbox, GlFormInput, GlFormSelect, GlFormTextarea } from '@gitlab/ui'; import { capitalize, lowerCase, isEmpty } from 'lodash'; import { mapGetters } from 'vuex'; +import SafeHtml from '~/vue_shared/directives/safe_html'; export default { name: 'DynamicField', @@ -80,7 +74,7 @@ export default { }; }, computed: { - ...mapGetters(['isInheriting']), + ...mapGetters(['isInheriting', 'propsSource']), isCheckbox() { return this.type === 'checkbox'; }, @@ -122,11 +116,18 @@ export default { name: this.fieldName, state: this.valid, readonly: this.isInheriting, + disabled: this.isDisabled, }; }, valid() { return !this.required || !isEmpty(this.model) || this.isNonEmptyPassword || !this.isValidated; }, + isInheritingOrDisabled() { + return this.isInheriting || this.isDisabled; + }, + isDisabled() { + return !this.propsSource.editable; + }, }, created() { if (this.isNonEmptyPassword) { @@ -149,7 +150,7 @@ export default { <template v-if="isCheckbox"> <input :name="fieldName" type="hidden" :value="model || false" /> - <gl-form-checkbox :id="fieldId" v-model="model" :disabled="isInheriting"> + <gl-form-checkbox :id="fieldId" v-model="model" :disabled="isInheritingOrDisabled"> {{ checkboxLabel || humanizedTitle }} <template #help> <span v-safe-html="help"></span> @@ -158,7 +159,12 @@ export default { </template> <template v-else-if="isSelect"> <input type="hidden" :name="fieldName" :value="model" /> - <gl-form-select :id="fieldId" v-model="model" :options="options" :disabled="isInheriting" /> + <gl-form-select + :id="fieldId" + v-model="model" + :options="options" + :disabled="isInheritingOrDisabled" + /> </template> <gl-form-textarea v-else-if="isTextarea" diff --git a/app/assets/javascripts/integrations/edit/components/integration_form.vue b/app/assets/javascripts/integrations/edit/components/integration_form.vue index 4bf2b8d4468..d86e6326f64 100644 --- a/app/assets/javascripts/integrations/edit/components/integration_form.vue +++ b/app/assets/javascripts/integrations/edit/components/integration_form.vue @@ -1,22 +1,15 @@ <script> -import { - GlAlert, - GlBadge, - GlButton, - GlModalDirective, - GlSafeHtmlDirective as SafeHtml, - GlForm, -} from '@gitlab/ui'; +import { GlAlert, GlBadge, GlButton, GlForm } from '@gitlab/ui'; import axios from 'axios'; import * as Sentry from '@sentry/browser'; import { mapState, mapActions, mapGetters } from 'vuex'; import { s__ } from '~/locale'; +import SafeHtml from '~/vue_shared/directives/safe_html'; import { I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE, I18N_DEFAULT_ERROR_MESSAGE, I18N_SUCCESSFUL_CONNECTION_MESSAGE, INTEGRATION_FORM_TYPE_SLACK, - integrationLevels, integrationFormSectionComponents, billingPlanNames, } from '~/integrations/constants'; @@ -25,11 +18,10 @@ import csrf from '~/lib/utils/csrf'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import { testIntegrationSettings } from '../api'; import ActiveCheckbox from './active_checkbox.vue'; -import ConfirmationModal from './confirmation_modal.vue'; import DynamicField from './dynamic_field.vue'; import OverrideDropdown from './override_dropdown.vue'; -import ResetConfirmationModal from './reset_confirmation_modal.vue'; import TriggerFields from './trigger_fields.vue'; +import IntegrationFormActions from './integration_form_actions.vue'; export default { name: 'IntegrationForm', @@ -38,8 +30,7 @@ export default { ActiveCheckbox, TriggerFields, DynamicField, - ConfirmationModal, - ResetConfirmationModal, + IntegrationFormActions, IntegrationSectionConfiguration: () => import( /* webpackChunkName: 'integrationSectionConfiguration' */ '~/integrations/edit/components/sections/configuration.vue' @@ -66,7 +57,6 @@ export default { GlForm, }, directives: { - GlModal: GlModalDirective, SafeHtml, }, mixins: [glFeatureFlagsMixin()], @@ -78,10 +68,10 @@ export default { data() { return { integrationActive: false, - isTesting: false, + isValidated: false, isSaving: false, + isTesting: false, isResetting: false, - isValidated: false, }; }, computed: { @@ -90,21 +80,6 @@ export default { isEditable() { return this.propsSource.editable; }, - isInstanceOrGroupLevel() { - return ( - this.customState.integrationLevel === integrationLevels.INSTANCE || - this.customState.integrationLevel === integrationLevels.GROUP - ); - }, - showResetButton() { - return this.isInstanceOrGroupLevel && this.propsSource.resetPath; - }, - showTestButton() { - return this.propsSource.canTest; - }, - disableButtons() { - return Boolean(this.isSaving || this.isResetting || this.isTesting); - }, hasSections() { if (this.hasSlackNotificationsDisabled) { return false; @@ -134,6 +109,14 @@ export default { } return !this.hasSections && this.helpHtml; }, + shouldUpgradeSlack() { + return ( + this.isSlackIntegration && + this.glFeatures.integrationSlackAppNotifications && + this.customState.shouldUpgradeSlack && + (this.hasFieldsWithoutSection || this.hasSections) + ); + }, }, methods: { ...mapActions(['setOverride', 'requestJiraIssueTypes']), @@ -148,7 +131,6 @@ export default { }, onSaveClick() { this.isSaving = true; - if (this.integrationActive && !this.form().checkValidity()) { this.isSaving = false; this.setIsValidated(); @@ -194,7 +176,6 @@ export default { }, onResetClick() { this.isResetting = true; - return axios .post(this.propsSource.resetPath) .then(() => { @@ -227,7 +208,10 @@ export default { billingPlanNames, slackUpgradeInfo: { title: s__( - `SlackIntegration|Notifications only work if you're on the latest version of the GitLab for Slack app`, + `SlackIntegration|Update to the latest version of GitLab for Slack to get notifications`, + ), + text: s__( + `SlackIntegration|Update to the latest version to receive notifications from GitLab.`, ), btnText: s__('SlackIntegration|Update to the latest version'), }, @@ -284,16 +268,18 @@ export default { </div> </section> + <div v-if="shouldUpgradeSlack" class="gl-border-t"> + <gl-alert + :dismissible="false" + :title="$options.slackUpgradeInfo.title" + :primary-button-link="customState.upgradeSlackUrl" + :primary-button-text="$options.slackUpgradeInfo.btnText" + class="gl-mb-8 gl-mt-5" + >{{ $options.slackUpgradeInfo.text }}</gl-alert + > + </div> + <template v-if="hasSections"> - <div v-if="customState.shouldUpgradeSlack && isSlackIntegration" class="gl-border-t"> - <gl-alert - :title="$options.slackUpgradeInfo.title" - variant="warning" - :primary-button-link="customState.upgradeSlackUrl" - :primary-button-text="$options.slackUpgradeInfo.btnText" - class="gl-mb-8 gl-mt-5" - /> - </div> <div v-for="(section, index) in customState.sections" :key="section.type" @@ -344,71 +330,16 @@ export default { </div> </section> - <section v-if="isEditable" :class="!hasSections && 'gl-lg-display-flex gl-justify-content-end'"> - <div :class="!hasSections && 'gl-flex-basis-two-thirds'"> - <div - class="footer-block row-content-block gl-lg-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-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 :href="propsSource.cancelPath">{{ __('Cancel') }}</gl-button> - </div> - - <template v-if="showResetButton"> - <gl-button - v-gl-modal.confirmResetIntegration - category="tertiary" - variant="danger" - :loading="isResetting" - :disabled="disableButtons" - data-testid="reset-button" - > - {{ __('Reset') }} - </gl-button> - - <reset-confirmation-modal @reset="onResetClick" /> - </template> - </div> - </div> - </section> + <integration-form-actions + v-if="isEditable" + :has-sections="hasSections" + :class="{ 'gl-lg-display-flex gl-justify-content-end': !hasSections }" + :is-saving="isSaving" + :is-testing="isTesting" + :is-resetting="isResetting" + @save="onSaveClick" + @test="onTestClick" + @reset="onResetClick" + /> </gl-form> </template> diff --git a/app/assets/javascripts/integrations/edit/components/integration_form_actions.vue b/app/assets/javascripts/integrations/edit/components/integration_form_actions.vue new file mode 100644 index 00000000000..e5ad5149cf7 --- /dev/null +++ b/app/assets/javascripts/integrations/edit/components/integration_form_actions.vue @@ -0,0 +1,143 @@ +<script> +import { GlButton, GlModalDirective } from '@gitlab/ui'; +import { mapState, mapGetters } from 'vuex'; +import { integrationLevels } from '~/integrations/constants'; +import ConfirmationModal from './confirmation_modal.vue'; +import ResetConfirmationModal from './reset_confirmation_modal.vue'; + +export default { + name: 'IntegrationFormActions', + components: { + GlButton, + ConfirmationModal, + ResetConfirmationModal, + }, + directives: { + GlModal: GlModalDirective, + }, + props: { + hasSections: { + type: Boolean, + required: true, + }, + isSaving: { + type: Boolean, + required: false, + default: false, + }, + isTesting: { + type: Boolean, + required: false, + default: false, + }, + isResetting: { + type: Boolean, + required: false, + default: false, + }, + }, + computed: { + ...mapGetters(['propsSource']), + ...mapState(['customState']), + isInstanceOrGroupLevel() { + return ( + this.customState.integrationLevel === integrationLevels.INSTANCE || + this.customState.integrationLevel === integrationLevels.GROUP + ); + }, + showResetButton() { + return this.isInstanceOrGroupLevel && this.propsSource.resetPath; + }, + showTestButton() { + return this.propsSource.canTest; + }, + disableButtons() { + return Boolean(this.isSaving || this.isResetting || this.isTesting); + }, + }, + methods: { + onSaveClick() { + this.$emit('save'); + }, + onTestClick() { + this.$emit('test'); + }, + onResetClick() { + this.$emit('reset'); + }, + }, +}; +</script> +<template> + <section> + <div :class="{ 'gl-flex-basis-two-thirds': !hasSections }"> + <div + class="footer-block row-content-block gl-lg-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" + data-qa-selector="save_changes_button" + > + {{ __('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 + :href="propsSource.cancelPath" + data-testid="cancel-button" + :disabled="disableButtons" + >{{ __('Cancel') }}</gl-button + > + </div> + + <template v-if="showResetButton"> + <gl-button + v-gl-modal.confirmResetIntegration + category="tertiary" + variant="danger" + :loading="isResetting" + :disabled="disableButtons" + data-testid="reset-button" + > + {{ __('Reset') }} + </gl-button> + + <reset-confirmation-modal @reset="onResetClick" /> + </template> + </div> + </div> + </section> +</template> diff --git a/app/assets/javascripts/integrations/edit/index.js b/app/assets/javascripts/integrations/edit/index.js index f15ad5e052e..b53bcd50f16 100644 --- a/app/assets/javascripts/integrations/edit/index.js +++ b/app/assets/javascripts/integrations/edit/index.js @@ -108,6 +108,7 @@ export default function initIntegrationSettingsForm() { const initialState = { defaultState: null, customState: customSettingsProps, + editable: customSettingsProps.editable && !customSettingsProps.shouldUpgradeSlack, }; if (defaultSettingsEl) { initialState.defaultState = Object.freeze(parseDatasetToProps(defaultSettingsEl.dataset)); |