feat(fe1 & fe2): guest role (#1768)
* feat: user guest role switching in FE1 * removed stream create buttons * fe1 done * fe1 - specifying role in invite dialogs * fe1 - bulk invites * WIP FE2 changes * fe1: allow role select condition fixes * xtra limitations on createForOnboarding * more invite creation validations * no longer able to set guest as project owner in invite * preparations for server role select in invite dialog * team management dialog done * server invite dialog updated * hiding invite dialog * fixed mocks
This commit is contained in:
committed by
GitHub
parent
872cb3fe7c
commit
069f64afc9
@@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<FormSelectBase
|
||||
v-model="selectedValue"
|
||||
:items="roles"
|
||||
:multiple="multiple"
|
||||
:disabled-item-predicate="disabledItemPredicate"
|
||||
name="serverRoles"
|
||||
label="Server roles"
|
||||
class="min-w-[110px]"
|
||||
>
|
||||
<template #nothing-selected>
|
||||
{{ multiple ? 'Select roles' : 'Select role' }}
|
||||
</template>
|
||||
<template #something-selected="{ value }">
|
||||
<template v-if="isMultiItemArrayValue(value)">
|
||||
<div ref="elementToWatchForChanges" class="flex items-center space-x-0.5">
|
||||
<div
|
||||
ref="itemContainer"
|
||||
class="flex flex-wrap overflow-hidden space-x-0.5 h-6"
|
||||
>
|
||||
<div v-for="(item, i) in value" :key="item" class="text-foreground">
|
||||
{{ RoleInfo.Server[item] + (i < value.length - 1 ? ', ' : '') }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="hiddenSelectedItemCount > 0" class="text-foreground-2 normal">
|
||||
+{{ hiddenSelectedItemCount }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="truncate text-foreground">
|
||||
{{ RoleInfo.Server[firstItem(value)] }}
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<template #option="{ item }">
|
||||
<div class="flex items-center">
|
||||
<span class="truncate">{{ RoleInfo.Server[firstItem(item)] }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</FormSelectBase>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { Nullable, Roles, ServerRoles, RoleInfo } from '@speckle/shared'
|
||||
import { useFormSelectChildInternals } from '@speckle/ui-components'
|
||||
import { PropType } from 'nuxt/dist/app/compat/capi'
|
||||
|
||||
type ValueType = ServerRoles | ServerRoles[] | undefined
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', v: ValueType): void
|
||||
}>()
|
||||
|
||||
const props = defineProps({
|
||||
multiple: Boolean,
|
||||
modelValue: {
|
||||
type: [String, Array] as PropType<ValueType>,
|
||||
default: undefined
|
||||
},
|
||||
allowGuest: Boolean,
|
||||
allowAdmin: Boolean,
|
||||
allowArchived: Boolean
|
||||
})
|
||||
|
||||
const elementToWatchForChanges = ref(null as Nullable<HTMLElement>)
|
||||
const itemContainer = ref(null as Nullable<HTMLElement>)
|
||||
|
||||
const { selectedValue, isMultiItemArrayValue, hiddenSelectedItemCount, firstItem } =
|
||||
useFormSelectChildInternals<ServerRoles>({
|
||||
props: toRefs(props),
|
||||
emit,
|
||||
dynamicVisibility: { elementToWatchForChanges, itemContainer }
|
||||
})
|
||||
|
||||
const roles = computed(() =>
|
||||
Object.values(Roles.Server).filter((r) => {
|
||||
if (r === Roles.Server.Admin) return props.allowAdmin
|
||||
if (r === Roles.Server.ArchivedUser) return props.allowArchived
|
||||
return true
|
||||
})
|
||||
)
|
||||
|
||||
const disabledItemPredicate = (item: ServerRoles) => {
|
||||
if (item === Roles.Server.Guest) return !props.allowGuest
|
||||
return false
|
||||
}
|
||||
</script>
|
||||
@@ -56,7 +56,7 @@
|
||||
<Icon class="w-5 h-5 mr-2" />
|
||||
</NuxtLink>
|
||||
</MenuItem>
|
||||
<MenuItem v-if="activeUser" v-slot="{ active }">
|
||||
<MenuItem v-if="activeUser && !isGuest" v-slot="{ active }">
|
||||
<NuxtLink
|
||||
:class="[
|
||||
active ? 'bg-foundation-focus' : '',
|
||||
@@ -124,7 +124,7 @@ import { useTheme, AppTheme } from '~~/lib/core/composables/theme'
|
||||
import { serverVersionInfoQuery } from '~~/lib/core/graphql/queries'
|
||||
|
||||
const { logout } = useAuthManager()
|
||||
const { activeUser } = useActiveUser()
|
||||
const { activeUser, isGuest } = useActiveUser()
|
||||
const { isDarkTheme, setTheme } = useTheme()
|
||||
const { result } = useQuery(serverVersionInfoQuery)
|
||||
const route = useRoute()
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
<template>
|
||||
<LayoutDialog v-model:open="isOpen" max-width="md">
|
||||
<div class="flex flex-col text-foreground space-y-4">
|
||||
<ProjectPageTeamDialogInviteUser v-if="isOwner" :project="project" />
|
||||
<ProjectPageTeamDialogInviteUser
|
||||
v-if="isOwner && !isServerGuest"
|
||||
:project="project"
|
||||
/>
|
||||
<ProjectPageTeamDialogManageUsers :project="project" />
|
||||
<ProjectPageTeamDialogManagePermissions :project="project" />
|
||||
</div>
|
||||
@@ -23,6 +26,7 @@ graphql(`
|
||||
role
|
||||
user {
|
||||
...LimitedUserAvatar
|
||||
role
|
||||
}
|
||||
}
|
||||
invitedTeam {
|
||||
@@ -32,6 +36,7 @@ graphql(`
|
||||
role
|
||||
user {
|
||||
...LimitedUserAvatar
|
||||
role
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,7 +51,7 @@ const props = defineProps<{
|
||||
project: ProjectPageTeamDialogFragment
|
||||
}>()
|
||||
|
||||
const { isOwner } = useTeamDialogInternals({ props: toRefs(props) })
|
||||
const { isOwner, isServerGuest } = useTeamDialogInternals({ props: toRefs(props) })
|
||||
|
||||
const isOpen = computed({
|
||||
get: () => props.open,
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { roleSelectItems } from '~~/lib/projects/helpers/components'
|
||||
import { StreamRoles } from '@speckle/shared'
|
||||
import { Roles, StreamRoles } from '@speckle/shared'
|
||||
import { reduce } from 'lodash-es'
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -48,15 +48,25 @@ const props = defineProps<{
|
||||
name?: string
|
||||
disabled?: boolean
|
||||
hideRemove?: boolean
|
||||
hideOwner?: boolean
|
||||
}>()
|
||||
|
||||
const items = ref(
|
||||
reduce(
|
||||
roleSelectItems,
|
||||
(results, item) => {
|
||||
if (!props.hideRemove || item.id !== 'delete') {
|
||||
if (item.id === 'delete') {
|
||||
if (!props.hideRemove) {
|
||||
results[item.id] = item
|
||||
}
|
||||
} else if (item.id === Roles.Stream.Owner) {
|
||||
if (!props.hideOwner) {
|
||||
results[item.id] = item
|
||||
}
|
||||
} else {
|
||||
results[item.id] = item
|
||||
}
|
||||
|
||||
return results
|
||||
},
|
||||
{} as typeof roleSelectItems
|
||||
|
||||
@@ -18,38 +18,35 @@
|
||||
</div>
|
||||
</template>
|
||||
</FormTextInput>
|
||||
<div v-if="searchUsers.length || selectedEmails" class="flex flex-col space-y-4">
|
||||
<div
|
||||
v-if="searchUsers.length || selectedEmails?.length"
|
||||
class="flex flex-col space-y-4"
|
||||
>
|
||||
<template v-if="searchUsers.length">
|
||||
<template v-for="user in searchUsers" :key="user.id">
|
||||
<div class="flex items-center space-x-2">
|
||||
<UserAvatar :user="user" />
|
||||
<span class="grow truncate">{{ user.name }}</span>
|
||||
<FormButton :disabled="loading" @click="onInviteUser(user)">
|
||||
Invite
|
||||
</FormButton>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else-if="selectedEmails?.length">
|
||||
<div class="flex items-center space-x-2">
|
||||
<UserAvatar />
|
||||
<span class="grow truncate">{{ selectedEmails.join(', ') }}</span>
|
||||
<FormButton
|
||||
:disabled="loading"
|
||||
@click="() => onInviteUser(selectedEmails || [])"
|
||||
>
|
||||
Invite
|
||||
</FormButton>
|
||||
</div>
|
||||
<ProjectPageTeamDialogInviteUserServerUserRow
|
||||
v-for="user in searchUsers"
|
||||
:key="user.id"
|
||||
:user="user"
|
||||
:stream-role="role"
|
||||
:disabled="loading"
|
||||
@invite-user="($event) => onInviteUser($event.user)"
|
||||
/>
|
||||
</template>
|
||||
<ProjectPageTeamDialogInviteUserEmailsRow
|
||||
v-else-if="selectedEmails?.length"
|
||||
:selected-emails="selectedEmails"
|
||||
:stream-role="role"
|
||||
:disabled="loading"
|
||||
:is-guest-mode="isGuestMode"
|
||||
@invite-emails="($event) => onInviteUser($event.emails, $event.serverRole)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { Roles } from '@speckle/shared'
|
||||
import { Get } from 'type-fest'
|
||||
import { useUserSearch } from '~~/lib/common/composables/users'
|
||||
import { Roles, ServerRoles, StreamRoles } from '@speckle/shared'
|
||||
import { UserSearchItem, useUserSearch } from '~~/lib/common/composables/users'
|
||||
import {
|
||||
ProjectInviteCreateInput,
|
||||
ProjectPageTeamDialogFragment
|
||||
@@ -61,8 +58,9 @@ import { useInviteUserToProject } from '~~/lib/projects/composables/projectManag
|
||||
import { useTeamDialogInternals } from '~~/lib/projects/composables/team'
|
||||
import { UserPlusIcon } from '@heroicons/vue/24/solid'
|
||||
import { useMixpanel } from '~~/lib/core/composables/mp'
|
||||
import { useServerInfo } from '~~/lib/core/composables/server'
|
||||
|
||||
type InvitableUser = NonNullable<Get<typeof searchUsers.value, '[0]'>> | string
|
||||
type InvitableUser = UserSearchItem | string
|
||||
|
||||
const props = defineProps<{
|
||||
project: ProjectPageTeamDialogFragment
|
||||
@@ -70,8 +68,9 @@ const props = defineProps<{
|
||||
|
||||
const loading = ref(false)
|
||||
const search = ref('')
|
||||
const role = ref(Roles.Stream.Contributor)
|
||||
const role = ref<StreamRoles>(Roles.Stream.Contributor)
|
||||
|
||||
const { isGuestMode } = useServerInfo()
|
||||
const createInvite = useInviteUserToProject()
|
||||
const { userSearch, searchVariables } = useUserSearch({
|
||||
variables: computed(() => ({
|
||||
@@ -83,6 +82,17 @@ const { collaboratorListItems } = useTeamDialogInternals({
|
||||
props: toRefs(props)
|
||||
})
|
||||
|
||||
const selectedEmails = computed(() => {
|
||||
const query = searchVariables.value?.query || ''
|
||||
if (isValidEmail(query)) return [query]
|
||||
|
||||
const multipleEmails = query.split(',').map((i) => i.trim())
|
||||
const validEmails = multipleEmails.filter((e) => isValidEmail(e))
|
||||
return validEmails.length ? validEmails : null
|
||||
})
|
||||
|
||||
const isOwnerSelected = computed(() => role.value === Roles.Stream.Owner)
|
||||
|
||||
const searchUsers = computed(() => {
|
||||
const searchResults = userSearch.value?.userSearch.items || []
|
||||
const collaboratorIds = new Set(
|
||||
@@ -103,15 +113,22 @@ const isValidEmail = (val: string) =>
|
||||
: false
|
||||
|
||||
const mp = useMixpanel()
|
||||
const onInviteUser = async (user: InvitableUser | InvitableUser[]) => {
|
||||
const users = isArray(user) ? user : [user]
|
||||
const onInviteUser = async (
|
||||
user: InvitableUser | InvitableUser[],
|
||||
serverRole?: ServerRoles
|
||||
) => {
|
||||
const users = (isArray(user) ? user : [user]).filter(
|
||||
(u) => !isOwnerSelected.value || isString(u) || u.role !== Roles.Server.Guest
|
||||
)
|
||||
|
||||
const inputs: ProjectInviteCreateInput[] = users
|
||||
.filter((u) => (isString(u) ? isValidEmail(u) : u))
|
||||
.map((u) => ({
|
||||
role: role.value,
|
||||
...(isString(u)
|
||||
? {
|
||||
email: u
|
||||
email: u,
|
||||
serverRole
|
||||
}
|
||||
: {
|
||||
userId: u.id
|
||||
@@ -136,13 +153,4 @@ const onInviteUser = async (user: InvitableUser | InvitableUser[]) => {
|
||||
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
const selectedEmails = computed(() => {
|
||||
const query = searchVariables.value?.query || ''
|
||||
if (isValidEmail(query)) return [query]
|
||||
|
||||
const multipleEmails = query.split(',').map((i) => i.trim())
|
||||
const validEmails = multipleEmails.filter((e) => isValidEmail(e))
|
||||
return validEmails.length ? validEmails : null
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
class="shrink-0"
|
||||
:model-value="collaborator.role"
|
||||
:disabled="loading"
|
||||
:hide-owner="collaborator.serverRole === Roles.Server.Guest"
|
||||
@update:model-value="onCollaboratorRoleChange(collaborator, $event)"
|
||||
@delete="onCollaboratorRoleChange(collaborator, null)"
|
||||
/>
|
||||
@@ -51,7 +52,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { Nullable, StreamRoles } from '@speckle/shared'
|
||||
import { Nullable, StreamRoles, Roles } from '@speckle/shared'
|
||||
import { useApolloClient } from '@vue/apollo-composable'
|
||||
import { useActiveUser } from '~~/lib/auth/composables/activeUser'
|
||||
import {
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
<template>
|
||||
<div class="flex items-center space-x-2">
|
||||
<UserAvatar />
|
||||
<span class="grow truncate">{{ selectedEmails.join(', ') }}</span>
|
||||
<div class="flex items-center space-x-2">
|
||||
<FormSelectServerRoles
|
||||
v-if="showServerRoleSelect"
|
||||
v-model="serverRole"
|
||||
:allow-guest="isGuestMode"
|
||||
:allow-admin="isAdmin"
|
||||
fixed-height
|
||||
/>
|
||||
<span
|
||||
v-tippy="
|
||||
isTryingToSetGuestOwner ? `Server guests can't be project owners` : undefined
|
||||
"
|
||||
>
|
||||
<FormButton
|
||||
:disabled="isButtonDisabled"
|
||||
@click="
|
||||
() =>
|
||||
$emit('invite-emails', {
|
||||
emails: selectedEmails || [],
|
||||
streamRole,
|
||||
serverRole: showServerRoleSelect ? serverRole : undefined
|
||||
})
|
||||
"
|
||||
>
|
||||
Invite
|
||||
</FormButton>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { Roles, StreamRoles, ServerRoles } from '@speckle/shared'
|
||||
import { useActiveUser } from '~~/lib/auth/composables/activeUser'
|
||||
|
||||
defineEmits<{
|
||||
(
|
||||
e: 'invite-emails',
|
||||
v: { emails: string[]; streamRole: StreamRoles; serverRole?: ServerRoles }
|
||||
): void
|
||||
}>()
|
||||
|
||||
const props = defineProps<{
|
||||
selectedEmails: string[]
|
||||
streamRole: StreamRoles
|
||||
disabled?: boolean
|
||||
isGuestMode?: boolean
|
||||
}>()
|
||||
|
||||
const { isAdmin } = useActiveUser()
|
||||
|
||||
const serverRole = ref<ServerRoles>(Roles.Server.User)
|
||||
|
||||
const showServerRoleSelect = computed(() => props.isGuestMode || isAdmin.value)
|
||||
|
||||
const isTryingToSetGuestOwner = computed(() => {
|
||||
if (!showServerRoleSelect.value) return false
|
||||
if (
|
||||
serverRole.value === Roles.Server.Guest &&
|
||||
props.streamRole === Roles.Stream.Owner
|
||||
)
|
||||
return true
|
||||
return false
|
||||
})
|
||||
|
||||
const isButtonDisabled = computed(() => {
|
||||
if (props.disabled) return true
|
||||
if (isTryingToSetGuestOwner.value) return true
|
||||
if (!props.selectedEmails.length) return true
|
||||
return false
|
||||
})
|
||||
</script>
|
||||
@@ -0,0 +1,42 @@
|
||||
<template>
|
||||
<div class="flex items-center space-x-2">
|
||||
<UserAvatar :user="user" />
|
||||
<span class="grow truncate">{{ user.name }}</span>
|
||||
<span
|
||||
v-tippy="
|
||||
isTryingToSetGuestOwner ? `Server guests can't be project owners` : undefined
|
||||
"
|
||||
>
|
||||
<FormButton
|
||||
:disabled="isButtonDisabled"
|
||||
@click="() => $emit('invite-user', { user, streamRole })"
|
||||
>
|
||||
Invite
|
||||
</FormButton>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { StreamRoles, Roles } from '@speckle/shared'
|
||||
import { UserSearchItem } from '~~/lib/common/composables/users'
|
||||
|
||||
defineEmits<{
|
||||
(e: 'invite-user', v: { user: UserSearchItem; streamRole: StreamRoles }): void
|
||||
}>()
|
||||
|
||||
const props = defineProps<{
|
||||
streamRole: StreamRoles
|
||||
user: UserSearchItem
|
||||
disabled?: boolean
|
||||
}>()
|
||||
|
||||
const isOwnerSelected = computed(() => props.streamRole === Roles.Stream.Owner)
|
||||
const isTryingToSetGuestOwner = computed(
|
||||
() => props.user.role === Roles.Server.Guest && isOwnerSelected.value
|
||||
)
|
||||
const isButtonDisabled = computed(() => {
|
||||
if (props.disabled) return true
|
||||
if (isTryingToSetGuestOwner.value) return true
|
||||
return false
|
||||
})
|
||||
</script>
|
||||
@@ -41,7 +41,11 @@
|
||||
class="w-56 grow md:grow-0"
|
||||
fixed-height
|
||||
/>
|
||||
<FormButton :icon-left="PlusIcon" @click="openNewProject = true">
|
||||
<FormButton
|
||||
v-if="!isGuest"
|
||||
:icon-left="PlusIcon"
|
||||
@click="openNewProject = true"
|
||||
>
|
||||
New
|
||||
</FormButton>
|
||||
</div>
|
||||
@@ -113,7 +117,7 @@ const debouncedSearch = ref('')
|
||||
const openNewProject = ref(false)
|
||||
const showLoadingBar = ref(false)
|
||||
|
||||
const { activeUser } = useActiveUser()
|
||||
const { activeUser, isGuest } = useActiveUser()
|
||||
const { triggerNotification } = useGlobalToast()
|
||||
const areQueriesLoading = useQueryLoading()
|
||||
const apollo = useApolloClient().client
|
||||
|
||||
@@ -26,15 +26,26 @@
|
||||
<div
|
||||
class="grow flex flex-col space-y-4 sm:space-y-0 sm:flex-row sm:justify-between sm:items-center"
|
||||
>
|
||||
<div class="grow">
|
||||
<div
|
||||
class="grow flex flex-col space-y-2 sm:flex-row sm:space-x-2 sm:space-y-0"
|
||||
>
|
||||
<FormSelectProjects
|
||||
v-model="selectedProject"
|
||||
label="(Optional) Select project to invite to"
|
||||
class="w-full sm:w-60"
|
||||
owned-only
|
||||
show-label
|
||||
/>
|
||||
<FormSelectServerRoles
|
||||
v-if="allowServerRoleSelect"
|
||||
v-model="serverRole"
|
||||
label="Select server role"
|
||||
show-label
|
||||
:allow-guest="isGuestMode"
|
||||
:allow-admin="isAdmin"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
<div class="flex justify-end self-end">
|
||||
<FormButton text @click="isOpen = false">Cancel</FormButton>
|
||||
<FormButton submit :disabled="anyMutationsLoading">Send</FormButton>
|
||||
</div>
|
||||
@@ -45,9 +56,10 @@
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { EnvelopeIcon } from '@heroicons/vue/24/solid'
|
||||
import { Optional } from '@speckle/shared'
|
||||
import { Optional, Roles, ServerRoles } from '@speckle/shared'
|
||||
import { useMutationLoading } from '@vue/apollo-composable'
|
||||
import { useForm } from 'vee-validate'
|
||||
import { useActiveUser } from '~~/lib/auth/composables/activeUser'
|
||||
import { FormSelectProjects_ProjectFragment } from '~~/lib/common/generated/gql/graphql'
|
||||
import {
|
||||
isRequired,
|
||||
@@ -55,6 +67,7 @@ import {
|
||||
isStringOfLength
|
||||
} from '~~/lib/common/helpers/validation'
|
||||
import { useMixpanel } from '~~/lib/core/composables/mp'
|
||||
import { useServerInfo } from '~~/lib/core/composables/server'
|
||||
import { useInviteUserToProject } from '~~/lib/projects/composables/projectManagement'
|
||||
import { useInviteUserToServer } from '~~/lib/server/composables/invites'
|
||||
|
||||
@@ -67,17 +80,22 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const selectedProject = ref(undefined as Optional<FormSelectProjects_ProjectFragment>)
|
||||
const serverRole = ref<ServerRoles>(Roles.Server.User)
|
||||
|
||||
const { handleSubmit } = useForm<{ message?: string; emailsString: string }>()
|
||||
const { mutate: inviteUserToServer } = useInviteUserToServer()
|
||||
const inviteUserToProject = useInviteUserToProject()
|
||||
const anyMutationsLoading = useMutationLoading()
|
||||
const { isAdmin } = useActiveUser()
|
||||
const { isGuestMode } = useServerInfo()
|
||||
|
||||
const isOpen = computed({
|
||||
get: () => props.open,
|
||||
set: (newVal) => emit('update:open', newVal)
|
||||
})
|
||||
|
||||
const allowServerRoleSelect = computed(() => isAdmin.value || isGuestMode.value)
|
||||
|
||||
const mp = useMixpanel()
|
||||
const onSubmit = handleSubmit(async (values) => {
|
||||
const emails = values.emailsString.split(',').map((i) => i.trim())
|
||||
@@ -87,13 +105,15 @@ const onSubmit = handleSubmit(async (values) => {
|
||||
? await inviteUserToProject(
|
||||
project.id,
|
||||
emails.map((email) => ({
|
||||
email
|
||||
email,
|
||||
serverRole: allowServerRoleSelect.value ? serverRole.value : undefined
|
||||
}))
|
||||
)
|
||||
: await inviteUserToServer(
|
||||
emails.map((email) => ({
|
||||
email,
|
||||
message: values.message
|
||||
message: values.message,
|
||||
serverRole: allowServerRoleSelect.value ? serverRole.value : undefined
|
||||
}))
|
||||
)
|
||||
if (success) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Roles } from '@speckle/shared'
|
||||
import { useApolloClient, useQuery } from '@vue/apollo-composable'
|
||||
import { graphql } from '~~/lib/common/generated/gql'
|
||||
import md5 from '~~/lib/common/helpers/md5'
|
||||
@@ -37,7 +38,10 @@ export function useActiveUser() {
|
||||
return '@' + md5(user.email.toLowerCase()).toUpperCase()
|
||||
})
|
||||
|
||||
return { activeUser, isLoggedIn, distinctId, refetch, onResult }
|
||||
const isGuest = computed(() => activeUser.value?.role === Roles.Server.Guest)
|
||||
const isAdmin = computed(() => activeUser.value?.role === Roles.Server.Admin)
|
||||
|
||||
return { activeUser, isLoggedIn, distinctId, refetch, onResult, isGuest, isAdmin }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import { UserSearchQueryVariables } from '~~/lib/common/generated/gql/graphql'
|
||||
import { Get } from 'type-fest'
|
||||
import {
|
||||
UserSearchQuery,
|
||||
UserSearchQueryVariables
|
||||
} from '~~/lib/common/generated/gql/graphql'
|
||||
import { userSearchQuery } from '~~/lib/common/graphql/queries'
|
||||
|
||||
export type UserSearchItem = NonNullable<Get<UserSearchQuery, 'userSearch.items[0]'>>
|
||||
|
||||
export function useUserSearch(params: { variables: Ref<UserSearchQueryVariables> }) {
|
||||
const { variables } = params
|
||||
const { result, variables: usedVariables } = useQuery(
|
||||
|
||||
@@ -46,7 +46,7 @@ const documents = {
|
||||
"\n fragment ProjectPageStatsBlockModels on Project {\n modelCount: models(limit: 0) {\n totalCount\n }\n }\n": types.ProjectPageStatsBlockModelsFragmentDoc,
|
||||
"\n fragment ProjectPageStatsBlockTeam on Project {\n id\n role\n team {\n role\n user {\n ...LimitedUserAvatar\n }\n }\n ...ProjectPageTeamDialog\n }\n": types.ProjectPageStatsBlockTeamFragmentDoc,
|
||||
"\n fragment ProjectPageStatsBlockVersions on Project {\n versionCount: versions(limit: 0) {\n totalCount\n }\n }\n": types.ProjectPageStatsBlockVersionsFragmentDoc,
|
||||
"\n fragment ProjectPageTeamDialog on Project {\n id\n name\n role\n allowPublicComments\n visibility\n team {\n role\n user {\n ...LimitedUserAvatar\n }\n }\n invitedTeam {\n id\n title\n inviteId\n role\n user {\n ...LimitedUserAvatar\n }\n }\n }\n": types.ProjectPageTeamDialogFragmentDoc,
|
||||
"\n fragment ProjectPageTeamDialog on Project {\n id\n name\n role\n allowPublicComments\n visibility\n team {\n role\n user {\n ...LimitedUserAvatar\n role\n }\n }\n invitedTeam {\n id\n title\n inviteId\n role\n user {\n ...LimitedUserAvatar\n role\n }\n }\n }\n": types.ProjectPageTeamDialogFragmentDoc,
|
||||
"\n subscription OnUserProjectsUpdate {\n userProjectsUpdated {\n type\n id\n project {\n ...ProjectDashboardItem\n }\n }\n }\n": types.OnUserProjectsUpdateDocument,
|
||||
"\n fragment ProjectsDashboardFilled on ProjectCollection {\n items {\n ...ProjectDashboardItem\n }\n }\n": types.ProjectsDashboardFilledFragmentDoc,
|
||||
"\n fragment ProjectsInviteBanner on PendingStreamCollaborator {\n id\n invitedBy {\n ...LimitedUserAvatar\n }\n projectId\n projectName\n token\n }\n": types.ProjectsInviteBannerFragmentDoc,
|
||||
@@ -68,9 +68,10 @@ const documents = {
|
||||
"\n query AuthServerInfo {\n serverInfo {\n ...AuthStategiesServerInfoFragment\n ...ServerTermsOfServicePrivacyPolicyFragment\n ...AuthRegisterPanelServerInfo\n }\n }\n": types.AuthServerInfoDocument,
|
||||
"\n query AuthorizableAppMetadata($id: String!) {\n app(id: $id) {\n id\n name\n description\n trustByDefault\n redirectUrl\n scopes {\n name\n description\n }\n author {\n name\n id\n avatar\n }\n }\n }\n": types.AuthorizableAppMetadataDocument,
|
||||
"\n query MentionsUserSearch($query: String!, $emailOnly: Boolean = false) {\n userSearch(\n query: $query\n limit: 5\n cursor: null\n archived: false\n emailOnly: $emailOnly\n ) {\n items {\n id\n name\n company\n }\n }\n }\n": types.MentionsUserSearchDocument,
|
||||
"\n query UserSearch($query: String!, $limit: Int, $cursor: String, $archived: Boolean) {\n userSearch(query: $query, limit: $limit, cursor: $cursor, archived: $archived) {\n cursor\n items {\n id\n name\n bio\n company\n avatar\n verified\n }\n }\n }\n": types.UserSearchDocument,
|
||||
"\n query UserSearch($query: String!, $limit: Int, $cursor: String, $archived: Boolean) {\n userSearch(query: $query, limit: $limit, cursor: $cursor, archived: $archived) {\n cursor\n items {\n id\n name\n bio\n company\n avatar\n verified\n role\n }\n }\n }\n": types.UserSearchDocument,
|
||||
"\n query ServerInfoBlobSizeLimit {\n serverInfo {\n blobSizeLimitBytes\n }\n }\n": types.ServerInfoBlobSizeLimitDocument,
|
||||
"\n query ProjectModelsSelectorValues($projectId: String!, $cursor: String) {\n project(id: $projectId) {\n id\n models(limit: 100, cursor: $cursor) {\n cursor\n totalCount\n items {\n ...CommonModelSelectorModel\n }\n }\n }\n }\n": types.ProjectModelsSelectorValuesDocument,
|
||||
"\n query MainServerInfoData {\n serverInfo {\n adminContact\n blobSizeLimitBytes\n canonicalUrl\n company\n description\n guestModeEnabled\n inviteOnly\n name\n termsOfService\n version\n }\n }\n": types.MainServerInfoDataDocument,
|
||||
"\n query ServerVersionInfo {\n serverInfo {\n version\n }\n }\n": types.ServerVersionInfoDocument,
|
||||
"\n query SearchProjects($search: String, $onlyWithRoles: [String!] = null) {\n activeUser {\n projects(limit: 10, filter: { search: $search, onlyWithRoles: $onlyWithRoles }) {\n totalCount\n items {\n ...FormSelectProjects_Project\n }\n }\n }\n }\n": types.SearchProjectsDocument,
|
||||
"\n fragment ProjectDashboardItemNoModels on Project {\n id\n name\n createdAt\n updatedAt\n role\n team {\n user {\n id\n name\n avatar\n }\n }\n ...ProjectPageModelsCardProject\n }\n": types.ProjectDashboardItemNoModelsFragmentDoc,
|
||||
@@ -288,7 +289,7 @@ export function graphql(source: "\n fragment ProjectPageStatsBlockVersions on P
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n fragment ProjectPageTeamDialog on Project {\n id\n name\n role\n allowPublicComments\n visibility\n team {\n role\n user {\n ...LimitedUserAvatar\n }\n }\n invitedTeam {\n id\n title\n inviteId\n role\n user {\n ...LimitedUserAvatar\n }\n }\n }\n"): (typeof documents)["\n fragment ProjectPageTeamDialog on Project {\n id\n name\n role\n allowPublicComments\n visibility\n team {\n role\n user {\n ...LimitedUserAvatar\n }\n }\n invitedTeam {\n id\n title\n inviteId\n role\n user {\n ...LimitedUserAvatar\n }\n }\n }\n"];
|
||||
export function graphql(source: "\n fragment ProjectPageTeamDialog on Project {\n id\n name\n role\n allowPublicComments\n visibility\n team {\n role\n user {\n ...LimitedUserAvatar\n role\n }\n }\n invitedTeam {\n id\n title\n inviteId\n role\n user {\n ...LimitedUserAvatar\n role\n }\n }\n }\n"): (typeof documents)["\n fragment ProjectPageTeamDialog on Project {\n id\n name\n role\n allowPublicComments\n visibility\n team {\n role\n user {\n ...LimitedUserAvatar\n role\n }\n }\n invitedTeam {\n id\n title\n inviteId\n role\n user {\n ...LimitedUserAvatar\n role\n }\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -376,7 +377,7 @@ export function graphql(source: "\n query MentionsUserSearch($query: String!, $
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n query UserSearch($query: String!, $limit: Int, $cursor: String, $archived: Boolean) {\n userSearch(query: $query, limit: $limit, cursor: $cursor, archived: $archived) {\n cursor\n items {\n id\n name\n bio\n company\n avatar\n verified\n }\n }\n }\n"): (typeof documents)["\n query UserSearch($query: String!, $limit: Int, $cursor: String, $archived: Boolean) {\n userSearch(query: $query, limit: $limit, cursor: $cursor, archived: $archived) {\n cursor\n items {\n id\n name\n bio\n company\n avatar\n verified\n }\n }\n }\n"];
|
||||
export function graphql(source: "\n query UserSearch($query: String!, $limit: Int, $cursor: String, $archived: Boolean) {\n userSearch(query: $query, limit: $limit, cursor: $cursor, archived: $archived) {\n cursor\n items {\n id\n name\n bio\n company\n avatar\n verified\n role\n }\n }\n }\n"): (typeof documents)["\n query UserSearch($query: String!, $limit: Int, $cursor: String, $archived: Boolean) {\n userSearch(query: $query, limit: $limit, cursor: $cursor, archived: $archived) {\n cursor\n items {\n id\n name\n bio\n company\n avatar\n verified\n role\n }\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -385,6 +386,10 @@ export function graphql(source: "\n query ServerInfoBlobSizeLimit {\n server
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n query ProjectModelsSelectorValues($projectId: String!, $cursor: String) {\n project(id: $projectId) {\n id\n models(limit: 100, cursor: $cursor) {\n cursor\n totalCount\n items {\n ...CommonModelSelectorModel\n }\n }\n }\n }\n"): (typeof documents)["\n query ProjectModelsSelectorValues($projectId: String!, $cursor: String) {\n project(id: $projectId) {\n id\n models(limit: 100, cursor: $cursor) {\n cursor\n totalCount\n items {\n ...CommonModelSelectorModel\n }\n }\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n query MainServerInfoData {\n serverInfo {\n adminContact\n blobSizeLimitBytes\n canonicalUrl\n company\n description\n guestModeEnabled\n inviteOnly\n name\n termsOfService\n version\n }\n }\n"): (typeof documents)["\n query MainServerInfoData {\n serverInfo {\n adminContact\n blobSizeLimitBytes\n canonicalUrl\n company\n description\n guestModeEnabled\n inviteOnly\n name\n termsOfService\n version\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
|
||||
@@ -1418,6 +1418,8 @@ export type ProjectInviteCreateInput = {
|
||||
email?: InputMaybe<Scalars['String']>;
|
||||
/** Defaults to the contributor role, if not specified */
|
||||
role?: InputMaybe<Scalars['String']>;
|
||||
/** Can only be specified if guest mode is on or if the user is an admin */
|
||||
serverRole?: InputMaybe<Scalars['String']>;
|
||||
/** Either this or email must be filled */
|
||||
userId?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
@@ -1506,7 +1508,10 @@ export type ProjectMutations = {
|
||||
__typename?: 'ProjectMutations';
|
||||
/** Create new project */
|
||||
create: Project;
|
||||
/** Create onboarding/tutorial project */
|
||||
/**
|
||||
* Create onboarding/tutorial project. If one is already created for the active user, that
|
||||
* one will be returned instead.
|
||||
*/
|
||||
createForOnboarding: Project;
|
||||
/** Delete an existing project */
|
||||
delete: Scalars['Boolean'];
|
||||
@@ -1844,7 +1849,6 @@ export enum ResourceType {
|
||||
Stream = 'stream'
|
||||
}
|
||||
|
||||
/** Available roles. */
|
||||
export type Role = {
|
||||
__typename?: 'Role';
|
||||
description: Scalars['String'];
|
||||
@@ -1900,8 +1904,10 @@ export type ServerInfo = {
|
||||
guestModeEnabled: Scalars['Boolean'];
|
||||
inviteOnly?: Maybe<Scalars['Boolean']>;
|
||||
name: Scalars['String'];
|
||||
roles: Array<Maybe<Role>>;
|
||||
scopes: Array<Maybe<Scope>>;
|
||||
/** @deprecated Use role constants from the @speckle/shared npm package instead */
|
||||
roles: Array<Role>;
|
||||
scopes: Array<Scope>;
|
||||
serverRoles: Array<ServerRoleItem>;
|
||||
termsOfService?: Maybe<Scalars['String']>;
|
||||
version?: Maybe<Scalars['String']>;
|
||||
};
|
||||
@@ -1926,6 +1932,8 @@ export type ServerInvite = {
|
||||
export type ServerInviteCreateInput = {
|
||||
email: Scalars['String'];
|
||||
message?: InputMaybe<Scalars['String']>;
|
||||
/** Can only be specified if guest mode is on or if the user is an admin */
|
||||
serverRole?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export enum ServerRole {
|
||||
@@ -1935,6 +1943,12 @@ export enum ServerRole {
|
||||
ServerUser = 'SERVER_USER'
|
||||
}
|
||||
|
||||
export type ServerRoleItem = {
|
||||
__typename?: 'ServerRoleItem';
|
||||
id: Scalars['String'];
|
||||
title: Scalars['String'];
|
||||
};
|
||||
|
||||
export type ServerStatistics = {
|
||||
__typename?: 'ServerStatistics';
|
||||
totalPendingInvites: Scalars['Int'];
|
||||
@@ -2109,6 +2123,7 @@ export type StreamCollaborator = {
|
||||
id: Scalars['String'];
|
||||
name: Scalars['String'];
|
||||
role: Scalars['String'];
|
||||
serverRole: Scalars['String'];
|
||||
};
|
||||
|
||||
export type StreamCollection = {
|
||||
@@ -2137,6 +2152,8 @@ export type StreamInviteCreateInput = {
|
||||
message?: InputMaybe<Scalars['String']>;
|
||||
/** Defaults to the contributor role, if not specified */
|
||||
role?: InputMaybe<Scalars['String']>;
|
||||
/** Can only be specified if guest mode is on or if the user is an admin */
|
||||
serverRole?: InputMaybe<Scalars['String']>;
|
||||
streamId: Scalars['String'];
|
||||
userId?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
@@ -2765,11 +2782,11 @@ export type ProjectPageStatsBlockCommentsFragment = { __typename?: 'Project', co
|
||||
|
||||
export type ProjectPageStatsBlockModelsFragment = { __typename?: 'Project', modelCount: { __typename?: 'ModelCollection', totalCount: number } };
|
||||
|
||||
export type ProjectPageStatsBlockTeamFragment = { __typename?: 'Project', id: string, role?: string | null, name: string, allowPublicComments: boolean, visibility: ProjectVisibility, team: Array<{ __typename?: 'ProjectCollaborator', role: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, inviteId: string, role: string, user?: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } | null }> | null };
|
||||
export type ProjectPageStatsBlockTeamFragment = { __typename?: 'Project', id: string, role?: string | null, name: string, allowPublicComments: boolean, visibility: ProjectVisibility, team: Array<{ __typename?: 'ProjectCollaborator', role: string, user: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, inviteId: string, role: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null };
|
||||
|
||||
export type ProjectPageStatsBlockVersionsFragment = { __typename?: 'Project', versionCount: { __typename?: 'VersionCollection', totalCount: number } };
|
||||
|
||||
export type ProjectPageTeamDialogFragment = { __typename?: 'Project', id: string, name: string, role?: string | null, allowPublicComments: boolean, visibility: ProjectVisibility, team: Array<{ __typename?: 'ProjectCollaborator', role: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, inviteId: string, role: string, user?: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } | null }> | null };
|
||||
export type ProjectPageTeamDialogFragment = { __typename?: 'Project', id: string, name: string, role?: string | null, allowPublicComments: boolean, visibility: ProjectVisibility, team: Array<{ __typename?: 'ProjectCollaborator', role: string, user: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, inviteId: string, role: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null };
|
||||
|
||||
export type OnUserProjectsUpdateSubscriptionVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
@@ -2812,7 +2829,7 @@ export type ActiveUserMainMetadataQuery = { __typename?: 'Query', activeUser?: {
|
||||
export type CreateOnboardingProjectMutationVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type CreateOnboardingProjectMutation = { __typename?: 'Mutation', projectMutations: { __typename?: 'ProjectMutations', createForOnboarding: { __typename?: 'Project', id: string, createdAt: string, role?: string | null, name: string, description?: string | null, visibility: ProjectVisibility, allowPublicComments: boolean, updatedAt: string, models: { __typename?: 'ModelCollection', totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }> }> }, pendingImportedModels: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, team: Array<{ __typename?: 'ProjectCollaborator', role: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, inviteId: string, role: string, user?: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } | null }> | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, modelCount: { __typename?: 'ModelCollection', totalCount: number }, commentThreadCount: { __typename?: 'ProjectCommentCollection', totalCount: number } } } };
|
||||
export type CreateOnboardingProjectMutation = { __typename?: 'Mutation', projectMutations: { __typename?: 'ProjectMutations', createForOnboarding: { __typename?: 'Project', id: string, createdAt: string, role?: string | null, name: string, description?: string | null, visibility: ProjectVisibility, allowPublicComments: boolean, updatedAt: string, models: { __typename?: 'ModelCollection', totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }> }> }, pendingImportedModels: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, team: Array<{ __typename?: 'ProjectCollaborator', role: string, user: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, inviteId: string, role: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, modelCount: { __typename?: 'ModelCollection', totalCount: number }, commentThreadCount: { __typename?: 'ProjectCommentCollection', totalCount: number } } } };
|
||||
|
||||
export type FinishOnboardingMutationVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
@@ -2847,7 +2864,7 @@ export type UserSearchQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type UserSearchQuery = { __typename?: 'Query', userSearch: { __typename?: 'UserSearchResultCollection', cursor?: string | null, items: Array<{ __typename?: 'LimitedUser', id: string, name: string, bio?: string | null, company?: string | null, avatar?: string | null, verified?: boolean | null }> } };
|
||||
export type UserSearchQuery = { __typename?: 'Query', userSearch: { __typename?: 'UserSearchResultCollection', cursor?: string | null, items: Array<{ __typename?: 'LimitedUser', id: string, name: string, bio?: string | null, company?: string | null, avatar?: string | null, verified?: boolean | null, role?: string | null }> } };
|
||||
|
||||
export type ServerInfoBlobSizeLimitQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
@@ -2862,6 +2879,11 @@ export type ProjectModelsSelectorValuesQueryVariables = Exact<{
|
||||
|
||||
export type ProjectModelsSelectorValuesQuery = { __typename?: 'Query', project: { __typename?: 'Project', id: string, models: { __typename?: 'ModelCollection', cursor?: string | null, totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string }> } } };
|
||||
|
||||
export type MainServerInfoDataQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type MainServerInfoDataQuery = { __typename?: 'Query', serverInfo: { __typename?: 'ServerInfo', adminContact?: string | null, blobSizeLimitBytes: number, canonicalUrl?: string | null, company?: string | null, description?: string | null, guestModeEnabled: boolean, inviteOnly?: boolean | null, name: string, termsOfService?: string | null, version?: string | null } };
|
||||
|
||||
export type ServerVersionInfoQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
@@ -2897,7 +2919,7 @@ export type CreateProjectMutationVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type CreateProjectMutation = { __typename?: 'Mutation', projectMutations: { __typename?: 'ProjectMutations', create: { __typename?: 'Project', id: string, createdAt: string, role?: string | null, name: string, description?: string | null, visibility: ProjectVisibility, allowPublicComments: boolean, updatedAt: string, models: { __typename?: 'ModelCollection', totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }> }> }, pendingImportedModels: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, team: Array<{ __typename?: 'ProjectCollaborator', role: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, inviteId: string, role: string, user?: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } | null }> | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, modelCount: { __typename?: 'ModelCollection', totalCount: number }, commentThreadCount: { __typename?: 'ProjectCommentCollection', totalCount: number } } } };
|
||||
export type CreateProjectMutation = { __typename?: 'Mutation', projectMutations: { __typename?: 'ProjectMutations', create: { __typename?: 'Project', id: string, createdAt: string, role?: string | null, name: string, description?: string | null, visibility: ProjectVisibility, allowPublicComments: boolean, updatedAt: string, models: { __typename?: 'ModelCollection', totalCount: number, items: Array<{ __typename?: 'Model', id: string, name: string, displayName: string, previewUrl?: string | null, createdAt: string, updatedAt: string, versionCount: { __typename?: 'VersionCollection', totalCount: number }, commentThreadCount: { __typename?: 'CommentCollection', totalCount: number }, pendingImportedVersions: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }> }> }, pendingImportedModels: Array<{ __typename?: 'FileUpload', id: string, projectId: string, modelName: string, convertedStatus: number, convertedMessage?: string | null, uploadDate: string, convertedLastUpdate: string, fileType: string, fileName: string }>, team: Array<{ __typename?: 'ProjectCollaborator', role: string, user: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, inviteId: string, role: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, modelCount: { __typename?: 'ModelCollection', totalCount: number }, commentThreadCount: { __typename?: 'ProjectCommentCollection', totalCount: number } } } };
|
||||
|
||||
export type UpdateModelMutationVariables = Exact<{
|
||||
input: UpdateModelInput;
|
||||
@@ -2926,7 +2948,7 @@ export type InviteProjectUserMutationVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type InviteProjectUserMutation = { __typename?: 'Mutation', projectMutations: { __typename?: 'ProjectMutations', invites: { __typename?: 'ProjectInviteMutations', batchCreate: { __typename?: 'Project', id: string, name: string, role?: string | null, allowPublicComments: boolean, visibility: ProjectVisibility, team: Array<{ __typename?: 'ProjectCollaborator', role: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, inviteId: string, role: string, user?: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } | null }> | null } } } };
|
||||
export type InviteProjectUserMutation = { __typename?: 'Mutation', projectMutations: { __typename?: 'ProjectMutations', invites: { __typename?: 'ProjectInviteMutations', batchCreate: { __typename?: 'Project', id: string, name: string, role?: string | null, allowPublicComments: boolean, visibility: ProjectVisibility, team: Array<{ __typename?: 'ProjectCollaborator', role: string, user: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, inviteId: string, role: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null } } } };
|
||||
|
||||
export type CancelProjectInviteMutationVariables = Exact<{
|
||||
projectId: Scalars['ID'];
|
||||
@@ -2934,7 +2956,7 @@ export type CancelProjectInviteMutationVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type CancelProjectInviteMutation = { __typename?: 'Mutation', projectMutations: { __typename?: 'ProjectMutations', invites: { __typename?: 'ProjectInviteMutations', cancel: { __typename?: 'Project', id: string, name: string, role?: string | null, allowPublicComments: boolean, visibility: ProjectVisibility, team: Array<{ __typename?: 'ProjectCollaborator', role: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, inviteId: string, role: string, user?: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } | null }> | null } } } };
|
||||
export type CancelProjectInviteMutation = { __typename?: 'Mutation', projectMutations: { __typename?: 'ProjectMutations', invites: { __typename?: 'ProjectInviteMutations', cancel: { __typename?: 'Project', id: string, name: string, role?: string | null, allowPublicComments: boolean, visibility: ProjectVisibility, team: Array<{ __typename?: 'ProjectCollaborator', role: string, user: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, inviteId: string, role: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null } } } };
|
||||
|
||||
export type UpdateProjectMetadataMutationVariables = Exact<{
|
||||
update: ProjectUpdateInput;
|
||||
@@ -3006,7 +3028,7 @@ export type ProjectPageQueryQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type ProjectPageQueryQuery = { __typename?: 'Query', project: { __typename?: 'Project', id: string, createdAt: string, role?: string | null, name: string, description?: string | null, visibility: ProjectVisibility, allowPublicComments: boolean, team: Array<{ __typename?: 'ProjectCollaborator', role: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, inviteId: string, role: string, user?: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } | null }> | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, modelCount: { __typename?: 'ModelCollection', totalCount: number }, commentThreadCount: { __typename?: 'ProjectCommentCollection', totalCount: number } }, projectInvite?: { __typename?: 'PendingStreamCollaborator', id: string, projectId: string, projectName: string, token?: string | null, invitedBy: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } } | null };
|
||||
export type ProjectPageQueryQuery = { __typename?: 'Query', project: { __typename?: 'Project', id: string, createdAt: string, role?: string | null, name: string, description?: string | null, visibility: ProjectVisibility, allowPublicComments: boolean, team: Array<{ __typename?: 'ProjectCollaborator', role: string, user: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, inviteId: string, role: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, modelCount: { __typename?: 'ModelCollection', totalCount: number }, commentThreadCount: { __typename?: 'ProjectCommentCollection', totalCount: number } }, projectInvite?: { __typename?: 'PendingStreamCollaborator', id: string, projectId: string, projectName: string, token?: string | null, invitedBy: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } } | null };
|
||||
|
||||
export type ProjectLatestModelsQueryVariables = Exact<{
|
||||
projectId: Scalars['String'];
|
||||
@@ -3112,7 +3134,7 @@ export type OnProjectUpdatedSubscriptionVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type OnProjectUpdatedSubscription = { __typename?: 'Subscription', projectUpdated: { __typename?: 'ProjectUpdatedMessage', id: string, type: ProjectUpdatedMessageType, project?: { __typename?: 'Project', id: string, createdAt: string, name: string, updatedAt: string, role?: string | null, description?: string | null, visibility: ProjectVisibility, allowPublicComments: boolean, team: Array<{ __typename?: 'ProjectCollaborator', role: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, inviteId: string, role: string, user?: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } | null }> | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, modelCount: { __typename?: 'ModelCollection', totalCount: number }, commentThreadCount: { __typename?: 'ProjectCommentCollection', totalCount: number } } | null } };
|
||||
export type OnProjectUpdatedSubscription = { __typename?: 'Subscription', projectUpdated: { __typename?: 'ProjectUpdatedMessage', id: string, type: ProjectUpdatedMessageType, project?: { __typename?: 'Project', id: string, createdAt: string, name: string, updatedAt: string, role?: string | null, description?: string | null, visibility: ProjectVisibility, allowPublicComments: boolean, team: Array<{ __typename?: 'ProjectCollaborator', role: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null, role?: string | null } }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, inviteId: string, role: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, modelCount: { __typename?: 'ModelCollection', totalCount: number }, commentThreadCount: { __typename?: 'ProjectCommentCollection', totalCount: number } } | null } };
|
||||
|
||||
export type OnProjectModelsUpdateSubscriptionVariables = Exact<{
|
||||
id: Scalars['String'];
|
||||
@@ -3294,7 +3316,7 @@ export type GetActiveUserQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
export type GetActiveUserQuery = { __typename?: 'Query', activeUser?: { __typename?: 'User', id: string, name: string, role?: string | null } | null };
|
||||
|
||||
export type ProjectPageProjectFragment = { __typename?: 'Project', id: string, createdAt: string, role?: string | null, name: string, description?: string | null, visibility: ProjectVisibility, allowPublicComments: boolean, team: Array<{ __typename?: 'ProjectCollaborator', role: string, user: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, inviteId: string, role: string, user?: { __typename?: 'LimitedUser', id: string, name: string, avatar?: string | null } | null }> | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, modelCount: { __typename?: 'ModelCollection', totalCount: number }, commentThreadCount: { __typename?: 'ProjectCommentCollection', totalCount: number } };
|
||||
export type ProjectPageProjectFragment = { __typename?: 'Project', id: string, createdAt: string, role?: string | null, name: string, description?: string | null, visibility: ProjectVisibility, allowPublicComments: boolean, team: Array<{ __typename?: 'ProjectCollaborator', role: string, user: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } }>, invitedTeam?: Array<{ __typename?: 'PendingStreamCollaborator', id: string, title: string, inviteId: string, role: string, user?: { __typename?: 'LimitedUser', role?: string | null, id: string, name: string, avatar?: string | null } | null }> | null, versionCount: { __typename?: 'VersionCollection', totalCount: number }, modelCount: { __typename?: 'ModelCollection', totalCount: number }, commentThreadCount: { __typename?: 'ProjectCommentCollection', totalCount: number } };
|
||||
|
||||
export type ModelPageProjectFragment = { __typename?: 'Project', id: string, createdAt: string, name: string };
|
||||
|
||||
@@ -3347,7 +3369,7 @@ export const ViewerCommentsListItemFragmentDoc = {"kind":"Document","definitions
|
||||
export const ViewerCommentBubblesDataFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ViewerCommentBubblesData"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Comment"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"viewedAt"}},{"kind":"Field","name":{"kind":"Name","value":"viewerState"}}]}}]} as unknown as DocumentNode<ViewerCommentBubblesDataFragment, unknown>;
|
||||
export const ViewerCommentThreadFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ViewerCommentThread"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Comment"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ViewerCommentsListItem"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"ViewerCommentBubblesData"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"ViewerCommentsReplyItem"}}]}}]} as unknown as DocumentNode<ViewerCommentThreadFragment, unknown>;
|
||||
export const ProjectPageProjectHeaderFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageProjectHeader"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Project"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"allowPublicComments"}}]}}]} as unknown as DocumentNode<ProjectPageProjectHeaderFragment, unknown>;
|
||||
export const ProjectPageTeamDialogFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageTeamDialog"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Project"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"allowPublicComments"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"LimitedUserAvatar"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"invitedTeam"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"inviteId"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"LimitedUserAvatar"}}]}}]}}]}}]} as unknown as DocumentNode<ProjectPageTeamDialogFragment, unknown>;
|
||||
export const ProjectPageTeamDialogFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageTeamDialog"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Project"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"allowPublicComments"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"LimitedUserAvatar"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"invitedTeam"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"inviteId"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"LimitedUserAvatar"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}}]}}]} as unknown as DocumentNode<ProjectPageTeamDialogFragment, unknown>;
|
||||
export const ProjectPageStatsBlockTeamFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageStatsBlockTeam"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Project"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"team"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"LimitedUserAvatar"}}]}}]}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectPageTeamDialog"}}]}}]} as unknown as DocumentNode<ProjectPageStatsBlockTeamFragment, unknown>;
|
||||
export const ProjectPageStatsBlockVersionsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageStatsBlockVersions"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Project"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"versionCount"},"name":{"kind":"Name","value":"versions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"0"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}}]} as unknown as DocumentNode<ProjectPageStatsBlockVersionsFragment, unknown>;
|
||||
export const ProjectPageStatsBlockModelsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectPageStatsBlockModels"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Project"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"modelCount"},"name":{"kind":"Name","value":"models"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"0"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}}]} as unknown as DocumentNode<ProjectPageStatsBlockModelsFragment, unknown>;
|
||||
@@ -3364,9 +3386,10 @@ export const FinishOnboardingDocument = {"kind":"Document","definitions":[{"kind
|
||||
export const AuthServerInfoDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AuthServerInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"serverInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"AuthStategiesServerInfoFragment"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"ServerTermsOfServicePrivacyPolicyFragment"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"AuthRegisterPanelServerInfo"}}]}}]}},...AuthStategiesServerInfoFragmentFragmentDoc.definitions,...ServerTermsOfServicePrivacyPolicyFragmentFragmentDoc.definitions,...AuthRegisterPanelServerInfoFragmentDoc.definitions]} as unknown as DocumentNode<AuthServerInfoQuery, AuthServerInfoQueryVariables>;
|
||||
export const AuthorizableAppMetadataDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AuthorizableAppMetadata"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"app"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"trustByDefault"}},{"kind":"Field","name":{"kind":"Name","value":"redirectUrl"}},{"kind":"Field","name":{"kind":"Name","value":"scopes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}},{"kind":"Field","name":{"kind":"Name","value":"author"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"avatar"}}]}}]}}]}}]} as unknown as DocumentNode<AuthorizableAppMetadataQuery, AuthorizableAppMetadataQueryVariables>;
|
||||
export const MentionsUserSearchDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MentionsUserSearch"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"query"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"emailOnly"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}},"defaultValue":{"kind":"BooleanValue","value":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userSearch"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"query"},"value":{"kind":"Variable","name":{"kind":"Name","value":"query"}}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"5"}},{"kind":"Argument","name":{"kind":"Name","value":"cursor"},"value":{"kind":"NullValue"}},{"kind":"Argument","name":{"kind":"Name","value":"archived"},"value":{"kind":"BooleanValue","value":false}},{"kind":"Argument","name":{"kind":"Name","value":"emailOnly"},"value":{"kind":"Variable","name":{"kind":"Name","value":"emailOnly"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"company"}}]}}]}}]}}]} as unknown as DocumentNode<MentionsUserSearchQuery, MentionsUserSearchQueryVariables>;
|
||||
export const UserSearchDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UserSearch"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"query"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"cursor"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"archived"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userSearch"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"query"},"value":{"kind":"Variable","name":{"kind":"Name","value":"query"}}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"Argument","name":{"kind":"Name","value":"cursor"},"value":{"kind":"Variable","name":{"kind":"Name","value":"cursor"}}},{"kind":"Argument","name":{"kind":"Name","value":"archived"},"value":{"kind":"Variable","name":{"kind":"Name","value":"archived"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"cursor"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"bio"}},{"kind":"Field","name":{"kind":"Name","value":"company"}},{"kind":"Field","name":{"kind":"Name","value":"avatar"}},{"kind":"Field","name":{"kind":"Name","value":"verified"}}]}}]}}]}}]} as unknown as DocumentNode<UserSearchQuery, UserSearchQueryVariables>;
|
||||
export const UserSearchDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UserSearch"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"query"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"cursor"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"archived"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userSearch"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"query"},"value":{"kind":"Variable","name":{"kind":"Name","value":"query"}}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"Argument","name":{"kind":"Name","value":"cursor"},"value":{"kind":"Variable","name":{"kind":"Name","value":"cursor"}}},{"kind":"Argument","name":{"kind":"Name","value":"archived"},"value":{"kind":"Variable","name":{"kind":"Name","value":"archived"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"cursor"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"bio"}},{"kind":"Field","name":{"kind":"Name","value":"company"}},{"kind":"Field","name":{"kind":"Name","value":"avatar"}},{"kind":"Field","name":{"kind":"Name","value":"verified"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}}]}}]}}]} as unknown as DocumentNode<UserSearchQuery, UserSearchQueryVariables>;
|
||||
export const ServerInfoBlobSizeLimitDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ServerInfoBlobSizeLimit"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"serverInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"blobSizeLimitBytes"}}]}}]}}]} as unknown as DocumentNode<ServerInfoBlobSizeLimitQuery, ServerInfoBlobSizeLimitQueryVariables>;
|
||||
export const ProjectModelsSelectorValuesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ProjectModelsSelectorValues"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"projectId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"cursor"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"project"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"projectId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"models"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"100"}},{"kind":"Argument","name":{"kind":"Name","value":"cursor"},"value":{"kind":"Variable","name":{"kind":"Name","value":"cursor"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"cursor"}},{"kind":"Field","name":{"kind":"Name","value":"totalCount"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CommonModelSelectorModel"}}]}}]}}]}}]}},...CommonModelSelectorModelFragmentDoc.definitions]} as unknown as DocumentNode<ProjectModelsSelectorValuesQuery, ProjectModelsSelectorValuesQueryVariables>;
|
||||
export const MainServerInfoDataDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MainServerInfoData"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"serverInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"adminContact"}},{"kind":"Field","name":{"kind":"Name","value":"blobSizeLimitBytes"}},{"kind":"Field","name":{"kind":"Name","value":"canonicalUrl"}},{"kind":"Field","name":{"kind":"Name","value":"company"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"guestModeEnabled"}},{"kind":"Field","name":{"kind":"Name","value":"inviteOnly"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"termsOfService"}},{"kind":"Field","name":{"kind":"Name","value":"version"}}]}}]}}]} as unknown as DocumentNode<MainServerInfoDataQuery, MainServerInfoDataQueryVariables>;
|
||||
export const ServerVersionInfoDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ServerVersionInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"serverInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"version"}}]}}]}}]} as unknown as DocumentNode<ServerVersionInfoQuery, ServerVersionInfoQueryVariables>;
|
||||
export const SearchProjectsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"SearchProjects"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"search"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"onlyWithRoles"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},"defaultValue":{"kind":"NullValue"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeUser"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"projects"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"10"}},{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"search"},"value":{"kind":"Variable","name":{"kind":"Name","value":"search"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"onlyWithRoles"},"value":{"kind":"Variable","name":{"kind":"Name","value":"onlyWithRoles"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FormSelectProjects_Project"}}]}}]}}]}}]}},...FormSelectProjects_ProjectFragmentDoc.definitions]} as unknown as DocumentNode<SearchProjectsQuery, SearchProjectsQueryVariables>;
|
||||
export const CreateModelDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateModel"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateModelInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"modelMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"create"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProjectPageLatestItemsModelItem"}}]}}]}}]}},...ProjectPageLatestItemsModelItemFragmentDoc.definitions,...PendingFileUploadFragmentDoc.definitions,...ProjectPageModelsCardRenameDialogFragmentDoc.definitions,...ProjectPageModelsCardDeleteDialogFragmentDoc.definitions,...ProjectPageModelsActionsFragmentDoc.definitions]} as unknown as DocumentNode<CreateModelMutation, CreateModelMutationVariables>;
|
||||
|
||||
@@ -29,6 +29,7 @@ export const userSearchQuery = graphql(`
|
||||
company
|
||||
avatar
|
||||
verified
|
||||
role
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import { graphql } from '~~/lib/common/generated/gql'
|
||||
|
||||
const serverInfoQuery = graphql(`
|
||||
query MainServerInfoData {
|
||||
serverInfo {
|
||||
adminContact
|
||||
blobSizeLimitBytes
|
||||
canonicalUrl
|
||||
company
|
||||
description
|
||||
guestModeEnabled
|
||||
inviteOnly
|
||||
name
|
||||
termsOfService
|
||||
version
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
export function useServerInfo() {
|
||||
const { result } = useQuery(serverInfoQuery)
|
||||
|
||||
const serverInfo = computed(() => result.value?.serverInfo)
|
||||
|
||||
const isGuestMode = computed(() => !!serverInfo.value?.guestModeEnabled)
|
||||
|
||||
return { serverInfo, isGuestMode }
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Roles } from '@speckle/shared'
|
||||
import { Nullable, Roles, ServerRoles } from '@speckle/shared'
|
||||
import { useActiveUser } from '~~/lib/auth/composables/activeUser'
|
||||
import { ProjectPageTeamDialogFragment } from '~~/lib/common/generated/gql/graphql'
|
||||
import { ProjectCollaboratorListItem } from '~~/lib/projects/helpers/components'
|
||||
@@ -12,7 +12,7 @@ export function useTeamDialogInternals(params: {
|
||||
props: { project }
|
||||
} = params
|
||||
|
||||
const { activeUser } = useActiveUser()
|
||||
const { activeUser, isGuest: isServerGuest } = useActiveUser()
|
||||
|
||||
const collaboratorListItems = computed((): ProjectCollaboratorListItem[] => {
|
||||
const results: ProjectCollaboratorListItem[] = []
|
||||
@@ -23,7 +23,8 @@ export function useTeamDialogInternals(params: {
|
||||
title: invitedUser.title,
|
||||
user: invitedUser.user || null,
|
||||
role: invitedUser.role,
|
||||
inviteId: invitedUser.inviteId
|
||||
inviteId: invitedUser.inviteId,
|
||||
serverRole: (invitedUser.user?.role || null) as Nullable<ServerRoles>
|
||||
})
|
||||
}
|
||||
|
||||
@@ -33,7 +34,8 @@ export function useTeamDialogInternals(params: {
|
||||
title: collaborator.user.name,
|
||||
user: collaborator.user,
|
||||
role: collaborator.role,
|
||||
inviteId: null
|
||||
inviteId: null,
|
||||
serverRole: collaborator.user.role as ServerRoles
|
||||
})
|
||||
}
|
||||
|
||||
@@ -54,6 +56,7 @@ export function useTeamDialogInternals(params: {
|
||||
return {
|
||||
collaboratorListItems,
|
||||
isOwner,
|
||||
canLeaveProject
|
||||
canLeaveProject,
|
||||
isServerGuest
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Nullable, Roles, StreamRoles } from '@speckle/shared'
|
||||
import { Nullable, Roles, ServerRoles, StreamRoles } from '@speckle/shared'
|
||||
import { LimitedUserAvatarFragment } from '~~/lib/common/generated/gql/graphql'
|
||||
|
||||
export type ProjectCollaboratorListItem = {
|
||||
@@ -7,6 +7,7 @@ export type ProjectCollaboratorListItem = {
|
||||
user: Nullable<LimitedUserAvatarFragment>
|
||||
role: string
|
||||
inviteId: Nullable<string>
|
||||
serverRole: Nullable<ServerRoles>
|
||||
}
|
||||
|
||||
export type SelectableStreamRole = StreamRoles | 'delete'
|
||||
|
||||
@@ -58,7 +58,10 @@ export const mockProjectPageQuery = apolloMockRequestWithDefaults<
|
||||
team: fakeUsers.map((u) => ({
|
||||
__typename: 'ProjectCollaborator',
|
||||
role: Roles.Stream.Contributor,
|
||||
user: u
|
||||
user: {
|
||||
...u,
|
||||
role: Roles.Server.User
|
||||
}
|
||||
})),
|
||||
invitedTeam: null
|
||||
},
|
||||
|
||||
@@ -27,7 +27,8 @@ const config = {
|
||||
rules: {
|
||||
'no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-unused-vars': ['error'],
|
||||
'vue/component-name-in-template-casing': ['warn', 'kebab-case']
|
||||
'vue/component-name-in-template-casing': ['warn', 'kebab-case'],
|
||||
'vue/require-default-prop': 'off'
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -18,6 +18,7 @@ export const streamCollaboratorFieldsFragment = gql`
|
||||
role
|
||||
company
|
||||
avatar
|
||||
serverRole
|
||||
}
|
||||
`
|
||||
|
||||
|
||||
@@ -54,6 +54,63 @@ export type ActivityCollection = {
|
||||
totalCount: Scalars['Int'];
|
||||
};
|
||||
|
||||
export type AdminInviteList = {
|
||||
__typename?: 'AdminInviteList';
|
||||
cursor?: Maybe<Scalars['String']>;
|
||||
items: Array<ServerInvite>;
|
||||
totalCount: Scalars['Int'];
|
||||
};
|
||||
|
||||
export type AdminQueries = {
|
||||
__typename?: 'AdminQueries';
|
||||
inviteList: AdminInviteList;
|
||||
projectList: ProjectCollection;
|
||||
serverStatistics: ServerStatistics;
|
||||
userList: AdminUserList;
|
||||
};
|
||||
|
||||
|
||||
export type AdminQueriesInviteListArgs = {
|
||||
cursor?: InputMaybe<Scalars['String']>;
|
||||
limit?: Scalars['Int'];
|
||||
query?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
|
||||
export type AdminQueriesProjectListArgs = {
|
||||
cursor?: InputMaybe<Scalars['String']>;
|
||||
limit?: Scalars['Int'];
|
||||
orderBy?: InputMaybe<Scalars['String']>;
|
||||
query?: InputMaybe<Scalars['String']>;
|
||||
visibility?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
|
||||
export type AdminQueriesUserListArgs = {
|
||||
cursor?: InputMaybe<Scalars['String']>;
|
||||
limit?: Scalars['Int'];
|
||||
query?: InputMaybe<Scalars['String']>;
|
||||
role?: InputMaybe<ServerRole>;
|
||||
};
|
||||
|
||||
export type AdminUserList = {
|
||||
__typename?: 'AdminUserList';
|
||||
cursor?: Maybe<Scalars['String']>;
|
||||
items: Array<AdminUserListItem>;
|
||||
totalCount: Scalars['Int'];
|
||||
};
|
||||
|
||||
export type AdminUserListItem = {
|
||||
__typename?: 'AdminUserListItem';
|
||||
avatar?: Maybe<Scalars['String']>;
|
||||
company?: Maybe<Scalars['String']>;
|
||||
email?: Maybe<Scalars['String']>;
|
||||
id: Scalars['ID'];
|
||||
name: Scalars['String'];
|
||||
role?: Maybe<Scalars['String']>;
|
||||
verified?: Maybe<Scalars['Boolean']>;
|
||||
};
|
||||
|
||||
export type AdminUsersListCollection = {
|
||||
__typename?: 'AdminUsersListCollection';
|
||||
items: Array<AdminUsersListItem>;
|
||||
@@ -369,6 +426,7 @@ export type Commit = {
|
||||
authorAvatar?: Maybe<Scalars['String']>;
|
||||
authorId?: Maybe<Scalars['String']>;
|
||||
authorName?: Maybe<Scalars['String']>;
|
||||
branch?: Maybe<Branch>;
|
||||
branchName?: Maybe<Scalars['String']>;
|
||||
/**
|
||||
* The total number of comments for this commit. To actually get the comments, use the comments query and pass in a resource array consisting of of this commit's id.
|
||||
@@ -709,6 +767,8 @@ export type ModelMutationsUpdateArgs = {
|
||||
export type ModelVersionsFilter = {
|
||||
/** Make sure these specified versions are always loaded first */
|
||||
priorityIds?: InputMaybe<Array<Scalars['String']>>;
|
||||
/** Only return versions specified in `priorityIds` */
|
||||
priorityIdsOnly?: InputMaybe<Scalars['Boolean']>;
|
||||
};
|
||||
|
||||
export type ModelsTreeItem = {
|
||||
@@ -1593,11 +1653,16 @@ export type Query = {
|
||||
_?: Maybe<Scalars['String']>;
|
||||
/** Gets the profile of the authenticated user or null if not authenticated */
|
||||
activeUser?: Maybe<User>;
|
||||
/** All the streams of the server. Available to admins only. */
|
||||
admin: AdminQueries;
|
||||
/**
|
||||
* All the streams of the server. Available to admins only.
|
||||
* @deprecated use admin.projectList instead
|
||||
*/
|
||||
adminStreams?: Maybe<StreamCollection>;
|
||||
/**
|
||||
* Get all (or search for specific) users, registered or invited, from the server in a paginated view.
|
||||
* The query looks for matches in name, company and email.
|
||||
* @deprecated use admin.UserList instead
|
||||
*/
|
||||
adminUsers?: Maybe<AdminUsersListCollection>;
|
||||
/** Gets a specific app from the server. */
|
||||
@@ -1629,6 +1694,7 @@ export type Query = {
|
||||
*/
|
||||
projectInvite?: Maybe<PendingStreamCollaborator>;
|
||||
serverInfo: ServerInfo;
|
||||
/** @deprecated use admin.serverStatistics instead */
|
||||
serverStats: ServerStats;
|
||||
/**
|
||||
* Returns a specific stream. Will throw an authorization error if active user isn't authorized
|
||||
@@ -1795,7 +1861,6 @@ export enum ResourceType {
|
||||
Stream = 'stream'
|
||||
}
|
||||
|
||||
/** Available roles. */
|
||||
export type Role = {
|
||||
__typename?: 'Role';
|
||||
description: Scalars['String'];
|
||||
@@ -1854,10 +1919,12 @@ export type ServerInfo = {
|
||||
canonicalUrl?: Maybe<Scalars['String']>;
|
||||
company?: Maybe<Scalars['String']>;
|
||||
description?: Maybe<Scalars['String']>;
|
||||
guestModeEnabled: Scalars['Boolean'];
|
||||
inviteOnly?: Maybe<Scalars['Boolean']>;
|
||||
name: Scalars['String'];
|
||||
roles: Array<Maybe<Role>>;
|
||||
scopes: Array<Maybe<Scope>>;
|
||||
roles: Array<Role>;
|
||||
scopes: Array<Scope>;
|
||||
serverRoles: Array<ServerRoleItem>;
|
||||
termsOfService?: Maybe<Scalars['String']>;
|
||||
version?: Maybe<Scalars['String']>;
|
||||
};
|
||||
@@ -1866,6 +1933,7 @@ export type ServerInfoUpdateInput = {
|
||||
adminContact?: InputMaybe<Scalars['String']>;
|
||||
company?: InputMaybe<Scalars['String']>;
|
||||
description?: InputMaybe<Scalars['String']>;
|
||||
guestModeEnabled?: InputMaybe<Scalars['Boolean']>;
|
||||
inviteOnly?: InputMaybe<Scalars['Boolean']>;
|
||||
name: Scalars['String'];
|
||||
termsOfService?: InputMaybe<Scalars['String']>;
|
||||
@@ -1886,9 +1954,23 @@ export type ServerInviteCreateInput = {
|
||||
export enum ServerRole {
|
||||
ServerAdmin = 'SERVER_ADMIN',
|
||||
ServerArchivedUser = 'SERVER_ARCHIVED_USER',
|
||||
ServerGuest = 'SERVER_GUEST',
|
||||
ServerUser = 'SERVER_USER'
|
||||
}
|
||||
|
||||
export type ServerRoleItem = {
|
||||
__typename?: 'ServerRoleItem';
|
||||
id: Scalars['String'];
|
||||
title: Scalars['String'];
|
||||
};
|
||||
|
||||
export type ServerStatistics = {
|
||||
__typename?: 'ServerStatistics';
|
||||
totalPendingInvites: Scalars['Int'];
|
||||
totalProjectCount: Scalars['Int'];
|
||||
totalUserCount: Scalars['Int'];
|
||||
};
|
||||
|
||||
export type ServerStats = {
|
||||
__typename?: 'ServerStats';
|
||||
/** An array of objects currently structured as { created_month: Date, count: int }. */
|
||||
@@ -2056,6 +2138,7 @@ export type StreamCollaborator = {
|
||||
id: Scalars['String'];
|
||||
name: Scalars['String'];
|
||||
role: Scalars['String'];
|
||||
serverRole: Scalars['String'];
|
||||
};
|
||||
|
||||
export type StreamCollection = {
|
||||
@@ -2289,6 +2372,7 @@ export type SubscriptionUserViewerActivityArgs = {
|
||||
|
||||
|
||||
export type SubscriptionViewerUserActivityBroadcastedArgs = {
|
||||
sessionId?: InputMaybe<Scalars['String']>;
|
||||
target: ViewerUpdateTrackingTarget;
|
||||
};
|
||||
|
||||
@@ -2333,10 +2417,6 @@ export type User = {
|
||||
/** Returns the apps you have created. */
|
||||
createdApps?: Maybe<Array<ServerApp>>;
|
||||
createdAt?: Maybe<Scalars['DateTime']>;
|
||||
/**
|
||||
* E-mail can be null, if it's requested for a user other than the authenticated one
|
||||
* and the user isn't an admin
|
||||
*/
|
||||
email?: Maybe<Scalars['String']>;
|
||||
/**
|
||||
* All the streams that a active user has favorited.
|
||||
@@ -2737,7 +2817,7 @@ export type StreamPendingAccessRequestsFragment = { __typename?: 'Stream', pendi
|
||||
|
||||
export type LimitedUserFieldsFragment = { __typename?: 'LimitedUser', id: string, name: string, bio?: string | null, company?: string | null, avatar?: string | null, verified?: boolean | null };
|
||||
|
||||
export type StreamCollaboratorFieldsFragment = { __typename?: 'StreamCollaborator', id: string, name: string, role: string, company?: string | null, avatar?: string | null };
|
||||
export type StreamCollaboratorFieldsFragment = { __typename?: 'StreamCollaborator', id: string, name: string, role: string, company?: string | null, avatar?: string | null, serverRole: string };
|
||||
|
||||
export type UsersOwnInviteFieldsFragment = { __typename?: 'PendingStreamCollaborator', id: string, inviteId: string, streamId: string, streamName: string, token?: string | null, invitedBy: { __typename?: 'LimitedUser', id: string, name: string, bio?: string | null, company?: string | null, avatar?: string | null, verified?: boolean | null } };
|
||||
|
||||
@@ -2817,27 +2897,32 @@ export type StreamObjectNoDataQuery = { __typename?: 'Query', stream?: { __typen
|
||||
|
||||
export type ServerInfoBlobSizeFieldsFragment = { __typename?: 'ServerInfo', blobSizeLimitBytes: number };
|
||||
|
||||
export type MainServerInfoFieldsFragment = { __typename?: 'ServerInfo', name: string, company?: string | null, description?: string | null, adminContact?: string | null, canonicalUrl?: string | null, termsOfService?: string | null, inviteOnly?: boolean | null, version?: string | null };
|
||||
export type MainServerInfoFieldsFragment = { __typename?: 'ServerInfo', name: string, company?: string | null, description?: string | null, adminContact?: string | null, canonicalUrl?: string | null, termsOfService?: string | null, inviteOnly?: boolean | null, version?: string | null, guestModeEnabled: boolean };
|
||||
|
||||
export type ServerInfoRolesFieldsFragment = { __typename?: 'ServerInfo', roles: Array<{ __typename?: 'Role', name: string, description: string, resourceTarget: string } | null> };
|
||||
export type ServerInfoRolesFieldsFragment = { __typename?: 'ServerInfo', serverRoles: Array<{ __typename?: 'ServerRoleItem', id: string, title: string }> };
|
||||
|
||||
export type ServerInfoScopesFieldsFragment = { __typename?: 'ServerInfo', scopes: Array<{ __typename?: 'Scope', name: string, description: string } | null> };
|
||||
export type ServerInfoScopesFieldsFragment = { __typename?: 'ServerInfo', scopes: Array<{ __typename?: 'Scope', name: string, description: string }> };
|
||||
|
||||
export type MainServerInfoQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type MainServerInfoQuery = { __typename?: 'Query', serverInfo: { __typename?: 'ServerInfo', name: string, company?: string | null, description?: string | null, adminContact?: string | null, canonicalUrl?: string | null, termsOfService?: string | null, inviteOnly?: boolean | null, version?: string | null } };
|
||||
export type MainServerInfoQuery = { __typename?: 'Query', serverInfo: { __typename?: 'ServerInfo', name: string, company?: string | null, description?: string | null, adminContact?: string | null, canonicalUrl?: string | null, termsOfService?: string | null, inviteOnly?: boolean | null, version?: string | null, guestModeEnabled: boolean } };
|
||||
|
||||
export type FullServerInfoQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type FullServerInfoQuery = { __typename?: 'Query', serverInfo: { __typename?: 'ServerInfo', name: string, company?: string | null, description?: string | null, adminContact?: string | null, canonicalUrl?: string | null, termsOfService?: string | null, inviteOnly?: boolean | null, version?: string | null, blobSizeLimitBytes: number, roles: Array<{ __typename?: 'Role', name: string, description: string, resourceTarget: string } | null>, scopes: Array<{ __typename?: 'Scope', name: string, description: string } | null> } };
|
||||
export type FullServerInfoQuery = { __typename?: 'Query', serverInfo: { __typename?: 'ServerInfo', name: string, company?: string | null, description?: string | null, adminContact?: string | null, canonicalUrl?: string | null, termsOfService?: string | null, inviteOnly?: boolean | null, version?: string | null, guestModeEnabled: boolean, blobSizeLimitBytes: number, serverRoles: Array<{ __typename?: 'ServerRoleItem', id: string, title: string }>, scopes: Array<{ __typename?: 'Scope', name: string, description: string }> } };
|
||||
|
||||
export type ServerInfoBlobSizeLimitQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type ServerInfoBlobSizeLimitQuery = { __typename?: 'Query', serverInfo: { __typename?: 'ServerInfo', blobSizeLimitBytes: number } };
|
||||
|
||||
export type AvailableServerRolesQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type AvailableServerRolesQuery = { __typename?: 'Query', serverInfo: { __typename?: 'ServerInfo', guestModeEnabled: boolean, serverRoles: Array<{ __typename?: 'ServerRoleItem', id: string, title: string }> } };
|
||||
|
||||
export type StreamCommitsQueryVariables = Exact<{
|
||||
id: Scalars['String'];
|
||||
}>;
|
||||
@@ -2852,21 +2937,21 @@ export type StreamsQueryVariables = Exact<{
|
||||
|
||||
export type StreamsQuery = { __typename?: 'Query', streams?: { __typename?: 'StreamCollection', totalCount: number, cursor?: string | null, items?: Array<{ __typename?: 'Stream', id: string, name: string, description?: string | null, role?: string | null, isPublic: boolean, createdAt: string, updatedAt: string, commentCount: number, favoritedDate?: string | null, favoritesCount: number, collaborators: Array<{ __typename?: 'StreamCollaborator', id: string, name: string, company?: string | null, avatar?: string | null, role: string }>, commits?: { __typename?: 'CommitCollection', totalCount: number, items?: Array<{ __typename?: 'Commit', id: string, createdAt?: string | null, message?: string | null, authorId?: string | null, branchName?: string | null, authorName?: string | null, authorAvatar?: string | null, referencedObject: string }> | null } | null, branches?: { __typename?: 'BranchCollection', totalCount: number } | null }> | null } | null };
|
||||
|
||||
export type CommonStreamFieldsFragment = { __typename?: 'Stream', id: string, name: string, description?: string | null, role?: string | null, isPublic: boolean, createdAt: string, updatedAt: string, commentCount: number, favoritedDate?: string | null, favoritesCount: number, collaborators: Array<{ __typename?: 'StreamCollaborator', id: string, name: string, role: string, company?: string | null, avatar?: string | null }>, commits?: { __typename?: 'CommitCollection', totalCount: number } | null, branches?: { __typename?: 'BranchCollection', totalCount: number } | null };
|
||||
export type CommonStreamFieldsFragment = { __typename?: 'Stream', id: string, name: string, description?: string | null, role?: string | null, isPublic: boolean, createdAt: string, updatedAt: string, commentCount: number, favoritedDate?: string | null, favoritesCount: number, collaborators: Array<{ __typename?: 'StreamCollaborator', id: string, name: string, role: string, company?: string | null, avatar?: string | null, serverRole: string }>, commits?: { __typename?: 'CommitCollection', totalCount: number } | null, branches?: { __typename?: 'BranchCollection', totalCount: number } | null };
|
||||
|
||||
export type StreamQueryVariables = Exact<{
|
||||
id: Scalars['String'];
|
||||
}>;
|
||||
|
||||
|
||||
export type StreamQuery = { __typename?: 'Query', stream?: { __typename?: 'Stream', id: string, name: string, description?: string | null, role?: string | null, isPublic: boolean, createdAt: string, updatedAt: string, commentCount: number, favoritedDate?: string | null, favoritesCount: number, collaborators: Array<{ __typename?: 'StreamCollaborator', id: string, name: string, role: string, company?: string | null, avatar?: string | null }>, commits?: { __typename?: 'CommitCollection', totalCount: number } | null, branches?: { __typename?: 'BranchCollection', totalCount: number } | null } | null };
|
||||
export type StreamQuery = { __typename?: 'Query', stream?: { __typename?: 'Stream', id: string, name: string, description?: string | null, role?: string | null, isPublic: boolean, createdAt: string, updatedAt: string, commentCount: number, favoritedDate?: string | null, favoritesCount: number, collaborators: Array<{ __typename?: 'StreamCollaborator', id: string, name: string, role: string, company?: string | null, avatar?: string | null, serverRole: string }>, commits?: { __typename?: 'CommitCollection', totalCount: number } | null, branches?: { __typename?: 'BranchCollection', totalCount: number } | null } | null };
|
||||
|
||||
export type StreamWithCollaboratorsQueryVariables = Exact<{
|
||||
id: Scalars['String'];
|
||||
}>;
|
||||
|
||||
|
||||
export type StreamWithCollaboratorsQuery = { __typename?: 'Query', stream?: { __typename?: 'Stream', id: string, name: string, isPublic: boolean, role?: string | null, collaborators: Array<{ __typename?: 'StreamCollaborator', id: string, name: string, role: string, company?: string | null, avatar?: string | null }>, pendingCollaborators?: Array<{ __typename?: 'PendingStreamCollaborator', title: string, inviteId: string, role: string, user?: { __typename?: 'LimitedUser', id: string, name: string, bio?: string | null, company?: string | null, avatar?: string | null, verified?: boolean | null } | null }> | null, pendingAccessRequests?: Array<{ __typename?: 'StreamAccessRequest', id: string, streamId: string, createdAt: string, requester: { __typename?: 'LimitedUser', id: string, name: string, bio?: string | null, company?: string | null, avatar?: string | null, verified?: boolean | null } }> | null } | null };
|
||||
export type StreamWithCollaboratorsQuery = { __typename?: 'Query', stream?: { __typename?: 'Stream', id: string, name: string, isPublic: boolean, role?: string | null, collaborators: Array<{ __typename?: 'StreamCollaborator', id: string, name: string, role: string, company?: string | null, avatar?: string | null, serverRole: string }>, pendingCollaborators?: Array<{ __typename?: 'PendingStreamCollaborator', title: string, inviteId: string, role: string, user?: { __typename?: 'LimitedUser', id: string, name: string, bio?: string | null, company?: string | null, avatar?: string | null, verified?: boolean | null } | null }> | null, pendingAccessRequests?: Array<{ __typename?: 'StreamAccessRequest', id: string, streamId: string, createdAt: string, requester: { __typename?: 'LimitedUser', id: string, name: string, bio?: string | null, company?: string | null, avatar?: string | null, verified?: boolean | null } }> | null } | null };
|
||||
|
||||
export type StreamWithActivityQueryVariables = Exact<{
|
||||
id: Scalars['String'];
|
||||
@@ -2938,7 +3023,7 @@ export type ShareableStreamQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type ShareableStreamQuery = { __typename?: 'Query', stream?: { __typename?: 'Stream', id: string, isPublic: boolean, role?: string | null, collaborators: Array<{ __typename?: 'StreamCollaborator', id: string, name: string, role: string, company?: string | null, avatar?: string | null }> } | null };
|
||||
export type ShareableStreamQuery = { __typename?: 'Query', stream?: { __typename?: 'Stream', id: string, isPublic: boolean, role?: string | null, collaborators: Array<{ __typename?: 'StreamCollaborator', id: string, name: string, role: string, company?: string | null, avatar?: string | null, serverRole: string }> } | null };
|
||||
|
||||
export type CommonUserFieldsFragment = { __typename?: 'User', id: string, email?: string | null, name: string, bio?: string | null, company?: string | null, avatar?: string | null, verified?: boolean | null, hasPendingVerification?: boolean | null, profiles?: Record<string, unknown> | null, role?: string | null, streams: { __typename?: 'StreamCollection', totalCount: number }, commits?: { __typename?: 'CommitCollection', totalCount: number, items?: Array<{ __typename?: 'Commit', id: string, createdAt?: string | null }> | null } | null };
|
||||
|
||||
@@ -2947,7 +3032,7 @@ export type UserFavoriteStreamsQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type UserFavoriteStreamsQuery = { __typename?: 'Query', activeUser?: { __typename?: 'User', id: string, email?: string | null, name: string, bio?: string | null, company?: string | null, avatar?: string | null, verified?: boolean | null, hasPendingVerification?: boolean | null, profiles?: Record<string, unknown> | null, role?: string | null, favoriteStreams: { __typename?: 'StreamCollection', totalCount: number, cursor?: string | null, items?: Array<{ __typename?: 'Stream', id: string, name: string, description?: string | null, role?: string | null, isPublic: boolean, createdAt: string, updatedAt: string, commentCount: number, favoritedDate?: string | null, favoritesCount: number, collaborators: Array<{ __typename?: 'StreamCollaborator', id: string, name: string, role: string, company?: string | null, avatar?: string | null }>, commits?: { __typename?: 'CommitCollection', totalCount: number } | null, branches?: { __typename?: 'BranchCollection', totalCount: number } | null }> | null }, streams: { __typename?: 'StreamCollection', totalCount: number }, commits?: { __typename?: 'CommitCollection', totalCount: number, items?: Array<{ __typename?: 'Commit', id: string, createdAt?: string | null }> | null } | null } | null };
|
||||
export type UserFavoriteStreamsQuery = { __typename?: 'Query', activeUser?: { __typename?: 'User', id: string, email?: string | null, name: string, bio?: string | null, company?: string | null, avatar?: string | null, verified?: boolean | null, hasPendingVerification?: boolean | null, profiles?: Record<string, unknown> | null, role?: string | null, favoriteStreams: { __typename?: 'StreamCollection', totalCount: number, cursor?: string | null, items?: Array<{ __typename?: 'Stream', id: string, name: string, description?: string | null, role?: string | null, isPublic: boolean, createdAt: string, updatedAt: string, commentCount: number, favoritedDate?: string | null, favoritesCount: number, collaborators: Array<{ __typename?: 'StreamCollaborator', id: string, name: string, role: string, company?: string | null, avatar?: string | null, serverRole: string }>, commits?: { __typename?: 'CommitCollection', totalCount: number } | null, branches?: { __typename?: 'BranchCollection', totalCount: number } | null }> | null }, streams: { __typename?: 'StreamCollection', totalCount: number }, commits?: { __typename?: 'CommitCollection', totalCount: number, items?: Array<{ __typename?: 'Commit', id: string, createdAt?: string | null }> | null } | null } | null };
|
||||
|
||||
export type MainUserDataQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
@@ -3153,14 +3238,14 @@ export const MainServerInfoFields = gql`
|
||||
termsOfService
|
||||
inviteOnly
|
||||
version
|
||||
guestModeEnabled
|
||||
}
|
||||
`;
|
||||
export const ServerInfoRolesFields = gql`
|
||||
fragment ServerInfoRolesFields on ServerInfo {
|
||||
roles {
|
||||
name
|
||||
description
|
||||
resourceTarget
|
||||
serverRoles {
|
||||
id
|
||||
title
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -3179,6 +3264,7 @@ export const StreamCollaboratorFields = gql`
|
||||
role
|
||||
company
|
||||
avatar
|
||||
serverRole
|
||||
}
|
||||
`;
|
||||
export const CommonStreamFields = gql`
|
||||
@@ -3446,6 +3532,17 @@ export const ServerInfoBlobSizeLimit = gql`
|
||||
}
|
||||
}
|
||||
${ServerInfoBlobSizeFields}`;
|
||||
export const AvailableServerRoles = gql`
|
||||
query AvailableServerRoles {
|
||||
serverInfo {
|
||||
serverRoles {
|
||||
id
|
||||
title
|
||||
}
|
||||
guestModeEnabled
|
||||
}
|
||||
}
|
||||
`;
|
||||
export const StreamCommits = gql`
|
||||
query StreamCommits($id: String!) {
|
||||
stream(id: $id) {
|
||||
@@ -3865,10 +3962,10 @@ export const FullStreamAccessRequestFieldsFragmentDoc = {"kind":"Document","defi
|
||||
export const StreamPendingAccessRequestsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"StreamPendingAccessRequests"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Stream"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"pendingAccessRequests"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullStreamAccessRequestFields"}}]}}]}}]} as unknown as DocumentNode<StreamPendingAccessRequestsFragment, unknown>;
|
||||
export const UsersOwnInviteFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"UsersOwnInviteFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PendingStreamCollaborator"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"inviteId"}},{"kind":"Field","name":{"kind":"Name","value":"streamId"}},{"kind":"Field","name":{"kind":"Name","value":"streamName"}},{"kind":"Field","name":{"kind":"Name","value":"token"}},{"kind":"Field","name":{"kind":"Name","value":"invitedBy"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"LimitedUserFields"}}]}}]}}]} as unknown as DocumentNode<UsersOwnInviteFieldsFragment, unknown>;
|
||||
export const ServerInfoBlobSizeFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ServerInfoBlobSizeFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ServerInfo"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"blobSizeLimitBytes"}}]}}]} as unknown as DocumentNode<ServerInfoBlobSizeFieldsFragment, unknown>;
|
||||
export const MainServerInfoFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MainServerInfoFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ServerInfo"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"company"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"adminContact"}},{"kind":"Field","name":{"kind":"Name","value":"canonicalUrl"}},{"kind":"Field","name":{"kind":"Name","value":"termsOfService"}},{"kind":"Field","name":{"kind":"Name","value":"inviteOnly"}},{"kind":"Field","name":{"kind":"Name","value":"version"}}]}}]} as unknown as DocumentNode<MainServerInfoFieldsFragment, unknown>;
|
||||
export const ServerInfoRolesFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ServerInfoRolesFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ServerInfo"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"roles"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"resourceTarget"}}]}}]}}]} as unknown as DocumentNode<ServerInfoRolesFieldsFragment, unknown>;
|
||||
export const MainServerInfoFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"MainServerInfoFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ServerInfo"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"company"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"adminContact"}},{"kind":"Field","name":{"kind":"Name","value":"canonicalUrl"}},{"kind":"Field","name":{"kind":"Name","value":"termsOfService"}},{"kind":"Field","name":{"kind":"Name","value":"inviteOnly"}},{"kind":"Field","name":{"kind":"Name","value":"version"}},{"kind":"Field","name":{"kind":"Name","value":"guestModeEnabled"}}]}}]} as unknown as DocumentNode<MainServerInfoFieldsFragment, unknown>;
|
||||
export const ServerInfoRolesFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ServerInfoRolesFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ServerInfo"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"serverRoles"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}}]}}]}}]} as unknown as DocumentNode<ServerInfoRolesFieldsFragment, unknown>;
|
||||
export const ServerInfoScopesFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ServerInfoScopesFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ServerInfo"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"scopes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}}]}}]} as unknown as DocumentNode<ServerInfoScopesFieldsFragment, unknown>;
|
||||
export const StreamCollaboratorFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"StreamCollaboratorFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StreamCollaborator"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"company"}},{"kind":"Field","name":{"kind":"Name","value":"avatar"}}]}}]} as unknown as DocumentNode<StreamCollaboratorFieldsFragment, unknown>;
|
||||
export const StreamCollaboratorFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"StreamCollaboratorFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StreamCollaborator"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"company"}},{"kind":"Field","name":{"kind":"Name","value":"avatar"}},{"kind":"Field","name":{"kind":"Name","value":"serverRole"}}]}}]} as unknown as DocumentNode<StreamCollaboratorFieldsFragment, unknown>;
|
||||
export const CommonStreamFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CommonStreamFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Stream"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"isPublic"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"commentCount"}},{"kind":"Field","name":{"kind":"Name","value":"collaborators"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"StreamCollaboratorFields"}}]}},{"kind":"Field","name":{"kind":"Name","value":"commits"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"1"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}},{"kind":"Field","name":{"kind":"Name","value":"branches"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}},{"kind":"Field","name":{"kind":"Name","value":"favoritedDate"}},{"kind":"Field","name":{"kind":"Name","value":"favoritesCount"}}]}}]} as unknown as DocumentNode<CommonStreamFieldsFragment, unknown>;
|
||||
export const CommonUserFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CommonUserFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"bio"}},{"kind":"Field","name":{"kind":"Name","value":"company"}},{"kind":"Field","name":{"kind":"Name","value":"avatar"}},{"kind":"Field","name":{"kind":"Name","value":"verified"}},{"kind":"Field","name":{"kind":"Name","value":"hasPendingVerification"}},{"kind":"Field","name":{"kind":"Name","value":"profiles"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"streams"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}},{"kind":"Field","name":{"kind":"Name","value":"commits"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"1"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]}}]}}]} as unknown as DocumentNode<CommonUserFieldsFragment, unknown>;
|
||||
export const GetStreamAccessRequestDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetStreamAccessRequest"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"streamId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"streamAccessRequest"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"streamId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"streamId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BasicStreamAccessRequestFields"}}]}}]}},...BasicStreamAccessRequestFieldsFragmentDoc.definitions]} as unknown as DocumentNode<GetStreamAccessRequestQuery, GetStreamAccessRequestQueryVariables>;
|
||||
@@ -3894,6 +3991,7 @@ export const StreamObjectNoDataDocument = {"kind":"Document","definitions":[{"ki
|
||||
export const MainServerInfoDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MainServerInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"serverInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"MainServerInfoFields"}}]}}]}},...MainServerInfoFieldsFragmentDoc.definitions]} as unknown as DocumentNode<MainServerInfoQuery, MainServerInfoQueryVariables>;
|
||||
export const FullServerInfoDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FullServerInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"serverInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"MainServerInfoFields"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"ServerInfoRolesFields"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"ServerInfoScopesFields"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"ServerInfoBlobSizeFields"}}]}}]}},...MainServerInfoFieldsFragmentDoc.definitions,...ServerInfoRolesFieldsFragmentDoc.definitions,...ServerInfoScopesFieldsFragmentDoc.definitions,...ServerInfoBlobSizeFieldsFragmentDoc.definitions]} as unknown as DocumentNode<FullServerInfoQuery, FullServerInfoQueryVariables>;
|
||||
export const ServerInfoBlobSizeLimitDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ServerInfoBlobSizeLimit"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"serverInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ServerInfoBlobSizeFields"}}]}}]}},...ServerInfoBlobSizeFieldsFragmentDoc.definitions]} as unknown as DocumentNode<ServerInfoBlobSizeLimitQuery, ServerInfoBlobSizeLimitQueryVariables>;
|
||||
export const AvailableServerRolesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AvailableServerRoles"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"serverInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"serverRoles"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}}]}},{"kind":"Field","name":{"kind":"Name","value":"guestModeEnabled"}}]}}]}}]} as unknown as DocumentNode<AvailableServerRolesQuery, AvailableServerRolesQueryVariables>;
|
||||
export const StreamCommitsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"StreamCommits"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"stream"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"commits"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"authorId"}},{"kind":"Field","name":{"kind":"Name","value":"authorName"}},{"kind":"Field","name":{"kind":"Name","value":"authorAvatar"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"referencedObject"}},{"kind":"Field","name":{"kind":"Name","value":"branchName"}},{"kind":"Field","name":{"kind":"Name","value":"sourceApplication"}}]}}]}}]}}]}}]} as unknown as DocumentNode<StreamCommitsQuery, StreamCommitsQueryVariables>;
|
||||
export const StreamsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Streams"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"cursor"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"streams"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"cursor"},"value":{"kind":"Variable","name":{"kind":"Name","value":"cursor"}}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"10"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}},{"kind":"Field","name":{"kind":"Name","value":"cursor"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"isPublic"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"commentCount"}},{"kind":"Field","name":{"kind":"Name","value":"collaborators"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"company"}},{"kind":"Field","name":{"kind":"Name","value":"avatar"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}},{"kind":"Field","name":{"kind":"Name","value":"commits"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"1"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"authorId"}},{"kind":"Field","name":{"kind":"Name","value":"branchName"}},{"kind":"Field","name":{"kind":"Name","value":"authorName"}},{"kind":"Field","name":{"kind":"Name","value":"authorAvatar"}},{"kind":"Field","name":{"kind":"Name","value":"referencedObject"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"branches"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}},{"kind":"Field","name":{"kind":"Name","value":"favoritedDate"}},{"kind":"Field","name":{"kind":"Name","value":"favoritesCount"}}]}}]}}]}}]} as unknown as DocumentNode<StreamsQuery, StreamsQueryVariables>;
|
||||
export const StreamDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Stream"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"stream"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CommonStreamFields"}}]}}]}},...CommonStreamFieldsFragmentDoc.definitions,...StreamCollaboratorFieldsFragmentDoc.definitions]} as unknown as DocumentNode<StreamQuery, StreamQueryVariables>;
|
||||
|
||||
@@ -16,15 +16,15 @@ export const mainServerInfoFieldsFragment = gql`
|
||||
termsOfService
|
||||
inviteOnly
|
||||
version
|
||||
guestModeEnabled
|
||||
}
|
||||
`
|
||||
|
||||
export const serverInfoRolesFieldsFragment = gql`
|
||||
fragment ServerInfoRolesFields on ServerInfo {
|
||||
roles {
|
||||
name
|
||||
description
|
||||
resourceTarget
|
||||
serverRoles {
|
||||
id
|
||||
title
|
||||
}
|
||||
}
|
||||
`
|
||||
@@ -75,3 +75,15 @@ export const serverInfoBlobSizeLimitQuery = gql`
|
||||
}
|
||||
${serverInfoBlobSizeFragment}
|
||||
`
|
||||
|
||||
export const availableServerRolesQuery = gql`
|
||||
query AvailableServerRoles {
|
||||
serverInfo {
|
||||
serverRoles {
|
||||
id
|
||||
title
|
||||
}
|
||||
guestModeEnabled
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<users-list-user-item
|
||||
v-if="registeredUser"
|
||||
:user="registeredUser"
|
||||
:roles="roles"
|
||||
:allow-guest="allowGuest"
|
||||
@change-role="$emit('user-change-role', $event)"
|
||||
@delete="$emit('user-delete', $event)"
|
||||
/>
|
||||
@@ -34,10 +34,7 @@ export default Vue.extend({
|
||||
return !!(val.invitedUser || val.registeredUser)
|
||||
}
|
||||
},
|
||||
roles: {
|
||||
type: Array as PropType<{ text: string; value: string }[]>,
|
||||
required: true
|
||||
}
|
||||
allowGuest: { type: Boolean }
|
||||
},
|
||||
computed: {
|
||||
registeredUser(): MaybeFalsy<User> {
|
||||
|
||||
@@ -35,25 +35,18 @@
|
||||
<v-col cols="3" class="d-flex align-center text-right">
|
||||
<v-icon small class="mr-2">
|
||||
{{
|
||||
selfUser.role === 'server:admin'
|
||||
selfUser.role === serverRoles.Admin
|
||||
? 'mdi-key'
|
||||
: selfUser.role === 'server:user'
|
||||
? 'mdi-account'
|
||||
: 'mdi-account-off'
|
||||
: selfUser.role === serverRoles.ArchivedUser
|
||||
? 'mdi-account-off'
|
||||
: 'mdi-account'
|
||||
}}
|
||||
</v-icon>
|
||||
<v-select
|
||||
v-tooltip="'Change role'"
|
||||
:value="selfUser.role"
|
||||
:items="roles"
|
||||
dense
|
||||
filled
|
||||
rounded
|
||||
hide-details
|
||||
@change="(e) => $emit('change-role', { user, role: e })"
|
||||
></v-select>
|
||||
<!-- </v-col>
|
||||
<v-col cols="1" class="text-right"> -->
|
||||
<user-role-select
|
||||
:allow-guest="allowGuest"
|
||||
:role="selfUser.role"
|
||||
@update:role="(e) => $emit('change-role', { user, role: e })"
|
||||
/>
|
||||
<v-btn
|
||||
v-tooltip="'Delete user'"
|
||||
small
|
||||
@@ -67,18 +60,23 @@
|
||||
</v-row>
|
||||
</template>
|
||||
<script>
|
||||
import UserRoleSelect from '@/main/components/common/UserRoleSelect.vue'
|
||||
import { Roles } from '@speckle/shared'
|
||||
|
||||
export default {
|
||||
name: 'UsersListUserItem',
|
||||
components: {
|
||||
UserAvatar: () => import('@/main/components/common/UserAvatar')
|
||||
UserAvatar: () => import('@/main/components/common/UserAvatar'),
|
||||
UserRoleSelect
|
||||
},
|
||||
props: {
|
||||
user: { type: Object, default: () => null },
|
||||
roles: { type: Array, default: () => [] }
|
||||
allowGuest: { type: Boolean }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selfUser: this.user
|
||||
selfUser: this.user,
|
||||
serverRoles: Roles.Server
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
<template>
|
||||
<v-select
|
||||
v-model="finalRole"
|
||||
:items="roles"
|
||||
dense
|
||||
filled
|
||||
rounded
|
||||
hide-details
|
||||
:label="label"
|
||||
></v-select>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ServerRoles, RoleInfo, Roles } from '@speckle/shared'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:role', val: ServerRoles): void
|
||||
}>()
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
role: ServerRoles
|
||||
allowGuest?: boolean
|
||||
allowAdmin?: boolean
|
||||
label?: string
|
||||
forInvite?: boolean
|
||||
}>(),
|
||||
{
|
||||
allowAdmin: true
|
||||
}
|
||||
)
|
||||
|
||||
const roles = computed(() =>
|
||||
Object.values(Roles.Server)
|
||||
.filter((r) => {
|
||||
if (r === Roles.Server.Admin) return props.allowAdmin
|
||||
if (r === Roles.Server.ArchivedUser) return !props.forInvite
|
||||
return true
|
||||
})
|
||||
.map((r) => ({
|
||||
text: RoleInfo.Server[r],
|
||||
value: r,
|
||||
disabled: r === Roles.Server.Guest && !props.allowGuest
|
||||
}))
|
||||
)
|
||||
|
||||
const finalRole = computed({
|
||||
get: () => props.role,
|
||||
set: (newVal) => {
|
||||
emit('update:role', newVal)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@@ -42,13 +42,14 @@
|
||||
<no-data-placeholder v-if="quickUser">
|
||||
<h2>Welcome {{ quickUser.name.split(' ')[0] }}!</h2>
|
||||
<p class="caption">
|
||||
Once you create a stream and start sending some data, your activity will
|
||||
show up here.
|
||||
Once you {{ isGuestUser ? 'join' : 'create' }} a stream and start sending
|
||||
some data, your activity will show up here.
|
||||
</p>
|
||||
|
||||
<template #actions>
|
||||
<v-list rounded class="transparent">
|
||||
<v-list-item
|
||||
v-if="!isGuestUser"
|
||||
link
|
||||
class="primary mb-4"
|
||||
dark
|
||||
@@ -83,6 +84,7 @@ import { useQuery } from '@vue/apollo-composable'
|
||||
import { computed } from 'vue'
|
||||
import { AppLocalStorage } from '@/utils/localStorage'
|
||||
import { SKIPPABLE_ACTION_TYPES } from '@/main/lib/feed/helpers/activityStream'
|
||||
import { isGuest } from '@/main/lib/core/helpers/users'
|
||||
|
||||
export default {
|
||||
name: 'FeedTimeline',
|
||||
@@ -174,12 +176,15 @@ export default {
|
||||
quickUser: activeUser {
|
||||
id
|
||||
name
|
||||
role
|
||||
}
|
||||
}
|
||||
`)
|
||||
const quickUser = computed(() => quickUserResult.value?.quickUser || null)
|
||||
const isGuestUser = computed(() => isGuest(quickUser.value))
|
||||
|
||||
return {
|
||||
isGuestUser,
|
||||
quickUser,
|
||||
groupedTimeline,
|
||||
timeline,
|
||||
|
||||
+18
-4
@@ -20,8 +20,8 @@
|
||||
</template>
|
||||
<v-list dense>
|
||||
<v-list-item
|
||||
v-for="(item, index) in roles.filter((r) => r.name !== user.role)"
|
||||
:key="index"
|
||||
v-for="item in availableRoles"
|
||||
:key="item.name"
|
||||
@click="$emit('update-user-role', { user, role: item })"
|
||||
>
|
||||
<v-list-item-action>
|
||||
@@ -41,9 +41,15 @@
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { StreamCollaboratorFieldsFragment, Role } from '@/graphql/generated/graphql'
|
||||
import { StreamCollaboratorFieldsFragment } from '@/graphql/generated/graphql'
|
||||
import { Roles } from '@speckle/shared'
|
||||
import Vue, { PropType } from 'vue'
|
||||
|
||||
type RoleItem = {
|
||||
name: string
|
||||
description: string
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'StreamCollaboratorRow',
|
||||
components: {
|
||||
@@ -54,8 +60,16 @@ export default Vue.extend({
|
||||
type: Object as PropType<StreamCollaboratorFieldsFragment>,
|
||||
required: true
|
||||
},
|
||||
roles: { type: Array as PropType<Role[]>, required: true },
|
||||
roles: { type: Array as PropType<RoleItem[]>, required: true },
|
||||
disabled: { type: Boolean, default: false }
|
||||
},
|
||||
computed: {
|
||||
availableRoles(): RoleItem[] {
|
||||
const baseRoles = this.roles.filter((r) => r.name !== this.user.role)
|
||||
if (this.user.serverRole !== Roles.Server.Guest) return baseRoles
|
||||
|
||||
return baseRoles.filter((r) => r.name !== Roles.Stream.Owner)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
+11
-6
@@ -49,7 +49,6 @@
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import {
|
||||
Role,
|
||||
StreamWithCollaboratorsQuery,
|
||||
StreamCollaborator
|
||||
} from '@/graphql/generated/graphql'
|
||||
@@ -57,8 +56,13 @@ import Vue, { PropType } from 'vue'
|
||||
import type { Get } from 'type-fest'
|
||||
import StreamCollaboratorRow from '@/main/components/stream/collaborators/StreamCollaboratorRow.vue'
|
||||
import SectionCard from '@/main/components/common/SectionCard.vue'
|
||||
import { Roles } from '@/helpers/mainConstants'
|
||||
import StreamPendingCollaboratorRow from '@/main/components/stream/collaborators/StreamPendingCollaboratorRow.vue'
|
||||
import { Roles } from '@speckle/shared'
|
||||
|
||||
type RoleItem = {
|
||||
name: string
|
||||
description: string
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'StreamRoleCollaborators',
|
||||
@@ -73,7 +77,7 @@ export default Vue.extend({
|
||||
required: true
|
||||
},
|
||||
roles: {
|
||||
type: Array as PropType<Role[]>,
|
||||
type: Array as PropType<RoleItem[]>,
|
||||
required: true
|
||||
},
|
||||
stream: {
|
||||
@@ -81,10 +85,11 @@ export default Vue.extend({
|
||||
NonNullable<Get<StreamWithCollaboratorsQuery, 'stream'>>
|
||||
>,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
disabledUpdates: Boolean
|
||||
},
|
||||
computed: {
|
||||
role(): Role {
|
||||
role(): RoleItem {
|
||||
const role = this.roles.find((r) => r.name === this.roleName)
|
||||
if (!role) {
|
||||
throw new Error('Invalid role name provided')
|
||||
@@ -93,7 +98,7 @@ export default Vue.extend({
|
||||
return role
|
||||
},
|
||||
disabled(): boolean {
|
||||
return this.stream.role !== Roles.Stream.Owner
|
||||
return this.stream.role !== Roles.Stream.Owner || this.disabledUpdates
|
||||
},
|
||||
collaborators(): StreamCollaborator[] {
|
||||
return this.stream.collaborators.filter((c) => c.role === this.roleName)
|
||||
|
||||
@@ -51,6 +51,15 @@
|
||||
:disabled="loading"
|
||||
label="message"
|
||||
/>
|
||||
<user-role-select
|
||||
v-if="allowServerRoleSelect && !user"
|
||||
class="mb-4"
|
||||
label="Select server role"
|
||||
for-invite
|
||||
:allow-admin="isAdmin"
|
||||
:allow-guest="isGuestMode"
|
||||
:role.sync="role"
|
||||
/>
|
||||
<v-card-actions>
|
||||
<v-btn block color="primary" type="submit" :disabled="loading">
|
||||
Send invite
|
||||
@@ -64,7 +73,7 @@
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { gql } from '@apollo/client/core'
|
||||
import Vue, { PropType } from 'vue'
|
||||
import { PropType, defineComponent } from 'vue'
|
||||
import { email, maxLength, noXss, required } from '@/main/lib/common/vuetify/validators'
|
||||
import { Nullable, Optional } from '@/helpers/typeHelpers'
|
||||
import { VFormInstance } from '@/helpers/vuetifyHelpers'
|
||||
@@ -73,13 +82,18 @@ import type { FetchResult } from '@apollo/client/core'
|
||||
import { UserSearchQuery } from '@/graphql/generated/graphql'
|
||||
import BasicUserInfoRow from '@/main/components/user/BasicUserInfoRow.vue'
|
||||
import { StreamEvents } from '@/main/lib/core/helpers/eventHubHelper'
|
||||
import { useActiveUser } from '@/main/lib/core/composables/activeUser'
|
||||
import UserRoleSelect from '@/main/components/common/UserRoleSelect.vue'
|
||||
import { useServerInfo } from '@/main/lib/core/composables/server'
|
||||
import { Roles } from '@speckle/shared'
|
||||
|
||||
type UserType = Get<UserSearchQuery, 'userSearch.items.0'>
|
||||
|
||||
export default Vue.extend({
|
||||
export default defineComponent({
|
||||
name: 'InviteDialog',
|
||||
components: {
|
||||
BasicUserInfoRow
|
||||
BasicUserInfoRow,
|
||||
UserRoleSelect
|
||||
},
|
||||
props: {
|
||||
streamId: {
|
||||
@@ -99,6 +113,11 @@ export default Vue.extend({
|
||||
default: false
|
||||
}
|
||||
},
|
||||
setup() {
|
||||
const { isAdmin } = useActiveUser()
|
||||
const { isGuestMode } = useServerInfo()
|
||||
return { isAdmin, isGuestMode }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
localEmail: null as Nullable<string>,
|
||||
@@ -107,6 +126,7 @@ export default Vue.extend({
|
||||
error: null as Nullable<string>,
|
||||
showError: false,
|
||||
loading: false,
|
||||
role: Roles.Server.User,
|
||||
validation: {
|
||||
emailRules: [required(), email()],
|
||||
messageRules: [
|
||||
@@ -117,6 +137,9 @@ export default Vue.extend({
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
allowServerRoleSelect() {
|
||||
return this.isAdmin || this.isGuestMode
|
||||
},
|
||||
isServerInvite(): boolean {
|
||||
return !this.streamId
|
||||
},
|
||||
@@ -165,7 +188,8 @@ export default Vue.extend({
|
||||
email: this.user ? null : this.localEmail,
|
||||
message: this.message,
|
||||
streamId: this.streamId,
|
||||
userId: this.user ? this.user.id : null
|
||||
userId: this.user ? this.user.id : null,
|
||||
serverRole: this.allowServerRoleSelect && this.role ? this.role : null
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -180,7 +204,8 @@ export default Vue.extend({
|
||||
variables: {
|
||||
input: {
|
||||
email: this.localEmail,
|
||||
message: this.message
|
||||
message: this.message,
|
||||
serverRole: this.isAdmin ? this.role : null
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -142,7 +142,7 @@
|
||||
:class="`${!$vuetify.theme.dark ? 'grey lighten-4' : 'grey darken-4'}`"
|
||||
>
|
||||
<v-toolbar
|
||||
v-if="stream.role === 'stream:owner'"
|
||||
v-if="stream.role === streamRoles.Owner"
|
||||
class="transparent"
|
||||
rounded
|
||||
flat
|
||||
@@ -176,7 +176,7 @@
|
||||
<v-toolbar
|
||||
v-tooltip="
|
||||
`${
|
||||
stream.role !== 'stream:owner'
|
||||
stream.role !== streamRoles.Owner
|
||||
? 'You do not have the right access level (' +
|
||||
stream.role +
|
||||
') to add collaborators.'
|
||||
@@ -207,7 +207,7 @@
|
||||
color="primary"
|
||||
text
|
||||
rounded
|
||||
:disabled="stream.role !== 'stream:owner'"
|
||||
:disabled="stream.role !== streamRoles.Owner"
|
||||
@click="goToStreamCollabs()"
|
||||
>
|
||||
Manage
|
||||
@@ -222,7 +222,7 @@
|
||||
v-if="!stream.isPublic"
|
||||
v-tooltip="
|
||||
`${
|
||||
stream.role !== 'stream:owner'
|
||||
stream.role !== streamRoles.Owner
|
||||
? 'You do not have the right access level (' +
|
||||
stream.role +
|
||||
') to invite people to this stream.'
|
||||
@@ -241,7 +241,7 @@
|
||||
color="primary"
|
||||
text
|
||||
rounded
|
||||
:disabled="stream.role !== 'stream:owner'"
|
||||
:disabled="stream.role !== streamRoles.Owner"
|
||||
@click="showStreamInviteDialog()"
|
||||
>
|
||||
Send Invite
|
||||
@@ -266,7 +266,7 @@ import {
|
||||
UpdateStreamSettingsDocument
|
||||
} from '@/graphql/generated/graphql'
|
||||
import { convertThrowIntoFetchResult } from '@/main/lib/common/apollo/helpers/apolloOperationHelper'
|
||||
import { Optional } from '@speckle/shared'
|
||||
import { Optional, Roles } from '@speckle/shared'
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
|
||||
/**
|
||||
@@ -355,7 +355,8 @@ export default {
|
||||
...options,
|
||||
url,
|
||||
iFrameUrl,
|
||||
resetUrlOptions
|
||||
resetUrlOptions,
|
||||
streamRoles: Roles.Stream
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import { MainUserDataDocument } from '@/graphql/generated/graphql'
|
||||
import { md5 } from '@speckle/shared'
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import { computed } from 'vue'
|
||||
import { isAdmin } from '@/main/lib/core/helpers/users'
|
||||
|
||||
/**
|
||||
* Get active user.
|
||||
* undefined - not yet resolved
|
||||
* null - resolved that user is a guest
|
||||
*/
|
||||
export function useActiveUser() {
|
||||
const { result, refetch, onResult } = useQuery(MainUserDataDocument)
|
||||
|
||||
const activeUser = computed(() =>
|
||||
result.value ? result.value.activeUser : undefined
|
||||
)
|
||||
const isLoggedIn = computed(() => !!activeUser.value?.id)
|
||||
const distinctId = computed(() => {
|
||||
const user = activeUser.value
|
||||
if (!user) return user // null or undefined
|
||||
if (!user.email) return null
|
||||
|
||||
return '@' + md5(user.email.toLowerCase()).toUpperCase()
|
||||
})
|
||||
|
||||
const isAdminUser = computed(() => isAdmin(activeUser.value))
|
||||
|
||||
return { activeUser, isLoggedIn, distinctId, refetch, onResult, isAdmin: isAdminUser }
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { MainServerInfoDocument } from '@/graphql/generated/graphql'
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import { computed } from 'vue'
|
||||
|
||||
export function useServerInfo() {
|
||||
const { result } = useQuery(MainServerInfoDocument)
|
||||
|
||||
const serverInfo = computed(() => result.value?.serverInfo)
|
||||
const isGuestMode = computed(() => !!serverInfo.value?.guestModeEnabled)
|
||||
|
||||
return { serverInfo, isGuestMode }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { Nullable, Roles } from '@speckle/shared'
|
||||
|
||||
export function isGuest(user?: { role?: string }) {
|
||||
return user?.role === Roles.Server.Guest
|
||||
}
|
||||
|
||||
export function isAdmin(user?: Nullable<{ role?: Nullable<string> }>) {
|
||||
return user?.role === Roles.Server.Admin
|
||||
}
|
||||
@@ -9,7 +9,12 @@
|
||||
<portal-target name="nav">
|
||||
<!-- Main Actions -->
|
||||
<v-list v-if="true" dense nav class="mb-0 pb-0">
|
||||
<v-list-item class="primary elevation-5" dark @click="newStreamDialog = true">
|
||||
<v-list-item
|
||||
v-if="!isUserGuest"
|
||||
class="primary elevation-5"
|
||||
dark
|
||||
@click="showNewStreamDialog = true"
|
||||
>
|
||||
<v-list-item-icon>
|
||||
<v-icon class="">mdi-folder-plus</v-icon>
|
||||
</v-list-item-icon>
|
||||
@@ -17,7 +22,7 @@
|
||||
<v-list-item-title>New Stream</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-list-item @click="inviteUsersDialog = true">
|
||||
<v-list-item v-if="!isUserGuest" @click="showInviteUsersDialog = true">
|
||||
<v-list-item-icon>
|
||||
<v-icon class="">mdi-email</v-icon>
|
||||
</v-list-item-icon>
|
||||
@@ -83,7 +88,12 @@
|
||||
</v-list-item>
|
||||
<portal-target name="subnav-commits" />
|
||||
|
||||
<v-list-item v-if="user && user.role === 'server:admin'" exact link to="/admin">
|
||||
<v-list-item
|
||||
v-if="user && user.role === serverRoles.Admin"
|
||||
exact
|
||||
link
|
||||
to="/admin"
|
||||
>
|
||||
<v-list-item-icon>
|
||||
<v-icon class="mt-2">mdi-cog-outline</v-icon>
|
||||
</v-list-item-icon>
|
||||
@@ -119,20 +129,25 @@
|
||||
|
||||
<!-- Dialogs -->
|
||||
<v-dialog
|
||||
v-model="newStreamDialog"
|
||||
v-model="showNewStreamDialog"
|
||||
max-width="500"
|
||||
:fullscreen="$vuetify.breakpoint.xsOnly"
|
||||
>
|
||||
<new-stream @created="newStreamDialog = false" @close="newStreamDialog = false" />
|
||||
<new-stream
|
||||
@created="showNewStreamDialog = false"
|
||||
@close="showNewStreamDialog = false"
|
||||
/>
|
||||
</v-dialog>
|
||||
|
||||
<invite-dialog :visible.sync="inviteUsersDialog" />
|
||||
<invite-dialog :visible.sync="showInviteUsersDialog" />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { mainUserDataQuery } from '@/graphql/user'
|
||||
import InviteDialog from '@/main/dialogs/InviteDialog.vue'
|
||||
import { setDarkTheme } from '@/main/utils/themeStateManager'
|
||||
import { Roles } from '@speckle/shared'
|
||||
import { isGuest } from '@/main/lib/core/helpers/users'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -158,7 +173,31 @@ export default {
|
||||
return {
|
||||
newStreamDialog: false,
|
||||
inviteUsersDialog: false,
|
||||
shadowSpeckle: false
|
||||
shadowSpeckle: false,
|
||||
serverRoles: Roles.Server
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isUserGuest() {
|
||||
return isGuest(this.user)
|
||||
},
|
||||
showNewStreamDialog: {
|
||||
get() {
|
||||
return this.newStreamDialog
|
||||
},
|
||||
set(val) {
|
||||
if (this.isUserGuest) return
|
||||
this.newStreamDialog = val
|
||||
}
|
||||
},
|
||||
showInviteUsersDialog: {
|
||||
get() {
|
||||
return this.inviteUsersDialog
|
||||
},
|
||||
set(val) {
|
||||
if (this.isUserGuest) return
|
||||
this.inviteUsersDialog = val
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@@ -169,7 +208,10 @@ export default {
|
||||
if (navContent.scrollTop > 50) this.shadowSpeckle = true
|
||||
else this.shadowSpeckle = false
|
||||
})
|
||||
this.$eventHub.$on('show-new-stream-dialog', () => (this.newStreamDialog = true))
|
||||
this.$eventHub.$on(
|
||||
'show-new-stream-dialog',
|
||||
() => (this.showNewStreamDialog = true)
|
||||
)
|
||||
},
|
||||
methods: {
|
||||
switchTheme() {
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<span v-else class="font-italic">No description provided</span>
|
||||
</div>
|
||||
<router-link
|
||||
v-if="stream.role === 'stream:owner'"
|
||||
v-if="stream.role === streamRoles.Owner"
|
||||
:to="`/streams/${$route.params.streamId}/settings`"
|
||||
class="text-decoration-none"
|
||||
>
|
||||
@@ -55,7 +55,7 @@
|
||||
</template>
|
||||
<!-- <v-divider class="mb-1"></v-divider> -->
|
||||
<v-list-item
|
||||
v-if="stream.role !== 'stream:reviewer'"
|
||||
v-if="stream.role !== streamRoles.Reviewer"
|
||||
v-tooltip.bottom="'Create a new branch to help categorise your commits.'"
|
||||
link
|
||||
@click="newBranchDialog = true"
|
||||
@@ -226,6 +226,7 @@ import {
|
||||
import { StreamEvents } from '@/main/lib/core/helpers/eventHubHelper'
|
||||
import { useRoute } from '@/main/lib/core/composables/router'
|
||||
import { useAllStreamBranches } from '@/main/lib/stream/composables/branches'
|
||||
import { Roles } from '@speckle/shared'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -247,7 +248,8 @@ export default {
|
||||
localBranches,
|
||||
refetchBranches,
|
||||
totalBranchCount,
|
||||
loading: branchesLoading
|
||||
loading: branchesLoading,
|
||||
streamRoles: Roles.Stream
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
||||
@@ -48,12 +48,13 @@
|
||||
<no-data-placeholder v-if="user && user.commits.totalCount === 0">
|
||||
<h2>Welcome {{ user.name.split(' ')[0] }}!</h2>
|
||||
<p class="caption">
|
||||
Once you create a stream and start sending some data, your activity will show up
|
||||
here.
|
||||
Once you {{ isGuestUser ? 'join' : 'create' }} a stream and start sending some
|
||||
data, your activity will show up here.
|
||||
</p>
|
||||
<template #actions>
|
||||
<v-list rounded class="transparent">
|
||||
<v-list-item
|
||||
v-if="!isGuestUser"
|
||||
link
|
||||
class="primary mb-4"
|
||||
dark
|
||||
@@ -96,6 +97,7 @@ import {
|
||||
deleteCommitsFromCachedCommitsQuery,
|
||||
disabledCheckboxMessage
|
||||
} from '@/main/lib/stream/services/commitMultiActions'
|
||||
import { isGuest } from '@/main/lib/core/helpers/users'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TheCommits',
|
||||
@@ -113,6 +115,7 @@ export default defineComponent({
|
||||
activeUser {
|
||||
id
|
||||
name
|
||||
role
|
||||
commits(limit: 10, cursor: $cursor) {
|
||||
totalCount
|
||||
cursor
|
||||
@@ -186,8 +189,10 @@ export default defineComponent({
|
||||
})
|
||||
const shareDialogCommitId = computed(() => shareDialogCommit.value?.id)
|
||||
const shareDialogStreamId = computed(() => shareDialogCommit.value?.stream.id)
|
||||
const isGuestUser = computed(() => isGuest(user.value))
|
||||
|
||||
return {
|
||||
isGuestUser,
|
||||
user,
|
||||
commitItems,
|
||||
totalCommitCount,
|
||||
|
||||
@@ -20,12 +20,13 @@
|
||||
<no-data-placeholder v-if="user">
|
||||
<h2>Welcome {{ user.name.split(' ')[0] }}!</h2>
|
||||
<p class="caption">
|
||||
Once you create a stream and start sending some data, your activity will show
|
||||
up here.
|
||||
Once you {{ isGuestUser ? 'join' : 'create' }} a stream and start sending some
|
||||
data, your activity will show up here.
|
||||
</p>
|
||||
<template #actions>
|
||||
<v-list rounded class="transparent">
|
||||
<v-list-item
|
||||
v-if="!isGuestUser"
|
||||
link
|
||||
class="primary mb-4"
|
||||
dark
|
||||
@@ -94,6 +95,8 @@ import StreamPreviewCard from '@/main/components/common/StreamPreviewCard.vue'
|
||||
import NoDataPlaceholder from '@/main/components/common/NoDataPlaceholder.vue'
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import { computed } from 'vue'
|
||||
import { Roles } from '@speckle/shared'
|
||||
import { isGuest } from '@/main/lib/core/helpers/users'
|
||||
|
||||
export default {
|
||||
name: 'TheStreams',
|
||||
@@ -129,19 +132,23 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
streamFilter: 1,
|
||||
infiniteId: 0
|
||||
infiniteId: 0,
|
||||
streamRoles: Roles.Stream
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isGuestUser() {
|
||||
return isGuest(this.user)
|
||||
},
|
||||
filteredStreams() {
|
||||
if (!this.streams) return []
|
||||
if (this.streamFilter === 1) return this.streams.items
|
||||
if (this.streamFilter === 2)
|
||||
return this.streams.items.filter((s) => s.role === 'stream:owner')
|
||||
return this.streams.items.filter((s) => s.role === this.streamRoles.Owner)
|
||||
if (this.streamFilter === 3)
|
||||
return this.streams.items.filter((s) => s.role === 'stream:contributor')
|
||||
return this.streams.items.filter((s) => s.role === this.streamRoles.Contributor)
|
||||
if (this.streamFilter === 4)
|
||||
return this.streams.items.filter((s) => s.role === 'stream:reviewer')
|
||||
return this.streams.items.filter((s) => s.role === this.streamRoles.Reviewer)
|
||||
return this.streams.items
|
||||
},
|
||||
/**
|
||||
@@ -169,9 +176,9 @@ export default {
|
||||
},
|
||||
checkFilter(role) {
|
||||
if (this.streamFilter === 1) return true
|
||||
if (this.streamFilter === 2 && role === 'stream:owner') return true
|
||||
if (this.streamFilter === 3 && role === 'stream:contributor') return true
|
||||
if (this.streamFilter === 4 && role === 'stream:reviewer') return true
|
||||
if (this.streamFilter === 2 && role === this.streamRoles.Owner) return true
|
||||
if (this.streamFilter === 3 && role === this.streamRoles.Contributor) return true
|
||||
if (this.streamFilter === 4 && role === this.streamRoles.Reviewer) return true
|
||||
return false
|
||||
},
|
||||
async infiniteHandler($state) {
|
||||
|
||||
@@ -18,13 +18,13 @@
|
||||
</error-placeholder>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { gql } from '@apollo/client/core'
|
||||
import {
|
||||
STANDARD_PORTAL_KEYS,
|
||||
buildPortalStateMixin
|
||||
} from '@/main/utils/portalStateManager'
|
||||
import { Roles } from '@speckle/shared'
|
||||
|
||||
export default {
|
||||
name: 'AdminPanel',
|
||||
@@ -54,7 +54,7 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
isAdmin() {
|
||||
return this.user?.role === 'server:admin'
|
||||
return this.user?.role === Roles.Server.Admin
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,13 @@
|
||||
</v-chip>
|
||||
</template>
|
||||
</v-combobox>
|
||||
<user-role-select
|
||||
class="mb-4"
|
||||
label="Select server role"
|
||||
for-invite
|
||||
:allow-guest="isGuestMode"
|
||||
:role.sync="role"
|
||||
/>
|
||||
<p v-if="!selectedStream">Optionally invite users to stream.</p>
|
||||
<stream-search-bar
|
||||
v-if="!selectedStream"
|
||||
@@ -87,7 +94,6 @@
|
||||
</section-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { gql } from '@apollo/client/core'
|
||||
import { isEmailValid } from '@/plugins/authHelpers'
|
||||
@@ -102,12 +108,15 @@ import {
|
||||
BatchInviteToServerDocument
|
||||
} from '@/graphql/generated/graphql'
|
||||
import { convertThrowIntoFetchResult } from '@/main/lib/common/apollo/helpers/apolloOperationHelper'
|
||||
import { Roles } from '@speckle/shared'
|
||||
import UserRoleSelect from '@/main/components/common/UserRoleSelect.vue'
|
||||
|
||||
export default {
|
||||
name: 'AdminInvites',
|
||||
components: {
|
||||
SectionCard: () => import('@/main/components/common/SectionCard'),
|
||||
StreamSearchBar: () => import('@/main/components/common/SearchBar')
|
||||
StreamSearchBar: () => import('@/main/components/common/SearchBar'),
|
||||
UserRoleSelect
|
||||
},
|
||||
mixins: [buildPortalStateMixin([STANDARD_PORTAL_KEYS.Toolbar], 'admin-invites', 1)],
|
||||
data() {
|
||||
@@ -123,6 +132,7 @@ export default {
|
||||
chips: [],
|
||||
inputErrors: [],
|
||||
selectedStream: null,
|
||||
role: Roles.Server.User,
|
||||
validation: {
|
||||
messageRules: [
|
||||
maxLength(1024, "Message can't be longer than 1024 characters"),
|
||||
@@ -134,6 +144,9 @@ export default {
|
||||
computed: {
|
||||
submitable() {
|
||||
return this.chips && this.chips.length !== 0
|
||||
},
|
||||
isGuestMode() {
|
||||
return !!this.serverInfo?.guestModeEnabled
|
||||
}
|
||||
},
|
||||
apollo: {
|
||||
@@ -199,11 +212,13 @@ export default {
|
||||
? targetEmails.map((e) => ({
|
||||
email: e,
|
||||
streamId,
|
||||
message
|
||||
message,
|
||||
serverRole: this.role
|
||||
}))
|
||||
: targetEmails.map((e) => ({
|
||||
email: e,
|
||||
message
|
||||
message,
|
||||
serverRole: this.role
|
||||
}))
|
||||
|
||||
try {
|
||||
|
||||
@@ -88,6 +88,11 @@ export default {
|
||||
label: 'Invite-Only mode',
|
||||
hint: 'Only users with an invitation will be able to join',
|
||||
type: 'boolean'
|
||||
},
|
||||
guestModeEnabled: {
|
||||
label: 'Guest mode',
|
||||
hint: "Enable the 'Guest' server role, which allows users to only contribute to streams that they're invited to",
|
||||
type: 'boolean'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,6 +111,7 @@ export default {
|
||||
methods: {
|
||||
async saveEdit() {
|
||||
this.loading = true
|
||||
const changes = pick(this.serverModifications, Object.keys(this.serverDetails))
|
||||
await this.$apollo.mutate({
|
||||
mutation: gql`
|
||||
mutation ($info: ServerInfoUpdateInput!) {
|
||||
@@ -113,10 +119,21 @@ export default {
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
info: pick(this.serverModifications, Object.keys(this.serverDetails))
|
||||
info: changes
|
||||
},
|
||||
update: (cache) => {
|
||||
cache.writeQuery({
|
||||
query: mainServerInfoQuery,
|
||||
data: {
|
||||
serverInfo: {
|
||||
...this.serverInfo,
|
||||
...changes
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
await this.$apollo.queries['serverInfo'].refetch()
|
||||
// await this.$apollo.queries['serverInfo'].refetch()
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<div v-for="item in adminUsers.items" :key="item.id">
|
||||
<users-list-item
|
||||
:item="item"
|
||||
:roles="availableRoles"
|
||||
:allow-guest="serverInfo?.guestModeEnabled"
|
||||
@user-change-role="changeUserRole"
|
||||
@user-delete="initiateDeleteUser"
|
||||
@invite-delete="deleteInvite"
|
||||
@@ -111,11 +111,12 @@ import {
|
||||
import {
|
||||
DeleteInviteDocument,
|
||||
ResendInviteDocument,
|
||||
AdminUsersListDocument
|
||||
AdminUsersListDocument,
|
||||
AvailableServerRolesDocument
|
||||
} from '@/graphql/generated/graphql'
|
||||
import SectionCard from '@/main/components/common/SectionCard.vue'
|
||||
import UsersListItem from '@/main/components/admin/UsersListItem.vue'
|
||||
import { Roles } from '@/helpers/mainConstants'
|
||||
import { RoleInfo } from '@speckle/shared'
|
||||
import { convertThrowIntoFetchResult } from '@/main/lib/common/apollo/helpers/apolloOperationHelper'
|
||||
|
||||
// TODO: This needs a redesign, it's pretty unusable on small screens
|
||||
@@ -140,12 +141,7 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
roleLookupTable: {
|
||||
[Roles.Server.User]: 'User',
|
||||
[Roles.Server.Admin]: 'Admin',
|
||||
[Roles.Server.ArchivedUser]: 'Archived',
|
||||
[Roles.Server.Guest]: 'Guest'
|
||||
},
|
||||
roleLookupTable: RoleInfo.Server,
|
||||
adminUsers: {
|
||||
items: [],
|
||||
totalCount: 0
|
||||
@@ -181,13 +177,6 @@ export default {
|
||||
},
|
||||
numberOfPages() {
|
||||
return Math.ceil(this.adminUsers.totalCount / this.limit)
|
||||
},
|
||||
availableRoles() {
|
||||
const roleItems = []
|
||||
for (const role in this.roleLookupTable) {
|
||||
roleItems.push({ text: this.roleLookupTable[role], value: role })
|
||||
}
|
||||
return roleItems
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -328,6 +317,9 @@ export default {
|
||||
query: this.q
|
||||
}
|
||||
}
|
||||
},
|
||||
serverInfo: {
|
||||
query: AvailableServerRolesDocument
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<v-col v-if="serverInfo && stream" cols="12">
|
||||
<v-row>
|
||||
<!-- Add contributors panel -->
|
||||
<v-col v-if="isStreamOwner" cols="12">
|
||||
<v-col v-if="canEditCollaborators" cols="12">
|
||||
<section-card :elevation="4">
|
||||
<v-progress-linear v-show="loading" indeterminate></v-progress-linear>
|
||||
<template slot="header">
|
||||
@@ -66,17 +66,18 @@
|
||||
</template>
|
||||
|
||||
<!-- Users found -->
|
||||
<basic-user-info-row
|
||||
v-for="user in filteredSearchResults"
|
||||
v-else
|
||||
:key="user.id"
|
||||
:user="user"
|
||||
@click="showUserInviteDialog(user)"
|
||||
>
|
||||
<template #actions>
|
||||
<v-btn color="primary">Invite</v-btn>
|
||||
</template>
|
||||
</basic-user-info-row>
|
||||
<template v-else>
|
||||
<basic-user-info-row
|
||||
v-for="user in filteredSearchResults"
|
||||
:key="user.id"
|
||||
:user="user"
|
||||
@click="showUserInviteDialog(user)"
|
||||
>
|
||||
<template #actions>
|
||||
<v-btn color="primary">Invite</v-btn>
|
||||
</template>
|
||||
</basic-user-info-row>
|
||||
</template>
|
||||
</v-list>
|
||||
</v-card-text>
|
||||
<invite-dialog
|
||||
@@ -90,7 +91,7 @@
|
||||
</v-col>
|
||||
|
||||
<!-- No permissions warning -->
|
||||
<v-col v-if="stream.role !== 'stream:owner'" cols="12">
|
||||
<v-col v-if="!isStreamOwner" cols="12">
|
||||
<v-alert type="warning" class="mb-0">
|
||||
Your permission level ({{ stream.role ? stream.role : 'none' }}) is not
|
||||
high enough to edit this stream's collaborators.
|
||||
@@ -100,7 +101,9 @@
|
||||
<!-- Stream access requests -->
|
||||
<v-col
|
||||
v-if="
|
||||
isStreamOwner && pendingAccessRequests && pendingAccessRequests.length
|
||||
canEditCollaborators &&
|
||||
pendingAccessRequests &&
|
||||
pendingAccessRequests.length
|
||||
"
|
||||
cols="12"
|
||||
>
|
||||
@@ -117,6 +120,7 @@
|
||||
:role-name="role.name"
|
||||
:roles="roles"
|
||||
:stream="stream"
|
||||
:disabled-updates="!canEditCollaborators"
|
||||
@update-user-role="setUserPermissions"
|
||||
@remove-user="removeUser"
|
||||
@cancel-invite="cancelInvite"
|
||||
@@ -154,13 +158,14 @@ import {
|
||||
UpdateStreamPermissionDocument
|
||||
} from '@/graphql/generated/graphql'
|
||||
import { StreamEvents } from '@/main/lib/core/helpers/eventHubHelper'
|
||||
import { Roles } from '@/helpers/mainConstants'
|
||||
import { Roles, RoleInfo } from '@speckle/shared'
|
||||
import LeaveStreamPanel from '@/main/components/stream/collaborators/LeaveStreamPanel.vue'
|
||||
import { IsLoggedInMixin } from '@/main/lib/core/mixins/isLoggedInMixin'
|
||||
import { vueWithMixins } from '@/helpers/typeHelpers'
|
||||
import { convertThrowIntoFetchResult } from '@/main/lib/common/apollo/helpers/apolloOperationHelper'
|
||||
import { AppLocalStorage } from '@/utils/localStorage'
|
||||
import StreamAccessRequestBanner from '@/main/components/stream/StreamAccessRequestBanner.vue'
|
||||
import { MainUserDataDocument } from '@/graphql/generated/graphql'
|
||||
|
||||
export default vueWithMixins(IsLoggedInMixin).extend({
|
||||
// @vue/component
|
||||
@@ -221,6 +226,9 @@ export default vueWithMixins(IsLoggedInMixin).extend({
|
||||
serverInfo: {
|
||||
prefetch: true,
|
||||
query: fullServerInfoQuery
|
||||
},
|
||||
activeUser: {
|
||||
query: MainUserDataDocument
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -231,29 +239,23 @@ export default vueWithMixins(IsLoggedInMixin).extend({
|
||||
|
||||
return true
|
||||
},
|
||||
canEditCollaborators() {
|
||||
return this.isStreamOwner && !this.isServerGuest
|
||||
},
|
||||
isStreamOwner() {
|
||||
return this.stream?.role === Roles.Stream.Owner
|
||||
},
|
||||
isServerGuest() {
|
||||
return this.activeUser?.role === Roles.Server.Guest
|
||||
},
|
||||
streamId() {
|
||||
return this.$route.params.streamId
|
||||
},
|
||||
roles() {
|
||||
if (this.serverInfo.roles.length === 0) return []
|
||||
const temp = this.serverInfo.roles.filter((x) => x.resourceTarget === 'streams')
|
||||
const ret = [null, null, null]
|
||||
// World's most idiotic way of enforcing order
|
||||
for (const role of temp) {
|
||||
if (role.name === 'stream:owner') {
|
||||
ret[0] = role
|
||||
} else if (role.name === 'stream:contributor') {
|
||||
ret[1] = role
|
||||
} else if (role.name === 'stream:reviewer') {
|
||||
ret[2] = role
|
||||
} else {
|
||||
ret.push(role)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
return Object.values(Roles.Stream).map((r) => ({
|
||||
name: r,
|
||||
description: RoleInfo.Stream[r].description
|
||||
}))
|
||||
},
|
||||
collaborators() {
|
||||
if (!this.stream) return []
|
||||
@@ -261,15 +263,17 @@ export default vueWithMixins(IsLoggedInMixin).extend({
|
||||
},
|
||||
reviewers() {
|
||||
if (!this.stream) return []
|
||||
return this.stream.collaborators.filter((u) => u.role === 'stream:reviewer')
|
||||
return this.stream.collaborators.filter((u) => u.role === Roles.Stream.Reviewer)
|
||||
},
|
||||
contributors() {
|
||||
if (!this.stream) return []
|
||||
return this.stream.collaborators.filter((u) => u.role === 'stream:contributor')
|
||||
return this.stream.collaborators.filter(
|
||||
(u) => u.role === Roles.Stream.Contributor
|
||||
)
|
||||
},
|
||||
owners() {
|
||||
if (!this.stream) return []
|
||||
return this.stream.collaborators.filter((u) => u.role === 'stream:owner')
|
||||
return this.stream.collaborators.filter((u) => u.role === Roles.Stream.Owner)
|
||||
},
|
||||
pendingAccessRequests() {
|
||||
return this.stream?.pendingAccessRequests
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<template #header><b>Authorized Apps</b></template>
|
||||
<user-authorised-apps />
|
||||
</section-card>
|
||||
<section-card expandable class="mt-6 mb-10">
|
||||
<section-card v-if="!isGuestUser" expandable class="mt-6 mb-10">
|
||||
<template #header><b>Developer Settings</b></template>
|
||||
<v-alert type="info" color="primary" dense class="my-2 mx-4">
|
||||
Heads up! The sections below are intended for developers.
|
||||
@@ -50,6 +50,7 @@ import {
|
||||
buildPortalStateMixin
|
||||
} from '@/main/utils/portalStateManager'
|
||||
import UserNotificationPreferences from '@/main/components/user/UserNotificationPreferences'
|
||||
import { isGuest } from '@/main/lib/core/helpers/users'
|
||||
|
||||
export default {
|
||||
name: 'TheProfileSelf',
|
||||
@@ -71,6 +72,11 @@ export default {
|
||||
update: (data) => data.activeUser
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isGuestUser() {
|
||||
return isGuest(this.user)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.$apollo.queries.user.refetch()
|
||||
|
||||
@@ -54,6 +54,10 @@ input ProjectInviteCreateInput {
|
||||
Defaults to the contributor role, if not specified
|
||||
"""
|
||||
role: String
|
||||
"""
|
||||
Can only be specified if guest mode is on or if the user is an admin
|
||||
"""
|
||||
serverRole: String
|
||||
}
|
||||
|
||||
input ProjectInviteUseInput {
|
||||
@@ -68,11 +72,13 @@ type ProjectInviteMutations {
|
||||
"""
|
||||
create(projectId: ID!, input: ProjectInviteCreateInput!): Project!
|
||||
@hasScope(scope: "users:invite")
|
||||
@hasServerRole(role: SERVER_USER)
|
||||
"""
|
||||
Batch invite to project
|
||||
"""
|
||||
batchCreate(projectId: ID!, input: [ProjectInviteCreateInput!]!): Project!
|
||||
@hasScope(scope: "users:invite")
|
||||
@hasServerRole(role: SERVER_USER)
|
||||
|
||||
"""
|
||||
Accept or decline a project invite
|
||||
@@ -82,29 +88,32 @@ type ProjectInviteMutations {
|
||||
"""
|
||||
Cancel a pending stream invite. Can only be invoked by a project owner.
|
||||
"""
|
||||
cancel(projectId: ID!, inviteId: String!): Project! @hasScope(scope: "users:invite")
|
||||
cancel(projectId: ID!, inviteId: String!): Project!
|
||||
@hasScope(scope: "users:invite")
|
||||
@hasServerRole(role: SERVER_USER)
|
||||
}
|
||||
|
||||
type ProjectMutations {
|
||||
"""
|
||||
Delete an existing project
|
||||
"""
|
||||
delete(id: String!): Boolean!
|
||||
delete(id: String!): Boolean! @hasServerRole(role: SERVER_USER)
|
||||
|
||||
"""
|
||||
Updates an existing project
|
||||
"""
|
||||
update(update: ProjectUpdateInput!): Project!
|
||||
update(update: ProjectUpdateInput!): Project! @hasServerRole(role: SERVER_USER)
|
||||
|
||||
"""
|
||||
Create onboarding/tutorial project
|
||||
Create onboarding/tutorial project. If one is already created for the active user, that
|
||||
one will be returned instead.
|
||||
"""
|
||||
createForOnboarding: Project!
|
||||
|
||||
"""
|
||||
Create new project
|
||||
"""
|
||||
create(input: ProjectCreateInput): Project!
|
||||
create(input: ProjectCreateInput): Project! @hasServerRole(role: SERVER_USER)
|
||||
|
||||
"""
|
||||
Invite related mutations
|
||||
@@ -114,7 +123,7 @@ type ProjectMutations {
|
||||
"""
|
||||
Update role for a collaborator
|
||||
"""
|
||||
updateRole(input: ProjectUpdateRoleInput!): Project!
|
||||
updateRole(input: ProjectUpdateRoleInput!): Project! @hasServerRole(role: SERVER_USER)
|
||||
|
||||
"""
|
||||
Leave a project. Only possible if you're not the last remaining owner.
|
||||
@@ -124,7 +133,7 @@ type ProjectMutations {
|
||||
|
||||
extend type Mutation {
|
||||
projectMutations: ProjectMutations!
|
||||
@hasServerRole(role: SERVER_USER)
|
||||
@hasServerRole(role: SERVER_GUEST)
|
||||
@hasScope(scope: "streams:write")
|
||||
}
|
||||
|
||||
@@ -241,7 +250,7 @@ extend type User {
|
||||
Get all invitations to projects that the active user has
|
||||
"""
|
||||
projectInvites: [PendingStreamCollaborator!]!
|
||||
@hasServerRole(role: SERVER_USER)
|
||||
@hasServerRole(role: SERVER_GUEST)
|
||||
@hasScope(scope: "streams:read")
|
||||
@isOwner
|
||||
}
|
||||
|
||||
@@ -12,22 +12,28 @@ type ServerInfo {
|
||||
adminContact: String
|
||||
canonicalUrl: String
|
||||
termsOfService: String
|
||||
roles: [Role]!
|
||||
scopes: [Scope]!
|
||||
roles: [Role!]!
|
||||
@deprecated(
|
||||
reason: "Use role constants from the @speckle/shared npm package instead"
|
||||
)
|
||||
scopes: [Scope!]!
|
||||
inviteOnly: Boolean
|
||||
guestModeEnabled: Boolean!
|
||||
version: String
|
||||
serverRoles: [ServerRoleItem!]!
|
||||
}
|
||||
|
||||
"""
|
||||
Available roles.
|
||||
"""
|
||||
type Role {
|
||||
name: String!
|
||||
description: String!
|
||||
resourceTarget: String!
|
||||
}
|
||||
|
||||
type ServerRoleItem {
|
||||
id: String!
|
||||
title: String!
|
||||
}
|
||||
|
||||
"""
|
||||
Available scopes.
|
||||
"""
|
||||
|
||||
@@ -116,6 +116,7 @@ type StreamCollaborator {
|
||||
role: String!
|
||||
company: String
|
||||
avatar: String
|
||||
serverRole: String!
|
||||
}
|
||||
|
||||
type PendingStreamCollaborator {
|
||||
|
||||
@@ -79,6 +79,10 @@ type ServerInvite {
|
||||
input ServerInviteCreateInput {
|
||||
email: String!
|
||||
message: String
|
||||
"""
|
||||
Can only be specified if guest mode is on or if the user is an admin
|
||||
"""
|
||||
serverRole: String
|
||||
}
|
||||
|
||||
input StreamInviteCreateInput {
|
||||
@@ -90,4 +94,8 @@ input StreamInviteCreateInput {
|
||||
Defaults to the contributor role, if not specified
|
||||
"""
|
||||
role: String
|
||||
"""
|
||||
Can only be specified if guest mode is on or if the user is an admin
|
||||
"""
|
||||
serverRole: String
|
||||
}
|
||||
|
||||
@@ -126,26 +126,45 @@ export async function addStreamDeletedActivity(params: {
|
||||
export async function addStreamClonedActivity(
|
||||
params: {
|
||||
sourceStreamId: string
|
||||
newStreamId: string
|
||||
newStream: StreamRecord
|
||||
clonerId: string
|
||||
},
|
||||
options?: Partial<{ trx: Knex.Transaction }>
|
||||
) {
|
||||
const { trx } = options || {}
|
||||
const { sourceStreamId, newStreamId, clonerId } = params
|
||||
const { sourceStreamId, newStream, clonerId } = params
|
||||
const newStreamId = newStream.id
|
||||
|
||||
await saveActivity(
|
||||
{
|
||||
streamId: newStreamId,
|
||||
resourceType: ResourceTypes.Stream,
|
||||
resourceId: newStreamId,
|
||||
actionType: ActionTypes.Stream.Clone,
|
||||
userId: clonerId,
|
||||
info: { sourceStreamId, newStreamId, clonerId },
|
||||
message: `User ${clonerId} cloned stream ${sourceStreamId} as ${newStreamId}`
|
||||
},
|
||||
{ trx }
|
||||
)
|
||||
const publishSubscriptions = async () =>
|
||||
publish(UserSubscriptions.UserProjectsUpdated, {
|
||||
userProjectsUpdated: {
|
||||
id: newStreamId,
|
||||
type: UserProjectsUpdatedMessageType.Added,
|
||||
project: newStream
|
||||
},
|
||||
ownerId: clonerId
|
||||
})
|
||||
|
||||
await Promise.all([
|
||||
saveActivity(
|
||||
{
|
||||
streamId: newStreamId,
|
||||
resourceType: ResourceTypes.Stream,
|
||||
resourceId: newStreamId,
|
||||
actionType: ActionTypes.Stream.Clone,
|
||||
userId: clonerId,
|
||||
info: { sourceStreamId, newStreamId, clonerId },
|
||||
message: `User ${clonerId} cloned stream ${sourceStreamId} as ${newStreamId}`
|
||||
},
|
||||
{ trx }
|
||||
),
|
||||
!trx ? publishSubscriptions() : null
|
||||
])
|
||||
|
||||
if (trx) {
|
||||
// can't await this, cause it'll block everything
|
||||
void trx.executionPromise.then(publishSubscriptions)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -107,7 +107,13 @@ module.exports = async (app, session, sessionStorage, finalizeAuth) => {
|
||||
const validInvite = await validateServerInvite(user.email, req.session.token)
|
||||
|
||||
// create the user
|
||||
const myUser = await findOrCreateUser({ user, rawProfile: req.user._json })
|
||||
const myUser = await findOrCreateUser({
|
||||
user: {
|
||||
...user,
|
||||
role: validInvite?.serverRole
|
||||
},
|
||||
rawProfile: req.user._json
|
||||
})
|
||||
|
||||
// ID is used later for verifying access token
|
||||
req.user.id = myUser.id
|
||||
|
||||
@@ -84,7 +84,13 @@ module.exports = async (app, session, sessionStorage, finalizeAuth) => {
|
||||
const validInvite = await validateServerInvite(user.email, req.session.token)
|
||||
|
||||
// create the user
|
||||
const myUser = await findOrCreateUser({ user, rawProfile: profile._raw })
|
||||
const myUser = await findOrCreateUser({
|
||||
user: {
|
||||
...user,
|
||||
role: validInvite?.serverRole
|
||||
},
|
||||
rawProfile: profile._raw
|
||||
})
|
||||
|
||||
// use the invite
|
||||
await finalizeInvitedServerRegistration(user.email, myUser.id)
|
||||
|
||||
@@ -78,7 +78,13 @@ module.exports = async (app, session, sessionStorage, finalizeAuth) => {
|
||||
const validInvite = await validateServerInvite(user.email, req.session.token)
|
||||
|
||||
// create the user
|
||||
const myUser = await findOrCreateUser({ user, rawProfile: profile._raw })
|
||||
const myUser = await findOrCreateUser({
|
||||
user: {
|
||||
...user,
|
||||
role: validInvite?.serverRole
|
||||
},
|
||||
rawProfile: profile._raw
|
||||
})
|
||||
|
||||
// use the invite
|
||||
await finalizeInvitedServerRegistration(user.email, myUser.id)
|
||||
|
||||
@@ -97,7 +97,10 @@ module.exports = async (app, session, sessionAppId, finalizeAuth) => {
|
||||
// * the server public and the user has a valid invite
|
||||
// * the server public and the user doesn't have an invite
|
||||
// so we go ahead and register the user
|
||||
const userId = await createUser(user)
|
||||
const userId = await createUser({
|
||||
...user,
|
||||
role: invite?.serverRole
|
||||
})
|
||||
req.user = {
|
||||
id: userId,
|
||||
email: user.email,
|
||||
|
||||
@@ -97,7 +97,13 @@ module.exports = async (app, session, sessionStorage, finalizeAuth) => {
|
||||
)
|
||||
|
||||
// create the user
|
||||
const myUser = await findOrCreateUser({ user, rawProfile: userinfo })
|
||||
const myUser = await findOrCreateUser({
|
||||
user: {
|
||||
...user,
|
||||
role: validInvite?.serverRole
|
||||
},
|
||||
rawProfile: userinfo
|
||||
})
|
||||
|
||||
await finalizeInvitedServerRegistration(user.email, myUser.id)
|
||||
|
||||
|
||||
@@ -254,7 +254,7 @@ export const StreamFavorites = buildTableHelper('stream_favorites', [
|
||||
export const UsersMeta = buildMetaTableHelper(
|
||||
'users_meta',
|
||||
['userId', 'key', 'value', 'createdAt', 'updatedAt'],
|
||||
['isOnboardingFinished', 'foo', 'bar'],
|
||||
['isOnboardingFinished', 'foo', 'bar', 'onboardingStreamId'],
|
||||
'userId'
|
||||
)
|
||||
|
||||
@@ -314,7 +314,8 @@ export const ServerInvites = buildTableHelper('server_invites', [
|
||||
'resourceTarget',
|
||||
'resourceId',
|
||||
'role',
|
||||
'token'
|
||||
'token',
|
||||
'serverRole'
|
||||
])
|
||||
|
||||
export const PasswordResetTokens = buildTableHelper('pwdreset_tokens', [
|
||||
|
||||
@@ -1430,6 +1430,8 @@ export type ProjectInviteCreateInput = {
|
||||
email?: InputMaybe<Scalars['String']>;
|
||||
/** Defaults to the contributor role, if not specified */
|
||||
role?: InputMaybe<Scalars['String']>;
|
||||
/** Can only be specified if guest mode is on or if the user is an admin */
|
||||
serverRole?: InputMaybe<Scalars['String']>;
|
||||
/** Either this or email must be filled */
|
||||
userId?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
@@ -1518,7 +1520,10 @@ export type ProjectMutations = {
|
||||
__typename?: 'ProjectMutations';
|
||||
/** Create new project */
|
||||
create: Project;
|
||||
/** Create onboarding/tutorial project */
|
||||
/**
|
||||
* Create onboarding/tutorial project. If one is already created for the active user, that
|
||||
* one will be returned instead.
|
||||
*/
|
||||
createForOnboarding: Project;
|
||||
/** Delete an existing project */
|
||||
delete: Scalars['Boolean'];
|
||||
@@ -1856,7 +1861,6 @@ export enum ResourceType {
|
||||
Stream = 'stream'
|
||||
}
|
||||
|
||||
/** Available roles. */
|
||||
export type Role = {
|
||||
__typename?: 'Role';
|
||||
description: Scalars['String'];
|
||||
@@ -1912,8 +1916,10 @@ export type ServerInfo = {
|
||||
guestModeEnabled: Scalars['Boolean'];
|
||||
inviteOnly?: Maybe<Scalars['Boolean']>;
|
||||
name: Scalars['String'];
|
||||
roles: Array<Maybe<Role>>;
|
||||
scopes: Array<Maybe<Scope>>;
|
||||
/** @deprecated Use role constants from the @speckle/shared npm package instead */
|
||||
roles: Array<Role>;
|
||||
scopes: Array<Scope>;
|
||||
serverRoles: Array<ServerRoleItem>;
|
||||
termsOfService?: Maybe<Scalars['String']>;
|
||||
version?: Maybe<Scalars['String']>;
|
||||
};
|
||||
@@ -1938,6 +1944,8 @@ export type ServerInvite = {
|
||||
export type ServerInviteCreateInput = {
|
||||
email: Scalars['String'];
|
||||
message?: InputMaybe<Scalars['String']>;
|
||||
/** Can only be specified if guest mode is on or if the user is an admin */
|
||||
serverRole?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export enum ServerRole {
|
||||
@@ -1947,6 +1955,12 @@ export enum ServerRole {
|
||||
ServerUser = 'SERVER_USER'
|
||||
}
|
||||
|
||||
export type ServerRoleItem = {
|
||||
__typename?: 'ServerRoleItem';
|
||||
id: Scalars['String'];
|
||||
title: Scalars['String'];
|
||||
};
|
||||
|
||||
export type ServerStatistics = {
|
||||
__typename?: 'ServerStatistics';
|
||||
totalPendingInvites: Scalars['Int'];
|
||||
@@ -2121,6 +2135,7 @@ export type StreamCollaborator = {
|
||||
id: Scalars['String'];
|
||||
name: Scalars['String'];
|
||||
role: Scalars['String'];
|
||||
serverRole: Scalars['String'];
|
||||
};
|
||||
|
||||
export type StreamCollection = {
|
||||
@@ -2149,6 +2164,8 @@ export type StreamInviteCreateInput = {
|
||||
message?: InputMaybe<Scalars['String']>;
|
||||
/** Defaults to the contributor role, if not specified */
|
||||
role?: InputMaybe<Scalars['String']>;
|
||||
/** Can only be specified if guest mode is on or if the user is an admin */
|
||||
serverRole?: InputMaybe<Scalars['String']>;
|
||||
streamId: Scalars['String'];
|
||||
userId?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
@@ -2894,6 +2911,7 @@ export type ResolversTypes = {
|
||||
ServerInvite: ResolverTypeWrapper<ServerInviteGraphQLReturnType>;
|
||||
ServerInviteCreateInput: ServerInviteCreateInput;
|
||||
ServerRole: ServerRole;
|
||||
ServerRoleItem: ResolverTypeWrapper<ServerRoleItem>;
|
||||
ServerStatistics: ResolverTypeWrapper<GraphQLEmptyReturn>;
|
||||
ServerStats: ResolverTypeWrapper<ServerStats>;
|
||||
SmartTextEditorValue: ResolverTypeWrapper<SmartTextEditorValue>;
|
||||
@@ -3047,6 +3065,7 @@ export type ResolversParentTypes = {
|
||||
ServerInfoUpdateInput: ServerInfoUpdateInput;
|
||||
ServerInvite: ServerInviteGraphQLReturnType;
|
||||
ServerInviteCreateInput: ServerInviteCreateInput;
|
||||
ServerRoleItem: ServerRoleItem;
|
||||
ServerStatistics: GraphQLEmptyReturn;
|
||||
ServerStats: ServerStats;
|
||||
SmartTextEditorValue: SmartTextEditorValue;
|
||||
@@ -3767,8 +3786,9 @@ export type ServerInfoResolvers<ContextType = GraphQLContext, ParentType extends
|
||||
guestModeEnabled?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType>;
|
||||
inviteOnly?: Resolver<Maybe<ResolversTypes['Boolean']>, ParentType, ContextType>;
|
||||
name?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
|
||||
roles?: Resolver<Array<Maybe<ResolversTypes['Role']>>, ParentType, ContextType>;
|
||||
scopes?: Resolver<Array<Maybe<ResolversTypes['Scope']>>, ParentType, ContextType>;
|
||||
roles?: Resolver<Array<ResolversTypes['Role']>, ParentType, ContextType>;
|
||||
scopes?: Resolver<Array<ResolversTypes['Scope']>, ParentType, ContextType>;
|
||||
serverRoles?: Resolver<Array<ResolversTypes['ServerRoleItem']>, ParentType, ContextType>;
|
||||
termsOfService?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
|
||||
version?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
@@ -3781,6 +3801,12 @@ export type ServerInviteResolvers<ContextType = GraphQLContext, ParentType exten
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type ServerRoleItemResolvers<ContextType = GraphQLContext, ParentType extends ResolversParentTypes['ServerRoleItem'] = ResolversParentTypes['ServerRoleItem']> = {
|
||||
id?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
|
||||
title?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type ServerStatisticsResolvers<ContextType = GraphQLContext, ParentType extends ResolversParentTypes['ServerStatistics'] = ResolversParentTypes['ServerStatistics']> = {
|
||||
totalPendingInvites?: Resolver<ResolversTypes['Int'], ParentType, ContextType>;
|
||||
totalProjectCount?: Resolver<ResolversTypes['Int'], ParentType, ContextType>;
|
||||
@@ -3855,6 +3881,7 @@ export type StreamCollaboratorResolvers<ContextType = GraphQLContext, ParentType
|
||||
id?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
|
||||
name?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
|
||||
role?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
|
||||
serverRole?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
};
|
||||
|
||||
@@ -4087,6 +4114,7 @@ export type Resolvers<ContextType = GraphQLContext> = {
|
||||
ServerAppListItem?: ServerAppListItemResolvers<ContextType>;
|
||||
ServerInfo?: ServerInfoResolvers<ContextType>;
|
||||
ServerInvite?: ServerInviteResolvers<ContextType>;
|
||||
ServerRoleItem?: ServerRoleItemResolvers<ContextType>;
|
||||
ServerStatistics?: ServerStatisticsResolvers<ContextType>;
|
||||
ServerStats?: ServerStatsResolvers<ContextType>;
|
||||
SmartTextEditorValue?: SmartTextEditorValueResolvers<ContextType>;
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
updateStreamAndNotify,
|
||||
updateStreamRoleAndNotify
|
||||
} from '@/modules/core/services/streams/management'
|
||||
import { createOnboardingStream } from '@/modules/core/services/streams/onboarding'
|
||||
import { ensureOnboardingStream } from '@/modules/core/services/streams/onboarding'
|
||||
import { removeStreamCollaborator } from '@/modules/core/services/streams/streamAccessService'
|
||||
import { cancelStreamInvite } from '@/modules/serverinvites/services/inviteProcessingService'
|
||||
import {
|
||||
@@ -69,7 +69,7 @@ export = {
|
||||
return await deleteStreamAndNotify(id, userId!)
|
||||
},
|
||||
async createForOnboarding(_parent, _args, { userId }) {
|
||||
return await createOnboardingStream(userId!)
|
||||
return await ensureOnboardingStream(userId!)
|
||||
},
|
||||
async update(_parent, { update }, { userId }) {
|
||||
await authorizeResolver(userId, update.id, Roles.Stream.Owner)
|
||||
|
||||
@@ -6,7 +6,7 @@ const {
|
||||
getPublicScopes,
|
||||
getPublicRoles
|
||||
} = require('../../services/generic')
|
||||
const { Roles, Scopes } = require('@speckle/shared')
|
||||
const { Roles, Scopes, RoleInfo } = require('@speckle/shared')
|
||||
const { throwForNotHavingServerRole } = require('@/modules/shared/authz')
|
||||
|
||||
module.exports = {
|
||||
@@ -23,6 +23,16 @@ module.exports = {
|
||||
|
||||
async scopes() {
|
||||
return await getPublicScopes()
|
||||
},
|
||||
|
||||
async serverRoles(parent) {
|
||||
const { guestModeEnabled } = parent
|
||||
return Object.values(Roles.Server)
|
||||
.filter((role) => guestModeEnabled || role !== Roles.Server.Guest)
|
||||
.map((r) => ({
|
||||
id: r,
|
||||
title: RoleInfo.Server[r]
|
||||
}))
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -330,6 +330,13 @@ module.exports = {
|
||||
)
|
||||
}
|
||||
},
|
||||
StreamCollaborator: {
|
||||
async serverRole(parent, _args, ctx) {
|
||||
const { id } = parent
|
||||
const user = await ctx.loaders.users.getUser.load(id)
|
||||
return user?.role
|
||||
}
|
||||
},
|
||||
PendingStreamCollaborator: {
|
||||
/**
|
||||
* @param {import('@/modules/serverinvites/services/inviteRetrievalService').PendingStreamCollaboratorGraphQLType} parent
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
getCommitStreams,
|
||||
StreamWithCommitId
|
||||
} from '@/modules/core/repositories/streams'
|
||||
import { getUsers } from '@/modules/core/repositories/users'
|
||||
import { UserWithOptionalRole, getUsers } from '@/modules/core/repositories/users'
|
||||
import { keyBy } from 'lodash'
|
||||
import { getInvites } from '@/modules/serverinvites/repositories'
|
||||
import { AuthContext } from '@/modules/shared/authz'
|
||||
@@ -346,10 +346,15 @@ export function buildRequestLoaders(
|
||||
/**
|
||||
* Get user from DB
|
||||
*/
|
||||
getUser: createLoader<string, Nullable<LimitedUserRecord>>(async (userIds) => {
|
||||
const results = keyBy(await getUsers(userIds.slice()), 'id')
|
||||
return userIds.map((i) => results[i] || null)
|
||||
}),
|
||||
getUser: createLoader<string, Nullable<UserWithOptionalRole<LimitedUserRecord>>>(
|
||||
async (userIds) => {
|
||||
const results = keyBy(
|
||||
await getUsers(userIds.slice(), { withRole: true }),
|
||||
'id'
|
||||
)
|
||||
return userIds.map((i) => results[i] || null)
|
||||
}
|
||||
),
|
||||
|
||||
/**
|
||||
* Get meta values associated with one or more users
|
||||
|
||||
@@ -989,3 +989,32 @@ export async function getOnboardingBaseStream(version: string) {
|
||||
|
||||
return await q
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user's own onboarding stream, if any
|
||||
*/
|
||||
export async function getUserOnboardingStream(userId: string) {
|
||||
const q = Users.meta
|
||||
.knex()
|
||||
.select<StreamRecord[]>(Streams.cols)
|
||||
.innerJoin(
|
||||
Streams.name,
|
||||
Streams.col.id,
|
||||
knex.raw(`?? #>> '{}'`, [Users.meta.col.value])
|
||||
)
|
||||
.where(Users.meta.col.userId, userId)
|
||||
.andWhere(Users.meta.col.key, Users.meta.metaKey.onboardingStreamId)
|
||||
.first()
|
||||
|
||||
return await q
|
||||
}
|
||||
|
||||
export async function markUserOnboardingStream(userId: string, streamId: string) {
|
||||
const stream = await getStream({ streamId })
|
||||
if (!stream) {
|
||||
throw new Error(`Stream ${streamId} not found`)
|
||||
}
|
||||
|
||||
const meta = metaHelpers(Users)
|
||||
await meta.set(userId, Users.meta.metaKey.onboardingStreamId, streamId)
|
||||
}
|
||||
|
||||
@@ -131,9 +131,21 @@ export async function getUser(userId: string, params?: GetUserParams) {
|
||||
*/
|
||||
export async function getUserByEmail(
|
||||
email: string,
|
||||
options?: Partial<{ skipClean: boolean }>
|
||||
options?: Partial<{ skipClean: boolean; withRole: boolean }>
|
||||
) {
|
||||
const q = Users.knex<UserRecord[]>().whereRaw('lower(email) = lower(?)', [email])
|
||||
const q = Users.knex<UserWithOptionalRole[]>().whereRaw('lower(email) = lower(?)', [
|
||||
email
|
||||
])
|
||||
if (options?.withRole) {
|
||||
q.columns([
|
||||
...Object.values(Users.col),
|
||||
// Getting first role from grouped results
|
||||
knex.raw(`(array_agg("server_acl"."role"))[1] as role`)
|
||||
])
|
||||
q.leftJoin(ServerAcl.name, ServerAcl.col.userId, Users.col.id)
|
||||
q.groupBy(Users.col.id)
|
||||
}
|
||||
|
||||
const user = await q.first()
|
||||
return user ? (!options?.skipClean ? sanitizeUserRecord(user) : user) : null
|
||||
}
|
||||
|
||||
@@ -381,7 +381,7 @@ export async function cloneStream(userId: string, sourceStreamId: string) {
|
||||
try {
|
||||
// Clone stream/commits/branches/objects
|
||||
const coreCloneResult = await cloneStreamCore(state)
|
||||
const newStreamId = coreCloneResult.newStreamId
|
||||
const { newStream } = coreCloneResult
|
||||
|
||||
// Clone comments
|
||||
await cloneStreamComments(state, coreCloneResult)
|
||||
@@ -390,7 +390,7 @@ export async function cloneStream(userId: string, sourceStreamId: string) {
|
||||
await addStreamClonedActivity(
|
||||
{
|
||||
sourceStreamId,
|
||||
newStreamId,
|
||||
newStream,
|
||||
clonerId: userId
|
||||
},
|
||||
{ trx: state.trx }
|
||||
|
||||
@@ -5,12 +5,17 @@ import { StreamRecord } from '@/modules/core/helpers/types'
|
||||
import { logger } from '@/logging/logging'
|
||||
import { createStreamReturnRecord } from '@/modules/core/services/streams/management'
|
||||
import { getOnboardingBaseProject } from '@/modules/cross-server-sync/services/onboardingProject'
|
||||
import {
|
||||
getUserOnboardingStream,
|
||||
markUserOnboardingStream
|
||||
} from '@/modules/core/repositories/streams'
|
||||
|
||||
export async function createOnboardingStream(targetUserId: string) {
|
||||
const sourceStream = await getOnboardingBaseProject()
|
||||
|
||||
// clone from base
|
||||
let newStream: Optional<StreamRecord> = undefined
|
||||
if (sourceStream) {
|
||||
let newStream: Optional<StreamRecord> = undefined
|
||||
try {
|
||||
newStream = await cloneStream(targetUserId, sourceStream.id)
|
||||
} catch (e) {
|
||||
@@ -20,10 +25,22 @@ export async function createOnboardingStream(targetUserId: string) {
|
||||
logger.warn(e, 'Stream clone failed')
|
||||
}
|
||||
}
|
||||
|
||||
if (newStream) return newStream
|
||||
}
|
||||
|
||||
// clone failed, just create empty stream
|
||||
return await createStreamReturnRecord({ ownerId: targetUserId })
|
||||
if (!newStream) {
|
||||
newStream = await createStreamReturnRecord({ ownerId: targetUserId })
|
||||
}
|
||||
|
||||
// mark as onboarding stream
|
||||
await markUserOnboardingStream(targetUserId, newStream.id)
|
||||
|
||||
return newStream
|
||||
}
|
||||
|
||||
export async function ensureOnboardingStream(targetUserId: string) {
|
||||
return (
|
||||
(await getUserOnboardingStream(targetUserId)) ||
|
||||
(await createOnboardingStream(targetUserId))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ const {
|
||||
PasswordTooShortError
|
||||
} = require('@/modules/core/errors/userinput')
|
||||
const { Roles } = require('@speckle/shared')
|
||||
const { getServerInfo } = require('@/modules/core/services/generic')
|
||||
|
||||
const _changeUserRole = async ({ userId, role }) =>
|
||||
await Acl().where({ userId }).update({ role })
|
||||
@@ -73,6 +74,15 @@ module.exports = {
|
||||
// ONLY ALLOW SKIPPING WHEN CREATING USERS FOR TESTS, IT'S UNSAFE OTHERWISE
|
||||
const { skipPropertyValidation = false } = options || {}
|
||||
|
||||
let expectedRole = null
|
||||
if (user.role) {
|
||||
const isValidRole = Object.values(Roles.Server).includes(user.role)
|
||||
const isValidIfGuestModeEnabled =
|
||||
user.role === Roles.Server.Guest && (await getServerInfo()).guestModeEnabled
|
||||
expectedRole = isValidRole && isValidIfGuestModeEnabled ? user.role : null
|
||||
}
|
||||
delete user.role
|
||||
|
||||
user = skipPropertyValidation
|
||||
? user
|
||||
: pick(user, ['id', 'bio', 'email', 'password', 'name', 'company'])
|
||||
@@ -95,7 +105,9 @@ module.exports = {
|
||||
if (!newUser) throw new Error("Couldn't create user")
|
||||
|
||||
const userRole =
|
||||
(await countAdminUsers()) === 0 ? Roles.Server.Admin : Roles.Server.User
|
||||
(await countAdminUsers()) === 0
|
||||
? Roles.Server.Admin
|
||||
: expectedRole || Roles.Server.User
|
||||
|
||||
await Acl().insert({ userId: newId, role: userRole })
|
||||
|
||||
|
||||
@@ -1421,6 +1421,8 @@ export type ProjectInviteCreateInput = {
|
||||
email?: InputMaybe<Scalars['String']>;
|
||||
/** Defaults to the contributor role, if not specified */
|
||||
role?: InputMaybe<Scalars['String']>;
|
||||
/** Can only be specified if guest mode is on or if the user is an admin */
|
||||
serverRole?: InputMaybe<Scalars['String']>;
|
||||
/** Either this or email must be filled */
|
||||
userId?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
@@ -1509,7 +1511,10 @@ export type ProjectMutations = {
|
||||
__typename?: 'ProjectMutations';
|
||||
/** Create new project */
|
||||
create: Project;
|
||||
/** Create onboarding/tutorial project */
|
||||
/**
|
||||
* Create onboarding/tutorial project. If one is already created for the active user, that
|
||||
* one will be returned instead.
|
||||
*/
|
||||
createForOnboarding: Project;
|
||||
/** Delete an existing project */
|
||||
delete: Scalars['Boolean'];
|
||||
@@ -1847,7 +1852,6 @@ export enum ResourceType {
|
||||
Stream = 'stream'
|
||||
}
|
||||
|
||||
/** Available roles. */
|
||||
export type Role = {
|
||||
__typename?: 'Role';
|
||||
description: Scalars['String'];
|
||||
@@ -1903,8 +1907,10 @@ export type ServerInfo = {
|
||||
guestModeEnabled: Scalars['Boolean'];
|
||||
inviteOnly?: Maybe<Scalars['Boolean']>;
|
||||
name: Scalars['String'];
|
||||
roles: Array<Maybe<Role>>;
|
||||
scopes: Array<Maybe<Scope>>;
|
||||
/** @deprecated Use role constants from the @speckle/shared npm package instead */
|
||||
roles: Array<Role>;
|
||||
scopes: Array<Scope>;
|
||||
serverRoles: Array<ServerRoleItem>;
|
||||
termsOfService?: Maybe<Scalars['String']>;
|
||||
version?: Maybe<Scalars['String']>;
|
||||
};
|
||||
@@ -1929,6 +1935,8 @@ export type ServerInvite = {
|
||||
export type ServerInviteCreateInput = {
|
||||
email: Scalars['String'];
|
||||
message?: InputMaybe<Scalars['String']>;
|
||||
/** Can only be specified if guest mode is on or if the user is an admin */
|
||||
serverRole?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export enum ServerRole {
|
||||
@@ -1938,6 +1946,12 @@ export enum ServerRole {
|
||||
ServerUser = 'SERVER_USER'
|
||||
}
|
||||
|
||||
export type ServerRoleItem = {
|
||||
__typename?: 'ServerRoleItem';
|
||||
id: Scalars['String'];
|
||||
title: Scalars['String'];
|
||||
};
|
||||
|
||||
export type ServerStatistics = {
|
||||
__typename?: 'ServerStatistics';
|
||||
totalPendingInvites: Scalars['Int'];
|
||||
@@ -2112,6 +2126,7 @@ export type StreamCollaborator = {
|
||||
id: Scalars['String'];
|
||||
name: Scalars['String'];
|
||||
role: Scalars['String'];
|
||||
serverRole: Scalars['String'];
|
||||
};
|
||||
|
||||
export type StreamCollection = {
|
||||
@@ -2140,6 +2155,8 @@ export type StreamInviteCreateInput = {
|
||||
message?: InputMaybe<Scalars['String']>;
|
||||
/** Defaults to the contributor role, if not specified */
|
||||
role?: InputMaybe<Scalars['String']>;
|
||||
/** Can only be specified if guest mode is on or if the user is an admin */
|
||||
serverRole?: InputMaybe<Scalars['String']>;
|
||||
streamId: Scalars['String'];
|
||||
userId?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
@@ -26,13 +26,15 @@ const {
|
||||
const { authorizeResolver } = require('@/modules/shared')
|
||||
const { chunk } = require('lodash')
|
||||
|
||||
/** @type {import('@/modules/core/graph/generated/graphql').Resolvers} */
|
||||
module.exports = {
|
||||
Mutation: {
|
||||
async serverInviteCreate(_parent, args, context) {
|
||||
await createAndSendInvite({
|
||||
target: args.input.email,
|
||||
inviterId: context.userId,
|
||||
message: args.input.message
|
||||
message: args.input.message,
|
||||
serverRole: args.input.serverRole
|
||||
})
|
||||
|
||||
return true
|
||||
@@ -56,7 +58,8 @@ module.exports = {
|
||||
createAndSendInvite({
|
||||
target: params.email,
|
||||
inviterId: context.userId,
|
||||
message: params.message
|
||||
message: params.message,
|
||||
serverRole: params.serverRole
|
||||
})
|
||||
)
|
||||
)
|
||||
@@ -83,7 +86,7 @@ module.exports = {
|
||||
for (const paramsBatchArray of batches) {
|
||||
await Promise.all(
|
||||
paramsBatchArray.map((params) => {
|
||||
const { email, userId, message, streamId, role } = params
|
||||
const { email, userId, message, streamId, role, serverRole } = params
|
||||
const target = userId ? buildUserTarget(userId) : email
|
||||
return createAndSendInvite({
|
||||
target,
|
||||
@@ -91,7 +94,8 @@ module.exports = {
|
||||
message,
|
||||
resourceTarget: ResourceTargets.Streams,
|
||||
resourceId: streamId,
|
||||
role: role || Roles.Stream.Contributor
|
||||
role: role || Roles.Stream.Contributor,
|
||||
serverRole
|
||||
})
|
||||
})
|
||||
)
|
||||
|
||||
@@ -11,4 +11,5 @@ export type ServerInviteRecord = {
|
||||
resourceId: Nullable<string>
|
||||
role: Nullable<string>
|
||||
token: string
|
||||
serverRole: Nullable<string>
|
||||
}
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
import { Knex } from 'knex'
|
||||
|
||||
const TABLE_NAME = 'server_invites'
|
||||
const COL_NAME = 'serverRole'
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
await knex.schema.alterTable(TABLE_NAME, (table) => {
|
||||
table.string(COL_NAME).nullable()
|
||||
})
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.alterTable(TABLE_NAME, (table) => {
|
||||
// Drop token field
|
||||
table.dropColumn(COL_NAME)
|
||||
})
|
||||
}
|
||||
@@ -50,11 +50,13 @@ async function getResource(invite) {
|
||||
/**
|
||||
* Try to find a user using the target value
|
||||
* @param {string} target
|
||||
* @returns {Promise<import('@/modules/core/helpers/userHelper').UserRecord>}
|
||||
* @returns {Promise<import('@/modules/core/repositories/users').UserWithOptionalRole | undefined>}
|
||||
*/
|
||||
async function getUserFromTarget(target) {
|
||||
const { userEmail, userId } = resolveTarget(target)
|
||||
return userEmail ? await getUserByEmail(userEmail) : await getUser(userId)
|
||||
return userEmail
|
||||
? await getUserByEmail(userEmail, { withRole: true })
|
||||
: await getUser(userId, { withRole: true })
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,6 +36,7 @@ const { getFrontendOrigin } = require('@/modules/shared/helpers/envHelper')
|
||||
* resourceTarget?: string;
|
||||
* resourceId?: string;
|
||||
* role?: string;
|
||||
* serverRole?: string
|
||||
* }} CreateInviteParams
|
||||
*/
|
||||
|
||||
@@ -327,12 +328,15 @@ async function buildEmailContents(invite, inviter, targetUser, resource) {
|
||||
* @returns {Promise<string>} The ID of the created invite
|
||||
*/
|
||||
async function createAndSendInvite(params) {
|
||||
const { inviterId, resourceTarget, resourceId, role } = params
|
||||
const { inviterId, resourceTarget, resourceId, role, serverRole } = params
|
||||
let { message, target } = params
|
||||
|
||||
const inviter = await getUser(inviterId)
|
||||
const targetUser = await getUserFromTarget(target)
|
||||
const resource = await getResource(params)
|
||||
const [inviter, targetUser, resource, serverInfo] = await Promise.all([
|
||||
getUser(inviterId, { withRole: true }),
|
||||
getUserFromTarget(target),
|
||||
getResource(params),
|
||||
getServerInfo()
|
||||
])
|
||||
|
||||
// if target user found, always use the user ID
|
||||
if (targetUser) target = buildUserTarget(targetUser.id)
|
||||
@@ -347,6 +351,24 @@ async function createAndSendInvite(params) {
|
||||
message = sanitizeMessage(message)
|
||||
}
|
||||
|
||||
// validate server role
|
||||
if (serverRole && !Object.values(Roles.Server).includes(serverRole)) {
|
||||
throw new InviteCreateValidationError('Invalid server role')
|
||||
}
|
||||
if (inviter.role !== Roles.Server.Admin && serverRole === Roles.Server.Admin) {
|
||||
throw new InviteCreateValidationError(
|
||||
'Only server admins can assign the admin server role'
|
||||
)
|
||||
}
|
||||
if (serverRole === Roles.Server.Guest && !serverInfo.guestModeEnabled) {
|
||||
throw new InviteCreateValidationError('Guest mode is not enabled on this server')
|
||||
}
|
||||
if (targetUser && targetUser.role === Roles.Server.Guest) {
|
||||
if (role === Roles.Stream.Owner) {
|
||||
throw new InviteCreateValidationError('Guest users cannot be owners of streams')
|
||||
}
|
||||
}
|
||||
|
||||
// write to DB
|
||||
const invite = {
|
||||
id: crs({ length: 20 }),
|
||||
@@ -356,7 +378,8 @@ async function createAndSendInvite(params) {
|
||||
resourceTarget,
|
||||
resourceId,
|
||||
role,
|
||||
token: crs({ length: 50 })
|
||||
token: crs({ length: 50 }),
|
||||
serverRole
|
||||
}
|
||||
await insertInviteAndDeleteOld(
|
||||
invite,
|
||||
|
||||
@@ -37,7 +37,8 @@ export async function createStreamInviteAndNotify(
|
||||
resourceTarget: ResourceTargets.Streams,
|
||||
resourceId: isStreamInviteCreateInput(input) ? input.streamId : input.projectId,
|
||||
role: role || Roles.Stream.Contributor,
|
||||
message: isStreamInviteCreateInput(input) ? input.message || undefined : undefined
|
||||
message: isStreamInviteCreateInput(input) ? input.message || undefined : undefined,
|
||||
serverRole: input.serverRole || undefined
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1421,6 +1421,8 @@ export type ProjectInviteCreateInput = {
|
||||
email?: InputMaybe<Scalars['String']>;
|
||||
/** Defaults to the contributor role, if not specified */
|
||||
role?: InputMaybe<Scalars['String']>;
|
||||
/** Can only be specified if guest mode is on or if the user is an admin */
|
||||
serverRole?: InputMaybe<Scalars['String']>;
|
||||
/** Either this or email must be filled */
|
||||
userId?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
@@ -1509,7 +1511,10 @@ export type ProjectMutations = {
|
||||
__typename?: 'ProjectMutations';
|
||||
/** Create new project */
|
||||
create: Project;
|
||||
/** Create onboarding/tutorial project */
|
||||
/**
|
||||
* Create onboarding/tutorial project. If one is already created for the active user, that
|
||||
* one will be returned instead.
|
||||
*/
|
||||
createForOnboarding: Project;
|
||||
/** Delete an existing project */
|
||||
delete: Scalars['Boolean'];
|
||||
@@ -1847,7 +1852,6 @@ export enum ResourceType {
|
||||
Stream = 'stream'
|
||||
}
|
||||
|
||||
/** Available roles. */
|
||||
export type Role = {
|
||||
__typename?: 'Role';
|
||||
description: Scalars['String'];
|
||||
@@ -1903,8 +1907,10 @@ export type ServerInfo = {
|
||||
guestModeEnabled: Scalars['Boolean'];
|
||||
inviteOnly?: Maybe<Scalars['Boolean']>;
|
||||
name: Scalars['String'];
|
||||
roles: Array<Maybe<Role>>;
|
||||
scopes: Array<Maybe<Scope>>;
|
||||
/** @deprecated Use role constants from the @speckle/shared npm package instead */
|
||||
roles: Array<Role>;
|
||||
scopes: Array<Scope>;
|
||||
serverRoles: Array<ServerRoleItem>;
|
||||
termsOfService?: Maybe<Scalars['String']>;
|
||||
version?: Maybe<Scalars['String']>;
|
||||
};
|
||||
@@ -1929,6 +1935,8 @@ export type ServerInvite = {
|
||||
export type ServerInviteCreateInput = {
|
||||
email: Scalars['String'];
|
||||
message?: InputMaybe<Scalars['String']>;
|
||||
/** Can only be specified if guest mode is on or if the user is an admin */
|
||||
serverRole?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export enum ServerRole {
|
||||
@@ -1938,6 +1946,12 @@ export enum ServerRole {
|
||||
ServerUser = 'SERVER_USER'
|
||||
}
|
||||
|
||||
export type ServerRoleItem = {
|
||||
__typename?: 'ServerRoleItem';
|
||||
id: Scalars['String'];
|
||||
title: Scalars['String'];
|
||||
};
|
||||
|
||||
export type ServerStatistics = {
|
||||
__typename?: 'ServerStatistics';
|
||||
totalPendingInvites: Scalars['Int'];
|
||||
@@ -2112,6 +2126,7 @@ export type StreamCollaborator = {
|
||||
id: Scalars['String'];
|
||||
name: Scalars['String'];
|
||||
role: Scalars['String'];
|
||||
serverRole: Scalars['String'];
|
||||
};
|
||||
|
||||
export type StreamCollection = {
|
||||
@@ -2140,6 +2155,8 @@ export type StreamInviteCreateInput = {
|
||||
message?: InputMaybe<Scalars['String']>;
|
||||
/** Defaults to the contributor role, if not specified */
|
||||
role?: InputMaybe<Scalars['String']>;
|
||||
/** Can only be specified if guest mode is on or if the user is an admin */
|
||||
serverRole?: InputMaybe<Scalars['String']>;
|
||||
streamId: Scalars['String'];
|
||||
userId?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
@@ -19,6 +19,31 @@ export const Roles = Object.freeze(<const>{
|
||||
}
|
||||
})
|
||||
|
||||
export const RoleInfo = Object.freeze(<const>{
|
||||
Stream: {
|
||||
[Roles.Stream.Owner]: {
|
||||
title: 'Owner',
|
||||
description:
|
||||
'Owners have full access, including deletion rights & access control.'
|
||||
},
|
||||
[Roles.Stream.Contributor]: {
|
||||
title: 'Contributor',
|
||||
description:
|
||||
'Contributors can create new branches and commits, but they cannot edit stream details or manage collaborators.'
|
||||
},
|
||||
[Roles.Stream.Reviewer]: {
|
||||
title: 'Reviewer',
|
||||
description: 'Reviewers can only view (read) the data from this stream.'
|
||||
}
|
||||
},
|
||||
Server: {
|
||||
[Roles.Server.Admin]: 'Admin',
|
||||
[Roles.Server.User]: 'User',
|
||||
[Roles.Server.Guest]: 'Guest',
|
||||
[Roles.Server.ArchivedUser]: 'Archived'
|
||||
}
|
||||
})
|
||||
|
||||
export type ServerRoles = (typeof Roles)['Server'][keyof (typeof Roles)['Server']]
|
||||
export type StreamRoles = (typeof Roles)['Stream'][keyof (typeof Roles)['Stream']]
|
||||
|
||||
|
||||
@@ -290,3 +290,11 @@ export const Simple: StoryType = {
|
||||
buttonStyle: 'simple'
|
||||
}
|
||||
}
|
||||
|
||||
export const WithDisabledItems: StoryType = {
|
||||
...Default,
|
||||
args: {
|
||||
...Default.args,
|
||||
disabledItemPredicate: (item: FakeItemType) => item.id === '3'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,13 +102,15 @@
|
||||
:key="itemKey(item)"
|
||||
v-slot="{ active, selected }: { active: boolean, selected: boolean }"
|
||||
:value="item"
|
||||
:disabled="disabledItemPredicate?.(item) || false"
|
||||
>
|
||||
<li
|
||||
:class="[
|
||||
active ? 'text-primary' : 'text-foreground',
|
||||
'relative transition cursor-pointer select-none py-1.5 pl-3',
|
||||
!hideCheckmarks ? 'pr-9' : ''
|
||||
]"
|
||||
:class="
|
||||
listboxOptionClasses({
|
||||
active,
|
||||
disabled: disabledItemPredicate?.(item) || false
|
||||
})
|
||||
"
|
||||
>
|
||||
<span :class="['block truncate']">
|
||||
<slot
|
||||
@@ -116,6 +118,7 @@
|
||||
:item="item"
|
||||
:active="active"
|
||||
:selected="selected"
|
||||
:disabled="disabledItemPredicate?.(item) || false"
|
||||
>
|
||||
{{ simpleDisplayText(item) }}
|
||||
</slot>
|
||||
@@ -216,6 +219,13 @@ const props = defineProps({
|
||||
>,
|
||||
default: undefined
|
||||
},
|
||||
/**
|
||||
* Set this to disable certain items in the list
|
||||
*/
|
||||
disabledItemPredicate: {
|
||||
type: Function as PropType<Optional<(item: SingleItem) => boolean>>,
|
||||
default: undefined
|
||||
},
|
||||
/**
|
||||
* If search=true and this is set, you can use this to load data asynchronously depending
|
||||
* on the search query
|
||||
@@ -508,6 +518,24 @@ const triggerSearch = async () => {
|
||||
}
|
||||
const debouncedSearch = debounce(triggerSearch, 1000)
|
||||
|
||||
const listboxOptionClasses = (params: { active: boolean; disabled: boolean }) => {
|
||||
const { active, disabled } = params || {}
|
||||
const { hideCheckmarks } = props
|
||||
|
||||
const classParts = [
|
||||
'relative transition cursor-pointer select-none py-1.5 pl-3',
|
||||
!hideCheckmarks ? 'pr-9' : ''
|
||||
]
|
||||
|
||||
if (disabled) {
|
||||
classParts.push('opacity-50 cursor-not-allowed')
|
||||
} else {
|
||||
classParts.push(active ? 'text-primary' : 'text-foreground')
|
||||
}
|
||||
|
||||
return classParts.join(' ')
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.items,
|
||||
(newItems) => {
|
||||
|
||||
Reference in New Issue
Block a user