1
0

Add default list setting & creating tasks from home (#520)

Co-authored-by: sytone <github@sytone.com>
Co-authored-by: Sytone <github@sytone.com>
Co-authored-by: kolaente <k@knt.li>
Reviewed-on: https://kolaente.dev/vikunja/frontend/pulls/520
Reviewed-by: konrad <konrad@kola-entertainments.de>
Co-authored-by: sytone <kolaente@sytone.com>
Co-committed-by: sytone <kolaente@sytone.com>
This commit is contained in:
sytone
2021-07-17 21:21:46 +00:00
committed by konrad
parent bad5e3d0ec
commit 306a926c66
37 changed files with 342 additions and 163 deletions

View File

@ -3,10 +3,15 @@
<h2>
{{ $t(`home.welcome${welcome}`, {username: userInfo.name !== '' ? userInfo.name : userInfo.username}) }}!
</h2>
<add-task
:listId="defaultListId"
@taskAdded="updateTaskList"
class="is-max-width-desktop"
/>
<template v-if="!hasTasks">
<p>{{ $t('home.list.newText') }}</p>
<x-button
:to="{name: 'list.create', params: { id: defaultNamespaceId }}"
:to="{ name: 'list.create', params: { id: defaultNamespaceId } }"
:shadow="false"
class="ml-2"
v-if="defaultNamespaceId > 0"
@ -34,7 +39,7 @@
/>
</div>
</div>
<ShowTasks :show-all="true" v-if="hasLists"/>
<ShowTasks :show-all="true" v-if="hasLists" :key="showTasksKey"/>
</div>
</template>
@ -43,18 +48,21 @@ import {mapState} from 'vuex'
import ShowTasks from './tasks/ShowTasks'
import {getHistory} from '@/modules/listHistory'
import ListCard from '@/components/list/partials/list-card'
import AddTask from '../components/tasks/add-task'
export default {
name: 'Home',
components: {
ListCard,
ShowTasks,
AddTask,
},
data() {
return {
loading: false,
currentDate: new Date(),
tasks: [],
showTasksKey: 0,
}
},
computed: {
@ -86,10 +94,13 @@ export default {
})
},
...mapState({
migratorsEnabled: state => state.config.availableMigrators !== null && state.config.availableMigrators.length > 0,
migratorsEnabled: state =>
state.config.availableMigrators !== null &&
state.config.availableMigrators.length > 0,
authenticated: state => state.auth.authenticated,
userInfo: state => state.auth.info,
hasTasks: state => state.hasTasks,
defaultListId: state => state.auth.defaultListId,
defaultNamespaceId: state => {
if (state.namespaces.namespaces.length === 0) {
return 0
@ -105,6 +116,13 @@ export default {
return state.namespaces.namespaces[0].lists.length > 0
},
}),
}
},
methods: {
// This is to reload the tasks list after adding a new task through the global task add.
// FIXME: Should use vuex (somehow?)
updateTaskList() {
this.showTasksKey++
},
},
}
</script>

View File

