feat(frontend): 🧹
This commit is contained in:
@@ -5,7 +5,7 @@ Vue.prototype.$eventHub = new Vue()
|
||||
import App from './App.vue'
|
||||
|
||||
import { createProvider } from './vue-apollo'
|
||||
import { checkAccessCodeAndGetTokens, prefetchUserAndSetSuuid } from './auth-helpers'
|
||||
import { checkAccessCodeAndGetTokens, prefetchUserAndSetSuuid } from '@/plugins/authHelpers'
|
||||
|
||||
import router from './router'
|
||||
import vuetify from './plugins/vuetify'
|
||||
|
||||
+1
-1
@@ -277,7 +277,7 @@
|
||||
|
||||
<script>
|
||||
import UserAvatar from '@/cleanup/components/common/UserAvatar'
|
||||
import UserPill from './UserPill'
|
||||
import UserPill from '@/cleanup/components/activity/UserPill'
|
||||
import SourceAppAvatar from '@/cleanup/components/common/SourceAppAvatar'
|
||||
import PreviewImage from '@/cleanup/components/common/PreviewImage'
|
||||
import gql from 'graphql-tag'
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
</template>
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
import UserAvatar from './UserAvatar'
|
||||
import UserAvatar from '@/cleanup/components/common/UserAvatar'
|
||||
|
||||
export default {
|
||||
components: { UserAvatar },
|
||||
@@ -9,7 +9,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { signOut } from '@/auth-helpers'
|
||||
import { signOut } from '@/plugins/authHelpers'
|
||||
import userQuery from '@/graphql/userById.gql'
|
||||
import UserAvatarIcon from '@/cleanup/components/common/UserAvatarIcon'
|
||||
|
||||
|
||||
@@ -277,7 +277,7 @@
|
||||
|
||||
<script>
|
||||
import UserAvatar from '@/cleanup/components/common/UserAvatar'
|
||||
import UserPill from '@/components/UserPill'
|
||||
import UserPill from '@/cleanup/components/activity/UserPill'
|
||||
import SourceAppAvatar from '@/cleanup/components/common/SourceAppAvatar'
|
||||
import PreviewImage from '@/cleanup/components/common/PreviewImage'
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
@@ -277,7 +277,7 @@
|
||||
|
||||
<script>
|
||||
import UserAvatar from '@/cleanup/components/common/UserAvatar'
|
||||
import UserPill from '@/components/UserPill'
|
||||
import UserPill from '@/cleanup/components/activity/UserPill'
|
||||
import SourceAppAvatar from '@/cleanup/components/common/SourceAppAvatar'
|
||||
import PreviewImage from '@/cleanup/components/common/PreviewImage'
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
@@ -76,7 +76,7 @@ export default {
|
||||
name: 'Timeline',
|
||||
components: {
|
||||
InfiniteLoading: () => import('vue-infinite-loading'),
|
||||
ListItemActivity: () => import('@/cleanup/components/feed/ListItemActivity2'),
|
||||
ListItemActivity: () => import('@/cleanup/components/activity/ListItemActivity'),
|
||||
NoDataPlaceholder: () => import('@/cleanup/components/common/NoDataPlaceholder')
|
||||
},
|
||||
props: {
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
import UserDeleteDialog from '@/cleanup/dialogs/UserDeleteDialog'
|
||||
import { signOut } from '@/auth-helpers'
|
||||
import { signOut } from '@/plugins/authHelpers'
|
||||
|
||||
export default {
|
||||
components: { UserDeleteDialog },
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
import DOMPurify from 'dompurify'
|
||||
import { isEmailValid } from '@/auth-helpers'
|
||||
import { isEmailValid } from '@/plugins/authHelpers'
|
||||
|
||||
export default {
|
||||
name: 'ServerInviteDialog',
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
import DOMPurify from 'dompurify'
|
||||
import { isEmailValid } from '@/auth-helpers'
|
||||
import { isEmailValid } from '@/plugins/authHelpers'
|
||||
|
||||
export default {
|
||||
name: 'StreamInviteDialog',
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { signOut } from '@/auth-helpers'
|
||||
import { signOut } from '@/plugins/authHelpers'
|
||||
import userQuery from '@/graphql/user.gql'
|
||||
|
||||
export default {
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
import DOMPurify from 'dompurify'
|
||||
import { isEmailValid } from '@/auth-helpers'
|
||||
import { isEmailValid } from '@/plugins/authHelpers'
|
||||
|
||||
export default {
|
||||
name: 'AdminInvites',
|
||||
|
||||
@@ -81,8 +81,8 @@
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
import crs from 'crypto-random-string'
|
||||
import Strategies from '@/components/auth/Strategies'
|
||||
import { isEmailValid } from '@/auth-helpers'
|
||||
import Strategies from '@/cleanup/components/auth/Strategies'
|
||||
import { isEmailValid } from '@/plugins/authHelpers'
|
||||
|
||||
export default {
|
||||
name: 'Login',
|
||||
|
||||
@@ -165,7 +165,7 @@ import debounce from 'lodash.debounce'
|
||||
import crs from 'crypto-random-string'
|
||||
|
||||
import Strategies from '@/cleanup/components/auth/Strategies'
|
||||
import { isEmailValid } from '@/auth-helpers'
|
||||
import { isEmailValid } from '@/plugins/authHelpers'
|
||||
|
||||
export default {
|
||||
name: 'Registration',
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
</template>
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
import { isEmailValid } from '@/auth-helpers'
|
||||
import { isEmailValid } from '@/plugins/authHelpers'
|
||||
|
||||
export default {
|
||||
name: 'ResetPasswordRequest',
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
<template>
|
||||
<v-row>
|
||||
<v-col cols="12">
|
||||
<v-timeline v-if="stream && groupedActivity && groupedActivity.length !== 0" align-top dense>
|
||||
<list-item-activity
|
||||
v-for="activity in groupedActivity"
|
||||
:key="activity.time"
|
||||
:activity="activity"
|
||||
:activity-group="activity"
|
||||
class="my-1"
|
||||
></list-item-activity>
|
||||
<infinite-loading
|
||||
v-if="stream.activity && stream.activity.items.length < stream.activity.totalCount"
|
||||
@infinite="infiniteHandler"
|
||||
>
|
||||
<div slot="no-more">This is all your activity!</div>
|
||||
<div slot="no-results">There are no ctivities to load</div>
|
||||
</infinite-loading>
|
||||
</v-timeline>
|
||||
<v-timeline v-else-if="$apollo.loading" align-top dense>
|
||||
<v-timeline-item v-for="i in 6" :key="i" medium>
|
||||
<v-skeleton-loader type="article"></v-skeleton-loader>
|
||||
</v-timeline-item>
|
||||
</v-timeline>
|
||||
<div v-if="groupedActivity && groupedActivity.length === 0">
|
||||
<v-card class="transparent elevation-0 mt-10">
|
||||
<v-card-text>Nothing to show 🍃</v-card-text>
|
||||
</v-card>
|
||||
</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export default {
|
||||
name: 'Activity',
|
||||
components: {
|
||||
ListItemActivity: () => import('@/cleanup/components/activity/ListItemActivity'),
|
||||
InfiniteLoading: () => import('vue-infinite-loading')
|
||||
},
|
||||
data() {
|
||||
return { groupedActivity: null }
|
||||
},
|
||||
apollo: {
|
||||
stream: {
|
||||
query: gql`
|
||||
query Stream($id: String!, $cursor: DateTime) {
|
||||
stream(id: $id) {
|
||||
id
|
||||
name
|
||||
createdAt
|
||||
commits {
|
||||
totalCount
|
||||
}
|
||||
branches {
|
||||
totalCount
|
||||
}
|
||||
activity(cursor: $cursor) {
|
||||
totalCount
|
||||
cursor
|
||||
items {
|
||||
actionType
|
||||
userId
|
||||
streamId
|
||||
resourceId
|
||||
resourceType
|
||||
time
|
||||
info
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables() {
|
||||
return {
|
||||
id: this.$route.params.streamId
|
||||
}
|
||||
},
|
||||
result({ data }) {
|
||||
this.groupSimilarActivities(data)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
groupSimilarActivities(data) {
|
||||
let groupedActivity = data.stream.activity.items.reduce(function (prev, curr) {
|
||||
//first item
|
||||
if (!prev.length) {
|
||||
prev.push([curr])
|
||||
return prev
|
||||
}
|
||||
let test = prev[prev.length - 1][0]
|
||||
let action = 'split' // split | combine | skip
|
||||
if (curr.actionType === test.actionType && curr.streamId === test.streamId) {
|
||||
if (curr.actionType.includes('stream_permissions')) {
|
||||
//skip multiple stream_permission actions on the same user, just pick the last!
|
||||
if (prev[prev.length - 1].some((x) => x.info.targetUser === curr.info.targetUser))
|
||||
action = 'skip'
|
||||
else action = 'combine'
|
||||
} //stream, branch, commit
|
||||
else if (curr.actionType.includes('_update') || curr.actionType === 'commit_create')
|
||||
action = 'combine'
|
||||
}
|
||||
if (action === 'combine') {
|
||||
prev[prev.length - 1].push(curr)
|
||||
} else if (action === 'split') {
|
||||
prev.push([curr])
|
||||
}
|
||||
return prev
|
||||
}, [])
|
||||
// console.log(groupedTimeline)
|
||||
this.groupedActivity = groupedActivity
|
||||
},
|
||||
infiniteHandler($state) {
|
||||
this.$apollo.queries.stream.fetchMore({
|
||||
variables: {
|
||||
cursor: this.stream.activity.cursor
|
||||
},
|
||||
// Transform the previous result with new data
|
||||
updateQuery: (previousResult, { fetchMoreResult }) => {
|
||||
const newItems = fetchMoreResult.stream.activity.items
|
||||
|
||||
//set vue-infinite state
|
||||
if (newItems.length === 0) $state.complete()
|
||||
else $state.loaded()
|
||||
|
||||
fetchMoreResult.stream.activity.items = [
|
||||
...previousResult.stream.activity.items,
|
||||
...newItems
|
||||
]
|
||||
|
||||
return fetchMoreResult
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -49,7 +49,7 @@
|
||||
</template>
|
||||
<script>
|
||||
import userQuery from '@/graphql/user.gql'
|
||||
import { signOut } from '@/auth-helpers'
|
||||
import { signOut } from '@/plugins/authHelpers'
|
||||
export default {
|
||||
name: 'Profile',
|
||||
components: {
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
<template>
|
||||
<v-chip
|
||||
v-tooltip="`Source Application: ${applicationName ? applicationName : 'unknown'}`"
|
||||
x-small
|
||||
class="ma-1 caption white--text no-hover"
|
||||
:color="color"
|
||||
>
|
||||
{{ shortName }}
|
||||
</v-chip>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
applicationName: {
|
||||
type: String,
|
||||
default: '?'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// adding new colors?
|
||||
// this can help: https://codepen.io/teocomi/pen/vYxvREG?editors=1010
|
||||
color() {
|
||||
if (!this.applicationName) return 'grey'
|
||||
|
||||
let appname = this.applicationName.toLowerCase()
|
||||
|
||||
if (appname.includes('dynamo')) return 'purple'
|
||||
if (appname.includes('revit')) return 'blue darken-3'
|
||||
if (appname.includes('autocad')) return 'red lighten-1'
|
||||
if (appname.includes('civil')) return 'blue lighten-1'
|
||||
if (appname.includes('blender')) return 'orange darken-1'
|
||||
if (appname.includes('rhino')) return 'black'
|
||||
if (appname.includes('grasshopper')) return 'green darken-2'
|
||||
if (appname.includes('excel')) return 'green lighten-1'
|
||||
if (appname.includes('unity')) return 'teal'
|
||||
if (appname.includes('unreal')) return 'brown'
|
||||
if (appname.includes('python')) return 'yellow darken-1'
|
||||
if (appname.includes('.net')) return 'purple darken-2'
|
||||
return 'grey'
|
||||
},
|
||||
shortName() {
|
||||
if (!this.applicationName) return '?'
|
||||
|
||||
let appname = this.applicationName.toLowerCase()
|
||||
|
||||
if (appname.includes('dynamo')) return 'DYN'
|
||||
if (appname.includes('revit')) return 'RVT'
|
||||
if (appname.includes('autocad')) return 'ACAD'
|
||||
if (appname.includes('civil')) return 'C3D'
|
||||
if (appname.includes('blender')) return 'BLNDR'
|
||||
if (appname.includes('rhino')) return 'RH'
|
||||
if (appname.includes('grasshopper')) return 'GH'
|
||||
if (appname.includes('excel')) return 'XLSX'
|
||||
if (appname.includes('unity')) return 'UNITY'
|
||||
if (appname.includes('unreal')) return 'UE'
|
||||
if (appname.includes('python')) return 'PY'
|
||||
if (appname.includes('.net')) return '.NET'
|
||||
return appname
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,109 +0,0 @@
|
||||
<template>
|
||||
<div style="display: inline-block">
|
||||
<v-menu v-if="loggedIn" offset-x open-on-hover>
|
||||
<template #activator="{ on, attrs }">
|
||||
<div v-bind="attrs" v-on="on">
|
||||
<user-avatar-icon
|
||||
v-if="userById"
|
||||
:size="size"
|
||||
:avatar="userById.avatar"
|
||||
:seed="id"
|
||||
v-bind="attrs"
|
||||
class="ma-1"
|
||||
></user-avatar-icon>
|
||||
<v-avatar v-else class="ma-1" :size="size">
|
||||
<v-img contain src="/logo.svg"></v-img>
|
||||
</v-avatar>
|
||||
</div>
|
||||
</template>
|
||||
<v-card
|
||||
v-if="userById && showHover"
|
||||
style="width: 200px"
|
||||
:to="isSelf ? '/profile' : '/profile/' + id"
|
||||
>
|
||||
<v-card-text v-if="!$apollo.loading" class="text-center">
|
||||
<user-avatar-icon class="my-4" :size="40" :avatar="avatar" :seed="id"></user-avatar-icon>
|
||||
|
||||
<!-- Uncomment when email verification is in place -->
|
||||
<!-- <div v-if="userById.verified" class="mb-1">
|
||||
<v-chip color="primary" small>
|
||||
<v-icon small class="mr-2">mdi-shield</v-icon>
|
||||
verified email
|
||||
</v-chip>
|
||||
</div> -->
|
||||
|
||||
<div>
|
||||
<b>{{ userById.name }}</b>
|
||||
</div>
|
||||
<div class="caption">
|
||||
{{ userById.company }}
|
||||
<br />
|
||||
{{ userById.bio ? 'Bio: ' + userById.bio : '' }}
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
<v-card v-else-if="showHover">
|
||||
<v-card-text class="text-xs">
|
||||
<b>Speckle Ghost</b>
|
||||
<br />
|
||||
This user no longer exists.
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-menu>
|
||||
<user-avatar-icon
|
||||
v-else
|
||||
class="ma-1"
|
||||
:size="size"
|
||||
:avatar="avatar"
|
||||
:seed="id"
|
||||
></user-avatar-icon>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import userByIdQuery from '../graphql/userById.gql'
|
||||
import UserAvatarIcon from '@/components/UserAvatarIcon'
|
||||
|
||||
export default {
|
||||
components: { UserAvatarIcon },
|
||||
props: {
|
||||
avatar: String,
|
||||
name: String,
|
||||
showHover: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
size: {
|
||||
type: Number,
|
||||
default: 42
|
||||
},
|
||||
id: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isSelf() {
|
||||
return this.id === localStorage.getItem('uuid')
|
||||
},
|
||||
loggedIn() {
|
||||
return localStorage.getItem('uuid') !== null
|
||||
}
|
||||
},
|
||||
apollo: {
|
||||
userById: {
|
||||
query: userByIdQuery,
|
||||
variables() {
|
||||
return {
|
||||
id: this.id
|
||||
}
|
||||
},
|
||||
skip() {
|
||||
return !this.loggedIn
|
||||
},
|
||||
update: (data) => {
|
||||
return data.user
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,25 +0,0 @@
|
||||
<template>
|
||||
<v-avatar :size="size" color="grey lighten-3">
|
||||
<v-img v-if="avatar" :src="avatar" />
|
||||
<v-img v-else :src="`https://robohash.org/${seed}.png?size=${size}x${size}`" />
|
||||
</v-avatar>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
size: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
seed: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
avatar: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -36,7 +36,7 @@ import gql from 'graphql-tag'
|
||||
export default {
|
||||
name: 'Activity',
|
||||
components: {
|
||||
ListItemActivity: () => import('@/components/ListItemActivity'),
|
||||
ListItemActivity: () => import('@/cleanup/components/activity/ListItemActivity'),
|
||||
InfiniteLoading: () => import('vue-infinite-loading')
|
||||
},
|
||||
data() {
|
||||
|
||||
Reference in New Issue
Block a user