Add updating the list position through the menu
This commit is contained in:
parent
29b33d2070
commit
cd8f77765c
@ -49,7 +49,7 @@
|
||||
</div>
|
||||
|
||||
<aside class="menu namespaces-lists loader-container" :class="{'is-loading': loading}">
|
||||
<template v-for="n in namespaces">
|
||||
<template v-for="(n, nk) in namespaces">
|
||||
<div :key="n.id" class="namespace-title" :class="{'has-menu': n.id > 0}">
|
||||
<span
|
||||
@click="toggleLists(n.id)"
|
||||
@ -73,38 +73,53 @@
|
||||
</a>
|
||||
<namespace-settings-dropdown :namespace="n" v-if="n.id > 0"/>
|
||||
</div>
|
||||
<div :key="n.id + 'child'" class="more-container" v-if="typeof listsVisible[n.id] !== 'undefined' ? listsVisible[n.id] : true">
|
||||
<div
|
||||
:key="n.id + 'child'"
|
||||
class="more-container"
|
||||
v-if="typeof listsVisible[n.id] !== 'undefined' ? listsVisible[n.id] : true"
|
||||
>
|
||||
<ul class="menu-list can-be-hidden">
|
||||
<template v-for="l in n.lists">
|
||||
<!-- This is a bit ugly but vue wouldn't want to let me filter this - probably because the lists
|
||||
are nested inside of the namespaces makes it a lot harder.-->
|
||||
<li :key="l.id" v-if="!l.isArchived">
|
||||
<router-link
|
||||
class="list-menu-link"
|
||||
:class="{'router-link-exact-active': currentList.id === l.id}"
|
||||
:to="{ name: 'list.index', params: { listId: l.id} }"
|
||||
tag="span"
|
||||
>
|
||||
<span
|
||||
:style="{ backgroundColor: l.hexColor }"
|
||||
class="color-bubble"
|
||||
v-if="l.hexColor !== ''">
|
||||
<draggable
|
||||
v-model="n.lists"
|
||||
:group="`namespace-${n.id}-lists`"
|
||||
@start="() => drag = true"
|
||||
@end="e => saveListPosition(e, nk)"
|
||||
v-bind="dragOptions"
|
||||
handle=".handle"
|
||||
>
|
||||
<transition-group type="transition" :name="!drag ? 'flip-list' : null">
|
||||
<!-- eslint-disable vue/no-use-v-if-with-v-for,vue/no-confusing-v-for-v-if -->
|
||||
<li v-for="l in n.lists" :key="l.id" v-if="!l.isArchived">
|
||||
<router-link
|
||||
class="list-menu-link"
|
||||
:class="{'router-link-exact-active': currentList.id === l.id}"
|
||||
:to="{ name: 'list.index', params: { listId: l.id} }"
|
||||
tag="span"
|
||||
>
|
||||
<span class="icon handle">
|
||||
<icon icon="grip-lines"/>
|
||||
</span>
|
||||
<span class="list-menu-title">
|
||||
<span
|
||||
:style="{ backgroundColor: l.hexColor }"
|
||||
class="color-bubble"
|
||||
v-if="l.hexColor !== ''">
|
||||
</span>
|
||||
<span class="list-menu-title">
|
||||
{{ getListTitle(l) }}
|
||||
</span>
|
||||
<span
|
||||
:class="{'is-favorite': l.isFavorite}"
|
||||
@click.stop="toggleFavoriteList(l)"
|
||||
class="favorite">
|
||||
<span
|
||||
:class="{'is-favorite': l.isFavorite}"
|
||||
@click.stop="toggleFavoriteList(l)"
|
||||
class="favorite">
|
||||
<icon icon="star" v-if="l.isFavorite"/>
|
||||
<icon :icon="['far', 'star']" v-else/>
|
||||
</span>
|
||||
</router-link>
|
||||
<list-settings-dropdown :list="l" v-if="l.id > 0"/>
|
||||
<span class="list-setting-spacer" v-else></span>
|
||||
</li>
|
||||
</template>
|
||||
</router-link>
|
||||
<list-settings-dropdown :list="l" v-if="l.id > 0"/>
|
||||
<span class="list-setting-spacer" v-else></span>
|
||||
</li>
|
||||
</transition-group>
|
||||
</draggable>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
@ -120,17 +135,25 @@ import {mapState} from 'vuex'
|
||||
import {CURRENT_LIST, MENU_ACTIVE, LOADING, LOADING_MODULE} from '@/store/mutation-types'
|
||||
import ListSettingsDropdown from '@/components/list/list-settings-dropdown.vue'
|
||||
import NamespaceSettingsDropdown from '@/components/namespace/namespace-settings-dropdown.vue'
|
||||
import draggable from 'vuedraggable'
|
||||
import {calculateItemPosition} from '@/helpers/calculateItemPosition'
|
||||
|
||||
export default {
|
||||
name: 'navigation',
|
||||
data() {
|
||||
return {
|
||||
listsVisible: {},
|
||||
drag: false,
|
||||
dragOptions: {
|
||||
animation: 100,
|
||||
ghostClass: 'ghost',
|
||||
},
|
||||
}
|
||||
},
|
||||
components: {
|
||||
ListSettingsDropdown,
|
||||
NamespaceSettingsDropdown,
|
||||
draggable,
|
||||
},
|
||||
computed: mapState({
|
||||
namespaces: state => state.namespaces.namespaces.filter(n => !n.isArchived),
|
||||
@ -176,6 +199,19 @@ export default {
|
||||
toggleLists(namespaceId) {
|
||||
this.$set(this.listsVisible, namespaceId, !this.listsVisible[namespaceId] ?? false)
|
||||
},
|
||||
saveListPosition(e, namespaceIndex) {
|
||||
const listsFiltered = this.namespaces[namespaceIndex].lists.filter(l => !l.isArchived)
|
||||
const list = listsFiltered[e.newIndex]
|
||||
const listBefore = listsFiltered[e.newIndex - 1] ?? null
|
||||
const listAfter = listsFiltered[e.newIndex + 1] ?? null
|
||||
|
||||
list.position = calculateItemPosition(listBefore !== null ? listBefore.position : null, listAfter !== null ? listAfter.position : null)
|
||||
|
||||
this.$store.dispatch('lists/updateList', list)
|
||||
.catch(e => {
|
||||
this.error(e)
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import TaskCollectionService from '../../../services/taskCollection'
|
||||
import cloneDeep from 'lodash/cloneDeep'
|
||||
import {calculateTaskPosition} from '../../../helpers/calculateTaskPosition'
|
||||
import {calculateItemPosition} from '../../../helpers/calculateItemPosition'
|
||||
|
||||
/**
|
||||
* This mixin provides a base set of methods and properties to get tasks on a list.
|
||||
@ -195,7 +195,7 @@ export default {
|
||||
const taskBefore = this.tasks[e.newIndex - 1] ?? null
|
||||
const taskAfter = this.tasks[e.newIndex + 1] ?? null
|
||||
|
||||
task.position = calculateTaskPosition(taskBefore !== null ? taskBefore.position : null, taskAfter !== null ? taskAfter.position : null)
|
||||
task.position = calculateItemPosition(taskBefore !== null ? taskBefore.position : null, taskAfter !== null ? taskAfter.position : null)
|
||||
|
||||
this.$store.dispatch('tasks/update', task)
|
||||
.then(r => {
|
||||
|
@ -1,6 +1,4 @@
|
||||
export const calculateTaskPosition = (positionBefore: number | null, positionAfter: number | null): number => {
|
||||
console.log('calculate', positionBefore, positionAfter)
|
||||
|
||||
export const calculateItemPosition = (positionBefore: number | null, positionAfter: number | null): number => {
|
||||
if (positionBefore === null && positionAfter === null) {
|
||||
return 0
|
||||
}
|
@ -1,18 +1,18 @@
|
||||
import {calculateTaskPosition} from './calculateTaskPosition'
|
||||
import {calculateItemPosition} from './calculateItemPosition'
|
||||
|
||||
it('should calculate the task position', () => {
|
||||
const result = calculateTaskPosition(10, 100)
|
||||
const result = calculateItemPosition(10, 100)
|
||||
expect(result).toBe(55)
|
||||
})
|
||||
it('should return 0 if no position was provided', () => {
|
||||
const result = calculateTaskPosition(null, null)
|
||||
const result = calculateItemPosition(null, null)
|
||||
expect(result).toBe(0)
|
||||
})
|
||||
it('should calculate the task position for the first task', () => {
|
||||
const result = calculateTaskPosition(null, 100)
|
||||
const result = calculateItemPosition(null, 100)
|
||||
expect(result).toBe(50)
|
||||
})
|
||||
it('should calculate the task position for the last task', () => {
|
||||
const result = calculateTaskPosition(10, null)
|
||||
const result = calculateItemPosition(10, null)
|
||||
expect(result).toBe(65546)
|
||||
})
|
||||
|
@ -245,7 +245,7 @@
|
||||
}
|
||||
|
||||
span.list-menu-link, li > a {
|
||||
padding: 0.75rem .5rem 0.75rem $navbar-padding * 1.5;
|
||||
padding: 0.75rem .5rem 0.75rem ($navbar-padding * 1.5 - 1.75rem);
|
||||
transition: all 0.2s ease;
|
||||
|
||||
-webkit-border-radius: 0;
|
||||
@ -261,6 +261,18 @@
|
||||
height: 1rem;
|
||||
vertical-align: middle;
|
||||
padding-right: 0.5rem;
|
||||
|
||||
&.handle {
|
||||
opacity: 0;
|
||||
transition: opacity $transition;
|
||||
margin-right: .25rem;
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&:hover .icon.handle {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&.router-link-exact-active {
|
||||
@ -315,6 +327,10 @@
|
||||
span.list-menu-link, li > a {
|
||||
padding-left: 2rem;
|
||||
display: inline-block;
|
||||
|
||||
.icon {
|
||||
padding-bottom: .25rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -295,7 +295,7 @@ import Dropdown from '@/components/misc/dropdown.vue'
|
||||
import {playPop} from '@/helpers/playPop'
|
||||
import createTask from '@/components/tasks/mixins/createTask'
|
||||
import {getCollapsedBucketState, saveCollapsedBucketState} from '@/helpers/saveCollapsedBucketState'
|
||||
import {calculateTaskPosition} from '../../../helpers/calculateTaskPosition'
|
||||
import {calculateItemPosition} from '../../../helpers/calculateItemPosition'
|
||||
|
||||
export default {
|
||||
name: 'Kanban',
|
||||
@ -448,7 +448,7 @@ export default {
|
||||
this.$set(this.taskUpdating, task.id, true)
|
||||
this.oneTaskUpdating = true
|
||||
|
||||
task.kanbanPosition = calculateTaskPosition(taskBefore !== null ? taskBefore.kanbanPosition : null, taskAfter !== null ? taskAfter.kanbanPosition : null)
|
||||
task.kanbanPosition = calculateItemPosition(taskBefore !== null ? taskBefore.kanbanPosition : null, taskAfter !== null ? taskAfter.kanbanPosition : null)
|
||||
console.log(task.kanbanPosition)
|
||||
|
||||
task.bucketId = bucketId
|
||||
|
@ -185,7 +185,7 @@ import createTask from '@/components/tasks/mixins/createTask'
|
||||
|
||||
import {mapState} from 'vuex'
|
||||
import draggable from 'vuedraggable'
|
||||
import {calculateTaskPosition} from '../../../helpers/calculateTaskPosition'
|
||||
import {calculateItemPosition} from '../../../helpers/calculateItemPosition'
|
||||
|
||||
export default {
|
||||
name: 'List',
|
||||
@ -228,7 +228,7 @@ export default {
|
||||
return 0
|
||||
}
|
||||
|
||||
return calculateTaskPosition(null, this.tasks[0].position)
|
||||
return calculateItemPosition(null, this.tasks[0].position)
|
||||
},
|
||||
...mapState({
|
||||
canWrite: state => state.currentList.maxRight > Rights.READ,
|
||||
|
@ -90,6 +90,10 @@ export default {
|
||||
computed: mapState({
|
||||
namespaces(state) {
|
||||
return state.namespaces.namespaces.filter(n => this.showArchived ? true : !n.isArchived)
|
||||
// return state.namespaces.namespaces.filter(n => this.showArchived ? true : !n.isArchived).map(n => {
|
||||
// n.lists = n.lists.filter(l => !l.isArchived)
|
||||
// return n
|
||||
// })
|
||||
},
|
||||
loading: LOADING,
|
||||
}),
|
||||
|
Reference in New Issue
Block a user