fix(filters): rework filter popup button
This commit is contained in:
parent
79577c14b7
commit
15215b30a0
@ -1,11 +1,4 @@
|
|||||||
<template>
|
<template>
|
||||||
<x-button
|
|
||||||
v-if="hasFilters"
|
|
||||||
variant="secondary"
|
|
||||||
@click="clearFilters"
|
|
||||||
>
|
|
||||||
{{ $t('filters.clear') }}
|
|
||||||
</x-button>
|
|
||||||
<x-button
|
<x-button
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
icon="filter"
|
icon="filter"
|
||||||
|
@ -25,6 +25,13 @@
|
|||||||
v-if="hasFooter"
|
v-if="hasFooter"
|
||||||
#footer
|
#footer
|
||||||
>
|
>
|
||||||
|
<x-button
|
||||||
|
variant="secondary"
|
||||||
|
@click.prevent.stop="clearFiltersAndEmit"
|
||||||
|
class="mr-2"
|
||||||
|
>
|
||||||
|
{{ $t('filters.clear') }}
|
||||||
|
</x-button>
|
||||||
<x-button
|
<x-button
|
||||||
variant="primary"
|
variant="primary"
|
||||||
@click.prevent.stop="changeAndEmitButton"
|
@click.prevent.stop="changeAndEmitButton"
|
||||||
@ -130,4 +137,9 @@ function changeAndEmitButton() {
|
|||||||
change()
|
change()
|
||||||
emit('showResultsButtonClicked')
|
emit('showResultsButtonClicked')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clearFiltersAndEmit() {
|
||||||
|
params.value.filter = ''
|
||||||
|
changeAndEmitButton()
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -18,13 +18,11 @@ $filter-container-top-link-share-list: -47px;
|
|||||||
margin-top: $filter-container-top-default;
|
margin-top: $filter-container-top-default;
|
||||||
z-index: 4;
|
z-index: 4;
|
||||||
|
|
||||||
.items {
|
display: flex;
|
||||||
display: flex;
|
justify-content: flex-end;
|
||||||
justify-content: flex-end;
|
|
||||||
|
|
||||||
.button:not(:last-of-type) {
|
.button:not(:last-of-type) {
|
||||||
margin-right: .5rem;
|
margin-right: .5rem;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
@ -35,37 +33,6 @@ $filter-container-top-link-share-list: -47px;
|
|||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fancycheckbox {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
margin-right: .5rem;
|
|
||||||
|
|
||||||
.field {
|
|
||||||
transition: width $transition;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
&.hidden {
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
margin: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.filters input {
|
|
||||||
font-size: .9rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: $tablet) {
|
@media screen and (max-width: $tablet) {
|
||||||
position: static;
|
position: static;
|
||||||
margin: 0 0 1rem 0 !important;
|
margin: 0 0 1rem 0 !important;
|
||||||
|
@ -5,13 +5,11 @@
|
|||||||
view-name="kanban"
|
view-name="kanban"
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<div
|
<div class="filter-container">
|
||||||
v-if="!isSavedFilter(project)"
|
<FilterPopup
|
||||||
class="filter-container"
|
v-if="!isSavedFilter(project)"
|
||||||
>
|
v-model="params"
|
||||||
<div class="items">
|
/>
|
||||||
<FilterPopup v-model="params" />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -47,7 +45,7 @@
|
|||||||
v-tooltip="$t('project.kanban.doneBucketHint')"
|
v-tooltip="$t('project.kanban.doneBucketHint')"
|
||||||
class="icon is-small has-text-success mr-2"
|
class="icon is-small has-text-success mr-2"
|
||||||
>
|
>
|
||||||
<icon icon="check-double" />
|
<icon icon="check-double"/>
|
||||||
</span>
|
</span>
|
||||||
<h2
|
<h2
|
||||||
class="title input"
|
class="title input"
|
||||||
@ -197,7 +195,9 @@
|
|||||||
variant="secondary"
|
variant="secondary"
|
||||||
@click="toggleShowNewTaskInput(bucket.id)"
|
@click="toggleShowNewTaskInput(bucket.id)"
|
||||||
>
|
>
|
||||||
{{ bucket.tasks.length === 0 ? $t('project.kanban.addTask') : $t('project.kanban.addAnotherTask') }}
|
{{
|
||||||
|
bucket.tasks.length === 0 ? $t('project.kanban.addTask') : $t('project.kanban.addAnotherTask')
|
||||||
|
}}
|
||||||
</x-button>
|
</x-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -290,7 +290,11 @@ import KanbanCard from '@/components/tasks/partials/kanban-card.vue'
|
|||||||
import Dropdown from '@/components/misc/dropdown.vue'
|
import Dropdown from '@/components/misc/dropdown.vue'
|
||||||
import DropdownItem from '@/components/misc/dropdown-item.vue'
|
import DropdownItem from '@/components/misc/dropdown-item.vue'
|
||||||
|
|
||||||
import {getCollapsedBucketState, saveCollapsedBucketState, type CollapsedBuckets} from '@/helpers/saveCollapsedBucketState'
|
import {
|
||||||
|
type CollapsedBuckets,
|
||||||
|
getCollapsedBucketState,
|
||||||
|
saveCollapsedBucketState,
|
||||||
|
} from '@/helpers/saveCollapsedBucketState'
|
||||||
import {calculateItemPosition} from '@/helpers/calculateItemPosition'
|
import {calculateItemPosition} from '@/helpers/calculateItemPosition'
|
||||||
|
|
||||||
import {isSavedFilter} from '@/services/savedFilter'
|
import {isSavedFilter} from '@/services/savedFilter'
|
||||||
@ -322,7 +326,7 @@ const kanbanStore = useKanbanStore()
|
|||||||
const taskStore = useTaskStore()
|
const taskStore = useTaskStore()
|
||||||
const projectStore = useProjectStore()
|
const projectStore = useProjectStore()
|
||||||
|
|
||||||
const taskContainerRefs = ref<{[id: IBucket['id']]: HTMLElement}>({})
|
const taskContainerRefs = ref<{ [id: IBucket['id']]: HTMLElement }>({})
|
||||||
const bucketLimitInputRef = ref<HTMLInputElement | null>(null)
|
const bucketLimitInputRef = ref<HTMLInputElement | null>(null)
|
||||||
|
|
||||||
const drag = ref(false)
|
const drag = ref(false)
|
||||||
@ -334,18 +338,18 @@ const bucketToDelete = ref(0)
|
|||||||
const bucketTitleEditable = ref(false)
|
const bucketTitleEditable = ref(false)
|
||||||
|
|
||||||
const newTaskText = ref('')
|
const newTaskText = ref('')
|
||||||
const showNewTaskInput = ref<{[id: IBucket['id']]: boolean}>({})
|
const showNewTaskInput = ref<{ [id: IBucket['id']]: boolean }>({})
|
||||||
|
|
||||||
const newBucketTitle = ref('')
|
const newBucketTitle = ref('')
|
||||||
const showNewBucketInput = ref(false)
|
const showNewBucketInput = ref(false)
|
||||||
const newTaskError = ref<{[id: IBucket['id']]: boolean}>({})
|
const newTaskError = ref<{ [id: IBucket['id']]: boolean }>({})
|
||||||
const newTaskInputFocused = ref(false)
|
const newTaskInputFocused = ref(false)
|
||||||
|
|
||||||
const showSetLimitInput = ref(false)
|
const showSetLimitInput = ref(false)
|
||||||
const collapsedBuckets = ref<CollapsedBuckets>({})
|
const collapsedBuckets = ref<CollapsedBuckets>({})
|
||||||
|
|
||||||
// We're using this to show the loading animation only at the task when updating it
|
// We're using this to show the loading animation only at the task when updating it
|
||||||
const taskUpdating = ref<{[id: ITask['id']]: boolean}>({})
|
const taskUpdating = ref<{ [id: ITask['id']]: boolean }>({})
|
||||||
const oneTaskUpdating = ref(false)
|
const oneTaskUpdating = ref(false)
|
||||||
|
|
||||||
const params = ref<TaskFilterParams>({
|
const params = ref<TaskFilterParams>({
|
||||||
@ -378,7 +382,7 @@ const bucketDraggableComponentData = computed(() => ({
|
|||||||
],
|
],
|
||||||
}))
|
}))
|
||||||
const canWrite = computed(() => baseStore.currentProject?.maxRight > Rights.READ)
|
const canWrite = computed(() => baseStore.currentProject?.maxRight > Rights.READ)
|
||||||
const project = computed(() => projectId ? projectStore.projects[projectId]: null)
|
const project = computed(() => projectId ? projectStore.projects[projectId] : null)
|
||||||
|
|
||||||
const buckets = computed(() => kanbanStore.buckets)
|
const buckets = computed(() => kanbanStore.buckets)
|
||||||
const loading = computed(() => kanbanStore.isLoading)
|
const loading = computed(() => kanbanStore.isLoading)
|
||||||
@ -497,7 +501,7 @@ async function updateTaskPosition(e) {
|
|||||||
await taskStore.update(newTask)
|
await taskStore.update(newTask)
|
||||||
|
|
||||||
// Make sure the first and second task don't both get position 0 assigned
|
// Make sure the first and second task don't both get position 0 assigned
|
||||||
if(newTaskIndex === 0 && taskAfter !== null && taskAfter.kanbanPosition === 0) {
|
if (newTaskIndex === 0 && taskAfter !== null && taskAfter.kanbanPosition === 0) {
|
||||||
const taskAfterAfter = newBucket.tasks[newTaskIndex + 2] ?? null
|
const taskAfterAfter = newBucket.tasks[newTaskIndex + 2] ?? null
|
||||||
const newTaskAfter = klona(taskAfter) // cloning the task to avoid pinia store manipulation
|
const newTaskAfter = klona(taskAfter) // cloning the task to avoid pinia store manipulation
|
||||||
newTaskAfter.bucketId = newBucket.id
|
newTaskAfter.bucketId = newBucket.id
|
||||||
@ -602,7 +606,7 @@ function updateBuckets(value: IBucket[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: fix type
|
// TODO: fix type
|
||||||
function updateBucketPosition(e: {newIndex: number}) {
|
function updateBucketPosition(e: { newIndex: number }) {
|
||||||
// (2) bucket positon is changed
|
// (2) bucket positon is changed
|
||||||
dragBucket.value = false
|
dragBucket.value = false
|
||||||
|
|
||||||
@ -631,19 +635,19 @@ async function saveBucketLimit(bucketId: IBucket['id'], limit: number) {
|
|||||||
success({message: t('project.kanban.bucketLimitSavedSuccess')})
|
success({message: t('project.kanban.bucketLimitSavedSuccess')})
|
||||||
}
|
}
|
||||||
|
|
||||||
const setBucketLimitCancel = ref<number|null>(null)
|
const setBucketLimitCancel = ref<number | null>(null)
|
||||||
|
|
||||||
async function setBucketLimit(bucketId: IBucket['id'], now: boolean = false) {
|
async function setBucketLimit(bucketId: IBucket['id'], now: boolean = false) {
|
||||||
const limit = parseInt(bucketLimitInputRef.value?.value || '')
|
const limit = parseInt(bucketLimitInputRef.value?.value || '')
|
||||||
|
|
||||||
if (setBucketLimitCancel.value !== null) {
|
if (setBucketLimitCancel.value !== null) {
|
||||||
clearTimeout(setBucketLimitCancel.value)
|
clearTimeout(setBucketLimitCancel.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (now) {
|
if (now) {
|
||||||
return saveBucketLimit(bucketId, limit)
|
return saveBucketLimit(bucketId, limit)
|
||||||
}
|
}
|
||||||
|
|
||||||
setBucketLimitCancel.value = setTimeout(saveBucketLimit, 2500, bucketId, limit)
|
setBucketLimitCancel.value = setTimeout(saveBucketLimit, 2500, bucketId, limit)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -739,6 +743,7 @@ $filter-container-height: '1rem - #{$switch-view-height}';
|
|||||||
* {
|
* {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -780,6 +785,7 @@ $filter-container-height: '1rem - #{$switch-view-height}';
|
|||||||
&:first-of-type {
|
&:first-of-type {
|
||||||
padding-top: .5rem;
|
padding-top: .5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:last-of-type {
|
&:last-of-type {
|
||||||
padding-bottom: .5rem;
|
padding-bottom: .5rem;
|
||||||
}
|
}
|
||||||
|
@ -5,52 +5,12 @@
|
|||||||
view-name="project"
|
view-name="project"
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<div
|
<div class="filter-container">
|
||||||
v-if="!isSavedFilter(project)"
|
<FilterPopup
|
||||||
class="filter-container"
|
v-if="!isSavedFilter(project)"
|
||||||
>
|
v-model="params"
|
||||||
<div class="items">
|
@update:modelValue="prepareFiltersAndLoadTasks()"
|
||||||
<div class="search">
|
/>
|
||||||
<div
|
|
||||||
:class="{ hidden: !showTaskSearch }"
|
|
||||||
class="field has-addons"
|
|
||||||
>
|
|
||||||
<div class="control has-icons-left has-icons-right">
|
|
||||||
<input
|
|
||||||
v-model="searchTerm"
|
|
||||||
v-focus
|
|
||||||
class="input"
|
|
||||||
:placeholder="$t('misc.search')"
|
|
||||||
type="text"
|
|
||||||
@blur="hideSearchBar()"
|
|
||||||
@keyup.enter="searchTasks"
|
|
||||||
>
|
|
||||||
<span class="icon is-left">
|
|
||||||
<icon icon="search" />
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="control">
|
|
||||||
<x-button
|
|
||||||
:loading="loading"
|
|
||||||
:shadow="false"
|
|
||||||
@click="searchTasks"
|
|
||||||
>
|
|
||||||
{{ $t('misc.search') }}
|
|
||||||
</x-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<x-button
|
|
||||||
v-if="!showTaskSearch"
|
|
||||||
icon="search"
|
|
||||||
variant="secondary"
|
|
||||||
@click="showTaskSearch = !showTaskSearch"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<FilterPopup
|
|
||||||
v-model="params"
|
|
||||||
@update:modelValue="prepareFiltersAndLoadTasks()"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -113,14 +73,14 @@
|
|||||||
>
|
>
|
||||||
<template v-if="canWrite">
|
<template v-if="canWrite">
|
||||||
<span class="icon handle">
|
<span class="icon handle">
|
||||||
<icon icon="grip-lines" />
|
<icon icon="grip-lines"/>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</SingleTaskInProject>
|
</SingleTaskInProject>
|
||||||
</template>
|
</template>
|
||||||
</draggable>
|
</draggable>
|
||||||
|
|
||||||
<Pagination
|
<Pagination
|
||||||
:total-pages="totalPages"
|
:total-pages="totalPages"
|
||||||
:current-page="currentPage"
|
:current-page="currentPage"
|
||||||
/>
|
/>
|
||||||
@ -131,7 +91,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export default { name: 'List' }
|
export default {name: 'List'}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@ -183,7 +143,7 @@ const {
|
|||||||
searchTerm,
|
searchTerm,
|
||||||
params,
|
params,
|
||||||
sortByParam,
|
sortByParam,
|
||||||
} = useTaskList(() => projectId, {position: 'asc' })
|
} = useTaskList(() => projectId, {position: 'asc'})
|
||||||
|
|
||||||
const tasks = ref<ITask[]>([])
|
const tasks = ref<ITask[]>([])
|
||||||
watch(
|
watch(
|
||||||
@ -203,7 +163,7 @@ watch(
|
|||||||
|
|
||||||
// If the task is a subtask, make sure the parent task is available in the current view as well
|
// If the task is a subtask, make sure the parent task is available in the current view as well
|
||||||
for (const pt of t.relatedTasks.parenttask) {
|
for (const pt of t.relatedTasks.parenttask) {
|
||||||
if(typeof tasksById[pt.id] === 'undefined') {
|
if (typeof tasksById[pt.id] === 'undefined') {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -265,16 +225,16 @@ function hideSearchBar() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const addTaskRef = ref<typeof AddTask | null>(null)
|
const addTaskRef = ref<typeof AddTask | null>(null)
|
||||||
|
|
||||||
function focusNewTaskInput() {
|
function focusNewTaskInput() {
|
||||||
addTaskRef.value?.focusTaskInput()
|
addTaskRef.value?.focusTaskInput()
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateTaskList(task: ITask) {
|
function updateTaskList(task: ITask) {
|
||||||
if (isAlphabeticalSorting.value ) {
|
if (isAlphabeticalSorting.value) {
|
||||||
// reload tasks with current filter and sorting
|
// reload tasks with current filter and sorting
|
||||||
loadTasks()
|
loadTasks()
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
allTasks.value = [
|
allTasks.value = [
|
||||||
task,
|
task,
|
||||||
...allTasks.value,
|
...allTasks.value,
|
||||||
@ -310,8 +270,8 @@ async function saveTaskPosition(e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function prepareFiltersAndLoadTasks() {
|
function prepareFiltersAndLoadTasks() {
|
||||||
if(isAlphabeticalSorting.value) {
|
if (isAlphabeticalSorting.value) {
|
||||||
sortByParam.value = {}
|
sortByParam.value = {}
|
||||||
sortByParam.value[ALPHABETICAL_SORT] = 'asc'
|
sortByParam.value[ALPHABETICAL_SORT] = 'asc'
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,7 +288,7 @@ function prepareFiltersAndLoadTasks() {
|
|||||||
border-radius: $radius;
|
border-radius: $radius;
|
||||||
background: var(--grey-100);
|
background: var(--grey-100);
|
||||||
border: 2px dashed var(--grey-300);
|
border: 2px dashed var(--grey-300);
|
||||||
|
|
||||||
* {
|
* {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
@ -339,8 +299,8 @@ function prepareFiltersAndLoadTasks() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.link-share-view .card {
|
.link-share-view .card {
|
||||||
border: none;
|
border: none;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.control.has-icons-left .icon,
|
.control.has-icons-left .icon,
|
||||||
|
@ -67,7 +67,7 @@
|
|||||||
</card>
|
</card>
|
||||||
</template>
|
</template>
|
||||||
</Popup>
|
</Popup>
|
||||||
<FilterPopup v-model="params" />
|
<FilterPopup v-model="params"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -84,175 +84,175 @@
|
|||||||
<div class="has-horizontal-overflow">
|
<div class="has-horizontal-overflow">
|
||||||
<table class="table has-actions is-hoverable is-fullwidth mb-0">
|
<table class="table has-actions is-hoverable is-fullwidth mb-0">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th v-if="activeColumns.index">
|
<th v-if="activeColumns.index">
|
||||||
#
|
#
|
||||||
<Sort
|
<Sort
|
||||||
:order="sortBy.index"
|
:order="sortBy.index"
|
||||||
@click="sort('index')"
|
@click="sort('index')"
|
||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
<th v-if="activeColumns.done">
|
<th v-if="activeColumns.done">
|
||||||
{{ $t('task.attributes.done') }}
|
{{ $t('task.attributes.done') }}
|
||||||
<Sort
|
<Sort
|
||||||
:order="sortBy.done"
|
:order="sortBy.done"
|
||||||
@click="sort('done')"
|
@click="sort('done')"
|
||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
<th v-if="activeColumns.title">
|
<th v-if="activeColumns.title">
|
||||||
{{ $t('task.attributes.title') }}
|
{{ $t('task.attributes.title') }}
|
||||||
<Sort
|
<Sort
|
||||||
:order="sortBy.title"
|
:order="sortBy.title"
|
||||||
@click="sort('title')"
|
@click="sort('title')"
|
||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
<th v-if="activeColumns.priority">
|
<th v-if="activeColumns.priority">
|
||||||
{{ $t('task.attributes.priority') }}
|
{{ $t('task.attributes.priority') }}
|
||||||
<Sort
|
<Sort
|
||||||
:order="sortBy.priority"
|
:order="sortBy.priority"
|
||||||
@click="sort('priority')"
|
@click="sort('priority')"
|
||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
<th v-if="activeColumns.labels">
|
<th v-if="activeColumns.labels">
|
||||||
{{ $t('task.attributes.labels') }}
|
{{ $t('task.attributes.labels') }}
|
||||||
</th>
|
</th>
|
||||||
<th v-if="activeColumns.assignees">
|
<th v-if="activeColumns.assignees">
|
||||||
{{ $t('task.attributes.assignees') }}
|
{{ $t('task.attributes.assignees') }}
|
||||||
</th>
|
</th>
|
||||||
<th v-if="activeColumns.dueDate">
|
<th v-if="activeColumns.dueDate">
|
||||||
{{ $t('task.attributes.dueDate') }}
|
{{ $t('task.attributes.dueDate') }}
|
||||||
<Sort
|
<Sort
|
||||||
:order="sortBy.due_date"
|
:order="sortBy.due_date"
|
||||||
@click="sort('due_date')"
|
@click="sort('due_date')"
|
||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
<th v-if="activeColumns.startDate">
|
<th v-if="activeColumns.startDate">
|
||||||
{{ $t('task.attributes.startDate') }}
|
{{ $t('task.attributes.startDate') }}
|
||||||
<Sort
|
<Sort
|
||||||
:order="sortBy.start_date"
|
:order="sortBy.start_date"
|
||||||
@click="sort('start_date')"
|
@click="sort('start_date')"
|
||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
<th v-if="activeColumns.endDate">
|
<th v-if="activeColumns.endDate">
|
||||||
{{ $t('task.attributes.endDate') }}
|
{{ $t('task.attributes.endDate') }}
|
||||||
<Sort
|
<Sort
|
||||||
:order="sortBy.end_date"
|
:order="sortBy.end_date"
|
||||||
@click="sort('end_date')"
|
@click="sort('end_date')"
|
||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
<th v-if="activeColumns.percentDone">
|
<th v-if="activeColumns.percentDone">
|
||||||
{{ $t('task.attributes.percentDone') }}
|
{{ $t('task.attributes.percentDone') }}
|
||||||
<Sort
|
<Sort
|
||||||
:order="sortBy.percent_done"
|
:order="sortBy.percent_done"
|
||||||
@click="sort('percent_done')"
|
@click="sort('percent_done')"
|
||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
<th v-if="activeColumns.doneAt">
|
<th v-if="activeColumns.doneAt">
|
||||||
{{ $t('task.attributes.doneAt') }}
|
{{ $t('task.attributes.doneAt') }}
|
||||||
<Sort
|
<Sort
|
||||||
:order="sortBy.done_at"
|
:order="sortBy.done_at"
|
||||||
@click="sort('done_at')"
|
@click="sort('done_at')"
|
||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
<th v-if="activeColumns.created">
|
<th v-if="activeColumns.created">
|
||||||
{{ $t('task.attributes.created') }}
|
{{ $t('task.attributes.created') }}
|
||||||
<Sort
|
<Sort
|
||||||
:order="sortBy.created"
|
:order="sortBy.created"
|
||||||
@click="sort('created')"
|
@click="sort('created')"
|
||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
<th v-if="activeColumns.updated">
|
<th v-if="activeColumns.updated">
|
||||||
{{ $t('task.attributes.updated') }}
|
{{ $t('task.attributes.updated') }}
|
||||||
<Sort
|
<Sort
|
||||||
:order="sortBy.updated"
|
:order="sortBy.updated"
|
||||||
@click="sort('updated')"
|
@click="sort('updated')"
|
||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
<th v-if="activeColumns.createdBy">
|
<th v-if="activeColumns.createdBy">
|
||||||
{{ $t('task.attributes.createdBy') }}
|
{{ $t('task.attributes.createdBy') }}
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr
|
<tr
|
||||||
v-for="t in tasks"
|
v-for="t in tasks"
|
||||||
:key="t.id"
|
:key="t.id"
|
||||||
>
|
>
|
||||||
<td v-if="activeColumns.index">
|
<td v-if="activeColumns.index">
|
||||||
<router-link :to="taskDetailRoutes[t.id]">
|
<router-link :to="taskDetailRoutes[t.id]">
|
||||||
<template v-if="t.identifier === ''">
|
<template v-if="t.identifier === ''">
|
||||||
#{{ t.index }}
|
#{{ t.index }}
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
{{ t.identifier }}
|
{{ t.identifier }}
|
||||||
</template>
|
</template>
|
||||||
</router-link>
|
</router-link>
|
||||||
</td>
|
</td>
|
||||||
<td v-if="activeColumns.done">
|
<td v-if="activeColumns.done">
|
||||||
<Done
|
<Done
|
||||||
:is-done="t.done"
|
:is-done="t.done"
|
||||||
variant="small"
|
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
|
</td>
|
||||||
v-if="activeColumns.startDate"
|
<td v-if="activeColumns.title">
|
||||||
:date="t.startDate"
|
<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"
|
||||||
/>
|
/>
|
||||||
<DateTableCell
|
</td>
|
||||||
v-if="activeColumns.endDate"
|
<td v-if="activeColumns.labels">
|
||||||
:date="t.endDate"
|
<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 v-if="activeColumns.percentDone">
|
</td>
|
||||||
{{ t.percentDone * 100 }}%
|
<DateTableCell
|
||||||
</td>
|
v-if="activeColumns.dueDate"
|
||||||
<DateTableCell
|
:date="t.dueDate"
|
||||||
v-if="activeColumns.doneAt"
|
/>
|
||||||
:date="t.doneAt"
|
<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"
|
||||||
/>
|
/>
|
||||||
<DateTableCell
|
</td>
|
||||||
v-if="activeColumns.created"
|
</tr>
|
||||||
: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>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@ -284,9 +284,8 @@ import FilterPopup from '@/components/project/partials/filter-popup.vue'
|
|||||||
import Pagination from '@/components/misc/pagination.vue'
|
import Pagination from '@/components/misc/pagination.vue'
|
||||||
import Popup from '@/components/misc/popup.vue'
|
import Popup from '@/components/misc/popup.vue'
|
||||||
|
|
||||||
import {useTaskList} from '@/composables/useTaskList'
|
|
||||||
|
|
||||||
import type {SortBy} from '@/composables/useTaskList'
|
import type {SortBy} from '@/composables/useTaskList'
|
||||||
|
import {useTaskList} from '@/composables/useTaskList'
|
||||||
import type {ITask} from '@/modelTypes/ITask'
|
import type {ITask} from '@/modelTypes/ITask'
|
||||||
import type {IProject} from '@/modelTypes/IProject'
|
import type {IProject} from '@/modelTypes/IProject'
|
||||||
import AssigneeList from '@/components/tasks/partials/assigneeList.vue'
|
import AssigneeList from '@/components/tasks/partials/assigneeList.vue'
|
||||||
@ -381,6 +380,11 @@ const taskDetailRoutes = computed(() => Object.fromEntries(
|
|||||||
.columns-filter {
|
.columns-filter {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
||||||
|
:deep(.card-content .content) {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
&.is-open {
|
&.is-open {
|
||||||
margin: 2rem 0 1rem;
|
margin: 2rem 0 1rem;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user