diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-08-06 15:10:15 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-08-06 15:10:15 +0300 |
commit | 14b5bf2629cf6cd77fe9bb6108d4a6dc0963f6c1 (patch) | |
tree | 90544438a276b7cd3c9b24ab92f46927ef768185 /app | |
parent | ff490fb7dfd0f4fedbd45b9079fcfa13ade3144c (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
22 files changed, 260 insertions, 395 deletions
diff --git a/app/views/shared/icons/_dev_ops_report_overview.svg b/app/assets/images/dev_ops_report_overview.svg index 2f31113bad7..2f31113bad7 100644 --- a/app/views/shared/icons/_dev_ops_report_overview.svg +++ b/app/assets/images/dev_ops_report_overview.svg diff --git a/app/assets/javascripts/analytics/devops_report/components/devops_score.vue b/app/assets/javascripts/analytics/devops_report/components/devops_score.vue index 1a3289ffb75..be38b32c119 100644 --- a/app/assets/javascripts/analytics/devops_report/components/devops_score.vue +++ b/app/assets/javascripts/analytics/devops_report/components/devops_score.vue @@ -2,6 +2,7 @@ import { GlBadge, GlTable, GlLink, GlEmptyState } from '@gitlab/ui'; import { GlSingleStat } from '@gitlab/ui/dist/charts'; import { sprintf, s__ } from '~/locale'; +import DevopsScoreCallout from './devops_score_callout.vue'; const defaultHeaderAttrs = { thClass: 'gl-bg-white!', @@ -15,6 +16,7 @@ export default { GlSingleStat, GlLink, GlEmptyState, + DevopsScoreCallout, }, inject: { devopsScoreMetrics: { @@ -65,46 +67,49 @@ export default { }; </script> <template> - <gl-empty-state - v-if="isEmpty" - :title="__('Data is still calculating...')" - :svg-path="noDataImagePath" - > - <template #description> - <p class="gl-mb-0">{{ __('It may be several days before you see feature usage data.') }}</p> - <gl-link :href="devopsReportDocsPath">{{ - __('See example DevOps Score page in our documentation.') - }}</gl-link> - </template> - </gl-empty-state> - <div v-else data-testid="devops-score-app"> - <div class="gl-text-gray-400 gl-my-4" data-testid="devops-score-note-text"> - {{ titleHelperText }} - </div> - <gl-single-stat - unit="%" - size="sm" - :title="s__('DevopsReport|Your score')" - :should-animate="true" - :value="devopsScoreMetrics.averageScore.value" - :meta-icon="devopsScoreMetrics.averageScore.scoreLevel.icon" - :meta-text="devopsScoreMetrics.averageScore.scoreLevel.label" - :variant="devopsScoreMetrics.averageScore.scoreLevel.variant" - /> - <gl-table - :fields="$options.tableHeaderFields" - :items="devopsScoreMetrics.cards" - thead-class="gl-border-t-0 gl-border-b-solid gl-border-b-1 gl-border-b-gray-100" - stacked="sm" + <div data-testid="devops-score-container"> + <devops-score-callout /> + <gl-empty-state + v-if="isEmpty" + :title="__('Data is still calculating...')" + :svg-path="noDataImagePath" > - <template #cell(usage)="{ item }"> - <div data-testid="usageCol"> - <span>{{ item.usage }}</span> - <gl-badge :variant="item.scoreLevel.variant" size="sm" class="gl-ml-1">{{ - item.scoreLevel.label - }}</gl-badge> - </div> + <template #description> + <p class="gl-mb-0">{{ __('It may be several days before you see feature usage data.') }}</p> + <gl-link :href="devopsReportDocsPath">{{ + __('See example DevOps Score page in our documentation.') + }}</gl-link> </template> - </gl-table> + </gl-empty-state> + <div v-else data-testid="devops-score-app"> + <div class="gl-text-gray-400 gl-my-4" data-testid="devops-score-note-text"> + {{ titleHelperText }} + </div> + <gl-single-stat + unit="%" + size="sm" + :title="s__('DevopsReport|Your score')" + :should-animate="true" + :value="devopsScoreMetrics.averageScore.value" + :meta-icon="devopsScoreMetrics.averageScore.scoreLevel.icon" + :meta-text="devopsScoreMetrics.averageScore.scoreLevel.label" + :variant="devopsScoreMetrics.averageScore.scoreLevel.variant" + /> + <gl-table + :fields="$options.tableHeaderFields" + :items="devopsScoreMetrics.cards" + thead-class="gl-border-t-0 gl-border-b-solid gl-border-b-1 gl-border-b-gray-100" + stacked="sm" + > + <template #cell(usage)="{ item }"> + <div data-testid="usageCol"> + <span>{{ item.usage }}</span> + <gl-badge :variant="item.scoreLevel.variant" size="sm" class="gl-ml-1">{{ + item.scoreLevel.label + }}</gl-badge> + </div> + </template> + </gl-table> + </div> </div> </template> diff --git a/app/assets/javascripts/analytics/devops_report/components/devops_score_callout.vue b/app/assets/javascripts/analytics/devops_report/components/devops_score_callout.vue new file mode 100644 index 00000000000..e594b4e360a --- /dev/null +++ b/app/assets/javascripts/analytics/devops_report/components/devops_score_callout.vue @@ -0,0 +1,55 @@ +<script> +import { GlBanner } from '@gitlab/ui'; +import { parseBoolean, getCookie, setCookie } from '~/lib/utils/common_utils'; +import { + INTRO_COOKIE_KEY, + INTRO_BANNER_TITLE, + INTRO_BANNER_BODY, + INTRO_BANNER_ACTION_TEXT, +} from '../constants'; + +export default { + name: 'DevopsScoreCallout', + components: { + GlBanner, + }, + inject: { + devopsReportDocsPath: { + default: '', + }, + devopsScoreIntroImagePath: { + default: '', + }, + }, + data() { + return { + bannerDismissed: parseBoolean(getCookie(INTRO_COOKIE_KEY)), + }; + }, + i18n: { + title: INTRO_BANNER_TITLE, + body: INTRO_BANNER_BODY, + action: INTRO_BANNER_ACTION_TEXT, + }, + methods: { + dismissBanner() { + setCookie(INTRO_COOKIE_KEY, 'true'); + this.bannerDismissed = true; + }, + }, +}; +</script> +<template> + <gl-banner + v-if="!bannerDismissed" + class="gl-mt-3" + variant="introduction" + :title="$options.i18n.title" + :button-text="$options.i18n.action" + :button-link="devopsReportDocsPath" + :svg-path="devopsScoreIntroImagePath" + @close="dismissBanner" + > + <p>{{ $options.i18n.body }}</p> + </gl-banner> +</template> diff --git a/app/assets/javascripts/analytics/devops_report/constants.js b/app/assets/javascripts/analytics/devops_report/constants.js new file mode 100644 index 00000000000..b395d7eb464 --- /dev/null +++ b/app/assets/javascripts/analytics/devops_report/constants.js @@ -0,0 +1,11 @@ +import { __ } from '~/locale'; + +export const INTRO_COOKIE_KEY = 'dev_ops_report_intro_callout_dismissed'; + +export const INTRO_BANNER_TITLE = __('Introducing Your DevOps Report'); + +export const INTRO_BANNER_BODY = __( + 'Your DevOps Report gives an overview of how you are using GitLab from a feature perspective. Use it to view how you compare with other organizations.', +); + +export const INTRO_BANNER_ACTION_TEXT = __('Read more'); diff --git a/app/assets/javascripts/analytics/devops_report/devops_score.js b/app/assets/javascripts/analytics/devops_report/devops_score.js index 18f7cf0c3ab..20e9fc776bc 100644 --- a/app/assets/javascripts/analytics/devops_report/devops_score.js +++ b/app/assets/javascripts/analytics/devops_report/devops_score.js @@ -6,7 +6,12 @@ export default () => { if (!el) return false; - const { devopsScoreMetrics, devopsReportDocsPath, noDataImagePath } = el.dataset; + const { + devopsScoreMetrics, + devopsReportDocsPath, + noDataImagePath, + devopsScoreIntroImagePath, + } = el.dataset; return new Vue({ el, @@ -14,6 +19,7 @@ export default () => { devopsScoreMetrics: JSON.parse(devopsScoreMetrics), devopsReportDocsPath, noDataImagePath, + devopsScoreIntroImagePath, }, render(h) { return h(DevopsScore); diff --git a/app/assets/javascripts/filtered_search/admin_runners_filtered_search_token_keys.js b/app/assets/javascripts/filtered_search/admin_runners_filtered_search_token_keys.js deleted file mode 100644 index 42d0fbacca0..00000000000 --- a/app/assets/javascripts/filtered_search/admin_runners_filtered_search_token_keys.js +++ /dev/null @@ -1,36 +0,0 @@ -import { __ } from '~/locale'; -import FilteredSearchTokenKeys from './filtered_search_token_keys'; - -const tokenKeys = [ - { - formattedKey: __('Status'), - key: 'status', - type: 'string', - param: 'status', - symbol: '', - icon: 'messages', - tag: 'status', - }, - { - formattedKey: __('Type'), - key: 'type', - type: 'string', - param: 'type', - symbol: '', - icon: 'cube', - tag: 'type', - }, - { - formattedKey: __('Tag'), - key: 'tag', - type: 'array', - param: 'name[]', - symbol: '~', - icon: 'tag', - tag: '~tag', - }, -]; - -const AdminRunnersFilteredSearchTokenKeys = new FilteredSearchTokenKeys(tokenKeys); - -export default AdminRunnersFilteredSearchTokenKeys; diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/app.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/app.vue index ae5558111e6..707f186d4da 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/components/details/app.vue +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/app.vue @@ -20,12 +20,12 @@ import { numberToHumanSize } from '~/lib/utils/number_utils'; import { objectToQuery } from '~/lib/utils/url_utility'; import { s__, __ } from '~/locale'; // import DependencyRow from '~/packages/details/components/dependency_row.vue'; -// import InstallationCommands from '~/packages/details/components/installation_commands.vue'; // import PackageFiles from '~/packages/details/components/package_files.vue'; // import PackageListRow from '~/packages/shared/components/package_list_row.vue'; import PackagesListLoader from '~/packages/shared/components/packages_list_loader.vue'; import { packageTypeToTrackCategory } from '~/packages/shared/utils'; import AdditionalMetadata from '~/packages_and_registries/package_registry/components/details/additional_metadata.vue'; +import InstallationCommands from '~/packages_and_registries/package_registry/components/details/installation_commands.vue'; import PackageHistory from '~/packages_and_registries/package_registry/components/details/package_history.vue'; import { PACKAGE_TYPE_NUGET, @@ -62,7 +62,7 @@ export default { // DependencyRow, PackageHistory, AdditionalMetadata, - // InstallationCommands, + InstallationCommands, // PackageFiles, }, directives: { @@ -240,11 +240,7 @@ export default { <div v-if="!isLoading" data-qa-selector="package_information_content"> <package-history :package-entity="packageEntity" :project-name="projectName" /> - <!-- <installation-commands - :package-entity="packageEntity" - :npm-path="npmPath" - :npm-help-path="npmHelpPath" - /> --> + <installation-commands :package-entity="packageEntity" /> <additional-metadata :package-entity="packageEntity" /> </div> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/npm_installation.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/npm_installation.vue index c178d3e97e9..47081e23318 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/components/details/npm_installation.vue +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/npm_installation.vue @@ -1,9 +1,17 @@ <script> import { GlLink, GlSprintf } from '@gitlab/ui'; -import { mapGetters, mapState } from 'vuex'; import { s__ } from '~/locale'; -import { NpmManager, TrackingActions, TrackingLabels } from '~/packages/details/constants'; + import InstallationTitle from '~/packages_and_registries/package_registry/components/details/installation_title.vue'; +import { + TRACKING_ACTION_COPY_NPM_INSTALL_COMMAND, + TRACKING_ACTION_COPY_NPM_SETUP_COMMAND, + TRACKING_ACTION_COPY_YARN_INSTALL_COMMAND, + TRACKING_ACTION_COPY_YARN_SETUP_COMMAND, + TRACKING_LABEL_CODE_INSTRUCTION, + NPM_PACKAGE_MANAGER, + YARN_PACKAGE_MANAGER, +} from '~/packages_and_registries/package_registry/constants'; import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue'; export default { @@ -14,40 +22,70 @@ export default { GlLink, GlSprintf, }, + inject: ['npmHelpPath', 'npmPath'], + props: { + packageEntity: { + type: Object, + required: true, + }, + }, data() { return { - instructionType: 'npm', + instructionType: NPM_PACKAGE_MANAGER, }; }, computed: { - ...mapState(['npmHelpPath']), - ...mapGetters(['npmInstallationCommand', 'npmSetupCommand']), npmCommand() { - return this.npmInstallationCommand(NpmManager.NPM); + return this.npmInstallationCommand(NPM_PACKAGE_MANAGER); }, npmSetup() { - return this.npmSetupCommand(NpmManager.NPM); + return this.npmSetupCommand(NPM_PACKAGE_MANAGER); }, yarnCommand() { - return this.npmInstallationCommand(NpmManager.YARN); + return this.npmInstallationCommand(YARN_PACKAGE_MANAGER); }, yarnSetupCommand() { - return this.npmSetupCommand(NpmManager.YARN); + return this.npmSetupCommand(YARN_PACKAGE_MANAGER); }, showNpm() { - return this.instructionType === 'npm'; + return this.instructionType === NPM_PACKAGE_MANAGER; + }, + }, + methods: { + npmInstallationCommand(type) { + // eslint-disable-next-line @gitlab/require-i18n-strings + const instruction = type === NPM_PACKAGE_MANAGER ? 'npm i' : 'yarn add'; + + return `${instruction} ${this.packageEntity.name}`; }, + npmSetupCommand(type) { + const scope = this.packageEntity.name.substring(0, this.packageEntity.name.indexOf('/')); + + if (type === NPM_PACKAGE_MANAGER) { + return `echo ${scope}:registry=${this.npmPath}/ >> .npmrc`; + } + + return `echo \\"${scope}:registry\\" \\"${this.npmPath}/\\" >> .yarnrc`; + }, + }, + packageManagers: { + NPM_PACKAGE_MANAGER, + }, + tracking: { + TRACKING_ACTION_COPY_NPM_INSTALL_COMMAND, + TRACKING_ACTION_COPY_NPM_SETUP_COMMAND, + TRACKING_ACTION_COPY_YARN_INSTALL_COMMAND, + TRACKING_ACTION_COPY_YARN_SETUP_COMMAND, + TRACKING_LABEL_CODE_INSTRUCTION, }, i18n: { helpText: s__( 'PackageRegistry|You may also need to setup authentication using an auth token. %{linkStart}See the documentation%{linkEnd} to find out more.', ), }, - trackingActions: { ...TrackingActions }, - TrackingLabels, installOptions: [ - { value: 'npm', label: s__('PackageRegistry|Show NPM commands') }, - { value: 'yarn', label: s__('PackageRegistry|Show Yarn commands') }, + { value: NPM_PACKAGE_MANAGER, label: s__('PackageRegistry|Show NPM commands') }, + { value: YARN_PACKAGE_MANAGER, label: s__('PackageRegistry|Show Yarn commands') }, ], }; </script> @@ -55,7 +93,7 @@ export default { <template> <div> <installation-title - package-type="npm" + :package-type="$options.packageManagers.NPM_PACKAGE_MANAGER" :options="$options.installOptions" @change="instructionType = $event" /> @@ -64,16 +102,16 @@ export default { v-if="showNpm" :instruction="npmCommand" :copy-text="s__('PackageRegistry|Copy npm command')" - :tracking-action="$options.trackingActions.COPY_NPM_INSTALL_COMMAND" - :tracking-label="$options.TrackingLabels.CODE_INSTRUCTION" + :tracking-action="$options.tracking.TRACKING_ACTION_COPY_NPM_INSTALL_COMMAND" + :tracking-label="$options.tracking.TRACKING_LABEL_CODE_INSTRUCTION" /> <code-instruction v-else :instruction="yarnCommand" :copy-text="s__('PackageRegistry|Copy yarn command')" - :tracking-action="$options.trackingActions.COPY_YARN_INSTALL_COMMAND" - :tracking-label="$options.TrackingLabels.CODE_INSTRUCTION" + :tracking-action="$options.tracking.TRACKING_ACTION_COPY_YARN_INSTALL_COMMAND" + :tracking-label="$options.tracking.TRACKING_LABEL_CODE_INSTRUCTION" /> <h3 class="gl-font-lg">{{ __('Registry setup') }}</h3> @@ -82,16 +120,16 @@ export default { v-if="showNpm" :instruction="npmSetup" :copy-text="s__('PackageRegistry|Copy npm setup command')" - :tracking-action="$options.trackingActions.COPY_NPM_SETUP_COMMAND" - :tracking-label="$options.TrackingLabels.CODE_INSTRUCTION" + :tracking-action="$options.tracking.TRACKING_ACTION_COPY_NPM_SETUP_COMMAND" + :tracking-label="$options.tracking.TRACKING_LABEL_CODE_INSTRUCTION" /> <code-instruction v-else :instruction="yarnSetupCommand" :copy-text="s__('PackageRegistry|Copy yarn setup command')" - :tracking-action="$options.trackingActions.COPY_YARN_SETUP_COMMAND" - :tracking-label="$options.TrackingLabels.CODE_INSTRUCTION" + :tracking-action="$options.tracking.TRACKING_ACTION_COPY_YARN_SETUP_COMMAND" + :tracking-label="$options.tracking.TRACKING_LABEL_CODE_INSTRUCTION" /> <gl-sprintf :message="$options.i18n.helpText"> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/nuget_installation.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/nuget_installation.vue index 84493790b4d..2e9991b7be5 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/components/details/nuget_installation.vue +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/nuget_installation.vue @@ -1,9 +1,12 @@ <script> import { GlLink, GlSprintf } from '@gitlab/ui'; -import { mapGetters, mapState } from 'vuex'; import { s__ } from '~/locale'; -import { TrackingActions, TrackingLabels } from '~/packages/details/constants'; import InstallationTitle from '~/packages_and_registries/package_registry/components/details/installation_title.vue'; +import { + TRACKING_ACTION_COPY_NUGET_INSTALL_COMMAND, + TRACKING_ACTION_COPY_NUGET_SETUP_COMMAND, + TRACKING_LABEL_CODE_INSTRUCTION, +} from '~/packages_and_registries/package_registry/constants'; import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue'; export default { @@ -14,17 +17,31 @@ export default { GlLink, GlSprintf, }, + inject: ['nugetHelpPath', 'nugetPath'], + props: { + packageEntity: { + type: Object, + required: true, + }, + }, computed: { - ...mapState(['nugetHelpPath']), - ...mapGetters(['nugetInstallationCommand', 'nugetSetupCommand']), + nugetInstallationCommand() { + return `nuget install ${this.packageEntity.name} -Source "GitLab"`; + }, + nugetSetupCommand() { + return `nuget source Add -Name "GitLab" -Source "${this.nugetPath}" -UserName <your_username> -Password <your_token>`; + }, + }, + tracking: { + TRACKING_ACTION_COPY_NUGET_INSTALL_COMMAND, + TRACKING_ACTION_COPY_NUGET_SETUP_COMMAND, + TRACKING_LABEL_CODE_INSTRUCTION, }, i18n: { helpText: s__( 'PackageRegistry|For more information on the NuGet registry, %{linkStart}see the documentation%{linkEnd}.', ), }, - trackingActions: { ...TrackingActions }, - TrackingLabels, installOptions: [{ value: 'nuget', label: s__('PackageRegistry|Show Nuget commands') }], }; </script> @@ -37,8 +54,8 @@ export default { :label="s__('PackageRegistry|NuGet Command')" :instruction="nugetInstallationCommand" :copy-text="s__('PackageRegistry|Copy NuGet Command')" - :tracking-action="$options.trackingActions.COPY_NUGET_INSTALL_COMMAND" - :tracking-label="$options.TrackingLabels.CODE_INSTRUCTION" + :tracking-action="$options.tracking.TRACKING_ACTION_COPY_NUGET_INSTALL_COMMAND" + :tracking-label="$options.tracking.TRACKING_LABEL_CODE_INSTRUCTION" /> <h3 class="gl-font-lg">{{ __('Registry setup') }}</h3> @@ -46,8 +63,8 @@ export default { :label="s__('PackageRegistry|Add NuGet Source')" :instruction="nugetSetupCommand" :copy-text="s__('PackageRegistry|Copy NuGet Setup Command')" - :tracking-action="$options.trackingActions.COPY_NUGET_SETUP_COMMAND" - :tracking-label="$options.TrackingLabels.CODE_INSTRUCTION" + :tracking-action="$options.tracking.TRACKING_ACTION_COPY_NUGET_SETUP_COMMAND" + :tracking-label="$options.tracking.TRACKING_LABEL_CODE_INSTRUCTION" /> <gl-sprintf :message="$options.i18n.helpText"> <template #link="{ content }"> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/pypi_installation.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/pypi_installation.vue index 21eba44a720..669adab9df6 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/components/details/pypi_installation.vue +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/pypi_installation.vue @@ -1,9 +1,13 @@ <script> import { GlLink, GlSprintf } from '@gitlab/ui'; -import { mapGetters, mapState } from 'vuex'; + import { s__ } from '~/locale'; -import { TrackingActions, TrackingLabels } from '~/packages/details/constants'; import InstallationTitle from '~/packages_and_registries/package_registry/components/details/installation_title.vue'; +import { + TRACKING_ACTION_COPY_PIP_INSTALL_COMMAND, + TRACKING_ACTION_COPY_PYPI_SETUP_COMMAND, + TRACKING_LABEL_CODE_INSTRUCTION, +} from '~/packages_and_registries/package_registry/constants'; import CodeInstruction from '~/vue_shared/components/registry/code_instruction.vue'; export default { @@ -14,9 +18,29 @@ export default { GlLink, GlSprintf, }, + inject: ['pypiHelpPath', 'pypiPath', 'pypiSetupPath'], + props: { + packageEntity: { + type: Object, + required: true, + }, + }, computed: { - ...mapState(['pypiHelpPath']), - ...mapGetters(['pypiPipCommand', 'pypiSetupCommand']), + pypiPipCommand() { + // eslint-disable-next-line @gitlab/require-i18n-strings + return `pip install ${this.packageEntity.name} --extra-index-url ${this.pypiPath}`; + }, + pypiSetupCommand() { + return `[gitlab] +repository = ${this.pypiSetupPath} +username = __token__ +password = <your personal access token>`; + }, + }, + tracking: { + TRACKING_ACTION_COPY_PIP_INSTALL_COMMAND, + TRACKING_ACTION_COPY_PYPI_SETUP_COMMAND, + TRACKING_LABEL_CODE_INSTRUCTION, }, i18n: { setupText: s__( @@ -26,8 +50,6 @@ export default { 'PackageRegistry|For more information on the PyPi registry, %{linkStart}see the documentation%{linkEnd}.', ), }, - trackingActions: { ...TrackingActions }, - TrackingLabels, installOptions: [{ value: 'pypi', label: s__('PackageRegistry|Show PyPi commands') }], }; </script> @@ -41,8 +63,8 @@ export default { :instruction="pypiPipCommand" :copy-text="s__('PackageRegistry|Copy Pip command')" data-testid="pip-command" - :tracking-action="$options.trackingActions.COPY_PIP_INSTALL_COMMAND" - :tracking-label="$options.TrackingLabels.CODE_INSTRUCTION" + :tracking-action="$options.tracking.TRACKING_ACTION_COPY_PIP_INSTALL_COMMAND" + :tracking-label="$options.tracking.TRACKING_LABEL_CODE_INSTRUCTION" /> <h3 class="gl-font-lg">{{ __('Registry setup') }}</h3> @@ -59,8 +81,8 @@ export default { :copy-text="s__('PackageRegistry|Copy .pypirc content')" data-testid="pypi-setup-content" multiline - :tracking-action="$options.trackingActions.COPY_PYPI_SETUP_COMMAND" - :tracking-label="$options.TrackingLabels.CODE_INSTRUCTION" + :tracking-action="$options.tracking.TRACKING_ACTION_COPY_PYPI_SETUP_COMMAND" + :tracking-label="$options.tracking.TRACKING_LABEL_CODE_INSTRUCTION" /> <gl-sprintf :message="$options.i18n.helpText"> <template #link="{ content }"> diff --git a/app/assets/javascripts/packages_and_registries/package_registry/constants.js b/app/assets/javascripts/packages_and_registries/package_registry/constants.js index 0008e5f0c98..c1de9e7a61e 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/constants.js +++ b/app/assets/javascripts/packages_and_registries/package_registry/constants.js @@ -83,3 +83,6 @@ export const PACKAGE_ERROR_STATUS = 'error'; export const PACKAGE_DEFAULT_STATUS = 'default'; export const PACKAGE_HIDDEN_STATUS = 'hidden'; export const PACKAGE_PROCESSING_STATUS = 'processing'; + +export const NPM_PACKAGE_MANAGER = 'npm'; +export const YARN_PACKAGE_MANAGER = 'yarn'; diff --git a/app/assets/javascripts/pages/admin/runners/index/index.js b/app/assets/javascripts/pages/admin/runners/index/index.js index 8e7861c300a..f83111b6385 100644 --- a/app/assets/javascripts/pages/admin/runners/index/index.js +++ b/app/assets/javascripts/pages/admin/runners/index/index.js @@ -1,17 +1,3 @@ -import AdminRunnersFilteredSearchTokenKeys from '~/filtered_search/admin_runners_filtered_search_token_keys'; -import { FILTERED_SEARCH } from '~/pages/constants'; -import initFilteredSearch from '~/pages/search/init_filtered_search'; -import { initInstallRunner } from '~/pages/shared/mount_runner_instructions'; import { initAdminRunners } from '~/runner/admin_runners'; -initFilteredSearch({ - page: FILTERED_SEARCH.ADMIN_RUNNERS, - filteredSearchTokenKeys: AdminRunnersFilteredSearchTokenKeys, - useDefaultState: true, -}); - -initInstallRunner(); - -if (gon.features?.runnerListViewVueUi) { - initAdminRunners(); -} +initAdminRunners(); diff --git a/app/assets/javascripts/repository/components/breadcrumbs.vue b/app/assets/javascripts/repository/components/breadcrumbs.vue index 0b8408643ac..db84e2b5912 100644 --- a/app/assets/javascripts/repository/components/breadcrumbs.vue +++ b/app/assets/javascripts/repository/components/breadcrumbs.vue @@ -247,7 +247,8 @@ export default { return items; }, renderAddToTreeDropdown() { - return this.canCollaborate || this.canCreateMrFromFork; + const isBlobPath = this.$route.name === 'blobPath' || this.$route.name === 'blobPathDecoded'; + return !isBlobPath && (this.canCollaborate || this.canCreateMrFromFork); }, }, methods: { diff --git a/app/controllers/admin/runners_controller.rb b/app/controllers/admin/runners_controller.rb index d1c91d9617f..8c74352a179 100644 --- a/app/controllers/admin/runners_controller.rb +++ b/app/controllers/admin/runners_controller.rb @@ -4,19 +4,11 @@ class Admin::RunnersController < Admin::ApplicationController include RunnerSetupScripts before_action :runner, except: [:index, :tag_list, :runner_setup_scripts] - before_action only: [:index] do - push_frontend_feature_flag(:runner_list_view_vue_ui, current_user, default_enabled: :yaml) - end feature_category :runner - NUMBER_OF_RUNNERS_PER_PAGE = 30 - def index - finder = Ci::RunnersFinder.new(current_user: current_user, params: params) - @runners = finder.execute.page(params[:page]).per(NUMBER_OF_RUNNERS_PER_PAGE) @active_runners_count = Ci::Runner.online.count - @sort = finder.sort_key end def show diff --git a/app/models/concerns/each_batch.rb b/app/models/concerns/each_batch.rb index a59f00d73ec..443e1ab53b4 100644 --- a/app/models/concerns/each_batch.rb +++ b/app/models/concerns/each_batch.rb @@ -91,7 +91,11 @@ module EachBatch # Any ORDER BYs are useless for this relation and can lead to less # efficient UPDATE queries, hence we get rid of it. - yield relation.except(:order), index + relation = relation.except(:order) + + # Using unscoped is necessary to prevent leaking the current scope used by + # ActiveRecord to chain `each_batch` method. + unscoped { yield relation, index } break unless stop end diff --git a/app/models/integrations/datadog.rb b/app/models/integrations/datadog.rb index 8a356cf8abc..08cd451db94 100644 --- a/app/models/integrations/datadog.rb +++ b/app/models/integrations/datadog.rb @@ -129,14 +129,12 @@ module Integrations end def test(data) - begin - result = execute(data) - return { success: false, result: result[:message] } if result[:http_status] != 200 - rescue StandardError => error - return { success: false, result: error } - end - - { success: true, result: result[:message] } + result = execute(data) + + { + success: (200..299).cover?(result[:http_status]), + result: result[:message] + } end private diff --git a/app/views/admin/dev_ops_report/_callout.html.haml b/app/views/admin/dev_ops_report/_callout.html.haml deleted file mode 100644 index 2b4c258a00c..00000000000 --- a/app/views/admin/dev_ops_report/_callout.html.haml +++ /dev/null @@ -1,13 +0,0 @@ -.gl-mt-3 -.user-callout{ data: { uid: 'dev_ops_report_intro_callout_dismissed' } } - .bordered-box.landing.content-block - %button.gl-button.btn.btn-default-tertiary.close.js-close-callout{ type: 'button', - 'aria-label' => _('Dismiss DevOps Report introduction') } - = sprite_icon('close', size: 16, css_class: 'dismiss-icon') - .user-callout-copy - %h4 - = _('Introducing Your DevOps Report') - %p - = _('Your DevOps Report gives an overview of how you are using GitLab from a feature perspective. Use it to view how you compare with other organizations.') - .svg-container.devops - = custom_icon('dev_ops_report_overview') diff --git a/app/views/admin/dev_ops_report/_report.html.haml b/app/views/admin/dev_ops_report/_report.html.haml index 0b26548d6e6..5ab68a463ba 100644 --- a/app/views/admin/dev_ops_report/_report.html.haml +++ b/app/views/admin/dev_ops_report/_report.html.haml @@ -1,9 +1,6 @@ - service_ping_enabled = Gitlab::CurrentSettings.usage_ping_enabled -- if service_ping_enabled && show_callout?('dev_ops_report_intro_callout_dismissed') - = render 'callout' - - if !service_ping_enabled #js-devops-service-ping-disabled{ data: { is_admin: current_user&.admin.to_s, empty_state_svg_path: image_path('illustrations/convdev/convdev_no_index.svg'), enable_service_ping_path: metrics_and_profiling_admin_application_settings_path(anchor: 'js-usage-settings'), docs_link: help_page_path('development/service_ping/index.md') } } - else - #js-devops-score{ data: { devops_score_metrics: devops_score_metrics(@metric).to_json, devops_report_docs_path: help_page_path('user/admin_area/analytics/dev_ops_report'), no_data_image_path: image_path('dev_ops_report_no_data.svg') } } + #js-devops-score{ data: { devops_score_metrics: devops_score_metrics(@metric).to_json, devops_report_docs_path: help_page_path('user/admin_area/analytics/dev_ops_report'), no_data_image_path: image_path('dev_ops_report_no_data.svg'), devops_score_intro_image_path: image_path('dev_ops_report_overview.svg') } } diff --git a/app/views/admin/runners/_runner.html.haml b/app/views/admin/runners/_runner.html.haml deleted file mode 100644 index ce143a6b155..00000000000 --- a/app/views/admin/runners/_runner.html.haml +++ /dev/null @@ -1,80 +0,0 @@ --# Note: This file should stay aligned with: --# `app/views/groups/runners/_runner.html.haml` - -.gl-responsive-table-row{ data: { testid: "runner-row-#{runner.id}" } } - .table-section.section-10.section-wrap - .table-mobile-header{ role: 'rowheader' }= _('Type') - .table-mobile-content - - if runner.instance_type? - %span.badge.badge-pill.gl-badge.sm.badge-success= s_('Runners|shared') - - elsif runner.group_type? - %span.badge.badge-pill.gl-badge.sm.badge-success= s_('Runners|group') - - else - %span.badge.badge-pill.gl-badge.sm.badge-info= s_('Runners|specific') - - if runner.locked? - %span.badge.badge-pill.gl-badge.sm.badge-warning= s_('Runners|locked') - - unless runner.active? - %span.badge.badge-pill.gl-badge.sm.badge-danger= s_('Runners|paused') - - .table-section.section-30 - .table-mobile-header{ role: 'rowheader' }= s_('Runners|Runner') - .table-mobile-content - = link_to("##{runner.id} (#{runner.short_sha})", admin_runner_path(runner)) - .gl-text-truncate - %span{ title: runner.description, data: { toggle: 'tooltip', container: 'body' } } - = runner.description - - .table-section.section-10 - .table-mobile-header{ role: 'rowheader' }= _('Version') - .table-mobile-content.str-truncated.has-tooltip{ title: runner.version } - = runner.version - - .table-section.section-10 - .table-mobile-header{ role: 'rowheader' }= _('IP Address') - .table-mobile-content.str-truncated.has-tooltip{ title: runner.ip_address } - = runner.ip_address - - .table-section.section-5 - .table-mobile-header{ role: 'rowheader' }= _('Projects') - .table-mobile-content - - if runner.instance_type? || runner.group_type? - = _('n/a') - - else - = runner.projects.count(:all) - - .table-section.section-5 - .table-mobile-header{ role: 'rowheader' }= _('Jobs') - .table-mobile-content - = limited_counter_with_delimiter(runner.builds) - - .table-section.section-10.section-wrap - .table-mobile-header{ role: 'rowheader' }= _('Tags') - .table-mobile-content - - runner.tags.map(&:name).sort.each do |tag| - %span.badge.badge-primary.str-truncated.has-tooltip{ title: tag } - = tag - - .table-section.section-10 - .table-mobile-header{ role: 'rowheader' }= _('Last contact') - .table-mobile-content - - contacted_at = runner_contacted_at(runner) - - if contacted_at - = time_ago_with_tooltip contacted_at - - else - = _('Never') - - .table-section.table-button-footer.section-10 - .btn-group.table-action-buttons - .btn-group - = link_to admin_runner_path(runner), class: 'gl-button btn btn-default btn-icon has-tooltip', title: _('Edit'), ref: 'tooltip', aria: { label: _('Edit') }, data: { placement: 'top', container: 'body'} do - = sprite_icon('pencil', css_class: 'gl-icon') - .btn-group - - if runner.active? - = link_to [:pause, :admin, runner], method: :post, class: 'gl-button btn btn-default btn-icon has-tooltip', title: _('Pause'), ref: 'tooltip', aria: { label: _('Pause') }, data: { placement: 'top', container: 'body', confirm: _('Are you sure?') } do - = sprite_icon('pause', css_class: 'gl-icon') - - else - = link_to [:resume, :admin, runner], method: :post, class: 'gl-button btn btn-default btn-icon has-tooltip gl-px-3', title: _('Resume'), ref: 'tooltip', aria: { label: _('Resume') }, data: { placement: 'top', container: 'body'} do - = sprite_icon('play', css_class: 'gl-icon') - .btn-group - = link_to [:admin, runner], method: :delete, class: 'gl-button btn btn-danger btn-icon has-tooltip', title: _('Remove'), ref: 'tooltip', aria: { label: _('Remove') }, data: { placement: 'top', container: 'body', confirm: _('Are you sure?') } do - = sprite_icon('close', css_class: 'gl-icon') diff --git a/app/views/admin/runners/index.html.haml b/app/views/admin/runners/index.html.haml index 5dce44a787c..f298fce7bcf 100644 --- a/app/views/admin/runners/index.html.haml +++ b/app/views/admin/runners/index.html.haml @@ -1,140 +1,4 @@ - breadcrumb_title _('Runners') - page_title _('Runners') -- if Feature.enabled?(:runner_list_view_vue_ui, current_user, default_enabled: :yaml) - #js-admin-runners{ data: { registration_token: Gitlab::CurrentSettings.runners_registration_token, runner_install_help_page: 'https://docs.gitlab.com/runner/install/', active_runners_count: @active_runners_count } } -- else - .row - .col-sm-6 - .bs-callout - %p - = _("Runners are processes that pick up and execute CI/CD jobs for GitLab.") - %br - = _('You can register runners as separate users, on separate servers, and on your local machine. Register as many runners as you want.') - %br - - %div - %span= _('Runners can be:') - %ul - %li - %span.badge.badge-pill.gl-badge.sm.badge-success= s_('Runners|shared') - \- - = _('Runs jobs from all unassigned projects.') - %li - %span.badge.badge-pill.gl-badge.sm.badge-success= s_('Runners|group') - \- - = _('Runs jobs from all unassigned projects in its group.') - %li - %span.badge.badge-pill.gl-badge.sm.badge-info= s_('Runners|specific') - \- - = _('Runs jobs from assigned projects.') - %li - %span.badge.badge-pill.gl-badge.sm.badge-warning= s_('Runners|locked') - \- - = _('Cannot be assigned to other projects.') - %li - %span.badge.badge-pill.gl-badge.sm.badge-danger= s_('Runners|paused') - \- - = _('Not available to run jobs.') - - .col-sm-6 - .bs-callout - = render partial: 'ci/runner/how_to_setup_runner', - locals: { registration_token: Gitlab::CurrentSettings.runners_registration_token, - type: s_('Runners|shared'), - reset_token_url: reset_registration_token_admin_application_settings_path, - project_path: '', - group_path: '' } - - .row - .col-sm-9 - = form_tag admin_runners_path, id: 'runners-search', method: :get, class: 'filter-form js-filter-form' do - .filtered-search-wrapper.d-flex - .filtered-search-box - = dropdown_tag(_('Recent searches'), - options: { wrapper_class: 'filtered-search-history-dropdown-wrapper', - toggle_class: 'gl-button btn btn-default filtered-search-history-dropdown-toggle-button', - dropdown_class: 'filtered-search-history-dropdown', - content_class: 'filtered-search-history-dropdown-content' }) do - .js-filtered-search-history-dropdown{ data: { full_path: admin_runners_path } } - .filtered-search-box-input-container.droplab-dropdown - .scroll-container - %ul.tokens-container.list-unstyled - %li.input-token - %input.form-control.filtered-search{ search_filter_input_options('runners') } - #js-dropdown-hint.filtered-search-input-dropdown-menu.dropdown-menu.hint-dropdown - %ul.filter-dropdown{ data: { dynamic: true, dropdown: true } } - %li.filter-dropdown-item{ data: {hint: "#{'{{hint}}'}", tag: "#{'{{tag}}'}", action: "#{'{{hint === \'search\' ? \'submit\' : \'\' }}'}" } } - = button_tag class: %w[gl-button btn btn-link] do - -# Encapsulate static class name `{{icon}}` inside #{} to bypass - -# haml lint's ClassAttributeWithStaticValue - %svg - %use{ 'xlink:href': "#{'{{icon}}'}" } - %span.js-filter-hint - {{formattedKey}} - #js-dropdown-operator.filtered-search-input-dropdown-menu.dropdown-menu - %ul.filter-dropdown{ data: { dropdown: true, dynamic: true } } - %li.filter-dropdown-item{ data: { value: "{{ title }}" } } - %button.gl-button.btn.btn-link{ type: 'button' } - {{ title }} - %span.btn-helptext - {{ help }} - #js-dropdown-admin-runner-status.filtered-search-input-dropdown-menu.dropdown-menu - %ul{ data: { dropdown: true } } - - Ci::Runner::AVAILABLE_STATUSES.each do |status| - %li.filter-dropdown-item{ data: { value: status } } - = button_tag class: %w[gl-button btn btn-link] do - = status.titleize - - #js-dropdown-admin-runner-type.filtered-search-input-dropdown-menu.dropdown-menu - %ul{ data: { dropdown: true } } - - Ci::Runner::AVAILABLE_TYPES.each do |runner_type| - %li.filter-dropdown-item{ data: { value: runner_type } } - = button_tag class: %w[gl-button btn btn-link] do - = runner_type.titleize - - #js-dropdown-admin-runner-type.filtered-search-input-dropdown-menu.dropdown-menu - %ul{ data: { dropdown: true } } - - Ci::Runner::AVAILABLE_TYPES.each do |runner_type| - %li.filter-dropdown-item{ data: { value: runner_type } } - = button_tag class: %w[gl-button btn btn-link] do - = runner_type.titleize - - #js-dropdown-runner-tag.filtered-search-input-dropdown-menu.dropdown-menu - %ul{ data: { dropdown: true } } - %li.filter-dropdown-item{ data: { value: 'none' } } - %button.gl-button.btn.btn-link - = _('No Tag') - %li.divider.droplab-item-ignore - %ul.filter-dropdown{ data: { dynamic: true, dropdown: true } } - %li.filter-dropdown-item - %button.gl-button.btn.btn-link.js-data-value - %span.dropdown-light-content - {{name}} - - = button_tag class: %w[clear-search hidden] do - = sprite_icon('close', size: 16, css_class: 'clear-search-icon') - .filter-dropdown-container - = render 'sort_dropdown' - - .col-sm-3.text-right-lg - = _('Runners currently online: %{active_runners_count}') % { active_runners_count: @active_runners_count } - - if @runners.any? - .content-list{ data: { testid: 'runners-table' } } - .table-holder - .gl-responsive-table-row.table-row-header{ role: 'row' } - .table-section.section-10{ role: 'rowheader' }= _('Type/State') - .table-section.section-30{ role: 'rowheader' }= s_('Runners|Runner') - .table-section.section-10{ role: 'rowheader' }= _('Version') - .table-section.section-10{ role: 'rowheader' }= _('IP Address') - .table-section.section-5{ role: 'rowheader' }= _('Projects') - .table-section.section-5{ role: 'rowheader' }= _('Jobs') - .table-section.section-10{ role: 'rowheader' }= _('Tags') - .table-section.section-10{ role: 'rowheader' }= _('Last contact') - .table-section.section-10{ role: 'rowheader' } - - - @runners.each do |runner| - = render 'admin/runners/runner', runner: runner - = paginate @runners, theme: 'gitlab' - - else - .nothing-here-block= _('No runners found') +#js-admin-runners{ data: { registration_token: Gitlab::CurrentSettings.runners_registration_token, runner_install_help_page: 'https://docs.gitlab.com/runner/install/', active_runners_count: @active_runners_count } } diff --git a/app/views/groups/runners/_settings.html.haml b/app/views/groups/runners/_settings.html.haml index 187588f5f11..50982fa381c 100644 --- a/app/views/groups/runners/_settings.html.haml +++ b/app/views/groups/runners/_settings.html.haml @@ -75,7 +75,7 @@ = button_tag class: 'clear-search hidden' do = sprite_icon('close', size: 16, css_class: 'clear-search-icon') .filter-dropdown-container - = render 'admin/runners/sort_dropdown' + = render 'groups/runners/sort_dropdown' .col-sm-3.text-right-lg = _('Runners currently online: %{active_runners_count}') % { active_runners_count: limited_counter_with_delimiter(@all_group_runners.online) } diff --git a/app/views/admin/runners/_sort_dropdown.html.haml b/app/views/groups/runners/_sort_dropdown.html.haml index c6627ae0f27..eb826552211 100644 --- a/app/views/admin/runners/_sort_dropdown.html.haml +++ b/app/views/groups/runners/_sort_dropdown.html.haml @@ -8,4 +8,3 @@ %li = sortable_item(sort_title_created_date, page_filter_path(sort: sort_value_created_date), sorted_by) = sortable_item(sort_title_contacted_date, page_filter_path(sort: sort_value_contacted_date), sorted_by) - |