feat(views): allow reordering views
Resolves https://community.vikunja.io/t/reordering-views/2394
This commit is contained in:
parent
9f604eca79
commit
d12deee977
@ -401,8 +401,9 @@
|
|||||||
"titleRequired": "Please provide a title.",
|
"titleRequired": "Please provide a title.",
|
||||||
"delete": "Delete this view",
|
"delete": "Delete this view",
|
||||||
"deleteText": "Are you sure you want to remove this view? It will no longer be possible to use it to view tasks in this project. This action won't delete any tasks. This cannot be undone!",
|
"deleteText": "Are you sure you want to remove this view? It will no longer be possible to use it to view tasks in this project. This action won't delete any tasks. This cannot be undone!",
|
||||||
"deleteSuccess": "The view was successfully deleted",
|
"deleteSuccess": "The view was deleted successfully.",
|
||||||
"onlyAdminsCanEdit": "Only project admins can edit views."
|
"onlyAdminsCanEdit": "Only project admins can edit views.",
|
||||||
|
"updateSuccess": "The view was updated successfully."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"filters": {
|
"filters": {
|
||||||
|
@ -224,11 +224,13 @@ export const useProjectStore = defineStore('project', () => {
|
|||||||
const viewPos = projects.value[view.projectId].views.findIndex(v => v.id === view.id)
|
const viewPos = projects.value[view.projectId].views.findIndex(v => v.id === view.id)
|
||||||
if (viewPos !== -1) {
|
if (viewPos !== -1) {
|
||||||
projects.value[view.projectId].views[viewPos] = view
|
projects.value[view.projectId].views[viewPos] = view
|
||||||
|
projects.value[view.projectId].views.sort((a, b) => a.position < b.position ? -1 : 1)
|
||||||
setProject(projects.value[view.projectId])
|
setProject(projects.value[view.projectId])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
projects.value[view.projectId].views.push(view)
|
projects.value[view.projectId].views.push(view)
|
||||||
|
projects.value[view.projectId].views.sort((a, b) => a.position < b.position ? -1 : 1)
|
||||||
|
|
||||||
setProject(projects.value[view.projectId])
|
setProject(projects.value[view.projectId])
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import CreateEdit from '@/components/misc/CreateEdit.vue'
|
import CreateEdit from '@/components/misc/CreateEdit.vue'
|
||||||
import {watch, ref, computed} from 'vue'
|
import {watch, ref} from 'vue'
|
||||||
import {useProjectStore} from '@/stores/projects'
|
import {useProjectStore} from '@/stores/projects'
|
||||||
import ProjectViewModel from '@/models/projectView'
|
import ProjectViewModel from '@/models/projectView'
|
||||||
import type {IProjectView} from '@/modelTypes/IProjectView'
|
import type {IProjectView} from '@/modelTypes/IProjectView'
|
||||||
@ -13,6 +13,8 @@ import ProjectService from '@/services/project'
|
|||||||
import {RIGHTS} from '@/constants/rights'
|
import {RIGHTS} from '@/constants/rights'
|
||||||
import ProjectModel from '@/models/project'
|
import ProjectModel from '@/models/project'
|
||||||
import Message from '@/components/misc/Message.vue'
|
import Message from '@/components/misc/Message.vue'
|
||||||
|
import draggable from 'zhyswan-vuedraggable'
|
||||||
|
import {calculateItemPosition} from '@/helpers/calculateItemPosition'
|
||||||
|
|
||||||
const {
|
const {
|
||||||
projectId,
|
projectId,
|
||||||
@ -23,7 +25,19 @@ const {
|
|||||||
const projectStore = useProjectStore()
|
const projectStore = useProjectStore()
|
||||||
const {t} = useI18n()
|
const {t} = useI18n()
|
||||||
|
|
||||||
const views = computed(() => projectStore.projects[projectId]?.views)
|
const views = ref<IProjectView[]>([])
|
||||||
|
watch(
|
||||||
|
projectStore.projects[projectId]?.views,
|
||||||
|
allViews => {
|
||||||
|
if (!allViews) {
|
||||||
|
views.value = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
views.value = [...allViews]
|
||||||
|
},
|
||||||
|
{immediate: true},
|
||||||
|
)
|
||||||
|
|
||||||
const showCreateForm = ref(false)
|
const showCreateForm = ref(false)
|
||||||
|
|
||||||
const projectViewService = ref(new ProjectViewService())
|
const projectViewService = ref(new ProjectViewService())
|
||||||
@ -91,6 +105,21 @@ async function saveView() {
|
|||||||
const result = await projectViewService.value.update(viewToEdit.value)
|
const result = await projectViewService.value.update(viewToEdit.value)
|
||||||
projectStore.setProjectView(result)
|
projectStore.setProjectView(result)
|
||||||
viewToEdit.value = null
|
viewToEdit.value = null
|
||||||
|
success({message: t('project.views.updateSuccess')})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveViewPosition(e) {
|
||||||
|
const view = views.value[e.newIndex]
|
||||||
|
const viewBefore = views.value[e.newIndex - 1] ?? null
|
||||||
|
const viewAfter = views.value[e.newIndex + 1] ?? null
|
||||||
|
|
||||||
|
const position = calculateItemPosition(viewBefore !== null ? viewBefore.position : null, viewAfter !== null ? viewAfter.position : null)
|
||||||
|
const result = await projectViewService.value.update({
|
||||||
|
...view,
|
||||||
|
position,
|
||||||
|
})
|
||||||
|
projectStore.setProjectView(result)
|
||||||
|
success({message: t('project.views.updateSuccess')})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -135,11 +164,16 @@ async function saveView() {
|
|||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<draggable
|
||||||
<tr
|
v-model="views"
|
||||||
v-for="v in views"
|
tag="tbody"
|
||||||
:key="v.id"
|
item-key="id"
|
||||||
|
handle=".handle"
|
||||||
|
:animation="100"
|
||||||
|
@end="saveViewPosition"
|
||||||
>
|
>
|
||||||
|
<template #item="{element: v}">
|
||||||
|
<tr>
|
||||||
<template v-if="viewToEdit !== null && viewToEdit.id === v.id">
|
<template v-if="viewToEdit !== null && viewToEdit.id === v.id">
|
||||||
<td colspan="3">
|
<td colspan="3">
|
||||||
<ViewEditForm
|
<ViewEditForm
|
||||||
@ -155,7 +189,7 @@ async function saveView() {
|
|||||||
<template v-else>
|
<template v-else>
|
||||||
<td>{{ v.title }}</td>
|
<td>{{ v.title }}</td>
|
||||||
<td>{{ v.viewKind }}</td>
|
<td>{{ v.viewKind }}</td>
|
||||||
<td class="has-text-right">
|
<td class="has-text-right actions">
|
||||||
<XButton
|
<XButton
|
||||||
v-if="isAdmin"
|
v-if="isAdmin"
|
||||||
class="is-danger mr-2"
|
class="is-danger mr-2"
|
||||||
@ -170,10 +204,14 @@ async function saveView() {
|
|||||||
icon="pen"
|
icon="pen"
|
||||||
@click="viewToEdit = {...v}"
|
@click="viewToEdit = {...v}"
|
||||||
/>
|
/>
|
||||||
|
<span class="icon handle">
|
||||||
|
<icon icon="grip-lines" />
|
||||||
|
</span>
|
||||||
</td>
|
</td>
|
||||||
</template>
|
</template>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</template>
|
||||||
|
</draggable>
|
||||||
</table>
|
</table>
|
||||||
</CreateEdit>
|
</CreateEdit>
|
||||||
|
|
||||||
@ -191,3 +229,16 @@ async function saveView() {
|
|||||||
</template>
|
</template>
|
||||||
</modal>
|
</modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.handle {
|
||||||
|
cursor: grab;
|
||||||
|
margin-left: .25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
</style>
|
@ -302,9 +302,7 @@ func (p *Project) ReadOne(s *xorm.Session, a web.Auth) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.
|
p.Views, err = getViewsForProject(s, p.ID)
|
||||||
Where("project_id = ?", p.ID).
|
|
||||||
Find(&p.Views)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -640,6 +638,7 @@ func addProjectDetails(s *xorm.Session, projects []*Project, a web.Auth) (err er
|
|||||||
views := []*ProjectView{}
|
views := []*ProjectView{}
|
||||||
err = s.
|
err = s.
|
||||||
In("project_id", projectIDs).
|
In("project_id", projectIDs).
|
||||||
|
OrderBy("position asc").
|
||||||
Find(&views)
|
Find(&views)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -160,6 +160,7 @@ func getViewsForProject(s *xorm.Session, projectID int64) (views []*ProjectView,
|
|||||||
views = []*ProjectView{}
|
views = []*ProjectView{}
|
||||||
err = s.
|
err = s.
|
||||||
Where("project_id = ?", projectID).
|
Where("project_id = ?", projectID).
|
||||||
|
OrderBy("position asc").
|
||||||
Find(&views)
|
Find(&views)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user