diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-09-10 21:08:54 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-09-10 21:08:54 +0300 |
commit | c596046be917b250019fdfb509be85cfb48df152 (patch) | |
tree | 2c3716f6f70b42e0683022269a13117704d85d15 /app | |
parent | 9afe9ca576408a1145b6250d9493032fe65255ae (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
54 files changed, 612 insertions, 186 deletions
diff --git a/app/assets/images/auth_buttons/atlassian_64.png b/app/assets/images/auth_buttons/atlassian_64.png Binary files differnew file mode 100644 index 00000000000..548f1c93318 --- /dev/null +++ b/app/assets/images/auth_buttons/atlassian_64.png diff --git a/app/assets/javascripts/admin/dev_ops_score/components/usage_ping_disabled.vue b/app/assets/javascripts/admin/dev_ops_report/components/usage_ping_disabled.vue index 5429ec403d3..5429ec403d3 100644 --- a/app/assets/javascripts/admin/dev_ops_score/components/usage_ping_disabled.vue +++ b/app/assets/javascripts/admin/dev_ops_report/components/usage_ping_disabled.vue diff --git a/app/assets/javascripts/issue_show/components/incidents/highlight_bar/graphql/queries/get_highlight_bar_info.graphql b/app/assets/javascripts/issue_show/components/incidents/highlight_bar/graphql/queries/get_highlight_bar_info.graphql new file mode 100644 index 00000000000..fe299adf53e --- /dev/null +++ b/app/assets/javascripts/issue_show/components/incidents/highlight_bar/graphql/queries/get_highlight_bar_info.graphql @@ -0,0 +1,12 @@ +query getHighlightBarInfo($iid: String!, $fullPath: ID!) { + project(fullPath: $fullPath) { + issue(iid: $iid) { + alertManagementAlert { + title + detailsUrl + createdAt + eventCount + } + } + } +} diff --git a/app/assets/javascripts/issue_show/components/incidents/highlight_bar/higlight_bar.vue b/app/assets/javascripts/issue_show/components/incidents/highlight_bar/higlight_bar.vue new file mode 100644 index 00000000000..dbef301856d --- /dev/null +++ b/app/assets/javascripts/issue_show/components/incidents/highlight_bar/higlight_bar.vue @@ -0,0 +1,51 @@ +<script> +import { GlLink } from '@gitlab/ui'; +import { formatDate } from '~/lib/utils/datetime_utility'; +import getHighlightBarInfo from './graphql/queries/get_highlight_bar_info.graphql'; + +export default { + components: { + GlLink, + }, + inject: ['fullPath', 'iid'], + apollo: { + alert: { + query: getHighlightBarInfo, + variables() { + return { + fullPath: this.fullPath, + iid: this.iid, + }; + }, + update: data => data.project?.issue?.alertManagementAlert, + }, + }, + computed: { + startTime() { + return formatDate(this.alert.createdAt, 'yyyy-mm-dd Z'); + }, + }, +}; +</script> + +<template> + <div + v-if="alert" + class="gl-border-solid gl-border-1 gl-border-gray-100 gl-p-5 gl-mb-3 gl-rounded-base gl-display-flex gl-justify-content-space-between" + > + <div class="text-truncate gl-pr-3"> + <span class="gl-font-weight-bold">{{ s__('HighlightBar|Original alert:') }}</span> + <gl-link :href="alert.detailsUrl">{{ alert.title }}</gl-link> + </div> + + <div class="gl-pr-3 gl-white-space-nowrap"> + <span class="gl-font-weight-bold">{{ s__('HighlightBar|Alert start time:') }}</span> + {{ startTime }} + </div> + + <div class="gl-white-space-nowrap"> + <span class="gl-font-weight-bold">{{ s__('HighlightBar|Alert events:') }}</span> + <span>{{ alert.eventCount }}</span> + </div> + </div> +</template> diff --git a/app/assets/javascripts/issue_show/components/incident_tabs.vue b/app/assets/javascripts/issue_show/components/incidents/incident_tabs.vue index f6e82cfaa74..e5dde1aaca6 100644 --- a/app/assets/javascripts/issue_show/components/incident_tabs.vue +++ b/app/assets/javascripts/issue_show/components/incidents/incident_tabs.vue @@ -1,24 +1,23 @@ <script> import { GlTab, GlTabs } from '@gitlab/ui'; -import DescriptionComponent from './description.vue'; +import DescriptionComponent from '../description.vue'; +import HighlightBar from './highlight_bar/higlight_bar.vue'; export default { components: { GlTab, GlTabs, DescriptionComponent, + HighlightBar, }, }; </script> <template> <div> - <gl-tabs - content-class="gl-reset-line-height gl-mt-3" - class="gl-mt-n3" - data-testid="incident-tabs" - > + <gl-tabs content-class="gl-reset-line-height" class="gl-mt-n3" data-testid="incident-tabs"> <gl-tab :title="__('Summary')"> + <highlight-bar /> <description-component v-bind="$attrs" /> </gl-tab> </gl-tabs> diff --git a/app/assets/javascripts/issue_show/incident.js b/app/assets/javascripts/issue_show/incident.js index 82b862a2195..a34e75ee64a 100644 --- a/app/assets/javascripts/issue_show/incident.js +++ b/app/assets/javascripts/issue_show/incident.js @@ -1,13 +1,28 @@ import Vue from 'vue'; +import VueApollo from 'vue-apollo'; +import createDefaultClient from '~/lib/graphql'; import issuableApp from './components/app.vue'; -import incidentTabs from './components/incident_tabs.vue'; +import incidentTabs from './components/incidents/incident_tabs.vue'; + +Vue.use(VueApollo); export default function initIssuableApp(issuableData = {}) { + const apolloProvider = new VueApollo({ + defaultClient: createDefaultClient(), + }); + + const { projectNamespace, projectPath, iid } = issuableData; + return new Vue({ el: document.getElementById('js-issuable-app'), + apolloProvider, components: { issuableApp, }, + provide: { + fullPath: `${projectNamespace}/${projectPath}`, + iid, + }, render(createElement) { return createElement('issuable-app', { props: { diff --git a/app/assets/javascripts/pages/admin/dev_ops_score/index.js b/app/assets/javascripts/pages/admin/dev_ops_report/index.js index 9d018408b88..643497003ba 100644 --- a/app/assets/javascripts/pages/admin/dev_ops_score/index.js +++ b/app/assets/javascripts/pages/admin/dev_ops_report/index.js @@ -1,6 +1,6 @@ import Vue from 'vue'; import UserCallout from '~/user_callout'; -import UsagePingDisabled from '~/admin/dev_ops_score/components/usage_ping_disabled.vue'; +import UsagePingDisabled from '~/admin/dev_ops_report/components/usage_ping_disabled.vue'; document.addEventListener('DOMContentLoaded', () => { // eslint-disable-next-line no-new diff --git a/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue b/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue index 589636c620b..aa53c5040e8 100644 --- a/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue +++ b/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue @@ -2,13 +2,11 @@ import { mapGetters } from 'vuex'; import { GlTooltipDirective, GlFriendlyWrap, GlIcon } from '@gitlab/ui'; import { __ } from '~/locale'; -import SmartVirtualList from '~/vue_shared/components/smart_virtual_list.vue'; export default { name: 'TestsSuiteTable', components: { GlIcon, - SmartVirtualList, GlFriendlyWrap, }, directives: { @@ -27,8 +25,6 @@ export default { return this.getSuiteTests.length > 0; }, }, - maxShownRows: 30, - typicalRowHeight: 75, wrapSymbols: ['::', '#', '.', '_', '-', '/', '\\'], }; </script> @@ -60,66 +56,60 @@ export default { </div> </div> - <smart-virtual-list - :length="getSuiteTests.length" - :remain="$options.maxShownRows" - :size="$options.typicalRowHeight" + <div + v-for="(testCase, index) in getSuiteTests" + :key="index" + class="gl-responsive-table-row rounded align-items-md-start mt-xs-3 js-case-row" > - <div - v-for="(testCase, index) in getSuiteTests" - :key="index" - class="gl-responsive-table-row rounded align-items-md-start mt-xs-3 js-case-row" - > - <div class="table-section section-20 section-wrap"> - <div role="rowheader" class="table-mobile-header">{{ __('Suite') }}</div> - <div class="table-mobile-content pr-md-1 gl-overflow-wrap-break"> - <gl-friendly-wrap :symbols="$options.wrapSymbols" :text="testCase.classname" /> - </div> + <div class="table-section section-20 section-wrap"> + <div role="rowheader" class="table-mobile-header">{{ __('Suite') }}</div> + <div class="table-mobile-content pr-md-1 gl-overflow-wrap-break"> + <gl-friendly-wrap :symbols="$options.wrapSymbols" :text="testCase.classname" /> </div> + </div> - <div class="table-section section-20 section-wrap"> - <div role="rowheader" class="table-mobile-header">{{ __('Name') }}</div> - <div class="table-mobile-content pr-md-1 gl-overflow-wrap-break"> - <gl-friendly-wrap - data-testid="caseName" - :symbols="$options.wrapSymbols" - :text="testCase.name" - /> - </div> + <div class="table-section section-20 section-wrap"> + <div role="rowheader" class="table-mobile-header">{{ __('Name') }}</div> + <div class="table-mobile-content pr-md-1 gl-overflow-wrap-break"> + <gl-friendly-wrap + data-testid="caseName" + :symbols="$options.wrapSymbols" + :text="testCase.name" + /> </div> + </div> - <div class="table-section section-10 section-wrap"> - <div role="rowheader" class="table-mobile-header">{{ __('Status') }}</div> - <div class="table-mobile-content text-center"> - <div - class="add-border ci-status-icon d-flex align-items-center justify-content-end justify-content-md-center" - :class="`ci-status-icon-${testCase.status}`" - > - <gl-icon :size="24" :name="testCase.icon" /> - </div> + <div class="table-section section-10 section-wrap"> + <div role="rowheader" class="table-mobile-header">{{ __('Status') }}</div> + <div class="table-mobile-content text-center"> + <div + class="add-border ci-status-icon d-flex align-items-center justify-content-end justify-content-md-center" + :class="`ci-status-icon-${testCase.status}`" + > + <gl-icon :size="24" :name="testCase.icon" /> </div> </div> + </div> - <div class="table-section flex-grow-1"> - <div role="rowheader" class="table-mobile-header">{{ __('Trace'), }}</div> - <div class="table-mobile-content"> - <pre - v-if="testCase.system_output" - class="build-trace build-trace-rounded text-left" - ><code class="bash p-0">{{testCase.system_output}}</code></pre> - </div> + <div class="table-section flex-grow-1"> + <div role="rowheader" class="table-mobile-header">{{ __('Trace'), }}</div> + <div class="table-mobile-content"> + <pre + v-if="testCase.system_output" + class="build-trace build-trace-rounded text-left" + ><code class="bash p-0">{{testCase.system_output}}</code></pre> </div> + </div> - <div class="table-section section-10 section-wrap"> - <div role="rowheader" class="table-mobile-header"> - {{ __('Duration') }} - </div> - <div class="table-mobile-content text-right pr-sm-1"> - {{ testCase.formattedTime }} - </div> + <div class="table-section section-10 section-wrap"> + <div role="rowheader" class="table-mobile-header"> + {{ __('Duration') }} + </div> + <div class="table-mobile-content text-right pr-sm-1"> + {{ testCase.formattedTime }} </div> </div> - </smart-virtual-list> + </div> </div> <div v-else> diff --git a/app/assets/javascripts/pipelines/components/test_reports/test_summary_table.vue b/app/assets/javascripts/pipelines/components/test_reports/test_summary_table.vue index e774fe06fbe..5f9c0be3ccc 100644 --- a/app/assets/javascripts/pipelines/components/test_reports/test_summary_table.vue +++ b/app/assets/javascripts/pipelines/components/test_reports/test_summary_table.vue @@ -2,13 +2,11 @@ import { mapGetters } from 'vuex'; import { GlIcon, GlTooltipDirective } from '@gitlab/ui'; import { s__ } from '~/locale'; -import SmartVirtualList from '~/vue_shared/components/smart_virtual_list.vue'; export default { name: 'TestsSummaryTable', components: { GlIcon, - SmartVirtualList, }, directives: { GlTooltip: GlTooltipDirective, @@ -31,8 +29,6 @@ export default { this.$emit('row-click', index); }, }, - maxShownRows: 20, - typicalRowHeight: 55, }; </script> @@ -69,83 +65,77 @@ export default { </div> </div> - <smart-virtual-list - :length="getTestSuites.length" - :remain="$options.maxShownRows" - :size="$options.typicalRowHeight" + <div + v-for="(testSuite, index) in getTestSuites" + :key="index" + role="row" + class="gl-responsive-table-row test-reports-summary-row rounded js-suite-row" + :class="{ + 'gl-responsive-table-row-clickable cursor-pointer': !testSuite.suite_error, + }" + @click="tableRowClick(index)" > - <div - v-for="(testSuite, index) in getTestSuites" - :key="index" - role="row" - class="gl-responsive-table-row test-reports-summary-row rounded js-suite-row" - :class="{ - 'gl-responsive-table-row-clickable cursor-pointer': !testSuite.suite_error, - }" - @click="tableRowClick(index)" - > - <div class="table-section section-25"> - <div role="rowheader" class="table-mobile-header font-weight-bold"> - {{ __('Suite') }} - </div> - <div class="table-mobile-content underline cgray pl-3"> - {{ testSuite.name }} - <gl-icon - v-if="testSuite.suite_error" - ref="suiteErrorIcon" - v-gl-tooltip - name="error" - :title="testSuite.suite_error" - class="vertical-align-middle" - /> - </div> + <div class="table-section section-25"> + <div role="rowheader" class="table-mobile-header font-weight-bold"> + {{ __('Suite') }} </div> + <div class="table-mobile-content underline cgray pl-3"> + {{ testSuite.name }} + <gl-icon + v-if="testSuite.suite_error" + ref="suiteErrorIcon" + v-gl-tooltip + name="error" + :title="testSuite.suite_error" + class="vertical-align-middle" + /> + </div> + </div> - <div class="table-section section-25"> - <div role="rowheader" class="table-mobile-header font-weight-bold"> - {{ __('Duration') }} - </div> - <div class="table-mobile-content text-md-left"> - {{ testSuite.formattedTime }} - </div> + <div class="table-section section-25"> + <div role="rowheader" class="table-mobile-header font-weight-bold"> + {{ __('Duration') }} + </div> + <div class="table-mobile-content text-md-left"> + {{ testSuite.formattedTime }} </div> + </div> - <div class="table-section section-10 text-center"> - <div role="rowheader" class="table-mobile-header font-weight-bold"> - {{ __('Failed') }} - </div> - <div class="table-mobile-content">{{ testSuite.failed_count }}</div> + <div class="table-section section-10 text-center"> + <div role="rowheader" class="table-mobile-header font-weight-bold"> + {{ __('Failed') }} </div> + <div class="table-mobile-content">{{ testSuite.failed_count }}</div> + </div> - <div class="table-section section-10 text-center"> - <div role="rowheader" class="table-mobile-header font-weight-bold"> - {{ __('Errors') }} - </div> - <div class="table-mobile-content">{{ testSuite.error_count }}</div> + <div class="table-section section-10 text-center"> + <div role="rowheader" class="table-mobile-header font-weight-bold"> + {{ __('Errors') }} </div> + <div class="table-mobile-content">{{ testSuite.error_count }}</div> + </div> - <div class="table-section section-10 text-center"> - <div role="rowheader" class="table-mobile-header font-weight-bold"> - {{ __('Skipped') }} - </div> - <div class="table-mobile-content">{{ testSuite.skipped_count }}</div> + <div class="table-section section-10 text-center"> + <div role="rowheader" class="table-mobile-header font-weight-bold"> + {{ __('Skipped') }} </div> + <div class="table-mobile-content">{{ testSuite.skipped_count }}</div> + </div> - <div class="table-section section-10 text-center"> - <div role="rowheader" class="table-mobile-header font-weight-bold"> - {{ __('Passed') }} - </div> - <div class="table-mobile-content">{{ testSuite.success_count }}</div> + <div class="table-section section-10 text-center"> + <div role="rowheader" class="table-mobile-header font-weight-bold"> + {{ __('Passed') }} </div> + <div class="table-mobile-content">{{ testSuite.success_count }}</div> + </div> - <div class="table-section section-10 text-right pr-md-3"> - <div role="rowheader" class="table-mobile-header font-weight-bold"> - {{ __('Total') }} - </div> - <div class="table-mobile-content">{{ testSuite.total_count }}</div> + <div class="table-section section-10 text-right pr-md-3"> + <div role="rowheader" class="table-mobile-header font-weight-bold"> + {{ __('Total') }} </div> + <div class="table-mobile-content">{{ testSuite.total_count }}</div> </div> - </smart-virtual-list> + </div> </div> <div v-else> diff --git a/app/assets/javascripts/sidebar/components/severity/constants.js b/app/assets/javascripts/sidebar/components/severity/constants.js new file mode 100644 index 00000000000..c7d6a51ea1c --- /dev/null +++ b/app/assets/javascripts/sidebar/components/severity/constants.js @@ -0,0 +1,43 @@ +import { __, s__ } from '~/locale'; + +export const INCIDENT_SEVERITY = { + CRITICAL: { + value: 'CRITICAL', + icon: 'critical', + label: s__('IncidentManagement|Critical - S1'), + }, + HIGH: { + value: 'HIGH', + icon: 'high', + label: s__('IncidentManagement|High - S2'), + }, + MEDIUM: { + value: 'MEDIUM', + icon: 'medium', + label: s__('IncidentManagement|Medium - S3'), + }, + LOW: { + value: 'LOW', + icon: 'low', + label: s__('IncidentManagement|Low - S4'), + }, + UNKNOWN: { + value: 'UNKNOWN', + icon: 'unknown', + label: s__('IncidentManagement|Unknown'), + }, +}; + +export const ISSUABLE_TYPES = { + INCIDENT: 'incident', +}; + +export const SIDEBAR_ANIMATION_DURATION = 300; + +export const I18N = { + UPDATE_SEVERITY_ERROR: s__('SeverityWidget|There was an error while updating severity.'), + TRY_AGAIN: __('Please try again'), + EDIT: __('Edit'), + SEVERITY: s__('SeverityWidget|Severity'), + SEVERITY_VALUE: s__('SeverityWidget|Severity: %{severity}'), +}; diff --git a/app/assets/javascripts/sidebar/components/severity/graphql/mutations/update_issuable_severity.mutation.graphql b/app/assets/javascripts/sidebar/components/severity/graphql/mutations/update_issuable_severity.mutation.graphql new file mode 100644 index 00000000000..750e757971f --- /dev/null +++ b/app/assets/javascripts/sidebar/components/severity/graphql/mutations/update_issuable_severity.mutation.graphql @@ -0,0 +1,9 @@ +mutation updateIssuableSeverity($projectPath: ID!, $severity: IssuableSeverity!, $iid: String!) { + issueSetSeverity(input: { iid: $iid, severity: $severity, projectPath: $projectPath }) { + errors + issue { + iid + severity + } + } +} diff --git a/app/assets/javascripts/sidebar/components/severity/severity.vue b/app/assets/javascripts/sidebar/components/severity/severity.vue new file mode 100644 index 00000000000..7e7d62256c9 --- /dev/null +++ b/app/assets/javascripts/sidebar/components/severity/severity.vue @@ -0,0 +1,42 @@ +<script> +import { GlIcon } from '@gitlab/ui'; + +export default { + components: { + GlIcon, + }, + props: { + severity: { + type: Object, + required: true, + validator(severity) { + const { value, label, icon } = severity; + return value && label && icon; + }, + }, + iconSize: { + type: Number, + required: false, + default: 12, + }, + iconOnly: { + type: Boolean, + required: false, + default: false, + }, + }, +}; +</script> + +<template> + <div + class="incident-severity gl-display-inline-flex gl-align-items-center gl-justify-content-between" + > + <gl-icon + :size="iconSize" + :name="`severity-${severity.icon}`" + :class="[`icon-${severity.icon}`, { 'gl-mr-3': !iconOnly }]" + /> + <span v-if="!iconOnly">{{ severity.label }}</span> + </div> +</template> diff --git a/app/assets/javascripts/sidebar/components/severity/sidebar_severity.vue b/app/assets/javascripts/sidebar/components/severity/sidebar_severity.vue new file mode 100644 index 00000000000..65ff7a6d2ac --- /dev/null +++ b/app/assets/javascripts/sidebar/components/severity/sidebar_severity.vue @@ -0,0 +1,195 @@ +<script> +import { + GlDropdown, + GlDropdownItem, + GlLoadingIcon, + GlTooltip, + GlSprintf, + GlLink, +} from '@gitlab/ui'; +import { INCIDENT_SEVERITY, ISSUABLE_TYPES, SIDEBAR_ANIMATION_DURATION, I18N } from './constants'; +import updateIssuableSeverity from './graphql/mutations/update_issuable_severity.mutation.graphql'; +import SeverityToken from './severity.vue'; +import createFlash from '~/flash'; + +export default { + i18n: I18N, + components: { + GlLoadingIcon, + GlTooltip, + GlSprintf, + GlDropdown, + GlDropdownItem, + GlLink, + SeverityToken, + }, + props: { + projectPath: { + type: String, + required: true, + }, + iid: { + type: String, + required: true, + }, + initialSeverity: { + type: String, + required: false, + default: INCIDENT_SEVERITY.UNKNOWN.value, + }, + issuableType: { + type: String, + required: false, + default: ISSUABLE_TYPES.INCIDENT, + validator: value => { + // currently severity is supported only for incidents, but this list might be extended + return [ISSUABLE_TYPES.INCIDENT].includes(value); + }, + }, + }, + data() { + return { + isDropdownShowing: false, + isUpdating: false, + severity: this.initialSeverity, + }; + }, + computed: { + severitiesList() { + switch (this.issuableType) { + case ISSUABLE_TYPES.INCIDENT: + return Object.values(INCIDENT_SEVERITY); + default: + return []; + } + }, + dropdownClass() { + return this.isDropdownShowing ? 'show' : 'gl-display-none'; + }, + selectedItem() { + return this.severitiesList.find(severity => severity.value === this.severity); + }, + }, + mounted() { + document.addEventListener('click', this.handleOffClick); + }, + beforeDestroy() { + document.removeEventListener('click', this.handleOffClick); + }, + methods: { + handleOffClick(event) { + if (!this.isDropdownShowing) { + return; + } + + if (!this.$refs.sidebarSeverity.contains(event.target)) { + this.hideDropdown(); + } + }, + hideDropdown() { + this.isDropdownShowing = false; + const event = new Event('hidden.gl.dropdown'); + this.$el.dispatchEvent(event); + }, + toggleFormDropdown(collapsedSidebar) { + this.isDropdownShowing = !this.isDropdownShowing; + const timeout = collapsedSidebar ? SIDEBAR_ANIMATION_DURATION : 0; + setTimeout(() => { + const { dropdown } = this.$refs; + if (dropdown && this.isDropdownShowing) { + dropdown.show(); + } + }, timeout); + }, + updateSeverity(value) { + this.hideDropdown(); + this.isUpdating = true; + this.$apollo + .mutate({ + mutation: updateIssuableSeverity, + variables: { + iid: this.iid, + severity: value, + projectPath: this.projectPath, + }, + }) + .then(resp => { + const { + data: { + issueSetSeverity: { + errors = [], + issue: { severity }, + }, + }, + } = resp; + + if (errors[0]) { + throw errors[0]; + } + this.severity = severity; + }) + .catch(() => + createFlash({ + message: `${this.$options.i18n.UPDATE_SEVERITY_ERROR} ${this.$options.i18n.TRY_AGAIN}`, + }), + ) + .finally(() => { + this.isUpdating = false; + }); + }, + }, +}; +</script> + +<template> + <div ref="sidebarSeverity" class="block"> + <div ref="severity" class="sidebar-collapsed-icon" @click="toggleFormDropdown(true)"> + <severity-token :severity="selectedItem" :icon-size="14" :icon-only="true" /> + <gl-tooltip :target="() => $refs.severity" boundary="viewport" placement="left"> + <gl-sprintf :message="$options.i18n.SEVERITY_VALUE"> + <template #severity> + {{ selectedItem.label }} + </template> + </gl-sprintf> + </gl-tooltip> + </div> + + <div class="hide-collapsed"> + <p class="title gl-display-flex gl-justify-content-space-between"> + {{ $options.i18n.SEVERITY }} + <gl-link + data-testid="editButton" + href="#" + @click="toggleFormDropdown" + @keydown.esc="hideDropdown" + > + {{ $options.i18n.EDIT }} + </gl-link> + </p> + + <gl-dropdown + ref="dropdown" + :class="dropdownClass" + block + :text="selectedItem.label" + toggle-class="dropdown-menu-toggle gl-mb-2" + @keydown.esc.native="hideDropdown" + > + <gl-dropdown-item + v-for="option in severitiesList" + :key="option.value" + data-testid="severityDropdownItem" + :is-check-item="true" + :is-checked="option.value === severity" + @click="updateSeverity(option.value)" + > + <severity-token :severity="option" /> + </gl-dropdown-item> + </gl-dropdown> + + <gl-loading-icon v-if="isUpdating" :inline="true" /> + + <severity-token v-else-if="!isDropdownShowing" :severity="selectedItem" /> + </div> + </div> +</template> diff --git a/app/assets/javascripts/sidebar/mount_sidebar.js b/app/assets/javascripts/sidebar/mount_sidebar.js index 015219200db..e7520cb096a 100644 --- a/app/assets/javascripts/sidebar/mount_sidebar.js +++ b/app/assets/javascripts/sidebar/mount_sidebar.js @@ -8,6 +8,7 @@ import SidebarMoveIssue from './lib/sidebar_move_issue'; import IssuableLockForm from './components/lock/issuable_lock_form.vue'; import sidebarParticipants from './components/participants/sidebar_participants.vue'; import sidebarSubscriptions from './components/subscriptions/sidebar_subscriptions.vue'; +import SidebarSeverity from './components/severity/sidebar_severity.vue'; import Translate from '../vue_shared/translate'; import createDefaultClient from '~/lib/graphql'; import { store } from '~/notes/stores'; @@ -159,6 +160,35 @@ function mountTimeTrackingComponent() { }); } +function mountSeverityComponent() { + const severityContainerEl = document.querySelector('#js-severity'); + + if (!severityContainerEl) { + return false; + } + const apolloProvider = new VueApollo({ + defaultClient: createDefaultClient(), + }); + + const { fullPath, iid, severity } = getSidebarOptions(); + + return new Vue({ + el: severityContainerEl, + apolloProvider, + components: { + SidebarSeverity, + }, + render: createElement => + createElement('sidebar-severity', { + props: { + projectPath: fullPath, + iid: String(iid), + initialSeverity: severity.toUpperCase(), + }, + }), + }); +} + export function mountSidebar(mediator) { mountAssigneesComponent(mediator); mountConfidentialComponent(mediator); @@ -173,6 +203,8 @@ export function mountSidebar(mediator) { ).init(); mountTimeTrackingComponent(); + + mountSeverityComponent(); } export { getSidebarOptions }; diff --git a/app/assets/stylesheets/_page_specific_files.scss b/app/assets/stylesheets/_page_specific_files.scss index b27602f6b4a..f706b615e7e 100644 --- a/app/assets/stylesheets/_page_specific_files.scss +++ b/app/assets/stylesheets/_page_specific_files.scss @@ -10,7 +10,7 @@ @import './pages/cycle_analytics'; @import './pages/deploy_keys'; @import './pages/detail_page'; -@import './pages/dev_ops_score'; +@import './pages/dev_ops_report'; @import './pages/diff'; @import './pages/editor'; @import './pages/environment_logs'; diff --git a/app/assets/stylesheets/pages/alert_management/severity-icons.scss b/app/assets/stylesheets/pages/alert_management/severity-icons.scss index 6004697b3e1..f58ad87a673 100644 --- a/app/assets/stylesheets/pages/alert_management/severity-icons.scss +++ b/app/assets/stylesheets/pages/alert_management/severity-icons.scss @@ -1,3 +1,4 @@ +.incident-severity, .incident-management-list, .alert-management-details { .icon-critical { diff --git a/app/assets/stylesheets/pages/dev_ops_score.scss b/app/assets/stylesheets/pages/dev_ops_report.scss index a6bc9b9332b..a6bc9b9332b 100644 --- a/app/assets/stylesheets/pages/dev_ops_score.scss +++ b/app/assets/stylesheets/pages/dev_ops_report.scss diff --git a/app/controllers/admin/dev_ops_score_controller.rb b/app/controllers/admin/dev_ops_report_controller.rb index 3e012e7d76b..bed0d51c331 100644 --- a/app/controllers/admin/dev_ops_score_controller.rb +++ b/app/controllers/admin/dev_ops_report_controller.rb @@ -1,13 +1,13 @@ # frozen_string_literal: true -class Admin::DevOpsScoreController < Admin::ApplicationController +class Admin::DevOpsReportController < Admin::ApplicationController include Analytics::UniqueVisitsHelper track_unique_visits :show, target_id: 'i_analytics_dev_ops_score' # rubocop: disable CodeReuse/ActiveRecord def show - @metric = DevOpsScore::Metric.order(:created_at).last&.present + @metric = DevOpsReport::Metric.order(:created_at).last&.present end # rubocop: enable CodeReuse/ActiveRecord end diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb index 0245c00aacb..6414792dd43 100644 --- a/app/controllers/admin/groups_controller.rb +++ b/app/controllers/admin/groups_controller.rb @@ -19,7 +19,7 @@ class Admin::GroupsController < Admin::ApplicationController # the Group with statistics). @group = Group.with_statistics.find(group&.id) @members = present_members( - @group.members.order("access_level DESC").page(params[:members_page])) + group_members.order("access_level DESC").page(params[:members_page])) @requesters = present_members( AccessRequestsFinder.new(@group).execute(current_user)) @projects = @group.projects.with_statistics.page(params[:projects_page]) @@ -82,6 +82,10 @@ class Admin::GroupsController < Admin::ApplicationController @group ||= Group.find_by_full_path(params[:id]) end + def group_members + @group.members + end + def group_params params.require(:group).permit(allowed_group_params) end diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb index a558b01f0c6..b798d6680bc 100644 --- a/app/controllers/omniauth_callbacks_controller.rb +++ b/app/controllers/omniauth_callbacks_controller.rb @@ -83,6 +83,10 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController end end + def atlassian_oauth2 + omniauth_flow(Gitlab::Auth::Atlassian) + end + private def log_failed_login(user, provider) diff --git a/app/controllers/profiles/accounts_controller.rb b/app/controllers/profiles/accounts_controller.rb index 95e055a44db..b19285e98bb 100644 --- a/app/controllers/profiles/accounts_controller.rb +++ b/app/controllers/profiles/accounts_controller.rb @@ -7,10 +7,9 @@ class Profiles::AccountsController < Profiles::ApplicationController render(locals: show_view_variables) end - # rubocop: disable CodeReuse/ActiveRecord def unlink provider = params[:provider] - identity = current_user.identities.find_by(provider: provider) + identity = find_identity(provider) return render_404 unless identity @@ -22,13 +21,18 @@ class Profiles::AccountsController < Profiles::ApplicationController redirect_to profile_account_path end - # rubocop: enable CodeReuse/ActiveRecord private def show_view_variables {} end + + def find_identity(provider) + return current_user.atlassian_identity if provider == 'atlassian_oauth2' + + current_user.identities.find_by(provider: provider) # rubocop: disable CodeReuse/ActiveRecord + end end Profiles::AccountsController.prepend_if_ee('EE::Profiles::AccountsController') diff --git a/app/controllers/projects/static_site_editor_controller.rb b/app/controllers/projects/static_site_editor_controller.rb index 9ec50ff8196..3251814bac8 100644 --- a/app/controllers/projects/static_site_editor_controller.rb +++ b/app/controllers/projects/static_site_editor_controller.rb @@ -14,7 +14,13 @@ class Projects::StaticSiteEditorController < Projects::ApplicationController end def show - @config = Gitlab::StaticSiteEditor::Config.new(@repository, @ref, @path, params[:return_url]) + config = Gitlab::StaticSiteEditor::Config::CombinedConfig.new( + @repository, + @ref, + @path, + params[:return_url] + ) + @data = config.data end private diff --git a/app/finders/group_members_finder.rb b/app/finders/group_members_finder.rb index a4b00588368..ce0d52ad97a 100644 --- a/app/finders/group_members_finder.rb +++ b/app/finders/group_members_finder.rb @@ -27,7 +27,7 @@ class GroupMembersFinder < UnionFinder relations << group_members if include_relations.include?(:direct) if include_relations.include?(:inherited) && group.parent - parents_members = GroupMember.non_request + parents_members = GroupMember.non_request.non_minimal_access .where(source_id: group.ancestors.select(:id)) .where.not(user_id: group.users.select(:id)) @@ -35,7 +35,7 @@ class GroupMembersFinder < UnionFinder end if include_relations.include?(:descendants) - descendant_members = GroupMember.non_request + descendant_members = GroupMember.non_request.non_minimal_access .where(source_id: group.descendants.select(:id)) .where.not(user_id: group.users.select(:id)) diff --git a/app/finders/members_finder.rb b/app/finders/members_finder.rb index ce9137f91bb..013ed03a789 100644 --- a/app/finders/members_finder.rb +++ b/app/finders/members_finder.rb @@ -63,7 +63,7 @@ class MembersFinder def direct_group_members(include_descendants) requested_relations = [:inherited, :direct] requested_relations << :descendants if include_descendants - GroupMembersFinder.new(group).execute(include_relations: requested_relations).non_invite # rubocop: disable CodeReuse/Finder + GroupMembersFinder.new(group).execute(include_relations: requested_relations).non_invite.non_minimal_access # rubocop: disable CodeReuse/Finder end def project_invited_groups_members @@ -73,7 +73,7 @@ class MembersFinder .public_or_visible_to_user(current_user) .select(:id) - GroupMember.with_source_id(invited_groups_ids_including_ancestors) + GroupMember.with_source_id(invited_groups_ids_including_ancestors).non_minimal_access end def distinct_union_of_members(union_members) diff --git a/app/helpers/auth_helper.rb b/app/helpers/auth_helper.rb index a57e27d23c8..7f8cb66a84f 100644 --- a/app/helpers/auth_helper.rb +++ b/app/helpers/auth_helper.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module AuthHelper - PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2 facebook azure_oauth2 authentiq salesforce).freeze + PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2 facebook azure_oauth2 authentiq salesforce atlassian_oauth2).freeze LDAP_PROVIDER = /\Aldap/.freeze def ldap_enabled? @@ -133,6 +133,8 @@ module AuthHelper # rubocop: disable CodeReuse/ActiveRecord def auth_active?(provider) + return current_user.atlassian_identity.present? if provider == :atlassian_oauth2 + current_user.identities.exists?(provider: provider.to_s) end # rubocop: enable CodeReuse/ActiveRecord diff --git a/app/helpers/dev_ops_score_helper.rb b/app/helpers/dev_ops_report_helper.rb index 9a673998149..ab7e56fc1a2 100644 --- a/app/helpers/dev_ops_score_helper.rb +++ b/app/helpers/dev_ops_report_helper.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module DevOpsScoreHelper +module DevOpsReportHelper def score_level(score) if score < 33.33 'low' diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb index 398e76b6697..54fa3ca57b8 100644 --- a/app/helpers/issuables_helper.rb +++ b/app/helpers/issuables_helper.rb @@ -294,7 +294,8 @@ module IssuablesHelper hasClosingMergeRequest: issuable.merge_requests_count(current_user) != 0, issueType: issuable.issue_type, zoomMeetingUrl: ZoomMeeting.canonical_meeting_url(issuable), - sentryIssueIdentifier: SentryIssue.find_by(issue: issuable)&.sentry_issue_identifier # rubocop:disable CodeReuse/ActiveRecord + sentryIssueIdentifier: SentryIssue.find_by(issue: issuable)&.sentry_issue_identifier, # rubocop:disable CodeReuse/ActiveRecord + iid: issuable.iid.to_s } end @@ -465,6 +466,7 @@ module IssuablesHelper rootPath: root_path, fullPath: issuable[:project_full_path], iid: issuable[:iid], + severity: issuable[:severity], timeTrackingLimitToHours: Gitlab::CurrentSettings.time_tracking_limit_to_hours } end diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb index ae9612308e4..2318596c63a 100644 --- a/app/helpers/nav_helper.rb +++ b/app/helpers/nav_helper.rb @@ -63,7 +63,7 @@ module NavHelper end def admin_analytics_nav_links - %w(dev_ops_score cohorts) + %w(dev_ops_report cohorts) end def group_issues_sub_menu_items diff --git a/app/helpers/system_note_helper.rb b/app/helpers/system_note_helper.rb index 4bbfa499919..0227ad1092d 100644 --- a/app/helpers/system_note_helper.rb +++ b/app/helpers/system_note_helper.rb @@ -7,7 +7,7 @@ module SystemNoteHelper 'description' => 'pencil-square', 'merge' => 'git-merge', 'merged' => 'git-merge', - 'opened' => 'issue-open', + 'opened' => 'issues', 'closed' => 'issue-close', 'time_tracking' => 'timer', 'assignee' => 'user', diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index 09b1dbaba58..888e1b384a2 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -185,6 +185,10 @@ module Issuable is_a?(TimeTrackable) && !incident? end + def supports_severity? + incident? + end + def incident? is_a?(Issue) && super end diff --git a/app/models/concerns/loaded_in_group_list.rb b/app/models/concerns/loaded_in_group_list.rb index 79ff82d9f99..e624b9aa356 100644 --- a/app/models/concerns/loaded_in_group_list.rb +++ b/app/models/concerns/loaded_in_group_list.rb @@ -54,6 +54,7 @@ module LoadedInGroupList .where(members[:source_type].eq(Namespace.name)) .where(members[:source_id].eq(namespaces[:id])) .where(members[:requested_at].eq(nil)) + .where(members[:access_level].gt(Gitlab::Access::MINIMAL_ACCESS)) end end @@ -70,7 +71,7 @@ module LoadedInGroupList end def member_count - @member_count ||= try(:preloaded_member_count) || users.count + @member_count ||= try(:preloaded_member_count) || members.count end end diff --git a/app/models/dev_ops_score/card.rb b/app/models/dev_ops_report/card.rb index b1894cf4138..4060cb1e5b6 100644 --- a/app/models/dev_ops_score/card.rb +++ b/app/models/dev_ops_report/card.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module DevOpsScore +module DevOpsReport class Card attr_accessor :metric, :title, :description, :feature, :blog, :docs diff --git a/app/models/dev_ops_score/idea_to_production_step.rb b/app/models/dev_ops_report/idea_to_production_step.rb index d892793cf97..2503d5949e5 100644 --- a/app/models/dev_ops_score/idea_to_production_step.rb +++ b/app/models/dev_ops_report/idea_to_production_step.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module DevOpsScore +module DevOpsReport class IdeaToProductionStep attr_accessor :metric, :title, :features diff --git a/app/models/dev_ops_score/metric.rb b/app/models/dev_ops_report/metric.rb index a9133128ce9..14eff725433 100644 --- a/app/models/dev_ops_score/metric.rb +++ b/app/models/dev_ops_report/metric.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module DevOpsScore +module DevOpsReport class Metric < ApplicationRecord include Presentable diff --git a/app/models/group.rb b/app/models/group.rb index f8cbaa2495c..5c6e946b02e 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -20,8 +20,10 @@ class Group < Namespace UpdateSharedRunnersError = Class.new(StandardError) - has_many :group_members, -> { where(requested_at: nil) }, dependent: :destroy, as: :source # rubocop:disable Cop/ActiveRecordDependent + has_many :all_group_members, -> { where(requested_at: nil) }, dependent: :destroy, as: :source, class_name: 'GroupMember' # rubocop:disable Cop/ActiveRecordDependent + has_many :group_members, -> { where(requested_at: nil).where.not(members: { access_level: Gitlab::Access::MINIMAL_ACCESS }) }, dependent: :destroy, as: :source # rubocop:disable Cop/ActiveRecordDependent alias_method :members, :group_members + has_many :users, through: :group_members has_many :owners, -> { where(members: { access_level: Gitlab::Access::OWNER }) }, @@ -395,6 +397,10 @@ class Group < Namespace ]) end + def users_count + members.count + end + # Returns all users that are members of projects # belonging to the current group or sub-groups def project_users_with_descendants @@ -630,6 +636,7 @@ class Group < Namespace .where(group_member_table[:requested_at].eq(nil)) .where(group_member_table[:source_id].eq(group_group_link_table[:shared_with_group_id])) .where(group_member_table[:source_type].eq('Namespace')) + .non_minimal_access end def smallest_value_arel(args, column_alias) diff --git a/app/models/member.rb b/app/models/member.rb index 55bb78b7f94..5a084a3a2e6 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -25,7 +25,6 @@ class Member < ApplicationRecord validates :user_id, uniqueness: { scope: [:source_type, :source_id], message: "already exists in source", allow_nil: true } - validates :access_level, inclusion: { in: Gitlab::Access.all_values }, presence: true validate :higher_access_level_than_group, unless: :importing? validates :invite_email, presence: { @@ -60,6 +59,7 @@ class Member < ApplicationRecord left_join_users .where(user_ok) .where(requested_at: nil) + .non_minimal_access .reorder(nil) end @@ -68,6 +68,8 @@ class Member < ApplicationRecord left_join_users .where(users: { state: 'active' }) .non_request + .non_invite + .non_minimal_access .reorder(nil) end @@ -85,6 +87,7 @@ class Member < ApplicationRecord scope :developers, -> { active.where(access_level: DEVELOPER) } scope :maintainers, -> { active.where(access_level: MAINTAINER) } scope :non_guests, -> { where('members.access_level > ?', GUEST) } + scope :non_minimal_access, -> { where('members.access_level > ?', MINIMAL_ACCESS) } scope :owners, -> { active.where(access_level: OWNER) } scope :owners_and_maintainers, -> { active.where(access_level: [OWNER, MAINTAINER]) } scope :with_user, -> (user) { where(user: user) } diff --git a/app/models/members/group_member.rb b/app/models/members/group_member.rb index 8c224dea88f..34958936c9f 100644 --- a/app/models/members/group_member.rb +++ b/app/models/members/group_member.rb @@ -13,6 +13,9 @@ class GroupMember < Member # Make sure group member points only to group as it source default_value_for :source_type, SOURCE_TYPE validates :source_type, format: { with: /\ANamespace\z/ } + validates :access_level, presence: true + validate :access_level_inclusion + default_scope { where(source_type: SOURCE_TYPE) } # rubocop:disable Cop/DefaultScope scope :of_groups, ->(groups) { where(source_id: groups.select(:id)) } @@ -45,6 +48,12 @@ class GroupMember < Member private + def access_level_inclusion + return if access_level.in?(Gitlab::Access.all_values) + + errors.add(:access_level, "is not included in the list") + end + def send_invite run_after_commit_or_now { notification_service.invite_group_member(self, @raw_invite_token) } diff --git a/app/models/user.rb b/app/models/user.rb index 9c4af91ad7e..9b8fe4881ad 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -120,7 +120,7 @@ class User < ApplicationRecord # Groups has_many :members - has_many :group_members, -> { where(requested_at: nil) }, source: 'GroupMember' + has_many :group_members, -> { where(requested_at: nil).where("access_level >= ?", Gitlab::Access::GUEST) }, source: 'GroupMember' has_many :groups, through: :group_members has_many :owned_groups, -> { where(members: { access_level: Gitlab::Access::OWNER }) }, through: :group_members, source: :group has_many :maintainers_groups, -> { where(members: { access_level: Gitlab::Access::MAINTAINER }) }, through: :group_members, source: :group diff --git a/app/presenters/dev_ops_score/metric_presenter.rb b/app/presenters/dev_ops_score/metric_presenter.rb index d22beefee54..e7363293435 100644 --- a/app/presenters/dev_ops_score/metric_presenter.rb +++ b/app/presenters/dev_ops_score/metric_presenter.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module DevOpsScore +module DevOpsReport class MetricPresenter < Gitlab::View::Presenter::Simple def cards [ diff --git a/app/serializers/issuable_sidebar_basic_entity.rb b/app/serializers/issuable_sidebar_basic_entity.rb index 11df60ade70..53c123c06fd 100644 --- a/app/serializers/issuable_sidebar_basic_entity.rb +++ b/app/serializers/issuable_sidebar_basic_entity.rb @@ -105,6 +105,7 @@ class IssuableSidebarBasicEntity < Grape::Entity expose :supports_time_tracking?, as: :supports_time_tracking expose :supports_milestone?, as: :supports_milestone + expose :supports_severity?, as: :supports_severity private diff --git a/app/serializers/issue_sidebar_basic_entity.rb b/app/serializers/issue_sidebar_basic_entity.rb index 165dc462cfe..e9e05718af9 100644 --- a/app/serializers/issue_sidebar_basic_entity.rb +++ b/app/serializers/issue_sidebar_basic_entity.rb @@ -3,6 +3,7 @@ class IssueSidebarBasicEntity < IssuableSidebarBasicEntity expose :due_date expose :confidential + expose :severity end IssueSidebarBasicEntity.prepend_if_ee('EE::IssueSidebarBasicEntity') diff --git a/app/services/submit_usage_ping_service.rb b/app/services/submit_usage_ping_service.rb index 9191943caa7..2fbeaf4405c 100644 --- a/app/services/submit_usage_ping_service.rb +++ b/app/services/submit_usage_ping_service.rb @@ -51,11 +51,11 @@ class SubmitUsagePingService end def store_metrics(response) - metrics = response['conv_index'] || response['dev_ops_score'] + metrics = response['conv_index'] || response['dev_ops_score'] # leaving dev_ops_score here, as the response data comes from the gitlab-version-com return unless metrics.present? - DevOpsScore::Metric.create!( + DevOpsReport::Metric.create!( metrics.slice(*METRICS) ) end diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml index b6ac5db4d2d..4acfc96caf2 100644 --- a/app/views/admin/dashboard/index.html.haml +++ b/app/views/admin/dashboard/index.html.haml @@ -17,37 +17,34 @@ .well-segment.well-centered = link_to admin_projects_path do %h3.text-center - Projects: - = approximate_count_with_delimiters(@counts, Project) + = s_('AdminArea|Projects: %{number_of_projects}') % { number_of_projects: approximate_count_with_delimiters(@counts, Project) } %hr - = link_to('New project', new_project_path, class: "btn btn-success gl-w-full") + = link_to(s_('AdminArea|New project'), new_project_path, class: "btn btn-success gl-w-full") .col-sm-4 .info-well.dark-well .well-segment.well-centered = link_to admin_users_path do %h3.text-center - Users: - = approximate_count_with_delimiters(@counts, User) + = s_('AdminArea|Users: %{number_of_users}') % { number_of_users: approximate_count_with_delimiters(@counts, User) } %hr .btn-group.d-flex{ role: 'group' } - = link_to 'New user', new_admin_user_path, class: "btn btn-success gl-w-full" + = link_to s_('AdminArea|New user'), new_admin_user_path, class: "btn btn-success gl-w-full" = link_to s_('AdminArea|Users statistics'), admin_dashboard_stats_path, class: 'btn btn-primary gl-w-full' .col-sm-4 .info-well.dark-well .well-segment.well-centered = link_to admin_groups_path do %h3.text-center - Groups: - = approximate_count_with_delimiters(@counts, Group) + = s_('AdminArea|Groups: %{number_of_groups}') % { number_of_groups: approximate_count_with_delimiters(@counts, Group) } %hr - = link_to 'New group', new_admin_group_path, class: "btn btn-success gl-w-full" + = link_to s_('AdminArea|New group'), new_admin_group_path, class: "btn btn-success gl-w-full" .row .col-md-4 #js-admin-statistics-container .col-md-4 .info-well .well-segment.admin-well.admin-well-features - %h4 Features + %h4= s_('AdminArea|Features') = feature_entry(_('Sign up'), href: general_admin_application_settings_path(anchor: 'js-signup-settings'), enabled: allow_signup?) @@ -87,42 +84,41 @@ .info-well .well-segment.admin-well %h4 - Components + = s_('AdminArea|Components') - if Gitlab::CurrentSettings.version_check_enabled .float-right = version_status_badge %p - %a{ href: general_admin_application_settings_path } - GitLab + = link_to _('GitLab'), general_admin_application_settings_path %span.float-right = Gitlab::VERSION = "(#{Gitlab.revision})" %p - GitLab Shell + = _('GitLab Shell') %span.float-right = Gitlab::Shell.version %p - GitLab Workhorse + = _('GitLab Workhorse') %span.float-right = gitlab_workhorse_version %p - GitLab API + = _('GitLab API') %span.float-right = API::API::version - if Gitlab.config.pages.enabled %p - GitLab Pages + = _('GitLab Pages') %span.float-right = Gitlab::Pages::VERSION = render_if_exists 'admin/dashboard/geo' %p - Ruby + = _('Ruby') %span.float-right #{RUBY_VERSION}p#{RUBY_PATCHLEVEL} %p - Rails + = _('Rails') %span.float-right #{Rails::VERSION::STRING} %p @@ -130,12 +126,12 @@ %span.float-right = Gitlab::Database.version %p - = link_to "Gitaly Servers", admin_gitaly_servers_path + = link_to _("Gitaly Servers"), admin_gitaly_servers_path .row .col-md-4 .info-well .well-segment.admin-well - %h4 Latest projects + %h4= s_('AdminArea|Latest projects') - @projects.each do |project| %p = link_to project.full_name, admin_project_path(project), class: 'str-truncated-60' @@ -144,7 +140,7 @@ .col-md-4 .info-well .well-segment.admin-well - %h4 Latest users + %h4= s_('AdminArea|Latest users') - @users.each do |user| %p = link_to [:admin, user], class: 'str-truncated-60' do @@ -154,7 +150,7 @@ .col-md-4 .info-well .well-segment.admin-well - %h4 Latest groups + %h4= s_('AdminArea|Latest groups') - @groups.each do |group| %p = link_to [:admin, group], class: 'str-truncated-60' do diff --git a/app/views/admin/dev_ops_score/_callout.html.haml b/app/views/admin/dev_ops_report/_callout.html.haml index 1b50c27834d..220456a4295 100644 --- a/app/views/admin/dev_ops_score/_callout.html.haml +++ b/app/views/admin/dev_ops_report/_callout.html.haml @@ -1,5 +1,5 @@ .gl-mt-3 -.user-callout{ data: { uid: 'dev_ops_score_intro_callout_dismissed' } } +.user-callout{ data: { uid: 'dev_ops_report_intro_callout_dismissed' } } .bordered-box.landing.content-block %button.btn.btn-default.close.js-close-callout{ type: 'button', 'aria-label' => _('Dismiss DevOps Report introduction') } @@ -10,4 +10,4 @@ %p = _('Your DevOps Report gives an overview of how you are using GitLab from a feature perspective. View how you compare with other organizations, discover features you are not using, and learn best practices through blog posts and white papers.') .svg-container.devops - = custom_icon('dev_ops_score_overview') + = custom_icon('dev_ops_report_overview') diff --git a/app/views/admin/dev_ops_score/_card.html.haml b/app/views/admin/dev_ops_report/_card.html.haml index dd6e5c0f108..dd6e5c0f108 100644 --- a/app/views/admin/dev_ops_score/_card.html.haml +++ b/app/views/admin/dev_ops_report/_card.html.haml diff --git a/app/views/admin/dev_ops_score/_no_data.html.haml b/app/views/admin/dev_ops_report/_no_data.html.haml index 8ea3797b1cc..585aa878b0b 100644 --- a/app/views/admin/dev_ops_score/_no_data.html.haml +++ b/app/views/admin/dev_ops_report/_no_data.html.haml @@ -1,6 +1,6 @@ .container.devops-empty .col-sm-12.justify-content-center.text-center - = custom_icon('dev_ops_score_no_data') + = custom_icon('dev_ops_report_no_data') %h4= _('Data is still calculating...') %p = _('In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index.') diff --git a/app/views/admin/dev_ops_score/show.html.haml b/app/views/admin/dev_ops_report/show.html.haml index 3a7fb9d7c8c..57d80bc8c85 100644 --- a/app/views/admin/dev_ops_score/show.html.haml +++ b/app/views/admin/dev_ops_report/show.html.haml @@ -2,7 +2,7 @@ - usage_ping_enabled = Gitlab::CurrentSettings.usage_ping_enabled .container - - if usage_ping_enabled && show_callout?('dev_ops_score_intro_callout_dismissed') + - if usage_ping_enabled && show_callout?('dev_ops_report_intro_callout_dismissed') = render 'callout' .gl-mt-3 diff --git a/app/views/admin/groups/_group.html.haml b/app/views/admin/groups/_group.html.haml index ab817b2ef6e..3a82f3803bd 100644 --- a/app/views/admin/groups/_group.html.haml +++ b/app/views/admin/groups/_group.html.haml @@ -27,7 +27,7 @@ %span.gl-ml-5 = sprite_icon('users', css_class: 'gl-vertical-align-text-bottom') - = number_with_delimiter(group.users.count) + = number_with_delimiter(group.users_count) %span.gl-ml-5.visibility-icon.has-tooltip{ data: { container: 'body', placement: 'left' }, title: visibility_icon_description(group) } = visibility_level_icon(group.visibility_level) diff --git a/app/views/layouts/nav/sidebar/_admin.html.haml b/app/views/layouts/nav/sidebar/_admin.html.haml index 960a4a93019..cb5277c02f0 100644 --- a/app/views/layouts/nav/sidebar/_admin.html.haml +++ b/app/views/layouts/nav/sidebar/_admin.html.haml @@ -49,7 +49,7 @@ = _('Gitaly Servers') = nav_link(controller: admin_analytics_nav_links) do - = link_to admin_dev_ops_score_path, data: { qa_selector: 'admin_analytics_link' } do + = link_to admin_dev_ops_report_path, data: { qa_selector: 'admin_analytics_link' } do .nav-icon-container = sprite_icon('chart') %span.nav-item-name @@ -57,12 +57,12 @@ %ul.sidebar-sub-level-items{ data: { qa_selector: 'admin_sidebar_analytics_submenu_content' } } = nav_link(controller: admin_analytics_nav_links, html_options: { class: "fly-out-top-item" }) do - = link_to admin_dev_ops_score_path do + = link_to admin_dev_ops_report_path do %strong.fly-out-top-item-name = _('Analytics') %li.divider.fly-out-top-item - = nav_link(controller: :dev_ops_score) do - = link_to admin_dev_ops_score_path, title: _('DevOps Report') do + = nav_link(controller: :dev_ops_report) do + = link_to admin_dev_ops_report_path, title: _('DevOps Report') do %span = _('DevOps Report') = nav_link(controller: :cohorts) do diff --git a/app/views/projects/static_site_editor/show.html.haml b/app/views/projects/static_site_editor/show.html.haml index 2d817912335..cbe27cefba3 100644 --- a/app/views/projects/static_site_editor/show.html.haml +++ b/app/views/projects/static_site_editor/show.html.haml @@ -1 +1 @@ -#static-site-editor{ data: @config.payload.merge({ merge_requests_illustration_path: image_path('illustrations/merge_requests.svg') }) } +#static-site-editor{ data: @data } diff --git a/app/views/shared/icons/_dev_ops_score_no_data.svg b/app/views/shared/icons/_dev_ops_report_no_data.svg index 5de929859ae..5de929859ae 100644 --- a/app/views/shared/icons/_dev_ops_score_no_data.svg +++ b/app/views/shared/icons/_dev_ops_report_no_data.svg diff --git a/app/views/shared/icons/_dev_ops_score_no_index.svg b/app/views/shared/icons/_dev_ops_report_no_index.svg index 0577efca93f..0577efca93f 100644 --- a/app/views/shared/icons/_dev_ops_score_no_index.svg +++ b/app/views/shared/icons/_dev_ops_report_no_index.svg diff --git a/app/views/shared/icons/_dev_ops_score_overview.svg b/app/views/shared/icons/_dev_ops_report_overview.svg index 2f31113bad7..2f31113bad7 100644 --- a/app/views/shared/icons/_dev_ops_score_overview.svg +++ b/app/views/shared/icons/_dev_ops_report_overview.svg diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml index dc985f96e3f..28bf64841fc 100644 --- a/app/views/shared/issuable/_sidebar.html.haml +++ b/app/views/shared/issuable/_sidebar.html.haml @@ -133,6 +133,9 @@ = render_if_exists 'shared/issuable/sidebar_weight', issuable_sidebar: issuable_sidebar + - if issuable_sidebar[:supports_severity] + #js-severity + - if issuable_sidebar.dig(:features_available, :health_status) .js-sidebar-status-entry-point |