Replace all spaces with tabs
continuous-integration/drone/push Build is passing Details

This commit is contained in:
kolaente 2019-11-03 13:44:40 +01:00
parent c6d7b288ce
commit e00f0046b5
Signed by: konrad
GPG Key ID: F40E70337AB24C9B
6 changed files with 691 additions and 691 deletions

View File

@ -1,182 +1,182 @@
<template>
<div>
<div v-if="isOnline">
<!-- This is a workaround to get the sw to "see" the to-be-cached version of the offline background image -->
<div class="offline" style="height: 0;width: 0;"></div>
<nav class="navbar main-theme is-fixed-top" role="navigation" aria-label="main navigation"
v-if="user.authenticated && user.infos.type === authTypes.USER">
<div class="navbar-brand">
<router-link :to="{name: 'home'}" class="navbar-item logo">
<img src="/images/logo-full.svg" alt="Vikunja"/>
</router-link>
</div>
<div class="navbar-end">
<div class="user">
<img :src="gravatar()" class="avatar" alt=""/>
<div class="dropdown is-right is-active">
<div class="dropdown-trigger">
<button class="button noshadow" @click="userMenuActive = !userMenuActive">
<span class="username">{{user.infos.username}}</span>
<span class="icon is-small">
<div>
<div v-if="isOnline">
<!-- This is a workaround to get the sw to "see" the to-be-cached version of the offline background image -->
<div class="offline" style="height: 0;width: 0;"></div>
<nav class="navbar main-theme is-fixed-top" role="navigation" aria-label="main navigation"
v-if="user.authenticated && user.infos.type === authTypes.USER">
<div class="navbar-brand">
<router-link :to="{name: 'home'}" class="navbar-item logo">
<img src="/images/logo-full.svg" alt="Vikunja"/>
</router-link>
</div>
<div class="navbar-end">
<div class="user">
<img :src="gravatar()" class="avatar" alt=""/>
<div class="dropdown is-right is-active">
<div class="dropdown-trigger">
<button class="button noshadow" @click="userMenuActive = !userMenuActive">
<span class="username">{{user.infos.username}}</span>
<span class="icon is-small">
<icon icon="chevron-down"/>
</span>
</button>
</div>
<transition name="fade">
<div class="dropdown-menu" v-if="userMenuActive">
<div class="dropdown-content">
<a @click="logout()" class="dropdown-item">
Logout
</a>
</div>
</div>
</transition>
</div>
</div>
</div>
</nav>
<div v-if="user.authenticated && user.infos.type === authTypes.USER">
<a @click="mobileMenuActive = true" class="mobilemenu-show-button" v-if="!mobileMenuActive">
<icon icon="bars"></icon>
</a>
<a @click="mobileMenuActive = false" class="mobilemenu-hide-button" v-if="mobileMenuActive">
<icon icon="times"></icon>
</a>
<div class="app-container">
<div class="namespace-container" :class="{'is-active': mobileMenuActive}">
<div class="menu top-menu">
<ul class="menu-list">
<li>
<router-link :to="{ name: 'home'}">
</button>
</div>
<transition name="fade">
<div class="dropdown-menu" v-if="userMenuActive">
<div class="dropdown-content">
<a @click="logout()" class="dropdown-item">
Logout
</a>
</div>
</div>
</transition>
</div>
</div>
</div>
</nav>
<div v-if="user.authenticated && user.infos.type === authTypes.USER">
<a @click="mobileMenuActive = true" class="mobilemenu-show-button" v-if="!mobileMenuActive">
<icon icon="bars"></icon>
</a>
<a @click="mobileMenuActive = false" class="mobilemenu-hide-button" v-if="mobileMenuActive">
<icon icon="times"></icon>
</a>
<div class="app-container">
<div class="namespace-container" :class="{'is-active': mobileMenuActive}">
<div class="menu top-menu">
<ul class="menu-list">
<li>
<router-link :to="{ name: 'home'}">
<span class="icon">
<icon icon="calendar"/>
</span>
Overview
</router-link>
</li>
<li>
<router-link :to="{ name: 'showTasksInRange', params: {type: 'month'}}">
Overview
</router-link>
</li>
<li>
<router-link :to="{ name: 'showTasksInRange', params: {type: 'month'}}">
<span class="icon">
<icon :icon="['far', 'calendar-alt']"/>
</span>
Next Month
</router-link>
</li>
<li>
<router-link :to="{ name: 'showTasksInRange', params: {type: 'week'}}">
Next Month
</router-link>
</li>
<li>
<router-link :to="{ name: 'showTasksInRange', params: {type: 'week'}}">
<span class="icon">
<icon icon="calendar-week"/>
</span>
Next Week
</router-link>
</li>
<li>
<router-link :to="{ name: 'listTeams'}">
Next Week
</router-link>
</li>
<li>
<router-link :to="{ name: 'listTeams'}">
<span class="icon">
<icon icon="users"/>
</span>
Teams
</router-link>
</li>
<li>
<router-link :to="{ name: 'newNamespace'}">
Teams
</router-link>
</li>
<li>
<router-link :to="{ name: 'newNamespace'}">
<span class="icon">
<icon icon="layer-group"/>
</span>
New Namespace
</router-link>
</li>
<li>
<router-link :to="{ name: 'listLabels'}">
New Namespace
</router-link>
</li>
<li>
<router-link :to="{ name: 'listLabels'}">
<span class="icon">
<icon icon="tags"/>
</span>
Labels
</router-link>
</li>
</ul>
</div>
<aside class="menu namespaces-lists">
<div class="spinner" :class="{ 'is-loading': namespaceService.loading}"></div>
<template v-for="n in namespaces">
<div :key="n.id">
<router-link v-tooltip.right="'Settings'"
:to="{name: 'editNamespace', params: {id: n.id} }" class="nsettings"
v-if="n.id > 0">
Labels
</router-link>
</li>
</ul>
</div>
<aside class="menu namespaces-lists">
<div class="spinner" :class="{ 'is-loading': namespaceService.loading}"></div>
<template v-for="n in namespaces">
<div :key="n.id">
<router-link v-tooltip.right="'Settings'"
:to="{name: 'editNamespace', params: {id: n.id} }" class="nsettings"
v-if="n.id > 0">
<span class="icon">
<icon icon="cog"/>
</span>
</router-link>
<router-link v-tooltip="'Add a new list in the ' + n.name + ' namespace'"
:to="{ name: 'newList', params: { id: n.id} }" class="nsettings"
:key="n.id + 'newList'" v-if="n.id > 0">
</router-link>
<router-link v-tooltip="'Add a new list in the ' + n.name + ' namespace'"
:to="{ name: 'newList', params: { id: n.id} }" class="nsettings"
:key="n.id + 'newList'" v-if="n.id > 0">
<span class="icon">
<icon icon="plus"/>
</span>
</router-link>
<label class="menu-label" v-tooltip="n.name + ' (' + n.lists.length + ')'" :for="n.id + 'checker'">
{{n.name}} ({{n.lists.length}})
</label>
</div>
<input :key="n.id + 'checker'" type="checkbox" checked="checked" :id="n.id + 'checker'" class="checkinput"/>
<div class="more-container" :key="n.id + 'child'">
<ul class="menu-list can-be-hidden" >
<li v-for="l in n.lists" :key="l.id">
<router-link :to="{ name: 'showList', params: { id: l.id} }">{{l.title}}
</router-link>
</li>
</ul>
<label class="hidden-hint" :for="n.id + 'checker'">
Show hidden lists ({{n.lists.length}})...
</label>
</div>
</template>
</aside>
</div>
<div class="app-content" :class="{'fullpage-overlay': fullpage}">
<a class="mobile-overlay" v-if="mobileMenuActive" @click="mobileMenuActive = false"></a>
<transition name="fade">
<router-view/>
</transition>
</div>
</div>
</div>
<!-- FIXME: This will only be triggered when the root component is already loaded before doing link share auth. Will "fix" itself once we use vuex. -->
<div v-else-if="user.authenticated && user.infos.type === authTypes.LINK_SHARE">
<div class="container has-text-centered link-share-view">
<div class="column is-10 is-offset-1">
<img src="/images/logo-full.svg" alt="Vikunja" class="logo"/>
<div class="box has-text-left">
<div class="logout">
<a @click="logout()" class="button logout">
<span>Logout</span>
<span class="icon is-small">
</router-link>
<label class="menu-label" v-tooltip="n.name + ' (' + n.lists.length + ')'" :for="n.id + 'checker'">
{{n.name}} ({{n.lists.length}})
</label>
</div>
<input :key="n.id + 'checker'" type="checkbox" checked="checked" :id="n.id + 'checker'" class="checkinput"/>
<div class="more-container" :key="n.id + 'child'">
<ul class="menu-list can-be-hidden" >
<li v-for="l in n.lists" :key="l.id">
<router-link :to="{ name: 'showList', params: { id: l.id} }">{{l.title}}
</router-link>
</li>
</ul>
<label class="hidden-hint" :for="n.id + 'checker'">
Show hidden lists ({{n.lists.length}})...
</label>
</div>
</template>
</aside>
</div>
<div class="app-content" :class="{'fullpage-overlay': fullpage}">
<a class="mobile-overlay" v-if="mobileMenuActive" @click="mobileMenuActive = false"></a>
<transition name="fade">
<router-view/>
</transition>
</div>
</div>
</div>
<!-- FIXME: This will only be triggered when the root component is already loaded before doing link share auth. Will "fix" itself once we use vuex. -->
<div v-else-if="user.authenticated && user.infos.type === authTypes.LINK_SHARE">
<div class="container has-text-centered link-share-view">
<div class="column is-10 is-offset-1">
<img src="/images/logo-full.svg" alt="Vikunja" class="logo"/>
<div class="box has-text-left">
<div class="logout">
<a @click="logout()" class="button logout">
<span>Logout</span>
<span class="icon is-small">
<icon icon="sign-out-alt"/>
</span>
</a>
</div>
<router-view/>
</div>
</div>
</div>
</div>
<div v-else>
<div class="container">
<div class="column is-4 is-offset-4">
<img src="/images/logo-full.svg" alt="Vikunja"/>
<router-view/>
</div>
</div>
</div>
<notifications position="bottom left"/>
</div>
<div class="app offline" v-else>
<div class="offline-message">
<h1>You are offline.</h1>
<p>Please check your network connection and try again.</p>
</div>
</div>
</div>
</a>
</div>
<router-view/>
</div>
</div>
</div>
</div>
<div v-else>
<div class="container">
<div class="column is-4 is-offset-4">
<img src="/images/logo-full.svg" alt="Vikunja"/>
<router-view/>
</div>
</div>
</div>
<notifications position="bottom left"/>
</div>
<div class="app offline" v-else>
<div class="offline-message">
<h1>You are offline.</h1>
<p>Please check your network connection and try again.</p>
</div>
</div>
</div>
</template>
<script>

