Fix loading states for unrelated components (#370)

Co-authored-by: kolaente <k@knt.li>
Reviewed-on: https://kolaente.dev/vikunja/frontend/pulls/370
Co-authored-by: konrad <konrad@kola-entertainments.de>
Co-committed-by: konrad <konrad@kola-entertainments.de>
This commit is contained in:
konrad 2021-01-09 14:24:06 +00:00
parent 7d40b29ae8
commit e44be61d2a
8 changed files with 30 additions and 17 deletions

View file

@ -133,7 +133,7 @@
<script> <script>
import {mapState} from 'vuex' import {mapState} from 'vuex'
import {CURRENT_LIST, IS_FULLPAGE, MENU_ACTIVE} from '@/store/mutation-types' import {CURRENT_LIST, IS_FULLPAGE, MENU_ACTIVE, LOADING, LOADING_MODULE} from '@/store/mutation-types'
export default { export default {
name: 'navigation', name: 'navigation',
@ -145,7 +145,7 @@ export default {
currentList: CURRENT_LIST, currentList: CURRENT_LIST,
background: 'background', background: 'background',
menuActive: MENU_ACTIVE, menuActive: MENU_ACTIVE,
loading: state => state.namespaces.loading, loading: state => state[LOADING] && state[LOADING_MODULE] === 'namespaces',
}), }),
beforeCreate() { beforeCreate() {
this.$store.dispatch('namespaces/loadNamespaces') this.$store.dispatch('namespaces/loadNamespaces')

View file

@ -1,9 +1,17 @@
import {LOADING} from './mutation-types' import {LOADING, LOADING_MODULE} from './mutation-types'
export const setLoading = (context, loadFunc = null) => { /**
* This helper sets the loading state with a 100ms delay to avoid flickering.
*
* @param {*} context The vuex module context.
* @param {null|String} module The module that is loading. This parameter allows components to listen for specific parts of the application loading.
* @param {null|function} loadFunc If not null, this function will be executed instead of the default setting loading.
*/
export const setLoading = (context, module = null, loadFunc = null) => {
const timeout = setTimeout(() => { const timeout = setTimeout(() => {
if (loadFunc === null) { if (loadFunc === null) {
context.commit(LOADING, true, {root: true}) context.commit(LOADING, true, {root: true})
context.commit(LOADING_MODULE, module, {root: true})
} else { } else {
loadFunc(true) loadFunc(true)
} }
@ -12,6 +20,7 @@ export const setLoading = (context, loadFunc = null) => {
clearTimeout(timeout) clearTimeout(timeout)
if (loadFunc === null) { if (loadFunc === null) {
context.commit(LOADING, false, {root: true}) context.commit(LOADING, false, {root: true})
context.commit(LOADING_MODULE, null, {root: true})
} else { } else {
loadFunc(false) loadFunc(false)
} }

View file

@ -7,6 +7,7 @@ import {
IS_FULLPAGE, IS_FULLPAGE,
KEYBOARD_SHORTCUTS_ACTIVE, KEYBOARD_SHORTCUTS_ACTIVE,
LOADING, LOADING,
LOADING_MODULE,
MENU_ACTIVE, MENU_ACTIVE,
ONLINE, ONLINE,
} from './mutation-types' } from './mutation-types'
@ -35,6 +36,7 @@ export const store = new Vuex.Store({
}, },
state: { state: {
loading: false, loading: false,
loadingModule: null,
errorMessage: '', errorMessage: '',
online: true, online: true,
isFullpage: false, isFullpage: false,
@ -49,6 +51,9 @@ export const store = new Vuex.Store({
[LOADING](state, loading) { [LOADING](state, loading) {
state.loading = loading state.loading = loading
}, },
[LOADING_MODULE](state, module) {
state.loadingModule = module
},
[ERROR_MESSAGE](state, error) { [ERROR_MESSAGE](state, error) {
state.errorMessage = error state.errorMessage = error
}, },

View file

@ -114,7 +114,7 @@ export default {
}, },
actions: { actions: {
loadBucketsForList(ctx, {listId, params}) { loadBucketsForList(ctx, {listId, params}) {
const cancel = setLoading(ctx) const cancel = setLoading(ctx, 'kanban')
// Clear everything to prevent having old buckets in the list if loading the buckets from this list takes a few moments // Clear everything to prevent having old buckets in the list if loading the buckets from this list takes a few moments
ctx.commit('setBuckets', []) ctx.commit('setBuckets', [])
@ -134,7 +134,7 @@ export default {
}) })
}, },
createBucket(ctx, bucket) { createBucket(ctx, bucket) {
const cancel = setLoading(ctx) const cancel = setLoading(ctx, 'kanban')
const bucketService = new BucketService() const bucketService = new BucketService()
return bucketService.create(bucket) return bucketService.create(bucket)
@ -150,7 +150,7 @@ export default {
}) })
}, },
deleteBucket(ctx, bucket) { deleteBucket(ctx, bucket) {
const cancel = setLoading(ctx) const cancel = setLoading(ctx, 'kanban')
const bucketService = new BucketService() const bucketService = new BucketService()
return bucketService.delete(bucket) return bucketService.delete(bucket)
@ -168,7 +168,7 @@ export default {
}) })
}, },
updateBucket(ctx, bucket) { updateBucket(ctx, bucket) {
const cancel = setLoading(ctx) const cancel = setLoading(ctx, 'kanban')
const bucketService = new BucketService() const bucketService = new BucketService()
return bucketService.update(bucket) return bucketService.update(bucket)

View file

@ -7,7 +7,6 @@ export default {
namespaced: true, namespaced: true,
state: () => ({ state: () => ({
namespaces: [], namespaces: [],
loading: false,
}), }),
mutations: { mutations: {
namespaces(state, namespaces) { namespaces(state, namespaces) {
@ -97,9 +96,7 @@ export default {
}, },
actions: { actions: {
loadNamespaces(ctx) { loadNamespaces(ctx) {
const cancel = setLoading(ctx, status => { const cancel = setLoading(ctx, 'namespaces')
ctx.commit('loading', status, {root: true})
})
const namespaceService = new NamespaceService() const namespaceService = new NamespaceService()
// We always load all namespaces and filter them on the frontend // We always load all namespaces and filter them on the frontend

View file

@ -10,7 +10,7 @@ export default {
state: () => ({}), state: () => ({}),
actions: { actions: {
update(ctx, task) { update(ctx, task) {
const cancel = setLoading(ctx) const cancel = setLoading(ctx, 'tasks')
const taskService = new TaskService() const taskService = new TaskService()
return taskService.update(task) return taskService.update(task)

View file

@ -1,4 +1,5 @@
export const LOADING = 'loading' export const LOADING = 'loading'
export const LOADING_MODULE = 'loadingModule'
export const ERROR_MESSAGE = 'errorMessage' export const ERROR_MESSAGE = 'errorMessage'
export const ONLINE = 'online' export const ONLINE = 'online'
export const IS_FULLPAGE = 'isFullpage' export const IS_FULLPAGE = 'isFullpage'

View file

@ -107,8 +107,8 @@
> >
<div <div
:class="{ :class="{
'is-loading': (taskService.loading || loading) && taskUpdating[task.id], 'is-loading': (taskService.loading || taskLoading) && taskUpdating[task.id],
'draggable': !(taskService.loading || loading) || !taskUpdating[task.id], 'draggable': !(taskService.loading || taskLoading) || !taskUpdating[task.id],
'has-light-text': !colorIsDark(task.hexColor) && task.hexColor !== `#${task.defaultColor}` && task.hexColor !== task.defaultColor, 'has-light-text': !colorIsDark(task.hexColor) && task.hexColor !== `#${task.defaultColor}` && task.hexColor !== task.defaultColor,
}" }"
:style="{'background-color': task.hexColor !== '#' && task.hexColor !== `#${task.defaultColor}` ? task.hexColor : false}" :style="{'background-color': task.hexColor !== '#' && task.hexColor !== `#${task.defaultColor}` ? task.hexColor : false}"
@ -268,9 +268,9 @@ import Filters from '../../../components/list/partials/filters'
import {filterObject} from '@/helpers/filterObject' import {filterObject} from '@/helpers/filterObject'
import {applyDrag} from '@/helpers/applyDrag' import {applyDrag} from '@/helpers/applyDrag'
import {mapState} from 'vuex' import {mapState} from 'vuex'
import {LOADING} from '@/store/mutation-types'
import {saveListView} from '@/helpers/saveListView' import {saveListView} from '@/helpers/saveListView'
import Rights from '../../../models/rights.json' import Rights from '../../../models/rights.json'
import { LOADING, LOADING_MODULE } from '../../../store/mutation-types'
export default { export default {
name: 'Kanban', name: 'Kanban',
@ -333,7 +333,8 @@ export default {
computed: mapState({ computed: mapState({
buckets: state => state.kanban.buckets, buckets: state => state.kanban.buckets,
loadedListId: state => state.kanban.listId, loadedListId: state => state.kanban.listId,
loading: LOADING, loading: state => state[LOADING] && state[LOADING_MODULE] === 'kanban',
taskLoading: state => state[LOADING] && state[LOADING_MODULE] === 'tasks',
canWrite: state => state.currentList.maxRight > Rights.READ, canWrite: state => state.currentList.maxRight > Rights.READ,
list: state => state.currentList, list: state => state.currentList,
}), }),