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>2020-02-25 00:09:08 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-02-25 00:09:08 +0300
commit7671216b60e2796a050358ff808b4a0c2de3d22f (patch)
tree605dfc1339a3cd7dc7353ac6d725191086a9acca /app/assets
parentc2367afbf57ebc65d5b78a743b5d6a91f0aece9f (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets')
-rw-r--r--app/assets/javascripts/blob/pipeline_tour_success_modal.vue78
-rw-r--r--app/assets/javascripts/pages/projects/blob/show/index.js22
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_suggest_pipeline.vue68
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_tour.vue143
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js1
-rw-r--r--app/assets/stylesheets/framework/images.scss2
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss4
8 files changed, 300 insertions, 20 deletions
diff --git a/app/assets/javascripts/blob/pipeline_tour_success_modal.vue b/app/assets/javascripts/blob/pipeline_tour_success_modal.vue
new file mode 100644
index 00000000000..0739b4d5e39
--- /dev/null
+++ b/app/assets/javascripts/blob/pipeline_tour_success_modal.vue
@@ -0,0 +1,78 @@
+<script>
+import { GlModal, GlSprintf, GlLink } from '@gitlab/ui';
+import { sprintf, s__, __ } from '~/locale';
+import Cookies from 'js-cookie';
+import { glEmojiTag } from '~/emoji';
+
+export default {
+ beginnerLink:
+ 'https://about.gitlab.com/blog/2018/01/22/a-beginners-guide-to-continuous-integration/',
+ exampleLink: 'https://docs.gitlab.com/ee/ci/examples/',
+ bodyMessage: s__(
+ 'MR widget|The pipeline will now run automatically every time you commit code. Pipelines are useful for deploying static web pages, detecting vulnerabilities in dependencies, static or dynamic application security testing (SAST and DAST), and so much more!',
+ ),
+ modalTitle: sprintf(
+ __("That's it, well done!%{celebrate}"),
+ {
+ celebrate: glEmojiTag('tada'),
+ },
+ false,
+ ),
+ components: {
+ GlModal,
+ GlSprintf,
+ GlLink,
+ },
+ props: {
+ goToPipelinesPath: {
+ type: String,
+ required: true,
+ },
+ commitCookie: {
+ type: String,
+ required: true,
+ },
+ },
+ mounted() {
+ this.disableModalFromRenderingAgain();
+ },
+ methods: {
+ disableModalFromRenderingAgain() {
+ Cookies.remove(this.commitCookie);
+ },
+ },
+};
+</script>
+<template>
+ <gl-modal
+ visible
+ size="sm"
+ :title="$options.modalTitle"
+ modal-id="success-pipeline-modal-id-not-used"
+ >
+ <p>
+ {{ $options.bodyMessage }}
+ </p>
+ <gl-sprintf
+ :message="
+ s__(`MR widget|Take a look at our %{beginnerLinkStart}Beginner's Guide to Continuous Integration%{beginnerLinkEnd}
+ and our %{exampleLinkStart}examples of GitLab CI/CD%{exampleLinkEnd}
+ to see all the cool stuff you can do with it.`)
+ "
+ >
+ <template #beginnerLink="{content}">
+ <gl-link :href="$options.beginnerLink" target="_blank">
+ {{ content }}
+ </gl-link>
+ </template>
+ <template #exampleLink="{content}">
+ <gl-link :href="$options.exampleLink" target="_blank">
+ {{ content }}
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ <template #modal-footer>
+ <a :href="goToPipelinesPath" class="btn btn-success">{{ __('Go to Pipelines') }}</a>
+ </template>
+ </gl-modal>
+</template>
diff --git a/app/assets/javascripts/pages/projects/blob/show/index.js b/app/assets/javascripts/pages/projects/blob/show/index.js
index caf9a8c0b64..4d308d6b07a 100644
--- a/app/assets/javascripts/pages/projects/blob/show/index.js
+++ b/app/assets/javascripts/pages/projects/blob/show/index.js
@@ -4,6 +4,7 @@ import BlobViewer from '~/blob/viewer/index';
import initBlob from '~/pages/projects/init_blob';
import GpgBadges from '~/gpg_badges';
import '~/sourcegraph/load';
+import PipelineTourSuccessModal from '~/blob/pipeline_tour_success_modal.vue';
document.addEventListener('DOMContentLoaded', () => {
new BlobViewer(); // eslint-disable-line no-new
@@ -35,4 +36,25 @@ document.addEventListener('DOMContentLoaded', () => {
// eslint-disable-next-line promise/catch-or-return
import('~/code_navigation').then(m => m.default());
}
+
+ if (gon.features?.suggestPipeline) {
+ const successPipelineEl = document.querySelector('.js-success-pipeline-modal');
+
+ if (successPipelineEl) {
+ // eslint-disable-next-line no-new
+ new Vue({
+ el: successPipelineEl,
+ render(createElement) {
+ const { commitCookie, pipelinesPath: goToPipelinesPath } = this.$el.dataset;
+
+ return createElement(PipelineTourSuccessModal, {
+ props: {
+ goToPipelinesPath,
+ commitCookie,
+ },
+ });
+ },
+ });
+ }
+ }
});
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_suggest_pipeline.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_suggest_pipeline.vue
index f08bfb3a90f..9942861d9e4 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_suggest_pipeline.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_suggest_pipeline.vue
@@ -1,45 +1,75 @@
<script>
import { GlLink, GlSprintf } from '@gitlab/ui';
import MrWidgetIcon from './mr_widget_icon.vue';
+import PipelineTourState from './states/mr_widget_pipeline_tour.vue';
export default {
name: 'MRWidgetSuggestPipeline',
iconName: 'status_notfound',
+ popoverTarget: 'suggest-popover',
+ popoverContainer: 'suggest-pipeline',
+ trackLabel: 'no_pipeline_noticed',
+ linkTrackValue: 30,
+ linkTrackEvent: 'click_link',
components: {
GlLink,
GlSprintf,
MrWidgetIcon,
+ PipelineTourState,
},
props: {
pipelinePath: {
type: String,
required: true,
},
+ pipelineSvgPath: {
+ type: String,
+ required: true,
+ },
+ humanAccess: {
+ type: String,
+ required: true,
+ },
},
};
</script>
<template>
- <div class="d-flex mr-pipeline-suggest append-bottom-default">
+ <div :id="$options.popoverContainer" class="d-flex mr-pipeline-suggest append-bottom-default">
<mr-widget-icon :name="$options.iconName" />
- <gl-sprintf
- class="js-no-pipeline-message"
- :message="
- s__(`mrWidget|%{prefixToLinkStart}No pipeline%{prefixToLinkEnd}
+ <div :id="$options.popoverTarget">
+ <gl-sprintf
+ :message="
+ s__(`mrWidget|%{prefixToLinkStart}No pipeline%{prefixToLinkEnd}
%{addPipelineLinkStart}Add the .gitlab-ci.yml file%{addPipelineLinkEnd}
to create one.`)
- "
- >
- <template #prefixToLink="{content}">
- <strong>
- {{ content }}
- </strong>
- </template>
- <template #addPipelineLink="{content}">
- <gl-link :href="pipelinePath" class="ml-2">
- {{ content }}
- </gl-link>
- &nbsp;
- </template>
- </gl-sprintf>
+ "
+ >
+ <template #prefixToLink="{content}">
+ <strong>
+ {{ content }}
+ </strong>
+ </template>
+ <template #addPipelineLink="{content}">
+ <gl-link
+ :href="pipelinePath"
+ class="ml-2 js-add-pipeline-path"
+ :data-track-property="humanAccess"
+ :data-track-value="$options.linkTrackValue"
+ :data-track-event="$options.linkTrackEvent"
+ :data-track-label="$options.trackLabel"
+ >
+ {{ content }}
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ <pipeline-tour-state
+ :pipeline-path="pipelinePath"
+ :pipeline-svg-path="pipelineSvgPath"
+ :human-access="humanAccess"
+ :popover-target="$options.popoverTarget"
+ :popover-container="$options.popoverContainer"
+ :track-label="$options.trackLabel"
+ />
+ </div>
</div>
</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_tour.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_tour.vue
new file mode 100644
index 00000000000..f2d7e86a85e
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_tour.vue
@@ -0,0 +1,143 @@
+<script>
+import { s__, sprintf } from '~/locale';
+import { GlPopover, GlButton } from '@gitlab/ui';
+import Icon from '~/vue_shared/components/icon.vue';
+import Cookies from 'js-cookie';
+import { parseBoolean } from '~/lib/utils/common_utils';
+import Tracking from '~/tracking';
+
+const trackingMixin = Tracking.mixin();
+
+const cookieKey = 'suggest_pipeline_dismissed';
+
+export default {
+ name: 'MRWidgetPipelineTour',
+ dismissTrackValue: 20,
+ showTrackValue: 10,
+ trackEvent: 'click_button',
+ popoverContent: sprintf(
+ '%{messageText1}%{lineBreak}%{messageText2}%{lineBreak}%{messageText3}%{lineBreak}%{messageText4}%{lineBreak}%{messageText5}',
+ {
+ messageText1: s__('mrWidget|Detect issues before deployment with a CI pipeline'),
+ messageText2: s__('mrWidget|that continuously tests your code. We created'),
+ messageText3: s__("mrWidget|a quick guide that'll show you how to create"),
+ messageText4: s__('mrWidget|one. Make your code more secure and more'),
+ messageText5: s__('mrWidget|robust in just a minute.'),
+ lineBreak: '<br/>',
+ },
+ false,
+ ),
+ components: {
+ GlPopover,
+ GlButton,
+ Icon,
+ },
+ mixins: [trackingMixin],
+ props: {
+ pipelinePath: {
+ type: String,
+ required: true,
+ },
+ pipelineSvgPath: {
+ type: String,
+ required: true,
+ },
+ humanAccess: {
+ type: String,
+ required: true,
+ },
+ popoverTarget: {
+ type: String,
+ required: true,
+ },
+ popoverContainer: {
+ type: String,
+ required: true,
+ },
+ trackLabel: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ popoverDismissed: parseBoolean(Cookies.get(cookieKey)),
+ tracking: {
+ label: this.trackLabel,
+ property: this.humanAccess,
+ },
+ };
+ },
+ mounted() {
+ this.trackOnShow();
+ },
+ methods: {
+ trackOnShow() {
+ if (!this.popoverDismissed) {
+ this.track();
+ }
+ },
+ dismissPopover() {
+ this.popoverDismissed = true;
+ Cookies.set(cookieKey, this.popoverDismissed, { expires: 365 });
+ },
+ },
+};
+</script>
+<template>
+ <gl-popover
+ v-if="!popoverDismissed"
+ show
+ :target="popoverTarget"
+ :container="popoverContainer"
+ placement="rightbottom"
+ >
+ <template #title>
+ <button
+ class="btn-blank float-right mt-1"
+ type="button"
+ :aria-label="__('Close')"
+ :data-track-property="humanAccess"
+ :data-track-value="$options.dismissTrackValue"
+ :data-track-event="$options.trackEvent"
+ :data-track-label="trackLabel"
+ @click="dismissPopover"
+ >
+ <icon name="close" aria-hidden="true" />
+ </button>
+ {{ s__('mrWidget|Are you adding technical debt or code vulnerabilities?') }}
+ </template>
+ <div class="svg-content svg-150 pt-1">
+ <img :src="pipelineSvgPath" />
+ </div>
+ <p v-html="$options.popoverContent"></p>
+ <gl-button
+ ref="ok"
+ category="primary"
+ class="mt-2 mb-0"
+ variant="info"
+ block
+ :href="pipelinePath"
+ :data-track-property="humanAccess"
+ :data-track-value="$options.showTrackValue"
+ :data-track-event="$options.trackEvent"
+ :data-track-label="trackLabel"
+ >
+ {{ __('Show me how') }}
+ </gl-button>
+ <gl-button
+ ref="no-thanks"
+ category="secondary"
+ class="mt-2 mb-0"
+ variant="info"
+ block
+ :data-track-property="humanAccess"
+ :data-track-value="$options.dismissTrackValue"
+ :data-track-event="$options.trackEvent"
+ :data-track-label="trackLabel"
+ @click="dismissPopover"
+ >
+ {{ __("No thanks, don't show this again") }}
+ </gl-button>
+ </gl-popover>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
index 27f13ace779..c8d69143f8d 100644
--- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
@@ -362,6 +362,8 @@ export default {
v-if="shouldSuggestPipelines"
class="mr-widget-workflow"
:pipeline-path="mr.mergeRequestAddCiConfigPath"
+ :pipeline-svg-path="mr.pipelinesEmptySvgPath"
+ :human-access="mr.humanAccess.toLowerCase()"
/>
<mr-widget-pipeline-container
v-if="shouldRenderPipelines"
diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
index 73a0b3cb673..ea83c61e275 100644
--- a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
+++ b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
@@ -176,6 +176,7 @@ export default class MergeRequestStore {
this.eligibleApproversDocsPath = data.eligible_approvers_docs_path;
this.mergeImmediatelyDocsPath = data.merge_immediately_docs_path;
this.mergeRequestAddCiConfigPath = data.merge_request_add_ci_config_path;
+ this.pipelinesEmptySvgPath = data.pipelines_empty_svg_path;
this.humanAccess = data.human_access;
}
diff --git a/app/assets/stylesheets/framework/images.scss b/app/assets/stylesheets/framework/images.scss
index d78c707192f..2c9397d363c 100644
--- a/app/assets/stylesheets/framework/images.scss
+++ b/app/assets/stylesheets/framework/images.scss
@@ -20,7 +20,7 @@
width: 100%;
}
- $image-widths: 80 130 250 306 394 430;
+ $image-widths: 80 130 150 250 306 394 430;
@each $width in $image-widths {
&.svg-#{$width} {
img,
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index 5ca75c28ac3..ad8b251d3e4 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -614,6 +614,10 @@ $mr-widget-min-height: 69px;
.circle-icon-container {
color: $gl-text-color-quaternary;
}
+
+ .popover {
+ z-index: 240;
+ }
}
.card-new-merge-request {