Merge branch 'master' into enh/archiveAllCardsFromStack

This commit is contained in:
Jakob
2020-08-17 21:03:21 +02:00
committed by Jakob Röhrl
260 changed files with 10928 additions and 6879 deletions

View File

@@ -23,13 +23,33 @@
<template>
<div class="board-wrapper">
<Controls :board="board" />
<transition name="fade" mode="out-in">
<div v-if="loading" key="loading" class="emptycontent">
<div class="icon icon-loading" />
<h2>{{ t('deck', 'Loading board') }}</h2>
<p />
</div>
<div v-else-if="board && !loading" key="board" class="board">
<EmptyContent v-else-if="isEmpty" key="empty" icon="icon-deck">
{{ t('deck', 'No lists available') }}
<template #desc>
{{ t('deck', 'Create a new list to add cards to this board') }}
<form @submit.prevent="addNewStack()">
<input id="new-stack-input-main"
v-model="newStackTitle"
v-focus
type="text"
class="no-close"
:placeholder="t('deck', 'List name')"
required>
<input v-tooltip="t('deck', 'Add new list')"
class="icon-confirm"
type="submit"
value="">
</form>
</template>
</EmptyContent>
<div v-else-if="!isEmpty && !loading" key="board" class="board">
<Container lock-axix="y"
orientation="horizontal"
:drag-handle-selector="dragHandleSelector"
@@ -54,6 +74,7 @@ import { Container, Draggable } from 'vue-smooth-dnd'
import { mapState, mapGetters } from 'vuex'
import Controls from '../Controls'
import Stack from './Stack'
import { EmptyContent } from '@nextcloud/vue'
export default {
name: 'Board',
@@ -62,6 +83,7 @@ export default {
Container,
Draggable,
Stack,
EmptyContent,
},
inject: [
'boardApi',
@@ -72,9 +94,10 @@ export default {
default: null,
},
},
data: function() {
data() {
return {
loading: true,
newStackTitle: '',
}
},
computed: {
@@ -91,6 +114,9 @@ export default {
dragHandleSelector() {
return this.canEdit ? null : '.no-drag'
},
isEmpty() {
return this.stacksByBoard.length === 0
},
},
watch: {
id: 'fetchData',
@@ -117,13 +143,13 @@ export default {
this.$store.dispatch('orderStack', { stack: this.stacksByBoard[removedIndex], removedIndex, addedIndex })
},
createStack() {
addNewStack() {
const newStack = {
title: 'FooBar',
title: this.newStackTitle,
boardId: this.id,
order: this.stacksByBoard().length,
}
this.$store.dispatch('createStack', newStack)
this.newStackTitle = ''
},
},
}
@@ -131,12 +157,25 @@ export default {
<style lang="scss" scoped>
@import "../../css/animations.scss";
@import '../../css/animations.scss';
$board-spacing: 15px;
$stack-spacing: 10px;
$stack-width: 300px;
form {
text-align: center;
display: flex;
width: 100%;
max-width: 200px;
margin: auto;
margin-top: 20px;
input[type=text] {
flex-grow: 1;
}
}
.board-wrapper {
position: relative;
width: 100%;

View File

@@ -89,6 +89,12 @@ export default {
li {
display: flex;
height: 44px;
&:hover, &:active, &.focus {
button {
opacity: 1;
}
}
}
span {
@@ -119,12 +125,5 @@ export default {
background-color: transparent;
opacity: 0.5;
}
li {
&:hover, &:active, &.focus {
button {
opacity: 1;
}
}
}
}
</style>

View File

@@ -178,20 +178,25 @@ export default {
#shareWithList {
margin-bottom: 20px;
}
#shareWithList li {
display: flex;
align-items: center;
}
.username {
padding: 12px 9px;
flex-grow: 1;
}
.board-owner-label {
opacity: .7;
}
.avatarLabel {
padding: 6px
}
.avatardiv {
background-color: #f5f5f5;
border-radius: 16px;

View File

@@ -25,21 +25,24 @@
<div class="stack">
<div v-click-outside="stopCardCreation" class="stack--header">
<transition name="fade" mode="out-in">
<h3 v-if="!canManage">
<h3 v-if="!canManage || isArchived">
{{ stack.title }}
</h3>
<h3 v-else-if="!editing" @click="startEditing(stack)">
<h3 v-else-if="!editing"
v-tooltip="stack.title"
class="stack--title"
@click="startEditing(stack)">
{{ stack.title }}
</h3>
<form v-else @submit.prevent="finishedEdit(stack)">
<input v-model="copiedStack.title" v-focus type="text">
<input v-tooltip="t('deck', 'Add a new stack')"
<input v-tooltip="t('deck', 'Add a new list')"
class="icon-confirm"
type="submit"
value="">
</form>
</transition>
<Actions v-if="canManage" :force-menu="true">
<Actions v-if="canManage && !isArchived" :force-menu="true">
<ActionButton icon="icon-archive" @click="modalArchivAllCardsShow=true">
{{ t('deck', 'Archive all cards') }}
</ActionButton>
@@ -47,7 +50,7 @@
{{ t('deck', 'Delete list') }}
</ActionButton>
</Actions>
<Actions v-if="canEdit && !showArchived">
<Actions v-if="canEdit && !showArchived && !isArchived">
<ActionButton icon="icon-add" @click.stop="showAddCard=true">
{{ t('deck', 'Add card') }}
</ActionButton>
@@ -57,7 +60,7 @@
<Modal v-if="modalArchivAllCardsShow" @close="modalArchivAllCardsShow=false">
<div class="modal__content">
<h3>{{ t('deck', 'Archive all cards in this list') }}</h3>
<progress :value="archiveAllCardsProgress" :max="stackLen" />
<progress :value="stackTransfer.current" :max="stackTransfer.total" />
<button class="primary" @click="archiveAllCardsFromStack(stack)">
{{ t('deck', 'Archive all cards') }}
</button>
@@ -112,7 +115,9 @@
import { mapGetters, mapState } from 'vuex'
import { Container, Draggable } from 'vue-smooth-dnd'
import { Actions, ActionButton, Modal } from '@nextcloud/vue'
import { showError } from '@nextcloud/dialogs'
import CardItem from '../cards/CardItem'
export default {
@@ -141,14 +146,17 @@ export default {
stateCardCreating: false,
animate: false,
modalArchivAllCardsShow: false,
archiveAllCardsProgress: null,
stackLen: 0,
stackTransfer: {
total: 0,
current: null,
},
}
},
computed: {
...mapGetters([
'canManage',
'canEdit',
'isArchived',
]),
...mapState({
showArchived: state => state.showArchived,
@@ -200,9 +208,9 @@ export default {
},
archiveAllCardsFromStack(stack) {
this.stackLen = this.cardsByStack.length
this.stackTransfer.total = this.cardsByStack.length
this.cardsByStack.forEach((card, index) => {
this.archiveAllCardsProgress = index
this.stackTransfer.current = index
this.$store.dispatch('archiveUnarchiveCard', { ...card, archived: true })
})
this.modalArchivAllCardsShow = false
@@ -234,7 +242,7 @@ export default {
})
this.$router.push({ name: 'card', params: { cardId: newCard.id } })
} catch (e) {
OCP.Toast.error('Could not create card: ' + e.response.data.message)
showError('Could not create card: ' + e.response.data.message)
} finally {
this.stateCardCreating = false
}
@@ -263,12 +271,14 @@ export default {
margin: 3px -3px;
margin-right: -10px;
margin-top: 0;
margin-bottom: 0;
margin-bottom: 3px;
background-color: var(--color-main-background-translucent);
cursor: grab;
h3, form {
flex-grow: 1;
display: flex;
cursor: inherit;
input[type=text] {
flex-grow: 1;
@@ -276,6 +286,13 @@ export default {
}
}
.stack--title {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: calc($stack-width - 60px);
}
.stack--card-add {
position: sticky;
top: 52px;
@@ -310,6 +327,7 @@ export default {
border: none;
}
}
.stack .smooth-dnd-container.vertical {
margin-top: 3px;
}
@@ -322,6 +340,7 @@ export default {
.slide-top-leave-active {
transition: all 100ms ease;
}
.slide-top-enter, .slide-top-leave-to {
transform: translateY(-10px);
opacity: 0;
@@ -334,10 +353,6 @@ export default {
min-height: 100px;
text-align: center;
margin: 20px 20px 20px 20px;
.multiselect {
margin-bottom: 10px;
}
}
.modal__content button {

View File

@@ -1,7 +1,7 @@
<template>
<div>
<ul class="labels">
<li v-for="label in labels" :key="label.id" :class="{editing: (editingLabelId === label.id)}">
<li v-for="label in labelsSorted" :key="label.id" :class="{editing: (editingLabelId === label.id)}">
<!-- Edit Tag -->
<template v-if="editingLabelId === label.id">
<form class="label-form" @submit.prevent="updateLabel(label)">
@@ -14,24 +14,30 @@
type="submit"
value=""
class="icon-confirm">
<input v-tooltip="t('deck', 'Cancel')"
value=""
class="icon-close"
@click="editingLabelId = null">
<Actions>
<ActionButton v-tooltip="{content: missingDataLabel, show: !editLabelObjValidated, trigger: 'manual' }"
:disabled="!editLabelObjValidated"
icon="icon-close"
@click="editingLabelId = null">
{{ t('deck', 'Cancel') }}
</ActionButton>
</Actions>
</form>
</template>
<template v-else>
<div :style="{ backgroundColor: `#${label.color}`, color:textColor(label.color) }" class="label-title">
<span>{{ label.title }}</span>
<div class="label-title" @click="clickEdit(label)">
<span :style="{ backgroundColor: `#${label.color}`, color: textColor(label.color) }">{{ label.title }}</span>
</div>
<button v-if="canManage"
v-tooltip="t('deck', 'Edit')"
class="icon-rename"
@click="clickEdit(label)" />
<button v-if="canManage"
v-tooltip="t('deck', 'Delete')"
class="icon-delete"
@click="deleteLabel(label.id)" />
<Actions v-if="canManage && !isArchived">
<ActionButton icon="icon-rename" @click="clickEdit(label)">
{{ t('deck', 'Edit') }}
</ActionButton>
</Actions>
<Actions v-if="canManage && !isArchived">
<ActionButton icon="icon-delete" @click="deleteLabel(label.id)">
{{ t('deck', 'Delete') }}
</ActionButton>
</Actions>
</template>
</li>
@@ -48,14 +54,15 @@
type="submit"
value=""
class="icon-confirm">
<input v-tooltip="t('deck', 'Cancel')"
value=""
class="icon-close"
@click="addLabel=false">
<Actions>
<ActionButton icon="icon-close" @click="addLabel=false">
{{ t('deck', 'Cancel') }}
</ActionButton>
</Actions>
</form>
</template>
</li>
<button v-if="canManage" @click="clickShowAddLabel()">
<button v-if="canManage && !isArchived" @click="clickShowAddLabel()">
<span class="icon-add" />{{ t('deck', 'Add a new tag') }}
</button>
</ul>
@@ -66,12 +73,14 @@
import { mapGetters } from 'vuex'
import Color from '../../mixins/color'
import { ColorPicker } from '@nextcloud/vue'
import { ColorPicker, Actions, ActionButton } from '@nextcloud/vue'
export default {
name: 'TagsTabSidebar',
components: {
ColorPicker,
Actions,
ActionButton,
},
mixins: [Color],
data() {
@@ -88,6 +97,7 @@ export default {
...mapGetters({
labels: 'currentBoardLabels',
canManage: 'canManage',
isArchived: 'isArchived',
}),
addLabelObjValidated() {
if (this.addLabelObj.title === '') {
@@ -111,6 +121,9 @@ export default {
return true
},
labelsSorted() {
return [...this.labels].sort((a, b) => (a.title < b.title) ? -1 : 1)
},
},
methods: {
@@ -145,7 +158,7 @@ export default {
}
</script>
<style scoped lang="scss">
$clickable-area: 37px;
$clickable-area: 44px;
.labels li {
display: flex;
@@ -153,12 +166,23 @@ export default {
align-items: stretch;
height: $clickable-area;
&:hover {
background-color: var(--color-background-hover);
border-radius: 3px;
}
.label-title {
flex-grow: 1;
border-radius: 3px;
padding: 7px;
padding: 10px;
&:hover, span:hover {
cursor: pointer;
}
span {
vertical-align: middle;
border-radius: 15px;
padding: 7px 12px;
}
}
&:not(.editing) button {
@@ -191,15 +215,11 @@ export default {
display: flex;
input[type=text] {
flex-grow: 1;
margin: 5px;
}
input[type=submit] {
margin-top: 5px;
}
}
button,
input:not([type='text']):last-child {
min-width: $clickable-area;
border-radius: 0 var(--border-radius) var(--border-radius) 0;
margin-left: -1px;
width: 35px;
background-color: var(--color-main-background);
}
}
</style>