Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-06-19 18:09:36 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-06-19 18:09:36 +0300
commit8bb837c4d180720d4d923ef2e7bd2c9a46ca97a0 (patch)
tree7dcb166661ba29fb6cd5935f0db34eee6c935388 /app/assets/javascripts/error_tracking
parenteef2437c0a359ec3437d31d1b1ea959e54c71458 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/error_tracking')
-rw-r--r--app/assets/javascripts/error_tracking/components/error_details.vue7
-rw-r--r--app/assets/javascripts/error_tracking/components/error_tracking_list.vue34
-rw-r--r--app/assets/javascripts/error_tracking/components/timeline_chart.vue129
-rw-r--r--app/assets/javascripts/error_tracking/queries/details.query.graphql4
4 files changed, 166 insertions, 8 deletions
diff --git a/app/assets/javascripts/error_tracking/components/error_details.vue b/app/assets/javascripts/error_tracking/components/error_details.vue
index 182090e64f9..0151dbb0bf7 100644
--- a/app/assets/javascripts/error_tracking/components/error_details.vue
+++ b/app/assets/javascripts/error_tracking/components/error_details.vue
@@ -24,6 +24,7 @@ import {
import { severityLevel, severityLevelVariant, errorStatus } from '../constants';
import Stacktrace from './stacktrace.vue';
import ErrorDetailsInfo from './error_details_info.vue';
+import TimelineChart from './timeline_chart.vue';
const SENTRY_TIMEOUT = 10000;
@@ -42,6 +43,7 @@ export default {
GlDropdownDivider,
TimeAgoTooltip,
ErrorDetailsInfo,
+ TimelineChart,
},
props: {
issueUpdatePath: {
@@ -375,6 +377,11 @@ export default {
<error-details-info :error="error" />
+ <div v-if="error.frequency" class="gl-mt-8">
+ <h3>{{ __('Last 24 hours') }}</h3>
+ <timeline-chart :timeline-data="error.frequency" :height="200" />
+ </div>
+
<div v-if="loadingStacktrace" class="gl-py-5">
<gl-loading-icon size="lg" />
</div>
diff --git a/app/assets/javascripts/error_tracking/components/error_tracking_list.vue b/app/assets/javascripts/error_tracking/components/error_tracking_list.vue
index e3784cc8b92..0c9a98f3b33 100644
--- a/app/assets/javascripts/error_tracking/components/error_tracking_list.vue
+++ b/app/assets/javascripts/error_tracking/components/error_tracking_list.vue
@@ -30,10 +30,12 @@ import {
} from '../events_tracking';
import { I18N_ERROR_TRACKING_LIST } from '../constants';
import ErrorTrackingActions from './error_tracking_actions.vue';
+import TimelineChart from './timeline_chart.vue';
const isValidErrorId = (errorId) => {
return /^[0-9]+$/.test(errorId);
};
+export const tableDataClass = 'gl-display-flex gl-md-display-table-cell gl-align-items-center';
export default {
FIRST_PAGE: 1,
PREV_PAGE: 1,
@@ -43,30 +45,37 @@ export default {
{
key: 'error',
label: __('Error'),
- thClass: 'w-60p',
+ thClass: 'gl-w-40p',
+ tdClass: `${tableDataClass}`,
+ },
+ {
+ key: 'timeline',
+ label: __('Timeline'),
+ thClass: 'gl-text-center gl-w-20p',
+ tdClass: `${tableDataClass} gl-text-center`,
},
{
key: 'events',
label: __('Events'),
- thClass: 'gl-text-right',
- tdClass: 'gl-text-right',
+ thClass: 'gl-text-center gl-w-10p',
+ tdClass: `${tableDataClass} gl-text-center`,
},
{
key: 'users',
label: __('Users'),
- thClass: 'gl-text-right',
- tdClass: 'gl-text-right',
+ thClass: 'gl-text-center gl-w-10p',
+ tdClass: `${tableDataClass} gl-text-center`,
},
{
key: 'lastSeen',
label: __('Last seen'),
- thClass: 'gl-w-15p',
- tdClass: 'gl-text-left',
+ thClass: 'gl-text-center gl-w-10p',
+ tdClass: `${tableDataClass} gl-text-center`,
},
{
key: 'status',
label: '',
- tdClass: 'gl-text-center',
+ tdClass: `${tableDataClass}`,
},
],
statusFilters: {
@@ -95,6 +104,7 @@ export default {
GlPagination,
TimeAgo,
ErrorTrackingActions,
+ TimelineChart,
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -438,6 +448,14 @@ export default {
</div>
</template>
+ <template #cell(timeline)="errors">
+ <timeline-chart
+ v-if="errors.item.frequency"
+ :timeline-data="errors.item.frequency"
+ :height="70"
+ />
+ </template>
+
<template #cell(events)="errors">
{{ errors.item.count }}
</template>
diff --git a/app/assets/javascripts/error_tracking/components/timeline_chart.vue b/app/assets/javascripts/error_tracking/components/timeline_chart.vue
new file mode 100644
index 00000000000..51e0c900e4b
--- /dev/null
+++ b/app/assets/javascripts/error_tracking/components/timeline_chart.vue
@@ -0,0 +1,129 @@
+<script>
+import { GlChart } from '@gitlab/ui/dist/charts';
+import { dataVizBlue500 } from '@gitlab/ui/scss_to_js/scss_variables';
+import { hexToRgba } from '@gitlab/ui/dist/utils/utils';
+import { isNumber } from 'lodash';
+import { formatDate } from '~/lib/utils/datetime/date_format_utility';
+import { logError } from '~/lib/logger';
+
+function parseTimelineData(timelineData) {
+ const xData = [];
+ const yData = [];
+ const invalidDataPoints = [];
+ timelineData.forEach((f) => {
+ let rawDate;
+ let count;
+
+ if (Array.isArray(f)) {
+ [rawDate, count] = f;
+ } else if (f.count !== undefined && f.time !== undefined) {
+ rawDate = f.time;
+ count = f.count;
+ }
+ if (rawDate !== undefined && count !== undefined) {
+ // dates/timestamps are in seconds
+ const date = isNumber(rawDate) ? rawDate * 1000 : rawDate;
+ xData.push(formatDate(date));
+ yData.push(count);
+ } else {
+ invalidDataPoints.push(f);
+ }
+ });
+ if (invalidDataPoints.length > 0) {
+ // only log up to 5 invalid data points to reduce log size
+ logError(`Found invalid data points ${invalidDataPoints.slice(0, 5)}`);
+ }
+ return { xData, yData };
+}
+
+export default {
+ components: {
+ GlChart,
+ },
+ props: {
+ timelineData: {
+ /**
+ * Array items can be:
+ * touples: [a_date: string | number, a_count: number]
+ * objects: {time: a_date, count: a_count}: {time: string | number, count: number}
+ *
+ * Dates can either be string or number/timestamp.
+ * When dates are timestamps, they are expected in seconds.
+ *
+ */
+ type: Array,
+ required: true,
+ validator(value) {
+ for (const item of value) {
+ if (Array.isArray(item)) {
+ if (item.length !== 2 || !isNumber(item[1])) {
+ return false;
+ }
+ } else if (typeof item === 'object') {
+ if (!('time' in item) || !('count' in item)) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ return true;
+ },
+ },
+ height: {
+ type: Number,
+ required: true,
+ },
+ },
+ computed: {
+ chartOptions() {
+ if (!this.timelineData) {
+ return {};
+ }
+ const { xData, yData } = parseTimelineData(this.timelineData);
+
+ return {
+ xAxis: {
+ type: 'category',
+ data: xData,
+ show: true,
+ axisTick: {
+ show: false,
+ },
+ axisLabel: {
+ show: false,
+ },
+ axisLine: {
+ show: true,
+ lineStyle: {
+ width: 1,
+ color: '#ececec',
+ },
+ },
+ },
+ yAxis: {
+ type: 'value',
+ show: false,
+ },
+ series: [
+ {
+ data: yData,
+ type: 'bar',
+ itemStyle: { color: hexToRgba(dataVizBlue500, 0.5) },
+ },
+ ],
+ tooltip: {
+ trigger: 'axis',
+ axisPointer: {
+ type: 'shadow',
+ },
+ },
+ };
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-chart v-if="timelineData" :options="chartOptions" :height="height" />
+</template>
diff --git a/app/assets/javascripts/error_tracking/queries/details.query.graphql b/app/assets/javascripts/error_tracking/queries/details.query.graphql
index dd21b0f9c92..5745491c32d 100644
--- a/app/assets/javascripts/error_tracking/queries/details.query.graphql
+++ b/app/assets/javascripts/error_tracking/queries/details.query.graphql
@@ -20,6 +20,10 @@ query errorDetails($fullPath: ID!, $errorId: GitlabErrorTrackingDetailedErrorID!
externalUrl
externalBaseUrl
firstReleaseVersion
+ frequency {
+ count
+ time
+ }
lastReleaseVersion
gitlabCommit
gitlabCommitPath