Skip to content
Snippets Groups Projects
Commit 7cc6c10c authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 630101f7
No related branches found
No related tags found
No related merge requests found
Showing
with 198 additions and 62 deletions
Loading
Loading
@@ -835,6 +835,13 @@ Please view this file on the master branch, on stable branches it's out of date.
- Don't send CI usage email notifications for self-hosted instances. !14809
 
 
## 12.0.12
### Fixed (1 change)
- Backport the new reliable fetcher to 12.0.9. !20532
## 12.0.10
 
- No changes.
Loading
Loading
Loading
Loading
@@ -17,8 +17,6 @@ import AccessorUtils from '~/lib/utils/accessor';
import Icon from '~/vue_shared/components/icon.vue';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
import { __ } from '~/locale';
import TrackEventDirective from '~/vue_shared/directives/track_event';
import { trackViewInSentryOptions } from '../utils';
 
export default {
fields: [
Loading
Loading
@@ -27,6 +25,11 @@ export default {
{ key: 'users', label: __('Users') },
{ key: 'lastSeen', label: __('Last seen'), thClass: 'w-15p' },
],
sortFields: {
last_seen: __('Last Seen'),
first_seen: __('First Seen'),
frequency: __('Frequency'),
},
components: {
GlEmptyState,
GlButton,
Loading
Loading
@@ -43,7 +46,6 @@ export default {
},
directives: {
GlTooltip: GlTooltipDirective,
TrackEvent: TrackEventDirective,
},
props: {
indexPath: {
Loading
Loading
@@ -74,45 +76,47 @@ export default {
};
},
computed: {
...mapState('list', ['errors', 'externalUrl', 'loading', 'recentSearches']),
...mapState('list', ['errors', 'loading', 'searchQuery', 'sortField', 'recentSearches']),
},
created() {
if (this.errorTrackingEnabled) {
this.startPolling(this.indexPath);
this.setEndpoint(this.indexPath);
this.startPolling();
}
},
methods: {
...mapActions('list', [
'startPolling',
'restartPolling',
'setEndpoint',
'searchByQuery',
'sortByField',
'addRecentSearch',
'clearRecentSearches',
'loadRecentSearches',
'setIndexPath',
]),
filterErrors() {
const searchTerm = this.errorSearchQuery.trim();
this.addRecentSearch(searchTerm);
this.startPolling(`${this.indexPath}?search_term=${searchTerm}`);
},
setSearchText(text) {
this.errorSearchQuery = text;
this.filterErrors();
this.searchByQuery(text);
},
trackViewInSentryOptions,
getDetailsLink(errorId) {
return `error_tracking/${errorId}/details`;
},
isCurrentSortField(field) {
return field === this.sortField;
},
},
};
</script>
 
<template>
<div>
<div class="error-list">
<div v-if="errorTrackingEnabled">
<div class="d-flex flex-row justify-content-around bg-secondary border p-3">
<div class="filtered-search-box">
<div
class="d-flex flex-row justify-content-around align-items-center bg-secondary border mt-2"
>
<div class="filtered-search-box flex-grow-1 my-3 ml-3 mr-2">
<gl-dropdown
:text="__('Recent searches')"
class="filtered-search-history-dropdown-wrapper d-none d-md-block"
Loading
Loading
@@ -143,7 +147,7 @@ export default {
:disabled="loading"
:placeholder="__('Search or filter results…')"
autofocus
@keyup.enter.native="filterErrors"
@keyup.enter.native="searchByQuery(errorSearchQuery)"
/>
</div>
<div class="gl-search-box-by-type-right-icons">
Loading
Loading
@@ -160,16 +164,28 @@ export default {
</div>
</div>
 
<gl-button
v-track-event="trackViewInSentryOptions(externalUrl)"
class="ml-3"
variant="primary"
:href="externalUrl"
target="_blank"
<gl-dropdown
:text="$options.sortFields[sortField]"
left
:disabled="loading"
class="mr-3"
menu-class="sort-dropdown"
>
{{ __('View in Sentry') }}
<icon name="external-link" class="flex-shrink-0" />
</gl-button>
<gl-dropdown-item
v-for="(label, field) in $options.sortFields"
:key="field"
@click="sortByField(field)"
>
<span class="d-flex">
<icon
class="flex-shrink-0 append-right-4"
:class="{ invisible: !isCurrentSortField(field) }"
name="mobile-issue-close"
/>
{{ label }}
</span>
</gl-dropdown-item>
</gl-dropdown>
</div>
 
<div v-if="loading" class="py-3">
Loading
Loading
import axios from '~/lib/utils/axios_utils';
 
export default {
getSentryData({ endpoint }) {
return axios.get(endpoint);
getSentryData({ endpoint, params }) {
return axios.get(endpoint, { params });
},
};
Loading
Loading
@@ -6,19 +6,24 @@ import { __, sprintf } from '~/locale';
 
let eTagPoll;
 
export function startPolling({ commit, dispatch }, endpoint) {
export function startPolling({ state, commit, dispatch }) {
commit(types.SET_LOADING, true);
 
eTagPoll = new Poll({
resource: Service,
method: 'getSentryData',
data: { endpoint },
data: {
endpoint: state.endpoint,
params: {
search_term: state.searchQuery,
sort: state.sortField,
},
},
successCallback: ({ data }) => {
if (!data) {
return;
}
commit(types.SET_ERRORS, data.errors);
commit(types.SET_EXTERNAL_URL, data.external_url);
commit(types.SET_LOADING, false);
dispatch('stopPolling');
},
Loading
Loading
@@ -45,7 +50,6 @@ export const stopPolling = () => {
 
export function restartPolling({ commit }) {
commit(types.SET_ERRORS, []);
commit(types.SET_EXTERNAL_URL, '');
commit(types.SET_LOADING, true);
 
if (eTagPoll) eTagPoll.restart();
Loading
Loading
@@ -67,4 +71,22 @@ export function clearRecentSearches({ commit }) {
commit(types.CLEAR_RECENT_SEARCHES);
}
 
export const searchByQuery = ({ commit, dispatch }, query) => {
const searchQuery = query.trim();
commit(types.SET_SEARCH_QUERY, searchQuery);
commit(types.ADD_RECENT_SEARCH, searchQuery);
dispatch('stopPolling');
dispatch('startPolling');
};
export const sortByField = ({ commit, dispatch }, field) => {
commit(types.SET_SORT_FIELD, field);
dispatch('stopPolling');
dispatch('startPolling');
};
export const setEndpoint = ({ commit }, endpoint) => {
commit(types.SET_ENDPOINT, endpoint);
};
export default () => {};
export const SET_ERRORS = 'SET_ERRORS';
export const SET_EXTERNAL_URL = 'SET_EXTERNAL_URL';
export const SET_INDEX_PATH = 'SET_INDEX_PATH';
export const SET_LOADING = 'SET_LOADING';
export const ADD_RECENT_SEARCH = 'ADD_RECENT_SEARCH';
export const CLEAR_RECENT_SEARCHES = 'CLEAR_RECENT_SEARCHES';
export const LOAD_RECENT_SEARCHES = 'LOAD_RECENT_SEARCHES';
export const SET_ENDPOINT = 'SET_ENDPOINT';
export const SET_SORT_FIELD = 'SET_SORT_FIELD';
export const SET_SEARCH_QUERY = 'SET_SEARCH_QUERY';
Loading
Loading
@@ -6,9 +6,6 @@ export default {
[types.SET_ERRORS](state, data) {
state.errors = convertObjectPropsToCamelCase(data, { deep: true });
},
[types.SET_EXTERNAL_URL](state, url) {
state.externalUrl = url;
},
[types.SET_LOADING](state, loading) {
state.loading = loading;
},
Loading
Loading
@@ -47,4 +44,13 @@ export default {
throw e;
}
},
[types.SET_SORT_FIELD](state, field) {
state.sortField = field;
},
[types.SET_SEARCH_QUERY](state, query) {
state.searchQuery = query;
},
[types.SET_ENDPOINT](state, endpoint) {
state.endpoint = endpoint;
},
};
export default () => ({
errors: [],
externalUrl: '',
loading: true,
endpoint: null,
sortField: 'last_seen',
searchQuery: null,
indexPath: '',
recentSearches: [],
});
/* eslint-disable @gitlab/i18n/no-non-i18n-strings */
/**
* Tracks snowplow event when user clicks View in Sentry btn
* @param {String} externalUrl that will be send as a property for the event
*/
export const trackViewInSentryOptions = url => ({
category: 'Error Tracking',
action: 'click_view_in_sentry',
label: 'External Url',
property: url,
});
/* eslint-disable @gitlab/i18n/no-non-i18n-strings, import/prefer-default-export */
 
/**
* Tracks snowplow event when User clicks on error link to Sentry
Loading
Loading
Loading
Loading
@@ -3,6 +3,7 @@ import BlobViewer from '~/blob/viewer';
import ZenMode from '~/zen_mode';
import initNotes from '~/init_notes';
import snippetEmbed from '~/snippet/snippet_embed';
import initSnippetsApp from '~/snippets';
 
document.addEventListener('DOMContentLoaded', () => {
if (!gon.features.snippetsVue) {
Loading
Loading
@@ -11,5 +12,7 @@ document.addEventListener('DOMContentLoaded', () => {
initNotes();
new ZenMode(); // eslint-disable-line no-new
snippetEmbed();
} else {
initSnippetsApp();
}
});
Loading
Loading
@@ -128,15 +128,15 @@ const bindEvents = () => {
},
iosswift: {
text: s__('ProjectTemplates|iOS (Swift)'),
icon: '.template-option svg.icon-gitlab',
icon: '.template-option .icon-iosswift',
},
dotnetcore: {
text: s__('ProjectTemplates|.NET Core'),
icon: '.template-option .icon-dotnet',
icon: '.template-option .icon-dotnetcore',
},
android: {
text: s__('ProjectTemplates|Android'),
icon: '.template-option svg.icon-android',
icon: '.template-option .icon-android',
},
gomicro: {
text: s__('ProjectTemplates|Go Micro'),
Loading
Loading
@@ -164,27 +164,27 @@ const bindEvents = () => {
},
nfhugo: {
text: s__('ProjectTemplates|Netlify/Hugo'),
icon: '.template-option .icon-netlify',
icon: '.template-option .icon-nfhugo',
},
nfjekyll: {
text: s__('ProjectTemplates|Netlify/Jekyll'),
icon: '.template-option .icon-netlify',
icon: '.template-option .icon-nfjekyll',
},
nfplainhtml: {
text: s__('ProjectTemplates|Netlify/Plain HTML'),
icon: '.template-option .icon-netlify',
icon: '.template-option .icon-nfplainhtml',
},
nfgitbook: {
text: s__('ProjectTemplates|Netlify/GitBook'),
icon: '.template-option .icon-netlify',
icon: '.template-option .icon-nfgitbook',
},
nfhexo: {
text: s__('ProjectTemplates|Netlify/Hexo'),
icon: '.template-option .icon-netlify',
icon: '.template-option .icon-nfhexo',
},
salesforcedx: {
text: s__('ProjectTemplates|SalesforceDX'),
icon: '.template-option svg.icon-gitlab',
icon: '.template-option .icon-salesforcedx',
},
serverless_framework: {
text: s__('ProjectTemplates|Serverless Framework/JS'),
Loading
Loading
<script>
import getSnippet from '../queries/getSnippet.query.graphql';
export default {
apollo: {
snippetData: {
query: getSnippet,
variables() {
return {
ids: this.snippetGid,
};
},
update: data => data.snippets.edges[0].node,
},
},
props: {
snippetGid: {
type: String,
required: true,
},
},
data() {
return {
snippetData: {},
};
},
};
</script>
<template>
<div class="js-snippet-view"></div>
</template>
import Vue from 'vue';
import Translate from '~/vue_shared/translate';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
import SnippetsApp from './components/app.vue';
Vue.use(VueApollo);
Vue.use(Translate);
export default () => {
const el = document.getElementById('js-snippet-view');
if (!el) {
return false;
}
const { snippetGid } = el.dataset;
const apolloProvider = new VueApollo({
defaultClient: createDefaultClient(),
});
return new Vue({
el,
apolloProvider,
render(createElement) {
return createElement(SnippetsApp, {
props: {
snippetGid,
},
});
},
});
};
query getSnippet($ids: [ID!]) {
snippets(ids: $ids) {
edges {
node {
title
description
createdAt
updatedAt
visibility
}
}
}
}
.error-list {
.sort-dropdown {
min-width: auto;
}
}
Loading
Loading
@@ -25,6 +25,7 @@
 
.description p {
margin-bottom: 0;
color: $gl-text-color-secondary;
}
}
 
Loading
Loading
- group = local_assigns.fetch(:group)
- css_class = 'no-description' if group.description.blank?
 
%li.group-row{ class: css_class }
%li.group-row.py-3{ class: css_class }
.controls
= link_to _('Edit'), admin_group_edit_path(group), id: "edit_#{dom_id(group)}", class: 'btn'
= link_to _('Delete'), [:admin, group], data: { confirm: _("Are you sure you want to remove %{group_name}?") % { group_name: group.name } }, method: :delete, class: 'btn btn-remove'
Loading
Loading
- user = local_assigns.fetch(:user, current_user)
- access = user&.max_member_access_for_group(group.id)
 
%li.group-row{ class: ('no-description' if group.description.blank?) }
%li.group-row.py-3{ class: ('no-description' if group.description.blank?) }
.stats
%span
= icon('bookmark')
Loading
Loading
- link_project = local_assigns.fetch(:link_project, false)
- notes_count = @noteable_meta_data[snippet.id].user_notes_count
 
%li.snippet-row
%li.snippet-row.py-3
= image_tag avatar_icon_for_user(snippet.author), class: "avatar s40 d-none d-sm-block", alt: ''
 
.title
Loading
Loading
Loading
Loading
@@ -5,7 +5,7 @@
- page_title "#{@snippet.title} (#{@snippet.to_reference})", _("Snippets")
 
- if Feature.enabled?(:snippets_vue)
#js-snippet-view{ 'data-qa-selector': 'snippet_view' }
#js-snippet-view{ data: {'qa-selector': 'snippet_view', 'snippet-gid': @snippet.to_global_id} }
- else
= render 'shared/snippets/header'
 
Loading
Loading
---
title: Sort Sentry error list by first seen, last seen or frequency
merge_request: 21250
author:
type: added
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment