feat(comments): selection, replies, alignments and other interactions
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
<template>
|
||||
<div class="mt-2 pa-1 d-flex align-center" style="width: 300px">
|
||||
<div class="">
|
||||
<div class="" style="width: 100%">
|
||||
<template v-for="(reply, index) in thread">
|
||||
<div v-if="index % 3 === 0" :key="index + 'date'" class="d-flex justify-center mouse">
|
||||
<div v-if="showTime(index)" :key="index + 'date'" class="d-flex justify-center mouse">
|
||||
<div class="d-inline px-2 py-0 caption text-center mb-2 rounded-lg background grey--text">
|
||||
{{ new Date(Date.now()).toLocaleString() }}
|
||||
{{ new Date(reply.createdAt).toLocaleString() }}
|
||||
<timeago :datetime="reply.createdAt" class="font-italic ma-1"></timeago>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -23,15 +24,27 @@
|
||||
</template>
|
||||
<div class="px-0 mb-4">
|
||||
<v-textarea
|
||||
v-model="replyText"
|
||||
solo
|
||||
hide-details
|
||||
auto-grow
|
||||
rows="1"
|
||||
placeholder="Reply"
|
||||
placeholder="Reply (shift + enter to send)"
|
||||
class="rounded-xl mb-2 caption"
|
||||
append-icon="mdi-send"
|
||||
@click:append="addReply"
|
||||
@keydown.enter.shift.exact.prevent="addReply()"
|
||||
></v-textarea>
|
||||
<v-btn
|
||||
v-tooltip="'Marks this thread as resolved.'"
|
||||
class="float-right"
|
||||
x-small
|
||||
rounded
|
||||
depressed
|
||||
color="error"
|
||||
>
|
||||
Archive
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -46,7 +59,7 @@ export default {
|
||||
comment: { type: Object, default: () => null }
|
||||
},
|
||||
apollo: {
|
||||
barf: {
|
||||
replyQuery: {
|
||||
query: gql`
|
||||
query($streamId: String!, $id: String!) {
|
||||
comment(streamId: $streamId, id: $id) {
|
||||
@@ -70,54 +83,96 @@ export default {
|
||||
id: this.comment.id
|
||||
}
|
||||
},
|
||||
skip() {
|
||||
return !this.comment.expanded
|
||||
},
|
||||
// result({ data }) {
|
||||
// console.log('data')
|
||||
// console.log(data)
|
||||
// skip() {
|
||||
// return !this.comment.expanded
|
||||
// },
|
||||
update: (data) => {
|
||||
console.log(data)
|
||||
return data.comment
|
||||
result({ data }) {
|
||||
data.comment.replies.items.forEach((item) => {
|
||||
if (this.localReplies.findIndex((c) => c.id === item.id) === -1)
|
||||
this.localReplies.push(item)
|
||||
})
|
||||
// this.localReplies.push(...data.comment.replies.items)
|
||||
},
|
||||
update: (data) => data.comment
|
||||
},
|
||||
$subscribe: {
|
||||
commentReplyCreated: {
|
||||
query: gql`
|
||||
subscription($streamId: String!, $commentId: String!) {
|
||||
commentReplyCreated(streamId: $streamId, commentId: $commentId)
|
||||
}
|
||||
`,
|
||||
variables() {
|
||||
return {
|
||||
streamId: this.$route.params.streamId,
|
||||
commentId: this.comment.id
|
||||
}
|
||||
},
|
||||
// skip() {
|
||||
// return !this.comment.expanded
|
||||
// },
|
||||
result({ data }) {
|
||||
if (!this.comment.expanded) return this.$emit('bounce', this.comment.id)
|
||||
this.localReplies.push({ ...data.commentReplyCreated })
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
replyText: null
|
||||
replyText: null,
|
||||
localReplies: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
thread() {
|
||||
// TODO: add the replies in here too
|
||||
return [this.comment]
|
||||
return [this.comment, ...this.localReplies]
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'comment.expanded': {
|
||||
deep: true,
|
||||
handler(newVal, oldVal) {
|
||||
if (!newVal) return
|
||||
this.localReplies = []
|
||||
this.$apollo.queries.replyQuery.refetch()
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
showTime(index) {
|
||||
if (index === 0) return true
|
||||
let curr = new Date(this.thread[index].createdAt)
|
||||
let prev = new Date(this.thread[index - 1].createdAt)
|
||||
let delta = Math.abs(prev - curr)
|
||||
return delta > 450000
|
||||
},
|
||||
async addReply() {
|
||||
if (!this.commentText || this.commentText.length < 5) {
|
||||
if (!this.replyText || this.replyText.length < 3) {
|
||||
this.$eventHub.$emit('notification', {
|
||||
text: `Reply must be at least 5 characters.`
|
||||
text: `Reply must be at least 3 characters.`
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
let commentInput = {
|
||||
let replyInput = {
|
||||
streamId: this.$route.params.streamId,
|
||||
resources: [{ resourceId: this.comment.id, resourceType: 'comment' }],
|
||||
parentComment: this.comment.id,
|
||||
// resources: [{ resourceId: this.$route.params.streamId, resourceType: 'stream' }],
|
||||
text: this.replyText
|
||||
}
|
||||
|
||||
try {
|
||||
await this.$apollo.mutate({
|
||||
mutation: gql`
|
||||
mutation commentCreate($input: CommentCreateInput!) {
|
||||
commentCreate(input: $input)
|
||||
mutation commentReply($input: ReplyCreateInput!) {
|
||||
commentReply(input: $input)
|
||||
}
|
||||
`,
|
||||
variables: { input: commentInput }
|
||||
variables: { input: replyInput }
|
||||
})
|
||||
this.replyText = null
|
||||
} catch (e) {
|
||||
this.$eventHub.$emit('notification', {
|
||||
text: e.message
|
||||
@@ -125,7 +180,7 @@ export default {
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
this.$emit('reply-added') // needed for layout reshuffle in parent
|
||||
this.$emit('refresh-layout') // needed for layout reshuffle in parent
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ export default {
|
||||
result({ data }) {
|
||||
// Note: swap user id checks for .userId (vs. uuid) if wanting to not allow same user two diff browsers
|
||||
// it's easier to test like this though :)
|
||||
if (data.userCommentActivity.status === 'disconnect') {
|
||||
if (data.userCommentActivity.status && data.userCommentActivity.status === 'disconnect') {
|
||||
this.users = this.users.filter((u) => u.uuid !== data.userCommentActivity.uuid)
|
||||
this.updateBubbles(true)
|
||||
return
|
||||
@@ -225,10 +225,15 @@ export default {
|
||||
controls._zoom
|
||||
]
|
||||
|
||||
let selectionLocation = this.selectionLocation
|
||||
if (this.$store.state.selectedComment) {
|
||||
selectionLocation = this.$store.state.selectedComment.data.location
|
||||
}
|
||||
|
||||
let data = {
|
||||
filter: this.$store.state.appliedFilter,
|
||||
selection: this.selectedIds,
|
||||
selectionLocation: this.selectionLocation,
|
||||
selectionLocation,
|
||||
sectionBox: window.__viewer.sectionBox.getCurrentBox(),
|
||||
selectionCenter: this.selectionCenter,
|
||||
camera: c,
|
||||
|
||||
@@ -16,7 +16,11 @@
|
||||
class="no-mouse"
|
||||
>
|
||||
<v-slide-x-transition>
|
||||
<div v-show="visible" ref="commentButton" class="absolute-pos">
|
||||
<div
|
||||
v-show="visible && !$store.state.selectedComment"
|
||||
ref="commentButton"
|
||||
class="absolute-pos"
|
||||
>
|
||||
<div class="d-flex align-center" style="height: 48px; width: 320px">
|
||||
<v-btn
|
||||
v-tooltip="!expand ? 'Add a comment (ctrl + shift + c)' : 'Cancel'"
|
||||
@@ -62,7 +66,7 @@
|
||||
<portal to="viewercontrols" :order="100">
|
||||
<v-slide-x-transition>
|
||||
<v-btn
|
||||
v-show="!location"
|
||||
v-show="!location && !$store.state.selectedComment"
|
||||
v-tooltip="'Add a comment (ctrl + shift + c)'"
|
||||
icon
|
||||
dark
|
||||
@@ -115,6 +119,7 @@ export default {
|
||||
let commentInput = {
|
||||
streamId: this.$route.params.streamId,
|
||||
resources: [
|
||||
{ resourceType: 'stream', resourceId: this.$route.params.streamId },
|
||||
{
|
||||
resourceType: this.$route.path.includes('object') ? 'object' : 'commit',
|
||||
resourceId: this.$route.params.resourceId
|
||||
@@ -126,11 +131,11 @@ export default {
|
||||
? this.location
|
||||
: new THREE.Vector3(camTarget.x, camTarget.y, camTarget.z),
|
||||
camPos: getCamArray(),
|
||||
filters: null, // TODO
|
||||
sectionBox: null, // TODO
|
||||
selection: null, // TODO
|
||||
screenshot: null // TODO
|
||||
}
|
||||
filters: this.$store.state.appliedFilter,
|
||||
sectionBox: window.__viewer.sectionBox.getCurrentBox(),
|
||||
selection: null // TODO for later, lazy now
|
||||
},
|
||||
screenshot: window.__viewer.interactions.screenshot()
|
||||
}
|
||||
if (this.$route.query.overlay) {
|
||||
commentInput.resources.push(
|
||||
|
||||
@@ -5,18 +5,20 @@
|
||||
<div
|
||||
ref="parent"
|
||||
style="width: 100%; height: 100vh; position: absolute; pointer-events: none; overflow: hidden"
|
||||
class="d-flex align-center justify-center no-mouse-parent"
|
||||
class="d-flex align-center justify-center no-mouse"
|
||||
>
|
||||
<div v-show="showComments">
|
||||
<div
|
||||
v-show="showComments"
|
||||
style="width: 100%; height: 100vh; position: absolute; pointer-events: none; overflow: hidden"
|
||||
class="no-mouse"
|
||||
>
|
||||
<!-- Comment bubbles -->
|
||||
<div
|
||||
v-for="(comment, index) in localComments"
|
||||
:key="index"
|
||||
:ref="`comment-${index}`"
|
||||
:class="`absolute-pos rounded-xl`"
|
||||
:style="`pointer-events: none; transition: opacity 0.2s ease; z-index:${
|
||||
comment.expanded ? '20' : '10'
|
||||
}; ${
|
||||
v-for="comment in localComments"
|
||||
:key="comment.id"
|
||||
:ref="`comment-${comment.id}`"
|
||||
:class="`absolute-pos rounded-xl no-mouse`"
|
||||
:style="`transition: opacity 0.2s ease; z-index:${comment.expanded ? '20' : '10'}; ${
|
||||
hasExpandedComment && !comment.expanded && !comment.hovered
|
||||
? 'opacity: 0.1;'
|
||||
: 'opacity: 1;'
|
||||
@@ -27,10 +29,12 @@
|
||||
<div class="" style="pointer-events: none">
|
||||
<div class="d-flex align-center" style="pointer-events: none">
|
||||
<v-btn
|
||||
:ref="`comment-button-${comment.id}`"
|
||||
v-tooltip="comment.expanded ? 'Close comment thread' : 'Open comment thread'"
|
||||
small
|
||||
icon
|
||||
:class="`elevation-5 pa-0 ma-0 ${
|
||||
comment.expanded ? 'dark white--text primary' : 'background'
|
||||
:class="`elevation-5 pa-0 ma-0 mouse ${
|
||||
comment.expanded || comment.bouncing ? 'dark white--text primary' : 'background'
|
||||
}`"
|
||||
@click="toggleComment(comment)"
|
||||
>
|
||||
@@ -47,9 +51,9 @@
|
||||
</div>
|
||||
<!-- Comment Threads -->
|
||||
<div
|
||||
v-for="(comment, index) in localComments"
|
||||
:key="index + 'card'"
|
||||
:ref="`commentcard-${index}`"
|
||||
v-for="comment in localComments"
|
||||
:key="comment.id + '-card'"
|
||||
:ref="`commentcard-${comment.id}`"
|
||||
:class="`hover-bg absolute-pos rounded-xl overflow-y-auto ${
|
||||
comment.hovered && false ? 'background elevation-5' : ''
|
||||
}`"
|
||||
@@ -60,7 +64,11 @@
|
||||
<!-- <v-card class="elevation-0 ma-0 transparent" style="height: 100%"> -->
|
||||
<v-fade-transition>
|
||||
<div v-show="comment.expanded">
|
||||
<comment-thread-viewer :comment="comment" @reply-added="replyAdded" />
|
||||
<comment-thread-viewer
|
||||
:comment="comment"
|
||||
@bounce="bounceComment"
|
||||
@refresh-layout="updateCommentBubbles()"
|
||||
/>
|
||||
</div>
|
||||
</v-fade-transition>
|
||||
<!-- </v-card> -->
|
||||
@@ -132,6 +140,7 @@ export default {
|
||||
for (let c of data.comments.items) {
|
||||
c.expanded = false
|
||||
c.hovered = false
|
||||
c.bouncing = false
|
||||
if (this.localComments.findIndex((lc) => c.id === lc.id) === -1)
|
||||
this.localComments.push({ ...c })
|
||||
}
|
||||
@@ -155,10 +164,15 @@ export default {
|
||||
},
|
||||
result({ data }) {
|
||||
// console.log(data.commentCreated)
|
||||
if (!data.commentCreated) return
|
||||
data.commentCreated.expanded = false
|
||||
data.commentCreated.hovered = false
|
||||
data.commentCreated.bouncing = false
|
||||
this.localComments.push(data.commentCreated)
|
||||
setTimeout(this.updateCommentBubbles, 0)
|
||||
setTimeout(() => {
|
||||
this.updateCommentBubbles()
|
||||
this.bounceComment(data.commentCreated.id)
|
||||
}, 10)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -185,6 +199,7 @@ export default {
|
||||
for (let c of this.localComments) {
|
||||
c.expanded = false
|
||||
}
|
||||
this.$store.commit('setCommentSelection', { comment: null })
|
||||
}.bind(this),
|
||||
10
|
||||
)
|
||||
@@ -201,6 +216,7 @@ export default {
|
||||
for (let c of this.localComments) {
|
||||
if (c.id === comment.id && comment.expanded === false) {
|
||||
c.preventAutoClose = true
|
||||
this.$store.commit('setCommentSelection', { comment: c })
|
||||
this.setCommentPow(c)
|
||||
setTimeout(() => {
|
||||
c.expanded = true
|
||||
@@ -213,6 +229,7 @@ export default {
|
||||
// this.updateCommentBubbles()
|
||||
}, 1000)
|
||||
} else {
|
||||
if (c.expanded) this.$store.commit('setCommentSelection', { comment: null })
|
||||
c.expanded = false
|
||||
}
|
||||
}
|
||||
@@ -252,33 +269,48 @@ export default {
|
||||
if (camToSet[6] === 1) {
|
||||
window.__viewer.cameraHandler.activeCam.controls.zoom(camToSet[7], true)
|
||||
}
|
||||
if (comment.data.filters) {
|
||||
this.$store.commit('setFilterDirect', { filter: comment.data.filters })
|
||||
} else {
|
||||
this.$store.commit('resetFilters')
|
||||
}
|
||||
|
||||
if (comment.data.sectionBox) {
|
||||
window.__viewer.sectionBox.setBox(comment.data.sectionBox, 0)
|
||||
} else {
|
||||
// TODO: Toggle section box off
|
||||
// window.__viewer.sectionBox
|
||||
}
|
||||
// TODO: apply filters, section box, etc.
|
||||
},
|
||||
replyAdded() {
|
||||
this.updateCommentBubbles()
|
||||
},
|
||||
updateCommentBubbles() {
|
||||
if (!this.comments) return
|
||||
let index = -1
|
||||
let cam = window.__viewer.cameraHandler.camera
|
||||
cam.updateProjectionMatrix()
|
||||
for (let comment of this.localComments) {
|
||||
index++
|
||||
let commentEl = this.$refs[`comment-${index}`][0]
|
||||
// get html elements
|
||||
let commentEl = this.$refs[`comment-${comment.id}`][0]
|
||||
let card = this.$refs[`commentcard-${comment.id}`][0]
|
||||
|
||||
if (!commentEl) continue
|
||||
|
||||
let location = new THREE.Vector3(
|
||||
comment.data.location.x,
|
||||
comment.data.location.y,
|
||||
comment.data.location.z
|
||||
)
|
||||
|
||||
location.project(cam)
|
||||
|
||||
let commentLocation = new THREE.Vector3(
|
||||
(location.x * 0.5 + 0.5) * this.$refs.parent.clientWidth,
|
||||
(location.y * -0.5 + 0.5) * this.$refs.parent.clientHeight,
|
||||
0
|
||||
)
|
||||
|
||||
let tX = commentLocation.x - 20
|
||||
let tY = commentLocation.y - 20
|
||||
|
||||
const paddingX = 10
|
||||
const paddingYTop = 70
|
||||
const paddingYBottom = 90
|
||||
@@ -304,13 +336,18 @@ export default {
|
||||
tY = this.$refs.parent.clientHeight - paddingYBottom
|
||||
}
|
||||
|
||||
commentEl.style.transform = `translate(${tX}px,${tY}px)`
|
||||
commentEl.style.top = `${tY}px`
|
||||
commentEl.style.left = `${tX}px`
|
||||
|
||||
let card = this.$refs[`commentcard-${index}`][0]
|
||||
let maxHeight = this.$refs.parent.clientHeight - paddingYTop - paddingYBottom
|
||||
|
||||
card.style.maxHeight = `${maxHeight}px`
|
||||
|
||||
if (tX > this.$refs.parent.clientWidth - (paddingX + 50 + card.scrollWidth)) {
|
||||
tX = this.$refs.parent.clientWidth - (paddingX + 50 + card.scrollWidth)
|
||||
}
|
||||
card.style.left = `${tX + 40}px`
|
||||
// card.style.right = '0px'
|
||||
|
||||
let cardTop = paddingYTop
|
||||
|
||||
@@ -334,6 +371,16 @@ export default {
|
||||
card.style.top = `${cardTop}px`
|
||||
}
|
||||
}
|
||||
},
|
||||
bounceComment(id) {
|
||||
let commentEl = this.$refs[`comment-${id}`][0]
|
||||
commentEl.classList.add('tada-once')
|
||||
let comment = this.localComments.find((c) => c.id === id)
|
||||
comment.bouncing = true
|
||||
setTimeout(() => {
|
||||
commentEl.classList.remove('tada-once')
|
||||
comment.bouncing = false
|
||||
}, 2000)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -364,4 +411,10 @@ export default {
|
||||
.hover-bg {
|
||||
transition: background 0.3s ease;
|
||||
}
|
||||
.no-mouse {
|
||||
pointer-events: none;
|
||||
}
|
||||
.mouse {
|
||||
pointer-events: auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -136,7 +136,7 @@ export default {
|
||||
this.parseAndSetFilters()
|
||||
}
|
||||
},
|
||||
'$store.state.appliedFilter'(val) {
|
||||
'$store.state.appliedFilter'() {
|
||||
if (this.trySetPresetFilter) return
|
||||
if (this.$store.state.appliedFilter && this.$store.state.appliedFilter.filterBy) {
|
||||
let key = Object.keys(this.$store.state.appliedFilter.filterBy)[0]
|
||||
|
||||
@@ -4,10 +4,8 @@
|
||||
<v-btn
|
||||
v-show="showVisReset"
|
||||
v-tooltip="`Resets all applied filters`"
|
||||
:zzzdisabled="!showVisReset"
|
||||
:small="small"
|
||||
small
|
||||
rounded
|
||||
icon
|
||||
class="mr-2"
|
||||
@click="resetVisibility()"
|
||||
>
|
||||
|
||||
@@ -17,9 +17,14 @@ const store = new Vuex.Store({
|
||||
isolateCategoryKey: null,
|
||||
isolateCategoryValues: [],
|
||||
hideCategoryKey: null,
|
||||
hideCategoryValues: []
|
||||
hideCategoryValues: [],
|
||||
selectedComment: null
|
||||
},
|
||||
mutations: {
|
||||
setCommentSelection(state, { comment }) {
|
||||
if (comment) window.__viewer.interactions.deselectObjects()
|
||||
state.selectedComment = comment
|
||||
},
|
||||
isolateObjects(state, { filterKey, filterValues }) {
|
||||
state.hideKey = null
|
||||
state.hideValues = []
|
||||
|
||||
@@ -26,6 +26,73 @@ $primary-gradient: linear-gradient(0deg, $primary-darken 0%, $primary-base 40%);
|
||||
background: linear-gradient(to top left, #243b55, #141e30) !important;
|
||||
}
|
||||
|
||||
// TADAs
|
||||
.tada-infinte {
|
||||
-webkit-animation-name: tada;
|
||||
animation-name: tada;
|
||||
-webkit-animation-duration: 1s;
|
||||
animation-duration: 1s;
|
||||
-webkit-animation-fill-mode: both;
|
||||
animation-fill-mode: both;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
.tada-once {
|
||||
-webkit-animation-name: tada;
|
||||
animation-name: tada;
|
||||
-webkit-animation-duration: 1s;
|
||||
animation-duration: 1s;
|
||||
-webkit-animation-fill-mode: both;
|
||||
animation-fill-mode: both;
|
||||
animation-iteration-count: 2;
|
||||
}
|
||||
|
||||
|
||||
@-webkit-keyframes tada {
|
||||
0% {
|
||||
-webkit-transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
10%, 20% {
|
||||
-webkit-transform: scale3d(.8, .8, .8) rotate3d(0, 0, 1, -3deg);
|
||||
transform: scale3d(.8, .8, .8) rotate3d(0, 0, 1, -3deg);
|
||||
}
|
||||
30%, 50%, 70%, 90% {
|
||||
-webkit-transform: scale3d(1.4, 1.4, 1.4) rotate3d(0, 0, 1, 3deg);
|
||||
transform: scale3d(1.4, 1.4, 1.4) rotate3d(0, 0, 1, 3deg);
|
||||
}
|
||||
40%, 60%, 80% {
|
||||
-webkit-transform: scale3d(1.4, 1.4, 1.4) rotate3d(0, 0, 1, -3deg);
|
||||
transform: scale3d(1.4, 1.4, 1.4) rotate3d(0, 0, 1, -3deg);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
}
|
||||
@keyframes tada {
|
||||
0% {
|
||||
-webkit-transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
10%, 20% {
|
||||
-webkit-transform: scale3d(.8, .8, .8) rotate3d(0, 0, 1, -3deg);
|
||||
transform: scale3d(.8, .8, .8) rotate3d(0, 0, 1, -3deg);
|
||||
}
|
||||
30%, 50%, 70%, 90% {
|
||||
-webkit-transform: scale3d(1.4, 1.4, 1.4) rotate3d(0, 0, 1, 3deg);
|
||||
transform: scale3d(1.4, 1.4, 1.4) rotate3d(0, 0, 1, 3deg);
|
||||
}
|
||||
40%, 60%, 80% {
|
||||
-webkit-transform: scale3d(1.4, 1.4, 1.4) rotate3d(0, 0, 1, -3deg);
|
||||
transform: scale3d(1.4, 1.4, 1.4) rotate3d(0, 0, 1, -3deg);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: scale3d(1, 1, 1);
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* TOOLTIPs */
|
||||
|
||||
.tooltip {
|
||||
|
||||
@@ -54,11 +54,11 @@ module.exports = {
|
||||
// TODO: check perms, persist comment
|
||||
await authorizeResolver( context.userId, args.input.streamId, 'stream:reviewer' )
|
||||
let id = await createComment( { userId: context.userId, input: args.input } )
|
||||
console.log( args.input )
|
||||
// console.log( args.input )
|
||||
await pubsub.publish( 'COMMENT_CREATED', {
|
||||
commentCreated: { ...args.input, authorId: context.userId, createdAt: Date.now() },
|
||||
commentCreated: { ...args.input, authorId: context.userId, id, createdAt: Date.now() },
|
||||
streamId: args.input.streamId,
|
||||
resourceId: args.input.resources[0].resourceId // TODO: hack for now
|
||||
resourceId: args.input.resources[1].resourceId // TODO: hack for now
|
||||
} )
|
||||
return id
|
||||
},
|
||||
@@ -70,14 +70,15 @@ module.exports = {
|
||||
await authorizeResolver( context.userId, args.input.streamId, 'stream:reviewer' )
|
||||
// the reply also has to be linked to the stream, for the recursive reply lookup to work
|
||||
let input = { ...args.input, resources: [
|
||||
{ id: args.input.parentComment, type: 'comment' },
|
||||
{ id: args.input.streamId, type: 'stream' }
|
||||
{ resourceId: args.input.parentComment, resourceType: 'comment' },
|
||||
{ resourceId: args.input.streamId, resourceType: 'stream' }
|
||||
] }
|
||||
// console.log(input.resources)
|
||||
let id = await createComment( { userId: context.userId, input } )
|
||||
await pubsub.publish( 'COMMENT_REPLY_CREATED', {
|
||||
commentCreated: args.input,
|
||||
streamId: args.streamId,
|
||||
resourceId: args.resourceId
|
||||
commentReplyCreated: { ...args.input, id, authorId: context.userId, createdAt: Date.now() },
|
||||
streamId: args.input.streamId,
|
||||
commentId: args.input.parentComment
|
||||
} )
|
||||
return id
|
||||
},
|
||||
@@ -101,7 +102,10 @@ module.exports = {
|
||||
commentReplyCreated: {
|
||||
subscribe: withFilter( () => pubsub.asyncIterator( [ 'COMMENT_REPLY_CREATED' ] ), async( payload, variables, context ) => {
|
||||
await authorizeResolver( context.userId, payload.streamId, 'stream:reviewer' )
|
||||
return payload.streamId === variables.streamId && payload.resourceId === variables.resourceId
|
||||
console.log( 'sub' )
|
||||
console.log( payload )
|
||||
console.log( variables )
|
||||
return payload.streamId === variables.streamId && payload.commentId === variables.commentId
|
||||
} )
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ input ReplyCreateInput {
|
||||
streamId: String!
|
||||
parentComment: String!
|
||||
text: String!
|
||||
data: JSONObject!
|
||||
data: JSONObject
|
||||
}
|
||||
|
||||
input CommentEditInput {
|
||||
|
||||
@@ -5,7 +5,7 @@ exports.up = async ( knex ) => {
|
||||
table.string( 'authorId', 10 ).references( 'id' ).inTable( 'users' ).notNullable().index( )
|
||||
table.timestamp( 'createdAt' ).defaultTo( knex.fn.now( ) )
|
||||
table.timestamp( 'updatedAt' ).defaultTo( knex.fn.now( ) )
|
||||
table.string( 'text' )
|
||||
table.text( 'text' )
|
||||
table.text( 'screenshot' )
|
||||
table.jsonb( 'data' )
|
||||
table.boolean( 'archived' ).defaultTo( false ).notNullable()
|
||||
|
||||
@@ -53,8 +53,9 @@ const getCommentLinksForResources = async ( streamId, resources ) => {
|
||||
|
||||
module.exports = {
|
||||
async createComment( { userId, input } ) {
|
||||
console.log(input)
|
||||
const streamResources = input.resources.filter( r => r.resourceType === 'stream' )
|
||||
if ( streamResources.length < 1 ) throw Error( 'Must specify atleast a stream as the comment target' )
|
||||
if ( streamResources.length < 1 ) throw Error( 'Must specify at least a stream as the comment target' )
|
||||
if ( streamResources.length > 1 ) throw Error( 'Commenting on multiple streams is not supported' )
|
||||
|
||||
const [ stream ] = streamResources
|
||||
|
||||
Reference in New Issue
Block a user