feat(frontend): uniforms stream pages
This commit is contained in:
@@ -0,0 +1,252 @@
|
||||
<template>
|
||||
<v-card v-if="stream" :loading="loading" class="mt-5 pa-4" elevation="0" rounded="lg">
|
||||
<template slot="progress">
|
||||
<v-progress-linear indeterminate></v-progress-linear>
|
||||
</template>
|
||||
<v-card-title>
|
||||
<v-icon class="mr-2">mdi-account-plus-outline</v-icon>
|
||||
<span class="d-inline-block">Add collaborators</span>
|
||||
</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. Note: you can search by name and email.
|
||||
</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-list-item v-if="filteredSearchResults.length === 0" class="px-0 mx-0">
|
||||
<v-list-item-action>
|
||||
<v-btn color="primary" @click="showStreamInviteDialog">Invite {{ search }}</v-btn>
|
||||
</v-list-item-action>
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
v-for="item in filteredSearchResults"
|
||||
v-else
|
||||
: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>
|
||||
<stream-invite-dialog ref="streamInviteDialog" :stream-id="stream.id" :text="search" />
|
||||
<v-card-title>
|
||||
<v-icon class="mr-2">mdi-account-group-outline</v-icon>
|
||||
<span class="d-inline-block">Collaborators ({{ stream.collaborators.length - 1 }})</span>
|
||||
</v-card-title>
|
||||
<v-card-text class="px-0">
|
||||
<p v-if="collaborators.length === 0" class="ml-4">
|
||||
You don't have collaborators on this stream .
|
||||
</p>
|
||||
<v-list v-else>
|
||||
<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>
|
||||
</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 '@/components/UserAvatar'
|
||||
import StreamInviteDialog from '@/components/dialogs/StreamInviteDialog'
|
||||
|
||||
export default {
|
||||
components: { UserAvatar, StreamInviteDialog },
|
||||
data: () => ({
|
||||
search: '',
|
||||
selectedUsers: null,
|
||||
selectedRole: null,
|
||||
userSearch: { items: [] },
|
||||
serverInfo: { roles: [] },
|
||||
loading: false
|
||||
}),
|
||||
apollo: {
|
||||
stream: {
|
||||
prefetch: true,
|
||||
query: streamCollaboratorsQuery,
|
||||
variables() {
|
||||
return {
|
||||
id: this.$route.params.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.stream.id,
|
||||
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.stream.id,
|
||||
userId: user.id,
|
||||
role: user.role
|
||||
}
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
},
|
||||
showStreamInviteDialog() {
|
||||
this.$refs.streamInviteDialog.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -13,22 +13,33 @@
|
||||
<v-icon class="mr-2">mdi-earth</v-icon>
|
||||
Globals
|
||||
</v-card-title>
|
||||
<v-card-subtitle v-if="commitMessage" class="mt-3">
|
||||
<b>Selected commit:</b>
|
||||
<v-icon dense class="text-subtitle-1">mdi-source-commit</v-icon>
|
||||
{{ commitMessage }}
|
||||
</v-card-subtitle>
|
||||
<v-card-text>
|
||||
These global variables can be used for storing design values, project requirements, notes, or
|
||||
any info you want to keep track of alongside your geometry. Variable values can be text,
|
||||
numbers, lists, or booleans. Click the box icon next to any field to turn it into a nested
|
||||
group of fields, and drag and drop fields in and out of groups as you please! Note that field
|
||||
order may not always be preserved.
|
||||
</v-card-text>
|
||||
<v-card-text v-if="!(userRole === 'stream:contributor') && !(userRole === 'stream:owner')">
|
||||
You are free to play around with the globals here, but you do not have the required stream
|
||||
permission to save your changes.
|
||||
|
||||
<v-card-text class="subtitle-1">
|
||||
Click the box icon next to any field to turn it into a nested group of fields, and drag and
|
||||
drop fields in and out of groups as you please! Note that field order may not always be
|
||||
preserved.
|
||||
<span v-if="!(userRole === 'stream:contributor') && !(userRole === 'stream:owner')">
|
||||
<br />
|
||||
<br />
|
||||
You are free to play around with the globals here, but you do not have the required stream
|
||||
permission to save your changes.
|
||||
</span>
|
||||
<v-btn
|
||||
text
|
||||
small
|
||||
color="primary"
|
||||
href="https://speckle.guide/user/web.html#globals"
|
||||
target="_blank"
|
||||
>
|
||||
Read the docs
|
||||
</v-btn>
|
||||
<div v-if="commitMessage" class="mt-3">
|
||||
<b>Selected commit:</b>
|
||||
<v-icon dense class="text-subtitle-1">mdi-source-commit</v-icon>
|
||||
{{ commitMessage }}
|
||||
</div>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions>
|
||||
<v-switch
|
||||
v-model="deleteEntries"
|
||||
|
||||
@@ -45,6 +45,10 @@ export default {
|
||||
streamId: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
text: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -78,7 +82,7 @@ export default {
|
||||
watch: {
|
||||
showDialog() {
|
||||
this.clear()
|
||||
this.email = null
|
||||
this.email = this.text
|
||||
this.message = 'Hey, I want to share this stream with you!'
|
||||
}
|
||||
},
|
||||
|
||||
@@ -132,6 +132,15 @@ const routes = [
|
||||
props: true,
|
||||
component: () => import('@/views/stream/Activity.vue')
|
||||
},
|
||||
{
|
||||
path: 'collaborators/',
|
||||
name: 'collaborators',
|
||||
meta: {
|
||||
title: 'Stream Collaborators | Speckle'
|
||||
},
|
||||
props: true,
|
||||
component: () => import('@/views/stream/Collaborators.vue')
|
||||
},
|
||||
{
|
||||
path: 'settings/',
|
||||
name: 'settings',
|
||||
|
||||
@@ -76,26 +76,43 @@
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-app-bar>
|
||||
<v-navigation-drawer v-if="isStreamPage" v-model="drawer" app clipped left>
|
||||
<v-list v-if="stream">
|
||||
<v-navigation-drawer v-if="isStreamPage && stream" v-model="drawer" app clipped left>
|
||||
<v-list>
|
||||
<v-subheader>Stream menu</v-subheader>
|
||||
<v-list-item
|
||||
v-for="menu in menues"
|
||||
:key="menu.name"
|
||||
:to="menu.to"
|
||||
:disabled="menu.disabled"
|
||||
exact
|
||||
@click="handleFunction(menu.click)"
|
||||
>
|
||||
<v-list-item-icon>
|
||||
<v-icon>{{ menu.icon }}</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-group color="primary">
|
||||
<v-list-item
|
||||
v-for="menu in menues"
|
||||
:key="menu.name"
|
||||
:to="menu.to"
|
||||
:disabled="menu.disabled"
|
||||
exact
|
||||
@click="handleFunction(menu.click)"
|
||||
>
|
||||
<v-list-item-icon>
|
||||
<v-icon>{{ menu.icon }}</v-icon>
|
||||
</v-list-item-icon>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>{{ menu.name }}</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>{{ menu.name }}</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list-item-group>
|
||||
</v-list>
|
||||
<v-btn
|
||||
v-if="stream.role === 'stream:owner'"
|
||||
outlined
|
||||
color="primary"
|
||||
rounded
|
||||
height="50"
|
||||
class="ma-3 d-block"
|
||||
@click="showStreamInviteDialog"
|
||||
>
|
||||
<v-icon small class="mr-2">mdi-email-send-outline</v-icon>
|
||||
Invite to this
|
||||
<br />
|
||||
stream by email
|
||||
</v-btn>
|
||||
<stream-invite-dialog ref="streamInviteDialog" :stream-id="stream.id" />
|
||||
</v-navigation-drawer>
|
||||
<v-main :style="background">
|
||||
<router-view></router-view>
|
||||
@@ -134,9 +151,10 @@ import gql from 'graphql-tag'
|
||||
import userQuery from '../graphql/user.gql'
|
||||
import UserMenuTop from '../components/UserMenuTop'
|
||||
import SearchBar from '../components/SearchBar'
|
||||
import StreamInviteDialog from '../components/dialogs/StreamInviteDialog'
|
||||
|
||||
export default {
|
||||
components: { UserMenuTop, SearchBar },
|
||||
components: { UserMenuTop, SearchBar, StreamInviteDialog },
|
||||
data() {
|
||||
return {
|
||||
search: '',
|
||||
@@ -247,7 +265,7 @@ export default {
|
||||
{
|
||||
name: 'Collaborators',
|
||||
icon: 'mdi-account-group-outline',
|
||||
click: 'manageCollabrators',
|
||||
to: '/streams/' + this.$route.params.streamId + '/collaborators',
|
||||
disabled: this.stream.role !== 'stream:owner'
|
||||
},
|
||||
{
|
||||
@@ -259,7 +277,7 @@ export default {
|
||||
{
|
||||
name: 'Settings',
|
||||
icon: 'mdi-cog-outline',
|
||||
click: 'editStream',
|
||||
to: '/streams/' + this.$route.params.streamId + '/settings',
|
||||
disabled: this.stream.role !== 'stream:owner'
|
||||
}
|
||||
]
|
||||
@@ -274,11 +292,16 @@ export default {
|
||||
methods: {
|
||||
handleFunction(f) {
|
||||
if (this[f]) this[f]()
|
||||
},
|
||||
showStreamInviteDialog() {
|
||||
this.$refs.streamInviteDialog.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.action-button {
|
||||
}
|
||||
.logo {
|
||||
font-family: 'Space Grotesk', sans-serif;
|
||||
text-transform: none;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<v-row>
|
||||
<v-col v-if="stream" cols="12">
|
||||
<breadcrumb-title />
|
||||
<h3 class="title font-italic font-weight-thin my-5">Recent activity on this Stream</h3>
|
||||
</v-col>
|
||||
<v-col cols="12">
|
||||
<v-timeline v-if="stream" align-top>
|
||||
|
||||
@@ -6,35 +6,28 @@
|
||||
</v-col>
|
||||
<v-col v-else-if="stream.branch" cols="12">
|
||||
<breadcrumb-title />
|
||||
<v-card class="pa-4" elevation="0" rounded="lg">
|
||||
<h3 v-if="stream.branch.description" class="title font-italic font-weight-thin my-5">
|
||||
{{ stream.branch.descrption }}
|
||||
</h3>
|
||||
|
||||
<v-card class="mt-5 pa-4" elevation="0" rounded="lg">
|
||||
<branch-edit-dialog ref="editBranchDialog" />
|
||||
|
||||
<v-card-title class="mr-8">
|
||||
<v-card-title>
|
||||
<v-icon class="mr-2">mdi-source-branch</v-icon>
|
||||
<span class="d-inline-block">{{ stream.branch.name }}</span>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
v-if="stream.role === 'stream:contributor' || stream.role === 'stream:owner'"
|
||||
small
|
||||
color="primary"
|
||||
text
|
||||
class="px-0"
|
||||
class="my-2"
|
||||
small
|
||||
@click="editBranch"
|
||||
>
|
||||
<v-icon small class="mr-2 float-left">mdi-cog-outline</v-icon>
|
||||
Edit branch
|
||||
</v-btn>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text v-if="stream.branch.description">
|
||||
{{ stream.branch.description }}
|
||||
</v-card-text>
|
||||
<v-card-text v-else>
|
||||
<i>No description provided</i>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
<v-card class="mt-5 pa-4" elevation="0" rounded="lg">
|
||||
<v-subheader class="text-uppercase">
|
||||
Commits ({{ stream.branch.commits.totalCount }})
|
||||
</v-subheader>
|
||||
|
||||
@@ -3,38 +3,30 @@
|
||||
<v-col v-if="$apollo.queries.stream.loading">
|
||||
<v-skeleton-loader type="article"></v-skeleton-loader>
|
||||
</v-col>
|
||||
<v-col v-else-if="branches" cols="12">
|
||||
<v-col v-else-if="stream" cols="12">
|
||||
<breadcrumb-title />
|
||||
<v-card rounded="lg" class="pa-4 mb-4" elevation="0">
|
||||
<branch-new-dialog ref="newBranchDialog" />
|
||||
<h3 class="title font-italic font-weight-thin my-5">
|
||||
A branch represents a series of commits, you can see them as labels, folders etc
|
||||
</h3>
|
||||
|
||||
<v-card class="mt-5 pa-4" elevation="0" rounded="lg">
|
||||
<v-card-title>
|
||||
<v-icon class="mr-2">mdi-source-branch</v-icon>
|
||||
Branches
|
||||
|
||||
<span class="d-inline-block">Branches ({{ branches.length }})</span>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
v-if="stream.role === 'stream:contributor' || stream.role === 'stream:owner'"
|
||||
color="primary"
|
||||
text
|
||||
class="px-0"
|
||||
class="my-2"
|
||||
small
|
||||
@click="newBranch"
|
||||
>
|
||||
<v-icon small class="mr-2 float-left">mdi-plus-circle-outline</v-icon>
|
||||
<!-- <v-icon small class="mr-2 float-left">mdi-plus-circle-outline</v-icon> -->
|
||||
New branch
|
||||
</v-btn>
|
||||
<branch-new-dialog ref="newBranchDialog" />
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<i>
|
||||
A branch represents an independent line of data. You can think of them as an independent
|
||||
directory, staging area and project history.
|
||||
</i>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
<v-card v-if="!$apollo.queries.stream.loading" class="mt-5 pa-4" elevation="0" rounded="lg">
|
||||
<v-subheader class="text-uppercase">Branches ({{ branches.length }})</v-subheader>
|
||||
<v-card-text>
|
||||
<v-list two-line color="transparent">
|
||||
<template v-for="item in branches">
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<v-row>
|
||||
<v-col cols="12">
|
||||
<breadcrumb-title />
|
||||
<h3 class="title font-italic font-weight-thin my-5">Manage who has access to this Stream</h3>
|
||||
|
||||
<collaborators-manage />
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'Collaborators',
|
||||
components: {
|
||||
BreadcrumbTitle: () => import('@/components/BreadcrumbTitle'),
|
||||
CollaboratorsManage: () => import('@/components/CollaboratorsManage')
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -2,37 +2,49 @@
|
||||
<v-row>
|
||||
<v-col>
|
||||
<breadcrumb-title />
|
||||
<h3 class="title font-italic font-weight-thin my-5">
|
||||
Globals store design values, project requirements, notes etc
|
||||
</h3>
|
||||
<div v-if="!objectId && !$apollo.loading && !revealBuilder">
|
||||
<v-card :loading="loading">
|
||||
<v-card :loading="loading" class="mt-5 pa-4" elevation="0" rounded="lg">
|
||||
<template slot="progress">
|
||||
<v-progress-linear indeterminate></v-progress-linear>
|
||||
</template>
|
||||
<v-card-title>You don't have any globals on this stream!</v-card-title>
|
||||
<v-card-text
|
||||
v-if="stream.role === 'stream:contributor' || stream.role === 'stream:owner'"
|
||||
class="subtitle-1"
|
||||
>
|
||||
Globals are useful for storing design values, project requirements, notes, or any info
|
||||
you want to keep track of alongside your geometry. Would you like to create some now?
|
||||
</v-card-text>
|
||||
<v-card-text
|
||||
v-if="!(stream.role === 'contributor') && !(stream.role === 'stream:owner')"
|
||||
class="subtitle-1"
|
||||
>
|
||||
Globals are useful for storing design values, project requirements, notes, or any info
|
||||
you want to keep track of alongside your geometry. You don't have permission to create
|
||||
and edit globals on this stream, but you can create your own stream to try them out!
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-card-title>
|
||||
<v-icon class="mr-2">mdi-earth</v-icon>
|
||||
Globals
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
v-if="stream.role === 'stream:contributor' || stream.role === 'stream:owner'"
|
||||
color="primary"
|
||||
dark
|
||||
class="ma-2"
|
||||
small
|
||||
@click="createClicked"
|
||||
>
|
||||
create globals
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card-title>
|
||||
<v-card-text class="subtitle-1">
|
||||
There are no globals in this stream yet.
|
||||
<br />
|
||||
Globals are useful for storing design values, project requirements, notes, or any info
|
||||
you want to keep track of alongside your geometry.
|
||||
<strong v-if="!(stream.role === 'contributor') && !(stream.role === 'stream:owner')">
|
||||
<br />
|
||||
<br />
|
||||
You don't have permission to create globals in this stream.
|
||||
</strong>
|
||||
<v-btn
|
||||
text
|
||||
small
|
||||
color="primary"
|
||||
href="https://speckle.guide/user/web.html#globals"
|
||||
target="_blank"
|
||||
>
|
||||
Read the docs
|
||||
</v-btn>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</div>
|
||||
<div v-if="objectId || revealBuilder">
|
||||
@@ -52,7 +64,7 @@
|
||||
>
|
||||
<v-card-title>
|
||||
<v-icon class="mr-2">mdi-history</v-icon>
|
||||
History
|
||||
Globals History
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<list-item-commit
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
<template>
|
||||
<v-row v-if="!error">
|
||||
<v-col v-if="stream" cols="12">
|
||||
<breadcrumb-title />
|
||||
<h1 class="display-1">{{ stream.name }}</h1>
|
||||
<h3 class="title font-italic font-weight-thin my-5">
|
||||
{{ truncate(stream.description) }}
|
||||
</h3>
|
||||
<div class="mb-3">
|
||||
<span class="caption">
|
||||
Created
|
||||
<timeago v-tooltip="formatDate(stream.createdAt)" :datetime="stream.createdAt"></timeago>
|
||||
</span>
|
||||
<span class="ml-3 caption">
|
||||
Updated
|
||||
<timeago v-tooltip="formatDate(stream.updatedAt)" :datetime="stream.updatedAt"></timeago>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<v-chip>
|
||||
<v-icon small>mdi-source-branch</v-icon>
|
||||
@@ -32,14 +42,15 @@
|
||||
private
|
||||
</span>
|
||||
</v-chip>
|
||||
<span class="ml-3 caption">
|
||||
Created
|
||||
<timeago v-tooltip="formatDate(stream.createdAt)" :datetime="stream.createdAt"></timeago>
|
||||
</span>
|
||||
<span class="ml-3 caption">
|
||||
Updated
|
||||
<timeago v-tooltip="formatDate(stream.updatedAt)" :datetime="stream.updatedAt"></timeago>
|
||||
</span>
|
||||
<user-avatar
|
||||
v-for="(collab, i) in stream.collaborators"
|
||||
:id="collab.id"
|
||||
:key="i"
|
||||
:size="30"
|
||||
:avatar="collab.avatar"
|
||||
:name="collab.name"
|
||||
class="ml-1"
|
||||
></user-avatar>
|
||||
</div>
|
||||
</v-col>
|
||||
|
||||
@@ -103,16 +114,7 @@
|
||||
See commit details
|
||||
</v-btn>
|
||||
</v-sheet>
|
||||
<h3 class="title mt-4 mb-3">Collaborators</h3>
|
||||
|
||||
<user-avatar
|
||||
v-for="(collab, i) in stream.collaborators"
|
||||
:id="collab.id"
|
||||
:key="i"
|
||||
:size="40"
|
||||
:avatar="collab.avatar"
|
||||
:name="collab.name"
|
||||
></user-avatar>
|
||||
<no-data-placeholder v-if="!latestCommit" :message="`This branch has no commits.`" />
|
||||
</v-card>
|
||||
</div>
|
||||
|
||||
@@ -1,86 +1,86 @@
|
||||
<template>
|
||||
<admin-card :loading="loading" title="General">
|
||||
<v-card-text class="py-0 my-0">
|
||||
<v-form ref="form" v-model="valid" class="px-2" @submit.prevent="save">
|
||||
<v-text-field
|
||||
v-model="name"
|
||||
:rules="validation.nameRules"
|
||||
label="Name"
|
||||
hint="The name of this stream."
|
||||
/>
|
||||
<p class="subtitle-1">Description</p>
|
||||
<v-row>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<p class="caption">
|
||||
Use Markdown! Tips:
|
||||
<code>#, ##, ###</code>
|
||||
prefix headings, links:
|
||||
<code>[speckle](https://speckle.systems)</code>
|
||||
, images:
|
||||
<code></code>
|
||||
, list items are prefixed by
|
||||
<code>-</code>
|
||||
on new lines,
|
||||
<b>bold</b>
|
||||
text by surrounding it with
|
||||
<code>**</code>
|
||||
, etc.
|
||||
</p>
|
||||
<v-textarea
|
||||
<v-row>
|
||||
<v-col v-if="stream" cols="12">
|
||||
<breadcrumb-title />
|
||||
<h3 class="title font-italic font-weight-thin my-5">Fine tune this Stream's settings</h3>
|
||||
|
||||
<v-card class="mt-5 pa-4" elevation="0" rounded="lg" :loading="loading">
|
||||
<v-card-title>
|
||||
<v-icon class="mr-2">mdi-cog</v-icon>
|
||||
<span class="d-inline-block">General</span>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
<v-form ref="form" v-model="valid" class="px-2" @submit.prevent="save">
|
||||
<v-text-field
|
||||
v-model="name"
|
||||
:rules="validation.nameRules"
|
||||
label="Name"
|
||||
hint="The name of this stream."
|
||||
class="mt-5"
|
||||
/>
|
||||
<v-text-field
|
||||
v-model="description"
|
||||
auto-grow
|
||||
filled
|
||||
rows="10"
|
||||
style="font-size: 12px; line-height: 10px"
|
||||
></v-textarea>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="12" md="6">
|
||||
<p class="subtitle">Preview</p>
|
||||
<div class="marked-preview" v-html="compiledMarkdown"></div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-switch
|
||||
v-model="isPublic"
|
||||
:label="isPublic ? 'Public' : 'Private'"
|
||||
:hint="
|
||||
isPublic
|
||||
? 'Anyone can view this stream. It is also visible on your profile page. Only collaborators can edit it.'
|
||||
: 'Only collaborators can access this stream.'
|
||||
"
|
||||
persistent-hint
|
||||
/>
|
||||
</v-form>
|
||||
</v-card-text>
|
||||
label="Description"
|
||||
hint="The description of this stream."
|
||||
class="mt-5"
|
||||
/>
|
||||
|
||||
<v-divider class="mt-4 mb-3" />
|
||||
<v-switch
|
||||
v-model="isPublic"
|
||||
class="mt-5"
|
||||
:label="isPublic ? 'Public' : 'Private'"
|
||||
:hint="
|
||||
isPublic
|
||||
? 'Anyone can view this stream. It is also visible on your profile page. Only collaborators can edit it.'
|
||||
: 'Only collaborators can access this stream.'
|
||||
"
|
||||
persistent-hint
|
||||
/>
|
||||
</v-form>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions>
|
||||
<v-btn outlined color="success" type="submit" :disabled="!valid" @click="save">
|
||||
Save Changes
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</admin-card>
|
||||
<v-card-actions>
|
||||
<v-btn class="ml-3 mt-5" color="primary" type="submit" :disabled="!canSave" @click="save">
|
||||
Save Changes
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-col>
|
||||
<v-snackbar v-model="snackbar" timeout="800" color="primary">
|
||||
<p class="text-center my-0">
|
||||
<b>Changes saved!</b>
|
||||
</p>
|
||||
</v-snackbar>
|
||||
</v-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import marked from 'marked'
|
||||
import DOMPurify from 'dompurify'
|
||||
import gql from 'graphql-tag'
|
||||
import streamQuery from '@/graphql/stream.gql'
|
||||
|
||||
export default {
|
||||
name: 'SettingsGeneral',
|
||||
components: {
|
||||
AdminCard: () => import('@/components/admin/AdminCard')
|
||||
BreadcrumbTitle: () => import('@/components/BreadcrumbTitle')
|
||||
},
|
||||
apollo: {
|
||||
stream: {
|
||||
query: streamQuery,
|
||||
query: gql`
|
||||
query Stream($id: String!) {
|
||||
stream(id: $id) {
|
||||
id
|
||||
name
|
||||
description
|
||||
isPublic
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables() {
|
||||
return {
|
||||
id: this.$attrs.streamId
|
||||
id: this.$route.params.streamId
|
||||
}
|
||||
},
|
||||
|
||||
update(data) {
|
||||
let stream = data.stream
|
||||
if (stream)
|
||||
@@ -91,6 +91,7 @@ export default {
|
||||
}
|
||||
},
|
||||
data: () => ({
|
||||
snackbar: false,
|
||||
loading: false,
|
||||
valid: false,
|
||||
name: null,
|
||||
@@ -101,12 +102,16 @@ export default {
|
||||
}
|
||||
}),
|
||||
computed: {
|
||||
compiledMarkdown() {
|
||||
if (!this.description) return ''
|
||||
let md = marked(this.description)
|
||||
return DOMPurify.sanitize(md)
|
||||
canSave() {
|
||||
return (
|
||||
this.valid &&
|
||||
(this.name !== this.stream.name ||
|
||||
this.description !== this.stream.description ||
|
||||
this.isPublic !== this.stream.isPublic)
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
async save() {
|
||||
this.loading = true
|
||||
@@ -127,6 +132,7 @@ export default {
|
||||
}
|
||||
}
|
||||
})
|
||||
this.snackbar = true
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
<v-row>
|
||||
<v-col>
|
||||
<breadcrumb-title />
|
||||
<h3 class="title font-italic font-weight-thin my-5">
|
||||
Automate anything by adding webhooks to Stream events
|
||||
</h3>
|
||||
<admin-card v-if="selectedWebhook != undefined" :loading="loading" title="Edit Webhook">
|
||||
<template #subtitle>
|
||||
<v-icon dense class="text-subtitle-1 pr-1">mdi-webhook</v-icon>
|
||||
@@ -30,14 +33,28 @@
|
||||
|
||||
<admin-card v-else title="Webhooks" icon="mdi-webhook">
|
||||
<template #menu>
|
||||
<v-btn small outlined color="primary" :to="`/streams/${$attrs.streamId}/webhooks/new`">
|
||||
<v-btn
|
||||
color="primary"
|
||||
dark
|
||||
class="ma-2"
|
||||
small
|
||||
:to="`/streams/${$attrs.streamId}/webhooks/new`"
|
||||
>
|
||||
Add Webhook
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
<v-card-text v-if="webhooks && webhooks.length == 0">
|
||||
You don't have any webhooks on this stream yet. Click the blue "Add Webhook" button in the
|
||||
top right to add one.
|
||||
There are no webhooks on this stream yet.
|
||||
<v-btn
|
||||
text
|
||||
small
|
||||
color="primary"
|
||||
href="https://speckle.guide/dev/server-webhooks.html"
|
||||
target="_blank"
|
||||
>
|
||||
Read the docs
|
||||
</v-btn>
|
||||
</v-card-text>
|
||||
|
||||
<v-list subheader two-line>
|
||||
|
||||
Reference in New Issue
Block a user