@ -1,11 +1,15 @@
<template>
<div
:class="{ 'is-loading': taskCollectionService.loading}"
class="loader-container is-max-width-desktop list-view">
<div class="filter-container" v-if="list.isSavedFilter && !list.isSavedFilter()">
:class="{ 'is-loading': taskCollectionService.loading }"
class="loader-container is-max-width-desktop list-view"
>
<div
class="filter-container"
v-if="list.isSavedFilter && !list.isSavedFilter()"
>
<div class="items">
<div class="search">
<div :class="{ 'hidden': !showTaskSearch }" class="field has-addons">
<div :class="{ hidden: !showTaskSearch }" class="field has-addons">
<div class="control has-icons-left has-icons-right">
<input
@blur="hideSearchBar()"
@ -14,9 +18,10 @@
:placeholder="$t('misc.search')"
type="text"
v-focus
v-model="searchTerm"/>
v-model="searchTerm"
/>
<span class="icon is-left">
<icon icon="search"/>
<icon icon="search" />
</span>
</div>
<div class="control">
@ -52,48 +57,30 @@
</div>
<card :padding="false" :has-content="false" class="has-overflow">
<div class="field task-add" v-if="!list.isArchived && canWrite && list.id > 0">
<div class="field is-grouped">
<p :class="{ 'is-loading': taskService.loading}" class="control has-icons-left is-expanded">
<input
:class="{ 'disabled': taskService.loading}"
@keyup.enter="addTask()"
class="input"
:placeholder="$t('list.list.addPlaceholder')"
type="text"
v-focus
v-model="newTaskText"
ref="newTaskInput"
/>
<span class="icon is-small is-left">
<icon icon="tasks"/>
</span>
</p>
<p class="control">
<x-button
:disabled="newTaskText.length === 0"
@click="addTask()"
icon="plus"
>
{{ $t('list.list.add') }}
</x-button>
</p>
</div>
<p class="help is-danger" v-if="showError && newTaskText === ''">
{{ $t('list.list.addTitleRequired') }}
</p>
<quick-add-magic v-if="!showError"/>
</div>
<template
v-if="!list.isArchived && canWrite && list.id > 0"
>
<add-task
@taskAdded="updateTaskList"
ref="newTaskInput"
/>
</template>
<nothing v-if="ctaVisible && tasks.length === 0 && !taskCollectionService.loading">
{{ $t('list.list.empty') }}
<a @click="$refs.newTaskInput.focus()">
<a @click="focusNewTaskInput()">
{{ $t('list.list.newTaskCta') }}
</a>
</nothing>
<div class="tasks-container">
<div :class="{'short': isTaskEdit}" class="tasks mt-0" v-if="tasks && tasks.length > 0">
<div
:class="{ short: isTaskEdit }"
class="tasks mt-0"
v-if="tasks && tasks.length > 0"
>
<single-task-in-list
:show-list-color="false"
:disabled="!canWrite"
@ -103,8 +90,12 @@
task-detail-route="task.detail"
v-for="t in tasks"
>
<div @click="editTask(t.id)" class="icon settings" v-if="!list.isArchived && canWrite">
<icon icon="pencil-alt"/>
<div
@click="editTask(t.id)"
class="icon settings"
v-if="!list.isArchived && canWrite"
>
<icon icon="pencil-alt" />
</div>
</single-task-in-list>
</div>
@ -121,7 +112,8 @@
aria-label="pagination"
class="pagination is-centered p-4"
role="navigation"
v-if="taskCollectionService.totalPages > 1">
v-if="taskCollectionService.totalPages > 1"
>
<router-link
:disabled="currentPage === 1"
:to="getRouteForPagination(currentPage - 1)"
@ -138,13 +130,16 @@
</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">&hellip;</span></li>
<li :key="'page'+i" v-else>
<li :key="'page' + i" v-if="p.isEllipsis">
<span class="pagination-ellipsis">&hellip;</span>
</li>
<li :key="'page' + i" v-else>
<router-link
:aria-label="'Goto page ' + p.number"
:class="{'is-current': p.number === currentPage}"
:class="{ 'is-current': p.number === currentPage }"
:to="getRouteForPagination(p.number)"
class="pagination-link">
class="pagination-link"
>
{{ p.number }}
</router-link>
</li>
@ -155,10 +150,8 @@
<!-- This router view is used to show the task popup while keeping the kanban board itself -->
<transition name="modal">
<router-view/>
<router-view />
</transition>
</div>
</template>
@ -167,15 +160,16 @@ import TaskService from '../../../services/task'
import TaskModel from '../../../models/task'
import EditTask from '../../../components/tasks/edit-task'
import AddTask from '../../../components/tasks/add-task'
import SingleTaskInList from '../../../components/tasks/partials/singleTaskInList'
import taskList from '../../../components/tasks/mixins/taskList'
import {saveListView} from '@/helpers/saveListView'
import { saveListView } from '@/helpers/saveListView'
import Rights from '../../../models/rights.json'
import {mapState} from 'vuex'
import { mapState } from 'vuex'
import FilterPopup from '@/components/list/partials/filter-popup'
import { HAS_TASKS } from '@/store/mutation-types'
import Nothing from '@/components/misc/nothing'
import createTask from '@/components/tasks/mixins/createTask'
import QuickAddMagic from '@/components/tasks/partials/quick-add-magic'
export default {
name: 'List',
@ -184,8 +178,6 @@ export default {
taskService: TaskService,
isTaskEdit: false,
taskEditTask: TaskModel,
newTaskText: '',
showError: false,
ctaVisible: false,
}
},
@ -194,11 +186,11 @@ export default {
createTask,
],
components: {
QuickAddMagic,
Nothing,
FilterPopup,
SingleTaskInList,
EditTask,
AddTask,
},
created() {
this.taskService = new TaskService()
@ -212,7 +204,7 @@ export default {
list: state => state.currentList,
}),
mounted() {
this.$nextTick(() => this.ctaVisible = true)
this.$nextTick(() => (this.ctaVisible = true))
},
methods: {
// This function initializes the tasks page and loads the first page of tasks
@ -221,22 +213,13 @@ export default {
this.isTaskEdit = false
this.loadTasks(page, search)
},
addTask() {
if (this.newTaskText === '') {
this.showError = true
return
}
this.showError = false
this.createNewTask(this.newTaskText)
.then(task => {
this.tasks.push(task)
this.sortTasks()
this.newTaskText = ''
})
.catch(e => {
this.error(e)
})
focusNewTaskInput() {
this.$refs.newTaskInput.$refs.newTaskInput.focus()
},
updateTaskList(task) {
this.tasks.push(task)
this.sortTasks()
this.$store.commit(HAS_TASKS, true)
},
editTask(id) {
// Find the selected task and set it to the current object
@ -263,4 +246,4 @@ export default {
},
},
}
</script>
</script>

View File

@ -645,7 +645,7 @@ export default {
this.$refs[fieldName].$el.scrollIntoView({
behavior: 'smooth',
block: 'center',
inline: 'nearest'
inline: 'nearest',
})
}
})

