diff --git a/src/App.vue b/src/App.vue index c8367af887..059ebc43ec 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1169,20 +1169,6 @@ textarea.input:focus { max-width: 95%; } -.query-list .tag { - margin-right: 1em; - margin-bottom: 0.2em; - border: 1px solid transparent; -} - -.query-list .tag .delete { - transform: rotate(45deg) scale(0.7); -} - -.query-list .tag:hover { - transform: scale(1.1); -} - .fixed-page { position: fixed; left: 0; diff --git a/src/components/modals/EditSearchFilterGroupModal.vue b/src/components/modals/EditSearchFilterGroupModal.vue new file mode 100644 index 0000000000..173783ba74 --- /dev/null +++ b/src/components/modals/EditSearchFilterGroupModal.vue @@ -0,0 +1,128 @@ + + + diff --git a/src/components/modals/EditSearchFilterModal.vue b/src/components/modals/EditSearchFilterModal.vue index a01c286673..fafb3cbc92 100644 --- a/src/components/modals/EditSearchFilterModal.vue +++ b/src/components/modals/EditSearchFilterModal.vue @@ -17,17 +17,22 @@ + + @@ -49,14 +54,16 @@ filter label when it's too complex to read or too long. */ import { modalMixin } from '@/components/modals/base_modal' +import ModalFooter from '@/components/modals/ModalFooter' +import Combobox from '@/components/widgets/Combobox' import TextField from '@/components/widgets/TextField' -import ModalFooter from '@/components/modals/ModalFooter' export default { name: 'edit-search-filter-modal', mixins: [modalMixin], components: { + Combobox, ModalFooter, TextField }, @@ -70,6 +77,10 @@ export default { type: Boolean, default: false }, + isGroupEnabled: { + type: Boolean, + default: false + }, isLoading: { type: Boolean, default: false @@ -77,31 +88,32 @@ export default { searchQueryToEdit: { type: Object, default: () => {} + }, + groupOptions: { + type: Array, + default: () => [] } }, data() { - if (this.searchQueryToEdit && this.searchQueryToEdit.id) { - return { - form: { - text: this.searchQueryToEdit.text, - task_status_id: this.searchQueryToEdit.task_status_id - } - } - } else { - return { - form: { - text: '', - task_status_id: null - } + return { + form: { + id: null, + name: '', + search_filter_group_id: null, + search_query: '', + task_status_id: null } } }, - computed: {}, - methods: { runConfirmation(event) { + if (!this.form.name.length) { + this.$refs.nameField.focus() + return + } + if (!event || event.keyCode === 13 || !event.keyCode) { this.$emit('confirm', { id: this.searchQueryToEdit.id, @@ -113,15 +125,19 @@ export default { watch: { searchQueryToEdit() { - if (this.searchQueryToEdit && this.searchQueryToEdit.id) { + if (this.searchQueryToEdit?.id) { this.form.id = this.searchQueryToEdit.id this.form.name = this.searchQueryToEdit.name + this.form.search_filter_group_id = + this.searchQueryToEdit.search_filter_group_id this.form.search_query = this.searchQueryToEdit.search_query } else { this.form = { - id: '', + id: null, name: '', - search_query: '' + search_filter_group_id: null, + search_query: '', + task_status_id: null } } }, @@ -136,5 +152,3 @@ export default { } } - - diff --git a/src/components/pages/Assets.vue b/src/components/pages/Assets.vue index 2779c7313f..0b2b7b0850 100644 --- a/src/components/pages/Assets.vue +++ b/src/components/pages/Assets.vue @@ -61,7 +61,10 @@
{}) - .catch(err => { - if (err) console.error(err) - }) + this.saveAssetSearch(searchQuery).catch(err => { + if (err) console.error(err) + }) }, removeSearchQuery(searchQuery) { - this.removeAssetSearch(searchQuery) - .then(() => {}) - .catch(err => { - if (err) console.error(err) - }) + this.removeAssetSearch(searchQuery).catch(err => { + if (err) console.error(err) + }) }, saveScrollPosition(scrollPosition) { diff --git a/src/components/pages/Edits.vue b/src/components/pages/Edits.vue index 22e89b9174..d05c3f1773 100644 --- a/src/components/pages/Edits.vue +++ b/src/components/pages/Edits.vue @@ -65,6 +65,7 @@
@@ -577,19 +578,15 @@ export default { }, saveSearchQuery(searchQuery) { - this.savePersonTasksSearch(searchQuery) - .then(() => {}) - .catch(err => { - if (err) console.error(err) - }) + this.savePersonTasksSearch(searchQuery).catch(err => { + if (err) console.error(err) + }) }, removeSearchQuery(searchQuery) { - this.removePersonTasksSearch(searchQuery) - .then(() => {}) - .catch(err => { - if (err) console.error(err) - }) + this.removePersonTasksSearch(searchQuery).catch(err => { + if (err) console.error(err) + }) }, updateActiveTab() { diff --git a/src/components/pages/SequenceStats.vue b/src/components/pages/SequenceStats.vue index 664e7272d1..6f8301da9a 100644 --- a/src/components/pages/SequenceStats.vue +++ b/src/components/pages/SequenceStats.vue @@ -41,6 +41,7 @@
diff --git a/src/components/pages/Sequences.vue b/src/components/pages/Sequences.vue index f4d7b2f89f..4b9a0f991a 100644 --- a/src/components/pages/Sequences.vue +++ b/src/components/pages/Sequences.vue @@ -37,6 +37,7 @@
{}) - .catch(err => { - console.error(err) - }) + this.saveTaskSearch({ searchQuery, entityType }).catch(err => { + console.error(err) + }) }, removeSearchQuery(searchQuery) { - this.removeTaskSearch(searchQuery) - .then(() => {}) - .catch(err => { - console.error(err) - }) + this.removeTaskSearch(searchQuery).catch(err => { + console.error(err) + }) }, updateUrlParams() { diff --git a/src/components/pages/Todos.vue b/src/components/pages/Todos.vue index 9937673ef2..b848bfb7dd 100644 --- a/src/components/pages/Todos.vue +++ b/src/components/pages/Todos.vue @@ -78,6 +78,7 @@ > @@ -361,17 +362,13 @@ export default { }, saveSearchQuery(searchQuery) { - this.saveTodoSearch(searchQuery) - .then(() => {}) - .catch(console.error) + this.saveTodoSearch(searchQuery).catch(console.error) }, removeSearchQuery(searchQuery) { - this.removeTodoSearch(searchQuery) - .then(() => {}) - .catch(err => { - if (err) console.error(err) - }) + this.removeTodoSearch(searchQuery).catch(err => { + if (err) console.error(err) + }) }, onDateChanged(date) { diff --git a/src/components/widgets/SearchQueryList.vue b/src/components/widgets/SearchQueryList.vue index 22e9c851c1..8db7d02c89 100644 --- a/src/components/widgets/SearchQueryList.vue +++ b/src/components/widgets/SearchQueryList.vue @@ -1,34 +1,116 @@ @@ -38,10 +120,17 @@ * results. It allows to modify each query too. */ import { mapActions } from 'vuex' -import { Edit2Icon } from 'vue-feather-icons' +import { + ChevronDownIcon, + Edit2Icon, + FolderPlusIcon, + Trash2Icon +} from 'vue-feather-icons' import { sortByName } from '@/lib/sorting' +import stringHelpers from '@/lib/string' import EditSearchFilterModal from '@/components/modals/EditSearchFilterModal' +import EditSearchFilterGroupModal from '@/components/modals/EditSearchFilterGroupModal' export default { name: 'search-query-list', @@ -49,41 +138,91 @@ export default { queries: { type: Array, default: () => [] + }, + groups: { + type: Array, + default: () => [] + }, + isGroupEnabled: { + type: Boolean, + default: false + }, + type: { + type: String, + required: true } }, components: { + ChevronDownIcon, Edit2Icon, - EditSearchFilterModal + EditSearchFilterModal, + EditSearchFilterGroupModal, + FolderPlusIcon, + Trash2Icon }, data() { return { + groupToEdit: {}, searchQueryToEdit: {}, errors: { - edit: false + edit: false, + group: false }, loading: { - edit: false + edit: false, + group: false }, modals: { - edit: false - } + edit: false, + group: false + }, + toggleGroupId: null } }, computed: { - userFilters() { + sortedFilters() { return sortByName([...this.queries]) + }, + userFilters() { + return this.sortedFilters.filter(query => !query.search_filter_group_id) + }, + userFilterGroups() { + return sortByName([...this.groups]).map(group => { + return { + ...group, + queries: this.sortedFilters.filter( + query => query.search_filter_group_id === group.id + ) + } + }) + }, + groupOptions() { + return [ + { label: '', value: null }, + ...this.userFilterGroups.map(group => ({ + label: group.name, + value: group.id + })) + ] } }, methods: { - ...mapActions(['updateSearchFilter']), - - changeSearch(event, searchQuery) { - const isButtonClicked = ['delete flexrow', 'edit flexrow'].includes( - event.target.className - ) - if (!isButtonClicked) { - this.$emit('change-search', searchQuery) - } + ...mapActions([ + 'removeAssetSearchFilterGroup', + 'removeShotSearchFilterGroup', + 'saveAssetSearchFilterGroup', + 'saveShotSearchFilterGroup', + 'updateSearchFilter', + 'updateSearchFilterGroup' + ]), + + changeSearch(searchQuery) { + this.$emit('change-search', searchQuery) + }, + + editGroup(group = {}) { + this.groupToEdit = group + this.modals.group = true }, editSearch(searchQuery) { @@ -91,69 +230,182 @@ export default { this.modals.edit = true }, - confirmEditSearch(searchFilter) { - this.loading.edit = true - this.updateSearchFilter(searchFilter) - .then(() => { - this.loading.edit = false - this.modals.edit = false - }) - .catch(err => { - console.error(err) - this.loading.edit = false - this.errors.edit = true - }) + async confirmEditFilterGroup(filterGroup) { + try { + this.loading.group = true + this.errors.group = false + + if (!filterGroup.id) { + await this[ + `save${stringHelpers.capitalize(this.type)}SearchFilterGroup` + ](filterGroup) + } else { + await this.updateSearchFilterGroup(filterGroup) + } + this.modals.group = false + } catch (err) { + console.error(err) + this.errors.group = true + } finally { + this.loading.group = false + } + }, + + async confirmEditSearch(searchFilter) { + try { + this.loading.edit = true + this.errors.edit = false + await this.updateSearchFilter(searchFilter) + this.modals.edit = false + } catch (err) { + console.error(err) + this.errors.edit = true + } finally { + this.loading.edit = false + } + }, + + closeFilterGroupModal() { + this.modals.group = false }, removeSearch(searchQuery) { this.$emit('remove-search', searchQuery) + }, + + async removeGroup(filterGroup) { + try { + await this[ + `remove${stringHelpers.capitalize(this.type)}SearchFilterGroup` + ](filterGroup) + } catch (err) { + console.error(err) + } + }, + + toggleFilterGroup(group) { + this.toggleGroupId = this.toggleGroupId !== group.id ? group.id : null } } } - diff --git a/src/lib/string.js b/src/lib/string.js index d31a482812..eb43bab3a0 100644 --- a/src/lib/string.js +++ b/src/lib/string.js @@ -41,5 +41,9 @@ export default { .replace(/[^a-z0-9 -]/g, '') .replace(/\s+/g, '_') .replace(/-+/g, '_') + }, + + capitalize(str) { + return str.charAt(0).toUpperCase() + str.slice(1) } } diff --git a/src/locales/en.js b/src/locales/en.js index fc131f71d3..1c22b5afeb 100644 --- a/src/locales/en.js +++ b/src/locales/en.js @@ -391,6 +391,7 @@ export default { cancel: 'Cancel', clear_selection: 'Clear current selection', close: 'Close', + color: 'Color', column_visibility: 'Visible columns', confirmation: 'Confirm', confirmation_and_stay: 'Confirm and stay', @@ -410,6 +411,11 @@ export default { estimation: 'Estimation', estimation_short: 'Est.', files_selected: 'files selected', + filter_group: 'Filter Group', + filter_group_add: 'Add A Filter Group', + filter_group_edit: 'Edit A Filter Group', + filter_group_empty: 'No filter', + filter_group_error: 'An error occurred while saving this filter group.', for: 'For', fps: 'FPS', frames: 'Frames', diff --git a/src/store/api/people.js b/src/store/api/people.js index 5ae02867fa..3f216426ce 100644 --- a/src/store/api/people.js +++ b/src/store/api/people.js @@ -231,6 +231,33 @@ export default { client.get(`/api/data/persons/${personId}/done-tasks`, callback) }, + getUserSearchFilterGroups() { + return client.pget('/api/data/user/filter-groups') + }, + + createFilterGroup(listType, name, color, productionId, entityType) { + const data = { + list_type: listType, + name, + color, + project_id: productionId, + entity_type: entityType + } + return client.ppost('/api/data/user/filter-groups', data) + }, + + updateFilterGroup(filterGroup) { + const data = { + name: filterGroup.name, + color: filterGroup.color + } + return client.pput(`/api/data/user/filter-groups/${filterGroup.id}`, data) + }, + + removeFilterGroup(filterGroup) { + return client.pdel(`/api/data/user/filter-groups/${filterGroup.id}`) + }, + getUserSearchFilters(callback) { client.get('/api/data/user/filters', callback) }, @@ -238,7 +265,8 @@ export default { updateFilter(searchFilter) { const data = { name: searchFilter.name, - search_query: searchFilter.search_query + search_query: searchFilter.search_query, + search_filter_group_id: searchFilter.search_filter_group_id } return client.pput(`/api/data/user/filters/${searchFilter.id}`, data) }, @@ -254,7 +282,7 @@ export default { return client.ppost('/api/data/user/filters', data) }, - removeFilter(searchFilter, callback) { + removeFilter(searchFilter) { return client.pdel(`/api/data/user/filters/${searchFilter.id}`) }, diff --git a/src/store/modules/assets.js b/src/store/modules/assets.js index 58bb2af7d6..33b8363dcc 100644 --- a/src/store/modules/assets.js +++ b/src/store/modules/assets.js @@ -64,6 +64,8 @@ import { SAVE_ASSET_SEARCH_END, REMOVE_ASSET_SEARCH_END, SET_ASSET_TYPE_SEARCH, + SAVE_ASSET_SEARCH_FILTER_GROUP_END, + REMOVE_ASSET_SEARCH_FILTER_GROUP_END, COMPUTE_ASSET_TYPE_STATS, UPDATE_METADATA_DESCRIPTOR_END, SET_CURRENT_EPISODE, @@ -271,6 +273,7 @@ const initialState = { assetSearchText: '', assetSelectionGrid: {}, assetSearchQueries: [], + assetSearchFilterGroups: [], assetSorting: [], displayedAssetTypes: [], @@ -302,6 +305,7 @@ const getters = { assetMap: state => state.assetMap, assetSearchText: state => state.assetSearchText, assetSearchQueries: state => state.assetSearchQueries, + assetSearchFilterGroups: state => state.assetSearchFilterGroups, assetSelectionGrid: state => state.assetSelectionGrid, assetValidationColumns: state => state.assetValidationColumns, @@ -350,6 +354,7 @@ const actions = { let episode = rootGetters.currentEpisode const isTVShow = rootGetters.isTVShow const userFilters = rootGetters.userFilters + const userFilterGroups = rootGetters.userFilterGroups const personMap = rootGetters.personMap const taskTypeMap = rootGetters.taskTypeMap const taskMap = rootGetters.taskMap @@ -382,6 +387,7 @@ const actions = { production, assets, userFilters, + userFilterGroups, personMap, taskMap, taskTypeMap @@ -558,6 +564,29 @@ const actions = { } }, + saveAssetSearchFilterGroup({ commit, state, rootGetters }, filterGroup) { + const groupExist = state.assetSearchFilterGroups.some( + query => query.name === filterGroup.name + ) + if (groupExist) { + return + } + + const production = rootGetters.currentProduction + return peopleApi + .createFilterGroup( + 'asset', + filterGroup.name, + filterGroup.color, + production.id, + null + ) + .then(filterGroup => { + commit(SAVE_ASSET_SEARCH_FILTER_GROUP_END, { filterGroup, production }) + return filterGroup + }) + }, + removeAssetSearch({ commit, rootGetters }, searchQuery) { const production = rootGetters.currentProduction return peopleApi.removeFilter(searchQuery).then(() => { @@ -566,6 +595,13 @@ const actions = { }) }, + removeAssetSearchFilterGroup({ commit, rootGetters }, filterGroup) { + const production = rootGetters.currentProduction + return peopleApi.removeFilterGroup(filterGroup).then(() => { + commit(REMOVE_ASSET_SEARCH_FILTER_GROUP_END, { filterGroup, production }) + }) + }, + displayMoreAssets({ commit, rootGetters }) { commit(DISPLAY_MORE_ASSETS, { taskTypeMap: rootGetters.taskTypeMap, @@ -726,6 +762,7 @@ const mutations = { state.assetFilledColumns = {} helpers.setListStats(state, []) state.assetSearchQueries = [] + state.assetSearchFilterGroups = [] state.selectedAssets = new Map() }, @@ -743,6 +780,7 @@ const mutations = { state.assetFilledColumns = {} helpers.setListStats(state, []) state.assetSearchQueries = [] + state.assetSearchFilterGroups = [] state.selectedAssets = new Map() }, @@ -754,7 +792,15 @@ const mutations = { [LOAD_ASSETS_END]( state, - { production, assets, userFilters, personMap, taskMap, taskTypeMap } + { + production, + assets, + userFilters, + userFilterGroups, + personMap, + taskMap, + taskTypeMap + } ) { const validationColumns = {} const assetTypeMap = new Map() @@ -814,11 +860,10 @@ const mutations = { const maxY = state.nbValidationColumns state.assetSelectionGrid = buildSelectionGrid(maxX, maxY) - if (userFilters.asset && userFilters.asset[production.id]) { - state.assetSearchQueries = userFilters.asset[production.id] - } else { - state.assetSearchQueries = [] - } + state.assetSearchQueries = userFilters.asset?.[production.id] || [] + + state.assetSearchFilterGroups = + userFilterGroups.asset?.[production.id] || [] }, [ADD_ASSET](state, { taskTypeMap, taskMap, personMap, production, asset }) { @@ -965,6 +1010,13 @@ const mutations = { } }, + [SAVE_ASSET_SEARCH_FILTER_GROUP_END](state, { filterGroup }) { + if (!state.assetSearchFilterGroups.includes(filterGroup)) { + state.assetSearchFilterGroups.push(filterGroup) + state.assetSearchFilterGroups = sortByName(state.assetSearchFilterGroups) + } + }, + [REMOVE_ASSET_SEARCH_END](state, { searchQuery }) { const queryIndex = state.assetSearchQueries.findIndex( query => query.name === searchQuery.name @@ -974,6 +1026,15 @@ const mutations = { } }, + [REMOVE_ASSET_SEARCH_FILTER_GROUP_END](state, { filterGroup }) { + const groupIndex = state.assetSearchFilterGroups.findIndex( + query => query.name === filterGroup.name + ) + if (groupIndex >= 0) { + state.assetSearchFilterGroups.splice(groupIndex, 1) + } + }, + [DISPLAY_MORE_ASSETS]( state, { taskTypeMap, taskStatusMap, taskMap, production } diff --git a/src/store/modules/shots.js b/src/store/modules/shots.js index 1710a5a889..4ca69106d1 100644 --- a/src/store/modules/shots.js +++ b/src/store/modules/shots.js @@ -62,7 +62,9 @@ import { CLEAR_SELECTED_TASKS, SET_PREVIEW, SAVE_SHOT_SEARCH_END, + SAVE_SHOT_SEARCH_FILTER_GROUP_END, REMOVE_SHOT_SEARCH_END, + REMOVE_SHOT_SEARCH_FILTER_GROUP_END, CHANGE_SHOT_SORT, UPDATE_METADATA_DESCRIPTOR_END, LOCK_SHOT, @@ -246,6 +248,7 @@ const initialState = { shotMap: new Map(), shotSearchText: '', shotSearchQueries: [], + shotSearchFilterGroups: [], shotSorting: [], isFps: false, @@ -288,6 +291,7 @@ const getters = { shotValidationColumns: state => state.shotValidationColumns, shotSearchQueries: state => state.shotSearchQueries, + shotSearchFilterGroups: state => state.shotSearchFilterGroups, shotMap: state => state.shotMap, shotSorting: state => state.shotSorting, @@ -376,6 +380,7 @@ const actions = { const production = rootGetters.currentProduction const episodes = rootGetters.episodes const userFilters = rootGetters.userFilters + const userFilterGroups = rootGetters.userFilterGroups const taskTypeMap = rootGetters.taskTypeMap const taskMap = rootGetters.taskMap const episodeMap = rootGetters.episodeMap @@ -419,6 +424,7 @@ const actions = { production, shots, userFilters, + userFilterGroups, taskTypeMap, taskMap, personMap, @@ -587,6 +593,29 @@ const actions = { } }, + saveShotSearchFilterGroup({ commit, state, rootGetters }, filterGroup) { + const groupExist = state.shotSearchFilterGroups.some( + query => query.name === filterGroup.name + ) + if (groupExist) { + return + } + + const production = rootGetters.currentProduction + return peopleApi + .createFilterGroup( + 'shot', + filterGroup.name, + filterGroup.color, + production.id, + null + ) + .then(filterGroup => { + commit(SAVE_SHOT_SEARCH_FILTER_GROUP_END, { filterGroup, production }) + return filterGroup + }) + }, + removeShotSearch({ commit, rootGetters }, searchQuery) { const production = rootGetters.currentProduction return peopleApi.removeFilter(searchQuery).then(() => { @@ -595,6 +624,13 @@ const actions = { }) }, + removeShotSearchFilterGroup({ commit, rootGetters }, filterGroup) { + const production = rootGetters.currentProduction + return peopleApi.removeFilterGroup(filterGroup).then(() => { + commit(REMOVE_SHOT_SEARCH_FILTER_GROUP_END, { filterGroup, production }) + }) + }, + getShotsCsvLines({ state, rootGetters }) { const production = rootGetters.currentProduction const isTVShow = rootGetters.isTVShow @@ -746,6 +782,7 @@ const mutations = { state.displayedEstimation = 0 state.displayedFrames = 0 state.shotSearchQueries = [] + state.shotSearchFilterGroups = [] state.displayedSequences = [] state.displayedSequencesLength = 0 @@ -768,6 +805,7 @@ const mutations = { state.displayedEstimation = 0 state.displayedFrames = 0 state.shotSearchQueries = [] + state.shotSearchFilterGroups = [] state.displayedSequences = [] state.displayedSequencesLength = 0 @@ -785,6 +823,7 @@ const mutations = { production, shots, userFilters, + userFilterGroups, taskMap, taskTypeMap, personMap, @@ -888,11 +927,9 @@ const mutations = { state.shotSelectionGrid = buildSelectionGrid(maxX, maxY) helpers.setListStats(state, shots) - if (userFilters.shot && userFilters.shot[production.id]) { - state.shotSearchQueries = userFilters.shot[production.id] - } else { - state.shotSearchQueries = [] - } + state.shotSearchQueries = userFilters.shot?.[production.id] || [] + + state.shotSearchFilterGroups = userFilterGroups.shot?.[production.id] || [] }, [SAVE_SHOT_SEARCH_END](state, { searchQuery }) { @@ -900,6 +937,13 @@ const mutations = { state.shotSearchQueries = sortByName(state.shotSearchQueries) }, + [SAVE_SHOT_SEARCH_FILTER_GROUP_END](state, { filterGroup }) { + if (!state.shotSearchFilterGroups.includes(filterGroup)) { + state.shotSearchFilterGroups.push(filterGroup) + state.shotSearchFilterGroups = sortByName(state.shotSearchFilterGroups) + } + }, + [REMOVE_SHOT_SEARCH_END](state, { searchQuery }) { const queryIndex = state.shotSearchQueries.findIndex( query => query.name === searchQuery.name @@ -909,6 +953,15 @@ const mutations = { } }, + [REMOVE_SHOT_SEARCH_FILTER_GROUP_END](state, { filterGroup }) { + const groupIndex = state.shotSearchFilterGroups.findIndex( + query => query.name === filterGroup.name + ) + if (groupIndex >= 0) { + state.shotSearchFilterGroups.splice(groupIndex, 1) + } + }, + [LOAD_SHOT_END](state, { shot, taskTypeMap }) { shot.tasks.forEach(task => { helpers.populateTask(task, shot) diff --git a/src/store/modules/user.js b/src/store/modules/user.js index 2682456496..9cc8703bff 100644 --- a/src/store/modules/user.js +++ b/src/store/modules/user.js @@ -43,6 +43,9 @@ import { LOAD_USER_FILTERS_END, LOAD_USER_FILTERS_ERROR, UPDATE_USER_FILTER, + LOAD_USER_FILTER_GROUPS_END, + LOAD_USER_FILTER_GROUPS_ERROR, + UPDATE_USER_FILTER_GROUP, SAVE_TODO_SEARCH_END, REMOVE_TODO_SEARCH_END, ADD_SELECTED_TASK, @@ -109,6 +112,7 @@ const initialState = { todoSelectionGrid: {}, todoSearchQueries: [], userFilters: {}, + userFilterGroups: {}, todoListScrollPosition: 0, timeSpentMap: {}, @@ -144,6 +148,7 @@ const getters = { todoSelectionGrid: state => state.todoSelectionGrid, todoSearchQueries: state => state.todoSearchQueries, userFilters: state => state.userFilters, + userFilterGroups: state => state.userFilterGroups, isTodosLoading: state => state.isTodosLoading, isTodosLoadingError: state => state.isTodosLoadingError, todoListScrollPosition: state => state.todoListScrollPosition, @@ -334,9 +339,14 @@ const actions = { commit(SET_TODOS_SEARCH, searchText) }, - updateSearchFilter({ commit }, searchFilter) { + async updateSearchFilterGroup({ commit }, searchFilterGroup) { + await peopleApi.updateFilterGroup(searchFilterGroup) + commit(UPDATE_USER_FILTER_GROUP, searchFilterGroup) + }, + + async updateSearchFilter({ commit }, searchFilter) { + await peopleApi.updateFilter(searchFilter) commit(UPDATE_USER_FILTER, searchFilter) - return peopleApi.updateFilter(searchFilter) }, loadUserSearchFilters({ commit }, callback) { @@ -378,6 +388,7 @@ const actions = { loadContext({ commit, rootGetters }, callback) { return peopleApi.getContext().then(context => { commit(LOAD_USER_FILTERS_END, context.search_filters) + commit(LOAD_USER_FILTER_GROUPS_END, context.search_filter_groups) commit(LOAD_PRODUCTION_STATUS_END, context.project_status) commit(LOAD_DEPARTMENTS_END, context.departments) commit(LOAD_TASK_STATUSES_END, context.task_status) @@ -701,6 +712,24 @@ const mutations = { }) }, + [LOAD_USER_FILTER_GROUPS_ERROR](state) {}, + [LOAD_USER_FILTER_GROUPS_END](state, userFilterGroups) { + state.userFilterGroups = userFilterGroups + }, + [UPDATE_USER_FILTER_GROUP](state, userFilterGroup) { + Object.keys(state.userFilterGroups).forEach(typeName => { + Object.keys(state.userFilterGroups[typeName]).forEach(projectId => { + const projectFilterGroups = state.userFilterGroups[typeName][projectId] + const filterGroup = projectFilterGroups.find( + f => f.id === userFilterGroup.id + ) + if (filterGroup) { + Object.assign(filterGroup, userFilterGroup) + } + }) + }) + }, + [SET_TIME_SPENT](state, timeSpent) { if (state.user.id === timeSpent.person_id) { state.timeSpentMap[timeSpent.task_id] = timeSpent diff --git a/src/store/mutation-types.js b/src/store/mutation-types.js index 3bc8469311..f0cfed8c97 100644 --- a/src/store/mutation-types.js +++ b/src/store/mutation-types.js @@ -93,6 +93,10 @@ export const SET_TODOS_SEARCH = 'SET_TODOS_SEARCH' export const LOAD_USER_FILTERS_END = 'LOAD_USER_FILTERS_END' export const LOAD_USER_FILTERS_ERROR = 'LOAD_USER_FILTERS_ERROR' export const UPDATE_USER_FILTER = 'UPDATE_USER_FILTER' +export const LOAD_USER_FILTER_GROUPS_END = 'LOAD_USER_FILTER_GROUPS_END' +export const LOAD_USER_FILTER_GROUPS_ERROR = 'LOAD_USER_FILTER_GROUPS_ERROR' +export const UPDATE_USER_FILTER_GROUP = 'UPDATE_USER_FILTER_GROUP' + export const SET_TODO_LIST_SCROLL_POSITION = 'SET_TODO_LIST_SCROLL_POSITION' // Tasks @@ -337,6 +341,11 @@ export const SAVE_ASSET_SEARCH_END = 'SAVE_ASSET_SEARCH_END' export const REMOVE_ASSET_SEARCH_END = 'REMOVE_ASSET_SEARCH_END' export const DISPLAY_MORE_ASSETS = 'DISPLAY_MORE_ASSETS' +export const SAVE_ASSET_SEARCH_FILTER_GROUP_END = + 'SAVE_ASSET_SEARCH_FILTER_GROUP_END' +export const REMOVE_ASSET_SEARCH_FILTER_GROUP_END = + 'REMOVE_ASSET_SEARCH_FILTER_GROUP_END' + export const COMPUTE_ASSET_TYPE_STATS = 'COMPUTE_ASSET_TYPE_STATS' export const SET_ASSET_TYPE_SEARCH = 'SET_ASSET_TYPE_SEARCH' @@ -443,6 +452,11 @@ export const SET_EPISODE_SEARCH = 'SET_EPISODE_SEARCH' export const DISPLAY_MORE_SHOTS = 'DISPLAY_MORE_SHOTS' export const DISPLAY_MORE_SEQUENCES = 'DISPLAY_MORE_SEQUENCES' +export const SAVE_SHOT_SEARCH_FILTER_GROUP_END = + 'SAVE_SHOT_SEARCH_FILTER_GROUP_END' +export const REMOVE_SHOT_SEARCH_FILTER_GROUP_END = + 'REMOVE_SHOT_SEARCH_FILTER_GROUP_END' + export const SET_SHOT_LIST_SCROLL_POSITION = 'SET_SHOT_LIST_SCROLL_POSITION' export const SET_SEQUENCE_LIST_SCROLL_POSITION = 'SET_SEQUENCE_LIST_SCROLL_POSITION' diff --git a/tests/unit/store/assets.spec.js b/tests/unit/store/assets.spec.js index b4346c2c4f..f8e69fb026 100644 --- a/tests/unit/store/assets.spec.js +++ b/tests/unit/store/assets.spec.js @@ -771,6 +771,7 @@ describe('Assets store', () => { assetValidationColumns: 1, displayedAssets: 1, assetFilledColumns: 1, + assetSearchFilterGroups: 1, assetSearchQueries: 1, displayedAssetsCount: 100, displayedAssetsLength: 100, @@ -786,6 +787,7 @@ describe('Assets store', () => { assetValidationColumns: [], displayedAssets: [], assetFilledColumns: {}, + assetSearchFilterGroups: [], assetSearchQueries: [], displayedAssetsCount: 0, displayedAssetsLength: 0, @@ -806,6 +808,7 @@ describe('Assets store', () => { assetValidationColumns: 1, displayedAssets: 1, assetFilledColumns: 1, + assetSearchFilterGroups: 1, assetSearchQueries: 1, displayedAssetsCount: 100, displayedAssetsLength: 100, @@ -823,6 +826,7 @@ describe('Assets store', () => { assetValidationColumns: [], displayedAssets: [], assetFilledColumns: {}, + assetSearchFilterGroups: [], assetSearchQueries: [], displayedAssetsCount: 0, displayedAssetsLength: 0, @@ -896,6 +900,11 @@ describe('Assets store', () => { 1: 'assetSearchQueries' } } + const userFilterGroups = { + asset: { + 1: 'assetSearchFilterGroups' + } + } const personMap = new Map() const taskMap = new Map() const taskTypeMap = new Map() @@ -903,6 +912,7 @@ describe('Assets store', () => { production, assets, userFilters, + userFilterGroups, personMap, taskMap, taskTypeMap @@ -998,6 +1008,7 @@ describe('Assets store', () => { displayedAssetsCount: 4, displayedAssetsLength: 2, displayedAssetsTimeSpent: 0, + assetSearchFilterGroups: 'assetSearchFilterGroups', assetSearchQueries: 'assetSearchQueries', assetMap: new Map(Object.entries({ 4: { @@ -1961,6 +1972,7 @@ describe('Assets store', () => { assetFilledColumns: {}, assetListScrollPosition: 0, assetMap: new Map(), + assetSearchFilterGroups: [], assetSearchQueries: [], assetSearchText: '', assetSelectionGrid: {},