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>2019-12-11 12:08:12 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2019-12-11 12:08:12 +0300
commit6b8040dc25fdc5fe614c3796a147517dd50bc7d8 (patch)
tree1930c21748fc632a7900659a71fcb7248097879f /app/assets/javascripts/error_tracking
parent7b875aa3fd1645e2e881997256ba94c6cb73ab3d (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_tracking_list.vue210
-rw-r--r--app/assets/javascripts/error_tracking/store/list/actions.js16
-rw-r--r--app/assets/javascripts/error_tracking/store/list/mutation_types.js4
-rw-r--r--app/assets/javascripts/error_tracking/store/list/mutations.js36
-rw-r--r--app/assets/javascripts/error_tracking/store/list/state.js2
5 files changed, 195 insertions, 73 deletions
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 9d8e5396dea..5cd68687329 100644
--- a/app/assets/javascripts/error_tracking/components/error_tracking_list.vue
+++ b/app/assets/javascripts/error_tracking/components/error_tracking_list.vue
@@ -3,11 +3,17 @@ import { mapActions, mapState } from 'vuex';
import {
GlEmptyState,
GlButton,
+ GlIcon,
GlLink,
GlLoadingIcon,
GlTable,
- GlSearchBoxByClick,
+ GlFormInput,
+ GlDropdown,
+ GlDropdownItem,
+ GlDropdownDivider,
+ GlTooltipDirective,
} from '@gitlab/ui';
+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';
@@ -24,14 +30,19 @@ export default {
components: {
GlEmptyState,
GlButton,
+ GlDropdown,
+ GlDropdownItem,
+ GlDropdownDivider,
+ GlIcon,
GlLink,
GlLoadingIcon,
GlTable,
- GlSearchBoxByClick,
+ GlFormInput,
Icon,
TimeAgo,
},
directives: {
+ GlTooltip: GlTooltipDirective,
TrackEvent: TrackEventDirective,
},
props: {
@@ -56,13 +67,14 @@ export default {
required: true,
},
},
+ hasLocalStorage: AccessorUtils.isLocalStorageAccessSafe(),
data() {
return {
errorSearchQuery: '',
};
},
computed: {
- ...mapState('list', ['errors', 'externalUrl', 'loading']),
+ ...mapState('list', ['errors', 'externalUrl', 'loading', 'recentSearches']),
},
created() {
if (this.errorTrackingEnabled) {
@@ -70,9 +82,23 @@ export default {
}
},
methods: {
- ...mapActions('list', ['startPolling', 'restartPolling']),
+ ...mapActions('list', [
+ 'startPolling',
+ 'restartPolling',
+ 'addRecentSearch',
+ 'clearRecentSearches',
+ 'loadRecentSearches',
+ 'setIndexPath',
+ ]),
filterErrors() {
- this.startPolling(`${this.indexPath}?search_term=${this.errorSearchQuery}`);
+ const searchTerm = this.errorSearchQuery.trim();
+ this.addRecentSearch(searchTerm);
+
+ this.startPolling(`${this.indexPath}?search_term=${searchTerm}`);
+ },
+ setSearchText(text) {
+ this.errorSearchQuery = text;
+ this.filterErrors();
},
trackViewInSentryOptions,
getDetailsLink(errorId) {
@@ -85,81 +111,119 @@ export default {
<template>
<div>
<div v-if="errorTrackingEnabled">
- <div>
- <div class="d-flex flex-row justify-content-around bg-secondary border">
- <gl-search-box-by-click
- v-model="errorSearchQuery"
- class="col-lg-10 m-3 p-0"
- :placeholder="__('Search or filter results...')"
- type="search"
- autofocus
- @submit="filterErrors"
- />
- <gl-button
- v-track-event="trackViewInSentryOptions(externalUrl)"
- class="m-3"
- variant="primary"
- :href="externalUrl"
- target="_blank"
+ <div class="d-flex flex-row justify-content-around bg-secondary border p-3">
+ <div class="filtered-search-box">
+ <gl-dropdown
+ :text="__('Recent searches')"
+ class="filtered-search-history-dropdown-wrapper d-none d-md-block"
+ toggle-class="filtered-search-history-dropdown-toggle-button"
+ :disabled="loading"
>
- {{ __('View in Sentry') }}
- <icon name="external-link" class="flex-shrink-0" />
- </gl-button>
- </div>
-
- <div v-if="loading" class="py-3">
- <gl-loading-icon size="md" />
+ <div v-if="!$options.hasLocalStorage" class="px-3">
+ {{ __('This feature requires local storage to be enabled') }}
+ </div>
+ <template v-else-if="recentSearches.length > 0">
+ <gl-dropdown-item
+ v-for="searchQuery in recentSearches"
+ :key="searchQuery"
+ @click="setSearchText(searchQuery)"
+ >{{ searchQuery }}</gl-dropdown-item
+ >
+ <gl-dropdown-divider />
+ <gl-dropdown-item ref="clearRecentSearches" @click="clearRecentSearches">{{
+ __('Clear recent searches')
+ }}</gl-dropdown-item>
+ </template>
+ <div v-else class="px-3">{{ __("You don't have any recent searches") }}</div>
+ </gl-dropdown>
+ <div class="filtered-search-input-container flex-fill">
+ <gl-form-input
+ v-model="errorSearchQuery"
+ class="pl-2 filtered-search"
+ :disabled="loading"
+ :placeholder="__('Search or filter results…')"
+ autofocus
+ @keyup.enter.native="filterErrors"
+ />
+ </div>
+ <div class="gl-search-box-by-type-right-icons">
+ <gl-button
+ v-if="errorSearchQuery.length > 0"
+ v-gl-tooltip.hover
+ :title="__('Clear')"
+ class="clear-search text-secondary"
+ name="clear"
+ @click="errorSearchQuery = ''"
+ >
+ <gl-icon name="close" :size="12" />
+ </gl-button>
+ </div>
</div>
- <gl-table
- v-else
- class="mt-3"
- :items="errors"
- :fields="$options.fields"
- :show-empty="true"
- fixed
- stacked="sm"
+ <gl-button
+ v-track-event="trackViewInSentryOptions(externalUrl)"
+ class="ml-3"
+ variant="primary"
+ :href="externalUrl"
+ target="_blank"
>
- <template slot="HEAD_events" slot-scope="data">
- <div class="text-md-right">{{ data.label }}</div>
- </template>
- <template slot="HEAD_users" slot-scope="data">
- <div class="text-md-right">{{ data.label }}</div>
- </template>
- <template slot="error" slot-scope="errors">
- <div class="d-flex flex-column">
- <gl-link class="d-flex text-dark" :href="getDetailsLink(errors.item.id)">
- <strong class="text-truncate">{{ errors.item.title.trim() }}</strong>
- </gl-link>
- <span class="text-secondary text-truncate">
- {{ errors.item.culprit }}
- </span>
- </div>
- </template>
+ {{ __('View in Sentry') }}
+ <icon name="external-link" class="flex-shrink-0" />
+ </gl-button>
+ </div>
- <template slot="events" slot-scope="errors">
- <div class="text-md-right">{{ errors.item.count }}</div>
- </template>
+ <div v-if="loading" class="py-3">
+ <gl-loading-icon size="md" />
+ </div>
- <template slot="users" slot-scope="errors">
- <div class="text-md-right">{{ errors.item.userCount }}</div>
- </template>
+ <gl-table
+ v-else
+ class="mt-3"
+ :items="errors"
+ :fields="$options.fields"
+ :show-empty="true"
+ fixed
+ stacked="sm"
+ >
+ <template slot="HEAD_events" slot-scope="data">
+ <div class="text-md-right">{{ data.label }}</div>
+ </template>
+ <template slot="HEAD_users" slot-scope="data">
+ <div class="text-md-right">{{ data.label }}</div>
+ </template>
+ <template slot="error" slot-scope="errors">
+ <div class="d-flex flex-column">
+ <gl-link class="d-flex text-dark" :href="getDetailsLink(errors.item.id)">
+ <strong class="text-truncate">{{ errors.item.title.trim() }}</strong>
+ </gl-link>
+ <span class="text-secondary text-truncate">
+ {{ errors.item.culprit }}
+ </span>
+ </div>
+ </template>
- <template slot="lastSeen" slot-scope="errors">
- <div class="d-flex align-items-center">
- <time-ago :time="errors.item.lastSeen" class="text-secondary" />
- </div>
- </template>
- <template slot="empty">
- <div ref="empty">
- {{ __('No errors to display.') }}
- <gl-link class="js-try-again" @click="restartPolling">
- {{ __('Check again') }}
- </gl-link>
- </div>
- </template>
- </gl-table>
- </div>
+ <template slot="events" slot-scope="errors">
+ <div class="text-md-right">{{ errors.item.count }}</div>
+ </template>
+
+ <template slot="users" slot-scope="errors">
+ <div class="text-md-right">{{ errors.item.userCount }}</div>
+ </template>
+
+ <template slot="lastSeen" slot-scope="errors">
+ <div class="d-flex align-items-center">
+ <time-ago :time="errors.item.lastSeen" class="text-secondary" />
+ </div>
+ </template>
+ <template slot="empty">
+ <div ref="empty">
+ {{ __('No errors to display.') }}
+ <gl-link class="js-try-again" @click="restartPolling">
+ {{ __('Check again') }}
+ </gl-link>
+ </div>
+ </template>
+ </gl-table>
</div>
<div v-else-if="userCanEnableErrorTracking">
<gl-empty-state
diff --git a/app/assets/javascripts/error_tracking/store/list/actions.js b/app/assets/javascripts/error_tracking/store/list/actions.js
index 401fef5983e..13b15549d81 100644
--- a/app/assets/javascripts/error_tracking/store/list/actions.js
+++ b/app/assets/javascripts/error_tracking/store/list/actions.js
@@ -51,4 +51,20 @@ export function restartPolling({ commit }) {
if (eTagPoll) eTagPoll.restart();
}
+export function setIndexPath({ commit }, path) {
+ commit(types.SET_INDEX_PATH, path);
+}
+
+export function loadRecentSearches({ commit }) {
+ commit(types.LOAD_RECENT_SEARCHES);
+}
+
+export function addRecentSearch({ commit }, searchQuery) {
+ commit(types.ADD_RECENT_SEARCH, searchQuery);
+}
+
+export function clearRecentSearches({ commit }) {
+ commit(types.CLEAR_RECENT_SEARCHES);
+}
+
export default () => {};
diff --git a/app/assets/javascripts/error_tracking/store/list/mutation_types.js b/app/assets/javascripts/error_tracking/store/list/mutation_types.js
index f9d77a6b08e..4199e8d5cda 100644
--- a/app/assets/javascripts/error_tracking/store/list/mutation_types.js
+++ b/app/assets/javascripts/error_tracking/store/list/mutation_types.js
@@ -1,3 +1,7 @@
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';
diff --git a/app/assets/javascripts/error_tracking/store/list/mutations.js b/app/assets/javascripts/error_tracking/store/list/mutations.js
index e4bd81db9c9..18404d3b0af 100644
--- a/app/assets/javascripts/error_tracking/store/list/mutations.js
+++ b/app/assets/javascripts/error_tracking/store/list/mutations.js
@@ -1,5 +1,6 @@
import * as types from './mutation_types';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+import AccessorUtils from '~/lib/utils/accessor';
export default {
[types.SET_ERRORS](state, data) {
@@ -11,4 +12,39 @@ export default {
[types.SET_LOADING](state, loading) {
state.loading = loading;
},
+ [types.SET_INDEX_PATH](state, path) {
+ state.indexPath = path;
+ },
+ [types.ADD_RECENT_SEARCH](state, searchTerm) {
+ if (searchTerm.length === 0) {
+ return;
+ }
+ // remove any existing item, then add it to the start of the list
+ const recentSearches = state.recentSearches.filter(s => s !== searchTerm);
+ recentSearches.unshift(searchTerm);
+ // only keep the last 5
+ state.recentSearches = recentSearches.slice(0, 5);
+
+ if (AccessorUtils.isLocalStorageAccessSafe()) {
+ localStorage.setItem(
+ `recent-searches${state.indexPath}`,
+ JSON.stringify(state.recentSearches),
+ );
+ }
+ },
+ [types.CLEAR_RECENT_SEARCHES](state) {
+ state.recentSearches = [];
+ if (AccessorUtils.isLocalStorageAccessSafe()) {
+ localStorage.removeItem(`recent-searches${state.indexPath}`);
+ }
+ },
+ [types.LOAD_RECENT_SEARCHES](state) {
+ const recentSearches = localStorage.getItem(`recent-searches${state.indexPath}`) || [];
+ try {
+ state.recentSearches = JSON.parse(recentSearches);
+ } catch (e) {
+ state.recentSearches = [];
+ throw e;
+ }
+ },
};
diff --git a/app/assets/javascripts/error_tracking/store/list/state.js b/app/assets/javascripts/error_tracking/store/list/state.js
index d371350ef0e..f1f0369e5f3 100644
--- a/app/assets/javascripts/error_tracking/store/list/state.js
+++ b/app/assets/javascripts/error_tracking/store/list/state.js
@@ -2,4 +2,6 @@ export default () => ({
errors: [],
externalUrl: '',
loading: true,
+ indexPath: '',
+ recentSearches: [],
});