mirror of
https://github.com/go-vikunja/vikunja.git
synced 2026-05-02 17:39:01 -05:00
chore(views): move actual project views into their own folder
This commit is contained in:
400
frontend/src/components/project/views/ProjectTable.vue
Normal file
400
frontend/src/components/project/views/ProjectTable.vue
Normal file
@@ -0,0 +1,400 @@
|
||||
<template>
|
||||
<ProjectWrapper
|
||||
class="project-table"
|
||||
:project-id="projectId"
|
||||
:viewId
|
||||
>
|
||||
<template #header>
|
||||
<div class="filter-container">
|
||||
<div class="items">
|
||||
<Popup>
|
||||
<template #trigger="{toggle}">
|
||||
<x-button
|
||||
icon="th"
|
||||
variant="secondary"
|
||||
@click.prevent.stop="toggle()"
|
||||
>
|
||||
{{ $t('project.table.columns') }}
|
||||
</x-button>
|
||||
</template>
|
||||
<template #content="{isOpen}">
|
||||
<card
|
||||
class="columns-filter"
|
||||
:class="{'is-open': isOpen}"
|
||||
>
|
||||
<Fancycheckbox v-model="activeColumns.index">
|
||||
#
|
||||
</Fancycheckbox>
|
||||
<Fancycheckbox v-model="activeColumns.done">
|
||||
{{ $t('task.attributes.done') }}
|
||||
</Fancycheckbox>
|
||||
<Fancycheckbox v-model="activeColumns.title">
|
||||
{{ $t('task.attributes.title') }}
|
||||
</Fancycheckbox>
|
||||
<Fancycheckbox v-model="activeColumns.priority">
|
||||
{{ $t('task.attributes.priority') }}
|
||||
</Fancycheckbox>
|
||||
<Fancycheckbox v-model="activeColumns.labels">
|
||||
{{ $t('task.attributes.labels') }}
|
||||
</Fancycheckbox>
|
||||
<Fancycheckbox v-model="activeColumns.assignees">
|
||||
{{ $t('task.attributes.assignees') }}
|
||||
</Fancycheckbox>
|
||||
<Fancycheckbox v-model="activeColumns.dueDate">
|
||||
{{ $t('task.attributes.dueDate') }}
|
||||
</Fancycheckbox>
|
||||
<Fancycheckbox v-model="activeColumns.startDate">
|
||||
{{ $t('task.attributes.startDate') }}
|
||||
</Fancycheckbox>
|
||||
<Fancycheckbox v-model="activeColumns.endDate">
|
||||
{{ $t('task.attributes.endDate') }}
|
||||
</Fancycheckbox>
|
||||
<Fancycheckbox v-model="activeColumns.percentDone">
|
||||
{{ $t('task.attributes.percentDone') }}
|
||||
</Fancycheckbox>
|
||||
<Fancycheckbox v-model="activeColumns.doneAt">
|
||||
{{ $t('task.attributes.doneAt') }}
|
||||
</Fancycheckbox>
|
||||
<Fancycheckbox v-model="activeColumns.created">
|
||||
{{ $t('task.attributes.created') }}
|
||||
</Fancycheckbox>
|
||||
<Fancycheckbox v-model="activeColumns.updated">
|
||||
{{ $t('task.attributes.updated') }}
|
||||
</Fancycheckbox>
|
||||
<Fancycheckbox v-model="activeColumns.createdBy">
|
||||
{{ $t('task.attributes.createdBy') }}
|
||||
</Fancycheckbox>
|
||||
</card>
|
||||
</template>
|
||||
</Popup>
|
||||
<FilterPopup v-model="params" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #default>
|
||||
<div
|
||||
:class="{'is-loading': loading}"
|
||||
class="loader-container"
|
||||
>
|
||||
<card
|
||||
:padding="false"
|
||||
:has-content="false"
|
||||
>
|
||||
<div class="has-horizontal-overflow">
|
||||
<table class="table has-actions is-hoverable is-fullwidth mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-if="activeColumns.index">
|
||||
#
|
||||
<Sort
|
||||
:order="sortBy.index"
|
||||
@click="sort('index')"
|
||||
/>
|
||||
</th>
|
||||
<th v-if="activeColumns.done">
|
||||
{{ $t('task.attributes.done') }}
|
||||
<Sort
|
||||
:order="sortBy.done"
|
||||
@click="sort('done')"
|
||||
/>
|
||||
</th>
|
||||
<th v-if="activeColumns.title">
|
||||
{{ $t('task.attributes.title') }}
|
||||
<Sort
|
||||
:order="sortBy.title"
|
||||
@click="sort('title')"
|
||||
/>
|
||||
</th>
|
||||
<th v-if="activeColumns.priority">
|
||||
{{ $t('task.attributes.priority') }}
|
||||
<Sort
|
||||
:order="sortBy.priority"
|
||||
@click="sort('priority')"
|
||||
/>
|
||||
</th>
|
||||
<th v-if="activeColumns.labels">
|
||||
{{ $t('task.attributes.labels') }}
|
||||
</th>
|
||||
<th v-if="activeColumns.assignees">
|
||||
{{ $t('task.attributes.assignees') }}
|
||||
</th>
|
||||
<th v-if="activeColumns.dueDate">
|
||||
{{ $t('task.attributes.dueDate') }}
|
||||
<Sort
|
||||
:order="sortBy.due_date"
|
||||
@click="sort('due_date')"
|
||||
/>
|
||||
</th>
|
||||
<th v-if="activeColumns.startDate">
|
||||
{{ $t('task.attributes.startDate') }}
|
||||
<Sort
|
||||
:order="sortBy.start_date"
|
||||
@click="sort('start_date')"
|
||||
/>
|
||||
</th>
|
||||
<th v-if="activeColumns.endDate">
|
||||
{{ $t('task.attributes.endDate') }}
|
||||
<Sort
|
||||
:order="sortBy.end_date"
|
||||
@click="sort('end_date')"
|
||||
/>
|
||||
</th>
|
||||
<th v-if="activeColumns.percentDone">
|
||||
{{ $t('task.attributes.percentDone') }}
|
||||
<Sort
|
||||
:order="sortBy.percent_done"
|
||||
@click="sort('percent_done')"
|
||||
/>
|
||||
</th>
|
||||
<th v-if="activeColumns.doneAt">
|
||||
{{ $t('task.attributes.doneAt') }}
|
||||
<Sort
|
||||
:order="sortBy.done_at"
|
||||
@click="sort('done_at')"
|
||||
/>
|
||||
</th>
|
||||
<th v-if="activeColumns.created">
|
||||
{{ $t('task.attributes.created') }}
|
||||
<Sort
|
||||
:order="sortBy.created"
|
||||
@click="sort('created')"
|
||||
/>
|
||||
</th>
|
||||
<th v-if="activeColumns.updated">
|
||||
{{ $t('task.attributes.updated') }}
|
||||
<Sort
|
||||
:order="sortBy.updated"
|
||||
@click="sort('updated')"
|
||||
/>
|
||||
</th>
|
||||
<th v-if="activeColumns.createdBy">
|
||||
{{ $t('task.attributes.createdBy') }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="t in tasks"
|
||||
:key="t.id"
|
||||
>
|
||||
<td v-if="activeColumns.index">
|
||||
<router-link :to="taskDetailRoutes[t.id]">
|
||||
<template v-if="t.identifier === ''">
|
||||
#{{ t.index }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ t.identifier }}
|
||||
</template>
|
||||
</router-link>
|
||||
</td>
|
||||
<td v-if="activeColumns.done">
|
||||
<Done
|
||||
:is-done="t.done"
|
||||
variant="small"
|
||||
/>
|
||||
</td>
|
||||
<td v-if="activeColumns.title">
|
||||
<router-link :to="taskDetailRoutes[t.id]">
|
||||
{{ t.title }}
|
||||
</router-link>
|
||||
</td>
|
||||
<td v-if="activeColumns.priority">
|
||||
<PriorityLabel
|
||||
:priority="t.priority"
|
||||
:done="t.done"
|
||||
:show-all="true"
|
||||
/>
|
||||
</td>
|
||||
<td v-if="activeColumns.labels">
|
||||
<Labels :labels="t.labels" />
|
||||
</td>
|
||||
<td v-if="activeColumns.assignees">
|
||||
<AssigneeList
|
||||
v-if="t.assignees.length > 0"
|
||||
:assignees="t.assignees"
|
||||
:avatar-size="28"
|
||||
class="ml-1"
|
||||
:inline="true"
|
||||
/>
|
||||
</td>
|
||||
<DateTableCell
|
||||
v-if="activeColumns.dueDate"
|
||||
:date="t.dueDate"
|
||||
/>
|
||||
<DateTableCell
|
||||
v-if="activeColumns.startDate"
|
||||
:date="t.startDate"
|
||||
/>
|
||||
<DateTableCell
|
||||
v-if="activeColumns.endDate"
|
||||
:date="t.endDate"
|
||||
/>
|
||||
<td v-if="activeColumns.percentDone">
|
||||
{{ t.percentDone * 100 }}%
|
||||
</td>
|
||||
<DateTableCell
|
||||
v-if="activeColumns.doneAt"
|
||||
:date="t.doneAt"
|
||||
/>
|
||||
<DateTableCell
|
||||
v-if="activeColumns.created"
|
||||
:date="t.created"
|
||||
/>
|
||||
<DateTableCell
|
||||
v-if="activeColumns.updated"
|
||||
:date="t.updated"
|
||||
/>
|
||||
<td v-if="activeColumns.createdBy">
|
||||
<User
|
||||
:avatar-size="27"
|
||||
:show-username="false"
|
||||
:user="t.createdBy"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<Pagination
|
||||
:total-pages="totalPages"
|
||||
:current-page="currentPage"
|
||||
/>
|
||||
</card>
|
||||
</div>
|
||||
</template>
|
||||
</ProjectWrapper>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {computed, type Ref} from 'vue'
|
||||
|
||||
import {useStorage} from '@vueuse/core'
|
||||
|
||||
import ProjectWrapper from '@/components/project/ProjectWrapper.vue'
|
||||
import Done from '@/components/misc/Done.vue'
|
||||
import User from '@/components/misc/user.vue'
|
||||
import PriorityLabel from '@/components/tasks/partials/priorityLabel.vue'
|
||||
import Labels from '@/components/tasks/partials/labels.vue'
|
||||
import DateTableCell from '@/components/tasks/partials/date-table-cell.vue'
|
||||
import Fancycheckbox from '@/components/input/fancycheckbox.vue'
|
||||
import Sort from '@/components/tasks/partials/sort.vue'
|
||||
import FilterPopup from '@/components/project/partials/filter-popup.vue'
|
||||
import Pagination from '@/components/misc/pagination.vue'
|
||||
import Popup from '@/components/misc/popup.vue'
|
||||
|
||||
import type {SortBy} from '@/composables/useTaskList'
|
||||
import {useTaskList} from '@/composables/useTaskList'
|
||||
import type {ITask} from '@/modelTypes/ITask'
|
||||
import type {IProject} from '@/modelTypes/IProject'
|
||||
import AssigneeList from '@/components/tasks/partials/assigneeList.vue'
|
||||
import type {IProjectView} from '@/modelTypes/IProjectView'
|
||||
|
||||
const {
|
||||
projectId,
|
||||
viewId,
|
||||
} = defineProps<{
|
||||
projectId: IProject['id'],
|
||||
viewId: IProjectView['id'],
|
||||
}>()
|
||||
|
||||
const ACTIVE_COLUMNS_DEFAULT = {
|
||||
index: true,
|
||||
done: true,
|
||||
title: true,
|
||||
priority: false,
|
||||
labels: true,
|
||||
assignees: true,
|
||||
dueDate: true,
|
||||
startDate: false,
|
||||
endDate: false,
|
||||
percentDone: false,
|
||||
created: false,
|
||||
updated: false,
|
||||
createdBy: false,
|
||||
doneAt: false,
|
||||
}
|
||||
|
||||
const SORT_BY_DEFAULT: SortBy = {
|
||||
index: 'desc',
|
||||
}
|
||||
|
||||
const activeColumns = useStorage('tableViewColumns', {...ACTIVE_COLUMNS_DEFAULT})
|
||||
const sortBy = useStorage<SortBy>('tableViewSortBy', {...SORT_BY_DEFAULT})
|
||||
|
||||
const taskList = useTaskList(() => projectId, () => viewId, sortBy.value)
|
||||
|
||||
const {
|
||||
loading,
|
||||
params,
|
||||
totalPages,
|
||||
currentPage,
|
||||
sortByParam,
|
||||
} = taskList
|
||||
const tasks: Ref<ITask[]> = taskList.tasks
|
||||
|
||||
Object.assign(params.value, {
|
||||
filter: '',
|
||||
})
|
||||
|
||||
// FIXME: by doing this we can have multiple sort orders
|
||||
function sort(property: keyof SortBy) {
|
||||
const order = sortBy.value[property]
|
||||
if (typeof order === 'undefined' || order === 'none') {
|
||||
sortBy.value[property] = 'desc'
|
||||
} else if (order === 'desc') {
|
||||
sortBy.value[property] = 'asc'
|
||||
} else {
|
||||
delete sortBy.value[property]
|
||||
}
|
||||
sortByParam.value = sortBy.value
|
||||
}
|
||||
|
||||
// TODO: re-enable opening task detail in modal
|
||||
// const router = useRouter()
|
||||
const taskDetailRoutes = computed(() => Object.fromEntries(
|
||||
tasks.value.map(({id}) => ([
|
||||
id,
|
||||
{
|
||||
name: 'task.detail',
|
||||
params: {id},
|
||||
// state: { backdropView: router.currentRoute.value.fullPath },
|
||||
},
|
||||
])),
|
||||
))
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.table {
|
||||
background: transparent;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
|
||||
th {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.user {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.columns-filter {
|
||||
margin: 0;
|
||||
|
||||
:deep(.card-content .content) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&.is-open {
|
||||
margin: 2rem 0 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.link-share-view .card {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user