Read about our upcoming Code of Conduct on this issue

Commit 11d8bca1 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 85e2c1e3b4c1
image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.5-golang-1.12-git-2.24-lfs-2.9-chrome-73.0-node-12.x-yarn-1.16-postgresql-9.6-graphicsmagick-1.3.33"
image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.5-golang-1.12-git-2.24-lfs-2.9-chrome-73.0-node-12.x-yarn-1.16-postgresql-9.6-graphicsmagick-1.3.34"
stages:
- sync
......
......@@ -78,7 +78,7 @@
- .default-retry
- .default-before_script
- .assets-compile-cache
image: registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.5-git-2.24-lfs-2.9-chrome-73.0-node-12.x-yarn-1.16-graphicsmagick-1.3.33-docker-19.03.1
image: registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.5-git-2.24-lfs-2.9-chrome-73.0-node-12.x-yarn-1.16-graphicsmagick-1.3.34-docker-19.03.1
stage: prepare
services:
- docker:19.03.0-dind
......
......@@ -203,7 +203,7 @@
- name: redis:alpine
.use-pg10:
image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.5-golang-1.12-git-2.24-lfs-2.9-chrome-73.0-node-12.x-yarn-1.16-postgresql-10-graphicsmagick-1.3.33"
image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.5-golang-1.12-git-2.24-lfs-2.9-chrome-73.0-node-12.x-yarn-1.16-postgresql-10-graphicsmagick-1.3.34"
services:
- name: postgres:10.9
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
......@@ -217,7 +217,7 @@
- name: elasticsearch:6.4.2
.use-pg10-ee:
image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.5-golang-1.12-git-2.24-lfs-2.9-chrome-73.0-node-12.x-yarn-1.16-postgresql-10-graphicsmagick-1.3.33"
image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.5-golang-1.12-git-2.24-lfs-2.9-chrome-73.0-node-12.x-yarn-1.16-postgresql-10-graphicsmagick-1.3.34"
services:
- name: postgres:10.9
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
......
......@@ -374,7 +374,7 @@ export default {
<div
:data-can-create-note="getNoteableData.current_user.can_create_note"
class="files d-flex prepend-top-default"
class="files d-flex"
>
<div
v-show="showTreeList"
......
<script>
/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
import { mapActions, mapGetters, mapState } from 'vuex';
import { GlTooltipDirective, GlLink, GlButton } from '@gitlab/ui';
import { __ } from '~/locale';
......@@ -63,9 +62,6 @@ export default {
showDropdowns() {
return !this.commit && this.mergeRequestDiffs.length;
},
fileTreeIcon() {
return this.showTreeList ? 'collapse-left' : 'expand-left';
},
toggleFileBrowserTitle() {
return this.showTreeList ? __('Hide file browser') : __('Show file browser');
},
......@@ -91,7 +87,7 @@ export default {
</script>
<template>
<div class="mr-version-controls border-top border-bottom">
<div class="mr-version-controls border-top">
<div
class="mr-version-menus-container content-block"
:class="{
......@@ -108,17 +104,17 @@ export default {
:title="toggleFileBrowserTitle"
@click="toggleShowTreeList"
>
<icon :name="fileTreeIcon" />
<icon name="file-tree" />
</button>
<div v-if="showDropdowns" class="d-flex align-items-center compare-versions-container">
Changes between
{{ __('Compare') }}
<compare-versions-dropdown
:other-versions="mergeRequestDiffs"
:merge-request-version="mergeRequestDiff"
:show-commit-count="true"
class="mr-version-dropdown"
/>
and
{{ __('and') }}
<compare-versions-dropdown
:other-versions="comparableDiffs"
:base-version-path="baseVersionPath"
......
......@@ -224,7 +224,7 @@ export default {
<div
v-if="!diffFile.submodule && addMergeRequestButtons"
class="file-actions d-none d-sm-block"
class="file-actions d-none d-sm-flex align-items-center flex-wrap"
>
<diff-stats :added-lines="diffFile.added_lines" :removed-lines="diffFile.removed_lines" />
<div class="btn-group" role="group">
......
......@@ -22,7 +22,7 @@ export default {
},
computed: {
filesText() {
return n__('File', 'Files', this.diffFilesLength);
return n__('file', 'files', this.diffFilesLength);
},
isCompareVersionsHeader() {
return Boolean(this.diffFilesLength);
......@@ -44,13 +44,21 @@ export default {
>
<div v-if="hasDiffFiles" class="diff-stats-group">
<icon name="doc-code" class="diff-stats-icon text-secondary" />
<strong>{{ diffFilesLength }} {{ filesText }}</strong>
<span class="text-secondary bold">{{ diffFilesLength }} {{ filesText }}</span>
</div>
<div class="diff-stats-group cgreen">
<icon name="file-addition" class="diff-stats-icon" /> <strong>{{ addedLines }}</strong>
<div
class="diff-stats-group cgreen d-flex align-items-center"
:class="{ bold: isCompareVersionsHeader }"
>
<span>+</span>
<span class="js-file-addition-line">{{ addedLines }}</span>
</div>
<div class="diff-stats-group cred">
<icon name="file-deletion" class="diff-stats-icon" /> <strong>{{ removedLines }}</strong>
<div
class="diff-stats-group cred d-flex align-items-center"
:class="{ bold: isCompareVersionsHeader }"
>
<span>-</span>
<span class="js-file-deletion-line">{{ removedLines }}</span>
</div>
</div>
</template>
......@@ -58,8 +58,8 @@ export default {
this.search = '';
},
},
searchPlaceholder: sprintf(s__('MergeRequest|Filter files or search with %{modifier_key}+p'), {
modifier_key: /Mac/i.test(navigator.userAgent) ? 'cmd' : 'ctrl',
searchPlaceholder: sprintf(s__('MergeRequest|Search files (%{modifier_key}P)'), {
modifier_key: /Mac/i.test(navigator.userAgent) ? '' : 'Ctrl+',
}),
};
</script>
......
......@@ -54,10 +54,6 @@ export default {
type: String,
required: true,
},
issueDetailsPath: {
type: String,
required: true,
},
issueStackTracePath: {
type: String,
required: true,
......@@ -72,7 +68,7 @@ export default {
},
},
apollo: {
GQLerror: {
error: {
query,
variables() {
return {
......@@ -81,19 +77,19 @@ export default {
};
},
pollInterval: 2000,
update: data => data.project.sentryDetailedError,
update: data => data.project.sentryErrors.detailedError,
error: () => createFlash(__('Failed to load error details from Sentry.')),
result(res) {
if (res.data.project?.sentryDetailedError) {
this.$apollo.queries.GQLerror.stopPolling();
this.setStatus(this.GQLerror.status);
if (res.data.project?.sentryErrors?.detailedError) {
this.$apollo.queries.error.stopPolling();
this.setStatus(this.error.status);
}
},
},
},
data() {
return {
GQLerror: null,
error: null,
issueCreationInProgress: false,
isAlertVisible: false,
closedIssueId: null,
......@@ -101,8 +97,6 @@ export default {
},
computed: {
...mapState('details', [
'error',
'loading',
'loadingStacktrace',
'stacktraceData',
'updatingResolveStatus',
......@@ -114,28 +108,23 @@ export default {
return sprintf(
__('Reported %{timeAgo} by %{reportedBy}'),
{
reportedBy: `<strong>${this.GQLerror.culprit}</strong>`,
reportedBy: `<strong>${this.error.culprit}</strong>`,
timeAgo: this.timeFormatted(this.stacktraceData.date_received),
},
false,
);
},
firstReleaseLink() {
return `${this.error.external_base_url}/releases/${this.GQLerror.firstReleaseShortVersion}`;
return `${this.error.externalBaseUrl}/releases/${this.error.firstReleaseShortVersion}`;
},
lastReleaseLink() {
return `${this.error.external_base_url}releases/${this.GQLerror.lastReleaseShortVersion}`;
},
showDetails() {
return Boolean(
!this.loading && !this.$apollo.queries.GQLerror.loading && this.error && this.GQLerror,
);
return `${this.error.externalBaseUrl}/releases/${this.error.lastReleaseShortVersion}`;
},
showStacktrace() {
return Boolean(!this.loadingStacktrace && this.stacktrace && this.stacktrace.length);
return Boolean(this.stacktrace?.length);
},
issueTitle() {
return this.GQLerror.title;
return this.error.title;
},
issueDescription() {
return sprintf(
......@@ -144,13 +133,13 @@ export default {
),
{
description: '# Error Details:\n',
errorUrl: `${this.GQLerror.externalUrl}\n`,
firstSeen: `\n${this.GQLerror.firstSeen}\n`,
lastSeen: `${this.GQLerror.lastSeen}\n`,
countLabel: n__('- Event', '- Events', this.GQLerror.count),
count: `${this.GQLerror.count}\n`,
userCountLabel: n__('- User', '- Users', this.GQLerror.userCount),
userCount: `${this.GQLerror.userCount}\n`,
errorUrl: `${this.error.externalUrl}\n`,
firstSeen: `\n${this.error.firstSeen}\n`,
lastSeen: `${this.error.lastSeen}\n`,
countLabel: n__('- Event', '- Events', this.error.count),
count: `${this.error.count}\n`,
userCountLabel: n__('- User', '- Users', this.error.userCount),
userCount: `${this.error.userCount}\n`,
},
false,
);
......@@ -171,12 +160,10 @@ export default {
},
},
mounted() {
this.startPollingDetails(this.issueDetailsPath);
this.startPollingStacktrace(this.issueStackTracePath);
},
methods: {
...mapActions('details', [
'startPollingDetails',
'startPollingStacktrace',
'updateStatus',
'setStatus',
......@@ -214,10 +201,10 @@ export default {
<template>
<div>
<div v-if="$apollo.queries.GQLerror.loading || loading" class="py-3">
<div v-if="$apollo.queries.error.loading" class="py-3">
<gl-loading-icon :size="3" />
</div>
<div v-else-if="showDetails" class="error-details">
<div v-else-if="error" class="error-details">
<gl-alert v-if="isAlertVisible" @dismiss="isAlertVisible = false">
<gl-sprintf
:message="
......@@ -232,7 +219,7 @@ export default {
<div class="top-area align-items-center justify-content-between py-3">
<span v-if="!loadingStacktrace && stacktrace" v-html="reported"></span>
<div class="d-inline-flex">
<div class="d-inline-flex ml-lg-auto">
<loading-button
:label="ignoreBtnLabel"
:loading="updatingIgnoreStatus"
......@@ -247,10 +234,10 @@ export default {
@click="onResolveStatusUpdate"
/>
<gl-button
v-if="error.gitlab_issue"
v-if="error.gitlabIssuePath"
class="ml-2"
data-qa-selector="view_issue_button"
:href="error.gitlab_issue"
:href="error.gitlabIssuePath"
variant="success"
>
{{ __('View issue') }}
......@@ -264,13 +251,13 @@ export default {
<gl-form-input class="hidden" name="issue[title]" :value="issueTitle" />
<input name="issue[description]" :value="issueDescription" type="hidden" />
<gl-form-input
:value="GQLerror.sentryId"
:value="error.sentryId"
class="hidden"
name="issue[sentry_issue_attributes][sentry_issue_identifier]"
/>
<gl-form-input :value="csrfToken" class="hidden" name="authenticity_token" />
<loading-button
v-if="!error.gitlab_issue"
v-if="!error.gitlabIssuePath"
class="btn-success"
:label="__('Create issue')"
:loading="issueCreationInProgress"
......@@ -281,8 +268,8 @@ export default {
</div>
</div>
<div>
<tooltip-on-truncate :title="GQLerror.title" truncate-target="child" placement="top">
<h2 class="text-truncate">{{ GQLerror.title }}</h2>
<tooltip-on-truncate :title="error.title" truncate-target="child" placement="top">
<h2 class="text-truncate">{{ error.title }}</h2>
</tooltip-on-truncate>
<template v-if="error.tags">
<gl-badge
......@@ -297,53 +284,51 @@ export default {
</gl-badge>
</template>
<ul>
<li v-if="GQLerror.gitlabCommit">
<li v-if="error.gitlabCommit">
<strong class="bold">{{ __('GitLab commit') }}:</strong>
<gl-link :href="GQLerror.gitlabCommitPath">
<span>{{ GQLerror.gitlabCommit.substr(0, 10) }}</span>
<gl-link :href="error.gitlabCommitPath">
<span>{{ error.gitlabCommit.substr(0, 10) }}</span>
</gl-link>
</li>
<li v-if="error.gitlab_issue">
<li v-if="error.gitlabIssuePath">
<strong class="bold">{{ __('GitLab Issue') }}:</strong>
<gl-link :href="error.gitlab_issue">
<span>{{ error.gitlab_issue }}</span>
<gl-link :href="error.gitlabIssuePath">
<span>{{ error.gitlabIssuePath }}</span>
</gl-link>
</li>
<li>
<strong class="bold">{{ __('Sentry event') }}:</strong>
<gl-link
v-track-event="trackClickErrorLinkToSentryOptions(GQLerror.externalUrl)"
v-track-event="trackClickErrorLinkToSentryOptions(error.externalUrl)"
class="d-inline-flex align-items-center"
:href="GQLerror.externalUrl"
:href="error.externalUrl"
target="_blank"
>
<span class="text-truncate">{{ GQLerror.externalUrl }}</span>
<span class="text-truncate">{{ error.externalUrl }}</span>
<icon name="external-link" class="ml-1 flex-shrink-0" />
</gl-link>
</li>
<li v-if="GQLerror.firstReleaseShortVersion">
<li v-if="error.firstReleaseShortVersion">
<strong class="bold">{{ __('First seen') }}:</strong>
{{ formatDate(GQLerror.firstSeen) }}
{{ formatDate(error.firstSeen) }}
<gl-link :href="firstReleaseLink" target="_blank">
<span>
{{ __('Release') }}: {{ GQLerror.firstReleaseShortVersion.substr(0, 10) }}
</span>
<span>{{ __('Release') }}: {{ error.firstReleaseShortVersion.substr(0, 10) }}</span>
</gl-link>
</li>
<li v-if="GQLerror.lastReleaseShortVersion">
<li v-if="error.lastReleaseShortVersion">
<strong class="bold">{{ __('Last seen') }}:</strong>
{{ formatDate(GQLerror.lastSeen) }}
{{ formatDate(error.lastSeen) }}
<gl-link :href="lastReleaseLink" target="_blank">
<span>{{ __('Release') }}: {{ GQLerror.lastReleaseShortVersion.substr(0, 10) }}</span>
<span>{{ __('Release') }}: {{ error.lastReleaseShortVersion.substr(0, 10) }}</span>
</gl-link>
</li>
<li>
<strong class="bold">{{ __('Events') }}:</strong>
<span>{{ GQLerror.count }}</span>
<span>{{ error.count }}</span>
</li>
<li>
<strong class="bold">{{ __('Users') }}:</strong>
<span>{{ GQLerror.userCount }}</span>
<span>{{ error.userCount }}</span>
</li>
</ul>
......@@ -351,7 +336,7 @@ export default {
<gl-loading-icon :size="3" />
</div>
<template v-if="showStacktrace">
<template v-else-if="showStacktrace">
<h3 class="my-4">{{ __('Stack trace') }}</h3>
<stacktrace :entries="stacktrace" />
</template>
......
......@@ -13,6 +13,7 @@ import {
GlDropdownDivider,
GlTooltipDirective,
GlPagination,
GlButtonGroup,
} from '@gitlab/ui';
import AccessorUtils from '~/lib/utils/accessor';
import Icon from '~/vue_shared/components/icon.vue';
......@@ -20,12 +21,16 @@ import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
import { __ } from '~/locale';
import _ from 'underscore';
export const tableDataClass = 'table-col d-flex d-sm-table-cell';
export const tableDataClass = 'table-col d-flex d-sm-table-cell align-items-center';
export default {
FIRST_PAGE: 1,
PREV_PAGE: 1,
NEXT_PAGE: 2,
statusButtons: [
{ status: 'ignored', icon: 'eye-slash', title: __('Ignore') },
{ status: 'resolved', icon: 'check-circle', title: __('Resolve') },
],
fields: [
{
key: 'error',
......@@ -48,20 +53,13 @@ export default {
{
key: 'lastSeen',
label: __('Last seen'),
thClass: '',
thClass: 'w-15p',
tdClass: `${tableDataClass}`,
},
{
key: 'ignore',
label: '',
thClass: 'w-3rem',
tdClass: `${tableDataClass} pl-0`,
},
{
key: 'resolved',
key: 'status',
label: '',
thClass: 'w-3rem',
tdClass: `${tableDataClass} pl-0`,
tdClass: `${tableDataClass} text-right`,
},
{
key: 'details',
......@@ -88,6 +86,7 @@ export default {
Icon,
GlPagination,
TimeAgo,
GlButtonGroup,
},
directives: {
GlTooltip: GlTooltipDirective,
......@@ -332,25 +331,19 @@ export default {
<time-ago :time="errors.item.lastSeen" class="text-secondary" />
</div>
</template>
<template #cell(ignore)="errors">
<gl-button
ref="ignoreError"
v-gl-tooltip.hover
:title="__('Ignore')"
@click="updateIssueStatus(errors.item.id, 'ignored')"
>
<gl-icon name="eye-slash" :size="12" />
</gl-button>
</template>
<template #cell(resolved)="errors">
<gl-button
ref="resolveError"
v-gl-tooltip
:title="__('Resolve')"
@click="updateIssueStatus(errors.item.id, 'resolved')"
>
<gl-icon name="check-circle" :size="12" />
</gl-button>
<template #cell(status)="errors">
<gl-button-group>
<gl-button
v-for="button in $options.statusButtons"
:key="button.status"
:ref="button.title.toLowerCase() + 'Error'"
v-gl-tooltip.hover
:title="button.title"
@click="updateIssueStatus(errors.item.id, button.status)"
>
<gl-icon :name="button.icon" :size="12" />
</gl-button>
</gl-button-group>
</template>
<template #cell(details)="errors">
<gl-button
......
......@@ -26,7 +26,6 @@ export default () => {
issueId,
projectPath,
issueUpdatePath,
issueDetailsPath,
issueStackTracePath,
projectIssuesPath,
} = domEl.dataset;
......@@ -36,7 +35,6 @@ export default () => {
issueId,
projectPath,
issueUpdatePath,
issueDetailsPath,
issueStackTracePath,
projectIssuesPath,
csrfToken: csrf.token,
......
query errorDetails($fullPath: ID!, $errorId: ID!) {
project(fullPath: $fullPath) {
sentryDetailedError(id: $errorId) {
id
sentryId
title
userCount
count
status
firstSeen
lastSeen
message
culprit
externalUrl
firstReleaseShortVersion
lastReleaseShortVersion
gitlabCommit
gitlabCommitPath
sentryErrors {
detailedError(id: $errorId) {
id
sentryId
title
userCount
count
status
firstSeen
lastSeen
message
culprit
tags {
level
logger
}
externalUrl
externalBaseUrl
firstReleaseShortVersion
lastReleaseShortVersion
gitlabCommit
gitlabCommitPath
gitlabIssuePath
}
}
}
}
......@@ -5,36 +5,11 @@ import Poll from '~/lib/utils/poll';
import { __ } from '~/locale';
let stackTracePoll;
let detailPoll;
const stopPolling = poll => {
if (poll) poll.stop();
};
export function startPollingDetails({ commit }, endpoint) {
detailPoll = new Poll({
resource: service,
method: 'getSentryData',
data: { endpoint },
successCallback: ({ data }) => {
if (!data) {
return;
}
commit(types.SET_ERROR, data.error);
commit(types.SET_LOADING, false);
stopPolling(detailPoll);
},
errorCallback: () => {