forked from vikunja/frontend
Merge remote-tracking branch 'upstream/main'
This commit is contained in:
commit
5ac95e914b
|
@ -35,7 +35,7 @@
|
|||
"vue-shortkey": "3.1.7",
|
||||
"vuedraggable": "2.24.3",
|
||||
"vuex": "3.6.2",
|
||||
"workbox-precaching": "6.2.4"
|
||||
"workbox-precaching": "6.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@4tw/cypress-drag-drop": "2.0.0",
|
||||
|
@ -53,7 +53,7 @@
|
|||
"babel-eslint": "10.1.0",
|
||||
"cypress": "8.3.1",
|
||||
"cypress-file-upload": "5.0.8",
|
||||
"esbuild": "0.12.25",
|
||||
"esbuild": "0.12.26",
|
||||
"eslint": "7.32.0",
|
||||
"eslint-plugin-vue": "7.17.0",
|
||||
"express": "4.17.1",
|
||||
|
@ -61,7 +61,7 @@
|
|||
"jest": "27.1.1",
|
||||
"rollup-plugin-terser": "7.0.2",
|
||||
"rollup-plugin-visualizer": "5.5.2",
|
||||
"sass": "1.39.0",
|
||||
"sass": "1.39.2",
|
||||
"ts-jest": "27.0.5",
|
||||
"typescript": "4.4.2",
|
||||
"vite": "2.5.6",
|
||||
|
@ -72,7 +72,7 @@
|
|||
"vue-router": "3.5.2",
|
||||
"vue-template-compiler": "2.6.14",
|
||||
"wait-on": "6.0.0",
|
||||
"workbox-cli": "6.2.4"
|
||||
"workbox-cli": "6.3.0"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
|
|
10
src/App.vue
10
src/App.vue
|
@ -23,11 +23,9 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from 'vuex'
|
||||
import {mapState, mapGetters} from 'vuex'
|
||||
import isTouchDevice from 'is-touch-device'
|
||||
|
||||
import authTypes from './models/authTypes'
|
||||
|
||||
import Notification from './components/misc/notification'
|
||||
import {KEYBOARD_SHORTCUTS_ACTIVE, ONLINE} from './store/mutation-types'
|
||||
import KeyboardShortcuts from './components/misc/keyboard-shortcuts'
|
||||
|
@ -74,11 +72,13 @@ export default {
|
|||
return isTouchDevice()
|
||||
},
|
||||
...mapState({
|
||||
authUser: state => state.auth.authenticated && (state.auth.info && state.auth.info.type === authTypes.USER),
|
||||
authLinkShare: state => state.auth.authenticated && (state.auth.info && state.auth.info.type === authTypes.LINK_SHARE),
|
||||
online: ONLINE,
|
||||
keyboardShortcutsActive: KEYBOARD_SHORTCUTS_ACTIVE,
|
||||
}),
|
||||
...mapGetters('auth', [
|
||||
'authUser',
|
||||
'authLinkShare',
|
||||
]),
|
||||
},
|
||||
methods: {
|
||||
setupOnlineStatus() {
|
||||
|
|
|
@ -97,7 +97,7 @@
|
|||
<script>
|
||||
import {mapState} from 'vuex'
|
||||
import {CURRENT_LIST, QUICK_ACTIONS_ACTIVE} from '@/store/mutation-types'
|
||||
import Rights from '@/models/rights.json'
|
||||
import Rights from '@/models/constants/rights.json'
|
||||
import Update from '@/components/home/update.vue'
|
||||
import ListSettingsDropdown from '@/components/list/list-settings-dropdown.vue'
|
||||
import Dropdown from '@/components/misc/dropdown.vue'
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
:checked="checked"
|
||||
:disabled="disabled"
|
||||
:id="checkBoxId"
|
||||
@change="updateData"
|
||||
@change="(event) => updateData(event.target.checked)"
|
||||
style="display: none;"
|
||||
type="checkbox"/>
|
||||
<label :for="checkBoxId" class="check">
|
||||
|
@ -51,10 +51,10 @@ export default {
|
|||
this.checkBoxId = 'fancycheckbox' + Math.random()
|
||||
},
|
||||
methods: {
|
||||
updateData(e) {
|
||||
this.checked = e.target.checked
|
||||
this.$emit('input', this.checked)
|
||||
this.$emit('change', e.target.checked)
|
||||
updateData(checked) {
|
||||
this.checked = checked
|
||||
this.$emit('input', checked)
|
||||
this.$emit('change', checked)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -190,6 +190,35 @@ import ListService from '@/services/list'
|
|||
import NamespaceService from '@/services/namespace'
|
||||
import EditLabels from '@/components/tasks/partials/editLabels.vue'
|
||||
|
||||
// FIXME: merge with DEFAULT_PARAMS in taskList.js
|
||||
const DEFAULT_PARAMS = {
|
||||
sort_by: [],
|
||||
order_by: [],
|
||||
filter_by: [],
|
||||
filter_value: [],
|
||||
filter_comparator: [],
|
||||
filter_include_nulls: true,
|
||||
filter_concat: 'or',
|
||||
s: '',
|
||||
}
|
||||
|
||||
const DEFAULT_FILTERS = {
|
||||
done: false,
|
||||
dueDate: '',
|
||||
requireAllFilters: false,
|
||||
priority: 0,
|
||||
usePriority: false,
|
||||
startDate: '',
|
||||
endDate: '',
|
||||
percentDone: 0,
|
||||
usePercentDone: false,
|
||||
reminders: '',
|
||||
assignees: '',
|
||||
labels: '',
|
||||
list_id: '',
|
||||
namespace: '',
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'filters',
|
||||
components: {
|
||||
|
@ -202,32 +231,8 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
params: {
|
||||
sort_by: [],
|
||||
order_by: [],
|
||||
filter_by: [],
|
||||
filter_value: [],
|
||||
filter_comparator: [],
|
||||
filter_include_nulls: true,
|
||||
filter_concat: 'or',
|
||||
s: '',
|
||||
},
|
||||
filters: {
|
||||
done: false,
|
||||
dueDate: '',
|
||||
requireAllFilters: false,
|
||||
priority: 0,
|
||||
usePriority: false,
|
||||
startDate: '',
|
||||
endDate: '',
|
||||
percentDone: 0,
|
||||
usePercentDone: false,
|
||||
reminders: '',
|
||||
assignees: '',
|
||||
labels: '',
|
||||
list_id: '',
|
||||
namespace: '',
|
||||
},
|
||||
params: DEFAULT_PARAMS,
|
||||
filters: DEFAULT_FILTERS,
|
||||
|
||||
usersService: UserService,
|
||||
foundusers: [],
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
<script>
|
||||
import NotificationService from '@/services/notification'
|
||||
import User from '@/components/misc/user.vue'
|
||||
import names from '@/models/notificationNames.json'
|
||||
import names from '@/models/constants/notificationNames.json'
|
||||
import {closeWhenClickedOutside} from '@/helpers/closeWhenClickedOutside'
|
||||
import {mapState} from 'vuex'
|
||||
|
||||
|
|
|
@ -173,7 +173,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import rights from '../../models/rights'
|
||||
import rights from '../../models/constants/rights'
|
||||
|
||||
import LinkShareService from '../../services/linkShare'
|
||||
import LinkShareModel from '../../models/linkShare'
|
||||
|
|
|
@ -145,7 +145,7 @@ import TeamListService from '../../services/teamList'
|
|||
import TeamService from '../../services/team'
|
||||
import TeamModel from '../../models/team'
|
||||
|
||||
import rights from '../../models/rights'
|
||||
import rights from '../../models/constants/rights.json'
|
||||
import Multiselect from '@/components/input/multiselect.vue'
|
||||
import Nothing from '@/components/misc/nothing.vue'
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
import ListService from '../../services/list'
|
||||
import TaskService from '../../services/task'
|
||||
import TaskModel from '../../models/task'
|
||||
import priorities from '../../models/priorities'
|
||||
import priorities from '../../models/constants/priorities'
|
||||
import EditLabels from './partials/editLabels'
|
||||
import Reminders from './partials/reminders'
|
||||
import ColorPicker from '../input/colorPicker'
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
</x-button>
|
||||
</div>
|
||||
<filter-popup
|
||||
@change="loadTasks"
|
||||
@change="loadTasks()"
|
||||
:visible="showTaskFilter"
|
||||
v-model="params"
|
||||
/>
|
||||
|
@ -24,10 +24,7 @@
|
|||
class="month"
|
||||
v-for="(m, mk) in days[yk]"
|
||||
>
|
||||
{{
|
||||
new Date(new Date(`${yk}-${parseInt(mk) + 1}-01`)).toLocaleString('en-us', {month: 'long'})
|
||||
}},
|
||||
{{ new Date(yk).getFullYear() }}
|
||||
{{ formatYear(new Date(`${yk}-${parseInt(mk) + 1}-01`)) }}
|
||||
<div class="days">
|
||||
<div
|
||||
:class="{ today: d.toDateString() === now.toDateString() }"
|
||||
|
@ -191,12 +188,13 @@ import EditTask from './edit-task'
|
|||
|
||||
import TaskService from '../../services/task'
|
||||
import TaskModel from '../../models/task'
|
||||
import priorities from '../../models/priorities'
|
||||
import priorities from '../../models/constants/priorities'
|
||||
import PriorityLabel from './partials/priorityLabel'
|
||||
import TaskCollectionService from '../../services/taskCollection'
|
||||
import {mapState} from 'vuex'
|
||||
import Rights from '../../models/rights.json'
|
||||
import Rights from '../../models/constants/rights.json'
|
||||
import FilterPopup from '@/components/list/partials/filter-popup.vue'
|
||||
import {format} from 'date-fns'
|
||||
|
||||
export default {
|
||||
name: 'GanttChart',
|
||||
|
@ -481,6 +479,9 @@ export default {
|
|||
this.error(e)
|
||||
})
|
||||
},
|
||||
formatYear(date) {
|
||||
return format(date, 'MMMM, yyyy')
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,17 +1,70 @@
|
|||
import TaskCollectionService from '../../../services/taskCollection'
|
||||
import TaskCollectionService from '@/services/taskCollection'
|
||||
import cloneDeep from 'lodash/cloneDeep'
|
||||
import {calculateItemPosition} from '../../../helpers/calculateItemPosition'
|
||||
|
||||
// FIXME: merge with DEFAULT_PARAMS in filters.vue
|
||||
const DEFAULT_PARAMS = {
|
||||
sort_by: ['position', 'id'],
|
||||
order_by: ['asc', 'desc'],
|
||||
filter_by: ['done'],
|
||||
filter_value: ['false'],
|
||||
filter_comparator: ['equals'],
|
||||
filter_concat: 'and',
|
||||
}
|
||||
|
||||
function createPagination(totalPages, currentPage) {
|
||||
const pages = []
|
||||
for (let i = 0; i < totalPages; i++) {
|
||||
|
||||
// Show ellipsis instead of all pages
|
||||
if (
|
||||
i > 0 && // Always at least the first page
|
||||
(i + 1) < totalPages && // And the last page
|
||||
(
|
||||
// And the current with current + 1 and current - 1
|
||||
(i + 1) > currentPage + 1 ||
|
||||
(i + 1) < currentPage - 1
|
||||
)
|
||||
) {
|
||||
// Only add an ellipsis if the last page isn't already one
|
||||
if (pages[i - 1] && !pages[i - 1].isEllipsis) {
|
||||
pages.push({
|
||||
number: 0,
|
||||
isEllipsis: true,
|
||||
})
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
pages.push({
|
||||
number: i + 1,
|
||||
isEllipsis: false,
|
||||
})
|
||||
}
|
||||
return pages
|
||||
}
|
||||
|
||||
export function getRouteForPagination(page = 1, type = 'list') {
|
||||
return {
|
||||
name: 'list.' + type,
|
||||
params: {
|
||||
type: type,
|
||||
},
|
||||
query: {
|
||||
page: page,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This mixin provides a base set of methods and properties to get tasks on a list.
|
||||
*/
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
taskCollectionService: TaskCollectionService,
|
||||
taskCollectionService: new TaskCollectionService(),
|
||||
tasks: [],
|
||||
|
||||
pages: [],
|
||||
currentPage: 0,
|
||||
|
||||
loadedList: null,
|
||||
|
@ -20,27 +73,21 @@ export default {
|
|||
searchTerm: '',
|
||||
|
||||
showTaskFilter: false,
|
||||
params: {
|
||||
sort_by: ['position', 'id'],
|
||||
order_by: ['asc', 'desc'],
|
||||
filter_by: ['done'],
|
||||
filter_value: ['false'],
|
||||
filter_comparator: ['equals'],
|
||||
filter_concat: 'and',
|
||||
},
|
||||
params: DEFAULT_PARAMS,
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'$route.query': 'loadTasksForPage', // Only listen for query path changes
|
||||
// Only listen for query path changes
|
||||
'$route.query': {
|
||||
handler: 'loadTasksForPage',
|
||||
immediate: true,
|
||||
},
|
||||
'$route.path': 'loadTasksOnSavedFilter',
|
||||
},
|
||||
beforeMount() {
|
||||
// Triggering loading the tasks in beforeMount lets the component maintain the current page, therefore the page
|
||||
// is not lost after navigating back from a task detail page for example.
|
||||
this.loadTasksForPage(this.$route.query)
|
||||
},
|
||||
created() {
|
||||
this.taskCollectionService = new TaskCollectionService()
|
||||
computed: {
|
||||
pages() {
|
||||
return createPagination(this.taskCollectionService.totalPages, this.currentPage)
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
loadTasks(
|
||||
|
@ -80,48 +127,20 @@ export default {
|
|||
return
|
||||
}
|
||||
|
||||
this.$set(this, 'tasks', [])
|
||||
this.tasks = []
|
||||
|
||||
this.taskCollectionService.getAll(list, params, page)
|
||||
.then(r => {
|
||||
this.$set(this, 'tasks', r)
|
||||
this.$set(this, 'pages', [])
|
||||
this.tasks = r
|
||||
this.currentPage = page
|
||||
|
||||
for (let i = 0; i < this.taskCollectionService.totalPages; i++) {
|
||||
|
||||
// Show ellipsis instead of all pages
|
||||
if (
|
||||
i > 0 && // Always at least the first page
|
||||
(i + 1) < this.taskCollectionService.totalPages && // And the last page
|
||||
(
|
||||
// And the current with current + 1 and current - 1
|
||||
(i + 1) > this.currentPage + 1 ||
|
||||
(i + 1) < this.currentPage - 1
|
||||
)
|
||||
) {
|
||||
// Only add an ellipsis if the last page isn't already one
|
||||
if (this.pages[i - 1] && !this.pages[i - 1].isEllipsis) {
|
||||
this.pages.push({
|
||||
number: 0,
|
||||
isEllipsis: true,
|
||||
})
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
this.pages.push({
|
||||
number: i + 1,
|
||||
isEllipsis: false,
|
||||
})
|
||||
}
|
||||
|
||||
this.loadedList = cloneDeep(currentList)
|
||||
})
|
||||
.catch(e => {
|
||||
this.error(e)
|
||||
})
|
||||
},
|
||||
|
||||
loadTasksForPage(e) {
|
||||
// The page parameter can be undefined, in the case where the user loads a new list from the side bar menu
|
||||
let page = Number(e.page)
|
||||
|
@ -177,17 +196,6 @@ export default {
|
|||
this.showTaskSearch = false
|
||||
}, 200)
|
||||
},
|
||||
getRouteForPagination(page = 1, type = 'list') {
|
||||
return {
|
||||
name: 'list.' + type,
|
||||
params: {
|
||||
type: type,
|
||||
},
|
||||
query: {
|
||||
page: page,
|
||||
},
|
||||
}
|
||||
},
|
||||
saveTaskPosition(e) {
|
||||
this.drag = false
|
||||
|
||||
|
@ -205,5 +213,6 @@ export default {
|
|||
this.error(e)
|
||||
})
|
||||
},
|
||||
getRouteForPagination,
|
||||
},
|
||||
}
|
|
@ -7,16 +7,17 @@
|
|||
<h1
|
||||
class="title input"
|
||||
:class="{'disabled': !canWrite}"
|
||||
@focusout="save()"
|
||||
@keydown.enter.prevent.stop="save()"
|
||||
@blur="save($event.target.textContent)"
|
||||
@keydown.enter.prevent.stop="$event.target.blur()"
|
||||
:contenteditable="canWrite ? 'true' : 'false'"
|
||||
spellcheck="false"
|
||||
ref="taskTitle">{{ task.title.trim() }}</h1>
|
||||
<transition name="fade">
|
||||
<span class="is-inline-flex is-align-items-center" v-if="loading && saving">
|
||||
<span class="loader is-inline-block mr-2"></span>
|
||||
{{ $t('misc.saving') }}
|
||||
</span>
|
||||
<span class="has-text-success is-inline-flex is-align-content-center" v-if="!loading && saved">
|
||||
<span class="has-text-success is-inline-flex is-align-content-center" v-if="!loading && showSavedMessage">
|
||||
<icon icon="check" class="mr-2"/>
|
||||
{{ $t('misc.saved') }}
|
||||
</span>
|
||||
|
@ -25,22 +26,22 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import {LOADING} from '@/store/mutation-types'
|
||||
import {mapState} from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'heading',
|
||||
data() {
|
||||
return {
|
||||
task: {title: '', identifier: '', index: ''},
|
||||
taskTitle: '',
|
||||
saved: false,
|
||||
showSavedMessage: false,
|
||||
saving: false, // Since loading is global state, this variable ensures we're only showing the saving icon when saving the description.
|
||||
}
|
||||
},
|
||||
computed: mapState({
|
||||
loading: LOADING,
|
||||
}),
|
||||
computed: {
|
||||
...mapState(['loading']),
|
||||
task() {
|
||||
return this.value
|
||||
},
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
required: true,
|
||||
|
@ -50,50 +51,29 @@ export default {
|
|||
default: false,
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
value(newVal) {
|
||||
this.task = newVal
|
||||
this.taskTitle = this.task.title
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.task = this.value
|
||||
this.taskTitle = this.task.title
|
||||
},
|
||||
methods: {
|
||||
save() {
|
||||
this.$refs.taskTitle.spellcheck = false
|
||||
|
||||
// Pull the task title from the contenteditable
|
||||
let taskTitle = this.$refs.taskTitle.textContent
|
||||
this.task.title = taskTitle
|
||||
|
||||
// We only want to save if the title was actually change.
|
||||
// Because the contenteditable does not have a change event,
|
||||
// we're building it ourselves and only calling saveTask()
|
||||
save(title) {
|
||||
// We only want to save if the title was actually changed.
|
||||
// Because the contenteditable does not have a change event
|
||||
// we're building it ourselves and only continue
|
||||
// if the task title changed.
|
||||
if (this.task.title !== this.taskTitle) {
|
||||
this.$refs.taskTitle.blur()
|
||||
this.saveTask()
|
||||
this.taskTitle = taskTitle
|
||||
}
|
||||
},
|
||||
saveTask() {
|
||||
// When only saving with enter, the focusout event is called as well. This then leads to the saveTask
|
||||
// method being called twice, overriding some task attributes in the second run.
|
||||
// If we simply check if we're already in the process of saving, we can prevent that.
|
||||
if (this.saving) {
|
||||
if (title === this.task.title) {
|
||||
return
|
||||
}
|
||||
|
||||
this.saving = true
|
||||
|
||||
this.$store.dispatch('tasks/update', this.task)
|
||||
.then(() => {
|
||||
this.$emit('input', this.task)
|
||||
this.saved = true
|
||||
const newTask = {
|
||||
...this.task,
|
||||
title,
|
||||
}
|
||||
|
||||
this.$store.dispatch('tasks/update', newTask)
|
||||
.then((task) => {
|
||||
this.$emit('input', task)
|
||||
this.showSavedMessage = true
|
||||
setTimeout(() => {
|
||||
this.saved = false
|
||||
this.showSavedMessage = false
|
||||
}, 2000)
|
||||
})
|
||||
.catch(e => {
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import priorites from '../../../models/priorities'
|
||||
import priorites from '../../../models/constants/priorities'
|
||||
|
||||
export default {
|
||||
name: 'priorityLabel',
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import priorites from '../../../models/priorities'
|
||||
import priorites from '../../../models/constants/priorities'
|
||||
|
||||
export default {
|
||||
name: 'prioritySelect',
|
||||
|
|
|
@ -122,7 +122,7 @@
|
|||
import TaskService from '../../../services/task'
|
||||
import TaskModel from '../../../models/task'
|
||||
import TaskRelationService from '../../../services/taskRelation'
|
||||
import relationKinds from '../../../models/relationKinds'
|
||||
import relationKinds from '../../../models/constants/relationKinds'
|
||||
import TaskRelationModel from '../../../models/taskRelation'
|
||||
|
||||
import Multiselect from '@/components/input/multiselect.vue'
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import repeatModes from '@/models/taskRepeatModes'
|
||||
import repeatModes from '@/models/constants/taskRepeatModes'
|
||||
|
||||
export default {
|
||||
name: 'repeatAfter',
|
||||
|
@ -62,7 +62,7 @@ export default {
|
|||
amount: 0,
|
||||
type: '',
|
||||
},
|
||||
repeatModes: repeatModes,
|
||||
repeatModes,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
export function findIndexById(array : [], id : string | number) {
|
||||
return array.findIndex(({id: currentId}) => currentId === id)
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"UNKNOWN": 0,
|
||||
"USER": 1,
|
||||
"LINK_SHARE": 2
|
||||
}
|
|
@ -5,7 +5,7 @@ import TaskModel from '@/models/task'
|
|||
import TaskCommentModel from '@/models/taskComment'
|
||||
import ListModel from '@/models/list'
|
||||
import TeamModel from '@/models/team'
|
||||
import names from './notificationNames.json'
|
||||
import names from './constants/notificationNames.json'
|
||||
|
||||
export default class NotificationModel extends AbstractModel {
|
||||
constructor(data) {
|
||||
|
|
|
@ -2,7 +2,7 @@ import AbstractModel from './abstractModel'
|
|||
import UserModel from './user'
|
||||
import LabelModel from './label'
|
||||
import AttachmentModel from './attachment'
|
||||
import {REPEAT_MODE_DEFAULT} from './taskRepeatModes'
|
||||
import {REPEAT_MODE_DEFAULT} from './constants/taskRepeatModes'
|
||||
|
||||
import SubscriptionModel from '@/models/subscription'
|
||||
import {parseDateOrNull} from '@/helpers/parseDateOrNull'
|
||||
|
@ -15,6 +15,7 @@ export default class TaskModel extends AbstractModel {
|
|||
super(data)
|
||||
|
||||
this.id = Number(this.id)
|
||||
this.title = this.title?.trim()
|
||||
this.listId = Number(this.listId)
|
||||
|
||||
// Make date objects from timestamps
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import {parseTaskText} from './parseTaskText'
|
||||
import {getDateFromText, getDateFromTextIn} from '../helpers/time/parseDate'
|
||||
import {calculateDayInterval} from '../helpers/time/calculateDayInterval'
|
||||
import priorities from '../models/priorities.json'
|
||||
import priorities from '../models/constants/priorities.json'
|
||||
|
||||
describe('Parse Task Text', () => {
|
||||
it('should return text with no intents as is', () => {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {parseDate} from '../helpers/time/parseDate'
|
||||
import _priorities from '../models/priorities.json'
|
||||
import _priorities from '../models/constants/priorities.json'
|
||||
|
||||
const LABEL_PREFIX: string = '@'
|
||||
const LIST_PREFIX: string = '#'
|
||||
|
|
|
@ -39,6 +39,8 @@ export default class TaskService extends AbstractService {
|
|||
|
||||
processModel(model) {
|
||||
|
||||
model.title = model.title?.trim()
|
||||
|
||||
// Ensure that listId is an int
|
||||
model.listId = Number(model.listId)
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import Vue from 'vue'
|
||||
|
||||
import {findIndexById} from '@/helpers/find'
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state: () => ({
|
||||
|
@ -15,13 +17,9 @@ export default {
|
|||
state.attachments.push(attachment)
|
||||
},
|
||||
removeById(state, id) {
|
||||
for (const a in state.attachments) {
|
||||
if (state.attachments[a].id === id) {
|
||||
state.attachments.splice(a, 1)
|
||||
console.debug('Remove attachement', id)
|
||||
break
|
||||
}
|
||||
}
|
||||
const attachmentIndex = findIndexById(state.attachments, id)
|
||||
state.attachments.splice(attachmentIndex, 1)
|
||||
console.debug('Remove attachement', id)
|
||||
},
|
||||
},
|
||||
}
|
|
@ -3,6 +3,12 @@ import {ERROR_MESSAGE, LOADING} from '../mutation-types'
|
|||
import UserModel from '../../models/user'
|
||||
import {getToken, refreshToken, removeToken, saveToken} from '@/helpers/auth'
|
||||
|
||||
const AUTH_TYPES = {
|
||||
'UNKNOWN': 0,
|
||||
'USER': 1,
|
||||
'LINK_SHARE': 2,
|
||||
}
|
||||
|
||||
const defaultSettings = settings => {
|
||||
if (typeof settings.weekStart === 'undefined' || settings.weekStart === '') {
|
||||
settings.weekStart = 0
|
||||
|
@ -21,6 +27,20 @@ export default {
|
|||
lastUserInfoRefresh: null,
|
||||
settings: {},
|
||||
}),
|
||||
getters: {
|
||||
authUser(state) {
|
||||
return state.authenticated && (
|
||||
state.info &&
|
||||
state.info.type === AUTH_TYPES.USER
|
||||
)
|
||||
},
|
||||
authLinkShare(state) {
|
||||
return state.authenticated && (
|
||||
state.info &&
|
||||
state.info.type === AUTH_TYPES.LINK_SHARE
|
||||
)
|
||||
},
|
||||
},
|
||||
mutations: {
|
||||
info(state, info) {
|
||||
state.info = info
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
@import "../../../node_modules/bulma/bulma";
|
||||
// utilities are imported in variables.scss
|
||||
@import "../../../node_modules/bulma/sass/base/_all";
|
||||
@import "../../../node_modules/bulma/sass/elements/_all";
|
||||
@import "../../../node_modules/bulma/sass/form/_all";
|
||||
@import "../../../node_modules/bulma/sass/components/_all";
|
||||
@import "../../../node_modules/bulma/sass/grid/_all";
|
||||
@import "../../../node_modules/bulma/sass/helpers/_all";
|
||||
@import "../../../node_modules/bulma/sass/layout/_all";
|
||||
|
||||
|
||||
@import "fonts";
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
@import "../../../node_modules/bulma/sass/utilities/_all";
|
||||
|
||||
@import 'colors';
|
||||
@import 'shadows';
|
||||
@import 'variables';
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable no-console */
|
||||
/* eslint-disable no-undef */
|
||||
|
||||
const workboxVersion = 'v6.2.4'
|
||||
const workboxVersion = 'v6.3.0'
|
||||
importScripts( `/workbox-${workboxVersion}/workbox-sw.js`)
|
||||
workbox.setConfig({modulePathPrefix: `/workbox-${workboxVersion}`})
|
||||
|
||||
|
|
|
@ -239,7 +239,7 @@ import BucketModel from '../../../models/bucket'
|
|||
import {filterObject} from '@/helpers/filterObject'
|
||||
import {mapState} from 'vuex'
|
||||
import {saveListView} from '@/helpers/saveListView'
|
||||
import Rights from '../../../models/rights.json'
|
||||
import Rights from '../../../models/constants/rights.json'
|
||||
import {LOADING, LOADING_MODULE} from '@/store/mutation-types'
|
||||
import FilterPopup from '@/components/list/partials/filter-popup.vue'
|
||||
import Dropdown from '@/components/misc/dropdown.vue'
|
||||
|
|
|
@ -177,7 +177,7 @@ 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 Rights from '../../../models/rights.json'
|
||||
import Rights from '../../../models/constants/rights.json'
|
||||
import FilterPopup from '@/components/list/partials/filter-popup.vue'
|
||||
import {HAS_TASKS} from '@/store/mutation-types'
|
||||
import Nothing from '@/components/misc/nothing.vue'
|
||||
|
|
|
@ -33,8 +33,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from 'vuex'
|
||||
import authTypes from '@/models/authTypes.json'
|
||||
import {mapGetters} from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'LinkSharingAuth',
|
||||
|
@ -54,9 +53,9 @@ export default {
|
|||
mounted() {
|
||||
this.setTitle(this.$t('sharing.authenticating'))
|
||||
},
|
||||
computed: mapState({
|
||||
authLinkShare: state => state.auth.authenticated && (state.auth.info && state.auth.info.type === authTypes.LINK_SHARE),
|
||||
}),
|
||||
computed: mapGetters('auth', [
|
||||
'authLinkShare',
|
||||
]),
|
||||
methods: {
|
||||
auth() {
|
||||
this.errorMessage = ''
|
||||
|
|
|
@ -419,10 +419,10 @@
|
|||
<script>
|
||||
import TaskService from '../../services/task'
|
||||
import TaskModel from '../../models/task'
|
||||
import relationKinds from '../../models/relationKinds.json'
|
||||
import relationKinds from '../../models/constants/relationKinds.json'
|
||||
|
||||
import priorites from '../../models/priorities.json'
|
||||
import rights from '../../models/rights.json'
|
||||
import priorites from '../../models/constants/priorities.json'
|
||||
import rights from '../../models/constants/rights.json'
|
||||
|
||||
import PrioritySelect from '../../components/tasks/partials/prioritySelect'
|
||||
import PercentDoneSelect from '../../components/tasks/partials/percentDoneSelect'
|
||||
|
|
|
@ -167,7 +167,7 @@ import TeamMemberService from '../../services/teamMember'
|
|||
import TeamMemberModel from '../../models/teamMember'
|
||||
import UserModel from '../../models/user'
|
||||
import UserService from '../../services/user'
|
||||
import Rights from '../../models/rights.json'
|
||||
import Rights from '../../models/constants/rights.json'
|
||||
|
||||
import LoadingComponent from '../../components/misc/loading'
|
||||
import ErrorComponent from '../../components/misc/error'
|
||||
|
|
Loading…
Reference in New Issue