View File

@ -312,7 +312,7 @@ export default {
this.success({
message: member.admin ?
this.$t('team.edit.madeAdmin') :
this.$t('team.edit.madeMember')
this.$t('team.edit.madeMember'),
})
})
.catch((e) => {

View File

@ -129,7 +129,7 @@ export default {
let emailVerifyToken = localStorage.getItem('emailConfirmToken')
if (emailVerifyToken) {
const cancel = this.setLoading()
HTTP.post(`user/confirm`, {token: emailVerifyToken})
HTTP.post('user/confirm', {token: emailVerifyToken})
.then(() => {
localStorage.removeItem('emailConfirmToken')
this.confirmedEmailSuccess = true

View File

@ -16,6 +16,12 @@
v-model="settings.name"/>
</div>
</div>
<div class="field">
<label class="label">
{{ $t('user.settings.general.defaultList') }}
</label>
<list-search v-model="defaultList"/>
</div>
<div class="field">
<label class="checkbox">
<input type="checkbox" v-model="settings.emailRemindersEnabled"/>
@ -282,6 +288,7 @@ import {mapState} from 'vuex'
import AvatarSettings from '../../components/user/avatar-settings'
import copy from 'copy-to-clipboard'
import ListSearch from '@/components/tasks/partials/listSearch'
export default {
name: 'Settings',
@ -306,9 +313,12 @@ export default {
settings: UserSettingsModel,
userSettingsService: UserSettingsService,
defaultList: null,
}
},
components: {
ListSearch,
AvatarSettings,
},
created() {
@ -326,6 +336,8 @@ export default {
this.playSoundWhenDone = localStorage.getItem(playSoundWhenDoneKey) === 'true' || localStorage.getItem(playSoundWhenDoneKey) === null
this.defaultList = this.$store.getters['lists/getListById'](this.settings.defaultListId)
this.totpStatus()
},
mounted() {
@ -351,7 +363,7 @@ export default {
migratorsEnabled: state => state.config.availableMigrators !== null && state.config.availableMigrators.length > 0,
caldavEnabled: state => state.config.caldavEnabled,
userInfo: state => state.auth.info,
})
}),
},
methods: {
updatePassword() {
@ -428,6 +440,7 @@ export default {
updateSettings() {
localStorage.setItem(playSoundWhenDoneKey, this.playSoundWhenDone)
saveLanguage(this.language)
this.settings.defaultListId = this.defaultList ? this.defaultList.id : 0
this.userSettingsService.update(this.settings)
.then(() => {