Create a new component for cards
continuous-integration/drone/pr Build is failing Details

This commit is contained in:
kolaente 2021-01-17 18:38:07 +01:00
parent d3641977ef
commit 7cce07dd71
Signed by: konrad
GPG Key ID: F40E70337AB24C9B
18 changed files with 1030 additions and 1152 deletions

View File

@ -1,70 +1,65 @@
<template>
<div
<card
:class="{ 'is-loading': backgroundService.loading}"
class="card list-background-setting loader-container"
v-if="uploadBackgroundEnabled || unsplashBackgroundEnabled">
<header class="card-header">
<p class="card-header-title">
Set list background
</p>
</header>
<div class="card-content">
<div class="content" v-if="uploadBackgroundEnabled">
<input
@change="uploadBackground"
accept="image/*"
class="is-hidden"
ref="backgroundUploadInput"
type="file"
/>
<x-button
:loading="backgroundUploadService.loading"
@click="$refs.backgroundUploadInput.click()"
type="primary"
>
Choose a background from your pc
</x-button>
</div>
<div class="content" v-if="unsplashBackgroundEnabled">
<input
:class="{'is-loading': backgroundService.loading}"
@keyup="() => newBackgroundSearch()"
class="input is-expanded"
placeholder="Search for a background..."
type="text"
v-model="backgroundSearchTerm"
/>
<p class="unsplash-link"><a href="https://unsplash.com" target="_blank">Powered by Unsplash</a></p>
<div class="image-search-result">
<a
:key="im.id"
:style="{'background-image': `url(${backgroundThumbs[im.id]})`}"
@click="() => setBackground(im.id)"
class="image"
v-for="im in backgroundSearchResult">
<a :href="`https://unsplash.com/@${im.info.author}`" target="_blank" class="info">
{{ im.info.authorName }}
</a>
</a>
</div>
<x-button
:disabled="backgroundService.loading"
@click="() => searchBackgrounds(currentPage + 1)"
class="is-load-more-button mt-4"
:shadow="false"
type="secondary"
v-if="backgroundSearchResult.length > 0"
>
<template v-if="backgroundService.loading">
Loading...
</template>
<template v-else>
Load more photos
</template>
</x-button>
</div>
class="list-background-setting loader-container"
v-if="uploadBackgroundEnabled || unsplashBackgroundEnabled"
title="Set list background"
>
<div class="mb-4" v-if="uploadBackgroundEnabled">
<input
@change="uploadBackground"
accept="image/*"
class="is-hidden"
ref="backgroundUploadInput"
type="file"
/>
<x-button
:loading="backgroundUploadService.loading"
@click="$refs.backgroundUploadInput.click()"
type="primary"
>
Choose a background from your pc
</x-button>
</div>
</div>
<template v-if="unsplashBackgroundEnabled">
<input
:class="{'is-loading': backgroundService.loading}"
@keyup="() => newBackgroundSearch()"
class="input is-expanded"
placeholder="Search for a background..."
type="text"
v-model="backgroundSearchTerm"
/>
<p class="unsplash-link"><a href="https://unsplash.com" target="_blank">Powered by Unsplash</a></p>
<div class="image-search-result">
<a
:key="im.id"
:style="{'background-image': `url(${backgroundThumbs[im.id]})`}"
@click="() => setBackground(im.id)"
class="image"
v-for="im in backgroundSearchResult">
<a :href="`https://unsplash.com/@${im.info.author}`" target="_blank" class="info">
{{ im.info.authorName }}
</a>
</a>
</div>
<x-button
:disabled="backgroundService.loading"
@click="() => searchBackgrounds(currentPage + 1)"
class="is-load-more-button mt-4"
:shadow="false"
type="secondary"
v-if="backgroundSearchResult.length > 0"
>
<template v-if="backgroundService.loading">
Loading...
</template>
<template v-else>
Load more photos
</template>
</x-button>
</template>
</card>
</template>
<script>

View File