View File

@ -1,195 +1,195 @@
<template>
<div class="card is-fullwidth">
<header class="card-header">
<p class="card-header-title">
Share links
</p>
</header>
<div class="card-content content sharables-list">
<form @submit.prevent="add()" class="add-form">
<div class="field is-grouped">
<div class="control">
<!-- TODO: maybe move this into a modal? -->
Add a new link share:
</div>
<div class="control">
<div class="select">
<select v-model="selectedRight" class="button buttonright">
<option :value="rights.READ">Read only</option>
<option :value="rights.READ_WRITE">Read & write</option>
<option :value="rights.ADMIN">Admin</option>
</select>
</div>
</div>
<div class="control">
<button type="submit" class="button is-success">
<span class="icon is-small">
<icon icon="plus"/>
</span>
Add
</button>
</div>
</div>
</form>
<table class="table is-striped is-hoverable is-fullwidth">
<tbody>
<tr>
<th>Link</th>
<th>Shared by</th>
<th>Right</th>
<th>Delete</th>
</tr>
<template v-if="linkShares.length > 0">
<tr v-for="s in linkShares" :key="s.id">
<td>
<div class="field has-addons">
<div class="control">
<input class="input" type="text" :value="getShareLink(s.hash)" readonly/>
</div>
<div class="control">
<a class="button is-success noshadow" @click="copy(getShareLink(s.hash))">
<span class="icon is-small">
<icon icon="paste"/>
</span>
</a>
</div>
</div>
</td>
<td>
{{ s.shared_by.username }}
</td>
<td class="type">
<template v-if="s.right === rights.ADMIN">
<span class="icon is-small">
<icon icon="lock"/>
</span>
Admin
</template>
<template v-else-if="s.right === rights.READ_WRITE">
<span class="icon is-small">
<icon icon="pen"/>
</span>
Write
</template>
<template v-else>
<span class="icon is-small">
<icon icon="users"/>
</span>
Read-only
</template>
</td>
<td class="actions">
<button @click="linkIDToDelete = s.id; showDeleteModal = true" class="button is-danger icon-only">
<span class="icon is-small">
<icon icon="trash-alt"/>
</span>
</button>
</td>
</tr>
</template>
</tbody>
</table>
</div>
<div class="card is-fullwidth">
<header class="card-header">
<p class="card-header-title">
Share links
</p>
</header>
<div class="card-content content sharables-list">
<form @submit.prevent="add()" class="add-form">
<div class="field is-grouped">
<div class="control">
<!-- TODO: maybe move this into a modal? -->
Add a new link share:
</div>
<div class="control">
<div class="select">
<select v-model="selectedRight" class="button buttonright">
<option :value="rights.READ">Read only</option>
<option :value="rights.READ_WRITE">Read & write</option>
<option :value="rights.ADMIN">Admin</option>
</select>
</div>
</div>
<div class="control">
<button type="submit" class="button is-success">
<span class="icon is-small">
<icon icon="plus"/>
</span>
Add
</button>
</div>
</div>
</form>
<table class="table is-striped is-hoverable is-fullwidth">
<tbody>
<tr>
<th>Link</th>
<th>Shared by</th>
<th>Right</th>
<th>Delete</th>
</tr>
<template v-if="linkShares.length > 0">
<tr v-for="s in linkShares" :key="s.id">
<td>
<div class="field has-addons">
<div class="control">
<input class="input" type="text" :value="getShareLink(s.hash)" readonly/>
</div>
<div class="control">
<a class="button is-success noshadow" @click="copy(getShareLink(s.hash))">
<span class="icon is-small">
<icon icon="paste"/>
</span>
</a>
</div>
</div>
</td>
<td>
{{ s.shared_by.username }}
</td>
<td class="type">
<template v-if="s.right === rights.ADMIN">
<span class="icon is-small">
<icon icon="lock"/>
</span>
Admin
</template>
<template v-else-if="s.right === rights.READ_WRITE">
<span class="icon is-small">
<icon icon="pen"/>
</span>
Write
</template>
<template v-else>
<span class="icon is-small">
<icon icon="users"/>
</span>
Read-only
</template>
</td>
<td class="actions">
<button @click="linkIDToDelete = s.id; showDeleteModal = true" class="button is-danger icon-only">
<span class="icon is-small">
<icon icon="trash-alt"/>
</span>
</button>
</td>
</tr>
</template>
</tbody>
</table>
</div>
<modal
v-if="showDeleteModal"
@close="showDeleteModal = false"
@submit="remove()">
<span slot="header">Remove a link share</span>
<p slot="text">Are you sure you want to remove this link share?<br/>
It will no longer be possible to access this list with this link share.<br/>
<b>This CANNOT BE UNDONE!</b></p>
</modal>
</div>
<modal
v-if="showDeleteModal"
@close="showDeleteModal = false"
@submit="remove()">
<span slot="header">Remove a link share</span>
<p slot="text">Are you sure you want to remove this link share?<br/>
It will no longer be possible to access this list with this link share.<br/>
<b>This CANNOT BE UNDONE!</b></p>
</modal>
</div>
</template>
<script>
import message from '../../message'
import rights from '../../models/rights'
import message from '../../message'
import rights from '../../models/rights'
import LinkShareService from '../../services/linkShare'
import LinkShareModel from '../../models/linkShare'
import LinkShareService from '../../services/linkShare'
import LinkShareModel from '../../models/linkShare'
import copy from 'copy-to-clipboard'
import copy from 'copy-to-clipboard'
export default {
name: 'linkSharing',
props: {
listID: {
default: 0,
required: true,
},
},
data() {
return {
linkShares: [],
linkShareService: LinkShareService,
newLinkShare: LinkShareModel,
rights: rights,
selectedRight: rights.READ,
showDeleteModal: false,
linkIDToDelete: 0,
}
},
beforeMount() {
this.linkShareService = new LinkShareService()
},
created() {
this.linkShareService = new LinkShareService()
this.load()
},
watch: {
listID: () => { // watch it
this.load()
}
},
methods: {
load() {
// If listID == 0 the list on the calling component wasn't already loaded, so we just bail out here
if (this.listID === 0) {
return
}
export default {
name: 'linkSharing',
props: {
listID: {
default: 0,
required: true,
},
},
data() {
return {
linkShares: [],
linkShareService: LinkShareService,
newLinkShare: LinkShareModel,
rights: rights,
selectedRight: rights.READ,
showDeleteModal: false,
linkIDToDelete: 0,
}
},
beforeMount() {
this.linkShareService = new LinkShareService()
},
created() {
this.linkShareService = new LinkShareService()
this.load()
},
watch: {
listID: () => { // watch it
this.load()
}
},
methods: {
load() {
// If listID == 0 the list on the calling component wasn't already loaded, so we just bail out here
if (this.listID === 0) {
return
}
this.linkShareService.getAll({listID: this.listID})
.then(r => {
this.linkShares = r
})
.catch(e => {
message.error(e, this)
})
},
add() {
let newLinkShare = new LinkShareModel({right: this.selectedRight, listID: this.listID})
this.linkShareService.create(newLinkShare)
.then(() => {
this.selectedRight = rights.READ
message.success({message: 'The link share was successfully created'}, this)
this.load()
})
.catch(e => {
message.error(e, this)
})
},
remove() {
let linkshare = new LinkShareModel({id: this.linkIDToDelete, listID: this.listID})
this.linkShareService.delete(linkshare)
.then(() => {
message.success({message: 'The link share was successfully deleted'}, this)
this.load()
})
.catch(e => {
message.error(e, this)
})
.finally(() => {
this.showDeleteModal = false
})
},
copy(text) {
copy(text)
},
getShareLink(hash) {
return this.$config.frontend_url + 'share/' + hash + '/auth'
},
},
}
this.linkShareService.getAll({listID: this.listID})
.then(r => {
this.linkShares = r
})
.catch(e => {
message.error(e, this)
})
},
add() {
let newLinkShare = new LinkShareModel({right: this.selectedRight, listID: this.listID})
this.linkShareService.create(newLinkShare)
.then(() => {
this.selectedRight = rights.READ
message.success({message: 'The link share was successfully created'}, this)
this.load()
})
.catch(e => {
message.error(e, this)
})
},
remove() {
let linkshare = new LinkShareModel({id: this.linkIDToDelete, listID: this.listID})
this.linkShareService.delete(linkshare)
.then(() => {
message.success({message: 'The link share was successfully deleted'}, this)
this.load()
})
.catch(e => {
message.error(e, this)
})
.finally(() => {
this.showDeleteModal = false
})
},
copy(text) {
copy(text)
},
getShareLink(hash) {
return this.$config.frontend_url + 'share/' + hash + '/auth'
},
},
}
</script>

