feat: project and comments tabs
Signed-off-by: Luka Trovic <luka@nextcloud.com>
This commit is contained in:
@@ -157,8 +157,7 @@ export default {
|
|||||||
|
|
||||||
.modal__card {
|
.modal__card {
|
||||||
min-width: 320px;
|
min-width: 320px;
|
||||||
width: 50vw;
|
width: 100%;
|
||||||
max-width: 800px;
|
|
||||||
min-height: 200px;
|
min-height: 200px;
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
@@ -171,6 +170,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.modal-wrapper--normal .modal-container{
|
.modal-wrapper--normal .modal-container{
|
||||||
width: 800px !important;
|
width: 900px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
<i class="icon icon-calendar-dark" />
|
<i class="icon icon-calendar-dark" />
|
||||||
Due date
|
Due date
|
||||||
</div>
|
</div>
|
||||||
<div class="tab project">
|
<div class="tab project" :class="{active: activeTab === 'project'}" @click="activeTab = 'project'">
|
||||||
<i class="icon icon-deck" />
|
<i class="icon icon-deck" />
|
||||||
Project
|
Project
|
||||||
</div>
|
</div>
|
||||||
@@ -57,6 +57,7 @@
|
|||||||
<MembersTab :card="currentCard" @click="activeTab = 'members'" @active-tab="changeActiveTab" />
|
<MembersTab :card="currentCard" @click="activeTab = 'members'" @active-tab="changeActiveTab" />
|
||||||
<TagsTab :card="currentCard" @click="activeTab = 'tags'" @active-tab="changeActiveTab" />
|
<TagsTab :card="currentCard" @click="activeTab = 'tags'" @active-tab="changeActiveTab" />
|
||||||
<DueDateTab :card="currentCard" @click="activeTab = 'duedate'" @active-tab="changeActiveTab" />
|
<DueDateTab :card="currentCard" @click="activeTab = 'duedate'" @active-tab="changeActiveTab" />
|
||||||
|
<ProjectTab :card="currentCard" @click="activeTab = 'project'" @active-tab="changeActiveTab" />
|
||||||
</div>
|
</div>
|
||||||
<Description :key="currentCard.id" :card="currentCard" @change="descriptionChanged" />
|
<Description :key="currentCard.id" :card="currentCard" @change="descriptionChanged" />
|
||||||
</div>
|
</div>
|
||||||
@@ -64,17 +65,22 @@
|
|||||||
<h2 class="activities-title">
|
<h2 class="activities-title">
|
||||||
<div class="icon-flash-black" /> Activities
|
<div class="icon-flash-black" /> Activities
|
||||||
</h2>
|
</h2>
|
||||||
<div class="comment">
|
<div class="comments">
|
||||||
<Avatar :user="currentUser.uid" />
|
<Avatar :user="currentUser.uid" />
|
||||||
<input v-model="comment"
|
<CommentForm v-model="newComment" @submit="createComment" />
|
||||||
type="text"
|
|
||||||
:placeholder="t('deck', 'Leave a comment')"
|
|
||||||
class="comment-input">
|
|
||||||
</div>
|
</div>
|
||||||
<div class="activities-logs">
|
<div class="activities-logs">
|
||||||
<p class="log-item">
|
<CommentItem v-if="replyTo"
|
||||||
<i class="icon-plus" /> You have created card Example Task 3 in list To do on board Personal
|
:comment="replyTo"
|
||||||
</p>
|
:reply="true"
|
||||||
|
:preview="true"
|
||||||
|
@cancel="cancelReply" />
|
||||||
|
<ul v-if="getCommentsForCard(currentCard.id).length > 0" id="commentsFeed">
|
||||||
|
<CommentItem v-for="comment in getCommentsForCard(currentCard.id)"
|
||||||
|
:key="comment.id"
|
||||||
|
:comment="comment"
|
||||||
|
@doReload="loadComments" />
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -91,12 +97,24 @@ import MembersTab from './MembersTab.vue'
|
|||||||
import TagsTab from './TagsTab.vue'
|
import TagsTab from './TagsTab.vue'
|
||||||
import DueDateTab from './DueDateTab.vue'
|
import DueDateTab from './DueDateTab.vue'
|
||||||
import Description from './Description.vue'
|
import Description from './Description.vue'
|
||||||
|
import ProjectTab from './ProjectTab.vue'
|
||||||
|
import CommentForm from './CommentForm'
|
||||||
|
import CommentItem from './CommentItem'
|
||||||
|
|
||||||
const capabilities = window.OC.getCapabilities()
|
const capabilities = window.OC.getCapabilities()
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'CardModal',
|
name: 'CardModal',
|
||||||
components: { Avatar, MembersTab, Description, TagsTab, DueDateTab },
|
components: {
|
||||||
|
Avatar,
|
||||||
|
MembersTab,
|
||||||
|
Description,
|
||||||
|
TagsTab,
|
||||||
|
DueDateTab,
|
||||||
|
ProjectTab,
|
||||||
|
CommentForm,
|
||||||
|
CommentItem,
|
||||||
|
},
|
||||||
mixins: [relativeDate],
|
mixins: [relativeDate],
|
||||||
props: {
|
props: {
|
||||||
id: {
|
id: {
|
||||||
@@ -116,6 +134,7 @@ export default {
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
newComment: '',
|
||||||
titleEditable: false,
|
titleEditable: false,
|
||||||
titleEditing: '',
|
titleEditing: '',
|
||||||
hasActivity: capabilities && capabilities.activity,
|
hasActivity: capabilities && capabilities.activity,
|
||||||
@@ -125,8 +144,13 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
...mapGetters([
|
||||||
|
'getCommentsForCard',
|
||||||
|
'hasMoreComments',
|
||||||
|
]),
|
||||||
...mapState({
|
...mapState({
|
||||||
currentBoard: state => state.currentBoard,
|
currentBoard: state => state.currentBoard,
|
||||||
|
replyTo: state => state.comment.replyTo,
|
||||||
}),
|
}),
|
||||||
...mapGetters(['canEdit', 'assignables', 'cardActions', 'stackById']),
|
...mapGetters(['canEdit', 'assignables', 'cardActions', 'stackById']),
|
||||||
title() {
|
title() {
|
||||||
@@ -156,7 +180,39 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
this.loadComments()
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
cancelReply() {
|
||||||
|
this.$store.dispatch('setReplyTo', null)
|
||||||
|
},
|
||||||
|
async createComment(content) {
|
||||||
|
const commentObj = {
|
||||||
|
cardId: this.currentCard.id,
|
||||||
|
comment: content,
|
||||||
|
}
|
||||||
|
await this.$store.dispatch('createComment', commentObj)
|
||||||
|
this.$store.dispatch('setReplyTo', null)
|
||||||
|
this.newComment = ''
|
||||||
|
await this.loadComments()
|
||||||
|
},
|
||||||
|
async loadComments() {
|
||||||
|
this.$store.dispatch('setReplyTo', null)
|
||||||
|
this.error = null
|
||||||
|
this.isLoading = true
|
||||||
|
try {
|
||||||
|
await this.$store.dispatch('fetchComments', { cardId: this.currentCard.id })
|
||||||
|
this.isLoading = false
|
||||||
|
if (this.currentCard.commentsUnread > 0) {
|
||||||
|
await this.$store.dispatch('markCommentsAsRead', this.currentCard.id)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
this.isLoading = false
|
||||||
|
console.error('Failed to fetch more comments during infinite loading', e)
|
||||||
|
this.error = t('deck', 'Failed to load comments')
|
||||||
|
}
|
||||||
|
},
|
||||||
descriptionChanged(newDesc) {
|
descriptionChanged(newDesc) {
|
||||||
this.copiedCard.description = newDesc
|
this.copiedCard.description = newDesc
|
||||||
},
|
},
|
||||||
@@ -200,8 +256,8 @@ export default {
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.content-tabs {
|
.content-tabs {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 2fr 1fr;
|
grid-template-columns: 1fr 2fr 1fr 1fr;
|
||||||
align-items: center;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-flash-black {
|
.icon-flash-black {
|
||||||
@@ -236,7 +292,7 @@ export default {
|
|||||||
margin-top: 100px;
|
margin-top: 100px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment {
|
.comments {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -244,6 +300,10 @@ export default {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.comment-form {
|
||||||
|
width: 95%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
@@ -265,8 +325,8 @@ export default {
|
|||||||
.tabs {
|
.tabs {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
display: flex;
|
display: grid;
|
||||||
justify-content: flex-start;
|
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
|
||||||
grid-gap: 30px;
|
grid-gap: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { DatetimePicker } from '@nextcloud/vue'
|
import { DatetimePicker } from '@nextcloud/vue'
|
||||||
import { mapState, mapGetters } from 'vuex'
|
import { mapState, mapGetters } from 'vuex'
|
||||||
@@ -137,3 +138,9 @@ export default {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.section-details {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
44
src/components/card/ProjectTab.vue
Normal file
44
src/components/card/ProjectTab.vue
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<template>
|
||||||
|
<div class="section-details">
|
||||||
|
<div class="section-wrapper" @click="$emit('active-tab', 'project')">
|
||||||
|
<CollectionList v-if="card.id"
|
||||||
|
:id="`${card.id}`"
|
||||||
|
:name="card.title"
|
||||||
|
type="deck-card" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { CollectionList } from 'nextcloud-vue-collections'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: { CollectionList },
|
||||||
|
props: {
|
||||||
|
card: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
#collection-select-container p {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#collection-list li {
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user