Merge branch 'master' into fix-archived-stack-button
This commit is contained in:
@@ -75,7 +75,7 @@ export default {
|
||||
const subject = this.activity.subject_rich[0]
|
||||
const parameters = JSON.parse(JSON.stringify(this.activity.subject_rich[1]))
|
||||
if (parameters.after && typeof parameters.after.id === 'string' && parameters.after.id.startsWith('dt:')) {
|
||||
const dateTime = parameters.after.id.substr(3)
|
||||
const dateTime = parameters.after.id.slice(3)
|
||||
parameters.after.name = moment(dateTime).format('L LTS')
|
||||
}
|
||||
|
||||
|
||||
@@ -27,17 +27,14 @@
|
||||
@drop.prevent="handleDropFiles">
|
||||
<slot />
|
||||
<transition name="fade" mode="out-in">
|
||||
<div
|
||||
v-show="isDraggingOver"
|
||||
<div v-show="isDraggingOver"
|
||||
class="dragover">
|
||||
<div class="drop-hint">
|
||||
<div
|
||||
class="drop-hint__icon"
|
||||
<div class="drop-hint__icon"
|
||||
:class="{
|
||||
'icon-upload' : !isReadOnly,
|
||||
'icon-error' : isReadOnly}" />
|
||||
<h2
|
||||
class="drop-hint__text">
|
||||
<h2 class="drop-hint__text">
|
||||
{{ dropHintText }}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
@@ -70,130 +70,135 @@
|
||||
</form>
|
||||
</div>
|
||||
<div v-if="board" class="board-action-buttons">
|
||||
<Popover @show="filterVisible=true" @hide="filterVisible=false">
|
||||
<Actions slot="trigger" :title="t('deck', 'Apply filter')">
|
||||
<ActionButton v-if="isFilterActive" icon="icon-filter_set" />
|
||||
<ActionButton v-else icon="icon-filter" />
|
||||
</Actions>
|
||||
|
||||
<div v-if="filterVisible" class="filter">
|
||||
<h3>{{ t('deck', 'Filter by tag') }}</h3>
|
||||
<div v-for="label in labelsSorted" :key="label.id" class="filter--item">
|
||||
<input
|
||||
:id="label.id"
|
||||
v-model="filter.tags"
|
||||
type="checkbox"
|
||||
class="checkbox"
|
||||
:value="label.id"
|
||||
@change="setFilter">
|
||||
<label :for="label.id"><span class="label" :style="labelStyle(label)">{{ label.title }}</span></label>
|
||||
</div>
|
||||
|
||||
<h3>{{ t('deck', 'Filter by assigned user') }}</h3>
|
||||
<div class="filter--item">
|
||||
<input
|
||||
id="unassigned"
|
||||
v-model="filter.unassigned"
|
||||
type="checkbox"
|
||||
class="checkbox"
|
||||
value="unassigned"
|
||||
@change="setFilter"
|
||||
@click="beforeSetFilter">
|
||||
<label for="unassigned">{{ t('deck', 'Unassigned') }}</label>
|
||||
</div>
|
||||
<div v-for="user in board.users" :key="user.uid" class="filter--item">
|
||||
<input
|
||||
:id="user.uid"
|
||||
v-model="filter.users"
|
||||
type="checkbox"
|
||||
class="checkbox"
|
||||
:value="user.uid"
|
||||
@change="setFilter">
|
||||
<label :for="user.uid"><Avatar :user="user.uid" :size="24" :disable-menu="true" /> {{ user.displayname }}</label>
|
||||
</div>
|
||||
|
||||
<h3>{{ t('deck', 'Filter by due date') }}</h3>
|
||||
|
||||
<div class="filter--item">
|
||||
<input
|
||||
id="overdue"
|
||||
v-model="filter.due"
|
||||
type="radio"
|
||||
class="radio"
|
||||
value="overdue"
|
||||
@change="setFilter"
|
||||
@click="beforeSetFilter">
|
||||
<label for="overdue">{{ t('deck', 'Overdue') }}</label>
|
||||
</div>
|
||||
|
||||
<div class="filter--item">
|
||||
<input
|
||||
id="dueToday"
|
||||
v-model="filter.due"
|
||||
type="radio"
|
||||
class="radio"
|
||||
value="dueToday"
|
||||
@change="setFilter"
|
||||
@click="beforeSetFilter">
|
||||
<label for="dueToday">{{ t('deck', 'Next 24 hours') }}</label>
|
||||
</div>
|
||||
|
||||
<div class="filter--item">
|
||||
<input
|
||||
id="dueWeek"
|
||||
v-model="filter.due"
|
||||
type="radio"
|
||||
class="radio"
|
||||
value="dueWeek"
|
||||
@change="setFilter"
|
||||
@click="beforeSetFilter">
|
||||
<label for="dueWeek">{{ t('deck', 'Next 7 days') }}</label>
|
||||
</div>
|
||||
|
||||
<div class="filter--item">
|
||||
<input
|
||||
id="dueMonth"
|
||||
v-model="filter.due"
|
||||
type="radio"
|
||||
class="radio"
|
||||
value="dueMonth"
|
||||
@change="setFilter"
|
||||
@click="beforeSetFilter">
|
||||
<label for="dueMonth">{{ t('deck', 'Next 30 days') }}</label>
|
||||
</div>
|
||||
|
||||
<div class="filter--item">
|
||||
<input
|
||||
id="noDue"
|
||||
v-model="filter.due"
|
||||
type="radio"
|
||||
class="radio"
|
||||
value="noDue"
|
||||
@change="setFilter"
|
||||
@click="beforeSetFilter">
|
||||
<label for="noDue">{{ t('deck', 'No due date') }}</label>
|
||||
</div>
|
||||
|
||||
<Button :disabled="!isFilterActive" @click="clearFilter">
|
||||
{{ t('deck', 'Clear filter') }}
|
||||
<div class="board-action-buttons__filter">
|
||||
<Popover container=".board-action-buttons__filter"
|
||||
:placement="'bottom-end'"
|
||||
:aria-label="t('deck', 'Active filters')"
|
||||
@show="filterVisible=true"
|
||||
@hide="filterVisible=false">
|
||||
<!-- We cannot use Actions here are the popover trigger does not update on reactive icons -->
|
||||
<Button slot="trigger"
|
||||
:title="t('deck', 'Apply filter')"
|
||||
class="filter-button"
|
||||
type="tertiary-no-background">
|
||||
<template #icon>
|
||||
<FilterIcon v-if="isFilterActive" :size="20" decorative />
|
||||
<FilterOffIcon v-else :size="20" decorative />
|
||||
</template>
|
||||
</Button>
|
||||
</div>
|
||||
</Popover>
|
||||
|
||||
<div v-if="filterVisible" class="filter">
|
||||
<h3>{{ t('deck', 'Filter by tag') }}</h3>
|
||||
<div v-for="label in labelsSorted" :key="label.id" class="filter--item">
|
||||
<input :id="label.id"
|
||||
v-model="filter.tags"
|
||||
type="checkbox"
|
||||
class="checkbox"
|
||||
:value="label.id"
|
||||
@change="setFilter">
|
||||
<label :for="label.id"><span class="label" :style="labelStyle(label)">{{ label.title }}</span></label>
|
||||
</div>
|
||||
|
||||
<h3>{{ t('deck', 'Filter by assigned user') }}</h3>
|
||||
<div class="filter--item">
|
||||
<input id="unassigned"
|
||||
v-model="filter.unassigned"
|
||||
type="checkbox"
|
||||
class="checkbox"
|
||||
value="unassigned"
|
||||
@change="setFilter"
|
||||
@click="beforeSetFilter">
|
||||
<label for="unassigned">{{ t('deck', 'Unassigned') }}</label>
|
||||
</div>
|
||||
<div v-for="user in board.users" :key="user.uid" class="filter--item">
|
||||
<input :id="user.uid"
|
||||
v-model="filter.users"
|
||||
type="checkbox"
|
||||
class="checkbox"
|
||||
:value="user.uid"
|
||||
@change="setFilter">
|
||||
<label :for="user.uid"><Avatar :user="user.uid" :size="24" :disable-menu="true" /> {{ user.displayname }}</label>
|
||||
</div>
|
||||
|
||||
<h3>{{ t('deck', 'Filter by due date') }}</h3>
|
||||
|
||||
<div class="filter--item">
|
||||
<input id="overdue"
|
||||
v-model="filter.due"
|
||||
type="radio"
|
||||
class="radio"
|
||||
value="overdue"
|
||||
@change="setFilter"
|
||||
@click="beforeSetFilter">
|
||||
<label for="overdue">{{ t('deck', 'Overdue') }}</label>
|
||||
</div>
|
||||
|
||||
<div class="filter--item">
|
||||
<input id="dueToday"
|
||||
v-model="filter.due"
|
||||
type="radio"
|
||||
class="radio"
|
||||
value="dueToday"
|
||||
@change="setFilter"
|
||||
@click="beforeSetFilter">
|
||||
<label for="dueToday">{{ t('deck', 'Next 24 hours') }}</label>
|
||||
</div>
|
||||
|
||||
<div class="filter--item">
|
||||
<input id="dueWeek"
|
||||
v-model="filter.due"
|
||||
type="radio"
|
||||
class="radio"
|
||||
value="dueWeek"
|
||||
@change="setFilter"
|
||||
@click="beforeSetFilter">
|
||||
<label for="dueWeek">{{ t('deck', 'Next 7 days') }}</label>
|
||||
</div>
|
||||
|
||||
<div class="filter--item">
|
||||
<input id="dueMonth"
|
||||
v-model="filter.due"
|
||||
type="radio"
|
||||
class="radio"
|
||||
value="dueMonth"
|
||||
@change="setFilter"
|
||||
@click="beforeSetFilter">
|
||||
<label for="dueMonth">{{ t('deck', 'Next 30 days') }}</label>
|
||||
</div>
|
||||
|
||||
<div class="filter--item">
|
||||
<input id="noDue"
|
||||
v-model="filter.due"
|
||||
type="radio"
|
||||
class="radio"
|
||||
value="noDue"
|
||||
@change="setFilter"
|
||||
@click="beforeSetFilter">
|
||||
<label for="noDue">{{ t('deck', 'No due date') }}</label>
|
||||
</div>
|
||||
|
||||
<Button :disabled="!isFilterActive" :wide="true" @click="clearFilter">
|
||||
{{ t('deck', 'Clear filter') }}
|
||||
</Button>
|
||||
</div>
|
||||
</Popover>
|
||||
</div>
|
||||
|
||||
<Actions>
|
||||
<ActionButton
|
||||
icon="icon-archive"
|
||||
@click="toggleShowArchived">
|
||||
<ActionButton @click="toggleShowArchived">
|
||||
<template #icon>
|
||||
<ArchiveIcon :size="20" decorative />
|
||||
</template>
|
||||
{{ showArchived ? t('deck', 'Hide archived cards') : t('deck', 'Show archived cards') }}
|
||||
</ActionButton>
|
||||
<ActionButton v-if="compactMode"
|
||||
icon="icon-toggle-compact-collapsed"
|
||||
@click="toggleCompactMode">
|
||||
<ArrowExpandVerticalIcon slot="icon" :size="20" decorative />
|
||||
{{ t('deck', 'Toggle compact mode') }}
|
||||
</ActionButton>
|
||||
<ActionButton v-else
|
||||
icon="icon-toggle-compact-expanded"
|
||||
@click="toggleCompactMode">
|
||||
<ArrowCollapseVerticalIcon slot="icon" :size="20" decorative />
|
||||
{{ t('deck', 'Toggle compact mode') }}
|
||||
</ActionButton>
|
||||
</Actions>
|
||||
@@ -208,14 +213,29 @@
|
||||
|
||||
<script>
|
||||
import { mapState, mapGetters } from 'vuex'
|
||||
import { Actions, ActionButton, Popover, Avatar } from '@nextcloud/vue'
|
||||
import { Actions, ActionButton, Avatar, Button, Popover } from '@nextcloud/vue'
|
||||
import labelStyle from '../mixins/labelStyle'
|
||||
import CardCreateDialog from '../CardCreateDialog'
|
||||
import ArchiveIcon from 'vue-material-design-icons/Archive'
|
||||
import FilterIcon from 'vue-material-design-icons/Filter'
|
||||
import FilterOffIcon from 'vue-material-design-icons/FilterOff'
|
||||
import ArrowCollapseVerticalIcon from 'vue-material-design-icons/ArrowCollapseVertical'
|
||||
import ArrowExpandVerticalIcon from 'vue-material-design-icons/ArrowExpandVertical'
|
||||
|
||||
export default {
|
||||
name: 'Controls',
|
||||
components: {
|
||||
Actions, ActionButton, Popover, Avatar, CardCreateDialog,
|
||||
Actions,
|
||||
ActionButton,
|
||||
Button,
|
||||
Popover,
|
||||
Avatar,
|
||||
CardCreateDialog,
|
||||
ArchiveIcon,
|
||||
FilterIcon,
|
||||
FilterOffIcon,
|
||||
ArrowCollapseVerticalIcon,
|
||||
ArrowExpandVerticalIcon,
|
||||
},
|
||||
mixins: [labelStyle],
|
||||
props: {
|
||||
@@ -258,18 +278,12 @@ export default {
|
||||
}
|
||||
},
|
||||
isFilterActive() {
|
||||
if (this.filter.tags.length !== 0 || this.filter.users.length !== 0 || this.filter.due !== '') {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return this.filter.tags.length !== 0 || this.filter.users.length !== 0 || this.filter.due !== ''
|
||||
},
|
||||
labelsSorted() {
|
||||
return [...this.board.labels].sort((a, b) => (a.title < b.title) ? -1 : 1)
|
||||
},
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.setPageTitle('')
|
||||
},
|
||||
watch: {
|
||||
board(current, previous) {
|
||||
if (current?.id !== previous?.id) {
|
||||
@@ -280,6 +294,9 @@ export default {
|
||||
}
|
||||
},
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.setPageTitle('')
|
||||
},
|
||||
methods: {
|
||||
beforeSetFilter(e) {
|
||||
if (this.filter.due === e.target.value) {
|
||||
@@ -408,12 +425,6 @@ export default {
|
||||
|
||||
.board-action-buttons {
|
||||
display: flex;
|
||||
button {
|
||||
border: 0;
|
||||
width: 44px;
|
||||
margin: 0 0 0 -1px;
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.deck-search {
|
||||
@@ -441,8 +452,9 @@ export default {
|
||||
}
|
||||
|
||||
.filter {
|
||||
width: 250px;
|
||||
max-height: 80vh;
|
||||
width: 240px;
|
||||
max-height: calc(100vh - 150px);
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
padding: 8px;
|
||||
}
|
||||
@@ -451,8 +463,23 @@ export default {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.filter-button {
|
||||
padding: 0;
|
||||
border-radius: 50%;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
|
||||
&:hover, &:focus {
|
||||
background-color: rgba(127,127,127,0.25) !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="scss">
|
||||
.popover:focus {
|
||||
outline: 2px solid var(--color-main-text);
|
||||
}
|
||||
|
||||
.tooltip-inner.popover-inner {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
@@ -46,6 +46,6 @@ export default {
|
||||
z-index: 100;
|
||||
}
|
||||
.app-deck .app-sidebar {
|
||||
z-index: 20000 !important;
|
||||
z-index: 1500 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -163,8 +163,8 @@ export default {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@import '../../css/animations.scss';
|
||||
@import '../../css/variables.scss';
|
||||
@import '../../css/animations';
|
||||
@import '../../css/variables';
|
||||
|
||||
form {
|
||||
text-align: center;
|
||||
@@ -222,6 +222,7 @@ export default {
|
||||
padding: $stack-spacing;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
scrollbar-gutter: stable;
|
||||
padding-top: 15px;
|
||||
margin-top: -10px;
|
||||
}
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
<span>{{ deletedStack.title }}</span>
|
||||
<span class="timestamp">{{ relativeDate(deletedStack.deletedAt*1000) }}</span>
|
||||
</div>
|
||||
<button
|
||||
:title="t('settings', 'Undo')"
|
||||
<button :title="t('settings', 'Undo')"
|
||||
class="app-navigation-entry-deleted-button icon-history"
|
||||
@click="stackUndoDelete(deletedStack)" />
|
||||
</li>
|
||||
@@ -23,8 +22,7 @@
|
||||
<span>{{ deletedCard.title }}</span>
|
||||
<span class="timestamp">{{ relativeDate(deletedCard.deletedAt*1000) }}</span>
|
||||
</div>
|
||||
<button
|
||||
:title="t('settings', 'Undo')"
|
||||
<button :title="t('settings', 'Undo')"
|
||||
class="app-navigation-entry-deleted-button icon-history"
|
||||
@click="cardUndoDelete(deletedCard)" />
|
||||
</li>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<Multiselect
|
||||
v-if="canShare"
|
||||
<Multiselect v-if="canShare"
|
||||
v-model="addAcl"
|
||||
:placeholder="t('deck', 'Share board with a user, group or circle …')"
|
||||
:options="formatedSharees"
|
||||
@@ -21,8 +20,7 @@
|
||||
</template>
|
||||
</Multiselect>
|
||||
|
||||
<ul
|
||||
id="shareWithList"
|
||||
<ul id="shareWithList"
|
||||
class="shareWithList">
|
||||
<li>
|
||||
<Avatar :user="board.owner.uid" />
|
||||
@@ -200,7 +198,7 @@ export default {
|
||||
},
|
||||
clickTransferOwner(newOwner) {
|
||||
OC.dialogs.confirmDestructive(
|
||||
t('deck', 'Are you sure you want to transfer the board {title} for {user}?', { title: this.board.title, user: newOwner }),
|
||||
t('deck', 'Are you sure you want to transfer the board {title} to {user}?', { title: this.board.title, user: newOwner }),
|
||||
t('deck', 'Transfer the board.'),
|
||||
{
|
||||
type: OC.dialogs.YES_NO_BUTTONS,
|
||||
@@ -214,13 +212,13 @@ export default {
|
||||
this.isLoading = true
|
||||
await this.$store.dispatch('transferOwnership', {
|
||||
boardId: this.board.id,
|
||||
newOwner
|
||||
newOwner,
|
||||
})
|
||||
const successMessage = t('deck', 'Transfer the board for {user} successfully', { user: newOwner })
|
||||
const successMessage = t('deck', 'The board has been transferred to {user}', { user: newOwner })
|
||||
showSuccess(successMessage)
|
||||
this.$router.push({ name: 'main' })
|
||||
} catch (e) {
|
||||
const errorMessage = t('deck', 'Failed to transfer the board for {user}', { user: newOwner.user })
|
||||
const errorMessage = t('deck', 'Failed to transfer the board to {user}', { user: newOwner.user })
|
||||
showError(errorMessage)
|
||||
} finally {
|
||||
this.isLoading = false
|
||||
|
||||
@@ -23,19 +23,29 @@
|
||||
|
||||
<template>
|
||||
<div class="stack">
|
||||
<div v-click-outside="stopCardCreation" class="stack__header" :class="{'stack__header--add': showAddCard }">
|
||||
<div v-click-outside="stopCardCreation"
|
||||
class="stack__header"
|
||||
:class="{'stack__header--add': showAddCard }"
|
||||
tabindex="0"
|
||||
:aria-label="stack.title">
|
||||
<transition name="fade" mode="out-in">
|
||||
<h3 v-if="!canManage || isArchived">
|
||||
{{ stack.title }}
|
||||
</h3>
|
||||
<h3 v-else-if="!editing"
|
||||
v-tooltip="stack.title"
|
||||
tabindex="0"
|
||||
:aria-label="stack.title"
|
||||
class="stack__title"
|
||||
@click="startEditing(stack)">
|
||||
@click="startEditing(stack)"
|
||||
@keydown.enter="startEditing(stack)">
|
||||
{{ stack.title }}
|
||||
</h3>
|
||||
<form v-else @submit.prevent="finishedEdit(stack)">
|
||||
<input v-model="copiedStack.title" v-focus type="text">
|
||||
<input v-model="copiedStack.title"
|
||||
v-focus
|
||||
type="text"
|
||||
required="required">
|
||||
<input v-tooltip="t('deck', 'Add a new list')"
|
||||
class="icon-confirm"
|
||||
type="submit"
|
||||
@@ -44,9 +54,15 @@
|
||||
</transition>
|
||||
<Actions v-if="canManage && !isArchived" :force-menu="true">
|
||||
<ActionButton v-if="!showArchived" icon="icon-archive" @click="modalArchivAllCardsShow=true">
|
||||
<template #icon>
|
||||
<ArchiveIcon decorative />
|
||||
</template>
|
||||
{{ t('deck', 'Archive all cards') }}
|
||||
</ActionButton>
|
||||
<ActionButton v-if="showArchived" icon="icon-archive" @click="modalArchivAllCardsShow=true">
|
||||
<ActionButton v-if="showArchived" @click="modalArchivAllCardsShow=true">
|
||||
<template #icon>
|
||||
<ArchiveIcon decorative />
|
||||
</template>
|
||||
{{ t('deck', 'Unarchive all cards') }}
|
||||
</ActionButton>
|
||||
<ActionButton icon="icon-delete" @click="deleteStack(stack)">
|
||||
@@ -111,12 +127,14 @@
|
||||
non-drag-area-selector=".dragDisabled"
|
||||
:drag-handle-selector="dragHandleSelector"
|
||||
@should-accept-drop="canEdit"
|
||||
@drag-start="draggingCard = true"
|
||||
@drag-end="draggingCard = false"
|
||||
@drop="($event) => onDropCard(stack.id, $event)">
|
||||
<Draggable v-for="card in cardsByStack" :key="card.id">
|
||||
<transition :appear="animate && !card.animated && (card.animated=true)"
|
||||
:appear-class="'zoom-appear-class'"
|
||||
:appear-active-class="'zoom-appear-active-class'">
|
||||
<CardItem :id="card.id" />
|
||||
<CardItem :id="card.id" :dragging="draggingCard" />
|
||||
</transition>
|
||||
</Draggable>
|
||||
</Container>
|
||||
@@ -133,6 +151,7 @@ import { showError, showUndo } from '@nextcloud/dialogs'
|
||||
import CardItem from '../cards/CardItem'
|
||||
|
||||
import '@nextcloud/dialogs/styles/toast.scss'
|
||||
import ArchiveIcon from 'vue-material-design-icons/Archive'
|
||||
|
||||
export default {
|
||||
name: 'Stack',
|
||||
@@ -143,6 +162,7 @@ export default {
|
||||
Container,
|
||||
Draggable,
|
||||
Modal,
|
||||
ArchiveIcon,
|
||||
},
|
||||
|
||||
props: {
|
||||
@@ -154,6 +174,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
editing: false,
|
||||
draggingCard: false,
|
||||
copiedStack: '',
|
||||
newCardTitle: '',
|
||||
showAddCard: false,
|
||||
@@ -288,7 +309,7 @@ export default {
|
||||
@import './../../css/variables';
|
||||
|
||||
.stack {
|
||||
width: $stack-width + $stack-spacing*3;
|
||||
width: $stack-width + $stack-spacing * 3;
|
||||
margin-left: math.div($stack-spacing, 2);
|
||||
margin-right: math.div($stack-spacing, 2);
|
||||
}
|
||||
@@ -337,36 +358,47 @@ export default {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
cursor: inherit;
|
||||
margin: 0;
|
||||
|
||||
input[type=text] {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.stack__title {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: calc($stack-width - 60px);
|
||||
h3.stack__title {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: calc($stack-width - 60px);
|
||||
border-radius: 3px;
|
||||
margin: 6px;
|
||||
padding: 4px 4px;
|
||||
|
||||
&:focus {
|
||||
outline: 2px solid var(--color-border-dark);
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
form {
|
||||
margin: 2px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.stack__card-add {
|
||||
width: $stack-width;
|
||||
height: 44px;
|
||||
flex-shrink: 0;
|
||||
z-index: 100;
|
||||
display: flex;
|
||||
margin-left: 12px;
|
||||
margin-right: 12px;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 20px;
|
||||
background-color: var(--color-main-background);
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
margin-left: 12px;
|
||||
margin-right: 12px;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
box-shadow: 0 0 3px var(--color-box-shadow);
|
||||
border-radius: var(--border-radius-large);
|
||||
overflow: hidden;
|
||||
|
||||
@@ -109,7 +109,7 @@ import relativeDate from '../../mixins/relativeDate'
|
||||
import { formatFileSize } from '@nextcloud/files'
|
||||
import { getCurrentUser } from '@nextcloud/auth'
|
||||
import { generateUrl, generateOcsUrl, generateRemoteUrl } from '@nextcloud/router'
|
||||
import { mapState } from 'vuex'
|
||||
import { mapState, mapActions } from 'vuex'
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
import attachmentUpload from '../../mixins/attachmentUpload'
|
||||
import { getFilePickerBuilder } from '@nextcloud/dialogs'
|
||||
@@ -205,11 +205,14 @@ export default {
|
||||
cardId: {
|
||||
immediate: true,
|
||||
handler() {
|
||||
this.$store.dispatch('fetchAttachments', this.cardId)
|
||||
this.fetchAttachments(this.cardId)
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapActions([
|
||||
'fetchAttachments',
|
||||
]),
|
||||
handleUploadFile(event) {
|
||||
const files = event.target.files ?? []
|
||||
for (const file of files) {
|
||||
@@ -233,7 +236,7 @@ export default {
|
||||
shareType: 12,
|
||||
shareWith: '' + this.cardId,
|
||||
}).then(() => {
|
||||
this.$store.dispatch('fetchAttachments', this.cardId)
|
||||
this.fetchAttachments(this.cardId)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
@@ -57,13 +57,14 @@
|
||||
|
||||
<AppSidebarTab id="attachments"
|
||||
:order="1"
|
||||
:name="t('deck', 'Attachments')"
|
||||
icon="icon-attach">
|
||||
:name="t('deck', 'Attachments')">
|
||||
<template #icon>
|
||||
<AttachmentIcon size="20" decorative />
|
||||
</template>
|
||||
<CardSidebarTabAttachments :card="currentCard" />
|
||||
</AppSidebarTab>
|
||||
|
||||
<AppSidebarTab
|
||||
id="comments"
|
||||
<AppSidebarTab id="comments"
|
||||
:order="2"
|
||||
:name="t('deck', 'Comments')"
|
||||
icon="icon-comment">
|
||||
@@ -90,6 +91,7 @@ import CardSidebarTabComments from './CardSidebarTabComments'
|
||||
import CardSidebarTabActivity from './CardSidebarTabActivity'
|
||||
import relativeDate from '../../mixins/relativeDate'
|
||||
import moment from '@nextcloud/moment'
|
||||
import AttachmentIcon from 'vue-material-design-icons/Paperclip.vue'
|
||||
|
||||
import { showError } from '@nextcloud/dialogs'
|
||||
import { getLocale } from '@nextcloud/l10n'
|
||||
@@ -106,6 +108,7 @@ export default {
|
||||
CardSidebarTabComments,
|
||||
CardSidebarTabActivity,
|
||||
CardSidebarTabDetails,
|
||||
AttachmentIcon,
|
||||
},
|
||||
mixins: [relativeDate],
|
||||
props: {
|
||||
@@ -217,14 +220,18 @@ export default {
|
||||
.modal__card .app-sidebar {
|
||||
$modal-padding: 14px;
|
||||
border: 0;
|
||||
min-width: calc(100% - #{$modal-padding*2});
|
||||
min-width: calc(100% - #{$modal-padding * 2});
|
||||
position: relative;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
max-width: calc(100% - #{$modal-padding*2});
|
||||
max-width: calc(100% - #{$modal-padding * 2});
|
||||
padding: 0 14px;
|
||||
max-height: 100%;
|
||||
overflow: initial;
|
||||
user-select: text;
|
||||
-webkit-user-select: text;
|
||||
|
||||
&::v-deep {
|
||||
.app-sidebar-header {
|
||||
position: sticky;
|
||||
@@ -240,6 +247,10 @@ export default {
|
||||
background-color: var(--color-main-background);
|
||||
}
|
||||
|
||||
.app-sidebar__tab {
|
||||
overflow: initial;
|
||||
}
|
||||
|
||||
#emptycontent, .emptycontent {
|
||||
margin-top: 88px;
|
||||
}
|
||||
|
||||
@@ -21,8 +21,7 @@
|
||||
-->
|
||||
|
||||
<template>
|
||||
<AttachmentList
|
||||
:card-id="card.id"
|
||||
<AttachmentList :card-id="card.id"
|
||||
:removable="true"
|
||||
@delete-attachment="deleteAttachment"
|
||||
@restore-attachment="restoreAttachment" />
|
||||
|
||||
@@ -388,9 +388,11 @@ export default {
|
||||
|
||||
.section-details {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
button.action-item--single {
|
||||
margin-top: -6px;
|
||||
margin-top: -3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,10 @@
|
||||
{{ comment.actorDisplayName }}
|
||||
</span>
|
||||
<Actions v-show="!edit" :force-menu="true">
|
||||
<ActionButton icon="icon-reply" :close-after-click="true" @click="replyTo()">
|
||||
<ActionButton :close-after-click="true" @click="replyTo()">
|
||||
<template #icon>
|
||||
<ReplyIcon decorative />
|
||||
</template>
|
||||
{{ t('deck', 'Reply') }}
|
||||
</ActionButton>
|
||||
<ActionButton v-if="canEdit"
|
||||
@@ -51,8 +54,7 @@
|
||||
</div>
|
||||
<CommentItem v-if="comment.replyTo" :reply="true" :comment="comment.replyTo" />
|
||||
<div v-show="!edit" ref="richTextElement">
|
||||
<RichText
|
||||
class="comment--content"
|
||||
<RichText class="comment--content"
|
||||
:text="richText(comment)"
|
||||
:arguments="richArgs(comment)"
|
||||
:autolink="true" />
|
||||
@@ -68,6 +70,7 @@ import CommentForm from './CommentForm'
|
||||
import { getCurrentUser } from '@nextcloud/auth'
|
||||
import md5 from 'blueimp-md5'
|
||||
import relativeDate from '../../mixins/relativeDate'
|
||||
import ReplyIcon from 'vue-material-design-icons/Reply'
|
||||
|
||||
const AtMention = {
|
||||
name: 'AtMention',
|
||||
@@ -91,6 +94,7 @@ export default {
|
||||
ActionButton,
|
||||
CommentForm,
|
||||
RichText,
|
||||
ReplyIcon,
|
||||
},
|
||||
mixins: [relativeDate],
|
||||
props: {
|
||||
|
||||
@@ -39,7 +39,10 @@
|
||||
</ActionButton>
|
||||
</Actions>
|
||||
<Actions v-if="canEdit">
|
||||
<ActionButton v-if="descriptionEditing" icon="icon-attach" @click="showAttachmentModal()">
|
||||
<ActionButton v-if="descriptionEditing" @click="showAttachmentModal()">
|
||||
<template #icon>
|
||||
<PaperclipIcon :size="24" decorative />
|
||||
</template>
|
||||
{{ t('deck', 'Add Attachment') }}
|
||||
</ActionButton>
|
||||
</Actions>
|
||||
@@ -63,8 +66,7 @@
|
||||
<Modal v-if="modalShow" :title="t('deck', 'Choose attachment')" @close="modalShow=false">
|
||||
<div class="modal__content">
|
||||
<h3>{{ t('deck', 'Choose attachment') }}</h3>
|
||||
<AttachmentList
|
||||
:card-id="card.id"
|
||||
<AttachmentList :card-id="card.id"
|
||||
:selectable="true"
|
||||
@select-attachment="addAttachment" />
|
||||
</div>
|
||||
@@ -74,18 +76,19 @@
|
||||
|
||||
<script>
|
||||
import MarkdownIt from 'markdown-it'
|
||||
import MarkdownItTaskLists from 'markdown-it-task-lists'
|
||||
import MarkdownItTaskCheckbox from 'markdown-it-task-checkbox'
|
||||
import MarkdownItLinkAttributes from 'markdown-it-link-attributes'
|
||||
import AttachmentList from './AttachmentList'
|
||||
import { Actions, ActionButton, Modal } from '@nextcloud/vue'
|
||||
import { formatFileSize } from '@nextcloud/files'
|
||||
import { generateUrl } from '@nextcloud/router'
|
||||
import { mapState, mapGetters } from 'vuex'
|
||||
import PaperclipIcon from 'vue-material-design-icons/Paperclip'
|
||||
|
||||
const markdownIt = new MarkdownIt({
|
||||
linkify: true,
|
||||
})
|
||||
markdownIt.use(MarkdownItTaskLists, { enabled: true, label: true, labelAfter: true })
|
||||
markdownIt.use(MarkdownItTaskCheckbox, { disabled: false, idPrefix: 'task-item-', ulClass: 'contains-task-list' })
|
||||
|
||||
markdownIt.use(MarkdownItLinkAttributes, {
|
||||
attrs: {
|
||||
@@ -102,6 +105,7 @@ export default {
|
||||
ActionButton,
|
||||
Modal,
|
||||
AttachmentList,
|
||||
PaperclipIcon,
|
||||
},
|
||||
props: {
|
||||
card: {
|
||||
@@ -264,6 +268,7 @@ export default {
|
||||
overflow-x: auto;
|
||||
|
||||
&::v-deep {
|
||||
/* stylelint-disable-next-line no-invalid-position-at-import-rule */
|
||||
@import './../../css/markdown';
|
||||
}
|
||||
|
||||
@@ -324,6 +329,12 @@ h5 {
|
||||
border-left: 1px solid var(--color-main-text);
|
||||
}
|
||||
|
||||
.CodeMirror-selected,
|
||||
.CodeMirror-line::selection, .CodeMirror-line>span::selection, .CodeMirror-line>span>span::selection {
|
||||
background: var(--color-primary-element) !important;
|
||||
color: var(--color-primary-text) !important;
|
||||
}
|
||||
|
||||
.editor-preview,
|
||||
.editor-statusbar {
|
||||
display: none;
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
:user="user.participant.uid"
|
||||
:display-name="user.participant.displayname"
|
||||
:disable-menu="true"
|
||||
:show-user-status="false"
|
||||
:size="32" />
|
||||
<Avatar v-if="user.type === 1"
|
||||
:user="user.participant.uid"
|
||||
@@ -56,8 +57,7 @@
|
||||
|
||||
<div class="avatar-print-list">
|
||||
<div v-for="user in avatarUsers" :key="user.id" class="avatar-print-list-item">
|
||||
<Avatar
|
||||
class="avatar-print-list-avatar"
|
||||
<Avatar class="avatar-print-list-avatar"
|
||||
:user="user.participant.uid"
|
||||
:display-name="user.participant.displayname"
|
||||
:disable-menu="true"
|
||||
|
||||
@@ -24,19 +24,23 @@
|
||||
<div v-if="card" class="badges">
|
||||
<div v-if="card.commentsCount > 0"
|
||||
v-tooltip="commentsHint"
|
||||
class="icon icon-comment"
|
||||
:class="{ 'icon-comment--unread': card.commentsUnread > 0 }"
|
||||
class="icon-badge"
|
||||
@click.stop="openComments">
|
||||
{{ card.commentsCount }}
|
||||
<CommentUnreadIcon v-if="card.commentsUnread > 0" size="16" />
|
||||
<CommentIcon v-else size="16" />
|
||||
<span>{{ card.commentsCount }}</span>
|
||||
</div>
|
||||
|
||||
<div v-if="card.description && checkListCount > 0" class="card-tasks icon icon-checkmark">
|
||||
{{ checkListCheckedCount }}/{{ checkListCount }}
|
||||
<div v-if="card.description && checkListCount > 0" class="icon-badge">
|
||||
<CheckmarkIcon :size="16" :title="t('deck', 'Todo items')" />
|
||||
<span>{{ checkListCheckedCount }}/{{ checkListCount }}</span>
|
||||
</div>
|
||||
<div v-else-if="card.description.trim() && checkListCount == 0" class="icon icon-description" />
|
||||
|
||||
<div v-if="card.attachmentCount > 0" class="icon-attach icon icon-attach-dark">
|
||||
{{ card.attachmentCount }}
|
||||
<TextIcon v-else-if="card.description.trim() && checkListCount == 0" size="16" decorative />
|
||||
|
||||
<div v-if="card.attachmentCount > 0" class="icon-badge">
|
||||
<AttachmentIcon size="16" />
|
||||
<span>{{ card.attachmentCount }}</span>
|
||||
</div>
|
||||
|
||||
<AvatarList :users="card.assignedUsers" />
|
||||
@@ -47,10 +51,15 @@
|
||||
<script>
|
||||
import AvatarList from './AvatarList'
|
||||
import CardMenu from './CardMenu'
|
||||
import TextIcon from 'vue-material-design-icons/Text.vue'
|
||||
import AttachmentIcon from 'vue-material-design-icons/Paperclip.vue'
|
||||
import CheckmarkIcon from 'vue-material-design-icons/CheckboxMarked.vue'
|
||||
import CommentIcon from 'vue-material-design-icons/Comment.vue'
|
||||
import CommentUnreadIcon from 'vue-material-design-icons/CommentAccount.vue'
|
||||
|
||||
export default {
|
||||
name: 'CardBadges',
|
||||
components: { AvatarList, CardMenu },
|
||||
components: { AvatarList, CardMenu, TextIcon, AttachmentIcon, CheckmarkIcon, CommentIcon, CommentUnreadIcon },
|
||||
props: {
|
||||
card: {
|
||||
type: Object,
|
||||
@@ -89,18 +98,13 @@ export default {
|
||||
width: 100%;
|
||||
flex-grow: 1;
|
||||
|
||||
.icon {
|
||||
opacity: 0.5;
|
||||
padding: 10px 20px;
|
||||
padding-right: 4px;
|
||||
margin-right: 5px;
|
||||
background-position: left;
|
||||
background-size: 16px;
|
||||
.icon-badge {
|
||||
opacity: .7;
|
||||
display: flex;
|
||||
margin-right: 2px;
|
||||
|
||||
span {
|
||||
margin-left: 18px;
|
||||
}
|
||||
&.icon-comment--unread {
|
||||
opacity: 1;
|
||||
padding: 10px 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,14 +35,18 @@
|
||||
{{ board.title }} » {{ stack.title }}
|
||||
</div>
|
||||
<div class="card-upper">
|
||||
<h3 v-if="compactMode || isArchived || showArchived || !canEdit || standalone">
|
||||
<h3 v-if="inlineEditingBlocked">
|
||||
{{ card.title }}
|
||||
</h3>
|
||||
<h3 v-else-if="!editing">
|
||||
<span @click.stop="startEditing(card)">{{ card.title }}</span>
|
||||
<h3 v-else-if="!editing"
|
||||
tabindex="0"
|
||||
class="editable"
|
||||
:aria-label="t('deck', 'Edit card title')"
|
||||
@click.stop="startEditing(card)"
|
||||
@keydown.enter.stop.prevent="startEditing(card)">
|
||||
{{ card.title }}
|
||||
</h3>
|
||||
|
||||
<form v-if="editing"
|
||||
<form v-else-if="editing"
|
||||
v-click-outside="cancelEdit"
|
||||
class="dragDisabled"
|
||||
@click.stop
|
||||
@@ -106,6 +110,10 @@ export default {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
dragging: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -135,6 +143,9 @@ export default {
|
||||
const board = this.$store.getters.boards.find((item) => item.id === this.card.boardId)
|
||||
return board ? !board.archived && board.permissions.PERMISSION_EDIT : false
|
||||
},
|
||||
inlineEditingBlocked() {
|
||||
return this.compactMode || this.isArchived || this.showArchived || !this.canEdit || this.standalone
|
||||
},
|
||||
card() {
|
||||
return this.item ? this.item : this.$store.getters.cardById(this.id)
|
||||
},
|
||||
@@ -154,6 +165,9 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
openCard() {
|
||||
if (this.dragging) {
|
||||
return
|
||||
}
|
||||
const boardId = this.card && this.card.boardId ? this.card.boardId : this.$route.params.id
|
||||
this.$router.push({ name: 'card', params: { id: boardId, cardId: this.card.id } }).catch(() => {})
|
||||
},
|
||||
@@ -171,6 +185,9 @@ export default {
|
||||
this.editing = false
|
||||
},
|
||||
applyLabelFilter(label) {
|
||||
if (this.dragging) {
|
||||
return
|
||||
}
|
||||
this.$nextTick(() => this.$store.dispatch('toggleFilter', { tags: [label.id] }))
|
||||
},
|
||||
},
|
||||
@@ -217,14 +234,20 @@ export default {
|
||||
|
||||
}
|
||||
h3 {
|
||||
margin: 12px $card-padding;
|
||||
margin: 5px $card-padding;
|
||||
padding: 6px;
|
||||
flex-grow: 1;
|
||||
font-size: 100%;
|
||||
overflow: hidden;
|
||||
word-wrap: break-word;
|
||||
padding-left: 4px;
|
||||
span {
|
||||
&.editable {
|
||||
cursor: text;
|
||||
|
||||
&:focus {
|
||||
outline: 2px solid var(--color-border-dark);
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
input[type=text] {
|
||||
@@ -232,6 +255,7 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
/* stylelint-disable-next-line no-invalid-position-at-import-rule */
|
||||
@import './../../css/labels';
|
||||
|
||||
.card-controls {
|
||||
|
||||
@@ -40,9 +40,13 @@
|
||||
{{ t('deck', 'Move card') }}
|
||||
</ActionButton>
|
||||
<ActionButton icon="icon-settings-dark" :close-after-click="true" @click="openCard">
|
||||
<CardBulletedIcon slot="icon" :size="20" decorative />
|
||||
{{ t('deck', 'Card details') }}
|
||||
</ActionButton>
|
||||
<ActionButton icon="icon-archive" :close-after-click="true" @click="archiveUnarchiveCard()">
|
||||
<ActionButton :close-after-click="true" @click="archiveUnarchiveCard()">
|
||||
<template #icon>
|
||||
<ArchiveIcon :size="20" decorative />
|
||||
</template>
|
||||
{{ card.archived ? t('deck', 'Unarchive card') : t('deck', 'Archive card') }}
|
||||
</ActionButton>
|
||||
<ActionButton v-if="showArchived === false"
|
||||
@@ -90,10 +94,12 @@ import { generateUrl } from '@nextcloud/router'
|
||||
import { getCurrentUser } from '@nextcloud/auth'
|
||||
import { showUndo } from '@nextcloud/dialogs'
|
||||
import '@nextcloud/dialogs/styles/toast.scss'
|
||||
import ArchiveIcon from 'vue-material-design-icons/Archive'
|
||||
import CardBulletedIcon from 'vue-material-design-icons/CardBulleted'
|
||||
|
||||
export default {
|
||||
name: 'CardMenu',
|
||||
components: { Actions, ActionButton, Modal, Multiselect },
|
||||
components: { Actions, ActionButton, Modal, Multiselect, ArchiveIcon, CardBulletedIcon },
|
||||
props: {
|
||||
card: {
|
||||
type: Object,
|
||||
@@ -135,7 +141,11 @@ export default {
|
||||
},
|
||||
activeBoards() {
|
||||
return this.$store.getters.boards.filter((item) => item.deletedAt === 0 && item.archived === false)
|
||||
}
|
||||
},
|
||||
|
||||
boardId() {
|
||||
return this.card?.boardId ? this.card.boardId : this.$route.params.id
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
openCard() {
|
||||
@@ -167,10 +177,13 @@ export default {
|
||||
},
|
||||
})
|
||||
},
|
||||
moveCard() {
|
||||
async moveCard() {
|
||||
this.copiedCard = Object.assign({}, this.card)
|
||||
this.copiedCard.stackId = this.selectedStack.id
|
||||
this.$store.dispatch('moveCard', this.copiedCard)
|
||||
if (parseInt(this.boardId) === parseInt(this.selectedStack.boardId)) {
|
||||
await this.$store.commit('addNewCard', { ...this.copiedCard })
|
||||
}
|
||||
this.modalShow = false
|
||||
},
|
||||
async loadStacksFromBoard(board) {
|
||||
|
||||
@@ -23,26 +23,25 @@
|
||||
<template>
|
||||
<AppNavigationVue :class="{'icon-loading': loading}">
|
||||
<template #list>
|
||||
<AppNavigationItem
|
||||
:title="t('deck', 'Upcoming cards')"
|
||||
<AppNavigationItem :title="t('deck', 'Upcoming cards')"
|
||||
icon="icon-calendar-dark"
|
||||
:exact="true"
|
||||
to="/" />
|
||||
<AppNavigationBoardCategory
|
||||
id="deck-navigation-all"
|
||||
<AppNavigationBoardCategory id="deck-navigation-all"
|
||||
to="/board"
|
||||
:text="t('deck', 'All boards')"
|
||||
:boards="noneArchivedBoards"
|
||||
:open-on-add-boards="true"
|
||||
icon="icon-deck" />
|
||||
<AppNavigationBoardCategory
|
||||
id="deck-navigation-archived"
|
||||
<AppNavigationBoardCategory id="deck-navigation-archived"
|
||||
to="/board/archived"
|
||||
:text="t('deck', 'Archived boards')"
|
||||
:boards="archivedBoards"
|
||||
icon="icon-archive" />
|
||||
<AppNavigationBoardCategory
|
||||
id="deck-navigation-shared"
|
||||
:boards="archivedBoards">
|
||||
<template #icon>
|
||||
<ArchiveIcon :size="20" decorative />
|
||||
</template>
|
||||
</AppNavigationBoardCategory>
|
||||
<AppNavigationBoardCategory id="deck-navigation-shared"
|
||||
to="/board/shared"
|
||||
:text="t('deck', 'Shared with you')"
|
||||
:boards="sharedBoards"
|
||||
@@ -50,7 +49,7 @@
|
||||
<AppNavigationAddBoard v-if="canCreate" />
|
||||
</template>
|
||||
<template #footer>
|
||||
<AppNavigationSettings>
|
||||
<AppNavigationSettings :title="t('deck', 'Deck settings')">
|
||||
<div>
|
||||
<div>
|
||||
<input id="toggle-modal"
|
||||
@@ -102,6 +101,7 @@ import AppNavigationBoardCategory from './AppNavigationBoardCategory'
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
import { generateOcsUrl } from '@nextcloud/router'
|
||||
import { getCurrentUser } from '@nextcloud/auth'
|
||||
import ArchiveIcon from 'vue-material-design-icons/Archive'
|
||||
|
||||
const canCreateState = loadState('deck', 'canCreate')
|
||||
|
||||
@@ -114,6 +114,7 @@ export default {
|
||||
AppNavigationBoardCategory,
|
||||
Multiselect,
|
||||
AppNavigationItem,
|
||||
ArchiveIcon,
|
||||
},
|
||||
directives: {
|
||||
ClickOutside,
|
||||
|
||||
@@ -35,8 +35,7 @@
|
||||
|
||||
<template v-if="!deleted" slot="actions">
|
||||
<template v-if="!isDueSubmenuActive">
|
||||
<ActionButton
|
||||
icon="icon-info"
|
||||
<ActionButton icon="icon-info"
|
||||
:close-after-click="true"
|
||||
@click="actionDetails">
|
||||
{{ t('deck', 'Board details') }}
|
||||
@@ -48,21 +47,27 @@
|
||||
{{ t('deck', 'Edit board') }}
|
||||
</ActionButton>
|
||||
<ActionButton v-if="canManage && !board.archived"
|
||||
icon="icon-clone"
|
||||
:close-after-click="true"
|
||||
@click="actionClone">
|
||||
<template #icon>
|
||||
<CloneIcon :size="20" decorative />
|
||||
</template>
|
||||
{{ t('deck', 'Clone board') }}
|
||||
</ActionButton>
|
||||
<ActionButton v-if="canManage && board.archived"
|
||||
icon="icon-archive"
|
||||
:close-after-click="true"
|
||||
@click="actionUnarchive">
|
||||
<template #icon>
|
||||
<ArchiveIcon :size="20" decorative />
|
||||
</template>
|
||||
{{ t('deck', 'Unarchive board') }}
|
||||
</ActionButton>
|
||||
<ActionButton v-else-if="canManage && !board.archived"
|
||||
icon="icon-archive"
|
||||
:close-after-click="true"
|
||||
@click="actionArchive">
|
||||
<template #icon>
|
||||
<ArchiveIcon :size="20" decorative />
|
||||
</template>
|
||||
{{ t('deck', 'Archive board') }}
|
||||
</ActionButton>
|
||||
|
||||
@@ -73,31 +78,27 @@
|
||||
|
||||
<!-- Due date reminder settings -->
|
||||
<template v-if="isDueSubmenuActive">
|
||||
<ActionButton
|
||||
:icon="updateDueSetting ? 'icon-loading-small' : 'icon-view-previous'"
|
||||
<ActionButton :icon="updateDueSetting ? 'icon-loading-small' : 'icon-view-previous'"
|
||||
:disabled="updateDueSetting"
|
||||
@click="isDueSubmenuActive=false">
|
||||
{{ t('deck', 'Due date reminders') }}
|
||||
</ActionButton>
|
||||
|
||||
<ActionButton
|
||||
name="notification"
|
||||
<ActionButton name="notification"
|
||||
icon="icon-sound"
|
||||
:disabled="updateDueSetting"
|
||||
:class="{ 'forced-active': board.settings['notify-due'] === 'all' }"
|
||||
@click="updateSetting('notify-due', 'all')">
|
||||
{{ t('deck', 'All cards') }}
|
||||
</ActionButton>
|
||||
<ActionButton
|
||||
name="notification"
|
||||
<ActionButton name="notification"
|
||||
icon="icon-user"
|
||||
:disabled="updateDueSetting"
|
||||
:class="{ 'forced-active': board.settings['notify-due'] === 'assigned' }"
|
||||
@click="updateSetting('notify-due', 'assigned')">
|
||||
{{ t('deck', 'Assigned cards') }}
|
||||
</ActionButton>
|
||||
<ActionButton
|
||||
name="notification"
|
||||
<ActionButton name="notification"
|
||||
icon="icon-sound-off"
|
||||
:disabled="updateDueSetting"
|
||||
:class="{ 'forced-active': board.settings['notify-due'] === 'off' }"
|
||||
@@ -138,6 +139,8 @@
|
||||
<script>
|
||||
import { AppNavigationIconBullet, AppNavigationCounter, AppNavigationItem, ColorPicker, Actions, ActionButton } from '@nextcloud/vue'
|
||||
import ClickOutside from 'vue-click-outside'
|
||||
import ArchiveIcon from 'vue-material-design-icons/Archive'
|
||||
import CloneIcon from 'vue-material-design-icons/ContentDuplicate'
|
||||
|
||||
export default {
|
||||
name: 'AppNavigationBoard',
|
||||
@@ -148,6 +151,8 @@ export default {
|
||||
ColorPicker,
|
||||
Actions,
|
||||
ActionButton,
|
||||
ArchiveIcon,
|
||||
CloneIcon,
|
||||
},
|
||||
directives: {
|
||||
ClickOutside,
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
:allow-collapse="collapsible"
|
||||
:open="opened">
|
||||
<AppNavigationBoard v-for="board in boardsSorted" :key="board.id" :board="board" />
|
||||
<template #icon>
|
||||
<slot name="icon" />
|
||||
</template>
|
||||
</AppNavigationItem>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -173,7 +173,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../../css/variables.scss';
|
||||
@import '../../css/variables';
|
||||
|
||||
.global-search {
|
||||
width: 100%;
|
||||
|
||||
@@ -18,8 +18,7 @@
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
<svg
|
||||
class="card-placeholder__placeholder"
|
||||
<svg class="card-placeholder__placeholder"
|
||||
:class="{ 'standalone': standalone }"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="url(#card-placeholder__gradient)">
|
||||
@@ -55,7 +54,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../../css/variables.scss';
|
||||
@import '../../css/variables';
|
||||
$clickable-area: 44px;
|
||||
|
||||
.card--placeholder {
|
||||
|
||||
Reference in New Issue
Block a user