View File

@ -1,40 +1,40 @@
<template>
<div class="message is-centered is-info" v-if="loading">
<div class="message-header">
<p class="has-text-centered">
Authenticating...
</p>
</div>
</div>
<div class="message is-centered is-info" v-if="loading">
<div class="message-header">
<p class="has-text-centered">
Authenticating...
</p>
</div>
</div>
</template>
<script>
import auth from '../../auth'
import router from '../../router'
import message from '../../message'
import auth from '../../auth'
import router from '../../router'
import message from '../../message'
export default {
name: 'linkSharingAuth',
data() {
return {
hash: '',
loading: true,
}
},
created() {
this.auth()
},
methods: {
auth() {
auth.linkShareAuth(this.$route.params.share)
.then((r) => {
this.loading = false
router.push({name: 'showList', params: {id: r.list_id}})
})
.catch(e => {
message.error(e, this)
})
}
},
}
export default {
name: 'linkSharingAuth',
data() {
return {
hash: '',
loading: true,
}
},
created() {
this.auth()
},
methods: {
auth() {
auth.linkShareAuth(this.$route.params.share)
.then((r) => {
this.loading = false
router.push({name: 'showList', params: {id: r.list_id}})
})
.catch(e => {
message.error(e, this)
})
}
},
}
</script>

