diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-18 15:10:46 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-18 15:10:46 +0000 |
commit | 346c2ebb5a818524c5d8d95dc6b9fc8c892e3b5c (patch) | |
tree | 63bf068a9d8cedf0b7f9e80cf99e491813617db1 /app/assets/javascripts | |
parent | 5f287a8e306da1e0b6152a0b7f8621a8e71a3fe4 (diff) | |
download | gitlab-ce-346c2ebb5a818524c5d8d95dc6b9fc8c892e3b5c.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts')
4 files changed, 328 insertions, 64 deletions
diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue index afd7467acf3..d9887c2ce05 100644 --- a/app/assets/javascripts/diffs/components/diff_file.vue +++ b/app/assets/javascripts/diffs/components/diff_file.vue @@ -5,6 +5,7 @@ import { mapActions, mapGetters, mapState } from 'vuex'; import { deprecatedCreateFlash as createFlash } from '~/flash'; import { hasDiff } from '~/helpers/diffs_helper'; import { diffViewerErrors } from '~/ide/constants'; +import { scrollToElement } from '~/lib/utils/common_utils'; import { sprintf } from '~/locale'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import notesEventHub from '../../notes/event_hub'; @@ -233,15 +234,20 @@ export default { eventHub.$emit(event); }); }, - handleToggle() { - const currentCollapsedFlag = this.isCollapsed; + handleToggle({ viaUserInteraction = false } = {}) { + const collapsingNow = !this.isCollapsed; + const contentElement = this.$el.querySelector(`#diff-content-${this.file.file_hash}`); this.setFileCollapsedByUser({ filePath: this.file.file_path, - collapsed: !currentCollapsedFlag, + collapsed: collapsingNow, }); - if (!this.hasDiff && currentCollapsedFlag) { + if (collapsingNow && viaUserInteraction && contentElement) { + scrollToElement(contentElement, { duration: 1 }); + } + + if (!this.hasDiff && !collapsingNow) { this.requestDiff(); } }, @@ -300,7 +306,7 @@ export default { :codequality-diff="codequalityDiffForFile" class="js-file-title file-title gl-border-1 gl-border-solid gl-border-gray-100" :class="hasBodyClasses.header" - @toggleFile="handleToggle" + @toggleFile="handleToggle({ viaUserInteraction: true })" @showForkMessage="showForkMessage" /> diff --git a/app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue b/app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue index cc85582ec77..43753926039 100644 --- a/app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue +++ b/app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue @@ -1,5 +1,15 @@ <script> -import { GlForm, GlIcon, GlLink, GlButton, GlSprintf, GlAlert, GlLoadingIcon } from '@gitlab/ui'; +import { + GlForm, + GlIcon, + GlLink, + GlButton, + GlSprintf, + GlAlert, + GlLoadingIcon, + GlModal, + GlModalDirective, +} from '@gitlab/ui'; import axios from '~/lib/utils/axios_utils'; import csrf from '~/lib/utils/csrf'; import { setUrlFragment } from '~/lib/utils/url_utility'; @@ -15,6 +25,67 @@ const MARKDOWN_LINK_TEXT = { }; export default { + i18n: { + title: { + label: s__('WikiPage|Title'), + placeholder: s__('WikiPage|Page title'), + helpText: { + existingPage: s__( + 'WikiPage|Tip: You can move this page by adding the path to the beginning of the title.', + ), + newPage: s__( + 'WikiPage|Tip: You can specify the full path for the new file. We will automatically create any missing directories.', + ), + moreInformation: s__('WikiPage|More Information.'), + }, + }, + format: { + label: s__('WikiPage|Format'), + }, + content: { + label: s__('WikiPage|Content'), + placeholder: s__('WikiPage|Write your content or drag files here…'), + }, + contentEditor: { + renderFailed: { + message: s__( + 'WikiPage|An error occured while trying to render the content editor. Please try again later.', + ), + primaryAction: s__('WikiPage|Retry'), + }, + useNewEditor: s__('WikiPage|Use new editor'), + switchToOldEditor: { + label: s__('WikiPage|Switch to old editor'), + helpText: s__("WikiPage|Switching will discard any changes you've made in the new editor."), + modal: { + title: s__('WikiPage|Are you sure you want to switch to the old editor?'), + primary: s__('WikiPage|Switch to old editor'), + cancel: s__('WikiPage|Keep editing'), + text: s__( + "WikiPage|Switching to the old editor will discard any changes you've made in the new editor.", + ), + }, + }, + helpText: s__( + "WikiPage|This editor is in beta and may not display the page's contents properly.", + ), + }, + linksHelpText: s__( + 'WikiPage|To link to a (new) page, simply type %{linkExample}. More examples are in the %{linkStart}documentation%{linkEnd}.', + ), + commitMessage: { + label: s__('WikiPage|Commit message'), + value: { + existingPage: s__('WikiPage|Update %{pageTitle}'), + newPage: s__('WikiPage|Create %{pageTitle}'), + }, + }, + submitButton: { + existingPage: s__('WikiPage|Save changes'), + newPage: s__('WikiPage|Create page'), + }, + cancel: s__('WikiPage|Cancel'), + }, components: { GlAlert, GlForm, @@ -22,6 +93,7 @@ export default { GlIcon, GlLink, GlButton, + GlModal, MarkdownField, GlLoadingIcon, ContentEditor: () => @@ -29,6 +101,9 @@ export default { /* webpackChunkName: 'content_editor' */ '~/content_editor/components/content_editor.vue' ), }, + directives: { + GlModalDirective, + }, mixins: [glFeatureFlagMixin()], inject: ['formatOptions', 'pageInfo'], data() { @@ -41,6 +116,7 @@ export default { commitMessage: '', contentEditor: null, isDirty: false, + contentEditorRenderFailed: false, }; }, computed: { @@ -58,15 +134,21 @@ export default { }, commitMessageI18n() { return this.pageInfo.persisted - ? s__('WikiPage|Update %{pageTitle}') - : s__('WikiPage|Create %{pageTitle}'); + ? this.$options.i18n.commitMessage.value.existingPage + : this.$options.i18n.commitMessage.value.newPage; }, linkExample() { return MARKDOWN_LINK_TEXT[this.format]; }, submitButtonText() { - if (this.pageInfo.persisted) return s__('WikiPage|Save changes'); - return s__('WikiPage|Create page'); + return this.pageInfo.persisted + ? this.$options.i18n.submitButton.existingPage + : this.$options.i18n.submitButton.newPage; + }, + titleHelpText() { + return this.pageInfo.persisted + ? this.$options.i18n.title.helpText.existingPage + : this.$options.i18n.title.helpText.newPage; }, cancelFormPath() { if (this.pageInfo.persisted) return this.pageInfo.path; @@ -81,6 +163,9 @@ export default { showContentEditorButton() { return this.isMarkdownFormat && !this.useContentEditor && this.glFeatures.wikiContentEditor; }, + disableSubmitButton() { + return !this.content || !this.title || this.contentEditorRenderFailed; + }, isContentEditorActive() { return this.isMarkdownFormat && this.useContentEditor; }, @@ -147,14 +232,32 @@ export default { onUpdate: () => this.handleContentChange(), }, }); - await this.contentEditor.setSerializedContent(this.content); - this.isContentEditorLoading = false; + try { + await this.contentEditor.setSerializedContent(this.content); + this.isContentEditorLoading = false; + } catch (e) { + this.contentEditorRenderFailed = true; + } + }, + + retryInitContentEditor() { + this.contentEditorRenderFailed = false; + this.initContentEditor(); }, switchToOldEditor() { this.useContentEditor = false; }, + + confirmSwitchToOldEditor() { + if (this.contentEditorRenderFailed) { + this.contentEditorRenderFailed = false; + this.switchToOldEditor(); + } else { + this.$refs.confirmSwitchToOldEditorModal.show(); + } + }, }, }; </script> @@ -167,26 +270,15 @@ export default { @submit="handleFormSubmit" > <gl-alert - v-if="isContentEditorActive" + v-if="isContentEditorActive && contentEditorRenderFailed" class="gl-mb-6" :dismissible="false" variant="danger" - :primary-button-text="s__('WikiPage|Switch to old editor')" - @primaryAction="switchToOldEditor()" + :primary-button-text="$options.i18n.contentEditor.renderFailed.primaryAction" + @primaryAction="retryInitContentEditor()" > <p> - {{ - s__( - "WikiPage|You are editing this page with Content Editor. This editor is in beta and may not display the page's contents properly.", - ) - }} - </p> - <p> - {{ - s__( - "WikiPage|Switching to the old editor will discard any changes you've made in the new editor.", - ) - }} + {{ $options.i18n.contentEditor.renderFailed.message }} </p> </gl-alert> @@ -200,7 +292,9 @@ export default { /> <div class="form-group row"> <div class="col-sm-2 col-form-label"> - <label class="control-label-full-width" for="wiki_title">{{ s__('WikiPage|Title') }}</label> + <label class="control-label-full-width" for="wiki_title">{{ + $options.i18n.title.label + }}</label> </div> <div class="col-sm-10"> <input @@ -212,22 +306,15 @@ export default { data-qa-selector="wiki_title_textbox" :required="true" :autofocus="!pageInfo.persisted" - :placeholder="s__('WikiPage|Page title')" + :placeholder="$options.i18n.title.placeholder" @input="updateCommitMessage" /> <span class="gl-display-inline-block gl-max-w-full gl-mt-2 gl-text-gray-600"> <gl-icon class="gl-mr-n1" name="bulb" /> - {{ - pageInfo.persisted - ? s__( - 'WikiPage|Tip: You can move this page by adding the path to the beginning of the title.', - ) - : s__( - 'WikiPage|Tip: You can specify the full path for the new file. We will automatically create any missing directories.', - ) - }} + {{ titleHelpText }} <gl-link :href="helpPath" target="_blank" - ><gl-icon name="question-o" /> {{ s__('WikiPage|More Information.') }}</gl-link + ><gl-icon name="question-o" /> + {{ $options.i18n.title.helpText.moreInformation }}</gl-link > </span> </div> @@ -235,10 +322,10 @@ export default { <div class="form-group row"> <div class="col-sm-2 col-form-label"> <label class="control-label-full-width" for="wiki_format">{{ - s__('WikiPage|Format') + $options.i18n.format.label }}</label> </div> - <div class="col-sm-10 gl-display-flex gl-flex-wrap"> + <div class="col-sm-10"> <select id="wiki_format" v-model="format" @@ -250,20 +337,43 @@ export default { {{ label }} </option> </select> - <gl-button - v-if="showContentEditorButton" - category="secondary" - variant="confirm" - class="gl-mt-4" - @click="initContentEditor" - >{{ s__('WikiPage|Use new editor') }}</gl-button - > + <div> + <gl-button + v-if="showContentEditorButton" + category="secondary" + variant="confirm" + class="gl-mt-4" + @click="initContentEditor" + >{{ $options.i18n.contentEditor.useNewEditor }}</gl-button + > + <div v-if="isContentEditorActive" class="gl-mt-4 gl-display-flex"> + <div class="gl-mr-4"> + <gl-button category="secondary" variant="confirm" @click="confirmSwitchToOldEditor">{{ + $options.i18n.contentEditor.switchToOldEditor.label + }}</gl-button> + </div> + <div class="gl-mt-2"> + <gl-icon name="warning" /> + {{ $options.i18n.contentEditor.switchToOldEditor.helpText }} + </div> + </div> + <gl-modal + ref="confirmSwitchToOldEditorModal" + modal-id="confirm-switch-to-old-editor" + :title="$options.i18n.contentEditor.switchToOldEditor.modal.title" + :action-primary="{ text: $options.i18n.contentEditor.switchToOldEditor.modal.primary }" + :action-cancel="{ text: $options.i18n.contentEditor.switchToOldEditor.modal.cancel }" + @primary="switchToOldEditor" + > + {{ $options.i18n.contentEditor.switchToOldEditor.modal.text }} + </gl-modal> + </div> </div> </div> <div class="form-group row"> <div class="col-sm-2 col-form-label"> <label class="control-label-full-width" for="wiki_content">{{ - s__('WikiPage|Content') + $options.i18n.content.label }}</label> </div> <div class="col-sm-10"> @@ -288,8 +398,8 @@ export default { data-supports-quick-actions="false" data-qa-selector="wiki_content_textarea" :autofocus="pageInfo.persisted" - :aria-label="s__('WikiPage|Content')" - :placeholder="s__('WikiPage|Write your content or drag files here…')" + :aria-label="$options.i18n.content.label" + :placeholder="$options.i18n.content.placeholder" @input="handleContentChange" > </textarea> @@ -305,14 +415,8 @@ export default { <div class="clearfix"></div> <div class="error-alert"></div> - <div v-if="!isContentEditorActive" class="form-text gl-text-gray-600"> - <gl-sprintf - :message=" - s__( - 'WikiPage|To link to a (new) page, simply type %{linkExample}. More examples are in the %{linkStart}documentation%{linkEnd}.', - ) - " - > + <div class="form-text gl-text-gray-600"> + <gl-sprintf v-if="!isContentEditorActive" :message="$options.i18n.linksHelpText"> <template #linkExample ><code>{{ linkExample }}</code></template > @@ -327,13 +431,16 @@ export default { ></template > </gl-sprintf> + <span v-else> + {{ $options.i18n.contentEditor.helpText }} + </span> </div> </div> </div> <div class="form-group row"> <div class="col-sm-2 col-form-label"> <label class="control-label-full-width" for="wiki_message">{{ - s__('WikiPage|Commit message') + $options.i18n.commitMessage.label }}</label> </div> <div class="col-sm-10"> @@ -344,7 +451,7 @@ export default { type="text" class="form-control" data-qa-selector="wiki_message_textbox" - :placeholder="s__('WikiPage|Commit message')" + :placeholder="$options.i18n.commitMessage.label" /> </div> </div> @@ -355,10 +462,10 @@ export default { type="submit" data-qa-selector="wiki_submit_button" data-testid="wiki-submit-button" - :disabled="!content || !title" + :disabled="disableSubmitButton" >{{ submitButtonText }}</gl-button > - <gl-button :href="cancelFormPath" class="float-right">{{ s__('WikiPage|Cancel') }}</gl-button> + <gl-button :href="cancelFormPath" class="float-right">{{ $options.i18n.cancel }}</gl-button> </div> </gl-form> </template> diff --git a/app/assets/javascripts/security_configuration/components/feature_card.vue b/app/assets/javascripts/security_configuration/components/feature_card.vue new file mode 100644 index 00000000000..518a6ede3de --- /dev/null +++ b/app/assets/javascripts/security_configuration/components/feature_card.vue @@ -0,0 +1,150 @@ +<script> +import { GlButton, GlCard, GlIcon, GlLink } from '@gitlab/ui'; +import { __, s__, sprintf } from '~/locale'; +import ManageViaMr from '~/vue_shared/security_configuration/components/manage_via_mr.vue'; + +export default { + components: { + GlButton, + GlCard, + GlIcon, + GlLink, + ManageViaMr, + }, + props: { + feature: { + type: Object, + required: true, + }, + }, + computed: { + available() { + return this.feature.available; + }, + enabled() { + return this.available && this.feature.configured; + }, + hasStatus() { + return !this.available || typeof this.feature.configured === 'boolean'; + }, + shortName() { + return this.feature.shortName ?? this.feature.name; + }, + configurationButton() { + const button = this.enabled + ? { + text: this.$options.i18n.configureFeature, + category: 'secondary', + } + : { + text: this.$options.i18n.enableFeature, + category: 'primary', + }; + + button.text = sprintf(button.text, { feature: this.shortName }); + + return button; + }, + showManageViaMr() { + const { available, configured, canEnableByMergeRequest } = this.feature; + return canEnableByMergeRequest && available && !configured; + }, + cardClasses() { + return { 'gl-bg-gray-10': !this.available }; + }, + statusClasses() { + const { enabled } = this; + + return { + 'gl-ml-auto': true, + 'gl-flex-shrink-0': true, + 'gl-text-gray-500': !enabled, + 'gl-text-green-500': enabled, + }; + }, + hasSecondary() { + const { name, description, configurationText } = this.feature.secondary ?? {}; + return Boolean(name && description && configurationText); + }, + }, + i18n: { + enabled: s__('SecurityConfiguration|Enabled'), + notEnabled: s__('SecurityConfiguration|Not enabled'), + availableWith: s__('SecurityConfiguration|Available with Ultimate'), + configurationGuide: s__('SecurityConfiguration|Configuration guide'), + configureFeature: s__('SecurityConfiguration|Configure %{feature}'), + enableFeature: s__('SecurityConfiguration|Enable %{feature}'), + learnMore: __('Learn more'), + }, +}; +</script> + +<template> + <gl-card :class="cardClasses"> + <div class="gl-display-flex gl-align-items-baseline"> + <h3 class="gl-font-lg gl-m-0 gl-mr-3">{{ feature.name }}</h3> + + <div :class="statusClasses" data-testid="feature-status"> + <template v-if="hasStatus"> + <template v-if="enabled"> + <gl-icon name="check-circle-filled" /> + <span class="gl-text-green-700">{{ $options.i18n.enabled }}</span> + </template> + + <template v-else-if="available"> + {{ $options.i18n.notEnabled }} + </template> + + <template v-else> + {{ $options.i18n.availableWith }} + </template> + </template> + </div> + </div> + + <p class="gl-mb-0 gl-mt-5"> + {{ feature.description }} + <gl-link :href="feature.helpPath">{{ $options.i18n.learnMore }}</gl-link> + </p> + + <template v-if="available"> + <gl-button + v-if="feature.configurationPath" + :href="feature.configurationPath" + variant="confirm" + :category="configurationButton.category" + class="gl-mt-5" + > + {{ configurationButton.text }} + </gl-button> + + <manage-via-mr + v-else-if="showManageViaMr" + :feature="feature" + variant="confirm" + category="primary" + class="gl-mt-5" + /> + + <gl-button v-else icon="external-link" :href="feature.configurationHelpPath" class="gl-mt-5"> + {{ $options.i18n.configurationGuide }} + </gl-button> + </template> + + <div v-if="hasSecondary" data-testid="secondary-feature"> + <h4 class="gl-font-base gl-m-0 gl-mt-6">{{ feature.secondary.name }}</h4> + + <p class="gl-mb-0 gl-mt-5">{{ feature.secondary.description }}</p> + + <gl-button + v-if="available && feature.secondary.configurationPath" + :href="feature.secondary.configurationPath" + variant="confirm" + category="secondary" + class="gl-mt-5" + > + {{ feature.secondary.configurationText }} + </gl-button> + </div> + </gl-card> +</template> diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue index 75831643f6a..0cd280c42d2 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue @@ -169,6 +169,7 @@ export default { role="button" href="#" class="btn btn-sm btn-default js-cancel-auto-merge" + data-qa-selector="cancel_auto_merge_button" data-testid="cancelAutomaticMergeButton" @click.prevent="cancelAutomaticMerge" > |