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>2023-02-28 21:08:32 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-02-28 21:08:32 +0300
commit36eff6e5089629619cc55f4771fa949d6ae2b29b (patch)
tree6381b0c90f403c535abdde2f712cd346a78770fe /app/assets/javascripts
parentbaed745d21710f1d78ece03558873acd6fd7d358 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts')
-rw-r--r--app/assets/javascripts/behaviors/copy_to_clipboard.js4
-rw-r--r--app/assets/javascripts/ci/runner/admin_register_runner/admin_register_runner_app.vue81
-rw-r--r--app/assets/javascripts/ci/runner/admin_register_runner/index.js33
-rw-r--r--app/assets/javascripts/ci/runner/components/registration/cli_command.vue42
-rw-r--r--app/assets/javascripts/ci/runner/components/registration/registration_instructions.vue142
-rw-r--r--app/assets/javascripts/ci/runner/components/registration/utils.js43
-rw-r--r--app/assets/javascripts/ci/runner/constants.js4
-rw-r--r--app/assets/javascripts/ci/runner/graphql/register/runner_for_registration.query.graphql7
-rw-r--r--app/assets/javascripts/issues/related_merge_requests/components/related_merge_requests.vue6
-rw-r--r--app/assets/javascripts/related_issues/components/related_issues_block.vue2
-rw-r--r--app/assets/javascripts/super_sidebar/components/help_center.vue2
-rw-r--r--app/assets/javascripts/super_sidebar/components/user_menu.vue99
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue6
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/widget/widget.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/upload_dropzone/upload_dropzone.vue2
-rw-r--r--app/assets/javascripts/work_items/components/widget_wrapper.vue2
16 files changed, 451 insertions, 26 deletions
diff --git a/app/assets/javascripts/behaviors/copy_to_clipboard.js b/app/assets/javascripts/behaviors/copy_to_clipboard.js
index 4b337dce8f3..834defe336b 100644
--- a/app/assets/javascripts/behaviors/copy_to_clipboard.js
+++ b/app/assets/javascripts/behaviors/copy_to_clipboard.js
@@ -10,10 +10,10 @@ const CLIPBOARD_ERROR_EVENT = 'clipboard-error';
const I18N_ERROR_MESSAGE = __('Copy failed. Please manually copy the value.');
function showTooltip(target, title) {
- const { title: originalTitle } = target.dataset;
+ const { originalTitle } = target.dataset;
once('hidden', (tooltip) => {
- if (tooltip.target === target) {
+ if (originalTitle && tooltip.target === target) {
target.setAttribute('title', originalTitle);
target.setAttribute('aria-label', originalTitle);
fixTitle(target);
diff --git a/app/assets/javascripts/ci/runner/admin_register_runner/admin_register_runner_app.vue b/app/assets/javascripts/ci/runner/admin_register_runner/admin_register_runner_app.vue
new file mode 100644
index 00000000000..b291be41203
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/admin_register_runner/admin_register_runner_app.vue
@@ -0,0 +1,81 @@
+<script>
+import { GlButton } from '@gitlab/ui';
+import { s__, sprintf } from '~/locale';
+import { createAlert } from '~/flash';
+import { getParameterByName } from '~/lib/utils/url_utility';
+import { convertToGraphQLId } from '~/graphql_shared/utils';
+import { TYPENAME_CI_RUNNER } from '~/graphql_shared/constants';
+import runnerForRegistrationQuery from '../graphql/register/runner_for_registration.query.graphql';
+import { I18N_FETCH_ERROR, PARAM_KEY_PLATFORM, DEFAULT_PLATFORM } from '../constants';
+import RegistrationInstructions from '../components/registration/registration_instructions.vue';
+import { captureException } from '../sentry_utils';
+
+export default {
+ name: 'AdminRegisterRunnerApp',
+ components: {
+ GlButton,
+ RegistrationInstructions,
+ },
+ props: {
+ runnerId: {
+ type: String,
+ required: true,
+ },
+ runnersPath: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ platform: getParameterByName(PARAM_KEY_PLATFORM) || DEFAULT_PLATFORM,
+ runner: null,
+ };
+ },
+ apollo: {
+ runner: {
+ query: runnerForRegistrationQuery,
+ variables() {
+ return {
+ id: convertToGraphQLId(TYPENAME_CI_RUNNER, this.runnerId),
+ };
+ },
+ error(error) {
+ createAlert({ message: I18N_FETCH_ERROR });
+ captureException({ error, component: this.$options.name });
+ },
+ },
+ },
+ computed: {
+ description() {
+ return this.runner?.description;
+ },
+ heading() {
+ if (this.description) {
+ return sprintf(s__('Runners|Register "%{runnerDescription}" runner'), {
+ runnerDescription: this.description,
+ });
+ }
+ return s__('Runners|Register runner');
+ },
+ ephemeralAuthenticationToken() {
+ return this.runner?.ephemeralAuthenticationToken;
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <h1 class="gl-font-size-h1">{{ heading }}</h1>
+
+ <registration-instructions
+ :loading="$apollo.queries.runner.loading"
+ :platform="platform"
+ :token="ephemeralAuthenticationToken"
+ />
+
+ <gl-button :href="runnersPath" variant="confirm">{{
+ s__('Runners|Go to runners page')
+ }}</gl-button>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/runner/admin_register_runner/index.js b/app/assets/javascripts/ci/runner/admin_register_runner/index.js
index edb2ec65e98..bd43a5e8ce9 100644
--- a/app/assets/javascripts/ci/runner/admin_register_runner/index.js
+++ b/app/assets/javascripts/ci/runner/admin_register_runner/index.js
@@ -1,5 +1,36 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createDefaultClient from '~/lib/graphql';
import { showAlertFromLocalStorage } from '../local_storage_alert/show_alert_from_local_storage';
+import AdminRegisterRunnerApp from './admin_register_runner_app.vue';
-export const initAdminRegisterRunner = () => {
+Vue.use(VueApollo);
+
+export const initAdminRegisterRunner = (selector = '#js-admin-register-runner') => {
showAlertFromLocalStorage();
+
+ const el = document.querySelector(selector);
+
+ if (!el) {
+ return null;
+ }
+
+ const { runnerId, runnersPath } = el.dataset;
+
+ const apolloProvider = new VueApollo({
+ defaultClient: createDefaultClient(),
+ });
+
+ return new Vue({
+ el,
+ apolloProvider,
+ render(h) {
+ return h(AdminRegisterRunnerApp, {
+ props: {
+ runnerId,
+ runnersPath,
+ },
+ });
+ },
+ });
};
diff --git a/app/assets/javascripts/ci/runner/components/registration/cli_command.vue b/app/assets/javascripts/ci/runner/components/registration/cli_command.vue
new file mode 100644
index 00000000000..95b135c83a7
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/registration/cli_command.vue
@@ -0,0 +1,42 @@
+<script>
+import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
+
+export default {
+ components: {
+ ClipboardButton,
+ },
+ props: {
+ prompt: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ command: {
+ type: [Array, String],
+ required: false,
+ default: '',
+ },
+ },
+ computed: {
+ lines() {
+ if (typeof this.command === 'string') {
+ return [this.command];
+ }
+ return this.command;
+ },
+ clipboard() {
+ return this.lines.join('');
+ },
+ },
+};
+</script>
+<template>
+ <div class="gl-display-flex gl-gap-3 gl-align-items-flex-start">
+ <!-- eslint-disable vue/require-v-for-key-->
+ <pre
+ class="gl-w-full"
+ ><span v-if="prompt" class="gl-user-select-none">{{ prompt }} </span><template v-for="line in lines">{{ line }}<br class="gl-user-select-none"/></template></pre>
+ <!-- eslint-enable vue/require-v-for-key-->
+ <clipboard-button :text="clipboard" :title="__('Copy')" />
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/runner/components/registration/registration_instructions.vue b/app/assets/javascripts/ci/runner/components/registration/registration_instructions.vue
new file mode 100644
index 00000000000..e01d8b64839
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/registration/registration_instructions.vue
@@ -0,0 +1,142 @@
+<script>
+import { GlIcon, GlLink, GlSprintf, GlSkeletonLoader } from '@gitlab/ui';
+import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
+
+import { INSTALL_HELP_URL, EXECUTORS_HELP_URL, SERVICE_COMMANDS_HELP_URL } from '../../constants';
+import CliCommand from './cli_command.vue';
+import { commandPrompt, registerCommand, runCommand } from './utils';
+
+export default {
+ components: {
+ GlIcon,
+ GlLink,
+ GlSkeletonLoader,
+ GlSprintf,
+ ClipboardButton,
+ CliCommand,
+ },
+ props: {
+ platform: {
+ type: String,
+ required: true,
+ },
+ loading: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ token: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ },
+ computed: {
+ commandPrompt() {
+ return commandPrompt({ platform: this.platform });
+ },
+ registerCommand() {
+ return registerCommand({ platform: this.platform, registrationToken: this.token });
+ },
+ runCommand() {
+ return runCommand({ platform: this.platform });
+ },
+ },
+ INSTALL_HELP_URL,
+ EXECUTORS_HELP_URL,
+ SERVICE_COMMANDS_HELP_URL,
+};
+</script>
+<template>
+ <div>
+ <p>
+ <gl-sprintf
+ :message="
+ s__(
+ 'Runners|GitLab Runner must be installed before you can register a runner. %{linkStart}How do I install GitLab Runner?%{linkEnd}',
+ )
+ "
+ >
+ <template #link="{ content }">
+ <gl-link :href="$options.INSTALL_HELP_URL">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
+
+ <section>
+ <h2 class="gl-font-size-h2">{{ s__('Runners|Step 1') }}</h2>
+ <p>
+ {{
+ s__(
+ 'Runners|Copy and paste the following command into your command line to register the runner.',
+ )
+ }}
+ </p>
+ <gl-skeleton-loader v-if="loading" />
+ <template v-else>
+ <cli-command :prompt="commandPrompt" :command="registerCommand" />
+ <p>
+ <gl-icon name="information-o" class="gl-text-blue-600!" />
+ <gl-sprintf
+ :message="
+ s__(
+ 'Runners|The %{boldStart}runner token%{boldEnd} %{token} displays %{boldStart}only for a short time%{boldEnd}, and is stored in the %{codeStart}config.toml%{codeEnd} after you create the runner. It will not be visible once the runner is registered.',
+ )
+ "
+ >
+ <template #token>
+ <code>{{ token }}</code>
+ <clipboard-button
+ :text="token"
+ :title="__('Copy')"
+ size="small"
+ category="tertiary"
+ class="gl-border-none!"
+ />
+ </template>
+ <template #bold="{ content }"
+ ><span class="gl-font-weight-bold">{{ content }}</span></template
+ >
+ <template #code="{ content }"
+ ><code>{{ content }}</code></template
+ >
+ </gl-sprintf>
+ </p>
+ </template>
+ </section>
+ <section>
+ <h2 class="gl-font-size-h2">{{ s__('Runners|Step 2') }}</h2>
+ <p>
+ <gl-sprintf
+ :message="
+ s__(
+ 'Runners|Choose an executor when prompted by the command line. Executors run builds in different environments. %{linkStart}Not sure which one to select?%{linkEnd}',
+ )
+ "
+ >
+ <template #link="{ content }">
+ <gl-link :href="$options.EXECUTORS_HELP_URL">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
+ </section>
+ <section>
+ <h2 class="gl-font-size-h2">{{ s__('Runners|Optional. Step 3') }}</h2>
+ <p>{{ s__('Runners|Manually verify that the runner is available to pick up jobs.') }}</p>
+ <cli-command :prompt="commandPrompt" :command="runCommand" />
+ <p>
+ <gl-sprintf
+ :message="
+ s__(
+ 'Runners|This may not be needed if you manage your runner as a %{linkStart}system or user service%{linkEnd}.',
+ )
+ "
+ >
+ <template #link="{ content }">
+ <gl-link :href="$options.SERVICE_COMMANDS_HELP_URL">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
+ </section>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/runner/components/registration/utils.js b/app/assets/javascripts/ci/runner/components/registration/utils.js
new file mode 100644
index 00000000000..32fb8eac5e9
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/registration/utils.js
@@ -0,0 +1,43 @@
+import {
+ DEFAULT_PLATFORM,
+ LINUX_PLATFORM,
+ MACOS_PLATFORM,
+ WINDOWS_PLATFORM,
+} from '../../constants';
+
+/* eslint-disable @gitlab/require-i18n-strings */
+const OS = {
+ [LINUX_PLATFORM]: {
+ commandPrompt: '$',
+ executable: 'gitlab-runner',
+ },
+ [MACOS_PLATFORM]: {
+ commandPrompt: '$',
+ executable: 'gitlab-runner',
+ },
+ [WINDOWS_PLATFORM]: {
+ commandPrompt: '>',
+ executable: '.\\gitlab-runner.exe',
+ },
+};
+
+export const commandPrompt = ({ platform }) => {
+ return (OS[platform] || OS[DEFAULT_PLATFORM]).commandPrompt;
+};
+
+export const executable = ({ platform }) => {
+ return (OS[platform] || OS[DEFAULT_PLATFORM]).executable;
+};
+
+export const registerCommand = ({ platform, url = gon.gitlab_url, registrationToken }) => {
+ return [
+ `${executable({ platform })} register`,
+ ` --url ${url}`,
+ ` --registration-token ${registrationToken}`,
+ ];
+};
+
+export const runCommand = ({ platform }) => {
+ return `${executable({ platform })} run`;
+};
+/* eslint-enable @gitlab/require-i18n-strings */
diff --git a/app/assets/javascripts/ci/runner/constants.js b/app/assets/javascripts/ci/runner/constants.js
index 27c02420036..1db4ff68872 100644
--- a/app/assets/javascripts/ci/runner/constants.js
+++ b/app/assets/javascripts/ci/runner/constants.js
@@ -188,5 +188,9 @@ export const DEFAULT_PLATFORM = LINUX_PLATFORM;
// Runner docs are in a separate repository and are not shipped with GitLab
// they are rendered as external URLs.
+export const INSTALL_HELP_URL = 'https://docs.gitlab.com/runner/install';
+export const EXECUTORS_HELP_URL = 'https://docs.gitlab.com/runner/executors/';
+export const SERVICE_COMMANDS_HELP_URL =
+ 'https://docs.gitlab.com/runner/commands/#service-related-commands';
export const DOCKER_HELP_URL = 'https://docs.gitlab.com/runner/install/docker.html';
export const KUBERNETES_HELP_URL = 'https://docs.gitlab.com/runner/install/kubernetes.html';
diff --git a/app/assets/javascripts/ci/runner/graphql/register/runner_for_registration.query.graphql b/app/assets/javascripts/ci/runner/graphql/register/runner_for_registration.query.graphql
new file mode 100644
index 00000000000..a26d43c3729
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/graphql/register/runner_for_registration.query.graphql
@@ -0,0 +1,7 @@
+query getRunnerForRegistration($id: CiRunnerID!) {
+ runner(id: $id) {
+ id
+ description
+ ephemeralAuthenticationToken
+ }
+}
diff --git a/app/assets/javascripts/issues/related_merge_requests/components/related_merge_requests.vue b/app/assets/javascripts/issues/related_merge_requests/components/related_merge_requests.vue
index 149049247fb..accf4e77043 100644
--- a/app/assets/javascripts/issues/related_merge_requests/components/related_merge_requests.vue
+++ b/app/assets/javascripts/issues/related_merge_requests/components/related_merge_requests.vue
@@ -66,7 +66,7 @@ export default {
<template>
<div v-if="isFetchingMergeRequests || (!isFetchingMergeRequests && totalCount)">
<div class="card card-slim gl-mt-5 gl-mb-0">
- <div class="card-header gl-bg-gray-10">
+ <div class="card-header gl-px-5 gl-py-4 gl-bg-white">
<div
class="card-title gl-relative gl-display-flex gl-align-items-center gl-line-height-20 gl-font-weight-bold gl-m-0"
>
@@ -79,7 +79,7 @@ export default {
{{ __('Related merge requests') }}
</h3>
<template v-if="totalCount">
- <gl-icon name="merge-request" class="gl-ml-5 gl-mr-2 gl-text-gray-500" />
+ <gl-icon name="merge-request" class="gl-ml-3 gl-mr-2 gl-text-gray-500" />
<span data-testid="count">{{ totalCount }}</span>
</template>
</div>
@@ -90,7 +90,7 @@ export default {
label="Fetching related merge requests"
class="gl-py-3"
/>
- <ul v-else class="content-list related-items-list">
+ <ul v-else class="content-list related-items-list gl-bg-gray-10">
<li v-for="mr in mergeRequests" :key="mr.id" class="list-item gl-m-0! gl-p-0!">
<related-issuable-item
:id-key="mr.id"
diff --git a/app/assets/javascripts/related_issues/components/related_issues_block.vue b/app/assets/javascripts/related_issues/components/related_issues_block.vue
index 4a130ade631..4aebaa86932 100644
--- a/app/assets/javascripts/related_issues/components/related_issues_block.vue
+++ b/app/assets/javascripts/related_issues/components/related_issues_block.vue
@@ -187,7 +187,7 @@ export default {
'gl-border-b-1': isOpen,
'gl-border-b-0': !isOpen,
}"
- class="gl-display-flex gl-justify-content-space-between gl-line-height-24 gl-py-3 gl-px-5 gl-bg-gray-10 gl-border-b-solid gl-border-b-gray-100"
+ class="gl-display-flex gl-justify-content-space-between gl-line-height-24 gl-pl-5 gl-pr-4 gl-py-4 gl-bg-white gl-border-b-solid gl-border-b-gray-100"
>
<h3 class="card-title h5 gl-my-0 gl-display-flex gl-align-items-center gl-flex-grow-1">
<gl-link
diff --git a/app/assets/javascripts/super_sidebar/components/help_center.vue b/app/assets/javascripts/super_sidebar/components/help_center.vue
index 5e24f20f40a..fb23a4f2deb 100644
--- a/app/assets/javascripts/super_sidebar/components/help_center.vue
+++ b/app/assets/javascripts/super_sidebar/components/help_center.vue
@@ -126,7 +126,7 @@ export default {
<gl-disclosure-dropdown ref="dropdown">
<template #toggle>
<gl-button category="tertiary" icon="question-o" class="btn-with-notification">
- <span v-if="showWhatsNewNotification" class="notification"></span>
+ <span v-if="showWhatsNewNotification" class="notification-dot-info"></span>
{{ $options.i18n.help }}
</gl-button>
</template>
diff --git a/app/assets/javascripts/super_sidebar/components/user_menu.vue b/app/assets/javascripts/super_sidebar/components/user_menu.vue
index 7700b7fa3f8..103501e86ef 100644
--- a/app/assets/javascripts/super_sidebar/components/user_menu.vue
+++ b/app/assets/javascripts/super_sidebar/components/user_menu.vue
@@ -9,6 +9,8 @@ import {
import SafeHtml from '~/vue_shared/directives/safe_html';
import { s__, __, sprintf } from '~/locale';
import NewNavToggle from '~/nav/components/new_nav_toggle.vue';
+import Tracking from '~/tracking';
+import PersistentUserCallout from '~/persistent_user_callout';
import UserNameGroup from './user_name_group.vue';
export default {
@@ -18,13 +20,13 @@ export default {
badgeLabel: s__('NorthstarNavigation|Alpha'),
sectionTitle: s__('NorthstarNavigation|Navigation redesign'),
},
- user: {
- setStatus: s__('SetStatusModal|Set status'),
- editStatus: s__('SetStatusModal|Edit status'),
- editProfile: s__('CurrentUser|Edit profile'),
- preferences: s__('CurrentUser|Preferences'),
- gitlabNext: s__('CurrentUser|Switch to GitLab Next'),
- },
+ setStatus: s__('SetStatusModal|Set status'),
+ editStatus: s__('SetStatusModal|Edit status'),
+ editProfile: s__('CurrentUser|Edit profile'),
+ preferences: s__('CurrentUser|Preferences'),
+ buyPipelineMinutes: s__('CurrentUser|Buy Pipeline minutes'),
+ oneOfGroupsRunningOutOfPipelineMinutes: s__('CurrentUser|One of your groups is running out'),
+ gitlabNext: s__('CurrentUser|Switch to GitLab Next'),
provideFeedback: s__('NorthstarNavigation|Provide feedback'),
startTrial: s__('CurrentUser|Start an Ultimate trial'),
signOut: __('Sign out'),
@@ -41,6 +43,7 @@ export default {
directives: {
SafeHtml,
},
+ mixins: [Tracking.mixin()],
inject: ['toggleNewNavEndpoint'],
props: {
data: {
@@ -56,7 +59,7 @@ export default {
const { busy, customized } = this.data.status;
const statusLabel =
- busy || customized ? this.$options.i18n.user.editStatus : this.$options.i18n.user.setStatus;
+ busy || customized ? this.$options.i18n.editStatus : this.$options.i18n.setStatus;
return {
text: statusLabel,
@@ -73,19 +76,32 @@ export default {
},
editProfileItem() {
return {
- text: this.$options.i18n.user.editProfile,
+ text: this.$options.i18n.editProfile,
href: this.data.settings.profile_path,
};
},
preferencesItem() {
return {
- text: this.$options.i18n.user.preferences,
+ text: this.$options.i18n.preferences,
href: this.data.settings.profile_preferences_path,
};
},
+ addBuyPipelineMinutesMenuItem() {
+ return this.data.pipeline_minutes?.show_buy_pipeline_minutes;
+ },
+ buyPipelineMinutesItem() {
+ return {
+ text: this.$options.i18n.buyPipelineMinutes,
+ warningText: this.$options.i18n.oneOfGroupsRunningOutOfPipelineMinutes,
+ href: this.data.pipeline_minutes?.buy_pipeline_minutes_path,
+ extraAttrs: {
+ class: 'js-follow-link',
+ },
+ };
+ },
gitlabNextItem() {
return {
- text: this.$options.i18n.user.gitlabNext,
+ text: this.$options.i18n.gitlabNext,
href: this.data.canary_toggle_com_url,
};
},
@@ -130,6 +146,38 @@ export default {
'data-current-clear-status-after': this.data.status.clear_after,
};
},
+ buyPipelineMinutesCalloutData() {
+ return this.showNotificationDot
+ ? {
+ 'data-feature-id': this.data.pipeline_minutes.callout_attrs.feature_id,
+ 'data-dismiss-endpoint': this.data.pipeline_minutes.callout_attrs.dismiss_endpoint,
+ }
+ : {};
+ },
+ showNotificationDot() {
+ return this.data.pipeline_minutes?.show_notification_dot;
+ },
+ },
+ methods: {
+ onShow() {
+ this.trackEvents();
+ this.initCallout();
+ },
+ initCallout() {
+ if (this.showNotificationDot) {
+ PersistentUserCallout.factory(this.$refs?.buyPipelineMinutesNotificationCallout.$el);
+ }
+ },
+ trackEvents() {
+ if (this.addBuyPipelineMinutesMenuItem) {
+ const {
+ 'track-action': trackAction,
+ 'track-label': label,
+ 'track-property': property,
+ } = this.data.pipeline_minutes.tracking_attrs;
+ this.track(trackAction, { label, property });
+ }
+ },
},
};
</script>
@@ -140,9 +188,10 @@ export default {
placement="right"
data-testid="user-dropdown"
data-qa-selector="user_menu"
+ @shown="onShow"
>
<template #toggle>
- <button class="user-bar-item">
+ <button class="user-bar-item btn-with-notification">
<span class="gl-sr-only">{{ toggleText }}</span>
<gl-avatar
:size="24"
@@ -151,6 +200,13 @@ export default {
aria-hidden="true"
data-qa-selector="user_avatar_content"
/>
+ <span
+ v-if="showNotificationDot"
+ class="notification-dot-warning"
+ data-testid="buy-pipeline-minutes-notification-dot"
+ v-bind="data.pipeline_minutes.notification_dot_attrs"
+ >
+ </span>
</button>
</template>
@@ -178,6 +234,25 @@ export default {
<gl-disclosure-dropdown-item :item="preferencesItem" data-testid="preferences-item" />
<gl-disclosure-dropdown-item
+ v-if="addBuyPipelineMinutesMenuItem"
+ ref="buyPipelineMinutesNotificationCallout"
+ :item="buyPipelineMinutesItem"
+ v-bind="buyPipelineMinutesCalloutData"
+ data-testid="buy-pipeline-minutes-item"
+ >
+ <template #list-item>
+ <span class="gl-display-flex gl-flex-direction-column">
+ <span>{{ buyPipelineMinutesItem.text }} <gl-emoji data-name="clock9" /></span>
+ <span
+ v-if="data.pipeline_minutes.show_with_subtext"
+ class="gl-font-sm small gl-pt-2 gl-text-orange-800"
+ >{{ buyPipelineMinutesItem.warningText }}</span
+ >
+ </span>
+ </template>
+ </gl-disclosure-dropdown-item>
+
+ <gl-disclosure-dropdown-item
v-if="data.gitlab_com_but_not_canary"
:item="gitlabNextItem"
data-testid="gitlab-next-item"
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue b/app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue
index b78293a9815..028f5370028 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/extensions/base.vue
@@ -313,7 +313,7 @@ export default {
:status="statusIconName"
:is-loading="isLoadingSummary"
:class="{ 'gl-cursor-pointer': isCollapsible }"
- class="gl-p-5"
+ class="gl-pl-5 gl-pr-4 gl-py-4"
@mousedown="onRowMouseDown"
@mouseup="onRowMouseUp"
>
@@ -381,7 +381,7 @@ export default {
v-else-if="hasFullData"
:items="fullData"
:min-item-size="32"
- class="report-block-container gl-px-5 gl-py-0"
+ class="report-block-container gl-p-0"
>
<template #default="{ item, index, active }">
<dynamic-scroller-item :item="item" :active="active" :class="{ active }">
@@ -389,7 +389,7 @@ export default {
:class="{
'gl-border-b-solid gl-border-b-1 gl-border-gray-100': index !== fullData.length - 1,
}"
- class="gl-py-3 gl-pl-7"
+ class="gl-py-3 gl-pl-9"
data-testid="extension-list-item"
>
<gl-intersection-observer
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/widget/widget.vue b/app/assets/javascripts/vue_merge_request_widget/components/widget/widget.vue
index 73129a86877..a754d4e80ea 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/widget/widget.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/widget/widget.vue
@@ -287,7 +287,7 @@ export default {
<template>
<section class="media-section" data-testid="widget-extension">
- <div class="gl-p-5 gl-align-items-center gl-display-flex">
+ <div class="gl-px-5 gl-py-4 gl-align-items-center gl-display-flex">
<status-icon
:level="1"
:name="widgetName"
diff --git a/app/assets/javascripts/vue_shared/components/upload_dropzone/upload_dropzone.vue b/app/assets/javascripts/vue_shared/components/upload_dropzone/upload_dropzone.vue
index a001b6bdf24..23fbf211d54 100644
--- a/app/assets/javascripts/vue_shared/components/upload_dropzone/upload_dropzone.vue
+++ b/app/assets/javascripts/vue_shared/components/upload_dropzone/upload_dropzone.vue
@@ -149,7 +149,7 @@ export default {
>
<slot>
<button
- class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-4 gl-mb-0"
+ class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-px-5 gl-py-4 gl-mb-0"
type="button"
@click="openFileUpload"
>
diff --git a/app/assets/javascripts/work_items/components/widget_wrapper.vue b/app/assets/javascripts/work_items/components/widget_wrapper.vue
index 355f17e970b..44c757f8f59 100644
--- a/app/assets/javascripts/work_items/components/widget_wrapper.vue
+++ b/app/assets/javascripts/work_items/components/widget_wrapper.vue
@@ -44,7 +44,7 @@ export default {
<template>
<div class="gl-rounded-base gl-border-1 gl-border-solid gl-border-gray-100 gl-bg-gray-10 gl-mt-4">
<div
- class="gl-px-5 gl-py-3 gl-display-flex gl-justify-content-space-between"
+ class="gl-pl-5 gl-pr-4 gl-py-4 gl-display-flex gl-justify-content-space-between gl-bg-white"
:class="{ 'gl-border-b-1 gl-border-b-solid gl-border-b-gray-100': isOpen }"
>
<div class="gl-display-flex gl-flex-grow-1">