Migrate to vue3
Signed-off-by: Raimund Schlüßler <raimund.schluessler@mailbox.org>
This commit is contained in:
parent
b998341fc7
commit
931dfe2d2f
File diff suppressed because it is too large
Load Diff
25
package.json
25
package.json
|
@ -31,14 +31,14 @@
|
|||
"@nextcloud/axios": "^2.4.0",
|
||||
"@nextcloud/calendar-js": "6.1.0",
|
||||
"@nextcloud/cdav-library": "1.1.0",
|
||||
"@nextcloud/dialogs": "^5.1.1",
|
||||
"@nextcloud/dialogs": "4.1.0",
|
||||
"@nextcloud/event-bus": "^3.1.0",
|
||||
"@nextcloud/initial-state": "2.1.0",
|
||||
"@nextcloud/l10n": "^2.2.0",
|
||||
"@nextcloud/logger": "^2.7.0",
|
||||
"@nextcloud/moment": "^1.3.1",
|
||||
"@nextcloud/router": "^2.2.1",
|
||||
"@nextcloud/vue": "8.5.1",
|
||||
"@nextcloud/vue": "9.0.0-alpha.0",
|
||||
"@vueuse/components": "^10.7.2",
|
||||
"color-convert": "^2.0.1",
|
||||
"debounce": "^2.0.0",
|
||||
|
@ -51,25 +51,22 @@
|
|||
"markdown-it-task-lists": "^2.1.1",
|
||||
"md5": "^2.3.0",
|
||||
"p-limit": "^5.0.0",
|
||||
"sortablejs-vue3": "^1.2.11",
|
||||
"uuid": "^9.0.1",
|
||||
"vue": "^2.7.16",
|
||||
"vue-material-design-icons": "^5.2.0",
|
||||
"vue-router": "^3.6.5",
|
||||
"vuedraggable": "^2.24.3",
|
||||
"vuex": "^3.6.2",
|
||||
"vuex-router-sync": "^5.0.0"
|
||||
"vue": "^3.4.15",
|
||||
"vue-material-design-icons": "^5.3.0",
|
||||
"vue-router": "^4.2.5",
|
||||
"vuex": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nextcloud/babel-config": "^1.0.0",
|
||||
"@nextcloud/browserslist-config": "^3.0.0",
|
||||
"@nextcloud/eslint-config": "^8.3.0",
|
||||
"@nextcloud/eslint-config": "github:nextcloud-libraries/eslint-config#vue3",
|
||||
"@nextcloud/stylelint-config": "^2.4.0",
|
||||
"@nextcloud/vite-config": "^1.2.0",
|
||||
"@vue/test-utils": "^1.3.6",
|
||||
"babel-core": "^7.0.0-bridge.0",
|
||||
"happy-dom": "^13.3.1",
|
||||
"@nextcloud/vite-config": "github:nextcloud-libraries/nextcloud-vite-config#vue3",
|
||||
"@vue/test-utils": "^2.4.4",
|
||||
"happy-dom": "^13.3.8",
|
||||
"mockdate": "^3.0.5",
|
||||
"regenerator-runtime": "^0.14.1",
|
||||
"vitest": "^1.2.2"
|
||||
},
|
||||
"engines": {
|
||||
|
|
|
@ -21,9 +21,9 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
<template>
|
||||
<NcContent app-name="tasks">
|
||||
<AppNavigation @click.native="closeAppSidebar($event)" />
|
||||
<AppNavigation @click="closeAppSidebar($event)" />
|
||||
|
||||
<NcAppContent @click.native="closeAppSidebar($event)">
|
||||
<NcAppContent @click="closeAppSidebar($event)">
|
||||
<RouterView />
|
||||
</NcAppContent>
|
||||
|
||||
|
@ -49,6 +49,7 @@ export default {
|
|||
NcAppContent,
|
||||
NcContent,
|
||||
},
|
||||
inject: ['$OCA'],
|
||||
data() {
|
||||
return {
|
||||
searchString: '',
|
||||
|
|
|
@ -39,8 +39,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
<template #counter>
|
||||
<NcCheckboxRadioSwitch :disabled="loading"
|
||||
:checked="writeable"
|
||||
@update:checked="editSharee">
|
||||
:model-value="writeable"
|
||||
@update:model-value="editSharee">
|
||||
{{ t('tasks', 'Can edit') }}
|
||||
</NcCheckboxRadioSwitch>
|
||||
</template>
|
||||
|
|
|
@ -27,10 +27,10 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
:name="calendar.displayName"
|
||||
:class="{'list--edit': editing, 'list--deleted': !!deleteTimeout}"
|
||||
class="list reactive"
|
||||
@drop.native="dropTask"
|
||||
@dragover.native="dragOver"
|
||||
@dragenter.native="dragEnter"
|
||||
@dragleave.native="dragLeave">
|
||||
@drop="dropTask"
|
||||
@dragover="dragOver"
|
||||
@dragenter="dragEnter"
|
||||
@dragleave="dragLeave">
|
||||
<template #icon>
|
||||
<NcAppNavigationIconBullet :color="calendar.color" />
|
||||
</template>
|
||||
|
@ -111,6 +111,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
<ShareCalendar v-if="shareOpen && !calendar.readOnly && !deleteTimeout" :calendar="calendar" />
|
||||
<div v-if="!deleteTimeout" :class="{error: nameError}" class="app-navigation-entry-edit">
|
||||
<NcTextField ref="editListInput"
|
||||
v-model="newCalendarName"
|
||||
v-tooltip="{
|
||||
content: tooltipMessage,
|
||||
shown: showTooltip('list_' + calendar.id),
|
||||
|
@ -119,14 +120,13 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
type="text"
|
||||
:show-trailing-button="newCalendarName !== ''"
|
||||
trailing-button-icon="arrowRight"
|
||||
:value.sync="newCalendarName"
|
||||
:error="nameError"
|
||||
:label="t('tasks', 'List name')"
|
||||
@trailing-button-click="save(calendar)"
|
||||
@keyup="checkName($event, calendar)">
|
||||
<Pencil :size="16" />
|
||||
</NcTextField>
|
||||
<Colorpicker :selected-color="selectedColor" @color-selected="setColor(...arguments)" />
|
||||
<Colorpicker :selected-color="selectedColor" @color-selected="setColor" />
|
||||
</div>
|
||||
</li>
|
||||
</NcAppNavigationItem>
|
||||
|
|
|
@ -70,8 +70,8 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
<div class="table__header">
|
||||
|
||||
</div>
|
||||
<template v-for="item in items">
|
||||
<div :key="`${item.url}desc`" class="table__body">
|
||||
<template v-for="item in items" :key="`${item.url}body`">
|
||||
<div class="table__body">
|
||||
<div class="icon-bullet"
|
||||
:style="{ 'background-color': item.color }" />
|
||||
<div class="item-description">
|
||||
|
@ -83,10 +83,10 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div :key="`${item.url}date`" class="table__body table__body--deletedAt">
|
||||
<div class="table__body table__body--deletedAt">
|
||||
<NcDateTime class="timestamp" :timestamp="item.deletedAt" :ignore-seconds="true" />
|
||||
</div>
|
||||
<div :key="`${item.url}action`" class="table__body">
|
||||
<div class="table__body">
|
||||
<NcButton @click="restore(item)">
|
||||
<template #icon>
|
||||
<Undo :size="20" />
|
||||
|
|
|
@ -28,7 +28,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
:disabled="isDisabled"
|
||||
:clearable="false"
|
||||
:options="calendarsMap"
|
||||
:value="calendarMap"
|
||||
:model-value="calendarMap"
|
||||
:placeholder="t('tasks', 'Select a calendar')"
|
||||
:append-to-body="false"
|
||||
@option:selected="change">
|
||||
|
|
|
@ -27,7 +27,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
<NcSelect label="displayName"
|
||||
:disabled="isDisabled"
|
||||
:options="options"
|
||||
:value="value"
|
||||
:model-value="value"
|
||||
:placeholder="placeholder"
|
||||
:multiple="false"
|
||||
:searchable="false"
|
||||
|
|
|
@ -34,7 +34,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
<pre><span>{{ newValue }}</span><br><br></pre>
|
||||
<textarea ref="note__editor"
|
||||
v-model="newValue"
|
||||
@keyup.27="setEditing(false)"
|
||||
@keyup.escape="setEditing(false)"
|
||||
@keydown.enter.ctrl.prevent="setValue()"
|
||||
@change="setValue()" />
|
||||
</div>
|
||||
|
@ -101,7 +101,7 @@ export default {
|
|||
mounted() {
|
||||
subscribe('tasks:edit-appsidebar-notes', this.setNotes)
|
||||
},
|
||||
beforeDestroy() {
|
||||
beforeUnmount() {
|
||||
unsubscribe('tasks:edit-appsidebar-notes', this.setNotes)
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -39,7 +39,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
type="number"
|
||||
:min="minValue"
|
||||
:max="maxValue"
|
||||
@keyup.27="setEditing(false)"
|
||||
@keyup.escape="setEditing(false)"
|
||||
@keydown.enter.prevent="setValue()">
|
||||
<input v-model="newValue"
|
||||
type="range"
|
||||
|
|
|
@ -27,7 +27,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
<div class="multiselect__icon">
|
||||
<component :is="icon" :size="20" />
|
||||
</div>
|
||||
<NcSelect :value="tags"
|
||||
<NcSelect :model-value="tags"
|
||||
taggable
|
||||
:disabled="disabled"
|
||||
:options="options"
|
||||
|
@ -36,7 +36,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
:close-on-select="false"
|
||||
:append-to-body="false"
|
||||
:tag-placeholder="t('tasks', 'Add this as a new tag')"
|
||||
@input="setTags"
|
||||
@update:model-value="setTags"
|
||||
@tag="addTag">
|
||||
<template #no-options>
|
||||
{{ t('tasks', 'No tag available. Create one!') }}
|
||||
|
|
|
@ -36,7 +36,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
<input ref="input"
|
||||
v-model="newValue"
|
||||
type="string"
|
||||
@keyup.27="setEditing(false)"
|
||||
@keyup.escape="setEditing(false)"
|
||||
@keydown.enter.prevent="setValue()">
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -36,8 +36,8 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
:multiple="true"
|
||||
:append-to-body="true"
|
||||
:options="tags"
|
||||
:value="filter.tags"
|
||||
@input="setTags">
|
||||
:model-value="filter.tags"
|
||||
@update:model-value="setTags">
|
||||
<template #icon>
|
||||
<TagMultiple :size="20" />
|
||||
</template>
|
||||
|
|
|
@ -24,7 +24,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
<div v-if="$route.params.collectionId !== 'completed' && calendar && !calendar.readOnly"
|
||||
class="header__input">
|
||||
<NcTextField ref="input"
|
||||
:value.sync="newTaskName"
|
||||
v-model="newTaskName"
|
||||
:label="placeholder"
|
||||
autocomplete="off"
|
||||
class="reactive"
|
||||
|
@ -35,7 +35,9 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
@keyup.esc="clearNewTask($event)"
|
||||
@keyup.enter="addTask"
|
||||
@paste.stop="addMultipleTasks">
|
||||
<Plus :size="20" />
|
||||
<template #icon>
|
||||
<Plus :size="20" />
|
||||
</template>
|
||||
</NcTextField>
|
||||
</div>
|
||||
<FilterDropdown />
|
||||
|
|
|
@ -80,7 +80,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
:size="20"
|
||||
:title="t('tasks', 'Task has a note')"
|
||||
@click="openAppSidebarTab($event, 'app-sidebar-tab-notes')"
|
||||
@dblclick.native.stop="openAppSidebarTab($event, 'app-sidebar-tab-notes', true)" />
|
||||
@dblclick.stop="openAppSidebarTab($event, 'app-sidebar-tab-notes', true)" />
|
||||
<div v-if="task.due || task.completed" :class="{'date--overdue': overdue(task.dueMoment) && !task.completed}" class="date">
|
||||
<span class="date__short" :class="{ 'date__short--completed': task.completed }">{{ dueDateShort }}</span>
|
||||
<span class="date__long" :class="{ 'date__long--date-only': task.allDay && !task.completed, 'date__long--completed': task.completed }">{{ dueDateLong }}</span>
|
||||
|
@ -151,7 +151,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
v-click-outside="closeSubtaskInput"
|
||||
class="task-item task-item__input">
|
||||
<NcTextField ref="input"
|
||||
:value.sync="newTaskName"
|
||||
v-model="newTaskName"
|
||||
:placeholder="subtasksCreationPlaceholder"
|
||||
:label-outside="true"
|
||||
:disabled="isAddingTask"
|
||||
|
@ -164,7 +164,9 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
@keyup.esc="showSubtaskInput = false"
|
||||
@keyup.enter="addTask"
|
||||
@paste.stop="addMultipleTasks">
|
||||
<Plus :size="20" />
|
||||
<template #icon>
|
||||
<Plus :size="20" />
|
||||
</template>
|
||||
</NcTextField>
|
||||
</div>
|
||||
<TaskDragContainer :tasks="filteredSubtasksShown"
|
||||
|
|
|
@ -20,31 +20,32 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
-->
|
||||
|
||||
<template>
|
||||
<draggable tag="ol"
|
||||
:list="['']"
|
||||
<Sortable tag="ol"
|
||||
:list="sortedTasks"
|
||||
:set-data="setDragData"
|
||||
v-bind="{group: 'tasks', swapThreshold: 0.30, delay: 500, delayOnTouchOnly: true, touchStartThreshold: 3, disabled: disabled, filter: '.readOnly'}"
|
||||
:move="onMove"
|
||||
item-key="key"
|
||||
:options="{group: 'tasks', swapThreshold: 0.30, delay: 500, delayOnTouchOnly: true, touchStartThreshold: 3, disabled: disabled, filter: '.readOnly'}"
|
||||
@move="onMove"
|
||||
@add="onAdd"
|
||||
@end="onEnd">
|
||||
<TaskBody v-for="task in sortedTasks"
|
||||
:key="task.key"
|
||||
:task="task"
|
||||
:collection-string="collectionString" />
|
||||
</draggable>
|
||||
<template #item="{element}">
|
||||
<TaskBody :task="element"
|
||||
:collection-string="collectionString" />
|
||||
</template>
|
||||
</Sortable>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Task from '../models/task.js'
|
||||
import { sort } from '../store/storeHelper.js'
|
||||
|
||||
import draggable from 'vuedraggable'
|
||||
import { Sortable } from 'sortablejs-vue3'
|
||||
import { mapGetters, mapActions, mapMutations } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'TaskDragContainer',
|
||||
components: {
|
||||
draggable,
|
||||
Sortable,
|
||||
},
|
||||
props: {
|
||||
tasks: {
|
||||
|
@ -182,20 +183,23 @@ export default {
|
|||
*
|
||||
* @param {object} $event The event which caused the drop
|
||||
*/
|
||||
onAdd($event) {
|
||||
async onAdd($event) {
|
||||
let task
|
||||
// The task to move
|
||||
const taskAttribute = $event.item.attributes['task-id']
|
||||
if (taskAttribute) {
|
||||
task = this.getTask(taskAttribute.value)
|
||||
}
|
||||
// Remove the drag item from the DOM, so it doesn't show up twice.
|
||||
const item = $event.item
|
||||
item.parentElement?.removeChild(item)
|
||||
/**
|
||||
* We have to adjust the sortOrder property of the tasks
|
||||
* to achieve the desired sort order.
|
||||
*/
|
||||
this.adjustSortOrder(task, $event.newIndex, -1)
|
||||
// Move the task to a new calendar or parent.
|
||||
this.prepareMoving(task, $event)
|
||||
await this.prepareMoving(task, $event)
|
||||
this.prepareCollecting(task, $event)
|
||||
$event.stopPropagation()
|
||||
},
|
||||
|
@ -244,7 +248,7 @@ export default {
|
|||
* @param {Task} task The task to change
|
||||
* @param {object} $event The event which caused the move
|
||||
*/
|
||||
prepareMoving(task, $event) {
|
||||
async prepareMoving(task, $event) {
|
||||
let parent, calendar
|
||||
// The new calendar --> make the moved task a root task
|
||||
const calendarAttribute = $event.to.attributes['calendar-id']
|
||||
|
@ -263,7 +267,7 @@ export default {
|
|||
calendar = task.calendar
|
||||
}
|
||||
// Move the task to the appropriate calendar and parent.
|
||||
this.moveTask({ task, calendar, parent })
|
||||
await this.moveTask({ task, calendar, parent })
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,21 +25,13 @@
|
|||
import Dashboard from './views/Dashboard.vue'
|
||||
import store from './store/store.js'
|
||||
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
Vue.prototype.$OC = OC
|
||||
Vue.prototype.$OCA = OCA
|
||||
import { createApp } from 'vue'
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
OCA.Dashboard.register('tasks', (el) => {
|
||||
const View = Vue.extend(Dashboard)
|
||||
const vm = new View({
|
||||
propsData: {},
|
||||
store,
|
||||
}).$mount(el)
|
||||
return vm
|
||||
const item = createApp(Dashboard)
|
||||
.use(store)
|
||||
.mount(el)
|
||||
return item
|
||||
})
|
||||
})
|
||||
|
|
|
@ -25,27 +25,21 @@
|
|||
*/
|
||||
import store from '../store/store.js'
|
||||
|
||||
import Vue from 'vue'
|
||||
import { createApp } from 'vue'
|
||||
|
||||
const buildSelector = (selector, propsData = {}) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const container = document.createElement('div')
|
||||
document.getElementById('body-user').append(container)
|
||||
const View = Vue.extend(selector)
|
||||
const ComponentVM = new View({
|
||||
propsData,
|
||||
store,
|
||||
}).$mount(container)
|
||||
ComponentVM.$root.$on('close', () => {
|
||||
ComponentVM.$el.remove()
|
||||
ComponentVM.$destroy()
|
||||
reject(new Error('Selection canceled'))
|
||||
})
|
||||
ComponentVM.$root.$on('select', (id) => {
|
||||
ComponentVM.$el.remove()
|
||||
ComponentVM.$destroy()
|
||||
resolve(id)
|
||||
const dialog = createApp(selector, {
|
||||
...propsData,
|
||||
onClose() {
|
||||
dialog.$el.remove()
|
||||
reject(new Error('Selection canceled'))
|
||||
},
|
||||
})
|
||||
.use(store)
|
||||
.mount(container)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
69
src/main.js
69
src/main.js
|
@ -36,45 +36,7 @@ import EyeOff from 'vue-material-design-icons/EyeOff.vue'
|
|||
import Pulse from 'vue-material-design-icons/Pulse.vue'
|
||||
import TrendingUp from 'vue-material-design-icons/TrendingUp.vue'
|
||||
|
||||
import Vue from 'vue'
|
||||
import { sync } from 'vuex-router-sync'
|
||||
|
||||
// Disable on production
|
||||
Vue.config.devtools = true
|
||||
Vue.config.performance = true
|
||||
|
||||
sync(store, router)
|
||||
|
||||
/**
|
||||
* We have to globally register these material design icons
|
||||
* so we can use them dynamically via `<component :is="icon" />`
|
||||
* in the MultiselectOption component.
|
||||
*/
|
||||
// eslint-disable-next-line vue/match-component-file-name
|
||||
Vue.component('IconAlertBoxOutline', AlertBoxOutline)
|
||||
// eslint-disable-next-line vue/match-component-file-name
|
||||
Vue.component('IconCalendarRemove', CalendarRemove)
|
||||
// eslint-disable-next-line vue/match-component-file-name
|
||||
Vue.component('IconCancel', Cancel)
|
||||
// eslint-disable-next-line vue/match-component-file-name
|
||||
Vue.component('IconCheck', Check)
|
||||
// eslint-disable-next-line vue/match-component-file-name
|
||||
Vue.component('IconDelete', Delete)
|
||||
// eslint-disable-next-line vue/match-component-file-name
|
||||
Vue.component('IconEye', Eye)
|
||||
// eslint-disable-next-line vue/match-component-file-name
|
||||
Vue.component('IconEyeOff', EyeOff)
|
||||
// eslint-disable-next-line vue/match-component-file-name
|
||||
Vue.component('IconPulse', Pulse)
|
||||
// eslint-disable-next-line vue/match-component-file-name
|
||||
Vue.component('IconTrendingUp', TrendingUp)
|
||||
|
||||
/**
|
||||
* We import TaskBody here globally, because we have a circular dependency
|
||||
* between TaskDragContainer and TaskBody which otherwise cannot be resolved.
|
||||
*/
|
||||
// eslint-disable-next-line vue/match-component-file-name
|
||||
Vue.component('TaskBody', TaskBody)
|
||||
import { createApp } from 'vue'
|
||||
|
||||
if (!OCA.Tasks) {
|
||||
/**
|
||||
|
@ -83,12 +45,25 @@ if (!OCA.Tasks) {
|
|||
OCA.Tasks = {}
|
||||
}
|
||||
|
||||
Vue.prototype.$OC = OC
|
||||
Vue.prototype.$OCA = OCA
|
||||
const Tasks = createApp(App)
|
||||
/**
|
||||
* We import TaskBody here globally, because we have a circular dependency
|
||||
* between TaskDragContainer and TaskBody which otherwise cannot be resolved.
|
||||
*/
|
||||
.component('TaskBody', TaskBody)
|
||||
.component('IconAlertBoxOutline', AlertBoxOutline)
|
||||
.component('IconCalendarRemove', CalendarRemove)
|
||||
.component('IconCancel', Cancel)
|
||||
.component('IconCheck', Check)
|
||||
.component('IconDelete', Delete)
|
||||
.component('IconEye', Eye)
|
||||
.component('IconEyeOff', EyeOff)
|
||||
.component('IconPulse', Pulse)
|
||||
.component('IconTrendingUp', TrendingUp)
|
||||
.provide('$OCA', OCA)
|
||||
.provide('$appVersion', appVersion)
|
||||
.use(router)
|
||||
.use(store)
|
||||
.mount('.app-tasks')
|
||||
|
||||
OCA.Tasks.App = new Vue({
|
||||
el: '.app-tasks',
|
||||
router,
|
||||
store,
|
||||
render: h => h(App),
|
||||
})
|
||||
OCA.Tasks.App = Tasks
|
||||
|
|
|
@ -24,10 +24,10 @@ export default {
|
|||
methods: {
|
||||
openNewTask(task) {
|
||||
// Only open the details view if there is enough space or if it is already open.
|
||||
if (this.$route !== undefined && (document.documentElement.clientWidth >= 768 || this.$route?.params.taskId !== undefined)) {
|
||||
if (this.$route.value !== undefined && (document.documentElement.clientWidth >= 768 || this.$route.value?.params.taskId !== undefined)) {
|
||||
// Open the details view for the new task
|
||||
const calendarId = this.$route.params.calendarId
|
||||
const collectionId = this.$route.params.collectionId
|
||||
const calendarId = this.$route.value.params.calendarId
|
||||
const collectionId = this.$route.value.params.collectionId
|
||||
if (calendarId) {
|
||||
this.$router.push({ name: 'calendarsTask', params: { calendarId, taskId: task.uri } })
|
||||
} else if (collectionId) {
|
||||
|
|
|
@ -25,47 +25,66 @@ import AppSidebar from './views/AppSidebar.vue'
|
|||
import Calendar from './views/AppContent/Calendar.vue'
|
||||
import Collections from './views/AppContent/Collections.vue'
|
||||
|
||||
import Vue from 'vue'
|
||||
import VueRouter from 'vue-router'
|
||||
import { h } from 'vue'
|
||||
import { createWebHashHistory, createRouter, RouterView } from 'vue-router'
|
||||
|
||||
const routes = [
|
||||
// using
|
||||
// { path: '/collections/all', component: CollectionGeneral, alias: '/' },
|
||||
// instead of
|
||||
{ path: '/', redirect: getInitialRoute() },
|
||||
// would also be an option, but it currently does not work
|
||||
// reliably with router-link due to
|
||||
// https://github.com/vuejs/vue-router/issues/419
|
||||
{ name: 'collections', path: '/collections/:collectionId', component: Collections, props: true },
|
||||
{
|
||||
name: 'collectionsTask',
|
||||
path: '/collections/:collectionId/tasks/:taskId',
|
||||
components: { default: Collections, AppSidebar },
|
||||
props: { default: true, AppSidebar: true },
|
||||
path: '/collections/:collectionId',
|
||||
components: {
|
||||
default: { render: () => h(RouterView, { name: 'default' }) },
|
||||
AppSidebar: { render: () => h(RouterView, { name: 'AppSidebar' }) },
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'collections',
|
||||
path: '/collections/:collectionId',
|
||||
component: Collections,
|
||||
props: true,
|
||||
},
|
||||
{
|
||||
name: 'collectionsTask',
|
||||
path: '/collections/:collectionId/tasks/:taskId',
|
||||
components: { default: Collections, AppSidebar },
|
||||
props: { default: true, AppSidebar: true },
|
||||
},
|
||||
{
|
||||
name: 'collectionsParamTask',
|
||||
path: '/collections/:collectionId/:collectionParam/tasks/:taskId',
|
||||
components: { default: Collections, AppSidebar },
|
||||
props: { default: true, AppSidebar: true },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'collectionsParamTask',
|
||||
path: '/collections/:collectionId/:collectionParam/tasks/:taskId',
|
||||
components: { default: Collections, AppSidebar },
|
||||
props: { default: true, AppSidebar: true },
|
||||
},
|
||||
{
|
||||
name: 'calendars',
|
||||
path: '/calendars/:calendarId',
|
||||
component: Calendar,
|
||||
props: true,
|
||||
},
|
||||
{
|
||||
name: 'calendarsTask',
|
||||
path: '/calendars/:calendarId/tasks/:taskId',
|
||||
components: { default: Calendar, AppSidebar },
|
||||
props: { default: true, AppSidebar: true },
|
||||
components: {
|
||||
default: { render: () => h(RouterView, { name: 'default' }) },
|
||||
AppSidebar: { render: () => h(RouterView, { name: 'AppSidebar' }) },
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'calendars',
|
||||
path: '/calendars/:calendarId',
|
||||
component: Calendar,
|
||||
props: true,
|
||||
},
|
||||
{
|
||||
name: 'calendarsTask',
|
||||
path: '/calendars/:calendarId/tasks/:taskId',
|
||||
components: { default: Calendar, AppSidebar },
|
||||
props: { default: true, AppSidebar: true },
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
Vue.use(VueRouter)
|
||||
|
||||
export default new VueRouter({
|
||||
linkActiveClass: 'active',
|
||||
routes, // short for `routes: routes`
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
routes,
|
||||
})
|
||||
|
||||
export { routes }
|
||||
|
||||
export default router
|
||||
|
|
|
@ -40,8 +40,6 @@ import { findVTODObyState } from './cdav-requests.js'
|
|||
import { detectColor, uidToHexColor } from '../utils/color.js'
|
||||
import { mapCDavObjectToCalendarObject } from '../models/calendarObject.js'
|
||||
|
||||
import Vue from 'vue'
|
||||
|
||||
const calendarModel = {
|
||||
id: '',
|
||||
color: '',
|
||||
|
@ -180,9 +178,7 @@ const getters = {
|
|||
* @return {Array<Calendar>} The calendars supporting tasks
|
||||
*/
|
||||
getTaskCalendars: state => {
|
||||
return state.calendars.filter(calendar => {
|
||||
return calendar.supportsTasks
|
||||
})
|
||||
return state.calendars.filter(c => c.supportsTasks)
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -193,11 +189,7 @@ const getters = {
|
|||
* @return {Array<Calendar>} Array of the calendars sorted alphabetically
|
||||
*/
|
||||
getSortedCalendars: (state, getters) => {
|
||||
return getters.getTaskCalendars.sort(function(cal1, cal2) {
|
||||
const n1 = cal1.order
|
||||
const n2 = cal2.order
|
||||
return (n1 < n2) ? -1 : (n1 > n2) ? 1 : 0
|
||||
})
|
||||
return [...getters.getTaskCalendars].sort((c1, c2) => c1.order - c2.order)
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -208,14 +200,7 @@ const getters = {
|
|||
* @return {Array<Calendar>} Array of the calendars sorted alphabetically
|
||||
*/
|
||||
getSortedWritableCalendars: (state, getters) => {
|
||||
return getters.getTaskCalendars.filter(calendar => {
|
||||
return !calendar.readOnly
|
||||
})
|
||||
.sort(function(cal1, cal2) {
|
||||
const n1 = cal1.order
|
||||
const n2 = cal2.order
|
||||
return (n1 < n2) ? -1 : (n1 > n2) ? 1 : 0
|
||||
})
|
||||
return getters.getSortedCalendars.filter(c => !c.readOnly)
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -230,8 +215,7 @@ const getters = {
|
|||
* @return {Calendar} The requested calendar
|
||||
*/
|
||||
(calendarId) => {
|
||||
const calendar = state.calendars.find(search => search.id === calendarId)
|
||||
return calendar
|
||||
return state.calendars.find(c => c.id === calendarId)
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -360,9 +344,7 @@ const getters = {
|
|||
* @return {Array}
|
||||
*/
|
||||
sortedDeletedCalendars(state) {
|
||||
console.debug(state.deletedCalendars)
|
||||
return state.deletedCalendars
|
||||
.sort((a, b) => a.deletedAt - b.deletedAt)
|
||||
return [...state.deletedCalendars].sort((a, b) => a.deletedAt - b.deletedAt)
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -511,7 +493,7 @@ const mutations = {
|
|||
if (list[task.uid]) {
|
||||
console.debug('Duplicate task overridden', list[task.uid], task)
|
||||
}
|
||||
Vue.set(list, task.uid, task)
|
||||
list[task.uid] = task
|
||||
return list
|
||||
}, calendar.tasks)
|
||||
|
||||
|
@ -524,7 +506,7 @@ const mutations = {
|
|||
* @param {Task} task The task to add
|
||||
*/
|
||||
addTaskToCalendar(state, task) {
|
||||
Vue.set(task.calendar.tasks, task.uid, task)
|
||||
task.calendar.tasks[task.uid] = task
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -534,7 +516,7 @@ const mutations = {
|
|||
* @param {Task} task The task to delete
|
||||
*/
|
||||
deleteTaskFromCalendar(state, task) {
|
||||
Vue.delete(task.calendar.tasks, task.uid)
|
||||
delete task.calendar.tasks[task.uid]
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -601,7 +583,7 @@ const mutations = {
|
|||
* @param {number} data.order The sort order
|
||||
*/
|
||||
setCalendarOrder(state, { calendar, order }) {
|
||||
Vue.set(calendar, 'order', order)
|
||||
calendar.order = order
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -693,15 +675,12 @@ const actions = {
|
|||
* @return {Promise}
|
||||
*/
|
||||
async deleteCalendar(context, calendar) {
|
||||
return calendar.dav.delete()
|
||||
.then((response) => {
|
||||
// Delete all the tasks from the store that belong to this calendar
|
||||
Object.values(calendar.tasks)
|
||||
.forEach(task => context.commit('deleteTask', task))
|
||||
// Then delete the calendar
|
||||
context.commit('deleteCalendar', calendar)
|
||||
})
|
||||
.catch((error) => { throw error })
|
||||
await calendar.dav.delete()
|
||||
// Delete all the tasks from the store that belong to this calendar
|
||||
Object.values(calendar.tasks)
|
||||
.forEach(task => context.commit('deleteTask', task))
|
||||
// Then delete the calendar
|
||||
context.commit('deleteCalendar', calendar)
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -802,9 +781,8 @@ const actions = {
|
|||
*/
|
||||
async toggleCalendarEnabled(context, calendar) {
|
||||
calendar.dav.enabled = !calendar.dav.enabled
|
||||
return calendar.dav.update()
|
||||
.then((response) => context.commit('toggleCalendarEnabled', calendar))
|
||||
.catch((error) => { throw error })
|
||||
await calendar.dav.update()
|
||||
context.commit('toggleCalendarEnabled', calendar)
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -820,9 +798,8 @@ const actions = {
|
|||
async changeCalendar(context, { calendar, newName, newColor }) {
|
||||
calendar.dav.displayname = newName
|
||||
calendar.dav.color = newColor
|
||||
return calendar.dav.update()
|
||||
.then((response) => context.commit('renameCalendar', { calendar, newName, newColor }))
|
||||
.catch((error) => { throw error })
|
||||
await calendar.dav.update()
|
||||
context.commit('renameCalendar', { calendar, newName, newColor })
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -848,7 +825,7 @@ const actions = {
|
|||
// so we need to parse one by one
|
||||
const tasks = response.map(item => {
|
||||
const task = new Task(item.data, calendar)
|
||||
Vue.set(task, 'dav', item)
|
||||
task.dav = item
|
||||
return task
|
||||
})
|
||||
|
||||
|
@ -865,7 +842,7 @@ const actions = {
|
|||
if (list[task.uid]) {
|
||||
console.debug('Duplicate task overridden', list[task.uid], task)
|
||||
}
|
||||
Vue.set(list, task.uid, task)
|
||||
list[task.uid] = task
|
||||
return list
|
||||
}, parent.subTasks)
|
||||
|
||||
|
@ -890,7 +867,7 @@ const actions = {
|
|||
const parent = Object.values(calendar.tasks).find(search => search.uid === related)
|
||||
if (parent) {
|
||||
parent.loadedCompleted = true
|
||||
tasks.map(task => Vue.set(parent.subTasks, task.uid, task))
|
||||
tasks.forEach(task => { parent.subTasks[task.uid] = task })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,11 +26,6 @@ import { isTaskInList, searchSubTasks } from './storeHelper.js'
|
|||
|
||||
import { generateUrl } from '@nextcloud/router'
|
||||
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
const state = {
|
||||
collections: [],
|
||||
}
|
||||
|
@ -94,7 +89,7 @@ const mutations = {
|
|||
*/
|
||||
setVisibility(state, newCollection) {
|
||||
const collection = state.collections.find(search => search.id === newCollection.id)
|
||||
Vue.set(collection, 'show', newCollection.show)
|
||||
collection.show = newCollection.show
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -29,8 +29,6 @@
|
|||
import client from '../services/cdav.js'
|
||||
import { getDefaultPrincipalObject, mapDavToPrincipal } from '../models/principal.js'
|
||||
|
||||
import Vue from 'vue'
|
||||
|
||||
const state = {
|
||||
principals: [],
|
||||
principalsById: {},
|
||||
|
@ -54,7 +52,7 @@ const mutations = {
|
|||
}
|
||||
|
||||
state.principals.push(object)
|
||||
Vue.set(state.principalsById, object.id, object)
|
||||
state.principalsById[object.id] = object
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -28,11 +28,6 @@ import Requests from '../services/requests.js'
|
|||
import { loadState } from '@nextcloud/initial-state'
|
||||
import { generateUrl } from '@nextcloud/router'
|
||||
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
const state = {
|
||||
settings: {
|
||||
sortOrder: 'default',
|
||||
|
|
|
@ -27,12 +27,9 @@ import tasks from './tasks.js'
|
|||
import settings from './settings.js'
|
||||
import principals from './principals.js'
|
||||
|
||||
import Vue from 'vue'
|
||||
import Vuex, { Store } from 'vuex'
|
||||
import { createStore } from 'vuex'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
export default new Store({
|
||||
export default createStore({
|
||||
modules: {
|
||||
calendars,
|
||||
collections,
|
||||
|
|
|
@ -33,10 +33,6 @@ import { translate as t } from '@nextcloud/l10n'
|
|||
import moment from '@nextcloud/moment'
|
||||
|
||||
import ICAL from 'ical.js'
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
const state = {
|
||||
tasks: {},
|
||||
|
@ -310,7 +306,7 @@ const mutations = {
|
|||
appendTasks(state, tasks = []) {
|
||||
state.tasks = tasks.reduce(function(list, task) {
|
||||
if (task instanceof Task) {
|
||||
Vue.set(list, task.key, task)
|
||||
list[task.key] = task
|
||||
} else {
|
||||
console.error('Wrong task object', task)
|
||||
}
|
||||
|
@ -325,7 +321,7 @@ const mutations = {
|
|||
* @param {Task} task The task to append
|
||||
*/
|
||||
appendTask(state, task) {
|
||||
Vue.set(state.tasks, task.key, task)
|
||||
state.tasks[task.key] = task
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -336,7 +332,7 @@ const mutations = {
|
|||
*/
|
||||
deleteTask(state, task) {
|
||||
if (state.tasks[task.key] && task instanceof Task) {
|
||||
Vue.delete(state.tasks, task.key)
|
||||
delete state.tasks[task.key]
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -352,7 +348,7 @@ const mutations = {
|
|||
if (task instanceof Task) {
|
||||
// Remove task from parents subTask list if necessary
|
||||
if (task.related && parent) {
|
||||
Vue.delete(parent.subTasks, task.uid)
|
||||
delete parent.subTasks[task.uid]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -367,7 +363,7 @@ const mutations = {
|
|||
*/
|
||||
addTaskToParent(state, { task, parent }) {
|
||||
if (task.related && parent) {
|
||||
Vue.set(parent.subTasks, task.uid, task)
|
||||
parent.subTasks[task.uid] = task
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -380,7 +376,7 @@ const mutations = {
|
|||
* @param {number} data.complete The complete value
|
||||
*/
|
||||
setComplete(state, { task, complete }) {
|
||||
Vue.set(task, 'complete', complete)
|
||||
task.complete = complete
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -391,9 +387,9 @@ const mutations = {
|
|||
*/
|
||||
toggleStarred(state, task) {
|
||||
if (+task.priority < 1 || +task.priority > 4) {
|
||||
Vue.set(task, 'priority', 1)
|
||||
task.priority = 1
|
||||
} else {
|
||||
Vue.set(task, 'priority', 0)
|
||||
task.priority = 0
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -404,7 +400,7 @@ const mutations = {
|
|||
* @param {Task} task The task
|
||||
*/
|
||||
togglePinned(state, task) {
|
||||
Vue.set(task, 'pinned', !task.pinned)
|
||||
task.pinned = !task.pinned
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -414,7 +410,7 @@ const mutations = {
|
|||
* @param {Task} task The task
|
||||
*/
|
||||
toggleSubtasksVisibility(state, task) {
|
||||
Vue.set(task, 'hideSubtasks', !task.hideSubtasks)
|
||||
task.hideSubtasks = !task.hideSubtasks
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -424,7 +420,7 @@ const mutations = {
|
|||
* @param {Task} task The task
|
||||
*/
|
||||
toggleCompletedSubtasksVisibility(state, task) {
|
||||
Vue.set(task, 'hideCompletedSubtasks', !task.hideCompletedSubtasks)
|
||||
task.hideCompletedSubtasks = !task.hideCompletedSubtasks
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -436,7 +432,7 @@ const mutations = {
|
|||
* @param {string} data.summary The summary
|
||||
*/
|
||||
setSummary(state, { task, summary }) {
|
||||
Vue.set(task, 'summary', summary)
|
||||
task.summary = summary
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -448,7 +444,7 @@ const mutations = {
|
|||
* @param {string} data.note The note
|
||||
*/
|
||||
setNote(state, { task, note }) {
|
||||
Vue.set(task, 'note', note)
|
||||
task.note = note
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -460,7 +456,7 @@ const mutations = {
|
|||
* @param {Array} data.tags The array of tags
|
||||
*/
|
||||
setTags(state, { task, tags }) {
|
||||
Vue.set(task, 'tags', tags)
|
||||
task.tags = tags
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -472,7 +468,7 @@ const mutations = {
|
|||
* @param {string} data.tag The tag to add
|
||||
*/
|
||||
addTag(state, { task, tag }) {
|
||||
Vue.set(task, 'tags', task.tags.concat([tag]))
|
||||
task.tags = task.tags.concat([tag])
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -484,7 +480,7 @@ const mutations = {
|
|||
* @param {string} data.priority The priority
|
||||
*/
|
||||
setPriority(state, { task, priority }) {
|
||||
Vue.set(task, 'priority', priority)
|
||||
task.priority = priority
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -496,7 +492,7 @@ const mutations = {
|
|||
* @param {string} data.location The location
|
||||
*/
|
||||
setLocation(state, { task, location }) {
|
||||
Vue.set(task, 'location', location)
|
||||
task.location = location
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -508,7 +504,7 @@ const mutations = {
|
|||
* @param {string} data.url The url
|
||||
*/
|
||||
setUrl(state, { task, url }) {
|
||||
Vue.set(task, 'customUrl', url)
|
||||
task.customUrl = url
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -520,7 +516,7 @@ const mutations = {
|
|||
* @param {string} data.classification The classification
|
||||
*/
|
||||
setClassification(state, { task, classification }) {
|
||||
Vue.set(task, 'class', classification)
|
||||
task.class = classification
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -532,7 +528,7 @@ const mutations = {
|
|||
* @param {string} data.status The status
|
||||
*/
|
||||
setStatus(state, { task, status }) {
|
||||
Vue.set(task, 'status', status)
|
||||
task.status = status
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -544,7 +540,7 @@ const mutations = {
|
|||
* @param {number} data.order The sort order
|
||||
*/
|
||||
setSortOrder(state, { task, order }) {
|
||||
Vue.set(task, 'sortOrder', order)
|
||||
task.sortOrder = order
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -559,7 +555,7 @@ const mutations = {
|
|||
setDue(state, { task, due, allDay }) {
|
||||
if (due === null) {
|
||||
// If the date is null, just set (remove) it.
|
||||
Vue.set(task, 'due', due)
|
||||
task.due = due
|
||||
} else {
|
||||
// Check, that the due date is after the start date.
|
||||
// If it is not, shift the start date to keep the difference between start and due equal.
|
||||
|
@ -571,10 +567,10 @@ const mutations = {
|
|||
} else {
|
||||
start = due.clone()
|
||||
}
|
||||
Vue.set(task, 'start', momentToICALTime(start, allDay))
|
||||
task.start = momentToICALTime(start, allDay)
|
||||
}
|
||||
// Set the due date, convert it to ICALTime first.
|
||||
Vue.set(task, 'due', momentToICALTime(due, allDay))
|
||||
task.due = momentToICALTime(due, allDay)
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -590,7 +586,7 @@ const mutations = {
|
|||
setStart(state, { task, start, allDay }) {
|
||||
if (start === null) {
|
||||
// If the date is null, just set (remove) it.
|
||||
Vue.set(task, 'start', start)
|
||||
task.start = start
|
||||
} else {
|
||||
// Check, that the start date is before the due date.
|
||||
// If it is not, shift the due date to keep the difference between start and due equal.
|
||||
|
@ -602,10 +598,10 @@ const mutations = {
|
|||
} else {
|
||||
due = start.clone()
|
||||
}
|
||||
Vue.set(task, 'due', momentToICALTime(due, allDay))
|
||||
task.due = momentToICALTime(due, allDay)
|
||||
}
|
||||
// Set the due date, convert it to ICALTime first.
|
||||
Vue.set(task, 'start', momentToICALTime(start, allDay))
|
||||
task.start = momentToICALTime(start, allDay)
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -616,7 +612,7 @@ const mutations = {
|
|||
* @param {Task} task The task
|
||||
*/
|
||||
toggleAllDay(state, task) {
|
||||
Vue.set(task, 'allDay', !task.allDay)
|
||||
task.allDay = !task.allDay
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -628,7 +624,7 @@ const mutations = {
|
|||
* @param {Calendar} data.calendar The calendar to move the task to
|
||||
*/
|
||||
setTaskCalendar(state, { task, calendar }) {
|
||||
Vue.set(task, 'calendar', calendar)
|
||||
task.calendar = calendar
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -640,7 +636,7 @@ const mutations = {
|
|||
* @param {string} data.related The uid of the related task
|
||||
*/
|
||||
setTaskParent(state, { task, related }) {
|
||||
Vue.set(task, 'related', related)
|
||||
task.related = related
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -706,17 +702,17 @@ const mutations = {
|
|||
* @param {string} filter The filter
|
||||
*/
|
||||
setFilter(state, filter) {
|
||||
Vue.set(state.filter, 'tags', filter.tags)
|
||||
state.filter.tags = filter.tags
|
||||
state.filter = filter
|
||||
},
|
||||
|
||||
addTaskForDeletion(state, { task }) {
|
||||
Vue.set(state.deletedTasks, task.key, task)
|
||||
state.deletedTasks[task.key] = task
|
||||
},
|
||||
|
||||
clearTaskFromDeletion(state, { task }) {
|
||||
if (state.deletedTasks[task.key] && task instanceof Task) {
|
||||
Vue.delete(state.deletedTasks, task.key)
|
||||
delete state.deletedTasks[task.key]
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -729,7 +725,7 @@ const mutations = {
|
|||
* @param {number} data.countdown The countdown value
|
||||
*/
|
||||
setTaskDeleteCountdown(state, { task, countdown }) {
|
||||
Vue.set(task, 'deleteCountdown', countdown)
|
||||
task.deleteCountdown = countdown
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -792,7 +788,7 @@ const actions = {
|
|||
|
||||
if (!task.dav) {
|
||||
const response = await task.calendar.dav.createVObject(vData)
|
||||
Vue.set(task, 'dav', response)
|
||||
task.dav = response
|
||||
task.syncStatus = new SyncStatus('success', t('tasks', 'Successfully created the task.'))
|
||||
context.commit('appendTask', task)
|
||||
context.commit('addTaskToCalendar', task)
|
||||
|
@ -975,7 +971,7 @@ const actions = {
|
|||
const response = await calendar.dav.find(taskUri)
|
||||
if (response) {
|
||||
const task = new Task(response.data, calendar)
|
||||
Vue.set(task, 'dav', response)
|
||||
task.dav = response
|
||||
if (task.related) {
|
||||
let parent = context.getters.getTaskByUid(task.related)
|
||||
// If the parent is not found locally, we try to get it from the server.
|
||||
|
@ -1016,7 +1012,7 @@ const actions = {
|
|||
// We expect to only get zero or one task when we query by UID.
|
||||
if (response.length) {
|
||||
const task = new Task(response[0].data, calendar)
|
||||
Vue.set(task, 'dav', response[0])
|
||||
task.dav = response[0]
|
||||
if (task.related) {
|
||||
let parent = context.getters.getTaskByUid(task.related)
|
||||
// If the parent is not found locally, we try to get it from the server.
|
||||
|
@ -1421,10 +1417,10 @@ const actions = {
|
|||
const oldParent = context.getters.getTaskByUid(task.related)
|
||||
context.commit('deleteTaskFromParent', { task, parent: oldParent })
|
||||
// Link to new parent
|
||||
Vue.set(task, 'related', parentId)
|
||||
task.related = parentId
|
||||
// Add task to new parents subtask list
|
||||
if (parent) {
|
||||
Vue.set(parent.subTasks, task.uid, task)
|
||||
parent.subTasks[task.uid] = task
|
||||
// If the parent is completed, we complete the task
|
||||
if (parent.completed) {
|
||||
await context.dispatch('setPercentComplete', { task, complete: 100 })
|
||||
|
|
|
@ -34,11 +34,6 @@ import { buildSelector } from './helpers/selector.js'
|
|||
import { translate as t } from '@nextcloud/l10n'
|
||||
import { generateUrl } from '@nextcloud/router'
|
||||
|
||||
import Vue from 'vue'
|
||||
|
||||
Vue.prototype.$OC = OC
|
||||
Vue.prototype.$OCA = OCA
|
||||
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
if (!window.OCA?.Talk?.registerMessageAction) {
|
||||
return
|
||||
|
|
|
@ -31,11 +31,11 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
:name="collection.displayName"
|
||||
class="collection reactive"
|
||||
draggable="false"
|
||||
@dragstart.native="dragStart"
|
||||
@drop.native="dropTaskOnCollection(...arguments, collection)"
|
||||
@dragover.native="dragOver"
|
||||
@dragenter.native="dragEnter(...arguments, collection)"
|
||||
@dragleave.native="dragLeave"
|
||||
@dragstart="dragStart"
|
||||
@drop="dropTaskOnCollection(...arguments, collection)"
|
||||
@dragover="dragOver"
|
||||
@dragenter="dragEnter(...arguments, collection)"
|
||||
@dragleave="dragLeave"
|
||||
@click="setInitialRoute(`/collections/${collection.id}`)">
|
||||
<template #icon>
|
||||
<component :is="collection.icon"
|
||||
|
@ -47,15 +47,17 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
</NcCounterBubble>
|
||||
</template>
|
||||
</NcAppNavigationItem>
|
||||
<draggable class="draggable-container"
|
||||
<Sortable class="draggable-container"
|
||||
:list="calendars"
|
||||
:set-data="setData"
|
||||
v-bind="{swapThreshold: 0.30, delay: 500, delayOnTouchOnly: true, touchStartThreshold: 3}"
|
||||
item-key="id"
|
||||
:options="{swapThreshold: 0.30, delay: 500, delayOnTouchOnly: true, touchStartThreshold: 3}"
|
||||
@update="update">
|
||||
<ListItemCalendar v-for="calendar in calendars"
|
||||
:key="calendar.id"
|
||||
:calendar="calendar"
|
||||
@click.native="setInitialRoute(`/calendars/${calendar.id}`)" />
|
||||
</draggable>
|
||||
<template #item="{element}">
|
||||
<ListItemCalendar :calendar="element"
|
||||
@click="setInitialRoute(`/calendars/${element.id}`)" />
|
||||
</template>
|
||||
</Sortable>
|
||||
<NcAppNavigationItem v-click-outside="() => {creating = false}"
|
||||
:name="t('tasks', 'Add List…')"
|
||||
:class="{'collection--edit': creating}"
|
||||
|
@ -67,6 +69,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
<li>
|
||||
<div class="app-navigation-entry-edit">
|
||||
<NcTextField ref="newListInput"
|
||||
v-model="newCalendarName"
|
||||
v-tooltip="{
|
||||
content: tooltipMessage,
|
||||
shown: showTooltip('list_new'),
|
||||
|
@ -75,7 +78,6 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
type="text"
|
||||
:show-trailing-button="newCalendarName !== ''"
|
||||
trailing-button-icon="arrowRight"
|
||||
:value.sync="newCalendarName"
|
||||
:error="nameError"
|
||||
:label="t('tasks', 'New list')"
|
||||
@trailing-button-click="create()"
|
||||
|
@ -115,7 +117,7 @@ import Plus from 'vue-material-design-icons/Plus.vue'
|
|||
import Star from 'vue-material-design-icons/Star.vue'
|
||||
import TrendingUp from 'vue-material-design-icons/TrendingUp.vue'
|
||||
|
||||
import draggable from 'vuedraggable'
|
||||
import { Sortable } from 'sortablejs-vue3'
|
||||
import { vOnClickOutside as ClickOutside } from '@vueuse/components'
|
||||
import { mapState, mapGetters, mapActions } from 'vuex'
|
||||
|
||||
|
@ -129,7 +131,7 @@ export default {
|
|||
NcCounterBubble,
|
||||
NcTextField,
|
||||
AppNavigationSettings,
|
||||
draggable,
|
||||
Sortable,
|
||||
CalendarToday,
|
||||
CalendarWeek,
|
||||
Check,
|
||||
|
@ -142,6 +144,7 @@ export default {
|
|||
ClickOutside,
|
||||
Tooltip,
|
||||
},
|
||||
inject: ['$OCA'],
|
||||
data() {
|
||||
return {
|
||||
editing: '',
|
||||
|
|
|
@ -20,16 +20,16 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
-->
|
||||
|
||||
<template>
|
||||
<NcAppSidebar :name="summary"
|
||||
<NcAppSidebar v-model:active="activeTab"
|
||||
:name="summary"
|
||||
:name-editable="editingSummary"
|
||||
:linkify-name="true"
|
||||
:subname="subsummary"
|
||||
:name-tooltip="summary"
|
||||
:subname-tooltip="subsummaryTooltip"
|
||||
:empty="!task"
|
||||
:active.sync="activeTab"
|
||||
@start-editing="newSummary = task.summary"
|
||||
@update:nameEditable="editSummary"
|
||||
@update:name-editable="editSummary"
|
||||
@update:name="updateSummary"
|
||||
@submit-name="saveSummary()"
|
||||
@close="closeAppSidebar()">
|
||||
|
@ -681,7 +681,7 @@ export default {
|
|||
subscribe('tasks:open-appsidebar-tab', this.openAppSidebarTab)
|
||||
subscribe('tasks:edit-appsidebar-summary', this.editSummary)
|
||||
},
|
||||
beforeDestroy() {
|
||||
beforeUnmount() {
|
||||
unsubscribe('tasks:close-appsidebar', this.closeAppSidebar)
|
||||
unsubscribe('tasks:task:deleted', this.handleTaskDeletion)
|
||||
unsubscribe('tasks:open-appsidebar-tab', this.openAppSidebarTab)
|
||||
|
|
|
@ -10,11 +10,8 @@ import router from '../../../../src/router.js'
|
|||
import { loadICS } from '../../../assets/loadAsset.js'
|
||||
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { shallowMount, createLocalVue } from '@vue/test-utils'
|
||||
import Vuex, { Store } from 'vuex'
|
||||
|
||||
const localVue = createLocalVue()
|
||||
localVue.use(Vuex)
|
||||
import { shallowMount } from '@vue/test-utils'
|
||||
import { createStore } from 'vuex'
|
||||
|
||||
const calendar = {
|
||||
url: 'calendar-1/tmp',
|
||||
|
@ -40,7 +37,7 @@ describe('TaskDragContainer.vue', () => {
|
|||
// Override the "updateTask" method so we don't get warnings about unresolved promises.
|
||||
tasks.actions.updateTask = vi.fn()
|
||||
|
||||
store = new Store({
|
||||
store = createStore({
|
||||
modules: {
|
||||
calendars,
|
||||
collections,
|
||||
|
@ -53,10 +50,10 @@ describe('TaskDragContainer.vue', () => {
|
|||
|
||||
it('Checks that the tasks are sorted correctly on manual sort.', async () => {
|
||||
const wrapper = shallowMount(TaskDragContainer, {
|
||||
localVue,
|
||||
store,
|
||||
router,
|
||||
propsData: {
|
||||
global: {
|
||||
plugins: [store, router],
|
||||
},
|
||||
props: {
|
||||
tasks: taskItems,
|
||||
},
|
||||
})
|
||||
|
@ -73,10 +70,10 @@ describe('TaskDragContainer.vue', () => {
|
|||
|
||||
it('Checks that tasks are properly reordered.', async () => {
|
||||
const wrapper = shallowMount(TaskDragContainer, {
|
||||
localVue,
|
||||
store,
|
||||
router,
|
||||
propsData: {
|
||||
global: {
|
||||
plugins: [store, router],
|
||||
},
|
||||
props: {
|
||||
tasks: taskItems,
|
||||
},
|
||||
})
|
||||
|
|
|
@ -2,8 +2,6 @@ import { OC } from './OC.js'
|
|||
|
||||
// eslint-disable-next-line n/no-unpublished-import
|
||||
import MockDate from 'mockdate'
|
||||
// eslint-disable-next-line n/no-unpublished-import
|
||||
import 'regenerator-runtime/runtime'
|
||||
|
||||
import { afterAll } from 'vitest'
|
||||
|
||||
|
|
|
@ -3,18 +3,12 @@ import collections from '../../../src/store/collections.js'
|
|||
import tasks from '../../../src/store/tasks.js'
|
||||
import settings from '../../../src/store/settings.js'
|
||||
import Task from '../../../src/models/task.js'
|
||||
import router from '../../../src/router.js'
|
||||
|
||||
import { loadICS } from '../../assets/loadAsset.js'
|
||||
|
||||
import { createLocalVue } from '@vue/test-utils'
|
||||
import Vuex, { Store } from 'vuex'
|
||||
import { sync } from 'vuex-router-sync'
|
||||
import { createStore } from 'vuex'
|
||||
|
||||
const localVue = createLocalVue()
|
||||
localVue.use(Vuex)
|
||||
|
||||
const store = new Store({
|
||||
const store = createStore({
|
||||
modules: {
|
||||
calendars,
|
||||
collections,
|
||||
|
@ -23,10 +17,6 @@ const store = new Store({
|
|||
},
|
||||
})
|
||||
|
||||
// Sync router and store so that we can access
|
||||
// the router from within the store
|
||||
sync(store, router)
|
||||
|
||||
const calendarsData = [
|
||||
{
|
||||
url: 'calendar-1/tmp',
|
||||
|
@ -80,7 +70,7 @@ calendarsData.forEach(calendarData => {
|
|||
url: `${calendar.id}/${task.uid}.ics`,
|
||||
update: () => { return Promise.resolve(response) },
|
||||
}
|
||||
localVue.set(task, 'dav', response)
|
||||
task.dav = response
|
||||
return task
|
||||
})
|
||||
// Add subtasks correctly
|
||||
|
@ -95,7 +85,7 @@ calendarsData.forEach(calendarData => {
|
|||
if (list[task.uid]) {
|
||||
console.debug('Duplicate task overridden', list[task.uid], task)
|
||||
}
|
||||
localVue.set(list, task.uid, task)
|
||||
list[task.uid] = task
|
||||
return list
|
||||
}, parent.subTasks)
|
||||
},
|
||||
|
@ -105,4 +95,4 @@ calendarsData.forEach(calendarData => {
|
|||
store.commit('appendTasksToCalendar', { calendar, tasks })
|
||||
})
|
||||
|
||||
export { store, localVue }
|
||||
export { store }
|
||||
|
|
|
@ -2,19 +2,27 @@ import General from '../../../../../src/views/AppContent/General.vue'
|
|||
import router from '../../../../../src/router.js'
|
||||
import TaskBody from '../../../../../src/components/TaskBody.vue'
|
||||
|
||||
import { store, localVue } from '../../setupStore.js'
|
||||
import { store } from '../../setupStore.js'
|
||||
|
||||
import { mount } from '@vue/test-utils'
|
||||
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import Vue from 'vue'
|
||||
Vue.component('TaskBody', TaskBody)
|
||||
|
||||
describe('General.vue', async () => {
|
||||
'use strict'
|
||||
|
||||
const wrapper = mount(General, { localVue, store, router })
|
||||
await router.push('/')
|
||||
// After this line, router is ready
|
||||
await router.isReady()
|
||||
|
||||
const wrapper = mount(General, {
|
||||
global: {
|
||||
plugins: [store, router],
|
||||
components: {
|
||||
TaskBody,
|
||||
},
|
||||
},
|
||||
})
|
||||
await vi.dynamicImportSettled()
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,20 +1,33 @@
|
|||
import Week from '../../../../../src/views/AppContent/Week.vue'
|
||||
import router from '../../../../../src/router.js'
|
||||
import { routes } from '../../../../../src/router.js'
|
||||
import TaskBody from '../../../../../src/components/TaskBody.vue'
|
||||
|
||||
import { store, localVue } from '../../setupStore.js'
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { store } from '../../setupStore.js'
|
||||
|
||||
import { mount, flushPromises } from '@vue/test-utils'
|
||||
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import Vue from 'vue'
|
||||
Vue.component('TaskBody', TaskBody)
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes,
|
||||
})
|
||||
|
||||
describe('Week.vue', async () => {
|
||||
'use strict'
|
||||
|
||||
const wrapper = mount(Week, { localVue, store, router })
|
||||
await router.push('/')
|
||||
await router.isReady()
|
||||
|
||||
const wrapper = mount(Week, {
|
||||
global: {
|
||||
plugins: [store, router],
|
||||
components: {
|
||||
TaskBody,
|
||||
},
|
||||
},
|
||||
})
|
||||
await vi.dynamicImportSettled()
|
||||
|
||||
it('Checks that the correct tasks are shown for day 0 (today)', () => {
|
||||
|
@ -46,8 +59,8 @@ describe('Week.vue', async () => {
|
|||
const taskAtDay2 = wrapper.find('div[day="2"] li[task-id="pwen8kz22g.ics"] > div')
|
||||
|
||||
// Click on first task to open it
|
||||
taskAtDay0.trigger('click')
|
||||
await localVue.nextTick()
|
||||
await taskAtDay0.trigger('click')
|
||||
await flushPromises()
|
||||
|
||||
expect(taskAtDay0.classes('task-item__body--active')).toBe(true) // Should be shown active, since it was clicked
|
||||
expect(taskAtDay2.classes('task-item__body--active')).toBe(false) // Shouldn't be shown active, since it was not clicked
|
||||
|
@ -58,12 +71,12 @@ describe('Week.vue', async () => {
|
|||
const taskAtDay2 = wrapper.find('div[day="2"] li[task-id="pwen8kz22g.ics"] > div')
|
||||
|
||||
// Click on different task to open it
|
||||
taskAtDay2.trigger('click')
|
||||
await localVue.nextTick()
|
||||
await taskAtDay2.trigger('click')
|
||||
await flushPromises()
|
||||
|
||||
if (wrapper.vm.$route.params.taskId !== null && wrapper.vm.$route.params.collectionId !== 'week') {
|
||||
await router.push({ name: 'collections', params: { collectionId: 'week' } })
|
||||
await localVue.nextTick()
|
||||
await flushPromises()
|
||||
}
|
||||
expect(taskAtDay0.classes('task-item__body--active')).toBe(false)
|
||||
|
||||
|
@ -72,8 +85,8 @@ describe('Week.vue', async () => {
|
|||
expect(wrapper.find('div[day="2"] li[task-id="pwen7kz22g.ics"]').exists()).toBe(true) // Shown, since it is due in 2 days
|
||||
|
||||
// Click on first task to open it
|
||||
taskAtDay0.trigger('click')
|
||||
await localVue.nextTick()
|
||||
await taskAtDay0.trigger('click')
|
||||
await flushPromises()
|
||||
expect(taskAtDay0.classes('task-item__body--active')).toBe(true)
|
||||
|
||||
expect(wrapper.find('div[day="0"] li[task-id="pwen7kz22g.ics"]').exists()).toBe(true) // Shown now, because parent is active
|
||||
|
@ -86,12 +99,12 @@ describe('Week.vue', async () => {
|
|||
const taskAtDay2 = wrapper.find('div[day="2"] li[task-id="pwen8kz22g.ics"] > div')
|
||||
|
||||
// Click on different task to open it
|
||||
taskAtDay2.trigger('click')
|
||||
await localVue.nextTick()
|
||||
await taskAtDay2.trigger('click')
|
||||
await flushPromises()
|
||||
|
||||
if (wrapper.vm.$route.params.taskId !== null && wrapper.vm.$route.params.collectionId !== 'week') {
|
||||
await router.push({ name: 'collections', params: { collectionId: 'week' } })
|
||||
await localVue.nextTick()
|
||||
await flushPromises()
|
||||
}
|
||||
expect(taskAtDay0.classes('task-item__body--active')).toBe(false)
|
||||
|
||||
|
@ -100,8 +113,8 @@ describe('Week.vue', async () => {
|
|||
expect(wrapper.find('div[day="0"] li[task-id="pwen2kz38g.ics"]').exists()).toBe(false) // Not shown, since it is not due at all
|
||||
|
||||
// Click on first task to open it
|
||||
taskAtDay0.trigger('click')
|
||||
await localVue.nextTick()
|
||||
await taskAtDay0.trigger('click')
|
||||
await flushPromises()
|
||||
expect(taskAtDay0.classes('task-item__body--active')).toBe(true)
|
||||
|
||||
expect(wrapper.find('div[day="0"] li[task-id="pwen2kz37g.ics"]').exists()).toBe(true) // Shown now, since parent is active
|
||||
|
@ -109,8 +122,8 @@ describe('Week.vue', async () => {
|
|||
|
||||
const subtaskAtDay0 = wrapper.find('div[day="0"] li[task-id="pwen2kz37g.ics"] > div')
|
||||
// Click on subtask to open it
|
||||
subtaskAtDay0.trigger('click')
|
||||
await localVue.nextTick()
|
||||
await subtaskAtDay0.trigger('click')
|
||||
await flushPromises()
|
||||
expect(subtaskAtDay0.classes('task-item__body--active')).toBe(true)
|
||||
|
||||
expect(wrapper.find('div[day="0"] li[task-id="pwen2kz38g.ics"]').exists()).toBe(true) // Shown now, since parent is active
|
||||
|
@ -118,8 +131,8 @@ describe('Week.vue', async () => {
|
|||
|
||||
const subsubtaskAtDay0 = wrapper.find('div[day="0"] li[task-id="pwen2kz38g.ics"] > div')
|
||||
// Click on subtask to open it
|
||||
subsubtaskAtDay0.trigger('click')
|
||||
await localVue.nextTick()
|
||||
await subsubtaskAtDay0.trigger('click')
|
||||
await flushPromises()
|
||||
expect(subsubtaskAtDay0.classes('task-item__body--active')).toBe(true)
|
||||
|
||||
expect(wrapper.find('div[day="0"] li[task-id="pwen8kz22g.ics"]').exists()).toBe(true) // Shown, since it is due today
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
import AppSidebar from '../../../../src/views/AppSidebar.vue'
|
||||
import router from '../../../../src/router.js'
|
||||
|
||||
import { store, localVue } from '../setupStore.js'
|
||||
import { store } from '../setupStore.js'
|
||||
|
||||
import { shallowMount } from '@vue/test-utils'
|
||||
|
||||
|
@ -36,7 +36,11 @@ describe('AppSidebar.vue', () => {
|
|||
router.push({ name: 'calendarsTask', params: { calendarId: 'calendar-1', taskId: 'pwen4kz18g.ics' } })
|
||||
|
||||
it('Returns the correct value for the new dates', () => {
|
||||
const wrapper = shallowMount(AppSidebar, { localVue, store, router })
|
||||
const wrapper = shallowMount(AppSidebar, {
|
||||
global: {
|
||||
plugins: [store, router],
|
||||
},
|
||||
})
|
||||
|
||||
let actual = wrapper.vm.newStartDate
|
||||
let expected = new Date('2019-01-01T12:00:00')
|
||||
|
|
|
@ -15,7 +15,6 @@ export default createAppConfig({
|
|||
},
|
||||
environment: 'happy-dom',
|
||||
setupFiles: resolve(__dirname, './tests/javascript/unit/setup.js'),
|
||||
alias: [{ find: /^vue$/, replacement: 'vue/dist/vue.runtime.common.js' }],
|
||||
server: {
|
||||
deps: {
|
||||
inline: ['@nextcloud/vue'],
|
||||
|
|
Loading…
Reference in New Issue