@ -1,182 +1,180 @@
<template>
<div class="card filters has-overflow">
<div class="card-content">
<fancycheckbox v-model="params.filter_include_nulls">
Include Tasks which don't have a value set
</fancycheckbox>
<fancycheckbox
v-model="filters.requireAllFilters"
@change="setFilterConcat()"
>
Require all filters to be true for a task to show up
</fancycheckbox>
<div class="field">
<label class="label">Show Done Tasks</label>
<div class="control">
<fancycheckbox @change="setDoneFilter" v-model="filters.done">
Show Done Tasks
</fancycheckbox>
</div>
<card class="filters has-overflow">
<fancycheckbox v-model="params.filter_include_nulls">
Include Tasks which don't have a value set
</fancycheckbox>
<fancycheckbox
v-model="filters.requireAllFilters"
@change="setFilterConcat()"
>
Require all filters to be true for a task to show up
</fancycheckbox>
<div class="field">
<label class="label">Show Done Tasks</label>
<div class="control">
<fancycheckbox @change="setDoneFilter" v-model="filters.done">
Show Done Tasks
</fancycheckbox>
</div>
<div class="field">
<label class="label">Priority</label>
<div class="control single-value-control">
<priority-select
:disabled="!filters.usePriority"
v-model.number="filters.priority"
@change="setPriority"
/>
<fancycheckbox
v-model="filters.usePriority"
@change="setPriority"
>
Enable Filter By Priority
</fancycheckbox>
</div>
</div>
<div class="field">
<label class="label">Priority</label>
<div class="control single-value-control">
<priority-select
:disabled="!filters.usePriority"
v-model.number="filters.priority"
@change="setPriority"
/>
<fancycheckbox
v-model="filters.usePriority"
@change="setPriority"
>
Enable Filter By Priority
</fancycheckbox>
</div>
<div class="field">
<label class="label">Percent Done</label>
<div class="control single-value-control">
<percent-done-select
v-model.number="filters.percentDone"
@change="setPercentDoneFilter"
:disabled="!filters.usePercentDone"
/>
<fancycheckbox
v-model="filters.usePercentDone"
@change="setPercentDoneFilter"
>
Enable Filter By Percent Done
</fancycheckbox>
</div>
</div>
<div class="field">
<label class="label">Percent Done</label>
<div class="control single-value-control">
<percent-done-select
v-model.number="filters.percentDone"
@change="setPercentDoneFilter"
:disabled="!filters.usePercentDone"
/>
<fancycheckbox
v-model="filters.usePercentDone"
@change="setPercentDoneFilter"
>
Enable Filter By Percent Done
</fancycheckbox>
</div>
<div class="field">
<label class="label">Due Date</label>
<div class="control">
<flat-pickr
:config="flatPickerConfig"
@on-close="setDueDateFilter"
class="input"
placeholder="Due Date Range"
v-model="filters.dueDate"
/>
</div>
</div>
<div class="field">
<label class="label">Due Date</label>
<div class="control">
<flat-pickr
:config="flatPickerConfig"
@on-close="setDueDateFilter"
class="input"
placeholder="Due Date Range"
v-model="filters.dueDate"
/>
</div>
<div class="field">
<label class="label">Start Date</label>
<div class="control">
<flat-pickr
:config="flatPickerConfig"
@on-close="setStartDateFilter"
class="input"
placeholder="Start Date Range"
v-model="filters.startDate"
/>
</div>
</div>
<div class="field">
<label class="label">Start Date</label>
<div class="control">
<flat-pickr
:config="flatPickerConfig"
@on-close="setStartDateFilter"
class="input"
placeholder="Start Date Range"
v-model="filters.startDate"
/>
</div>
<div class="field">
<label class="label">End Date</label>
<div class="control">
<flat-pickr
:config="flatPickerConfig"
@on-close="setEndDateFilter"
class="input"
placeholder="End Date Range"
v-model="filters.endDate"
/>
</div>
</div>
<div class="field">
<label class="label">End Date</label>
<div class="control">
<flat-pickr
:config="flatPickerConfig"
@on-close="setEndDateFilter"
class="input"
placeholder="End Date Range"
v-model="filters.endDate"
/>
</div>
<div class="field">
<label class="label">Reminders</label>
<div class="control">
<flat-pickr
:config="flatPickerConfig"
@on-close="setReminderFilter"
class="input"
placeholder="Reminder Date Range"
v-model="filters.reminders"
/>
</div>
</div>
<div class="field">
<label class="label">Reminders</label>
<div class="control">
<flat-pickr
:config="flatPickerConfig"
@on-close="setReminderFilter"
class="input"
placeholder="Reminder Date Range"
v-model="filters.reminders"
/>
</div>
</div>
<div class="field">
<label class="label">Assignees</label>
<div class="control">
<multiselect
:loading="usersService.loading"
placeholder="Type to search for a user..."
@search="query => find('users', query)"
:search-results="foundusers"
@select="() => add('users', 'assignees')"
label="username"
:multiple="true"
@remove="() => remove('users', 'assignees')"
v-model="users"
/>
</div>
<div class="field">
<label class="label">Assignees</label>
<div class="control">
<multiselect
:loading="usersService.loading"
placeholder="Type to search for a user..."
@search="query => find('users', query)"
:search-results="foundusers"
@select="() => add('users', 'assignees')"
label="username"
:multiple="true"
@remove="() => remove('users', 'assignees')"
v-model="users"
/>
</div>
</div>
<div class="field">
<label class="label">Labels</label>
<div class="control">
<multiselect
:loading="labelService.loading"
placeholder="Type to search for a label..."
@search="findLabels"
:search-results="foundLabels"
@select="label => addLabel(label)"
label="title"
:multiple="true"
v-model="labels"
>
<template v-slot:tag="props">
<div class="field">
<label class="label">Labels</label>
<div class="control">
<multiselect
:loading="labelService.loading"
placeholder="Type to search for a label..."
@search="findLabels"
:search-results="foundLabels"
@select="label => addLabel(label)"
label="title"
:multiple="true"
v-model="labels"
>
<template v-slot:tag="props">
<span
:style="{'background': props.item.hexColor, 'color': props.item.textColor}"
class="tag ml-2 mt-2">
<span>{{ props.item.title }}</span>
<a @click="removeLabel(props.item)" class="delete is-small"></a>
</span>
</template>
</multiselect>
</template>
</multiselect>
</div>
</div>
<template v-if="$route.name === 'filters.create' || $route.name === 'list.edit'">
<div class="field">
<label class="label">Lists</label>
<div class="control">
<multiselect
:loading="listsService.loading"
placeholder="Type to search for a list..."
@search="query => find('lists', query)"
:search-results="foundlists"
@select="() => add('lists', 'list_id')"
label="title"
@remove="() => remove('lists', 'list_id')"
:multiple="true"
v-model="lists"
/>
</div>
</div>
<template v-if="$route.name === 'filters.create' || $route.name === 'list.edit'">
<div class="field">
<label class="label">Lists</label>
<div class="control">
<multiselect
:loading="listsService.loading"
placeholder="Type to search for a list..."
@search="query => find('lists', query)"
:search-results="foundlists"
@select="() => add('lists', 'list_id')"
label="title"
@remove="() => remove('lists', 'list_id')"
:multiple="true"
v-model="lists"
/>
</div>
<div class="field">
<label class="label">Namespaces</label>
<div class="control">
<multiselect
:loading="namespaceService.loading"
placeholder="Type to search for a namespace..."
@search="query => find('namespace', query)"
:search-results="foundnamespace"
@select="() => add('namespace', 'namespace')"
label="title"
@remove="() => remove('namespace', 'namespace')"
:multiple="true"
v-model="namespace"
/>
</div>
<div class="field">
<label class="label">Namespaces</label>
<div class="control">
<multiselect
:loading="namespaceService.loading"
placeholder="Type to search for a namespace..."
@search="query => find('namespace', query)"
:search-results="foundnamespace"
@select="() => add('namespace', 'namespace')"
label="title"
@remove="() => remove('namespace', 'namespace')"
:multiple="true"
v-model="namespace"
/>
</div>
</div>
</template>
</div>
</div>
</div>
</template>
</card>
</template>
<script>

View File

@ -0,0 +1,39 @@
<template>
<div class="card">
<header class="card-header" v-if="title !== ''">
<p class="card-header-title">
{{ title }}
</p>
<a @click="$emit('close')" class="card-header-icon" v-if="hasClose">
<span class="icon">
<icon icon="angle-right"/>
</span>
</a>
</header>
<div class="card-content" :class="{'p-0': !padding}">
<div class="content">
<slot></slot>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'card',
props: {
title: {
type: String,
default: '',
},
padding: {
type: Boolean,
default: true,
},
hasClose: {
type: Boolean,
default: false,
},
},
}
</script>

View File

@ -2,71 +2,68 @@
<div class="modal-mask keyboard-shortcuts-modal">
<div @click.self="close()" class="modal-container">
<div class="modal-content">
<div class="card has-background-white has-no-shadow">
<header class="card-header">
<p class="card-header-title">Available Keyboard Shortcuts</p>
</header>
<div class="card-content content">
<p>
<strong>Toggle The Menu</strong>
<span class="shortcuts">
<card class="has-background-white has-no-shadow" title="Available Keyboard Shortcuts">
<p>
<strong>Toggle The Menu</strong>
<span class="shortcuts">
<span>ctrl</span>
<i>+</i>
<span>e</span>
</span>
</p>
<h3>Kanban</h3>
<div class="message is-primary" v-if="$route.name === 'list.kanban'">
<div class="message-body">
These shortcuts work on the current page.
</div>
</p>
<h3>Kanban</h3>
<div class="message is-primary" v-if="$route.name === 'list.kanban'">
<div class="message-body">
These shortcuts work on the current page.
</div>
<p>
<strong>Mark a task as done</strong>
<span class="shortcuts">
</div>
<p>
<strong>Mark a task as done</strong>
<span class="shortcuts">
<span>ctrl</span>
<i>+</i>
<span>click</span>
</span>
</p>
<h3>Task Page</h3>
<div class="message is-primary" v-if="$route.name === 'task.detail' || $route.name === 'task.list.detail' || $route.name === 'task.gantt.detail' || $route.name === 'task.kanban.detail' || $route.name === 'task.detail'">
<div class="message-body">
These shortcuts work on the current page.
</div>
</p>
<h3>Task Page</h3>
<div
class="message is-primary"
v-if="$route.name === 'task.detail' || $route.name === 'task.list.detail' || $route.name === 'task.gantt.detail' || $route.name === 'task.kanban.detail' || $route.name === 'task.detail'">
<div class="message-body">
These shortcuts work on the current page.
</div>
<p>
<strong>Assign this task to a user</strong>
<span class="shortcuts">
</div>
<p>
<strong>Assign this task to a user</strong>
<span class="shortcuts">
<span>a</span>
</span>
</p>
<p>
<strong>Add labels to this task</strong>
<span class="shortcuts">
</p>
<p>
<strong>Add labels to this task</strong>
<span class="shortcuts">
<span>l</span>
</span>
</p>
<p>
<strong>Change the due date of this task</strong>
<span class="shortcuts">
</p>
<p>
<strong>Change the due date of this task</strong>
<span class="shortcuts">
<span>d</span>
</span>
</p>
<p>
<strong>Add an attachment to this task</strong>
<span class="shortcuts">
</p>
<p>
<strong>Add an attachment to this task</strong>
<span class="shortcuts">
<span>f</span>
</span>
</p>
<p>
<strong>Modify related tasks of this task</strong>
<span class="shortcuts">
</p>
<p>
<strong>Modify related tasks of this task</strong>
<span class="shortcuts">
<span>r</span>
</span>
</p>
</div>
</div>
</p>
</card>
</div>
</div>
</div>

