diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-06-30 09:07:17 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-06-30 09:07:17 +0300 |
commit | 28fd41cf28bfac77fe877b6cce83594c1f9f21a1 (patch) | |
tree | f40a522a22db6518445b243b5244207416665f01 /app/assets/javascripts/search | |
parent | dbb27a91536f29550f7714356ab499d318e9d7e2 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/search')
8 files changed, 106 insertions, 2 deletions
diff --git a/app/assets/javascripts/search/store/actions.js b/app/assets/javascripts/search/store/actions.js index 0819634bd4b..f8c795b2aaf 100644 --- a/app/assets/javascripts/search/store/actions.js +++ b/app/assets/javascripts/search/store/actions.js @@ -2,7 +2,9 @@ import Api from '~/api'; import createFlash from '~/flash'; import { visitUrl, setUrlParams } from '~/lib/utils/url_utility'; import { __ } from '~/locale'; +import { GROUPS_LOCAL_STORAGE_KEY, PROJECTS_LOCAL_STORAGE_KEY } from './constants'; import * as types from './mutation_types'; +import { loadDataFromLS, setFrequentItemToLS } from './utils'; export const fetchGroups = ({ commit }, search) => { commit(types.REQUEST_GROUPS); @@ -39,6 +41,24 @@ export const fetchProjects = ({ commit, state }, search) => { } }; +export const loadFrequentGroups = ({ commit }) => { + const data = loadDataFromLS(GROUPS_LOCAL_STORAGE_KEY); + commit(types.LOAD_FREQUENT_ITEMS, { key: GROUPS_LOCAL_STORAGE_KEY, data }); +}; + +export const loadFrequentProjects = ({ commit }) => { + const data = loadDataFromLS(PROJECTS_LOCAL_STORAGE_KEY); + commit(types.LOAD_FREQUENT_ITEMS, { key: PROJECTS_LOCAL_STORAGE_KEY, data }); +}; + +export const setFrequentGroup = ({ state }, item) => { + setFrequentItemToLS(GROUPS_LOCAL_STORAGE_KEY, state.frequentItems, item); +}; + +export const setFrequentProject = ({ state }, item) => { + setFrequentItemToLS(PROJECTS_LOCAL_STORAGE_KEY, state.frequentItems, item); +}; + export const setQuery = ({ commit }, { key, value }) => { commit(types.SET_QUERY, { key, value }); }; diff --git a/app/assets/javascripts/search/store/constants.js b/app/assets/javascripts/search/store/constants.js new file mode 100644 index 00000000000..3abf7cac6ba --- /dev/null +++ b/app/assets/javascripts/search/store/constants.js @@ -0,0 +1,7 @@ +export const MAX_FREQUENT_ITEMS = 5; + +export const MAX_FREQUENCY = 5; + +export const GROUPS_LOCAL_STORAGE_KEY = 'global-search-frequent-groups'; + +export const PROJECTS_LOCAL_STORAGE_KEY = 'global-search-frequent-projects'; diff --git a/app/assets/javascripts/search/store/mutation_types.js b/app/assets/javascripts/search/store/mutation_types.js index a6430b53c4f..5c1c29dc738 100644 --- a/app/assets/javascripts/search/store/mutation_types.js +++ b/app/assets/javascripts/search/store/mutation_types.js @@ -7,3 +7,5 @@ export const RECEIVE_PROJECTS_SUCCESS = 'RECEIVE_PROJECTS_SUCCESS'; export const RECEIVE_PROJECTS_ERROR = 'RECEIVE_PROJECTS_ERROR'; export const SET_QUERY = 'SET_QUERY'; + +export const LOAD_FREQUENT_ITEMS = 'LOAD_FREQUENT_ITEMS'; diff --git a/app/assets/javascripts/search/store/mutations.js b/app/assets/javascripts/search/store/mutations.js index 91d7cf66c8f..63156a89738 100644 --- a/app/assets/javascripts/search/store/mutations.js +++ b/app/assets/javascripts/search/store/mutations.js @@ -26,4 +26,7 @@ export default { [types.SET_QUERY](state, { key, value }) { state.query[key] = value; }, + [types.LOAD_FREQUENT_ITEMS](state, { key, data }) { + state.frequentItems[key] = data; + }, }; diff --git a/app/assets/javascripts/search/store/state.js b/app/assets/javascripts/search/store/state.js index 9a0d61d0b93..5b1429ccc97 100644 --- a/app/assets/javascripts/search/store/state.js +++ b/app/assets/javascripts/search/store/state.js @@ -1,8 +1,14 @@ +import { GROUPS_LOCAL_STORAGE_KEY, PROJECTS_LOCAL_STORAGE_KEY } from './constants'; + const createState = ({ query }) => ({ query, groups: [], fetchingGroups: false, projects: [], fetchingProjects: false, + frequentItems: { + [GROUPS_LOCAL_STORAGE_KEY]: [], + [PROJECTS_LOCAL_STORAGE_KEY]: [], + }, }); export default createState; diff --git a/app/assets/javascripts/search/store/utils.js b/app/assets/javascripts/search/store/utils.js new file mode 100644 index 00000000000..6128f9f0b81 --- /dev/null +++ b/app/assets/javascripts/search/store/utils.js @@ -0,0 +1,50 @@ +import AccessorUtilities from '../../lib/utils/accessor'; +import { MAX_FREQUENT_ITEMS, MAX_FREQUENCY } from './constants'; + +export const loadDataFromLS = (key) => { + if (!AccessorUtilities.isLocalStorageAccessSafe()) { + return []; + } + + try { + return JSON.parse(localStorage.getItem(key)) || []; + } catch { + // The LS got in a bad state, let's wipe it + localStorage.removeItem(key); + return []; + } +}; + +export const setFrequentItemToLS = (key, data, item) => { + if (!AccessorUtilities.isLocalStorageAccessSafe()) { + return; + } + + try { + const frequentItems = data[key]; + const existingItemIndex = frequentItems.findIndex((i) => i.id === item.id); + + if (existingItemIndex >= 0) { + // Up the frequency (Max 5) + const currentFrequency = frequentItems[existingItemIndex].frequency; + frequentItems[existingItemIndex].frequency = Math.min(currentFrequency + 1, MAX_FREQUENCY); + } else { + // Only store a max of 5 items + if (frequentItems.length >= MAX_FREQUENT_ITEMS) { + frequentItems.pop(); + } + + frequentItems.push({ id: item.id, frequency: 1 }); + } + + // Sort by frequency + frequentItems.sort((a, b) => b.frequency - a.frequency); + + // Note we do not need to commit a mutation here as immediately after this we refresh the page to + // update the search results. + localStorage.setItem(key, JSON.stringify(frequentItems)); + } catch { + // The LS got in a bad state, let's wipe it + localStorage.removeItem(key); + } +}; diff --git a/app/assets/javascripts/search/topbar/components/group_filter.vue b/app/assets/javascripts/search/topbar/components/group_filter.vue index da9252eeacd..c97892e7fec 100644 --- a/app/assets/javascripts/search/topbar/components/group_filter.vue +++ b/app/assets/javascripts/search/topbar/components/group_filter.vue @@ -23,9 +23,17 @@ export default { return isEmpty(this.initialData) ? ANY_OPTION : this.initialData; }, }, + created() { + this.loadFrequentGroups(); + }, methods: { - ...mapActions(['fetchGroups']), + ...mapActions(['fetchGroups', 'setFrequentGroup', 'loadFrequentGroups']), handleGroupChange(group) { + // If group.id is null we are clearing the filter and don't need to store that in LS. + if (group.id) { + this.setFrequentGroup(group); + } + visitUrl( setUrlParams({ [GROUP_DATA.queryParam]: group.id, [PROJECT_DATA.queryParam]: null }), ); diff --git a/app/assets/javascripts/search/topbar/components/project_filter.vue b/app/assets/javascripts/search/topbar/components/project_filter.vue index dbe8ba54216..1440876afbc 100644 --- a/app/assets/javascripts/search/topbar/components/project_filter.vue +++ b/app/assets/javascripts/search/topbar/components/project_filter.vue @@ -22,9 +22,17 @@ export default { return this.initialData ? this.initialData : ANY_OPTION; }, }, + created() { + this.loadFrequentProjects(); + }, methods: { - ...mapActions(['fetchProjects']), + ...mapActions(['fetchProjects', 'setFrequentProject', 'loadFrequentProjects']), handleProjectChange(project) { + // If project.id is null we are clearing the filter and don't need to store that in LS. + if (project.id) { + this.setFrequentProject(project); + } + // This determines if we need to update the group filter or not const queryParams = { ...(project.namespace?.id && { [GROUP_DATA.queryParam]: project.namespace.id }), |