Kanban (#118)
Add error message when trying to create an invalid new task in a bucket Prevent creation of new buckets if the bucket title is empty Disable deleting a bucket if it's the last one Disable dragging tasks when they are being updated Fix transition when opening tasks Send the user to list view by default Show loading spinner when updating multiple tasks Add loading spinner when moving tasks Add loading animation when bucket is loading / updating etc Add bucket title edit Fix creating new buckets Add loading animation Add removing buckets Fix creating a new bucket after tasks were moved Fix warning about labels on tasks Fix labels on tasks not updating after retrieval from api Fix property width Add closing and mobile design Make the task detail popup look good Move list views Move task detail view in a popup Add link to tasks Add saving the new task position after it was moved Fix creating new bucket Fix creating a new task Cleanup Disable user selection for task cards Fix drag placeholder Add dragging style to task Add placeholder + change animation duration More cleanup Cleanup / docs Working of dragging and dropping tasks Adjust markup and styling for new library Change kanban library to something that works Add basic calculation of new positions Don't try to create empty tasks Add indicator if a task is done Add moving tasks between buckets Make empty buckets a little smaller Add gimmick for button description Fix color Fix scrolling bucket layout Add creating a new bucket Add hiding the task input field Co-authored-by: kolaente <k@knt.li> Reviewed-on: https://kolaente.dev/vikunja/frontend/pulls/118
This commit is contained in:
@ -1,94 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="gantt-options">
|
||||
<fancycheckbox v-model="showTaskswithoutDates" class="is-block">
|
||||
Show tasks which don't have dates set
|
||||
</fancycheckbox>
|
||||
<div class="range-picker">
|
||||
<div class="field">
|
||||
<label class="label" for="dayWidth">Size</label>
|
||||
<div class="control">
|
||||
<div class="select">
|
||||
<select id="dayWidth" v-model.number="dayWidth">
|
||||
<option value="35">Default</option>
|
||||
<option value="10">Month</option>
|
||||
<option value="80">Day</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label" for="fromDate">From</label>
|
||||
<div class="control">
|
||||
<flat-pickr
|
||||
class="input"
|
||||
v-model="dateFrom"
|
||||
:config="flatPickerConfig"
|
||||
id="fromDate"
|
||||
placeholder="From"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label" for="toDate">To</label>
|
||||
<div class="control">
|
||||
<flat-pickr
|
||||
class="input"
|
||||
v-model="dateTo"
|
||||
:config="flatPickerConfig"
|
||||
id="toDate"
|
||||
placeholder="To"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<gantt-chart
|
||||
:list="list"
|
||||
:show-taskswithout-dates="showTaskswithoutDates"
|
||||
:date-from="dateFrom"
|
||||
:date-to="dateTo"
|
||||
:day-width="dayWidth"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import GanttChart from './gantt-component'
|
||||
import flatPickr from 'vue-flatpickr-component'
|
||||
import ListModel from '../../models/list'
|
||||
import Fancycheckbox from '../global/fancycheckbox'
|
||||
|
||||
export default {
|
||||
name: 'Gantt',
|
||||
components: {
|
||||
Fancycheckbox,
|
||||
flatPickr,
|
||||
GanttChart
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showTaskswithoutDates: false,
|
||||
dayWidth: 35,
|
||||
dateFrom: null,
|
||||
dateTo: null,
|
||||
flatPickerConfig:{
|
||||
altFormat: 'j M Y',
|
||||
altInput: true,
|
||||
dateFormat: 'Y-m-d',
|
||||
enableTime: false,
|
||||
},
|
||||
}
|
||||
},
|
||||
beforeMount() {
|
||||
this.dateFrom = new Date((new Date()).setDate((new Date()).getDate() - 15))
|
||||
this.dateTo = new Date((new Date()).setDate((new Date()).getDate() + 30))
|
||||
},
|
||||
props: {
|
||||
list: {
|
||||
type: ListModel,
|
||||
required: true,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
@ -1,198 +0,0 @@
|
||||
<template>
|
||||
<div class="loader-container" :class="{ 'is-loading': taskCollectionService.loading}">
|
||||
<div class="search">
|
||||
<div class="field has-addons" :class="{ 'hidden': !showTaskSearch }">
|
||||
<div class="control has-icons-left has-icons-right">
|
||||
<input
|
||||
class="input"
|
||||
type="text"
|
||||
placeholder="Search"
|
||||
v-focus
|
||||
v-model="searchTerm"
|
||||
@keyup.enter="searchTasks"
|
||||
@blur="hideSearchBar()"/>
|
||||
<span class="icon is-left">
|
||||
<icon icon="search"/>
|
||||
</span>
|
||||
</div>
|
||||
<div class="control">
|
||||
<button
|
||||
class="button noshadow is-primary"
|
||||
@click="searchTasks"
|
||||
:class="{'is-loading': taskCollectionService.loading}"
|
||||
:disabled="searchTerm === ''">
|
||||
Search
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<button class="button" @click="showTaskSearch = !showTaskSearch" v-if="!showTaskSearch">
|
||||
<span class="icon">
|
||||
<icon icon="search"/>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="field task-add" v-if="!list.isArchived">
|
||||
<div class="field is-grouped">
|
||||
<p class="control has-icons-left is-expanded" :class="{ 'is-loading': taskService.loading}">
|
||||
<input v-focus class="input" :class="{ 'disabled': taskService.loading}" v-model="newTaskText" type="text" placeholder="Add a new task..." @keyup.enter="addTask()"/>
|
||||
<span class="icon is-small is-left">
|
||||
<icon icon="tasks"/>
|
||||
</span>
|
||||
</p>
|
||||
<p class="control">
|
||||
<button class="button is-success" :disabled="newTaskText.length < 3" @click="addTask()">
|
||||
<span class="icon is-small">
|
||||
<icon icon="plus"/>
|
||||
</span>
|
||||
Add
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
<p class="help is-danger" v-if="showError && newTaskText.length < 3">
|
||||
Please specify at least three characters.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<div class="tasks" v-if="tasks && tasks.length > 0" :class="{'short': isTaskEdit}">
|
||||
<div class="task" v-for="t in tasks" :key="t.id">
|
||||
<single-task-in-list :the-task="t" @taskUpdated="updateTasks"/>
|
||||
<div @click="editTask(t.id)" class="icon settings" v-if="!list.isArchived">
|
||||
<icon icon="pencil-alt"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column is-4" v-if="isTaskEdit">
|
||||
<div class="card taskedit">
|
||||
<header class="card-header">
|
||||
<p class="card-header-title">
|
||||
Edit Task
|
||||
</p>
|
||||
<a class="card-header-icon" @click="isTaskEdit = false">
|
||||
<span class="icon">
|
||||
<icon icon="angle-right"/>
|
||||
</span>
|
||||
</a>
|
||||
</header>
|
||||
<div class="card-content">
|
||||
<div class="content">
|
||||
<edit-task :task="taskEditTask"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="pagination is-centered" role="navigation" aria-label="pagination" v-if="taskCollectionService.totalPages > 1">
|
||||
<router-link class="pagination-previous" :to="getRouteForPagination(currentPage - 1)" tag="button" :disabled="currentPage === 1">Previous</router-link>
|
||||
<router-link class="pagination-next" :to="getRouteForPagination(currentPage + 1)" tag="button" :disabled="currentPage === taskCollectionService.totalPages">Next page</router-link>
|
||||
<ul class="pagination-list">
|
||||
<template v-for="(p, i) in pages">
|
||||
<li :key="'page'+i" v-if="p.isEllipsis"><span class="pagination-ellipsis">…</span></li>
|
||||
<li :key="'page'+i" v-else>
|
||||
<router-link :to="getRouteForPagination(p.number)" :class="{'is-current': p.number === currentPage}" class="pagination-link" :aria-label="'Goto page ' + p.number">{{ p.number }}</router-link>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TaskService from '../../services/task'
|
||||
import ListModel from '../../models/list'
|
||||
import EditTask from './edit-task'
|
||||
import TaskModel from '../../models/task'
|
||||
import SingleTaskInList from './reusable/singleTaskInList'
|
||||
import taskList from './helpers/taskList'
|
||||
|
||||
export default {
|
||||
name: 'ListView',
|
||||
data() {
|
||||
return {
|
||||
listId: this.$route.params.id,
|
||||
taskService: TaskService,
|
||||
list: {},
|
||||
isTaskEdit: false,
|
||||
taskEditTask: TaskModel,
|
||||
newTaskText: '',
|
||||
|
||||
showError: false,
|
||||
}
|
||||
},
|
||||
mixins: [
|
||||
taskList,
|
||||
],
|
||||
components: {
|
||||
SingleTaskInList,
|
||||
EditTask,
|
||||
},
|
||||
props: {
|
||||
theList: {
|
||||
type: ListModel,
|
||||
required: true,
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
theList() {
|
||||
this.list = this.theList
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.taskService = new TaskService()
|
||||
},
|
||||
methods: {
|
||||
// This function initializes the tasks page and loads the first page of tasks
|
||||
initTasks(page, search = '') {
|
||||
this.taskEditTask = null
|
||||
this.isTaskEdit = false
|
||||
this.loadTasks(page, search)
|
||||
},
|
||||
addTask() {
|
||||
if (this.newTaskText.length < 3) {
|
||||
this.showError = true
|
||||
return
|
||||
}
|
||||
this.showError = false
|
||||
|
||||
let task = new TaskModel({text: this.newTaskText, listId: this.$route.params.id})
|
||||
this.taskService.create(task)
|
||||
.then(r => {
|
||||
this.tasks.push(r)
|
||||
this.sortTasks()
|
||||
this.newTaskText = ''
|
||||
this.success({message: 'The task was successfully created.'}, this)
|
||||
})
|
||||
.catch(e => {
|
||||
this.error(e, this)
|
||||
})
|
||||
},
|
||||
editTask(id) {
|
||||
// Find the selected task and set it to the current object
|
||||
let theTask = this.getTaskById(id) // Somehow this does not work if we directly assign this to this.taskEditTask
|
||||
this.taskEditTask = theTask
|
||||
this.isTaskEdit = true
|
||||
},
|
||||
getTaskById(id) {
|
||||
for (const t in this.tasks) {
|
||||
if (this.tasks[t].id === parseInt(id)) {
|
||||
return this.tasks[t]
|
||||
}
|
||||
}
|
||||
return {} // FIXME: This should probably throw something to make it clear to the user noting was found
|
||||
},
|
||||
updateTasks(updatedTask) {
|
||||
for (const t in this.tasks) {
|
||||
if (this.tasks[t].id === updatedTask.id) {
|
||||
this.$set(this.tasks, t, updatedTask)
|
||||
break
|
||||
}
|
||||
}
|
||||
this.sortTasks()
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,234 +0,0 @@
|
||||
<template>
|
||||
<div class="table-view loader-container" :class="{'is-loading': taskCollectionService.loading}">
|
||||
<div class="column-filter">
|
||||
<button class="button" @click="showActiveColumnsFilter = !showActiveColumnsFilter">
|
||||
<span class="icon is-small">
|
||||
<icon icon="th"/>
|
||||
</span>
|
||||
Columns
|
||||
</button>
|
||||
<transition name="fade">
|
||||
<div class="card" v-if="showActiveColumnsFilter">
|
||||
<div class="card-content">
|
||||
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.id">#</fancycheckbox>
|
||||
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.done">Done</fancycheckbox>
|
||||
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.text">Name</fancycheckbox>
|
||||
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.priority">Priority</fancycheckbox>
|
||||
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.labels">Labels</fancycheckbox>
|
||||
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.assignees">Assignees</fancycheckbox>
|
||||
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.dueDate">Due Date</fancycheckbox>
|
||||
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.startDate">Start Date</fancycheckbox>
|
||||
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.endDate">End Date</fancycheckbox>
|
||||
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.percentDone">% Done</fancycheckbox>
|
||||
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.created">Created</fancycheckbox>
|
||||
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.updated">Updated</fancycheckbox>
|
||||
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.createdBy">Created By</fancycheckbox>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
|
||||
<table class="table is-hoverable is-fullwidth">
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-if="activeColumns.id">
|
||||
#
|
||||
<sort :order="sortBy.id" @click="sort('id')"/>
|
||||
</th>
|
||||
<th v-if="activeColumns.done">
|
||||
Done
|
||||
<sort :order="sortBy.done" @click="sort('done')"/>
|
||||
</th>
|
||||
<th v-if="activeColumns.text">
|
||||
Name
|
||||
<sort :order="sortBy.text" @click="sort('text')"/>
|
||||
</th>
|
||||
<th v-if="activeColumns.priority">
|
||||
Priority
|
||||
<sort :order="sortBy.priority" @click="sort('priority')"/>
|
||||
</th>
|
||||
<th v-if="activeColumns.labels">
|
||||
Labels
|
||||
</th>
|
||||
<th v-if="activeColumns.assignees">
|
||||
Assignees
|
||||
</th>
|
||||
<th v-if="activeColumns.dueDate">
|
||||
Due Date
|
||||
<sort :order="sortBy.due_date_unix" @click="sort('due_date_unix')"/>
|
||||
</th>
|
||||
<th v-if="activeColumns.startDate">
|
||||
Start Date
|
||||
<sort :order="sortBy.start_date_unix" @click="sort('start_date_unix')"/>
|
||||
</th>
|
||||
<th v-if="activeColumns.endDate">
|
||||
End Date
|
||||
<sort :order="sortBy.end_date_unix" @click="sort('end_date_unix')"/>
|
||||
</th>
|
||||
<th v-if="activeColumns.percentDone">
|
||||
% Done
|
||||
<sort :order="sortBy.percent_done" @click="sort('percent_done')"/>
|
||||
</th>
|
||||
<th v-if="activeColumns.created">
|
||||
Created
|
||||
<sort :order="sortBy.created" @click="sort('created')"/>
|
||||
</th>
|
||||
<th v-if="activeColumns.updated">
|
||||
Updated
|
||||
<sort :order="sortBy.updated" @click="sort('updated')"/>
|
||||
</th>
|
||||
<th v-if="activeColumns.createdBy">
|
||||
Created By
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="t in tasks" :key="t.id">
|
||||
<td v-if="activeColumns.id">
|
||||
<router-link :to="{name: 'taskDetailView', params: { id: t.id }}">{{ t.id }}</router-link>
|
||||
</td>
|
||||
<td v-if="activeColumns.done">
|
||||
<div class="is-done" v-if="t.done">Done</div>
|
||||
</td>
|
||||
<td v-if="activeColumns.text">
|
||||
<router-link :to="{name: 'taskDetailView', params: { id: t.id }}">{{ t.text }}</router-link>
|
||||
</td>
|
||||
<td v-if="activeColumns.priority">
|
||||
<priority-label :priority="t.priority" :show-all="true"/>
|
||||
</td>
|
||||
<td v-if="activeColumns.labels">
|
||||
<labels :labels="t.labels"/>
|
||||
</td>
|
||||
<td v-if="activeColumns.assignees">
|
||||
<user
|
||||
:user="a"
|
||||
:avatar-size="27"
|
||||
:show-username="false"
|
||||
:is-inline="true"
|
||||
v-for="(a, i) in t.assignees"
|
||||
:key="t.id + 'assignee' + a.id + i"
|
||||
/>
|
||||
</td>
|
||||
<date-table-cell :date="t.dueDate" v-if="activeColumns.dueDate"/>
|
||||
<date-table-cell :date="t.startDate" v-if="activeColumns.startDate"/>
|
||||
<date-table-cell :date="t.endDate" v-if="activeColumns.endDate"/>
|
||||
<td v-if="activeColumns.percentDone">{{ t.percentDone }}%</td>
|
||||
<date-table-cell :date="t.created" v-if="activeColumns.created"/>
|
||||
<date-table-cell :date="t.updated" v-if="activeColumns.updated"/>
|
||||
<td v-if="activeColumns.createdBy">
|
||||
<user
|
||||
:user="t.createdBy"
|
||||
:show-username="false"
|
||||
:avatar-size="27"/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<nav class="pagination is-centered" role="navigation" aria-label="pagination" v-if="taskCollectionService.totalPages > 1">
|
||||
<router-link class="pagination-previous" :to="getRouteForPagination(currentPage - 1, 'table')" tag="button" :disabled="currentPage === 1">Previous</router-link>
|
||||
<router-link class="pagination-next" :to="getRouteForPagination(currentPage + 1, 'table')" tag="button" :disabled="currentPage === taskCollectionService.totalPages">Next page</router-link>
|
||||
<ul class="pagination-list">
|
||||
<template v-for="(p, i) in pages">
|
||||
<li :key="'page'+i" v-if="p.isEllipsis"><span class="pagination-ellipsis">…</span></li>
|
||||
<li :key="'page'+i" v-else>
|
||||
<router-link :to="getRouteForPagination(p.number, 'table')" :class="{'is-current': p.number === currentPage}" class="pagination-link" :aria-label="'Goto page ' + p.number">{{ p.number }}</router-link>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ListModel from '../../models/list'
|
||||
import taskList from './helpers/taskList'
|
||||
import User from '../global/user'
|
||||
import PriorityLabel from './reusable/priorityLabel'
|
||||
import Labels from './reusable/labels'
|
||||
import DateTableCell from './reusable/date-table-cell'
|
||||
import Fancycheckbox from '../global/fancycheckbox'
|
||||
import Sort from './reusable/sort'
|
||||
|
||||
export default {
|
||||
name: 'TableView',
|
||||
components: {
|
||||
Sort,
|
||||
Fancycheckbox,
|
||||
DateTableCell,
|
||||
Labels,
|
||||
PriorityLabel,
|
||||
User,
|
||||
},
|
||||
mixins: [
|
||||
taskList,
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
showActiveColumnsFilter: false,
|
||||
activeColumns: {
|
||||
id: true,
|
||||
done: true,
|
||||
text: true,
|
||||
priority: false,
|
||||
labels: true,
|
||||
assignees: true,
|
||||
dueDate: true,
|
||||
startDate: false,
|
||||
endDate: false,
|
||||
percentDone: false,
|
||||
created: false,
|
||||
updated: false,
|
||||
createdBy: false,
|
||||
},
|
||||
sortBy: {
|
||||
id: 'desc',
|
||||
},
|
||||
}
|
||||
},
|
||||
props: {
|
||||
list: {
|
||||
type: ListModel,
|
||||
required: true,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
const savedShowColumns = localStorage.getItem('tableViewColumns')
|
||||
if (savedShowColumns !== null) {
|
||||
this.$set(this, 'activeColumns', JSON.parse(savedShowColumns))
|
||||
}
|
||||
const savedSortBy = localStorage.getItem('tableViewSortBy')
|
||||
if (savedSortBy !== null) {
|
||||
this.$set(this, 'sortBy', JSON.parse(savedSortBy))
|
||||
}
|
||||
|
||||
this.initTasks(1)
|
||||
},
|
||||
methods: {
|
||||
initTasks(page, search = '') {
|
||||
let params = {sort_by: [], order_by: []}
|
||||
Object.keys(this.sortBy).map(s => {
|
||||
params.sort_by.push(s)
|
||||
params.order_by.push(this.sortBy[s])
|
||||
})
|
||||
this.loadTasks(page, search, params)
|
||||
},
|
||||
sort(property) {
|
||||
const order = this.sortBy[property]
|
||||
if (typeof order === 'undefined' || order === 'none') {
|
||||
this.$set(this.sortBy, property, 'desc')
|
||||
} else if (order === 'desc') {
|
||||
this.$set(this.sortBy, property, 'asc')
|
||||
} else {
|
||||
this.$delete(this.sortBy, property)
|
||||
}
|
||||
this.initTasks(this.currentPage, this.searchTerm)
|
||||
// Save the order to be able to retrieve them later
|
||||
localStorage.setItem('tableViewSortBy', JSON.stringify(this.sortBy))
|
||||
},
|
||||
saveTaskColumns() {
|
||||
localStorage.setItem('tableViewColumns', JSON.stringify(this.activeColumns))
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
@ -8,12 +8,14 @@
|
||||
<div class="is-done" v-if="task.done">Done</div>
|
||||
<h1 class="title input" contenteditable="true" @focusout="saveTaskOnChange()" ref="taskTitle" @keyup.ctrl.enter="saveTaskOnChange()">{{ task.text }}</h1>
|
||||
</div>
|
||||
<h6 class="subtitle">
|
||||
{{ namespace.name }} >
|
||||
<router-link :to="{ name: 'showList', params: { id: list.id } }">
|
||||
{{ list.title }}
|
||||
</router-link>
|
||||
</h6>
|
||||
<!-- FIXME: Throw this away once we have vuex -->
|
||||
<!-- Commented out because it is a) not working and b) not working -->
|
||||
<!-- <h6 class="subtitle">-->
|
||||
<!-- {{ namespace.name }} >-->
|
||||
<!-- <router-link :to="{ name: 'showList', params: { id: list.id } }">-->
|
||||
<!-- {{ list.title }}-->
|
||||
<!-- </router-link>-->
|
||||
<!-- </h6>-->
|
||||
|
||||
<!-- Content and buttons -->
|
||||
<div class="columns">
|
||||
@ -218,7 +220,7 @@
|
||||
<!-- Comments -->
|
||||
<comments :task-id="taskId"/>
|
||||
</div>
|
||||
<div class="column is-one-fifth action-buttons">
|
||||
<div class="column is-one-third action-buttons">
|
||||
<a class="button is-outlined noshadow has-no-border" :class="{'is-success': !task.done}" @click="toggleTaskDone()">
|
||||
<span class="icon is-small"><icon icon="check-double"/></span>
|
||||
<template v-if="task.done">
|
||||
@ -464,15 +466,15 @@
|
||||
},
|
||||
setListAndNamespaceTitleFromParent() {
|
||||
// FIXME: Throw this away once we have vuex
|
||||
this.$parent.namespaces.forEach(n => {
|
||||
n.lists.forEach(l => {
|
||||
if (l.id === this.task.listId) {
|
||||
this.list = l
|
||||
this.namespace = n
|
||||
return
|
||||
}
|
||||
})
|
||||
})
|
||||
// this.$parent.namespaces.forEach(n => {
|
||||
// n.lists.forEach(l => {
|
||||
// if (l.id === this.task.listId) {
|
||||
// this.list = l
|
||||
// this.namespace = n
|
||||
// return
|
||||
// }
|
||||
// })
|
||||
// })
|
||||
},
|
||||
setFieldActive(fieldName) {
|
||||
this.activeFields[fieldName] = true
|
||||
@ -482,7 +484,7 @@
|
||||
this.taskService.delete(this.task)
|
||||
.then(() => {
|
||||
this.success({message: 'The task been deleted successfully.'}, this)
|
||||
router.push({name: 'showList', params: {id: this.list.id}})
|
||||
router.push({name: 'showList', params: {listId: this.list.id}})
|
||||
})
|
||||
.catch(e => {
|
||||
this.error(e, this)
|
||||
|
39
src/components/tasks/TaskDetailViewModal.vue
Normal file
39
src/components/tasks/TaskDetailViewModal.vue
Normal file
@ -0,0 +1,39 @@
|
||||
<template>
|
||||
<div class="modal-mask">
|
||||
<div class="modal-container" @click.self="close()">
|
||||
<div class="scrolling-content">
|
||||
<a @click="close()" class="close">
|
||||
<icon icon="times"/>
|
||||
</a>
|
||||
<task-detail-view :parent-list="list" :parent-namespace="namespace"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TaskDetailView from './TaskDetailView'
|
||||
import router from '../../router'
|
||||
|
||||
export default {
|
||||
name: 'TaskDetailViewModal',
|
||||
data() {
|
||||
return {
|
||||
list: null,
|
||||
namespace: null,
|
||||
}
|
||||
},
|
||||
components: {
|
||||
TaskDetailView,
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
router.back()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -108,7 +108,7 @@
|
||||
<p class="card-header-title">
|
||||
Edit Task
|
||||
</p>
|
||||
<a class="card-header-icon" @click="isTaskEdit = false;taskToEdit = null">
|
||||
<a class="card-header-icon" @click="() => {isTaskEdit = false; taskToEdit = null}">
|
||||
<span class="icon">
|
||||
<icon icon="times"/>
|
||||
</span>
|
||||
@ -130,7 +130,6 @@
|
||||
|
||||
import TaskService from '../../services/task'
|
||||
import TaskModel from '../../models/task'
|
||||
import ListModel from '../../models/list'
|
||||
import priorities from '../../models/priorities'
|
||||
import PriorityLabel from './reusable/priorityLabel'
|
||||
import TaskCollectionService from '../../services/taskCollection'
|
||||
@ -143,8 +142,8 @@
|
||||
VueDragResize,
|
||||
},
|
||||
props: {
|
||||
list: {
|
||||
type: ListModel,
|
||||
listId: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
showTaskswithoutDates: {
|
||||
@ -235,7 +234,7 @@
|
||||
prepareTasks() {
|
||||
|
||||
const getAllTasks = (page = 1) => {
|
||||
return this.taskCollectionService.getAll({listId: this.$route.params.id}, {}, page)
|
||||
return this.taskCollectionService.getAll({listId: this.listId}, {}, page)
|
||||
.then(tasks => {
|
||||
if(page < this.taskCollectionService.totalPages) {
|
||||
return getAllTasks(page + 1)
|
||||
@ -367,7 +366,7 @@
|
||||
if (!this.newTaskFieldActive) {
|
||||
return
|
||||
}
|
||||
let task = new TaskModel({text: this.newTaskTitle, listId: this.list.id})
|
||||
let task = new TaskModel({text: this.newTaskTitle, listId: this.listId})
|
||||
this.taskService.create(task)
|
||||
.then(r => {
|
||||
this.tasksWithoutDates.push(this.addGantAttributes(r))
|
||||
|
@ -29,10 +29,20 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
loadTasks(page, search = '', params = {sort_by: ['done', 'id'], order_by: ['asc', 'desc']}) {
|
||||
|
||||
// Because this function is triggered every time on navigation, we're putting a condition here to only load it when we actually want to show tasks
|
||||
// FIXME: This is a bit hacky -> Cleanup.
|
||||
if (
|
||||
this.$route.name !== 'list.list' &&
|
||||
this.$route.name !== 'list.table'
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
if (search !== '') {
|
||||
params.s = search
|
||||
}
|
||||
this.taskCollectionService.getAll({listId: this.$route.params.id}, params, page)
|
||||
this.taskCollectionService.getAll({listId: this.$route.params.listId}, params, page)
|
||||
.then(r => {
|
||||
this.$set(this, 'tasks', r)
|
||||
this.$set(this, 'pages', [])
|
||||
@ -104,7 +114,7 @@ export default {
|
||||
return
|
||||
}
|
||||
this.$router.push({
|
||||
name: 'showList',
|
||||
name: 'list.list',
|
||||
query: {search: this.searchTerm}
|
||||
})
|
||||
},
|
||||
|
@ -11,7 +11,6 @@
|
||||
name: 'labels',
|
||||
props: {
|
||||
labels: {
|
||||
type: Array,
|
||||
required: true,
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,7 @@
|
||||
<span class="title">{{ relationKindTitle(kind, rts.length) }}</span>
|
||||
<div class="tasks noborder">
|
||||
<div class="task" v-for="t in rts" :key="t.id">
|
||||
<router-link :to="{ name: 'taskDetailView', params: { id: t.id } }">
|
||||
<router-link :to="{ name: 'task.kanban.detail', params: { id: t.id } }">
|
||||
<span class="tasktext" :class="{ 'done': t.done}">
|
||||
{{t.text}}
|
||||
</span>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<span>
|
||||
<fancycheckbox v-model="task.done" @change="markAsDone" :disabled="isArchived"/>
|
||||
<router-link :to="{ name: 'taskDetailView', params: { id: task.id } }" class="tasktext" :class="{ 'done': task.done}">
|
||||
<router-link :to="{ name: 'task.list.detail', params: { id: task.id } }" class="tasktext" :class="{ 'done': task.done}">
|
||||
<!-- Show any parent tasks to make it clear this task is a sub task of something -->
|
||||
<span class="parent-tasks" v-if="typeof task.relatedTasks.parenttask !== 'undefined'">
|
||||
<template v-for="(pt, i) in task.relatedTasks.parenttask">
|
||||
|
Reference in New Issue
Block a user