View File

@ -1,9 +1,6 @@
<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">
<card title="Share links" class="is-fullwidth" :padding="false">
<div class="sharables-list">
<div class="p-4">
<p>Share with a link:</p>
<div class="field has-addons">
@ -19,7 +16,7 @@
</div>
</div>
<div class="control">
<x-button @click="add"> Share </x-button>
<x-button @click="add"> Share</x-button>
</div>
</div>
</div>
@ -28,74 +25,74 @@
v-if="linkShares.length > 0"
>
<thead>
<tr>
<th>Link</th>
<th>Shared by</th>
<th>Right</th>
<th>Delete</th>
</tr>
<tr>
<th>Link</th>
<th>Shared by</th>
<th>Right</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
<tr :key="s.id" v-for="s in linkShares">
<td>
<div class="field has-addons no-input-mobile">
<div class="control">
<input
:value="getShareLink(s.hash)"
class="input"
readonly
type="text"
/>
</div>
<div class="control">
<x-button
@click="copy(getShareLink(s.hash))"
:shadow="false"
v-tooltip="'Copy to clipboard'"
>
<span class="icon">
<icon icon="paste" />
</span>
</x-button>
</div>
<tr :key="s.id" v-for="s in linkShares">
<td>
<div class="field has-addons no-input-mobile">
<div class="control">
<input
:value="getShareLink(s.hash)"
class="input"
readonly
type="text"
/>
</div>
</td>
<td>
{{ s.sharedBy.getDisplayName() }}
</td>
<td class="type">
<template v-if="s.right === rights.ADMIN">
<div class="control">
<x-button
@click="copy(getShareLink(s.hash))"
:shadow="false"
v-tooltip="'Copy to clipboard'"
>
<span class="icon">
<icon icon="paste"/>
</span>
</x-button>
</div>
</div>
</td>
<td>
{{ s.sharedBy.getDisplayName() }}
</td>
<td class="type">
<template v-if="s.right === rights.ADMIN">
<span class="icon is-small">
<icon icon="lock" />
<icon icon="lock"/>
</span>
Admin
</template>
<template v-else-if="s.right === rights.READ_WRITE">
Admin
</template>
<template v-else-if="s.right === rights.READ_WRITE">
<span class="icon is-small">
<icon icon="pen" />
<icon icon="pen"/>
</span>
Write
</template>
<template v-else>
Write
</template>
<template v-else>
<span class="icon is-small">
<icon icon="users" />
<icon icon="users"/>
</span>
Read-only
</template>
</td>
<td class="actions">
<x-button
@click="
Read-only
</template>
</td>
<td class="actions">
<x-button
@click="
() => {
linkIdToDelete = s.id
showDeleteModal = true
}
"
class="is-danger"
icon="trash-alt"
/>
</td>
</tr>
class="is-danger"
icon="trash-alt"
/>
</td>
</tr>
</tbody>
</table>
</div>
@ -107,13 +104,13 @@
>
<span slot="header">Remove a link share</span>
<p slot="text">
Are you sure you want to remove this link share?<br />
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 />
share.<br/>
<b>This CANNOT BE UNDONE!</b>
</p>
</modal>
</div>
</card>
</template>
<script>
@ -123,7 +120,7 @@ import LinkShareService from '../../services/linkShare'
import LinkShareModel from '../../models/linkShare'
import copy from 'copy-to-clipboard'
import { mapState } from 'vuex'
import {mapState} from 'vuex'
export default {
name: 'linkSharing',
@ -168,7 +165,7 @@ export default {
}
this.linkShareService
.getAll({ listId: this.listId })
.getAll({listId: this.listId})
.then((r) => {
this.linkShares = r
})
@ -186,7 +183,7 @@ export default {
.then(() => {
this.selectedRight = rights.READ
this.success(
{ message: 'The link share was successfully created' },
{message: 'The link share was successfully created'},
this
)
this.load()
@ -204,7 +201,7 @@ export default {
.delete(linkshare)
.then(() => {
this.success(
{ message: 'The link share was successfully deleted' },
{message: 'The link share was successfully deleted'},
this
)
this.load()

View File

@ -1,9 +1,6 @@
<template>
<div class="card is-fullwidth has-overflow">
<header class="card-header">
<p class="card-header-title">Shared with these {{ shareType }}s</p>
</header>
<div class="card-content" v-if="userIsAdmin">
<card class="is-fullwidth has-overflow" :title="`Shared with these ${shareType}s`" :padding="false">
<div class="p-4" v-if="userIsAdmin">
<div class="field has-addons">
<p
class="control is-expanded"
@ -122,7 +119,7 @@
<b>This CANNOT BE UNDONE!</b>
</p>
</modal>
</div>
</card>
</template>
<script>

View File

@ -27,7 +27,7 @@
{{
new Date(
new Date(yk).setMonth(mk)
).toLocaleString('en-us', { month: 'long' })
).toLocaleString('en-us', {month: 'long'})
}},
{{ new Date(yk).getFullYear() }}
<div class="days">
@ -109,12 +109,12 @@
'has-super-high-priority':
t.priority === priorities.DO_NOW,
}"
>{{ t.title }}</span
>{{ t.title }}</span
>
<priority-label :priority="t.priority" />
<priority-label :priority="t.priority"/>
<!-- 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" />
<icon icon="pen"/>
</a>
</VueDragResize>
</div>
@ -177,29 +177,15 @@
</x-button>
</form>
<transition name="fade">
<div class="card taskedit" v-if="isTaskEdit">
<header class="card-header">
<p class="card-header-title">Edit Task</p>
<a
@click="
() => {
isTaskEdit = false
taskToEdit = null
}
"
class="card-header-icon"
>
<span class="icon">
<icon icon="times" />
</span>
</a>
</header>
<div class="card-content">
<div class="content">
<edit-task :task="taskToEdit" />
</div>
</div>
</div>
<card
v-if="isTaskEdit"
class="taskedit"
title="Edit Task"
@close="() => {isTaskEdit = false;taskToEdit = null}"
:has-close="true"
>
<edit-task :task="taskToEdit"/>
</card>
</transition>
</div>
</template>
@ -213,7 +199,7 @@ import TaskModel from '../../models/task'
import priorities from '../../models/priorities'
import PriorityLabel from './partials/priorityLabel'
import TaskCollectionService from '../../services/taskCollection'
import { mapState } from 'vuex'
import {mapState} from 'vuex'
import Rights from '../../models/rights.json'
import FilterPopup from '@/components/list/partials/filter-popup'
@ -340,7 +326,7 @@ export default {
const getAllTasks = (page = 1) => {
return this.taskCollectionService
.getAll({ listId: this.listId }, this.params, page)
.getAll({listId: this.listId}, this.params, page)
.then((tasks) => {
if (page < this.taskCollectionService.totalPages) {
return getAllTasks(page + 1).then((nextTasks) => {

View File

@ -1,71 +1,64 @@
<template>
<div class="card">
<header class="card-header">
<p class="card-header-title">
Avatar
</p>
</header>
<div class="card-content">
<div class="control mb-4">
<label class="radio">
<input name="avatarProvider" type="radio" v-model="avatarProvider" value="default"/>
Default
</label>
<label class="radio">
<input name="avatarProvider" type="radio" v-model="avatarProvider" value="initials"/>
Initials
</label>
<label class="radio">
<input name="avatarProvider" type="radio" v-model="avatarProvider" value="gravatar"/>
Gravatar
</label>
<label class="radio">
<input name="avatarProvider" type="radio" v-model="avatarProvider" value="upload"/>
Upload
</label>
</div>
<card title="Avatar">
<div class="control mb-4">
<label class="radio">
<input name="avatarProvider" type="radio" v-model="avatarProvider" value="default"/>
Default
</label>
<label class="radio">
<input name="avatarProvider" type="radio" v-model="avatarProvider" value="initials"/>
Initials
</label>
<label class="radio">
<input name="avatarProvider" type="radio" v-model="avatarProvider" value="gravatar"/>
Gravatar
</label>
<label class="radio">
<input name="avatarProvider" type="radio" v-model="avatarProvider" value="upload"/>
Upload
</label>
</div>
<template v-if="avatarProvider === 'upload'">
<input
@change="cropAvatar"
accept="image/*"
class="is-hidden"
ref="avatarUploadInput"
type="file"
/>
<template v-if="avatarProvider === 'upload'">
<input
@change="cropAvatar"
accept="image/*"
class="is-hidden"
ref="avatarUploadInput"
type="file"
/>
<x-button
:loading="avatarService.loading || loading"
@click="$refs.avatarUploadInput.click()"
v-if="!isCropAvatar">
Upload Avatar
</x-button>
<template v-else>
<cropper
:src="avatarToCrop"
:stencil-props="{aspectRatio: 1}"
@ready="() => loading = false"
class="mb-4"
ref="cropper"/>
<x-button
:loading="avatarService.loading || loading"
@click="$refs.avatarUploadInput.click()"
v-if="!isCropAvatar">
@click="uploadAvatar"
>
Upload Avatar
</x-button>
<template v-else>
<cropper
:src="avatarToCrop"
:stencil-props="{aspectRatio: 1}"
@ready="() => loading = false"
class="mb-4"
ref="cropper"/>
<x-button
:loading="avatarService.loading || loading"
@click="uploadAvatar"
>
Upload Avatar
</x-button>
</template>
</template>
</template>
<div class="mt-2" v-if="avatarProvider !== 'upload'">
<x-button
:loading="avatarService.loading || loading"
@click="updateAvatarStatus()"
class="is-fullwidth"
>
Save
</x-button>
</div>
<div class="mt-2" v-if="avatarProvider !== 'upload'">
<x-button
:loading="avatarService.loading || loading"
@click="updateAvatarStatus()"
class="is-fullwidth"
>
Save
</x-button>
</div>
</div>
</card>
</template>
<script>

View File

@ -165,6 +165,9 @@ const formatDate = (date, f) => {
import Button from '@/components/input/button'
Vue.component('x-button', Button)
import Card from '@/components/misc/card'
Vue.component('card', Card)
Vue.mixin({
methods: {
formatDateSince: date => {

View File

@ -2,65 +2,60 @@
<div class="modal-mask keyboard-shortcuts-modal">
<div @click.self="$router.back()" class="modal-container">
<div class="modal-content">
<div class="card has-background-white has-no-shadow">
<header class="card-header">
<p class="card-header-title">Create A Saved Filter</p>
</header>
<div class="card-content content">
<p>
A saved filter is a virtual list which is computed from a set of filters each time it is
accessed. Once created, it will appear in a special namespace.
</p>
<div class="field">
<label class="label" for="title">Title</label>
<div class="control">
<input
v-model="savedFilter.title"
:class="{ 'disabled': savedFilterService.loading}"
:disabled="savedFilterService.loading"
class="input"
id="Title"
placeholder="The saved filter title goes here..."
type="text"
v-focus
/>
</div>
<card class="has-background-white has-no-shadow" title="Create A Saved Filter">
<p>
A saved filter is a virtual list which is computed from a set of filters each time it is
accessed. Once created, it will appear in a special namespace.
</p>
<div class="field">
<label class="label" for="title">Title</label>
<div class="control">
<input
v-model="savedFilter.title"
:class="{ 'disabled': savedFilterService.loading}"
:disabled="savedFilterService.loading"
class="input"
id="Title"
placeholder="The saved filter title goes here..."
type="text"
v-focus
/>
</div>
<div class="field">
<label class="label" for="description">Description</label>
<div class="control">
<editor
v-model="savedFilter.description"
:class="{ 'disabled': savedFilterService.loading}"
:disabled="savedFilterService.loading"
:preview-is-default="false"
id="description"
placeholder="The description goes here..."
v-if="editorActive"
/>
</div>
</div>
<div class="field">
<label class="label" for="filters">Filters</label>
<div class="control">
<filters
:class="{ 'disabled': savedFilterService.loading}"
:disabled="savedFilterService.loading"
class="has-no-shadow has-no-border"
v-model="filters"
/>
</div>
</div>
<x-button
:loading="savedFilterService.loading"
:disabled="savedFilterService.loading"
@click="create()"
class="is-fullwidth"
>
Create new saved filter
</x-button>
</div>
</div>
<div class="field">
<label class="label" for="description">Description</label>
<div class="control">
<editor
v-model="savedFilter.description"
:class="{ 'disabled': savedFilterService.loading}"
:disabled="savedFilterService.loading"
:preview-is-default="false"
id="description"
placeholder="The description goes here..."
v-if="editorActive"
/>
</div>
</div>
<div class="field">
<label class="label" for="filters">Filters</label>
<div class="control">
<filters
:class="{ 'disabled': savedFilterService.loading}"
:disabled="savedFilterService.loading"
class="has-no-shadow has-no-border"
v-model="filters"
/>
</div>
</div>
<x-button
:loading="savedFilterService.loading"
:disabled="savedFilterService.loading"
@click="create()"
class="is-fullwidth"
>
Create new saved filter
</x-button>
</card>
</div>
</div>
</div>

View File

@ -1,76 +1,67 @@
<template>
<div :class="{ 'is-loading': filterService.loading}" class="loader-container edit-list is-max-width-desktop">
<div class="card">
<header class="card-header">
<p class="card-header-title">
Edit Saved Filter
</p>
</header>
<div class="card-content">
<div class="content">
<form @submit.prevent="save()">
<div class="field">
<label class="label" for="listtext">Filter Name</label>
<div class="control">
<input
:class="{ 'disabled': filterService.loading}"
:disabled="filterService.loading"
@keyup.enter="save"
class="input"
id="listtext"
placeholder="The list title goes here..."
type="text"
v-focus
v-model="filter.title"/>
</div>
</div>
<div class="field">
<label class="label" for="listdescription">Description</label>
<div class="control">
<editor
:class="{ 'disabled': filterService.loading}"
:disabled="filterService.loading"
:preview-is-default="false"
id="listdescription"
placeholder="The lists description goes here..."
v-model="filter.description"
/>
</div>
</div>
<div class="field">
<label class="label" for="filters">Filters</label>
<div class="control">
<filters
:class="{ 'disabled': filterService.loading}"
:disabled="filterService.loading"
class="has-no-shadow has-no-border"
v-model="filters"
/>
</div>
</div>
</form>
<div class="field has-addons mt-4">
<div class="control is-fullwidth">
<x-button
@click="save()"
:loading="filterService.loading"
class="is-fullwidth">
Save
</x-button>
</div>
<div class="control">
<x-button
@click="showDeleteModal = true"
:loading="filterService.loading"
class="is-danger"
icon="trash-alt"
/>
</div>
<card title="Edit Saved Filter">
<form @submit.prevent="save()">
<div class="field">
<label class="label" for="listtext">Filter Name</label>
<div class="control">
<input
:class="{ 'disabled': filterService.loading}"
:disabled="filterService.loading"
@keyup.enter="save"
class="input"
id="listtext"
placeholder="The list title goes here..."
type="text"
v-focus
v-model="filter.title"/>
</div>
</div>
<div class="field">
<label class="label" for="listdescription">Description</label>
<div class="control">
<editor
:class="{ 'disabled': filterService.loading}"
:disabled="filterService.loading"
:preview-is-default="false"
id="listdescription"
placeholder="The lists description goes here..."
v-model="filter.description"
/>
</div>
</div>
<div class="field">
<label class="label" for="filters">Filters</label>
<div class="control">
<filters
:class="{ 'disabled': filterService.loading}"
:disabled="filterService.loading"
class="has-no-shadow has-no-border"
v-model="filters"
/>
</div>
</div>
</form>
<div class="field has-addons mt-4">
<div class="control is-fullwidth">
<x-button
@click="save()"
:loading="filterService.loading"
class="is-fullwidth">
Save
</x-button>
</div>
<div class="control">
<x-button
@click="showDeleteModal = true"
:loading="filterService.loading"
class="is-danger"
icon="trash-alt"
/>
</div>
</div>
</div>
</card>
<modal
@close="showDeleteModal = false"

View File

@ -1,5 +1,5 @@
<template>
<div :class="{ 'is-loading': labelService.loading}" class="loader-container content">
<div :class="{ 'is-loading': labelService.loading}" class="loader-container">
<x-button
:to="{name:'labels.create'}"
class="is-pulled-right"
@ -7,12 +7,17 @@
>
New label
</x-button>
<h1>Manage labels</h1>
<p>
Click on a label to edit it.
You can edit all labels you created, you can use all labels which are associated with a task to whose list
you have access.
</p>
<div class="content">
<h1>Manage labels</h1>
<p>
Click on a label to edit it.
You can edit all labels you created, you can use all labels which are associated with a task to whose
list
you have access.
</p>
</div>
<div class="columns">
<div class="labels-list column">
<span
@ -36,67 +41,55 @@
</span>
</div>
<div class="column is-4" v-if="isLabelEdit">
<div class="card">
<header class="card-header">
<span class="card-header-title">
Edit Label
</span>
<a @click="isLabelEdit = false" class="card-header-icon">
<span class="icon">
<icon icon="times"/>
</span>
</a>
</header>
<div class="card-content">
<form @submit.prevent="editLabelSubmit()">
<div class="field">
<label class="label">Title</label>
<div class="control">
<input
class="input"
placeholder="Label title"
type="text"
v-model="labelEditLabel.title"/>
</div>
<card title="Edit Label" :has-close="true" @close="() => isLabelEdit = false">
<form @submit.prevent="editLabelSubmit()">
<div class="field">
<label class="label">Title</label>
<div class="control">
<input
class="input"
placeholder="Label title"
type="text"
v-model="labelEditLabel.title"/>
</div>
<div class="field">
<label class="label">Description</label>
<div class="control">
<editor
:preview-is-default="false"
placeholder="Label description"
v-if="editorActive"
v-model="labelEditLabel.description"
/>
</div>
</div>
<div class="field">
<label class="label">Description</label>
<div class="control">
<editor
:preview-is-default="false"
placeholder="Label description"
v-if="editorActive"
v-model="labelEditLabel.description"
/>
</div>
<div class="field">
<label class="label">Color</label>
<div class="control">
<color-picker v-model="labelEditLabel.hexColor"/>
</div>
</div>
<div class="field">
<label class="label">Color</label>
<div class="control">
<color-picker v-model="labelEditLabel.hexColor"/>
</div>
<div class="field has-addons">
<div class="control is-expanded">
<x-button
:loading="labelService.loading"
class="is-fullwidth"
@click="editLabelSubmit()"
>
Save
</x-button>
</div>
<div class="control">
<x-button
@click="() => {deleteLabel(labelEditLabel);isLabelEdit = false}"
icon="trash-alt"
class="is-danger"
/>
</div>
</div>
<div class="field has-addons">
<div class="control is-expanded">
<x-button
:loading="labelService.loading"
class="is-fullwidth"
@click="editLabelSubmit()"
>
Save
</x-button>
</div>
</form>
</div>
</div>
<div class="control">
<x-button
@click="() => {deleteLabel(labelEditLabel);isLabelEdit = false}"
icon="trash-alt"
class="is-danger"
/>
</div>
</div>
</form>
</card>
</div>
</div>
</div>

View File

@ -4,129 +4,112 @@
This list is archived.
It is not possible to create new or edit tasks or it.
</div>
<div class="card">
<header class="card-header">
<p class="card-header-title">
Edit List
</p>
</header>
<div class="card-content">
<div class="content">
<form @submit.prevent="submit()">
<div class="field">
<label class="label" for="listtext">List Name</label>
<div class="control">
<input
:class="{ 'disabled': listService.loading}"
:disabled="listService.loading"
@keyup.enter="submit"
class="input"
id="listtext"
placeholder="The list title goes here..."
type="text"
v-focus
v-model="list.title"/>
</div>
</div>
<div class="field">
<label
class="label"
for="listtext"
v-tooltip="'The list identifier can be used to uniquely identify a task across lists. You can set it to empty to disable it.'">
List Identifier
</label>
<div class="control">
<input
:class="{ 'disabled': listService.loading}"
:disabled="listService.loading"
@keyup.enter="submit"
class="input"
id="listtext"
placeholder="The list identifier goes here..."
type="text"
v-focus
v-model="list.identifier"/>
</div>
</div>
<div class="field">
<label class="label" for="listdescription">Description</label>
<div class="control">
<editor
:class="{ 'disabled': listService.loading}"
:disabled="listService.loading"
:preview-is-default="false"
id="listdescription"
placeholder="The lists description goes here..."
v-model="list.description"
/>
</div>
</div>
<div class="field">
<label class="label" for="isArchivedCheck">Is Archived</label>
<div class="control">
<fancycheckbox
v-model="list.isArchived"
v-tooltip="'If a list is archived, you cannot create new tasks or edit the list or existing tasks.'">
This list is archived
</fancycheckbox>
</div>
</div>
<div class="field">
<label class="label">Color</label>
<div class="control">
<color-picker v-model="list.hexColor"/>
</div>
</div>
</form>
<div class="field has-addons mt-4">
<div class="control is-fullwidth">
<x-button
@click="submit()"
:loading="listService.loading"
class="is-fullwidth">
Save
</x-button>
</div>
<div class="control">
<x-button
@click="showDeleteModal = true"
:locading="listService.loading"
icon="trash-alt"
class="is-danger"
/>
</div>
<card title="Edit List">
<form @submit.prevent="submit()">
<div class="field">
<label class="label" for="listtext">List Name</label>
<div class="control">
<input
:class="{ 'disabled': listService.loading}"
:disabled="listService.loading"
@keyup.enter="submit"
class="input"
id="listtext"
placeholder="The list title goes here..."
type="text"
v-focus
v-model="list.title"/>
</div>
</div>
</div>
</div>
<div class="card has-overflow">
<header class="card-header">
<p class="card-header-title">
Duplicate this list
</p>
</header>
<div class="card-content">
<div class="content">
<p>Select a namespace which should hold the duplicated list:</p>
<div class="field has-addons">
<div class="control is-expanded">
<namespace-search @selected="selectNamespace"/>
</div>
<div class="control">
<x-button
:loading="listDuplicateService.loading"
@click="duplicateList"
>
Duplicate
</x-button>
</div>
<div class="field">
<label
class="label"
for="listtext"
v-tooltip="'The list identifier can be used to uniquely identify a task across lists. You can set it to empty to disable it.'">
List Identifier
</label>
<div class="control">
<input
:class="{ 'disabled': listService.loading}"
:disabled="listService.loading"
@keyup.enter="submit"
class="input"
id="listtext"
placeholder="The list identifier goes here..."
type="text"
v-focus
v-model="list.identifier"/>
</div>
</div>
<div class="field">
<label class="label" for="listdescription">Description</label>
<div class="control">
<editor
:class="{ 'disabled': listService.loading}"
:disabled="listService.loading"
:preview-is-default="false"
id="listdescription"
placeholder="The lists description goes here..."
v-model="list.description"
/>
</div>
</div>
<div class="field">
<label class="label" for="isArchivedCheck">Is Archived</label>
<div class="control">
<fancycheckbox
v-model="list.isArchived"
v-tooltip="'If a list is archived, you cannot create new tasks or edit the list or existing tasks.'">
This list is archived
</fancycheckbox>
</div>
</div>
<div class="field">
<label class="label">Color</label>
<div class="control">
<color-picker v-model="list.hexColor"/>
</div>
</div>
</form>
<div class="field has-addons mt-4">
<div class="control is-fullwidth">
<x-button
@click="submit()"
:loading="listService.loading"
class="is-fullwidth">
Save
</x-button>
</div>
<div class="control">
<x-button
@click="showDeleteModal = true"
:locading="listService.loading"
icon="trash-alt"
class="is-danger"
/>
</div>
</div>
</div>
</card>
<!-- Duplicate list -->
<card class="has-overflow" title="Duplicate this list">
<p>Select a namespace which should hold the duplicated list:</p>
<div class="field has-addons">
<div class="control is-expanded">
<namespace-search @selected="selectNamespace"/>
</div>
<div class="control">
<x-button
:loading="listDuplicateService.loading"
@click="duplicateList"
>
Duplicate
</x-button>
</div>
</div>
</card>
<background :list-id="$route.params.id"/>

View File

@ -103,23 +103,9 @@
</div>
</div>
<div class="column is-4" v-if="isTaskEdit">
<div class="card taskedit">
<header class="card-header">
<p class="card-header-title">
Edit Task
</p>
<a @click="isTaskEdit = false" class="card-header-icon">
<span class="icon">
<icon icon="angle-right"/>
</span>
</a>
</header>
<div class="card-content">
<div class="content">
<edit-task :task="taskEditTask"/>
</div>
</div>
</div>
<card class="taskedit" title="Edit Task" :has-close="true" @close="() => isTaskEdit = false">
<edit-task :task="taskEditTask"/>
</card>
</div>
</div>

View File

@ -18,23 +18,21 @@
</x-button>
</div>
<transition name="fade">
<div class="card" v-if="showActiveColumnsFilter">
<div class="card-content">
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.id">#</fancycheckbox>
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.done">Done</fancycheckbox>
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.title">Title</fancycheckbox>
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.priority">Priority</fancycheckbox>
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.labels">Labels</fancycheckbox>
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.assignees">Assignees</fancycheckbox>
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.dueDate">Due Date</fancycheckbox>
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.startDate">Start Date</fancycheckbox>
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.endDate">End Date</fancycheckbox>
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.percentDone">% Done</fancycheckbox>
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.created">Created</fancycheckbox>
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.updated">Updated</fancycheckbox>
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.createdBy">Created By</fancycheckbox>
</div>
</div>
<card v-if="showActiveColumnsFilter">
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.id">#</fancycheckbox>
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.done">Done</fancycheckbox>
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.title">Title</fancycheckbox>
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.priority">Priority</fancycheckbox>
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.labels">Labels</fancycheckbox>
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.assignees">Assignees</fancycheckbox>
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.dueDate">Due Date</fancycheckbox>
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.startDate">Start Date</fancycheckbox>
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.endDate">End Date</fancycheckbox>
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.percentDone">% Done</fancycheckbox>
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.created">Created</fancycheckbox>
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.updated">Updated</fancycheckbox>
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.createdBy">Created By</fancycheckbox>
</card>
</transition>
<filter-popup
@change="loadTasks(1)"

View File

@ -4,83 +4,74 @@
This namespace is archived.
It is not possible to create new lists or edit it.
</div>
<div class="card">
<header class="card-header">
<p class="card-header-title">
Edit Namespace
</p>
</header>
<div class="card-content">
<div class="content">
<form @submit.prevent="submit()">
<div class="field">
<label class="label" for="namespacetext">Namespace Name</label>
<div class="control">
<input
:class="{ 'disabled': namespaceService.loading}"
:disabled="namespaceService.loading"
class="input"
id="namespacetext"
placeholder="The namespace text is here..."
type="text"
v-focus
v-model="namespace.title"/>
</div>
</div>
<div class="field">
<label class="label" for="namespacedescription">Description</label>
<div class="control">
<editor
:class="{ 'disabled': namespaceService.loading}"
:disabled="namespaceService.loading"
:preview-is-default="false"
id="namespacedescription"
placeholder="The namespaces description goes here..."
v-if="editorActive"
v-model="namespace.description"
/>
</div>
</div>
<div class="field">
<label class="label" for="isArchivedCheck">Is Archived</label>
<div class="control">
<fancycheckbox
v-model="namespace.isArchived"
v-tooltip="'If a namespace is archived, you cannot create new lists or edit it.'">
This namespace is archived
</fancycheckbox>
</div>
</div>
<div class="field">
<label class="label">Color</label>
<div class="control">
<color-picker v-model="namespace.hexColor"/>
</div>
</div>
</form>
<div class="field has-addons mt-4">
<div class="control is-fullwidth">
<x-button
@click="submit()"
:loading="namespaceService.loading"
class="is-fullwidth"
>
Save
</x-button>
</div>
<div class="control">
<x-button
@click="showDeleteModal = true"
:loading="namespaceService.loading"
class="is-danger"
icon="trash-alt"
/>
</div>
<card title="Edit Namespace">
<form @submit.prevent="submit()">
<div class="field">
<label class="label" for="namespacetext">Namespace Name</label>
<div class="control">
<input
:class="{ 'disabled': namespaceService.loading}"
:disabled="namespaceService.loading"
class="input"
id="namespacetext"
placeholder="The namespace text is here..."
type="text"
v-focus
v-model="namespace.title"/>
</div>
</div>
<div class="field">
<label class="label" for="namespacedescription">Description</label>
<div class="control">
<editor
:class="{ 'disabled': namespaceService.loading}"
:disabled="namespaceService.loading"
:preview-is-default="false"
id="namespacedescription"
placeholder="The namespaces description goes here..."
v-if="editorActive"
v-model="namespace.description"
/>
</div>
</div>
<div class="field">
<label class="label" for="isArchivedCheck">Is Archived</label>
<div class="control">
<fancycheckbox
v-model="namespace.isArchived"
v-tooltip="'If a namespace is archived, you cannot create new lists or edit it.'">
This namespace is archived
</fancycheckbox>
</div>
</div>
<div class="field">
<label class="label">Color</label>
<div class="control">
<color-picker v-model="namespace.hexColor"/>
</div>
</div>
</form>
<div class="field has-addons mt-4">
<div class="control is-fullwidth">
<x-button
@click="submit()"
:loading="namespaceService.loading"
class="is-fullwidth"
>
Save
</x-button>
</div>
<div class="control">
<x-button
@click="showDeleteModal = true"
:loading="namespaceService.loading"
class="is-danger"
icon="trash-alt"
/>
</div>
</div>
</div>
</card>
<component
:id="namespace.id"

View File

@ -3,83 +3,73 @@
class="loader-container is-max-width-desktop"
:class="{ 'is-loading': teamService.loading }"
>
<div class="card is-fullwidth" v-if="userIsAdmin">
<header class="card-header">
<p class="card-header-title">Edit Team</p>
</header>
<div class="card-content">
<div class="content">
<form @submit.prevent="save()">
<div class="field">
<label class="label" for="teamtext"
>Team Name</label
>
<div class="control">
<input
:class="{
<card class="is-fullwidth" v-if="userIsAdmin" title="Edit Team">
<form @submit.prevent="save()">
<div class="field">
<label class="label" for="teamtext"
>Team Name</label
>
<div class="control">
<input
:class="{
disabled: teamMemberService.loading,
}"
:disabled="teamMemberService.loading"
class="input"
id="teamtext"
placeholder="The team text is here..."
type="text"
v-focus
v-model="team.name"
/>
</div>
</div>
<p
class="help is-danger"
v-if="showError && team.name === ''"
>
Please specify a name.
</p>
<div class="field">
<label class="label" for="teamdescription"
>Description</label
>
<div class="control">
<editor
:class="{ disabled: teamService.loading }"
:disabled="teamService.loading"
:preview-is-default="false"
id="teamdescription"
placeholder="The teams description goes here..."
v-model="team.description"
/>
</div>
</div>
</form>
<div class="field has-addons mt-4">
<div class="control is-fullwidth">
<x-button
@click="save()"
:loading="teamService.loading"
class="is-fullwidth"
>
Save
</x-button>
</div>
<div class="control">
<x-button
@click="showDeleteModal = true"
:loading="teamService.loading"
class="is-danger"
icon="trash-alt"
/>
</div>
:disabled="teamMemberService.loading"
class="input"
id="teamtext"
placeholder="The team text is here..."
type="text"
v-focus
v-model="team.name"
/>
</div>
</div>
</div>
</div>
<p
class="help is-danger"
v-if="showError && team.name === ''"
>
Please specify a name.
</p>
<div class="field">
<label class="label" for="teamdescription"
>Description</label
>
<div class="control">
<editor
:class="{ disabled: teamService.loading }"
:disabled="teamService.loading"
:preview-is-default="false"
id="teamdescription"
placeholder="The teams description goes here..."
v-model="team.description"
/>
</div>
</div>
</form>
<div class="card is-fullwidth has-overflow">
<header class="card-header">
<p class="card-header-title">Team Members</p>
</header>
<div class="card-content" v-if="userIsAdmin">
<div class="field has-addons mt-4">
<div class="control is-fullwidth">
<x-button
@click="save()"
:loading="teamService.loading"
class="is-fullwidth"
>
Save
</x-button>
</div>
<div class="control">
<x-button
@click="showDeleteModal = true"
:loading="teamService.loading"
class="is-danger"
icon="trash-alt"
/>
</div>
</div>
</card>
<card class="is-fullwidth has-overflow" title="Team Members">
<div class="p-4" v-if="userIsAdmin">
<div class="field has-addons">
<div class="control is-expanded">
<multiselect
@ -141,7 +131,7 @@
</tr>
</tbody>
</table>
</div>
</card>
<!-- Team delete modal -->
<modal

View File

@ -3,270 +3,216 @@
:class="{ 'is-loading': passwordUpdateService.loading || emailUpdateService.loading || totpService.loading }"
class="loader-container is-max-width-desktop">
<!-- Password update -->
<div class="card">
<header class="card-header">
<p class="card-header-title">
Update Your Password
</p>
</header>
<div class="card-content">
<div class="content">
<form @submit.prevent="updatePassword()">
<div class="field">
<label class="label" for="newPassword">New Password</label>
<div class="control">
<input
@keyup.enter="updatePassword"
class="input"
id="newPassword"
placeholder="The new password..."
type="password"
v-model="passwordUpdate.newPassword"/>
</div>
</div>
<div class="field">
<label class="label" for="newPasswordConfirm">New Password Confirmation</label>
<div class="control">
<input
@keyup.enter="updatePassword"
class="input"
id="newPasswordConfirm"
placeholder="Confirm your new password..."
type="password"
v-model="passwordConfirm"/>
</div>
</div>
<div class="field">
<label class="label" for="currentPassword">Current Password</label>
<div class="control">
<input
@keyup.enter="updatePassword"
class="input"
id="currentPassword"
placeholder="Your current password"
type="password"
v-model="passwordUpdate.oldPassword"/>
</div>
</div>
</form>
<div class="mt-2">
<x-button
:loading="passwordUpdateService.loading"
@click="updatePassword()"
class="is-fullwidth">
Save
</x-button>
<card title="Update Your Password">
<form @submit.prevent="updatePassword()">
<div class="field">
<label class="label" for="newPassword">New Password</label>
<div class="control">
<input
@keyup.enter="updatePassword"
class="input"
id="newPassword"
placeholder="The new password..."
type="password"
v-model="passwordUpdate.newPassword"/>
</div>
</div>
</div>
</div>
<div class="field">
<label class="label" for="newPasswordConfirm">New Password Confirmation</label>
<div class="control">
<input
@keyup.enter="updatePassword"
class="input"
id="newPasswordConfirm"
placeholder="Confirm your new password..."
type="password"
v-model="passwordConfirm"/>
</div>
</div>
<div class="field">
<label class="label" for="currentPassword">Current Password</label>
<div class="control">
<input
@keyup.enter="updatePassword"
class="input"
id="currentPassword"
placeholder="Your current password"
type="password"
v-model="passwordUpdate.oldPassword"/>
</div>
</div>
</form>
<x-button
:loading="passwordUpdateService.loading"
@click="updatePassword()"
class="is-fullwidth mt-4">
Save
</x-button>
</card>
<!-- Update E-Mail -->
<div class="card">
<header class="card-header">
<p class="card-header-title">
Update Your E-Mail Address
</p>
</header>
<div class="card-content">
<div class="content">
<form @submit.prevent="updateEmail()">
<div class="field">
<label class="label" for="newEmail">New Email Address</label>
<div class="control">
<input
@keyup.enter="updateEmail"
class="input"
id="newEmail"
placeholder="The new email address..."
type="email"
v-model="emailUpdate.newEmail"/>
</div>
</div>
<div class="field">
<label class="label" for="currentPassword">Current Password</label>
<div class="control">
<input
@keyup.enter="updateEmail"
class="input"
id="currentPassword"
placeholder="Your current password"
type="password"
v-model="emailUpdate.password"/>
</div>
</div>
</form>
<div class="mt-2">
<x-button
:loading="emailUpdateService.loading"
@click="updateEmail()"
class="is-fullwidth">
Save
</x-button>
<card title="Update Your E-Mail Address">
<form @submit.prevent="updateEmail()">
<div class="field">
<label class="label" for="newEmail">New Email Address</label>
<div class="control">
<input
@keyup.enter="updateEmail"
class="input"
id="newEmail"
placeholder="The new email address..."
type="email"
v-model="emailUpdate.newEmail"/>
</div>
</div>
</div>
</div>
<div class="field">
<label class="label" for="currentPassword">Current Password</label>
<div class="control">
<input
@keyup.enter="updateEmail"
class="input"
id="currentPassword"
placeholder="Your current password"
type="password"
v-model="emailUpdate.password"/>
</div>
</div>
</form>
<x-button
:loading="emailUpdateService.loading"
@click="updateEmail()"
class="is-fullwidth mt-4">
Save
</x-button>
</card>
<!-- General -->
<div class="card update-name">
<header class="card-header">
<p class="card-header-title">
General Settings
</p>
</header>
<div class="card-content">
<div class="content">
<div class="field">
<label class="label" for="newName">Name</label>
<div class="control">
<input
@keyup.enter="updateSettings"
class="input"
id="newName"
placeholder="The new name"
type="text"
v-model="settings.name"/>
</div>
</div>
<div class="field">
<label class="checkbox">
<input type="checkbox" v-model="settings.emailRemindersEnabled"/>
Send me Reminders for tasks via Email
</label>
</div>
<div class="mt-2">
<x-button
:loading="userSettingsService.loading"
@click="updateSettings()"
class="is-fullwidth">
Save
</x-button>
</div>
<card title="General Settings">
<div class="field">
<label class="label" for="newName">Name</label>
<div class="control">
<input
@keyup.enter="updateSettings"
class="input"
id="newName"
placeholder="The new name"
type="text"
v-model="settings.name"/>
</div>
</div>
</div>
<div class="field">
<label class="checkbox">
<input type="checkbox" v-model="settings.emailRemindersEnabled"/>
Send me Reminders for tasks via Email
</label>
</div>
<x-button
:loading="userSettingsService.loading"
@click="updateSettings()"
class="is-fullwidth mt-4"
>
Save
</x-button>
</card>
<!-- Avatar -->
<avatar-settings/>
<!-- TOTP -->
<div class="card" v-if="totpEnabled">
<header class="card-header">
<p class="card-header-title">
Two Factor Authentication
<card title="Two Factor Authentication" v-if="totpEnabled">
<x-button
:loading="totpService.loading"
@click="totpEnroll()"
v-if="!totpEnrolled && totp.secret === ''">
Enroll
</x-button>
<template v-else-if="totp.secret !== '' && !totp.enabled">
<p>
To finish your setup, use this secret in your totp app (Google Authenticator or similar):
<strong>{{ totp.secret }}</strong><br/>
After that, enter a code from your app below.
</p>
</header>
<div class="card-content">
<x-button
:loading="totpService.loading"
@click="totpEnroll()"
v-if="!totpEnrolled && totp.secret === ''">
Enroll
</x-button>
<div class="content" v-else-if="totp.secret !== '' && !totp.enabled">
<p>
To finish your setup, use this secret in your totp app (Google Authenticator or similar):
<strong>{{ totp.secret }}</strong><br/>
After that, enter a code from your app below.
</p>
<p>
Alternatively you can scan this QR code:<br/>
<img :src="totpQR" alt=""/>
</p>
<p>
Alternatively you can scan this QR code:<br/>
<img :src="totpQR" alt=""/>
</p>
<div class="field">
<label class="label" for="totpConfirmPasscode">Passcode</label>
<div class="control">
<input
@keyup.enter="totpConfirm()"
class="input"
id="totpConfirmPasscode"
placeholder="A code generated by your totp application"
type="text"
v-model="totpConfirmPasscode"/>
</div>
</div>
<x-button @click="totpConfirm()">Confirm</x-button>
</template>
<template v-else-if="totp.secret !== '' && totp.enabled">
<p>
You've sucessfully set up two factor authentication!
</p>
<p v-if="!totpDisableForm">
<x-button @click="totpDisableForm = true" class="is-danger">Disable</x-button>
</p>
<div v-if="totpDisableForm">
<div class="field">
<label class="label" for="totpConfirmPasscode">Passcode</label>
<label class="label" for="currentPassword">Please Enter Your Password</label>
<div class="control">
<input
@keyup.enter="totpConfirm()"
@keyup.enter="totpDisable"
class="input"
id="totpConfirmPasscode"
placeholder="A code generated by your totp application"
type="text"
v-model="totpConfirmPasscode"/>
id="currentPassword"
placeholder="Your current password"
type="password"
v-focus
v-model="totpDisablePassword"/>
</div>
</div>
<x-button @click="totpConfirm()">Confirm</x-button>
<x-button @click="totpDisable()" class="is-danger">Disable two factor authentication</x-button>
</div>
<div class="content" v-else-if="totp.secret !== '' && totp.enabled">
<p>
You've sucessfully set up two factor authentication!
</p>
<p v-if="!totpDisableForm">
<x-button @click="totpDisableForm = true" class="is-danger">Disable</x-button>
</p>
<div v-if="totpDisableForm">
<div class="field">
<label class="label" for="currentPassword">Please Enter Your Password</label>
<div class="control">
<input
@keyup.enter="totpDisable"
class="input"
id="currentPassword"
placeholder="Your current password"
type="password"
v-focus
v-model="totpDisablePassword"/>
</div>
</div>
<x-button @click="totpDisable()" class="is-danger">Disable two factor authentication</x-button>
</div>
</div>
</div>
</div>
</template>
</card>
<!-- Migration -->
<div class="card" v-if="migratorsEnabled">
<header class="card-header">
<p class="card-header-title">
Migrate from other services to Vikunja
</p>
</header>
<div class="card-content">
<x-button
:to="{name: 'migrate.start'}"
v-if="migratorsEnabled"
>
Import your data into Vikunja
</x-button>
</div>
</div>
<card title="Migrate from other services to Vikunja" v-if="migratorsEnabled">
<x-button
:to="{name: 'migrate.start'}"
>
Import your data into Vikunja
</x-button>
</card>
<!-- Caldav -->
<div class="card" v-if="caldavEnabled">
<header class="card-header">
<p class="card-header-title">
Caldav
</p>
</header>
<div class="card-content content">
<p>
You can connect Vikunja to caldav clients to view and manage all tasks from different clients.
Enter this url into your client:
</p>
<div class="field has-addons no-input-mobile">
<div class="control is-expanded">
<input type="text" v-model="caldavUrl" class="input" readonly/>
</div>
<div class="control">
<x-button
@click="copy(caldavUrl)"
:shadow="false"
v-tooltip="'Copy to clipboard'"
icon="paste"
/>
</div>
<card v-if="caldavEnabled" title="Caldav">
<p>
You can connect Vikunja to caldav clients to view and manage all tasks from different clients.
Enter this url into your client:
</p>
<div class="field has-addons no-input-mobile">
<div class="control is-expanded">
<input type="text" v-model="caldavUrl" class="input" readonly/>
</div>
<div class="control">
<x-button
@click="copy(caldavUrl)"
:shadow="false"
v-tooltip="'Copy to clipboard'"
icon="paste"
/>
</div>
<p>
<a href="https://vikunja.io/docs/caldav/" target="_blank">
More information about caldav in Vikunja
</a>
</p>
</div>
</div>
<p>
<a href="https://vikunja.io/docs/caldav/" target="_blank">
More information about caldav in Vikunja
</a>
</p>
</card>
</div>
</template>