debian-mirror-gitlab/app/assets/javascripts/frequent_items/components/app.vue

148 lines
4.3 KiB
Vue
Raw Normal View History

2018-11-08 19:23:39 +05:30
<script>
2019-02-15 15:39:39 +05:30
import { GlLoadingIcon } from '@gitlab/ui';
2020-01-01 13:55:28 +05:30
import AccessorUtilities from '~/lib/utils/accessor';
2021-06-08 01:23:25 +05:30
import {
mapVuexModuleState,
mapVuexModuleActions,
mapVuexModuleGetters,
} from '~/lib/utils/vuex_module_mappers';
2018-11-08 19:23:39 +05:30
import { FREQUENT_ITEMS, STORAGE_KEY } from '../constants';
2021-03-11 19:13:27 +05:30
import eventHub from '../event_hub';
2020-02-01 01:16:34 +05:30
import { isMobile, updateExistingFrequentItem, sanitizeItem } from '../utils';
2018-11-08 19:23:39 +05:30
import FrequentItemsList from './frequent_items_list.vue';
import frequentItemsMixin from './frequent_items_mixin';
2021-03-11 19:13:27 +05:30
import FrequentItemsSearchInput from './frequent_items_search_input.vue';
2018-11-08 19:23:39 +05:30
export default {
components: {
FrequentItemsSearchInput,
FrequentItemsList,
2018-12-13 13:39:08 +05:30
GlLoadingIcon,
2018-11-08 19:23:39 +05:30
},
mixins: [frequentItemsMixin],
2021-06-08 01:23:25 +05:30
inject: ['vuexModule'],
2018-11-08 19:23:39 +05:30
props: {
currentUserName: {
type: String,
required: true,
},
currentItem: {
type: Object,
required: true,
},
2021-09-04 01:27:46 +05:30
searchClass: {
type: String,
required: false,
default: '',
},
2018-11-08 19:23:39 +05:30
},
computed: {
2021-06-08 01:23:25 +05:30
...mapVuexModuleState((vm) => vm.vuexModule, [
'searchQuery',
'isLoadingItems',
'isFetchFailed',
'items',
]),
...mapVuexModuleGetters((vm) => vm.vuexModule, ['hasSearchQuery']),
2018-11-08 19:23:39 +05:30
translations() {
return this.getTranslations(['loadingMessage', 'header']);
},
},
created() {
const { namespace, currentUserName, currentItem } = this;
const storageKey = `${currentUserName}/${STORAGE_KEY[namespace]}`;
this.setNamespace(namespace);
this.setStorageKey(storageKey);
if (currentItem.id) {
this.logItemAccess(storageKey, currentItem);
}
eventHub.$on(`${this.namespace}-dropdownOpen`, this.dropdownOpenHandler);
2019-03-02 22:35:43 +05:30
// As we init it through requestIdleCallback it could be that the dropdown is already open
const namespaceDropdown = document.getElementById(`nav-${this.namespace}-dropdown`);
if (namespaceDropdown && namespaceDropdown.classList.contains('show')) {
this.dropdownOpenHandler();
}
2018-11-08 19:23:39 +05:30
},
beforeDestroy() {
eventHub.$off(`${this.namespace}-dropdownOpen`, this.dropdownOpenHandler);
},
methods: {
2021-06-08 01:23:25 +05:30
...mapVuexModuleActions((vm) => vm.vuexModule, [
'setNamespace',
'setStorageKey',
'fetchFrequentItems',
]),
2018-11-08 19:23:39 +05:30
dropdownOpenHandler() {
if (this.searchQuery === '' || isMobile()) {
this.fetchFrequentItems();
}
},
2020-02-01 01:16:34 +05:30
logItemAccess(storageKey, unsanitizedItem) {
const item = sanitizeItem(unsanitizedItem);
2018-11-08 19:23:39 +05:30
if (!AccessorUtilities.isLocalStorageAccessSafe()) {
return false;
}
// Check if there's any frequent items list set
const storedRawItems = localStorage.getItem(storageKey);
const storedFrequentItems = storedRawItems
? JSON.parse(storedRawItems)
: [{ ...item, frequency: 1 }]; // No frequent items list set, set one up.
// Check if item already exists in list
const itemMatchIndex = storedFrequentItems.findIndex(
2021-03-08 18:12:59 +05:30
(frequentItem) => frequentItem.id === item.id,
2018-11-08 19:23:39 +05:30
);
if (itemMatchIndex > -1) {
storedFrequentItems[itemMatchIndex] = updateExistingFrequentItem(
storedFrequentItems[itemMatchIndex],
item,
);
} else {
if (storedFrequentItems.length === FREQUENT_ITEMS.MAX_COUNT) {
storedFrequentItems.shift();
}
storedFrequentItems.push({ ...item, frequency: 1 });
}
return localStorage.setItem(storageKey, JSON.stringify(storedFrequentItems));
},
},
};
</script>
<template>
2021-06-08 01:23:25 +05:30
<div class="gl-display-flex gl-flex-direction-column gl-flex-align-items-stretch gl-h-full">
2021-09-04 01:27:46 +05:30
<frequent-items-search-input
:namespace="namespace"
:class="searchClass"
data-testid="frequent-items-search-input"
/>
2018-12-05 23:21:45 +05:30
<gl-loading-icon
2018-11-08 19:23:39 +05:30
v-if="isLoadingItems"
:label="translations.loadingMessage"
2020-04-22 19:07:51 +05:30
size="lg"
2018-11-08 19:23:39 +05:30
class="loading-animation prepend-top-20"
2021-06-08 01:23:25 +05:30
data-testid="loading"
2018-11-08 19:23:39 +05:30
/>
2021-06-08 01:23:25 +05:30
<div v-if="!isLoadingItems && !hasSearchQuery" class="section-header" data-testid="header">
2018-11-08 19:23:39 +05:30
{{ translations.header }}
</div>
<frequent-items-list
v-if="!isLoadingItems"
:items="items"
:namespace="namespace"
:has-search-query="hasSearchQuery"
:is-fetch-failed="isFetchFailed"
:matcher="searchQuery"
/>
</div>
</template>