Files
speckle-server/packages/frontend/src/components/dialogs/StreamShareDialog.vue
T
2021-03-06 17:46:35 +00:00

239 lines
7.1 KiB
Vue

<template>
<v-card :loading="loading">
<template slot="progress">
<v-progress-linear indeterminate></v-progress-linear>
</template>
<v-card-title class="pt-10">Add collaborators</v-card-title>
<v-card-text>
<v-text-field
v-model="search"
autofocus
label="Search for a user"
hint="You will be able to set their roles once they have been added"
persistent-hint
/>
<div v-if="$apollo.loading">Searching.</div>
<v-list
v-if="search && search.length >= 3 && userSearch && userSearch.items"
dense
one-line
class="px-0 mx-0"
>
<v-list-item v-if="filteredSearchResults.length === 0" class="px-0 mx-0">
<v-list-item-content>
<v-list-item-title>No users found.</v-list-item-title>
<v-list-item-subtitle>
Note: you can search by name as well as email.
</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
<v-list-item
v-for="item in filteredSearchResults"
:key="item.id"
class="px-0 mx-0"
@click="addCollab(item)"
>
<v-list-item-avatar>
<user-avatar
:id="item.id"
:name="item.name"
:avatar="item.avatar"
:size="25"
class="ml-1"
></user-avatar>
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title>{{ item.name }}</v-list-item-title>
<v-list-item-subtitle>
{{ item.company ? item.company : 'no company info' }}
</v-list-item-subtitle>
</v-list-item-content>
<v-list-item-action>
<v-icon>mdi-plus</v-icon>
</v-list-item-action>
</v-list-item>
</v-list>
</v-card-text>
<v-card-title>Existing collaborators</v-card-title>
<v-card-text class="px-0">
<v-list>
<v-list-item v-for="user in collaborators" :key="user.id" two-lines>
<v-list-item-icon>
<user-avatar :id="user.id" :avatar="user.avatar" :name="user.name" :size="42" />
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title class="font-weight-bold">{{ user.name }}</v-list-item-title>
<v-list-item-subtitle>
<!-- Role: {{ user.role.replace('stream:', '') }} -->
<v-select
v-model="user.role"
item-value="name"
:items="roles"
class="py-0 my-0"
@change="setUserPermissions(user)"
>
<template #selection="{ item }">
{{ item.name }}
</template>
<template #item="{ item }">
<div class="pa-2">
<p class="pa-0 ma-0">{{ item.name }}</p>
<p class="caption pa-0 ma-0 grey--text" style="max-width: 300px">
{{ item.description }}
</p>
</div>
</template>
</v-select>
</v-list-item-subtitle>
</v-list-item-content>
<v-list-item-action>
<v-btn icon small color="error" @click="removeUser(user)">
<v-icon>mdi-close</v-icon>
</v-btn>
</v-list-item-action>
</v-list-item>
</v-list>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="primary" text @click="$emit('close')">Close</v-btn>
</v-card-actions>
</v-card>
</template>
<script>
import gql from 'graphql-tag'
import serverQuery from '../../graphql/server.gql'
import streamCollaboratorsQuery from '../../graphql/streamCollaborators.gql'
import userSearchQuery from '../../graphql/userSearch.gql'
import UserAvatar from '../UserAvatar'
export default {
components: { UserAvatar },
props: ['streamId', 'userId'],
data: () => ({
search: '',
selectedUsers: null,
selectedRole: null,
userSearch: { items: [] },
serverInfo: { roles: [] },
loading: false
}),
apollo: {
stream: {
prefetch: true,
query: streamCollaboratorsQuery,
variables() {
return {
id: this.streamId
}
}
},
userSearch: {
query: userSearchQuery,
variables() {
return {
query: this.search,
limit: 25
}
},
skip() {
return !this.search || this.search.length < 3
},
debounce: 300
},
serverInfo: {
prefetch: true,
query: serverQuery
}
},
computed: {
roles() {
return this.serverInfo.roles.filter((x) => x.resourceTarget === 'streams').reverse()
},
collaborators() {
if (!this.stream) return []
return this.stream.collaborators.filter((user) => user.id !== this.myId)
},
filteredSearchResults() {
if (!this.userSearch) return null
let users = []
for (let u of this.userSearch.items) {
if (u.id === this.myId) continue
let indx = this.collaborators.findIndex((eu) => eu.id === u.id)
if (indx === -1) users.push(u)
}
return users
},
myId() {
return localStorage.getItem('uuid')
}
},
methods: {
async removeUser(user) {
this.loading = true
this.$matomo && this.$matomo.trackPageView('stream/remove-collaborator')
try {
await this.$apollo.mutate({
mutation: gql`
mutation streamRevokePermission($params: StreamRevokePermissionInput!) {
streamRevokePermission(permissionParams: $params)
}
`,
variables: {
params: {
streamId: this.streamId,
userId: user.id
}
}
})
let index = this.stream.collaborators.findIndex((u) => u.id === user.id)
if (index !== -1) {
this.stream.collaborators.splice(index, 1)
}
} catch (e) {
console.log(e)
}
this.$apollo.queries.stream.refetch()
this.loading = false
},
async setUserPermissions(user) {
this.loading = true
await this.grantPermissionUser(user)
this.loading = false
this.$apollo.queries.stream.refetch()
},
async addCollab(user) {
this.loading = true
this.search = null
this.userSearch.items = null
user.role = 'stream:contributor'
await this.grantPermissionUser(user)
this.stream.collaborators.unshift(user)
this.loading = false
this.$apollo.queries.stream.refetch()
},
async grantPermissionUser(user) {
this.$matomo && this.$matomo.trackPageView('stream/add-collaborator')
try {
await this.$apollo.mutate({
mutation: gql`
mutation grantPerm($params: StreamGrantPermissionInput!) {
streamGrantPermission(permissionParams: $params)
}
`,
variables: {
params: {
streamId: this.streamId,
userId: user.id,
role: user.role
}
}
})
} catch (e) {
console.log(e)
}
}
}
}
</script>