View File

@ -38,7 +38,7 @@
<span class="tag" v-for="label in l.labels" :style="{'background': label.hex_color, 'color': label.textColor}" :key="label.id">
<span>{{ label.title }}</span>
</span>
<img :src="gravatar(a)" :alt="a.username" v-for="a in l.assignees" class="avatar" :key="l.id + 'assignee' + a.id"/>
<img :src="gravatar(a)" :alt="a.username" v-for="a in l.assignees" class="avatar" :key="l.id + 'assignee' + a.id"/>
<i v-if="l.dueDate > 0" :class="{'overdue': (l.dueDate <= new Date())}"> - Due on {{new Date(l.dueDate).toLocaleString()}}</i>
<span v-if="l.priority >= priorities.HIGH" class="high-priority" :class="{'not-so-high': l.priority === priorities.HIGH}">
<span class="icon">
@ -61,21 +61,21 @@
</div>
<div class="column is-4" v-if="isTaskEdit">
<div class="card taskedit">
<header class="card-header">
<p class="card-header-title">
Edit Task
</p>
<a class="card-header-icon" @click="isTaskEdit = false">
<span class="icon">
<icon icon="angle-right"/>
</span>
</a>
</header>
<div class="card-content">
<div class="content">
<edit-task :task="taskEditTask"/>
</div>
</div>
<header class="card-header">
<p class="card-header-title">
Edit Task
</p>
<a class="card-header-icon" @click="isTaskEdit = false">
<span class="icon">
<icon icon="angle-right"/>
</span>
</a>
</header>
<div class="card-content">
<div class="content">
<edit-task :task="taskEditTask"/>
</div>
</div>
</div>
</div>
</div>
@ -88,9 +88,9 @@
import ListService from '../../services/list'
import TaskService from '../../services/task'
import ListModel from '../../models/list'
import EditTask from './edit-task'
import TaskModel from '../../models/task'
import priorities from '../../models/priorities'
import EditTask from './edit-task'
import TaskModel from '../../models/task'
import priorities from '../../models/priorities'
export default {
data() {
@ -98,16 +98,16 @@
listID: this.$route.params.id,
listService: ListService,
taskService: TaskService,
list: {},
isTaskEdit: false,
list: {},
isTaskEdit: false,
taskEditTask: TaskModel,
newTaskText: '',
priorities: {},
priorities: {},
}
},
components: {
components: {
EditTask,
},
},
props: {
theList: {
type: ListModel,
@ -122,8 +122,8 @@
created() {
this.listService = new ListService()
this.taskService = new TaskService()
this.priorities = priorities
this.taskEditTask = null
this.priorities = priorities
this.taskEditTask = null
this.isTaskEdit = false
},
methods: {
@ -146,7 +146,7 @@
task.done = e.target.checked
this.taskService.update(task)
.then(() => {
this.list.sortTasks()
this.list.sortTasks()
message.success({message: 'The task was successfully ' + (task.done ? '' : 'un-') + 'marked as done.'}, this)
})
.catch(e => {
@ -163,7 +163,7 @@
editTask(id) {
// Find the selected task and set it to the current object
let theTask = this.list.getTaskByID(id) // Somehow this does not work if we directly assign this to this.taskEditTask
this.taskEditTask = theTask
this.taskEditTask = theTask
this.isTaskEdit = true
},
gravatar(user) {

View File

@ -1,296 +1,296 @@
<template>
<form @submit.prevent="editTaskSubmit()">
<div class="field">
<label class="label" for="tasktext">Task Text</label>
<div class="control">
<input v-focus :class="{ 'disabled': taskService.loading}" :disabled="taskService.loading" class="input"
type="text" id="tasktext" placeholder="The task text is here..." v-model="taskEditTask.text">
</div>
</div>
<div class="field">
<label class="label" for="taskdescription">Description</label>
<div class="control">
<textarea :class="{ 'disabled': taskService.loading}" :disabled="taskService.loading" class="textarea"
placeholder="The tasks description goes here..." id="taskdescription"
v-model="taskEditTask.description"></textarea>
</div>
</div>
<form @submit.prevent="editTaskSubmit()">
<div class="field">
<label class="label" for="tasktext">Task Text</label>
<div class="control">
<input v-focus :class="{ 'disabled': taskService.loading}" :disabled="taskService.loading" class="input"
type="text" id="tasktext" placeholder="The task text is here..." v-model="taskEditTask.text">
</div>
</div>
<div class="field">
<label class="label" for="taskdescription">Description</label>
<div class="control">
<textarea :class="{ 'disabled': taskService.loading}" :disabled="taskService.loading" class="textarea"
placeholder="The tasks description goes here..." id="taskdescription"
v-model="taskEditTask.description"></textarea>
</div>
</div>
<b>Reminder Dates</b>
<div class="reminder-input"
:class="{ 'overdue': (r < nowUnix && index !== (taskEditTask.reminderDates.length - 1))}"
v-for="(r, index) in taskEditTask.reminderDates" :key="index">
<flat-pickr
:class="{ 'disabled': taskService.loading}"
:disabled="taskService.loading"
:v-model="taskEditTask.reminderDates"
:config="flatPickerConfig"
:id="'taskreminderdate' + index"
:value="r"
:data-index="index"
placeholder="Add a new reminder...">
</flat-pickr>
<a v-if="index !== (taskEditTask.reminderDates.length - 1)" @click="removeReminderByIndex(index)">
<icon icon="times"></icon>
</a>
</div>
<b>Reminder Dates</b>
<div class="reminder-input"
:class="{ 'overdue': (r < nowUnix && index !== (taskEditTask.reminderDates.length - 1))}"
v-for="(r, index) in taskEditTask.reminderDates" :key="index">
<flat-pickr
:class="{ 'disabled': taskService.loading}"
:disabled="taskService.loading"
:v-model="taskEditTask.reminderDates"
:config="flatPickerConfig"
:id="'taskreminderdate' + index"
:value="r"
:data-index="index"
placeholder="Add a new reminder...">
</flat-pickr>
<a v-if="index !== (taskEditTask.reminderDates.length - 1)" @click="removeReminderByIndex(index)">
<icon icon="times"></icon>
</a>
</div>
<div class="field">
<label class="label" for="taskduedate">Due Date</label>
<div class="control">
<flat-pickr
:class="{ 'disabled': taskService.loading}"
class="input"
:disabled="taskService.loading"
v-model="taskEditTask.dueDate"
:config="flatPickerConfig"
id="taskduedate"
placeholder="The tasks due date is here...">
</flat-pickr>
</div>
</div>
<div class="field">
<label class="label" for="taskduedate">Due Date</label>
<div class="control">
<flat-pickr
:class="{ 'disabled': taskService.loading}"
class="input"
:disabled="taskService.loading"
v-model="taskEditTask.dueDate"
:config="flatPickerConfig"
id="taskduedate"
placeholder="The tasks due date is here...">
</flat-pickr>
</div>
</div>
<div class="field">
<label class="label" for="">Duration</label>
<div class="control columns">
<div class="column">
<flat-pickr
:class="{ 'disabled': taskService.loading}"
class="input"
:disabled="taskService.loading"
v-model="taskEditTask.startDate"
:config="flatPickerConfig"
id="taskduedate"
placeholder="Start date">
</flat-pickr>
</div>
<div class="column">
<flat-pickr
:class="{ 'disabled': taskService.loading}"
class="input"
:disabled="taskService.loading"
v-model="taskEditTask.endDate"
:config="flatPickerConfig"
id="taskduedate"
placeholder="End date">
</flat-pickr>
</div>
</div>
</div>
<div class="field">
<label class="label" for="">Duration</label>
<div class="control columns">
<div class="column">
<flat-pickr
:class="{ 'disabled': taskService.loading}"
class="input"
:disabled="taskService.loading"
v-model="taskEditTask.startDate"
:config="flatPickerConfig"
id="taskduedate"
placeholder="Start date">
</flat-pickr>
</div>
<div class="column">
<flat-pickr
:class="{ 'disabled': taskService.loading}"
class="input"
:disabled="taskService.loading"
v-model="taskEditTask.endDate"
:config="flatPickerConfig"
id="taskduedate"
placeholder="End date">
</flat-pickr>
</div>
</div>
</div>
<div class="field">
<label class="label" for="">Repeat after</label>
<div class="control repeat-after-input columns">
<div class="column">
<input class="input" placeholder="Specify an amount..." v-model="taskEditTask.repeatAfter.amount"/>
</div>
<div class="column is-3">
<div class="select">
<select v-model="taskEditTask.repeatAfter.type">
<option value="hours">Hours</option>
<option value="days">Days</option>
<option value="weeks">Weeks</option>
<option value="months">Months</option>
<option value="years">Years</option>
</select>
</div>
</div>
</div>
</div>
<div class="field">
<label class="label" for="">Repeat after</label>
<div class="control repeat-after-input columns">
<div class="column">
<input class="input" placeholder="Specify an amount..." v-model="taskEditTask.repeatAfter.amount"/>
</div>
<div class="column is-3">
<div class="select">
<select v-model="taskEditTask.repeatAfter.type">
<option value="hours">Hours</option>
<option value="days">Days</option>
<option value="weeks">Weeks</option>
<option value="months">Months</option>
<option value="years">Years</option>
</select>
</div>
</div>
</div>
</div>
<div class="field">
<label class="label" for="">Priority</label>
<div class="control priority-select">
<div class="select">
<select v-model="taskEditTask.priority">
<option :value="priorities.UNSET">Unset</option>
<option :value="priorities.LOW">Low</option>
<option :value="priorities.MEDIUM">Medium</option>
<option :value="priorities.HIGH">High</option>
<option :value="priorities.URGENT">Urgent</option>
<option :value="priorities.DO_NOW">DO NOW</option>
</select>
</div>
</div>
</div>
<div class="field">
<label class="label" for="">Priority</label>
<div class="control priority-select">
<div class="select">
<select v-model="taskEditTask.priority">
<option :value="priorities.UNSET">Unset</option>
<option :value="priorities.LOW">Low</option>
<option :value="priorities.MEDIUM">Medium</option>
<option :value="priorities.HIGH">High</option>
<option :value="priorities.URGENT">Urgent</option>
<option :value="priorities.DO_NOW">DO NOW</option>
</select>
</div>
</div>
</div>
<div class="field">
<label class="label">Percent Done</label>
<div class="control">
<div class="select">
<select v-model.number="taskEditTask.percentDone">
<option value="0">0%</option>
<option value="0.1">10%</option>
<option value="0.2">20%</option>
<option value="0.3">30%</option>
<option value="0.4">40%</option>
<option value="0.5">50%</option>
<option value="0.6">60%</option>
<option value="0.7">70%</option>
<option value="0.8">80%</option>
<option value="0.9">90%</option>
<option value="1">100%</option>
</select>
</div>
</div>
</div>
<div class="field">
<label class="label">Percent Done</label>
<div class="control">
<div class="select">
<select v-model.number="taskEditTask.percentDone">
<option value="0">0%</option>
<option value="0.1">10%</option>
<option value="0.2">20%</option>
<option value="0.3">30%</option>
<option value="0.4">40%</option>
<option value="0.5">50%</option>
<option value="0.6">60%</option>
<option value="0.7">70%</option>
<option value="0.8">80%</option>
<option value="0.9">90%</option>
<option value="1">100%</option>
</select>
</div>
</div>
</div>
<div class="field">
<label class="label">Color</label>
<div class="control">
<verte
v-model="taskEditTask.hexColor"
menuPosition="top"
picker="square"
model="hex"
:enableAlpha="false"
:rgbSliders="true">
</verte>
</div>
</div>
<div class="field">
<label class="label">Color</label>
<div class="control">
<verte
v-model="taskEditTask.hexColor"
menuPosition="top"
picker="square"
model="hex"
:enableAlpha="false"
:rgbSliders="true">
</verte>
</div>
</div>
<div class="field">
<label class="label" for="">Assignees</label>
<ul class="assingees">
<li v-for="(a, index) in taskEditTask.assignees" :key="a.id">
{{a.username}}
<a @click="deleteAssigneeByIndex(index)">
<icon icon="times"/>
</a>
</li>
</ul>
</div>
<div class="field">
<label class="label" for="">Assignees</label>
<ul class="assingees">
<li v-for="(a, index) in taskEditTask.assignees" :key="a.id">
{{a.username}}
<a @click="deleteAssigneeByIndex(index)">
<icon icon="times"/>
</a>
</li>
</ul>
</div>
<div class="field has-addons">
<div class="control is-expanded">
<multiselect
v-model="newAssignee"
:options="foundUsers"
:multiple="false"
:searchable="true"
:loading="listUserService.loading"
:internal-search="true"
@search-change="findUser"
placeholder="Type to search"
label="username"
track-by="id">
<template slot="clear" slot-scope="props">
<div class="multiselect__clear" v-if="newAssignee !== null && newAssignee.id !== 0"
@mousedown.prevent.stop="clearAllFoundUsers(props.search)"></div>
</template>
<span slot="noResult">Oops! No user found. Consider changing the search query.</span>
</multiselect>
</div>
<div class="control">
<a @click="addAssignee" class="button is-primary fullheight">
<span class="icon is-small">
<icon icon="plus"/>
</span>
</a>
</div>
</div>
<div class="field has-addons">
<div class="control is-expanded">
<multiselect
v-model="newAssignee"
:options="foundUsers"
:multiple="false"
:searchable="true"
:loading="listUserService.loading"
:internal-search="true"
@search-change="findUser"
placeholder="Type to search"
label="username"
track-by="id">
<template slot="clear" slot-scope="props">
<div class="multiselect__clear" v-if="newAssignee !== null && newAssignee.id !== 0"
@mousedown.prevent.stop="clearAllFoundUsers(props.search)"></div>
</template>
<span slot="noResult">Oops! No user found. Consider changing the search query.</span>
</multiselect>
</div>
<div class="control">
<a @click="addAssignee" class="button is-primary fullheight">
<span class="icon is-small">
<icon icon="plus"/>
</span>
</a>
</div>
</div>
<div class="field">
<label class="label">Labels</label>
<div class="control">
<multiselect
:multiple="true"
:close-on-select="false"
:clear-on-select="true"
:options-limit="300"
:hide-selected="true"
v-model="taskEditTask.labels"
:options="foundLabels"
:searchable="true"
:loading="labelService.loading || labelTaskService.loading"
:internal-search="true"
@search-change="findLabel"
@select="addLabel"
placeholder="Type to search"
label="title"
track-by="id"
:taggable="true"
@tag="createAndAddLabel"
tag-placeholder="Add this as new label"
>
<template slot="tag" slot-scope="{ option, remove }">
<span class="tag"
:style="{'background': option.hex_color, 'color': option.textColor}">
<span>{{ option.title }}</span>
<a class="delete is-small" @click="removeLabel(option)"></a>
</span>
</template>
<template slot="clear" slot-scope="props">
<div class="multiselect__clear" v-if="taskEditTask.labels.length"
@mousedown.prevent.stop="clearAllLabels(props.search)"></div>
</template>
</multiselect>
</div>
</div>
<div class="field">
<label class="label">Labels</label>
<div class="control">
<multiselect
:multiple="true"
:close-on-select="false"
:clear-on-select="true"
:options-limit="300"
:hide-selected="true"
v-model="taskEditTask.labels"
:options="foundLabels"
:searchable="true"
:loading="labelService.loading || labelTaskService.loading"
:internal-search="true"
@search-change="findLabel"
@select="addLabel"
placeholder="Type to search"
label="title"
track-by="id"
:taggable="true"
@tag="createAndAddLabel"
tag-placeholder="Add this as new label"
>
<template slot="tag" slot-scope="{ option, remove }">
<span class="tag"
:style="{'background': option.hex_color, 'color': option.textColor}">
<span>{{ option.title }}</span>
<a class="delete is-small" @click="removeLabel(option)"></a>
</span>
</template>
<template slot="clear" slot-scope="props">
<div class="multiselect__clear" v-if="taskEditTask.labels.length"
@mousedown.prevent.stop="clearAllLabels(props.search)"></div>
</template>
</multiselect>
</div>
</div>
<div class="field" v-for="(rts, kind ) in task.related_tasks" :key="kind" v-if="rts.length > 0">
<label class="label">{{ relationKinds[kind] }}</label>
<div class="tasks noborder">
<div class="task" v-for="t in rts" :key="t.id">
<label>
<span class="tasktext" :class="{ 'done': t.done}">
{{t.text}}
</span>
</label>
<a class="remove" @click="removeTaskRelation({relation_kind: kind, other_task_id: t.id})">
<icon icon="trash-alt"/>
</a>
</div>
</div>
<div class="field" v-for="(rts, kind ) in task.related_tasks" :key="kind" v-if="rts.length > 0">
<label class="label">{{ relationKinds[kind] }}</label>
<div class="tasks noborder">
<div class="task" v-for="t in rts" :key="t.id">
<label>
<span class="tasktext" :class="{ 'done': t.done}">
{{t.text}}
</span>
</label>
<a class="remove" @click="removeTaskRelation({relation_kind: kind, other_task_id: t.id})">
<icon icon="trash-alt"/>
</a>
</div>
</div>
</div>
</div>
<div class="field">
<label class="label">New Task Relation</label>
<div class="field">
<div class="control is-expanded">
<multiselect
v-model="newTaskRelationTask"
:options="foundTasks"
:multiple="false"
:searchable="true"
:loading="taskService.loading"
:internal-search="true"
@search-change="findTasks"
placeholder="Type to search"
label="text"
track-by="id">
<template slot="clear" slot-scope="props">
<div class="multiselect__clear"
v-if="newTaskRelationTask !== null && newTaskRelationTask.id !== 0"
@mousedown.prevent.stop="clearAllFoundTasks(props.search)"></div>
</template>
<span slot="noResult">No task found. Consider changing the search query.</span>
</multiselect>
</div>
</div>
<div class="field has-addons">
<div class="control is-expanded">
<div class="select is-fullwidth">
<select v-model="newTaskRelationKind">
<option value="unset">Select a kind of relation</option>
<option v-for="(label, rk) in relationKinds" :key="rk" :value="rk">
{{ label }}
</option>
</select>
</div>
</div>
<div class="control">
<a class="button is-primary" @click="addTaskRelation()">Add task Relation</a>
</div>
</div>
</div>
<div class="field">
<label class="label">New Task Relation</label>
<div class="field">
<div class="control is-expanded">
<multiselect
v-model="newTaskRelationTask"
:options="foundTasks"
:multiple="false"
:searchable="true"
:loading="taskService.loading"
:internal-search="true"
@search-change="findTasks"
placeholder="Type to search"
label="text"
track-by="id">
<template slot="clear" slot-scope="props">
<div class="multiselect__clear"
v-if="newTaskRelationTask !== null && newTaskRelationTask.id !== 0"
@mousedown.prevent.stop="clearAllFoundTasks(props.search)"></div>
</template>
<span slot="noResult">No task found. Consider changing the search query.</span>
</multiselect>
</div>
</div>
<div class="field has-addons">
<div class="control is-expanded">
<div class="select is-fullwidth">
<select v-model="newTaskRelationKind">
<option value="unset">Select a kind of relation</option>
<option v-for="(label, rk) in relationKinds" :key="rk" :value="rk">
{{ label }}
</option>
</select>
</div>
</div>
<div class="control">
<a class="button is-primary" @click="addTaskRelation()">Add task Relation</a>
</div>
</div>
</div>
<button type="submit" class="button is-success is-fullwidth" :class="{ 'is-loading': taskService.loading}">
Save
</button>
<button type="submit" class="button is-success is-fullwidth" :class="{ 'is-loading': taskService.loading}">
Save
</button>
</form>
</form>
</template>
<script>
@ -573,7 +573,7 @@
</script>
<style scoped>
form {
margin-bottom: 1em;
}
form {
margin-bottom: 1em;
}
</style>

View File

@ -29,8 +29,8 @@
<VueDragResize
class="task"
:class="{'done': t.done, 'is-current-edit': taskToEdit !== null && taskToEdit.id === t.id, 'has-light-text': !t.hasDarkColor(), 'has-dark-text': t.hasDarkColor()}"
:style="{'border-color': t.hexColor, 'background-color': t.hexColor}"
:isActive="true"
:style="{'border-color': t.hexColor, 'background-color': t.hexColor}"
:isActive="true"
:x="t.offsetDays * dayWidth - 6"
:y="0"
:w="t.durationDays * dayWidth"
@ -46,11 +46,11 @@
@dragstop="resizeTask"
@clicked="taskDragged = t"
>
<span :class="{
'has-high-priority': t.priority >= priorities.HIGH,
'has-not-so-high-priority': t.priority === priorities.HIGH,
'has-super-high-priority': t.priority === priorities.DO_NOW
}">{{t.text}}</span>
<span :class="{
'has-high-priority': t.priority >= priorities.HIGH,
'has-not-so-high-priority': t.priority === priorities.HIGH,
'has-super-high-priority': t.priority === priorities.DO_NOW
}">{{t.text}}</span>
<span v-if="t.priority >= priorities.HIGH" class="high-priority" :class="{'not-so-high': t.priority === priorities.HIGH}">
<span class="icon">
<icon icon="exclamation"/>
@ -63,10 +63,10 @@
</span>
</span>
<!-- using the key here forces vue to use the updated version model and not the response returned by the api -->
<a @click="editTask(theTasks[k])" class="edit-toggle">
<icon icon="pen"/>
</a>
</VueDragResize>
<a @click="editTask(theTasks[k])" class="edit-toggle">
<icon icon="pen"/>
</a>
</VueDragResize>
</div>
<template v-if="showTaskswithoutDates">
<div class="row" v-for="(t, k) in tasksWithoutDates" :key="t.id" :style="{background: 'repeating-linear-gradient(90deg, #ededed, #ededed 1px, ' + (k % 2 === 0 ? '#fafafa 1px, #fafafa ' : '#fff 1px, #fff ') + dayWidth + 'px)'}">
@ -183,7 +183,7 @@
fullWidth: 0,
now: null,
dayOffsetUntilToday: 0,
isTaskEdit: false,
isTaskEdit: false,
taskToEdit: null,
newTaskTitle: '',
newTaskFieldActive: false,
@ -312,10 +312,10 @@
})
}, 100)
},
editTask(task) {
editTask(task) {
this.taskToEdit = task
this.isTaskEdit = true
},
},
showCreateNewTask() {
if(!this.newTaskFieldActive) {
// Timeout to not send the form if the field isn't even shown