Merge pull request #1944 from nextcloud/refactor/navigation
This commit is contained in:
@@ -31,7 +31,7 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="board" class="board-actions">
|
<div v-if="board" class="board-actions">
|
||||||
<div v-if="canManage && !showArchived"
|
<div v-if="canManage && !showArchived && !board.archived"
|
||||||
id="stack-add"
|
id="stack-add"
|
||||||
v-click-outside="hideAddStack">
|
v-click-outside="hideAddStack">
|
||||||
<Actions v-if="!isAddStackVisible" :title="t('deck', 'Add new list')">
|
<Actions v-if="!isAddStackVisible" :title="t('deck', 'Add new list')">
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
<div class="stack">
|
<div class="stack">
|
||||||
<div v-click-outside="stopCardCreation" class="stack--header">
|
<div v-click-outside="stopCardCreation" class="stack--header">
|
||||||
<transition name="fade" mode="out-in">
|
<transition name="fade" mode="out-in">
|
||||||
<h3 v-if="!canManage">
|
<h3 v-if="!canManage || isArchived">
|
||||||
{{ stack.title }}
|
{{ stack.title }}
|
||||||
</h3>
|
</h3>
|
||||||
<h3 v-else-if="!editing"
|
<h3 v-else-if="!editing"
|
||||||
@@ -42,12 +42,12 @@
|
|||||||
value="">
|
value="">
|
||||||
</form>
|
</form>
|
||||||
</transition>
|
</transition>
|
||||||
<Actions v-if="canManage" :force-menu="true">
|
<Actions v-if="canManage && !isArchived" :force-menu="true">
|
||||||
<ActionButton icon="icon-delete" @click="deleteStack(stack)">
|
<ActionButton icon="icon-delete" @click="deleteStack(stack)">
|
||||||
{{ t('deck', 'Delete list') }}
|
{{ t('deck', 'Delete list') }}
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
</Actions>
|
</Actions>
|
||||||
<Actions v-if="canEdit && !showArchived">
|
<Actions v-if="canEdit && !showArchived && !isArchived">
|
||||||
<ActionButton icon="icon-add" @click.stop="showAddCard=true">
|
<ActionButton icon="icon-add" @click.stop="showAddCard=true">
|
||||||
{{ t('deck', 'Add card') }}
|
{{ t('deck', 'Add card') }}
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
@@ -133,6 +133,7 @@ export default {
|
|||||||
...mapGetters([
|
...mapGetters([
|
||||||
'canManage',
|
'canManage',
|
||||||
'canEdit',
|
'canEdit',
|
||||||
|
'isArchived',
|
||||||
]),
|
]),
|
||||||
...mapState({
|
...mapState({
|
||||||
showArchived: state => state.showArchived,
|
showArchived: state => state.showArchived,
|
||||||
|
|||||||
@@ -24,11 +24,11 @@
|
|||||||
<div :style="{ backgroundColor: `#${label.color}`, color:textColor(label.color) }" class="label-title">
|
<div :style="{ backgroundColor: `#${label.color}`, color:textColor(label.color) }" class="label-title">
|
||||||
<span>{{ label.title }}</span>
|
<span>{{ label.title }}</span>
|
||||||
</div>
|
</div>
|
||||||
<button v-if="canManage"
|
<button v-if="canManage && !isArchived"
|
||||||
v-tooltip="t('deck', 'Edit')"
|
v-tooltip="t('deck', 'Edit')"
|
||||||
class="icon-rename"
|
class="icon-rename"
|
||||||
@click="clickEdit(label)" />
|
@click="clickEdit(label)" />
|
||||||
<button v-if="canManage"
|
<button v-if="canManage && !isArchived"
|
||||||
v-tooltip="t('deck', 'Delete')"
|
v-tooltip="t('deck', 'Delete')"
|
||||||
class="icon-delete"
|
class="icon-delete"
|
||||||
@click="deleteLabel(label.id)" />
|
@click="deleteLabel(label.id)" />
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
</form>
|
</form>
|
||||||
</template>
|
</template>
|
||||||
</li>
|
</li>
|
||||||
<button v-if="canManage" @click="clickShowAddLabel()">
|
<button v-if="canManage && !isArchived" @click="clickShowAddLabel()">
|
||||||
<span class="icon-add" />{{ t('deck', 'Add a new tag') }}
|
<span class="icon-add" />{{ t('deck', 'Add a new tag') }}
|
||||||
</button>
|
</button>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -88,6 +88,7 @@ export default {
|
|||||||
...mapGetters({
|
...mapGetters({
|
||||||
labels: 'currentBoardLabels',
|
labels: 'currentBoardLabels',
|
||||||
canManage: 'canManage',
|
canManage: 'canManage',
|
||||||
|
isArchived: 'isArchived',
|
||||||
}),
|
}),
|
||||||
addLabelObjValidated() {
|
addLabelObjValidated() {
|
||||||
if (this.addLabelObj.title === '') {
|
if (this.addLabelObj.title === '') {
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
class="card"
|
class="card"
|
||||||
@click="openCard">
|
@click="openCard">
|
||||||
<div class="card-upper">
|
<div class="card-upper">
|
||||||
<h3 v-if="showArchived || !canEdit">
|
<h3 v-if="isArchived || showArchived || !canEdit">
|
||||||
{{ card.title }}
|
{{ card.title }}
|
||||||
</h3>
|
</h3>
|
||||||
<h3 v-else-if="!editing">
|
<h3 v-else-if="!editing">
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
<input type="button" class="icon-confirm" @click="finishedEdit(card)">
|
<input type="button" class="icon-confirm" @click="finishedEdit(card)">
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div v-if="!editing" class="right">
|
<div v-if="!editing" class="duedate right">
|
||||||
<transition name="zoom">
|
<transition name="zoom">
|
||||||
<div v-if="card.duedate" :class="dueIcon">
|
<div v-if="card.duedate" :class="dueIcon">
|
||||||
<span>{{ relativeDate }}</span>
|
<span>{{ relativeDate }}</span>
|
||||||
@@ -57,7 +57,8 @@
|
|||||||
|
|
||||||
<CardMenu v-if="!editing && compactMode" :id="id" class="right" />
|
<CardMenu v-if="!editing && compactMode" :id="id" class="right" />
|
||||||
</div>
|
</div>
|
||||||
<transition-group name="zoom"
|
<transition-group v-if="card.labels.length"
|
||||||
|
name="zoom"
|
||||||
tag="ul"
|
tag="ul"
|
||||||
class="labels"
|
class="labels"
|
||||||
@click="openCard">
|
@click="openCard">
|
||||||
@@ -109,6 +110,7 @@ export default {
|
|||||||
}),
|
}),
|
||||||
...mapGetters([
|
...mapGetters([
|
||||||
'canEdit',
|
'canEdit',
|
||||||
|
'isArchived',
|
||||||
]),
|
]),
|
||||||
card() {
|
card() {
|
||||||
return this.$store.getters.cardById(this.id)
|
return this.$store.getters.cardById(this.id)
|
||||||
@@ -189,7 +191,7 @@ export default {
|
|||||||
|
|
||||||
.card-upper {
|
.card-upper {
|
||||||
display: flex;
|
display: flex;
|
||||||
min-height: 50px;
|
min-height: 44px;
|
||||||
form {
|
form {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 5px 7px;
|
padding: 5px 7px;
|
||||||
@@ -200,7 +202,7 @@ export default {
|
|||||||
|
|
||||||
}
|
}
|
||||||
h3 {
|
h3 {
|
||||||
margin: 14px $card-padding;
|
margin: 12px $card-padding;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
font-size: 100%;
|
font-size: 100%;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
@@ -257,10 +259,12 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.duedate {
|
||||||
|
margin-right: 9px;
|
||||||
|
}
|
||||||
.right {
|
.right {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
margin-right: 9px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon.due {
|
.icon.due {
|
||||||
@@ -269,6 +273,7 @@ export default {
|
|||||||
margin-top: 9px;
|
margin-top: 9px;
|
||||||
margin-bottom: 9px;
|
margin-bottom: 9px;
|
||||||
padding: 3px 4px;
|
padding: 3px 4px;
|
||||||
|
padding-right: 0;
|
||||||
font-size: 90%;
|
font-size: 90%;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -284,14 +289,17 @@ export default {
|
|||||||
background-color: var(--color-error);
|
background-color: var(--color-error);
|
||||||
color: var(--color-primary-text);
|
color: var(--color-primary-text);
|
||||||
opacity: .7;
|
opacity: .7;
|
||||||
|
padding: 3px 4px;
|
||||||
}
|
}
|
||||||
&.now {
|
&.now {
|
||||||
background-color: var(--color-warning);
|
background-color: var(--color-warning);
|
||||||
opacity: .7;
|
opacity: .7;
|
||||||
|
padding: 3px 4px;
|
||||||
}
|
}
|
||||||
&.next {
|
&.next {
|
||||||
background-color: var(--color-background-dark);
|
background-color: var(--color-background-dark);
|
||||||
opacity: .7;
|
opacity: .7;
|
||||||
|
padding: 3px 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
span {
|
span {
|
||||||
@@ -303,8 +311,11 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.compact {
|
.compact {
|
||||||
min-height: 50px;
|
min-height: 44px;
|
||||||
|
|
||||||
|
.duedate {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
&.has-labels {
|
&.has-labels {
|
||||||
padding-bottom: $card-padding;
|
padding-bottom: $card-padding;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div @click.stop.prevent>
|
<div @click.stop.prevent>
|
||||||
<Actions v-if="canEdit">
|
<Actions v-if="canEdit && !isArchived">
|
||||||
<ActionButton v-if="showArchived === false" icon="icon-user" @click="assignCardToMe()">
|
<ActionButton v-if="showArchived === false" icon="icon-user" @click="assignCardToMe()">
|
||||||
{{ t('deck', 'Assign to me') }}
|
{{ t('deck', 'Assign to me') }}
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
@@ -93,6 +93,7 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
...mapGetters([
|
...mapGetters([
|
||||||
'canEdit',
|
'canEdit',
|
||||||
|
'isArchived',
|
||||||
]),
|
]),
|
||||||
...mapState({
|
...mapState({
|
||||||
showArchived: state => state.showArchived,
|
showArchived: state => state.showArchived,
|
||||||
|
|||||||
@@ -22,23 +22,47 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div id="app-navigation" :class="{'icon-loading': loading}">
|
<div id="app-navigation" :class="{'icon-loading': loading}">
|
||||||
|
<AppNavigationVue>
|
||||||
|
<ul>
|
||||||
|
<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"
|
||||||
|
to="/board/archived"
|
||||||
|
:text="t('deck', 'Archived boards')"
|
||||||
|
:boards="archivedBoards"
|
||||||
|
icon="icon-archive" />
|
||||||
|
<AppNavigationBoardCategory
|
||||||
|
id="deck-navigation-shared"
|
||||||
|
to="/board/shared"
|
||||||
|
:text="t('deck', 'Shared with you')"
|
||||||
|
:boards="sharedBoards"
|
||||||
|
icon="icon-shared" />
|
||||||
|
<AppNavigationAddBoard v-if="canCreate" />
|
||||||
|
</ul>
|
||||||
|
<AppNavigationSettings>
|
||||||
|
<div>
|
||||||
|
<Multiselect v-model="groupLimit"
|
||||||
|
:class="{'icon-loading-small': groupLimitDisabled}"
|
||||||
|
open-direction="bottom"
|
||||||
|
:options="groups"
|
||||||
|
:multiple="true"
|
||||||
|
:disabled="groupLimitDisabled"
|
||||||
|
:placeholder="t('deck', 'Limit deck usage of groups')"
|
||||||
|
label="displayname"
|
||||||
|
track-by="id"
|
||||||
|
@input="updateConfig" />
|
||||||
|
<p>{{ t('deck', 'Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them.') }}</p>
|
||||||
|
</div>
|
||||||
|
</AppNavigationSettings>
|
||||||
|
</AppNavigationVue>
|
||||||
|
|
||||||
<ul id="deck-navigation">
|
<ul id="deck-navigation">
|
||||||
<AppNavigationBoardCategory
|
|
||||||
id="deck-navigation-all"
|
|
||||||
:text="t('deck', 'All boards')"
|
|
||||||
:boards="noneArchivedBoards"
|
|
||||||
:open-on-add-boards="true"
|
|
||||||
icon="icon-deck" />
|
|
||||||
<AppNavigationBoardCategory
|
|
||||||
id="deck-navigation-archived"
|
|
||||||
:text="t('deck', 'Archived boards')"
|
|
||||||
:boards="archivedBoards"
|
|
||||||
icon="icon-archive" />
|
|
||||||
<AppNavigationBoardCategory
|
|
||||||
id="deck-navigation-shared"
|
|
||||||
:text="t('deck', 'Shared boards')"
|
|
||||||
:boards="sharedBoards"
|
|
||||||
icon="icon-shared" />
|
|
||||||
<AppNavigationAddBoard v-if="canCreate" />
|
<AppNavigationAddBoard v-if="canCreate" />
|
||||||
</ul>
|
</ul>
|
||||||
<div v-if="isAdmin"
|
<div v-if="isAdmin"
|
||||||
@@ -50,19 +74,6 @@
|
|||||||
{{ t('deck', 'Settings') }}
|
{{ t('deck', 'Settings') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="app-settings-content">
|
|
||||||
<Multiselect v-model="groupLimit"
|
|
||||||
:class="{'icon-loading-small': groupLimitDisabled}"
|
|
||||||
open-direction="bottom"
|
|
||||||
:options="groups"
|
|
||||||
:multiple="true"
|
|
||||||
:disabled="groupLimitDisabled"
|
|
||||||
:placeholder="t('deck', 'Limit deck usage of groups')"
|
|
||||||
label="displayname"
|
|
||||||
track-by="id"
|
|
||||||
@input="updateConfig" />
|
|
||||||
<p>{{ t('deck', 'Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them.') }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -71,8 +82,7 @@
|
|||||||
import axios from '@nextcloud/axios'
|
import axios from '@nextcloud/axios'
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
import ClickOutside from 'vue-click-outside'
|
import ClickOutside from 'vue-click-outside'
|
||||||
import { Multiselect } from '@nextcloud/vue'
|
import { AppNavigation as AppNavigationVue, AppNavigationSettings, Multiselect } from '@nextcloud/vue'
|
||||||
|
|
||||||
import AppNavigationAddBoard from './AppNavigationAddBoard'
|
import AppNavigationAddBoard from './AppNavigationAddBoard'
|
||||||
import AppNavigationBoardCategory from './AppNavigationBoardCategory'
|
import AppNavigationBoardCategory from './AppNavigationBoardCategory'
|
||||||
import { loadState } from '@nextcloud/initial-state'
|
import { loadState } from '@nextcloud/initial-state'
|
||||||
@@ -83,6 +93,8 @@ const canCreateState = loadState('deck', 'canCreate')
|
|||||||
export default {
|
export default {
|
||||||
name: 'AppNavigation',
|
name: 'AppNavigation',
|
||||||
components: {
|
components: {
|
||||||
|
AppNavigationVue,
|
||||||
|
AppNavigationSettings,
|
||||||
AppNavigationAddBoard,
|
AppNavigationAddBoard,
|
||||||
AppNavigationBoardCategory,
|
AppNavigationBoardCategory,
|
||||||
Multiselect,
|
Multiselect,
|
||||||
|
|||||||
@@ -20,38 +20,30 @@
|
|||||||
-
|
-
|
||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
<li id="deck-navigation-add"
|
<AppNavigationItem v-if="!editing"
|
||||||
:title="t('deck', 'Create new board')"
|
:title="t('deck', 'Create new board')"
|
||||||
:class="[{'icon-loading-small': loading, 'editing': editing}, classes]">
|
icon="icon-add"
|
||||||
<a class="icon-add" href="#" @click.prevent.stop="startCreateBoard">
|
@click.prevent.stop="startCreateBoard" />
|
||||||
{{ t('deck', 'Create new board') }}
|
<div v-else class="board-create">
|
||||||
</a>
|
<ColorPicker v-model="color" class="app-navigation-entry-bullet-wrapper">
|
||||||
|
<div :style="{ backgroundColor: color }" class="color0 icon-colorpicker app-navigation-entry-bullet" />
|
||||||
<!-- edit entry -->
|
</ColorPicker>
|
||||||
<div v-if="editing" class="app-navigation-entry-edit">
|
<form @submit.prevent.stop="createBoard">
|
||||||
<ColorPicker v-model="color" class="app-navigation-entry-bullet-wrapper">
|
<input :placeholder="t('deck', 'New board title')" type="text" required>
|
||||||
<div :style="{ backgroundColor: color }" class="color0 icon-colorpicker app-navigation-entry-bullet" />
|
<input type="submit" value="" class="icon-confirm">
|
||||||
</ColorPicker>
|
<Actions><ActionButton icon="icon-close" @click.stop.prevent="cancelEdit" /></Actions>
|
||||||
<form @submit.prevent.stop="createBoard">
|
</form>
|
||||||
<input :placeholder="t('deck', 'New board title')" type="text" required>
|
</div>
|
||||||
<input type="submit" value="" class="icon-confirm">
|
|
||||||
<input type="submit"
|
|
||||||
value=""
|
|
||||||
class="icon-close"
|
|
||||||
@click.stop.prevent="cancelEdit">
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<!-- <ColorPicker v-model="color" /> -->
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { ColorPicker } from '@nextcloud/vue'
|
import { ColorPicker, ActionButton, Actions, AppNavigationItem } from '@nextcloud/vue'
|
||||||
|
|
||||||
|
const randomColor = () => '#' + ((1 << 24) * Math.random() | 0).toString(16)
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'AppNavigationAddBoard',
|
name: 'AppNavigationAddBoard',
|
||||||
components: { ColorPicker },
|
components: { ColorPicker, AppNavigationItem, ActionButton, Actions },
|
||||||
directives: {},
|
directives: {},
|
||||||
props: {},
|
props: {},
|
||||||
data() {
|
data() {
|
||||||
@@ -59,7 +51,7 @@ export default {
|
|||||||
classes: [],
|
classes: [],
|
||||||
editing: false,
|
editing: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
color: '#000000',
|
color: randomColor(),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {},
|
computed: {},
|
||||||
@@ -76,27 +68,38 @@ export default {
|
|||||||
color: this.color.substring(1),
|
color: this.color.substring(1),
|
||||||
})
|
})
|
||||||
this.editing = false
|
this.editing = false
|
||||||
|
this.color = randomColor()
|
||||||
},
|
},
|
||||||
cancelEdit(e) {
|
cancelEdit(e) {
|
||||||
this.editing = false
|
this.editing = false
|
||||||
this.item.edit.reset(e)
|
this.color = randomColor()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
#app-navigation .app-navigation-entry-edit div {
|
.board-create {
|
||||||
width: auto;
|
order: 1;
|
||||||
display: block;
|
display: flex;
|
||||||
|
height: 44px;
|
||||||
|
|
||||||
|
form {
|
||||||
|
display: flex;
|
||||||
|
flex-grow: 1;
|
||||||
|
|
||||||
|
input[type="text"] {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-navigation-entry-bullet-wrapper {
|
.app-navigation-entry-bullet-wrapper {
|
||||||
position: absolute;
|
width: 44px;
|
||||||
left: 33px;
|
|
||||||
width: 44px !important;
|
|
||||||
margin: 6px;
|
|
||||||
height: 44px;
|
height: 44px;
|
||||||
.color0 {
|
.color0 {
|
||||||
width: 30px !important;
|
width: 30px !important;
|
||||||
|
margin: 5px;
|
||||||
|
margin-left: 7px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background-size: 14px;
|
background-size: 14px;
|
||||||
|
|||||||
@@ -20,75 +20,80 @@
|
|||||||
-
|
-
|
||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
<router-link :id="`board-${board.id}`"
|
<AppNavigationItem v-if="!editing"
|
||||||
:title="board.title"
|
:title="!deleted ? board.title : undoText"
|
||||||
:class="[{'icon-loading-small': loading, deleted: deleted, editing: editing }, classes]"
|
:loading="loading"
|
||||||
:to="routeTo"
|
:to="routeTo"
|
||||||
tag="li">
|
:undo="deleted"
|
||||||
<div :style="{ backgroundColor: `#${board.color}` }" class="app-navigation-entry-bullet" />
|
@undo="unDelete">
|
||||||
<a href="#">
|
<AppNavigationIconBullet slot="icon" :color="board.color" />
|
||||||
{{ board.title }}
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div v-if="actions.length > 0" class="app-navigation-entry-utils">
|
<AppNavigationCounter v-if="board.acl.length"
|
||||||
<ul>
|
slot="counter"
|
||||||
<li class="app-navigation-entry-utils-menu-button">
|
class="icon-shared"
|
||||||
<button v-if="board.acl.length === 0"
|
style="opacity: 0.5" />
|
||||||
v-tooltip="t('deck', 'Share')"
|
|
||||||
class="icon-shared"
|
|
||||||
style="opacity: 0.3"
|
|
||||||
@click="showSidebar" />
|
|
||||||
<button v-else
|
|
||||||
v-tooltip="t('deck', 'Share')"
|
|
||||||
class="icon-shared"
|
|
||||||
@click="showSidebar" />
|
|
||||||
</li>
|
|
||||||
<li class="app-navigation-entry-utils-menu-button">
|
|
||||||
<button v-click-outside="hideMenu" v-tooltip="t('deck', 'Options')" @click="showMenu" />
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div :class="{ 'open': menuOpen }" class="app-navigation-entry-menu">
|
|
||||||
<PopoverMenu :menu="actions" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- undo action -->
|
<template v-if="!deleted" slot="actions">
|
||||||
<div v-if="deleted" class="app-navigation-entry-deleted">
|
<ActionButton v-if="canManage && !board.archived"
|
||||||
<div class="app-navigation-entry-deleted-description">
|
icon="icon-rename"
|
||||||
{{ undoText }}
|
:close-after-click="true"
|
||||||
</div>
|
@click="actionEdit">
|
||||||
<button
|
{{ t('deck', 'Edit board') }}
|
||||||
:title="t('settings', 'Undo')"
|
</ActionButton>
|
||||||
class="app-navigation-entry-deleted-button icon-history"
|
<ActionButton v-if="canManage && !board.archived"
|
||||||
@click="unDelete" />
|
icon="icon-clone"
|
||||||
</div>
|
:close-after-click="true"
|
||||||
|
@click="actionClone">
|
||||||
<!-- edit entry -->
|
{{ t('deck', 'Clone board ') }}
|
||||||
<div v-if="editing" class="app-navigation-entry-edit">
|
</ActionButton>
|
||||||
<ColorPicker class="app-navigation-entry-bullet-wrapper" :value="`#${board.color}`" @input="updateColor">
|
<ActionButton v-if="canManage && board.archived"
|
||||||
<div :style="{ backgroundColor: getColor }" class="color0 icon-colorpicker app-navigation-entry-bullet" />
|
icon="icon-archive"
|
||||||
</ColorPicker>
|
:close-after-click="true"
|
||||||
<form @submit.prevent.stop="applyEdit">
|
@click="actionUnarchive">
|
||||||
<input v-model="editTitle" type="text" required>
|
{{ t('deck', 'Unarchive board ') }}
|
||||||
<input type="submit" value="" class="icon-confirm">
|
</ActionButton>
|
||||||
<input type="submit"
|
<ActionButton v-if="canManage && !board.archived"
|
||||||
value=""
|
icon="icon-archive"
|
||||||
class="icon-close"
|
:close-after-click="true"
|
||||||
@click.stop.prevent="cancelEdit">
|
@click="actionArchive">
|
||||||
</form>
|
{{ t('deck', 'Archive board ') }}
|
||||||
</div>
|
</ActionButton>
|
||||||
</router-link>
|
<ActionButton v-if="canManage"
|
||||||
|
icon="icon-delete"
|
||||||
|
:close-after-click="true"
|
||||||
|
@click="actionDelete">
|
||||||
|
{{ t('deck', 'Delete board ') }}
|
||||||
|
</ActionButton>
|
||||||
|
<ActionButton icon="icon-more" :close-after-click="true" @click="actionDetails">
|
||||||
|
{{ t('deck', 'Board details') }}
|
||||||
|
</ActionButton>
|
||||||
|
</template>
|
||||||
|
</AppNavigationItem>
|
||||||
|
<div v-else-if="editing" class="board-edit">
|
||||||
|
<ColorPicker class="app-navigation-entry-bullet-wrapper" :value="`#${board.color}`" @input="updateColor">
|
||||||
|
<div :style="{ backgroundColor: getColor }" class="color0 icon-colorpicker app-navigation-entry-bullet" />
|
||||||
|
</ColorPicker>
|
||||||
|
<form @submit.prevent.stop="applyEdit">
|
||||||
|
<input v-model="editTitle" type="text" required>
|
||||||
|
<input type="submit" value="" class="icon-confirm">
|
||||||
|
<Actions><ActionButton icon="icon-close" @click.stop.prevent="cancelEdit" /></Actions>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { PopoverMenu, ColorPicker } from '@nextcloud/vue'
|
import { AppNavigationIconBullet, AppNavigationCounter, AppNavigationItem, ColorPicker, Actions, ActionButton } from '@nextcloud/vue'
|
||||||
import ClickOutside from 'vue-click-outside'
|
import ClickOutside from 'vue-click-outside'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'AppNavigationBoard',
|
name: 'AppNavigationBoard',
|
||||||
components: {
|
components: {
|
||||||
|
AppNavigationIconBullet,
|
||||||
|
AppNavigationCounter,
|
||||||
|
AppNavigationItem,
|
||||||
ColorPicker,
|
ColorPicker,
|
||||||
PopoverMenu,
|
Actions,
|
||||||
|
ActionButton,
|
||||||
},
|
},
|
||||||
directives: {
|
directives: {
|
||||||
ClickOutside,
|
ClickOutside,
|
||||||
@@ -119,8 +124,7 @@ export default {
|
|||||||
return this.board.color
|
return this.board.color
|
||||||
},
|
},
|
||||||
undoText: function() {
|
undoText: function() {
|
||||||
// todo translation
|
return t('deck', 'Board {0} deleted', [this.board.title])
|
||||||
return 'deleted ' + this.board.title
|
|
||||||
},
|
},
|
||||||
routeTo: function() {
|
routeTo: function() {
|
||||||
return {
|
return {
|
||||||
@@ -128,117 +132,8 @@ export default {
|
|||||||
params: { id: this.board.id },
|
params: { id: this.board.id },
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: function() {
|
canManage() {
|
||||||
/* eslint-disable vue/no-side-effects-in-computed-properties */
|
return this.board.permissions.PERMISSION_MANAGE
|
||||||
/* eslint-disable vue/no-async-in-computed-properties */
|
|
||||||
const actions = []
|
|
||||||
|
|
||||||
// do not show actions while the item is loading
|
|
||||||
if (this.loading === false) {
|
|
||||||
const canManage = this.board.permissions.PERMISSION_MANAGE
|
|
||||||
|
|
||||||
if (canManage) {
|
|
||||||
actions.push({
|
|
||||||
action: () => {
|
|
||||||
this.hideMenu()
|
|
||||||
this.editTitle = this.board.title
|
|
||||||
this.editColor = '#' + this.board.color
|
|
||||||
this.editing = true
|
|
||||||
},
|
|
||||||
icon: 'icon-rename',
|
|
||||||
text: t('deck', 'Edit board'),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (canManage) {
|
|
||||||
|
|
||||||
actions.push({
|
|
||||||
action: async() => {
|
|
||||||
this.hideMenu()
|
|
||||||
this.loading = true
|
|
||||||
try {
|
|
||||||
const newBoard = await this.$store.dispatch('cloneBoard', this.board)
|
|
||||||
this.loading = false
|
|
||||||
const route = this.routeTo
|
|
||||||
route.params.id = newBoard.id
|
|
||||||
this.$router.push(route)
|
|
||||||
} catch (e) {
|
|
||||||
OC.Notification.showTemporary(t('deck', 'An error occurred'))
|
|
||||||
console.error(e)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
icon: 'icon-clone',
|
|
||||||
text: t('deck', 'Clone board'),
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!this.board.archived) {
|
|
||||||
actions.push({
|
|
||||||
action: () => {
|
|
||||||
this.hideMenu()
|
|
||||||
this.loading = true
|
|
||||||
this.$store.dispatch('archiveBoard', this.board)
|
|
||||||
},
|
|
||||||
icon: 'icon-archive',
|
|
||||||
text: t('deck', 'Archive board'),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
actions.push({
|
|
||||||
action: () => {
|
|
||||||
this.hideMenu()
|
|
||||||
this.loading = true
|
|
||||||
this.$store.dispatch('unarchiveBoard', this.board)
|
|
||||||
},
|
|
||||||
icon: 'icon-archive',
|
|
||||||
text: t('deck', 'Unarchive board'),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
actions.push({
|
|
||||||
action: () => {
|
|
||||||
OC.dialogs.confirmDestructive(
|
|
||||||
t('deck', 'Are you sure you want to delete the board {title}? This will delete all the data of this board.', { title: this.board.title }),
|
|
||||||
t('deck', 'Delete the board?'),
|
|
||||||
{
|
|
||||||
type: OC.dialogs.YES_NO_BUTTONS,
|
|
||||||
confirm: t('deck', 'Delete'),
|
|
||||||
confirmClasses: 'error',
|
|
||||||
cancel: t('deck', 'Cancel'),
|
|
||||||
},
|
|
||||||
(result) => {
|
|
||||||
if (result) {
|
|
||||||
this.hideMenu()
|
|
||||||
this.loading = true
|
|
||||||
this.boardApi.deleteBoard(this.board)
|
|
||||||
.then(() => {
|
|
||||||
this.loading = false
|
|
||||||
this.deleted = true
|
|
||||||
this.undoTimeoutHandle = setTimeout(() => {
|
|
||||||
this.$store.dispatch('removeBoard', this.board)
|
|
||||||
}, 7000)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
true
|
|
||||||
)
|
|
||||||
|
|
||||||
},
|
|
||||||
icon: 'icon-delete',
|
|
||||||
text: t('deck', 'Delete board'),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
actions.push({
|
|
||||||
action: () => {
|
|
||||||
const route = this.routeTo
|
|
||||||
route.name = 'board.details'
|
|
||||||
this.$router.push(route)
|
|
||||||
},
|
|
||||||
icon: 'icon-settings-dark',
|
|
||||||
text: t('deck', 'Board details'),
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return actions
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {},
|
watch: {},
|
||||||
@@ -254,15 +149,66 @@ export default {
|
|||||||
this.deleted = false
|
this.deleted = false
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
showMenu() {
|
|
||||||
this.menuOpen = true
|
|
||||||
},
|
|
||||||
hideMenu() {
|
|
||||||
this.menuOpen = false
|
|
||||||
},
|
|
||||||
updateColor(newColor) {
|
updateColor(newColor) {
|
||||||
this.editColor = newColor
|
this.editColor = newColor
|
||||||
},
|
},
|
||||||
|
actionEdit() {
|
||||||
|
this.editTitle = this.board.title
|
||||||
|
this.editColor = '#' + this.board.color
|
||||||
|
this.editing = true
|
||||||
|
},
|
||||||
|
async actionClone() {
|
||||||
|
this.loading = true
|
||||||
|
try {
|
||||||
|
const newBoard = await this.$store.dispatch('cloneBoard', this.board)
|
||||||
|
this.loading = false
|
||||||
|
const route = this.routeTo
|
||||||
|
route.params.id = newBoard.id
|
||||||
|
this.$router.push(route)
|
||||||
|
} catch (e) {
|
||||||
|
OC.Notification.showTemporary(t('deck', 'An error occurred'))
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actionArchive() {
|
||||||
|
this.loading = true
|
||||||
|
this.$store.dispatch('archiveBoard', this.board)
|
||||||
|
},
|
||||||
|
actionUnarchive() {
|
||||||
|
this.loading = true
|
||||||
|
this.$store.dispatch('unarchiveBoard', this.board)
|
||||||
|
},
|
||||||
|
actionDelete() {
|
||||||
|
OC.dialogs.confirmDestructive(
|
||||||
|
t('deck', 'Are you sure you want to delete the board {title}? This will delete all the data of this board.', { title: this.board.title }),
|
||||||
|
t('deck', 'Delete the board?'),
|
||||||
|
{
|
||||||
|
type: OC.dialogs.YES_NO_BUTTONS,
|
||||||
|
confirm: t('deck', 'Delete'),
|
||||||
|
confirmClasses: 'error',
|
||||||
|
cancel: t('deck', 'Cancel'),
|
||||||
|
},
|
||||||
|
(result) => {
|
||||||
|
if (result) {
|
||||||
|
this.loading = true
|
||||||
|
this.boardApi.deleteBoard(this.board)
|
||||||
|
.then(() => {
|
||||||
|
this.loading = false
|
||||||
|
this.deleted = true
|
||||||
|
this.undoTimeoutHandle = setTimeout(() => {
|
||||||
|
this.$store.dispatch('removeBoard', this.board)
|
||||||
|
}, 7000)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
true
|
||||||
|
)
|
||||||
|
},
|
||||||
|
actionDetails() {
|
||||||
|
const route = this.routeTo
|
||||||
|
route.name = 'board.details'
|
||||||
|
this.$router.push(route)
|
||||||
|
},
|
||||||
applyEdit(e) {
|
applyEdit(e) {
|
||||||
this.editing = false
|
this.editing = false
|
||||||
if (this.editTitle || this.editColor) {
|
if (this.editTitle || this.editColor) {
|
||||||
@@ -292,17 +238,29 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
#app-navigation #deck-navigation .editing {
|
.board-edit {
|
||||||
height: auto !important;
|
margin-left: 44px;
|
||||||
|
order: 1;
|
||||||
|
display: flex;
|
||||||
|
height: 44px;
|
||||||
|
|
||||||
|
form {
|
||||||
|
display: flex;
|
||||||
|
flex-grow: 1;
|
||||||
|
|
||||||
|
input[type="text"] {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-navigation-entry-bullet-wrapper {
|
.app-navigation-entry-bullet-wrapper {
|
||||||
position: absolute;
|
width: 44px;
|
||||||
left: 33px;
|
|
||||||
width: 44px !important;
|
|
||||||
margin: 6px;
|
|
||||||
height: 44px;
|
height: 44px;
|
||||||
.color0 {
|
.color0 {
|
||||||
width: 30px !important;
|
width: 30px !important;
|
||||||
|
margin: 5px;
|
||||||
|
margin-left: 7px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background-size: 14px;
|
background-size: 14px;
|
||||||
|
|||||||
@@ -20,33 +20,31 @@
|
|||||||
-
|
-
|
||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
<li v-if="boards.length > 0"
|
<AppNavigationItem v-if="boards.length > 0"
|
||||||
:id="id"
|
|
||||||
:title="text"
|
:title="text"
|
||||||
:class="{'open': opened, 'collapsible': collapsible }">
|
:icon="icon"
|
||||||
<button v-if="collapsible" class="collapse" @click.prevent.stop="toggleCollapse" />
|
:to="to"
|
||||||
<a :class="icon" href="#">
|
:allow-collapse="collapsible"
|
||||||
{{ text }}
|
:open="opened">
|
||||||
</a>
|
<AppNavigationBoard v-for="board in boardsSorted" :key="board.id" :board="board" />
|
||||||
<ul v-if="boards.length > 0">
|
</AppNavigationItem>
|
||||||
<AppNavigationBoard v-for="board in boardsSorted" :key="board.id" :board="board" />
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ClickOutside from 'vue-click-outside'
|
|
||||||
import AppNavigationBoard from './AppNavigationBoard'
|
import AppNavigationBoard from './AppNavigationBoard'
|
||||||
|
import { AppNavigationItem } from '@nextcloud/vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'AppNavigationBoardCategory',
|
name: 'AppNavigationBoardCategory',
|
||||||
components: {
|
components: {
|
||||||
|
AppNavigationItem,
|
||||||
AppNavigationBoard,
|
AppNavigationBoard,
|
||||||
},
|
},
|
||||||
directives: {
|
|
||||||
ClickOutside,
|
|
||||||
},
|
|
||||||
props: {
|
props: {
|
||||||
|
to: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
id: {
|
id: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
@@ -92,11 +90,5 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {},
|
|
||||||
methods: {
|
|
||||||
toggleCollapse() {
|
|
||||||
this.opened = !this.opened
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ export default new Vuex.Store({
|
|||||||
state: {
|
state: {
|
||||||
showArchived: false,
|
showArchived: false,
|
||||||
navShown: true,
|
navShown: true,
|
||||||
compactMode: localStorage.getItem('deck.compactMode'),
|
compactMode: localStorage.getItem('deck.compactMode') === 'true',
|
||||||
sidebarShown: false,
|
sidebarShown: false,
|
||||||
currentBoard: null,
|
currentBoard: null,
|
||||||
currentCard: null,
|
currentCard: null,
|
||||||
@@ -122,6 +122,9 @@ export default new Vuex.Store({
|
|||||||
canShare: state => {
|
canShare: state => {
|
||||||
return state.currentBoard ? state.currentBoard.permissions.PERMISSION_SHARE : false
|
return state.currentBoard ? state.currentBoard.permissions.PERMISSION_SHARE : false
|
||||||
},
|
},
|
||||||
|
isArchived: state => {
|
||||||
|
return state.currentBoard && state.currentBoard.archived
|
||||||
|
},
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
setSearchQuery(state, searchQuery) {
|
setSearchQuery(state, searchQuery) {
|
||||||
|
|||||||
Reference in New Issue
Block a user