Feat: Refactor workspace dashboard to improve performance (WIP) (#4500)
This commit is contained in:
@@ -27,6 +27,7 @@ export type ActiveUserMutations = {
|
||||
emailMutations: UserEmailMutations;
|
||||
/** Mark onboarding as complete */
|
||||
finishOnboarding: Scalars['Boolean']['output'];
|
||||
meta: UserMetaMutations;
|
||||
setActiveWorkspace: Scalars['Boolean']['output'];
|
||||
/** Edit a user's profile */
|
||||
update: User;
|
||||
@@ -432,6 +433,7 @@ export type Automation = {
|
||||
id: Scalars['ID']['output'];
|
||||
isTestAutomation: Scalars['Boolean']['output'];
|
||||
name: Scalars['String']['output'];
|
||||
permissions: AutomationPermissionChecks;
|
||||
runs: AutomateRunCollection;
|
||||
updatedAt: Scalars['DateTime']['output'];
|
||||
};
|
||||
@@ -449,6 +451,12 @@ export type AutomationCollection = {
|
||||
totalCount: Scalars['Int']['output'];
|
||||
};
|
||||
|
||||
export type AutomationPermissionChecks = {
|
||||
__typename?: 'AutomationPermissionChecks';
|
||||
canRead: PermissionCheckResult;
|
||||
canUpdate: PermissionCheckResult;
|
||||
};
|
||||
|
||||
export type AutomationRevision = {
|
||||
__typename?: 'AutomationRevision';
|
||||
functions: Array<AutomationRevisionFunction>;
|
||||
@@ -2552,8 +2560,10 @@ export enum ProjectPendingVersionsUpdatedMessageType {
|
||||
export type ProjectPermissionChecks = {
|
||||
__typename?: 'ProjectPermissionChecks';
|
||||
canBroadcastActivity: PermissionCheckResult;
|
||||
canCreateAutomation: PermissionCheckResult;
|
||||
canCreateComment: PermissionCheckResult;
|
||||
canCreateModel: PermissionCheckResult;
|
||||
canDelete: PermissionCheckResult;
|
||||
canLeave: PermissionCheckResult;
|
||||
canMoveToWorkspace: PermissionCheckResult;
|
||||
canRead: PermissionCheckResult;
|
||||
@@ -3199,7 +3209,7 @@ export type SetPrimaryUserEmailInput = {
|
||||
id: Scalars['ID']['input'];
|
||||
};
|
||||
|
||||
/** Visbility without the "discoverable" option */
|
||||
/** Visibility without the "discoverable" option */
|
||||
export enum SimpleProjectVisibility {
|
||||
Private = 'PRIVATE',
|
||||
Unlisted = 'UNLISTED'
|
||||
@@ -3848,6 +3858,7 @@ export type User = {
|
||||
isOnboardingFinished?: Maybe<Scalars['Boolean']['output']>;
|
||||
/** Returns `true` if last visited project was "legacy" "personal project" outside of a workspace */
|
||||
isProjectsActive?: Maybe<Scalars['Boolean']['output']>;
|
||||
meta: UserMeta;
|
||||
name: Scalars['String']['output'];
|
||||
notificationPreferences: Scalars['JSONObject']['output'];
|
||||
permissions: RootPermissionChecks;
|
||||
@@ -4068,6 +4079,28 @@ export type UserGendoAiCredits = {
|
||||
used: Scalars['Int']['output'];
|
||||
};
|
||||
|
||||
export type UserMeta = {
|
||||
__typename?: 'UserMeta';
|
||||
legacyProjectsExplainerCollapsed: Scalars['Boolean']['output'];
|
||||
newWorkspaceExplainerDismissed: Scalars['Boolean']['output'];
|
||||
};
|
||||
|
||||
export type UserMetaMutations = {
|
||||
__typename?: 'UserMetaMutations';
|
||||
setLegacyProjectsExplainerCollapsed: Scalars['Boolean']['output'];
|
||||
setNewWorkspaceExplainerDismissed: Scalars['Boolean']['output'];
|
||||
};
|
||||
|
||||
|
||||
export type UserMetaMutationsSetLegacyProjectsExplainerCollapsedArgs = {
|
||||
value: Scalars['Boolean']['input'];
|
||||
};
|
||||
|
||||
|
||||
export type UserMetaMutationsSetNewWorkspaceExplainerDismissedArgs = {
|
||||
value: Scalars['Boolean']['input'];
|
||||
};
|
||||
|
||||
export type UserProjectCollection = {
|
||||
__typename?: 'UserProjectCollection';
|
||||
cursor?: Maybe<Scalars['String']['output']>;
|
||||
|
||||
@@ -30,90 +30,94 @@
|
||||
class="border-r border-outline-3 px-2 pt-3 pb-2 bg-foundation-page"
|
||||
>
|
||||
<LayoutSidebarMenu>
|
||||
<LayoutSidebarMenuGroup v-if="isWorkspacesEnabled && isMobile">
|
||||
<LayoutSidebarMenuGroup v-if="isWorkspacesEnabled" class="lg:hidden mb-4">
|
||||
<HeaderWorkspaceSwitcher />
|
||||
</LayoutSidebarMenuGroup>
|
||||
|
||||
<LayoutSidebarMenuGroup>
|
||||
<NuxtLink :to="projectsLink" @click="isOpenMobile = false">
|
||||
<LayoutSidebarMenuGroupItem
|
||||
label="Projects"
|
||||
:active="route.name === 'workspaces-slug' || isActive(projectsRoute)"
|
||||
<div class="flex flex-col gap-y-2 lg:gap-y-4">
|
||||
<LayoutSidebarMenuGroup>
|
||||
<NuxtLink :to="projectsLink" @click="isOpenMobile = false">
|
||||
<LayoutSidebarMenuGroupItem
|
||||
label="Projects"
|
||||
:active="
|
||||
route.name === 'workspaces-slug' || isActive(projectsRoute)
|
||||
"
|
||||
>
|
||||
<template #icon>
|
||||
<IconProjects class="size-4 text-foreground-2" />
|
||||
</template>
|
||||
</LayoutSidebarMenuGroupItem>
|
||||
</NuxtLink>
|
||||
|
||||
<NuxtLink :to="connectorsRoute" @click="isOpenMobile = false">
|
||||
<LayoutSidebarMenuGroupItem
|
||||
label="Connectors"
|
||||
:active="isActive(connectorsRoute)"
|
||||
>
|
||||
<template #icon>
|
||||
<IconConnectors class="size-4 text-foreground-2" />
|
||||
</template>
|
||||
</LayoutSidebarMenuGroupItem>
|
||||
</NuxtLink>
|
||||
|
||||
<NuxtLink :to="tutorialsRoute" @click="isOpenMobile = false">
|
||||
<LayoutSidebarMenuGroupItem
|
||||
label="Tutorials"
|
||||
:active="isActive(tutorialsRoute)"
|
||||
>
|
||||
<template #icon>
|
||||
<IconTutorials class="size-4 text-foreground-2" />
|
||||
</template>
|
||||
</LayoutSidebarMenuGroupItem>
|
||||
</NuxtLink>
|
||||
</LayoutSidebarMenuGroup>
|
||||
|
||||
<LayoutSidebarMenuGroup title="Resources" collapsible>
|
||||
<NuxtLink
|
||||
to="https://speckle.community/"
|
||||
target="_blank"
|
||||
@click="isOpenMobile = false"
|
||||
>
|
||||
<template #icon>
|
||||
<IconProjects class="size-4 text-foreground-2" />
|
||||
</template>
|
||||
</LayoutSidebarMenuGroupItem>
|
||||
</NuxtLink>
|
||||
<LayoutSidebarMenuGroupItem label="Community forum" external>
|
||||
<template #icon>
|
||||
<IconCommunity class="size-4 text-foreground-2" />
|
||||
</template>
|
||||
</LayoutSidebarMenuGroupItem>
|
||||
</NuxtLink>
|
||||
|
||||
<NuxtLink :to="connectorsRoute" @click="isOpenMobile = false">
|
||||
<LayoutSidebarMenuGroupItem
|
||||
label="Connectors"
|
||||
:active="isActive(connectorsRoute)"
|
||||
<div @click="openFeedbackDialog">
|
||||
<LayoutSidebarMenuGroupItem label="Give us feedback">
|
||||
<template #icon>
|
||||
<IconFeedback class="size-4 text-foreground-2" />
|
||||
</template>
|
||||
</LayoutSidebarMenuGroupItem>
|
||||
</div>
|
||||
|
||||
<NuxtLink
|
||||
to="https://speckle.guide/"
|
||||
target="_blank"
|
||||
@click="isOpenMobile = false"
|
||||
>
|
||||
<template #icon>
|
||||
<IconConnectors class="size-4 text-foreground-2" />
|
||||
</template>
|
||||
</LayoutSidebarMenuGroupItem>
|
||||
</NuxtLink>
|
||||
<LayoutSidebarMenuGroupItem label="Documentation" external>
|
||||
<template #icon>
|
||||
<IconDocumentation class="size-4 text-foreground-2" />
|
||||
</template>
|
||||
</LayoutSidebarMenuGroupItem>
|
||||
</NuxtLink>
|
||||
|
||||
<NuxtLink :to="tutorialsRoute" @click="isOpenMobile = false">
|
||||
<LayoutSidebarMenuGroupItem
|
||||
label="Tutorials"
|
||||
:active="isActive(tutorialsRoute)"
|
||||
<NuxtLink
|
||||
to="https://speckle.community/c/making-speckle/changelog"
|
||||
target="_blank"
|
||||
@click="isOpenMobile = false"
|
||||
>
|
||||
<template #icon>
|
||||
<IconTutorials class="size-4 text-foreground-2" />
|
||||
</template>
|
||||
</LayoutSidebarMenuGroupItem>
|
||||
</NuxtLink>
|
||||
</LayoutSidebarMenuGroup>
|
||||
|
||||
<LayoutSidebarMenuGroup title="Resources" collapsible>
|
||||
<NuxtLink
|
||||
to="https://speckle.community/"
|
||||
target="_blank"
|
||||
@click="isOpenMobile = false"
|
||||
>
|
||||
<LayoutSidebarMenuGroupItem label="Community forum" external>
|
||||
<template #icon>
|
||||
<IconCommunity class="size-4 text-foreground-2" />
|
||||
</template>
|
||||
</LayoutSidebarMenuGroupItem>
|
||||
</NuxtLink>
|
||||
|
||||
<div @click="openFeedbackDialog">
|
||||
<LayoutSidebarMenuGroupItem label="Give us feedback">
|
||||
<template #icon>
|
||||
<IconFeedback class="size-4 text-foreground-2" />
|
||||
</template>
|
||||
</LayoutSidebarMenuGroupItem>
|
||||
</div>
|
||||
|
||||
<NuxtLink
|
||||
to="https://speckle.guide/"
|
||||
target="_blank"
|
||||
@click="isOpenMobile = false"
|
||||
>
|
||||
<LayoutSidebarMenuGroupItem label="Documentation" external>
|
||||
<template #icon>
|
||||
<IconDocumentation class="size-4 text-foreground-2" />
|
||||
</template>
|
||||
</LayoutSidebarMenuGroupItem>
|
||||
</NuxtLink>
|
||||
|
||||
<NuxtLink
|
||||
to="https://speckle.community/c/making-speckle/changelog"
|
||||
target="_blank"
|
||||
@click="isOpenMobile = false"
|
||||
>
|
||||
<LayoutSidebarMenuGroupItem label="Changelog" external>
|
||||
<template #icon>
|
||||
<IconChangelog class="size-4 text-foreground-2" />
|
||||
</template>
|
||||
</LayoutSidebarMenuGroupItem>
|
||||
</NuxtLink>
|
||||
</LayoutSidebarMenuGroup>
|
||||
<LayoutSidebarMenuGroupItem label="Changelog" external>
|
||||
<template #icon>
|
||||
<IconChangelog class="size-4 text-foreground-2" />
|
||||
</template>
|
||||
</LayoutSidebarMenuGroupItem>
|
||||
</NuxtLink>
|
||||
</LayoutSidebarMenuGroup>
|
||||
</div>
|
||||
</LayoutSidebarMenu>
|
||||
</LayoutSidebar>
|
||||
</div>
|
||||
@@ -139,15 +143,11 @@ import {
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useActiveUser } from '~~/lib/auth/composables/activeUser'
|
||||
import { useNavigation } from '~~/lib/navigation/composables/navigation'
|
||||
import { TailwindBreakpoints } from '~~/lib/common/helpers/tailwind'
|
||||
import { useBreakpoints } from '@vueuse/core'
|
||||
|
||||
const { isLoggedIn } = useActiveUser()
|
||||
const isWorkspacesEnabled = useIsWorkspacesEnabled()
|
||||
const route = useRoute()
|
||||
const { activeWorkspaceSlug } = useNavigation()
|
||||
const breakpoints = useBreakpoints(TailwindBreakpoints)
|
||||
const isMobile = breakpoints.smaller('lg')
|
||||
|
||||
const isOpenMobile = ref(false)
|
||||
const showFeedbackDialog = ref(false)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<template v-if="activeWorkspaceSlug || isProjectsActive">
|
||||
<div class="relative">
|
||||
<WorkspaceAvatar
|
||||
:size="isMobile ? 'sm' : 'base'"
|
||||
size="base"
|
||||
:name="displayName || ''"
|
||||
:logo="displayLogo"
|
||||
/>
|
||||
@@ -36,7 +36,7 @@
|
||||
leave-to-class="transform opacity-0 scale-95"
|
||||
>
|
||||
<MenuItems
|
||||
class="absolute left-2 lg:left-3 top-12 lg:top-14 w-full lg:w-[17rem] origin-top-right bg-foundation outline outline-1 outline-primary-muted rounded-md shadow-lg overflow-hidden divide-y divide-outline-2"
|
||||
class="absolute left-2 lg:left-3 top-[3.2rem] lg:top-14 w-[17rem] origin-top-right bg-foundation outline outline-1 outline-primary-muted rounded-md shadow-lg overflow-hidden divide-y divide-outline-2"
|
||||
>
|
||||
<HeaderWorkspaceSwitcherHeaderSsoExpired
|
||||
v-if="activeWorkspaceHasExpiredSsoSession"
|
||||
@@ -46,6 +46,7 @@
|
||||
<HeaderWorkspaceSwitcherHeaderWorkspace
|
||||
v-else-if="!!activeWorkspace"
|
||||
:workspace="activeWorkspace"
|
||||
@show-invite-dialog="showInviteDialog = true"
|
||||
/>
|
||||
<div
|
||||
class="p-2 pt-1 max-h-[60vh] lg:max-h-96 overflow-y-auto simple-scrollbar"
|
||||
@@ -100,6 +101,11 @@
|
||||
<WorkspaceDiscoverableWorkspacesModal
|
||||
v-model:open="showDiscoverableWorkspacesModal"
|
||||
/>
|
||||
|
||||
<InviteDialogWorkspace
|
||||
v-model:open="showInviteDialog"
|
||||
:workspace="activeWorkspace"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
@@ -120,15 +126,14 @@ import { graphql } from '~/lib/common/generated/gql'
|
||||
import { useNavigation } from '~~/lib/navigation/composables/navigation'
|
||||
import { Roles, WorkspacePlans } from '@speckle/shared'
|
||||
import type { HeaderWorkspaceSwitcherWorkspaceList_WorkspaceFragment } from '~/lib/common/generated/gql/graphql'
|
||||
import { TailwindBreakpoints } from '~~/lib/common/helpers/tailwind'
|
||||
import { useBreakpoints } from '@vueuse/core'
|
||||
|
||||
graphql(`
|
||||
fragment HeaderWorkspaceSwitcherActiveWorkspace_Workspace on Workspace {
|
||||
...HeaderWorkspaceSwitcherHeaderWorkspace_Workspace
|
||||
...InviteDialogWorkspace_Workspace
|
||||
id
|
||||
name
|
||||
logo
|
||||
...HeaderWorkspaceSwitcherHeaderWorkspace_Workspace
|
||||
}
|
||||
`)
|
||||
|
||||
@@ -184,10 +189,9 @@ const {
|
||||
hasDiscoverableWorkspacesOrJoinRequests
|
||||
} = useDiscoverableWorkspaces()
|
||||
const { hasProjectsToMove } = useActiveUserProjectsToMove()
|
||||
const breakpoints = useBreakpoints(TailwindBreakpoints)
|
||||
const isMobile = breakpoints.smaller('lg')
|
||||
|
||||
const showDiscoverableWorkspacesModal = ref(false)
|
||||
const showInviteDialog = ref(false)
|
||||
|
||||
const activeWorkspace = computed(() => {
|
||||
return activeWorkspaceData.value
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
color="outline"
|
||||
size="sm"
|
||||
:disabled="!isAdmin"
|
||||
@click="showInviteDialog = true"
|
||||
@click="$emit('show-invite-dialog')"
|
||||
>
|
||||
Invite members
|
||||
</FormButton>
|
||||
@@ -44,8 +44,6 @@
|
||||
</div>
|
||||
</template>
|
||||
</HeaderWorkspaceSwitcherHeader>
|
||||
|
||||
<InviteDialogWorkspace v-model:open="showInviteDialog" :workspace="workspace" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -60,7 +58,6 @@ import { formatName } from '~/lib/billing/helpers/plan'
|
||||
|
||||
graphql(`
|
||||
fragment HeaderWorkspaceSwitcherHeaderWorkspace_Workspace on Workspace {
|
||||
...InviteDialogWorkspace_Workspace
|
||||
id
|
||||
name
|
||||
logo
|
||||
@@ -74,13 +71,13 @@ graphql(`
|
||||
}
|
||||
`)
|
||||
|
||||
defineEmits(['show-invite-dialog'])
|
||||
|
||||
const props = defineProps<{
|
||||
workspace: MaybeNullOrUndefined<HeaderWorkspaceSwitcherHeaderWorkspace_WorkspaceFragment>
|
||||
}>()
|
||||
|
||||
const { activeWorkspaceSlug } = useNavigation()
|
||||
|
||||
const showInviteDialog = ref(false)
|
||||
|
||||
const isAdmin = computed(() => props.workspace?.role === Roles.Workspace.Admin)
|
||||
</script>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
class="border-r border-outline-3 px-2 pt-3 pb-2 bg-foundation-page"
|
||||
>
|
||||
<LayoutSidebarMenu>
|
||||
<LayoutSidebarMenuGroup v-if="!isMobile">
|
||||
<LayoutSidebarMenuGroup class="hidden lg:block lg:mb-4">
|
||||
<NuxtLink
|
||||
:to="exitSettingsRoute"
|
||||
class="items-center gap-x-1.5 px-2.5 flex"
|
||||
@@ -33,80 +33,76 @@
|
||||
<p class="text-body-xs font-medium text-foreground">Exit settings</p>
|
||||
</NuxtLink>
|
||||
</LayoutSidebarMenuGroup>
|
||||
<LayoutSidebarMenuGroup title="User settings">
|
||||
<template #title-icon>
|
||||
<IconAccount class="size-4" />
|
||||
</template>
|
||||
<NuxtLink
|
||||
v-for="sidebarMenuItem in userMenuItems"
|
||||
:key="`user-item-${sidebarMenuItem.route}`"
|
||||
:to="sidebarMenuItem.route"
|
||||
@click="isOpenMobile = false"
|
||||
>
|
||||
<LayoutSidebarMenuGroupItem
|
||||
:label="sidebarMenuItem.title"
|
||||
:active="route.path === sidebarMenuItem.route"
|
||||
/>
|
||||
</NuxtLink>
|
||||
</LayoutSidebarMenuGroup>
|
||||
<LayoutSidebarMenuGroup v-if="isAdmin" title="Server settings">
|
||||
<template #title-icon>
|
||||
<IconServer class="size-4" />
|
||||
</template>
|
||||
<NuxtLink
|
||||
v-for="sidebarMenuItem in serverMenuItems"
|
||||
:key="`server-item-${sidebarMenuItem.route}`"
|
||||
:to="sidebarMenuItem.route"
|
||||
@click="isOpenMobile = false"
|
||||
>
|
||||
<LayoutSidebarMenuGroupItem
|
||||
:label="sidebarMenuItem.title"
|
||||
:active="route.path === sidebarMenuItem.route"
|
||||
/>
|
||||
</NuxtLink>
|
||||
</LayoutSidebarMenuGroup>
|
||||
<LayoutSidebarMenuGroup
|
||||
v-if="showWorkspaceSettings"
|
||||
title="Workspace settings"
|
||||
>
|
||||
<template #title-icon>
|
||||
<IconWorkspaces class="size-4" />
|
||||
</template>
|
||||
<template v-if="activeWorkspaceItem">
|
||||
|
||||
<div class="flex flex-col gap-y-2 lg:gap-y-4">
|
||||
<LayoutSidebarMenuGroup title="User settings">
|
||||
<template #title-icon>
|
||||
<IconAccount class="size-4" />
|
||||
</template>
|
||||
<NuxtLink
|
||||
v-for="workspaceMenuItem in workspaceMenuItems"
|
||||
:key="`workspace-menu-item-${workspaceMenuItem.name}-${activeWorkspaceItem}`"
|
||||
v-for="sidebarMenuItem in userMenuItems"
|
||||
:key="`user-item-${sidebarMenuItem.route}`"
|
||||
:to="sidebarMenuItem.route"
|
||||
@click="isOpenMobile = false"
|
||||
>
|
||||
<LayoutSidebarMenuGroupItem
|
||||
:label="sidebarMenuItem.title"
|
||||
:active="route.path === sidebarMenuItem.route"
|
||||
/>
|
||||
</NuxtLink>
|
||||
</LayoutSidebarMenuGroup>
|
||||
<LayoutSidebarMenuGroup v-if="isServerAdmin" title="Server settings">
|
||||
<template #title-icon>
|
||||
<IconServer class="size-4" />
|
||||
</template>
|
||||
<NuxtLink
|
||||
v-for="sidebarMenuItem in serverMenuItems"
|
||||
:key="`server-item-${sidebarMenuItem.route}`"
|
||||
:to="sidebarMenuItem.route"
|
||||
@click="isOpenMobile = false"
|
||||
>
|
||||
<LayoutSidebarMenuGroupItem
|
||||
:label="sidebarMenuItem.title"
|
||||
:active="route.path === sidebarMenuItem.route"
|
||||
/>
|
||||
</NuxtLink>
|
||||
</LayoutSidebarMenuGroup>
|
||||
<LayoutSidebarMenuGroup
|
||||
v-if="showWorkspaceSettings"
|
||||
title="Workspace settings"
|
||||
>
|
||||
<template #title-icon>
|
||||
<IconWorkspaces class="size-4" />
|
||||
</template>
|
||||
|
||||
<NuxtLink
|
||||
v-for="workspaceMenuItem in filteredWorkspaceMenuItems"
|
||||
:key="`workspace-menu-item-${workspaceMenuItem.name}`"
|
||||
:to="
|
||||
!isAdmin &&
|
||||
(workspaceMenuItem.disabled ||
|
||||
needsSsoSession(activeWorkspaceItem, workspaceMenuItem.name))
|
||||
workspaceMenuItem.disabled || needsSsoSession(workspaceMenuItem.name)
|
||||
? undefined
|
||||
: workspaceMenuItem.route(activeWorkspaceItem.slug)
|
||||
: workspaceMenuItem.route(workspace?.slug)
|
||||
"
|
||||
@click="isOpenMobile = false"
|
||||
>
|
||||
<LayoutSidebarMenuGroupItem
|
||||
v-if="workspaceMenuItem.permission?.includes(activeWorkspaceItem.role as WorkspaceRoles)"
|
||||
:label="workspaceMenuItem.title"
|
||||
:active="
|
||||
route.name?.toString().startsWith(workspaceMenuItem.name) &&
|
||||
route.params.slug === activeWorkspaceItem.slug
|
||||
"
|
||||
:active="route.name?.toString().startsWith(workspaceMenuItem.name)"
|
||||
:tooltip-text="
|
||||
needsSsoSession(activeWorkspaceItem, workspaceMenuItem.name)
|
||||
needsSsoSession(workspaceMenuItem.name)
|
||||
? 'Log in with your SSO provider to access this page'
|
||||
: workspaceMenuItem.tooltipText
|
||||
"
|
||||
:disabled="
|
||||
!isAdmin &&
|
||||
!isServerAdmin &&
|
||||
(workspaceMenuItem.disabled ||
|
||||
needsSsoSession(activeWorkspaceItem, workspaceMenuItem.name))
|
||||
needsSsoSession(workspaceMenuItem.name))
|
||||
"
|
||||
class="!pl-8"
|
||||
/>
|
||||
</NuxtLink>
|
||||
</template>
|
||||
</LayoutSidebarMenuGroup>
|
||||
</LayoutSidebarMenuGroup>
|
||||
</div>
|
||||
</LayoutSidebarMenu>
|
||||
</LayoutSidebar>
|
||||
</div>
|
||||
@@ -114,6 +110,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { WorkspaceRoles } from '@speckle/shared'
|
||||
import { useIsWorkspacesEnabled } from '~/composables/globals'
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import { settingsSidebarQuery } from '~/lib/settings/graphql/queries'
|
||||
@@ -126,15 +123,11 @@ import {
|
||||
LayoutSidebarMenuGroup
|
||||
} from '@speckle/ui-components'
|
||||
import { graphql } from '~~/lib/common/generated/gql'
|
||||
import type { WorkspaceRoles } from '@speckle/shared'
|
||||
import {
|
||||
projectsRoute,
|
||||
settingsWorkspaceRoutes,
|
||||
workspaceRoute
|
||||
} from '~/lib/common/helpers/route'
|
||||
import type { SettingsMenu_WorkspaceFragment } from '~/lib/common/generated/gql/graphql'
|
||||
import { TailwindBreakpoints } from '~~/lib/common/helpers/tailwind'
|
||||
import { useBreakpoints } from '@vueuse/core'
|
||||
import { useNavigation } from '~~/lib/navigation/composables/navigation'
|
||||
|
||||
graphql(`
|
||||
@@ -143,67 +136,42 @@ graphql(`
|
||||
id
|
||||
slug
|
||||
role
|
||||
name
|
||||
logo
|
||||
plan {
|
||||
status
|
||||
name
|
||||
}
|
||||
creationState {
|
||||
completed
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
graphql(`
|
||||
fragment SettingsSidebar_User on User {
|
||||
id
|
||||
workspaces {
|
||||
items {
|
||||
...SettingsSidebar_Workspace
|
||||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
const isWorkspacesEnabled = useIsWorkspacesEnabled()
|
||||
const { activeWorkspaceSlug } = useNavigation()
|
||||
const settingsMenuState = useSettingsMenuState()
|
||||
const { isAdmin } = useActiveUser()
|
||||
const { isAdmin: isServerAdmin } = useActiveUser()
|
||||
const route = useRoute()
|
||||
const { result: workspaceResult } = useQuery(settingsSidebarQuery, null, {
|
||||
enabled: computed(() => isWorkspacesEnabled.value)
|
||||
})
|
||||
const { result: workspaceResult } = useQuery(settingsSidebarQuery, null, () => ({
|
||||
enabled: isWorkspacesEnabled.value
|
||||
}))
|
||||
const { userMenuItems, serverMenuItems, workspaceMenuItems } = useSettingsMenu()
|
||||
const breakpoints = useBreakpoints(TailwindBreakpoints)
|
||||
const isMobile = breakpoints.smaller('lg')
|
||||
|
||||
const isOpenMobile = ref(false)
|
||||
|
||||
const workspaceItems = computed(
|
||||
() =>
|
||||
workspaceResult.value?.activeUser?.workspaces.items.filter(
|
||||
(item) => item.creationState?.completed !== false // Removed workspaces that are not completely created
|
||||
) || []
|
||||
)
|
||||
const activeWorkspaceItem = computed(() =>
|
||||
workspaceItems.value.find((item) => item.slug === activeWorkspaceSlug.value)
|
||||
const workspace = computed(() => workspaceResult.value?.activeUser?.activeWorkspace)
|
||||
|
||||
const filteredWorkspaceMenuItems = computed(() =>
|
||||
workspaceMenuItems.value.filter(
|
||||
(item) =>
|
||||
!item.permission ||
|
||||
item.permission.includes(workspace.value?.role as WorkspaceRoles)
|
||||
)
|
||||
)
|
||||
|
||||
const wrapperClasses = computed(() => {
|
||||
return [
|
||||
'absolute z-40 lg:static h-full flex shrink-0 transition-all',
|
||||
`w-[13rem]`,
|
||||
'absolute z-40 lg:static h-full flex shrink-0 transition-all w-[13rem]',
|
||||
isOpenMobile.value ? '' : `-translate-x-[13rem] lg:translate-x-0`
|
||||
]
|
||||
})
|
||||
|
||||
const needsSsoSession = (
|
||||
workspace: SettingsMenu_WorkspaceFragment,
|
||||
routeName?: string
|
||||
) => {
|
||||
return workspace.sso?.provider?.id &&
|
||||
const needsSsoSession = (routeName?: string) => {
|
||||
return workspace.value?.sso?.provider?.id &&
|
||||
routeName !== settingsWorkspaceRoutes.general.name
|
||||
? !workspace.sso?.session?.validUntil
|
||||
? !workspace.value?.sso?.session?.validUntil
|
||||
: false
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
:workspace="workspace"
|
||||
:new-role="newRole"
|
||||
:is-active-user-target-user="isActiveUserTargetUser"
|
||||
:is-only-admin="hasSingleAdmin"
|
||||
:is-only-admin="isLastAdmin"
|
||||
:is-domain-compliant="targetUser.user.workspaceDomainPolicyCompliant"
|
||||
@success="onDialogSuccess"
|
||||
/>
|
||||
@@ -110,7 +110,7 @@ const showMenu = ref(false)
|
||||
const showDialog = ref(false)
|
||||
const dialogType = ref<WorkspaceUserActionTypes>()
|
||||
|
||||
const { hasSingleAdmin } = useWorkspaceLastAdminCheck({
|
||||
const { isLastAdmin } = useWorkspaceLastAdminCheck({
|
||||
workspaceSlug: props.workspace?.slug || ''
|
||||
})
|
||||
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
<template>
|
||||
<div>
|
||||
<LayoutMenu
|
||||
v-model:open="showMenu"
|
||||
:items="menuItems"
|
||||
:menu-position="HorizontalDirection.Left"
|
||||
:menu-id="menuId"
|
||||
@click.stop.prevent
|
||||
@chosen="onActionChosen"
|
||||
>
|
||||
<FormButton
|
||||
color="outline"
|
||||
:class="hideTextOnMobile ? 'hidden sm:block' : ''"
|
||||
@click="showMenu = !showMenu"
|
||||
>
|
||||
<div class="flex items-center gap-1">
|
||||
{{ ctaLabel || 'Add project' }}
|
||||
<ChevronDownIcon class="h-3 w-3" />
|
||||
</div>
|
||||
</FormButton>
|
||||
<FormButton
|
||||
color="outline"
|
||||
:class="hideTextOnMobile ? 'sm:hidden' : 'hidden'"
|
||||
hide-text
|
||||
:icon-left="PlusIcon"
|
||||
@click="showMenu = !showMenu"
|
||||
>
|
||||
Add project
|
||||
</FormButton>
|
||||
</LayoutMenu>
|
||||
<WorkspaceMoveProjectManager v-model:open="showMoveProjectDialog" />
|
||||
<ProjectsAddDialog v-model:open="showNewProjectDialog" />
|
||||
<ClientOnly>
|
||||
<WorkspacePlanProjectModelLimitReachedDialog
|
||||
v-model:open="showLimitDialog"
|
||||
:workspace-name="workspace?.name"
|
||||
:plan="workspace?.plan?.name"
|
||||
:workspace-role="workspace?.role"
|
||||
:workspace-slug="workspaceSlug"
|
||||
/>
|
||||
</ClientOnly>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// TODO: The ClientOnly is to avoid the dialog from being rendered on the server and have hydration sideeffects. These need to be addressed and fixed instead of the ClientOnly
|
||||
import { ChevronDownIcon, PlusIcon } from '@heroicons/vue/24/outline'
|
||||
import type { WorkspaceAddProjectMenu_WorkspaceFragment } from '~/lib/common/generated/gql/graphql'
|
||||
import { HorizontalDirection } from '~~/lib/common/composables/window'
|
||||
import type { LayoutMenuItem } from '~~/lib/layout/helpers/components'
|
||||
import type { MaybeNullOrUndefined } from '@speckle/shared'
|
||||
import { graphql } from '~~/lib/common/generated/gql'
|
||||
|
||||
graphql(`
|
||||
fragment WorkspaceAddProjectMenu_Workspace on Workspace {
|
||||
id
|
||||
name
|
||||
slug
|
||||
role
|
||||
plan {
|
||||
name
|
||||
}
|
||||
permissions {
|
||||
canCreateProject {
|
||||
...FullPermissionCheckResult
|
||||
}
|
||||
canMoveProjectToWorkspace {
|
||||
...FullPermissionCheckResult
|
||||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
enum AddNewProjectActionTypes {
|
||||
NewProject = 'new-project',
|
||||
MoveProject = 'move-project'
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
workspaceSlug: string
|
||||
workspace: MaybeNullOrUndefined<WorkspaceAddProjectMenu_WorkspaceFragment>
|
||||
hideTextOnMobile?: boolean
|
||||
ctaLabel?: string
|
||||
}>()
|
||||
|
||||
const menuId = useId()
|
||||
|
||||
const showMenu = ref(false)
|
||||
const showLimitDialog = ref(false)
|
||||
const showMoveProjectDialog = ref(false)
|
||||
const showNewProjectDialog = ref(false)
|
||||
|
||||
const isLimitReached = computed(() => {
|
||||
return (
|
||||
props.workspace?.permissions.canCreateProject?.code === 'WorkspaceLimitsReached'
|
||||
)
|
||||
})
|
||||
|
||||
const isDisabled = computed(() => {
|
||||
return (
|
||||
!props.workspace?.permissions.canCreateProject?.authorized && !isLimitReached.value
|
||||
)
|
||||
})
|
||||
|
||||
const menuItems = computed<LayoutMenuItem[][]>(() => [
|
||||
[
|
||||
{
|
||||
title: 'Create new project...',
|
||||
id: AddNewProjectActionTypes.NewProject,
|
||||
disabled: isDisabled.value,
|
||||
disabledTooltip: isDisabled.value
|
||||
? props.workspace?.permissions.canCreateProject?.message
|
||||
: undefined
|
||||
},
|
||||
{
|
||||
title: 'Move existing project...',
|
||||
id: AddNewProjectActionTypes.MoveProject,
|
||||
disabled: isDisabled.value,
|
||||
disabledTooltip: isDisabled.value
|
||||
? props.workspace?.permissions.canMoveProjectToWorkspace?.message
|
||||
: undefined
|
||||
}
|
||||
]
|
||||
])
|
||||
|
||||
const onActionChosen = (params: { item: LayoutMenuItem; event: MouseEvent }) => {
|
||||
const { item } = params
|
||||
|
||||
if (isLimitReached.value) {
|
||||
showMoveProjectDialog.value = false
|
||||
showNewProjectDialog.value = false
|
||||
showLimitDialog.value = true
|
||||
return
|
||||
}
|
||||
|
||||
switch (item.id) {
|
||||
case AddNewProjectActionTypes.NewProject:
|
||||
showNewProjectDialog.value = true
|
||||
break
|
||||
case AddNewProjectActionTypes.MoveProject:
|
||||
showMoveProjectDialog.value = true
|
||||
break
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,264 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<Portal to="right-sidebar">
|
||||
<WorkspaceSidebar
|
||||
v-if="workspace"
|
||||
:workspace-info="workspace"
|
||||
@show-invite-dialog="showInviteDialog = true"
|
||||
/>
|
||||
</Portal>
|
||||
<div v-if="workspaceInvite" class="flex justify-center">
|
||||
<WorkspaceInviteBlock :invite="workspaceInvite" />
|
||||
</div>
|
||||
<template v-else>
|
||||
<Portal v-if="workspace?.name" to="navigation">
|
||||
<HeaderNavLink
|
||||
:to="workspaceRoute(workspaceSlug)"
|
||||
name="Projects"
|
||||
:separator="false"
|
||||
/>
|
||||
</Portal>
|
||||
<WorkspaceHeader
|
||||
v-if="workspace"
|
||||
:icon="Squares2X2Icon"
|
||||
:workspace-info="workspace"
|
||||
@show-move-projects-dialog="onMoveProject"
|
||||
@show-new-project-dialog="openNewProject = true"
|
||||
@show-invite-dialog="showInviteDialog = true"
|
||||
/>
|
||||
<div v-if="showSearchBar" class="mt-2 lg:mt-4">
|
||||
<FormTextInput
|
||||
name="modelsearch"
|
||||
:show-label="false"
|
||||
:placeholder="`Search ${projects?.totalCount} ${
|
||||
projects?.totalCount === 1 ? 'project' : 'projects'
|
||||
}...`"
|
||||
:custom-icon="MagnifyingGlassIcon"
|
||||
color="foundation"
|
||||
wrapper-classes="w-full lg:w-60"
|
||||
show-clear
|
||||
v-bind="bind"
|
||||
v-on="on"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<CommonLoadingBar :loading="showLoadingBar" class="my-2" />
|
||||
|
||||
<section
|
||||
v-if="showEmptyState"
|
||||
class="bg-foundation-page h-96 flex flex-col items-center justify-center gap-4"
|
||||
>
|
||||
<WorkspaceEmptyStateIllustration />
|
||||
<span class="text-body-2xs text-foreground-2 text-center">
|
||||
Workspace is empty
|
||||
</span>
|
||||
<WorkspaceHeaderAddProjectMenu
|
||||
button-copy="Add your first project"
|
||||
:workspace-name="workspace?.name || ''"
|
||||
:workspace-slug="workspaceSlug"
|
||||
:workspace-role="workspace?.role"
|
||||
:workspace-plan="workspace?.plan?.name"
|
||||
:can-create-project="canCreateProject"
|
||||
:can-move-project-to-workspace="canMoveProjectToWorkspace"
|
||||
@new-project="openNewProject = true"
|
||||
@move-project="onMoveProject"
|
||||
/>
|
||||
</section>
|
||||
|
||||
<template v-else-if="projects?.items?.length">
|
||||
<ProjectsDashboardFilled :projects="projects" workspace-page />
|
||||
<InfiniteLoading :settings="{ identifier }" @infinite="onInfiniteLoad" />
|
||||
</template>
|
||||
|
||||
<CommonEmptySearchState v-else-if="!showLoadingBar" @clear-search="clearSearch" />
|
||||
|
||||
<ProjectsAddDialog v-model:open="openNewProject" :workspace-id="workspace?.id" />
|
||||
|
||||
<template v-if="workspace">
|
||||
<InviteDialogWorkspace v-model:open="showInviteDialog" :workspace="workspace" />
|
||||
<WorkspaceMoveProjectManager
|
||||
v-model:open="showMoveProjectsDialog"
|
||||
:workspace-slug="workspaceSlug"
|
||||
/>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { MagnifyingGlassIcon, Squares2X2Icon } from '@heroicons/vue/24/outline'
|
||||
import { useQuery, useQueryLoading } from '@vue/apollo-composable'
|
||||
import type { Nullable, Optional, StreamRoles } from '@speckle/shared'
|
||||
import {
|
||||
workspacePageQuery,
|
||||
workspaceProjectsQuery
|
||||
} from '~~/lib/workspaces/graphql/queries'
|
||||
import { useDebouncedTextInput } from '@speckle/ui-components'
|
||||
import { usePaginatedQuery } from '~/lib/common/composables/graphql'
|
||||
import { graphql } from '~~/lib/common/generated/gql'
|
||||
import type { WorkspaceProjectsQueryQueryVariables } from '~~/lib/common/generated/gql/graphql'
|
||||
import { workspaceRoute } from '~/lib/common/helpers/route'
|
||||
import { useBillingActions } from '~/lib/billing/composables/actions'
|
||||
import { useWorkspacesWizard } from '~/lib/workspaces/composables/wizard'
|
||||
import type { WorkspaceWizardState } from '~/lib/workspaces/helpers/types'
|
||||
import { useMixpanel } from '~/lib/core/composables/mp'
|
||||
|
||||
graphql(`
|
||||
fragment WorkspaceProjectList_Workspace on Workspace {
|
||||
id
|
||||
...WorkspaceBase_Workspace
|
||||
...WorkspaceTeam_Workspace
|
||||
...WorkspaceSecurity_Workspace
|
||||
...WorkspaceHeader_Workspace
|
||||
...BillingAlert_Workspace
|
||||
...InviteDialogWorkspace_Workspace
|
||||
projects {
|
||||
...WorkspaceProjectList_ProjectCollection
|
||||
}
|
||||
creationState {
|
||||
completed
|
||||
state
|
||||
}
|
||||
permissions {
|
||||
canCreateProject {
|
||||
...FullPermissionCheckResult
|
||||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
graphql(`
|
||||
fragment WorkspaceProjectList_ProjectCollection on ProjectCollection {
|
||||
totalCount
|
||||
items {
|
||||
...ProjectDashboardItem
|
||||
}
|
||||
cursor
|
||||
}
|
||||
`)
|
||||
|
||||
const props = defineProps<{
|
||||
workspaceSlug: string
|
||||
}>()
|
||||
|
||||
const { validateCheckoutSession } = useBillingActions()
|
||||
const areQueriesLoading = useQueryLoading()
|
||||
const route = useRoute()
|
||||
const {
|
||||
on,
|
||||
bind,
|
||||
value: search
|
||||
} = useDebouncedTextInput({
|
||||
debouncedBy: 800
|
||||
})
|
||||
|
||||
const showMoveProjectsDialog = ref(false)
|
||||
const selectedRoles = ref(undefined as Optional<StreamRoles[]>)
|
||||
const openNewProject = ref(false)
|
||||
const showInviteDialog = ref(false)
|
||||
|
||||
const token = computed(() => route.query.token as Optional<string>)
|
||||
|
||||
const pageFetchPolicy = usePageQueryStandardFetchPolicy()
|
||||
const { result: initialQueryResult, onResult } = useQuery(
|
||||
workspacePageQuery,
|
||||
() => ({
|
||||
workspaceSlug: props.workspaceSlug,
|
||||
token: token.value || null
|
||||
}),
|
||||
() => ({
|
||||
fetchPolicy: pageFetchPolicy.value
|
||||
})
|
||||
)
|
||||
|
||||
const { query, identifier, onInfiniteLoad } = usePaginatedQuery({
|
||||
query: workspaceProjectsQuery,
|
||||
baseVariables: computed(() => ({
|
||||
workspaceSlug: props.workspaceSlug,
|
||||
filter: {
|
||||
search: (search.value || '').trim() || null
|
||||
},
|
||||
cursor: null as Nullable<string>
|
||||
})),
|
||||
resolveKey: (vars: WorkspaceProjectsQueryQueryVariables) => ({
|
||||
workspaceSlug: vars.workspaceSlug,
|
||||
search: vars.filter?.search || ''
|
||||
}),
|
||||
resolveInitialResult: () =>
|
||||
!search.value ? initialQueryResult.value?.workspaceBySlug.projects : undefined,
|
||||
resolveCurrentResult: (result) => result?.workspaceBySlug?.projects,
|
||||
resolveNextPageVariables: (baseVariables, newCursor) => ({
|
||||
...baseVariables,
|
||||
cursor: newCursor
|
||||
}),
|
||||
resolveCursorFromVariables: (vars) => vars.cursor
|
||||
})
|
||||
const { finalizeWizard } = useWorkspacesWizard()
|
||||
|
||||
const canCreateProject = computed(
|
||||
() => initialQueryResult.value?.workspaceBySlug?.permissions.canCreateProject
|
||||
)
|
||||
const canMoveProjectToWorkspace = computed(
|
||||
() => initialQueryResult.value?.workspaceBySlug?.permissions.canMoveProjectToWorkspace
|
||||
)
|
||||
|
||||
const projects = computed(() => query.result.value?.workspaceBySlug?.projects)
|
||||
const workspaceInvite = computed(() => initialQueryResult.value?.workspaceInvite)
|
||||
const workspace = computed(() => initialQueryResult.value?.workspaceBySlug)
|
||||
const showEmptyState = computed(() => {
|
||||
if (search.value) return false
|
||||
|
||||
return projects.value && !projects.value?.items?.length
|
||||
})
|
||||
|
||||
const showLoadingBar = computed(() => {
|
||||
const isLoading = areQueriesLoading.value || (!!search.value && query.loading.value)
|
||||
|
||||
return isLoading
|
||||
})
|
||||
|
||||
const showSearchBar = computed(() => {
|
||||
return projects?.value?.totalCount || search.value
|
||||
})
|
||||
|
||||
const clearSearch = () => {
|
||||
search.value = ''
|
||||
selectedRoles.value = []
|
||||
}
|
||||
|
||||
const hasFinalized = ref(false)
|
||||
|
||||
const mixpanel = useMixpanel()
|
||||
|
||||
const onMoveProject = () => {
|
||||
mixpanel.track('Move Project CTA Clicked', {
|
||||
location: 'workspace',
|
||||
// eslint-disable-next-line camelcase
|
||||
workspace_id: props.workspaceSlug
|
||||
})
|
||||
showMoveProjectsDialog.value = true
|
||||
}
|
||||
|
||||
onResult((queryResult) => {
|
||||
if (
|
||||
queryResult.data?.workspaceBySlug.creationState?.completed === false &&
|
||||
queryResult.data.workspaceBySlug.creationState.state
|
||||
) {
|
||||
if (import.meta.server) return
|
||||
if (hasFinalized.value) return
|
||||
|
||||
hasFinalized.value = true
|
||||
finalizeWizard(
|
||||
queryResult.data.workspaceBySlug.creationState.state as WorkspaceWizardState,
|
||||
queryResult.data.workspaceBySlug.id
|
||||
)
|
||||
}
|
||||
|
||||
if (queryResult.data?.workspaceBySlug) {
|
||||
useHeadSafe({
|
||||
title: queryResult.data.workspaceBySlug.name
|
||||
})
|
||||
validateCheckoutSession(queryResult.data.workspaceBySlug)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<div>
|
||||
<Portal to="navigation">
|
||||
<HeaderNavLink
|
||||
:to="workspaceRoute(workspaceSlug)"
|
||||
name="Projects"
|
||||
:separator="false"
|
||||
/>
|
||||
</Portal>
|
||||
<WorkspaceDashboardHeader
|
||||
:workspace="workspace"
|
||||
:workspace-slug="workspaceSlug"
|
||||
:show-billing-alert="showBillingAlert"
|
||||
/>
|
||||
<WorkspaceDashboardProjectList
|
||||
:workspace-slug="workspaceSlug"
|
||||
:workspace="workspace"
|
||||
class="mt-2 lg:mt-4"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import { Roles, WorkspacePlanStatuses } from '@speckle/shared'
|
||||
import { workspaceDashboardQuery } from '~~/lib/workspaces/graphql/queries'
|
||||
import { graphql } from '~~/lib/common/generated/gql'
|
||||
import { workspaceRoute } from '~/lib/common/helpers/route'
|
||||
import { useWorkspacesWizard } from '~/lib/workspaces/composables/wizard'
|
||||
import type { WorkspaceWizardState } from '~/lib/workspaces/helpers/types'
|
||||
import { useBillingActions } from '~/lib/billing/composables/actions'
|
||||
|
||||
graphql(`
|
||||
fragment WorkspaceDashboard_Workspace on Workspace {
|
||||
...WorkspaceSidebarMembers_Workspace
|
||||
...WorkspaceDashboardHeader_Workspace
|
||||
...WorkspaceDashboardProjectList_Workspace
|
||||
id
|
||||
name
|
||||
role
|
||||
creationState {
|
||||
completed
|
||||
state
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
const props = defineProps<{
|
||||
workspaceSlug: string
|
||||
}>()
|
||||
|
||||
const { validateCheckoutSession } = useBillingActions()
|
||||
const { finalizeWizard } = useWorkspacesWizard()
|
||||
const pageFetchPolicy = usePageQueryStandardFetchPolicy()
|
||||
const { result: workspaceResult, onResult } = useQuery(
|
||||
workspaceDashboardQuery,
|
||||
() => ({
|
||||
workspaceSlug: props.workspaceSlug
|
||||
}),
|
||||
() => ({
|
||||
fetchPolicy: pageFetchPolicy.value
|
||||
})
|
||||
)
|
||||
|
||||
const hasFinalized = ref(false)
|
||||
|
||||
const workspace = computed(() => workspaceResult.value?.workspaceBySlug)
|
||||
const showBillingAlert = computed(
|
||||
() =>
|
||||
workspace?.value?.role === Roles.Workspace.Guest &&
|
||||
(workspace.value?.plan?.status === WorkspacePlanStatuses.PaymentFailed ||
|
||||
workspace.value?.plan?.status === WorkspacePlanStatuses.Canceled ||
|
||||
workspace.value?.plan?.status === WorkspacePlanStatuses.CancelationScheduled)
|
||||
)
|
||||
|
||||
onResult((queryResult) => {
|
||||
if (
|
||||
queryResult.data?.workspaceBySlug.creationState?.completed === false &&
|
||||
queryResult.data.workspaceBySlug.creationState.state &&
|
||||
!hasFinalized.value &&
|
||||
import.meta.client
|
||||
) {
|
||||
hasFinalized.value = true
|
||||
finalizeWizard(
|
||||
queryResult.data.workspaceBySlug.creationState.state as WorkspaceWizardState,
|
||||
queryResult.data.workspaceBySlug.id
|
||||
)
|
||||
}
|
||||
|
||||
if (queryResult.data?.workspaceBySlug) {
|
||||
useHeadSafe({
|
||||
title: queryResult.data.workspaceBySlug.name
|
||||
})
|
||||
validateCheckoutSession(queryResult.data.workspaceBySlug)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<div class="flex flex-col gap-3 lg:gap-4">
|
||||
<div v-if="showBillingAlert">
|
||||
<BillingAlert :workspace="workspace" />
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<div class="flex items-center gap-x-2">
|
||||
<h1 class="text-heading-sm md:text-heading line-clamp-2">
|
||||
Hello, {{ activeUser?.name }}
|
||||
</h1>
|
||||
<CommonBadge
|
||||
v-if="!isWorkspaceMember"
|
||||
rounded
|
||||
color-classes="bg-highlight-3 text-foreground-2"
|
||||
>
|
||||
<span class="capitalize">
|
||||
{{ workspace?.role?.split(':').reverse()[0] }}
|
||||
</span>
|
||||
</CommonBadge>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-1.5 md:gap-2">
|
||||
<WorkspaceAddProjectMenu
|
||||
:workspace-slug="workspaceSlug"
|
||||
:workspace="workspace"
|
||||
hide-text-on-mobile
|
||||
/>
|
||||
<FormButton
|
||||
color="outline"
|
||||
:icon-left="Cog8ToothIcon"
|
||||
hide-text
|
||||
@click="navigateTo(settingsWorkspaceRoutes.general.route(workspace?.slug))"
|
||||
>
|
||||
Settings
|
||||
</FormButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="lg:hidden mb-2">
|
||||
<WorkspaceSidebarMembers
|
||||
:workspace="workspace"
|
||||
:is-workspace-admin="isWorkspaceAdmin"
|
||||
:is-workspace-guest="isWorkspaceGuest"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { graphql } from '~~/lib/common/generated/gql'
|
||||
import type { WorkspaceDashboardHeader_WorkspaceFragment } from '~~/lib/common/generated/gql/graphql'
|
||||
import { Cog8ToothIcon } from '@heroicons/vue/24/outline'
|
||||
import { Roles, type MaybeNullOrUndefined } from '@speckle/shared'
|
||||
import { settingsWorkspaceRoutes } from '~/lib/common/helpers/route'
|
||||
|
||||
graphql(`
|
||||
fragment WorkspaceDashboardHeader_Workspace on Workspace {
|
||||
...WorkspaceSidebarMembers_Workspace
|
||||
...WorkspaceAddProjectMenu_Workspace
|
||||
...BillingAlert_Workspace
|
||||
id
|
||||
role
|
||||
plan {
|
||||
status
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
const props = defineProps<{
|
||||
workspaceSlug: string
|
||||
workspace: MaybeNullOrUndefined<WorkspaceDashboardHeader_WorkspaceFragment>
|
||||
showBillingAlert?: boolean
|
||||
}>()
|
||||
|
||||
const { activeUser } = useActiveUser()
|
||||
|
||||
const isWorkspaceAdmin = computed(() => props.workspace?.role === Roles.Workspace.Admin)
|
||||
const isWorkspaceGuest = computed(() => props.workspace?.role === Roles.Workspace.Guest)
|
||||
const isWorkspaceMember = computed(
|
||||
() => props.workspace?.role === Roles.Workspace.Member
|
||||
)
|
||||
</script>
|
||||
@@ -0,0 +1,124 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="showSearchBar">
|
||||
<FormTextInput
|
||||
name="modelsearch"
|
||||
:show-label="false"
|
||||
:placeholder="`Search ${projects?.totalCount} ${
|
||||
projects?.totalCount === 1 ? 'project' : 'projects'
|
||||
}...`"
|
||||
:custom-icon="MagnifyingGlassIcon"
|
||||
color="foundation"
|
||||
wrapper-classes="w-full lg:w-60"
|
||||
show-clear
|
||||
v-bind="bind"
|
||||
v-on="on"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<CommonLoadingBar :loading="showLoadingBar" class="my-2" />
|
||||
|
||||
<section
|
||||
v-if="showEmptyState"
|
||||
class="bg-foundation-page h-96 flex flex-col items-center justify-center gap-4"
|
||||
>
|
||||
<WorkspaceEmptyStateIllustration />
|
||||
<span class="text-body-2xs text-foreground-2 text-center">
|
||||
Workspace is empty
|
||||
</span>
|
||||
<WorkspaceAddProjectMenu
|
||||
:workspace="workspace"
|
||||
:workspace-slug="workspaceSlug"
|
||||
cta-label="Add your first project"
|
||||
/>
|
||||
</section>
|
||||
|
||||
<section v-else-if="projects?.items?.length">
|
||||
<ProjectsDashboardFilled :projects="projects" workspace-page />
|
||||
<InfiniteLoading :settings="{ identifier }" @infinite="onInfiniteLoad" />
|
||||
</section>
|
||||
|
||||
<CommonEmptySearchState v-else-if="!showLoadingBar" @clear-search="clearSearch" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { MagnifyingGlassIcon } from '@heroicons/vue/24/outline'
|
||||
import type { MaybeNullOrUndefined, Nullable } from '@speckle/shared'
|
||||
import { workspaceProjectsQuery } from '~~/lib/workspaces/graphql/queries'
|
||||
import { useDebouncedTextInput } from '@speckle/ui-components'
|
||||
import { usePaginatedQuery } from '~/lib/common/composables/graphql'
|
||||
import { graphql } from '~~/lib/common/generated/gql'
|
||||
import type {
|
||||
WorkspaceProjectsQueryQueryVariables,
|
||||
WorkspaceDashboardProjectList_WorkspaceFragment
|
||||
} from '~~/lib/common/generated/gql/graphql'
|
||||
|
||||
graphql(`
|
||||
fragment WorkspaceDashboardProjectList_ProjectCollection on ProjectCollection {
|
||||
totalCount
|
||||
items {
|
||||
...ProjectDashboardItem
|
||||
}
|
||||
cursor
|
||||
}
|
||||
`)
|
||||
|
||||
graphql(`
|
||||
fragment WorkspaceDashboardProjectList_Workspace on Workspace {
|
||||
...WorkspaceAddProjectMenu_Workspace
|
||||
id
|
||||
}
|
||||
`)
|
||||
|
||||
const props = defineProps<{
|
||||
workspaceSlug: string
|
||||
workspace: MaybeNullOrUndefined<WorkspaceDashboardProjectList_WorkspaceFragment>
|
||||
}>()
|
||||
|
||||
const {
|
||||
on,
|
||||
bind,
|
||||
value: search
|
||||
} = useDebouncedTextInput({
|
||||
debouncedBy: 800
|
||||
})
|
||||
|
||||
const {
|
||||
query: projectsQuery,
|
||||
identifier,
|
||||
onInfiniteLoad
|
||||
} = usePaginatedQuery({
|
||||
query: workspaceProjectsQuery,
|
||||
baseVariables: computed(() => ({
|
||||
workspaceSlug: props.workspaceSlug,
|
||||
filter: {
|
||||
search: (search.value || '').trim() || null
|
||||
},
|
||||
cursor: null as Nullable<string>
|
||||
})),
|
||||
resolveKey: (vars: WorkspaceProjectsQueryQueryVariables) => ({
|
||||
workspaceSlug: vars.workspaceSlug,
|
||||
search: vars.filter?.search || ''
|
||||
}),
|
||||
resolveCurrentResult: (result) => result?.workspaceBySlug?.projects,
|
||||
resolveNextPageVariables: (baseVariables, newCursor) => ({
|
||||
...baseVariables,
|
||||
cursor: newCursor
|
||||
}),
|
||||
resolveCursorFromVariables: (vars) => vars.cursor
|
||||
})
|
||||
|
||||
const projects = computed(() => projectsQuery.result.value?.workspaceBySlug?.projects)
|
||||
const showSearchBar = computed(() => {
|
||||
return projects?.value?.totalCount || search.value
|
||||
})
|
||||
const showLoadingBar = computed(() => projectsQuery.loading.value)
|
||||
const showEmptyState = computed(() =>
|
||||
search.value ? false : projects.value && !projects.value?.items?.length
|
||||
)
|
||||
|
||||
const clearSearch = () => {
|
||||
search.value = ''
|
||||
}
|
||||
</script>
|
||||
@@ -1,119 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<LayoutMenu
|
||||
v-model:open="showMenu"
|
||||
:items="menuItems"
|
||||
:menu-position="HorizontalDirection.Left"
|
||||
:menu-id="menuId"
|
||||
@click.stop.prevent
|
||||
@chosen="onActionChosen"
|
||||
>
|
||||
<FormButton
|
||||
color="outline"
|
||||
:class="hideTextOnMobile ? 'hidden md:block' : ''"
|
||||
@click="showMenu = !showMenu"
|
||||
>
|
||||
<div class="flex items-center gap-1">
|
||||
{{ buttonCopy || 'Add project' }}
|
||||
<ChevronDownIcon class="h-3 w-3" />
|
||||
</div>
|
||||
</FormButton>
|
||||
<FormButton
|
||||
color="outline"
|
||||
:class="hideTextOnMobile ? 'md:hidden' : 'hidden'"
|
||||
hide-text
|
||||
:icon-left="PlusIcon"
|
||||
@click="showMenu = !showMenu"
|
||||
>
|
||||
Add project
|
||||
</FormButton>
|
||||
</LayoutMenu>
|
||||
<WorkspacePlanProjectModelLimitReachedDialog
|
||||
v-model:open="showLimitDialog"
|
||||
:workspace-name="props.workspaceName"
|
||||
:plan="props.workspacePlan"
|
||||
:workspace-role="props.workspaceRole"
|
||||
:workspace-slug="props.workspaceSlug"
|
||||
location="add project menu"
|
||||
limit-type="project"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ChevronDownIcon, PlusIcon } from '@heroicons/vue/24/outline'
|
||||
import type { FullPermissionCheckResultFragment } from '~/lib/common/generated/gql/graphql'
|
||||
import { HorizontalDirection } from '~~/lib/common/composables/window'
|
||||
import type { LayoutMenuItem } from '~~/lib/layout/helpers/components'
|
||||
import type { MaybeNullOrUndefined, WorkspacePlans } from '@speckle/shared'
|
||||
|
||||
enum AddNewProjectActionTypes {
|
||||
NewProject = 'new-project',
|
||||
MoveProject = 'move-project'
|
||||
}
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'new-project'): void
|
||||
(e: 'move-project'): void
|
||||
}>()
|
||||
|
||||
const props = defineProps<{
|
||||
workspaceName: string
|
||||
workspaceSlug: string
|
||||
workspacePlan?: WorkspacePlans
|
||||
hideTextOnMobile?: boolean
|
||||
buttonCopy?: string
|
||||
canCreateProject: FullPermissionCheckResultFragment | undefined
|
||||
canMoveProjectToWorkspace: FullPermissionCheckResultFragment | undefined
|
||||
workspaceRole: MaybeNullOrUndefined<string>
|
||||
}>()
|
||||
|
||||
const menuId = useId()
|
||||
const showMenu = ref(false)
|
||||
const showLimitDialog = ref(false)
|
||||
|
||||
const menuItems = computed<LayoutMenuItem[][]>(() => [
|
||||
[
|
||||
{
|
||||
title: 'Create new project...',
|
||||
id: AddNewProjectActionTypes.NewProject,
|
||||
disabled: isDisabled.value,
|
||||
disabledTooltip: isDisabled.value ? props.canCreateProject?.message : undefined
|
||||
},
|
||||
{
|
||||
title: 'Move existing project...',
|
||||
id: AddNewProjectActionTypes.MoveProject,
|
||||
disabled: isDisabled.value,
|
||||
disabledTooltip: isDisabled.value
|
||||
? props.canMoveProjectToWorkspace?.message
|
||||
: undefined
|
||||
}
|
||||
]
|
||||
])
|
||||
|
||||
const onActionChosen = (params: { item: LayoutMenuItem; event: MouseEvent }) => {
|
||||
const { item } = params
|
||||
|
||||
if (isLimitReached.value) {
|
||||
showLimitDialog.value = true
|
||||
return
|
||||
}
|
||||
|
||||
switch (item.id) {
|
||||
case AddNewProjectActionTypes.NewProject:
|
||||
emit('new-project')
|
||||
break
|
||||
case AddNewProjectActionTypes.MoveProject:
|
||||
emit('move-project')
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const isLimitReached = computed(() => {
|
||||
return props.canCreateProject?.code === 'WorkspaceLimitsReached'
|
||||
})
|
||||
|
||||
const isDisabled = computed(() => {
|
||||
return !props.canCreateProject?.authorized && !isLimitReached.value
|
||||
})
|
||||
</script>
|
||||
@@ -1,125 +0,0 @@
|
||||
<template>
|
||||
<div class="flex flex-col gap-3 lg:gap-4">
|
||||
<div v-if="!isWorkspaceGuest && showBillingAlert">
|
||||
<BillingAlert :workspace="workspaceInfo" />
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<div class="flex items-center gap-x-2">
|
||||
<h1 class="text-heading-sm md:text-heading line-clamp-2">
|
||||
Hello, {{ activeUser?.name }}
|
||||
</h1>
|
||||
<CommonBadge
|
||||
v-if="!isWorkspaceMember"
|
||||
rounded
|
||||
color-classes="bg-highlight-3 text-foreground-2"
|
||||
>
|
||||
<span class="capitalize">
|
||||
{{ workspaceInfo.role?.split(':').reverse()[0] }}
|
||||
</span>
|
||||
</CommonBadge>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-1.5 md:gap-2">
|
||||
<WorkspaceHeaderAddProjectMenu
|
||||
:workspace-name="workspaceInfo.name"
|
||||
:workspace-slug="workspaceInfo.slug"
|
||||
:workspace-role="workspaceInfo.role"
|
||||
:workspace-plan="
|
||||
workspaceInfo.plan?.name ? workspaceInfo.plan?.name : undefined
|
||||
"
|
||||
hide-text-on-mobile
|
||||
:can-create-project="canCreateProject"
|
||||
:can-move-project-to-workspace="canMoveProjectToWorkspace"
|
||||
@new-project="$emit('show-new-project-dialog')"
|
||||
@move-project="$emit('show-move-projects-dialog')"
|
||||
/>
|
||||
|
||||
<FormButton
|
||||
color="outline"
|
||||
:icon-left="Cog8ToothIcon"
|
||||
hide-text
|
||||
@click="navigateTo(settingsWorkspaceRoutes.general.route(workspaceInfo.slug))"
|
||||
>
|
||||
Settings
|
||||
</FormButton>
|
||||
<ClientOnly>
|
||||
<PortalTarget name="workspace-sidebar-toggle"></PortalTarget>
|
||||
</ClientOnly>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="lg:hidden mb-2">
|
||||
<WorkspaceSidebarMembers
|
||||
v-if="!isWorkspaceGuest"
|
||||
:workspace-info="workspaceInfo"
|
||||
:is-workspace-admin="isWorkspaceAdmin"
|
||||
:is-workspace-guest="isWorkspaceGuest"
|
||||
@show-invite-dialog="$emit('show-invite-dialog')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { graphql } from '~~/lib/common/generated/gql'
|
||||
import {
|
||||
WorkspacePlanStatuses,
|
||||
type WorkspaceHeader_WorkspaceFragment
|
||||
} from '~~/lib/common/generated/gql/graphql'
|
||||
import { Cog8ToothIcon } from '@heroicons/vue/24/outline'
|
||||
import { Roles } from '@speckle/shared'
|
||||
import { settingsWorkspaceRoutes } from '~/lib/common/helpers/route'
|
||||
|
||||
graphql(`
|
||||
fragment WorkspaceHeader_Workspace on Workspace {
|
||||
...WorkspaceBase_Workspace
|
||||
...WorkspaceTeam_Workspace
|
||||
...BillingAlert_Workspace
|
||||
slug
|
||||
readOnly
|
||||
permissions {
|
||||
canCreateProject {
|
||||
...FullPermissionCheckResult
|
||||
}
|
||||
canMoveProjectToWorkspace {
|
||||
...FullPermissionCheckResult
|
||||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
defineEmits<{
|
||||
(e: 'show-move-projects-dialog'): void
|
||||
(e: 'show-new-project-dialog'): void
|
||||
(e: 'show-invite-dialog'): void
|
||||
}>()
|
||||
|
||||
const props = defineProps<{
|
||||
workspaceInfo: WorkspaceHeader_WorkspaceFragment
|
||||
}>()
|
||||
|
||||
const { activeUser } = useActiveUser()
|
||||
|
||||
const isWorkspaceAdmin = computed(
|
||||
() => props.workspaceInfo.role === Roles.Workspace.Admin
|
||||
)
|
||||
const isWorkspaceGuest = computed(
|
||||
() => props.workspaceInfo.role === Roles.Workspace.Guest
|
||||
)
|
||||
const isWorkspaceMember = computed(
|
||||
() => props.workspaceInfo.role === Roles.Workspace.Member
|
||||
)
|
||||
|
||||
const canCreateProject = computed(
|
||||
() => props.workspaceInfo.permissions.canCreateProject
|
||||
)
|
||||
const canMoveProjectToWorkspace = computed(
|
||||
() => props.workspaceInfo.permissions.canMoveProjectToWorkspace
|
||||
)
|
||||
const showBillingAlert = computed(
|
||||
() =>
|
||||
props.workspaceInfo.plan?.status === WorkspacePlanStatuses.PaymentFailed ||
|
||||
props.workspaceInfo.plan?.status === WorkspacePlanStatuses.Canceled ||
|
||||
props.workspaceInfo.plan?.status === WorkspacePlanStatuses.CancelationScheduled
|
||||
)
|
||||
</script>
|
||||
@@ -16,7 +16,7 @@ import type { MaybeNullOrUndefined, WorkspacePlans } from '@speckle/shared'
|
||||
import { Roles } from '@speckle/shared'
|
||||
import type { LayoutDialogButton } from '@speckle/ui-components'
|
||||
import { settingsWorkspaceRoutes } from '~/lib/common/helpers/route'
|
||||
import { useWorkspaceLimits } from '~/lib/workspaces/composables/limits'
|
||||
import { useWorkspaceUsage } from '~/lib/workspaces/composables/usage'
|
||||
import { formatName } from '~/lib/billing/helpers/plan'
|
||||
import { useMixpanel } from '~/lib/core/composables/mp'
|
||||
|
||||
@@ -24,13 +24,13 @@ const props = defineProps<{
|
||||
workspaceSlug: string
|
||||
workspaceName?: string
|
||||
workspaceRole?: MaybeNullOrUndefined<string>
|
||||
plan?: WorkspacePlans
|
||||
plan?: MaybeNullOrUndefined<WorkspacePlans>
|
||||
type?: 'version' | 'model'
|
||||
location?: string
|
||||
}>()
|
||||
|
||||
const mixpanel = useMixpanel()
|
||||
const { modelCount, projectCount } = useWorkspaceLimits(props.workspaceSlug)
|
||||
const { modelCount, projectCount } = useWorkspaceUsage(props.workspaceSlug)
|
||||
|
||||
const dialogOpen = defineModel<boolean>('open', {
|
||||
required: true
|
||||
|
||||
@@ -1,47 +1,53 @@
|
||||
<template>
|
||||
<LayoutSidebarMenuGroup
|
||||
:title="collapsible ? 'About' : undefined"
|
||||
:collapsible="collapsible"
|
||||
:icon="iconName"
|
||||
:icon-click="iconClick"
|
||||
:icon-text="iconText"
|
||||
no-hover
|
||||
>
|
||||
<div class="flex flex-col gap-4 text-body-2xs text-foreground-2 pb-0 lg:pb-4 mt-1">
|
||||
<div v-if="isEditing">
|
||||
<FormTextArea
|
||||
v-model="editedDescription"
|
||||
color="foundation"
|
||||
size="sm"
|
||||
name="Workspace description"
|
||||
placeholder="Workspace description"
|
||||
:rules="[isStringOfLength({ maxLength: 512 })]"
|
||||
validate-on-value-update
|
||||
@keyup.enter="saveDescription"
|
||||
@keyup.esc="cancelEdit"
|
||||
/>
|
||||
<div class="flex gap-1 mt-2">
|
||||
<FormButton size="sm" color="primary" @click="saveDescription">
|
||||
Save
|
||||
<div class="px-4 py-2">
|
||||
<LayoutSidebarMenuGroup
|
||||
title="About"
|
||||
collapsible
|
||||
:icon="iconName"
|
||||
:icon-click="iconClick"
|
||||
:icon-text="iconText"
|
||||
no-hover
|
||||
>
|
||||
<div
|
||||
class="flex flex-col gap-4 text-body-2xs text-foreground-2 pb-0 lg:pb-4 mt-1"
|
||||
>
|
||||
<div v-if="isEditing">
|
||||
<FormTextArea
|
||||
v-model="editedDescription"
|
||||
color="foundation"
|
||||
size="sm"
|
||||
name="Workspace description"
|
||||
placeholder="Workspace description"
|
||||
:rules="[isStringOfLength({ maxLength: 512 })]"
|
||||
validate-on-value-update
|
||||
@keyup.enter="saveDescription"
|
||||
@keyup.esc="cancelEdit"
|
||||
/>
|
||||
<div class="flex gap-1 mt-2">
|
||||
<FormButton size="sm" color="primary" @click="saveDescription">
|
||||
Save
|
||||
</FormButton>
|
||||
<FormButton size="sm" color="outline" @click="cancelEdit">
|
||||
Cancel
|
||||
</FormButton>
|
||||
</div>
|
||||
</div>
|
||||
<template v-else>
|
||||
<div class="whitespace-pre-wrap">
|
||||
{{ workspace?.description || 'No workspace description' }}
|
||||
</div>
|
||||
<FormButton
|
||||
v-if="!workspace?.description && isWorkspaceAdmin"
|
||||
color="outline"
|
||||
size="sm"
|
||||
@click="startEdit"
|
||||
>
|
||||
Add description
|
||||
</FormButton>
|
||||
<FormButton size="sm" color="outline" @click="cancelEdit">Cancel</FormButton>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<template v-else>
|
||||
<div class="whitespace-pre-wrap">
|
||||
{{ workspaceInfo.description || 'No workspace description' }}
|
||||
</div>
|
||||
<FormButton
|
||||
v-if="!workspaceInfo.description && isWorkspaceAdmin"
|
||||
color="outline"
|
||||
size="sm"
|
||||
@click="startEdit"
|
||||
>
|
||||
Add description
|
||||
</FormButton>
|
||||
</template>
|
||||
</div>
|
||||
</LayoutSidebarMenuGroup>
|
||||
</LayoutSidebarMenuGroup>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -56,16 +62,18 @@ import {
|
||||
import { isStringOfLength } from '~~/lib/common/helpers/validation'
|
||||
import type { WorkspaceSidebarAbout_WorkspaceFragment } from '~/lib/common/generated/gql/graphql'
|
||||
import { useMixpanel } from '~/lib/core/composables/mp'
|
||||
import type { MaybeNullOrUndefined } from '@speckle/shared'
|
||||
|
||||
graphql(`
|
||||
fragment WorkspaceSidebarAbout_Workspace on Workspace {
|
||||
...WorkspaceDashboardAbout_Workspace
|
||||
id
|
||||
name
|
||||
description
|
||||
}
|
||||
`)
|
||||
|
||||
const props = defineProps<{
|
||||
workspaceInfo: WorkspaceSidebarAbout_WorkspaceFragment
|
||||
collapsible?: boolean
|
||||
workspace: MaybeNullOrUndefined<WorkspaceSidebarAbout_WorkspaceFragment>
|
||||
isWorkspaceAdmin?: boolean
|
||||
}>()
|
||||
|
||||
@@ -79,7 +87,7 @@ const editedDescription = ref('')
|
||||
const iconName = computed(() => {
|
||||
if (!props.isWorkspaceAdmin) return undefined
|
||||
if (isEditing.value) return undefined
|
||||
return props.workspaceInfo.description ? 'edit' : 'add'
|
||||
return props.workspace?.description ? 'edit' : 'add'
|
||||
})
|
||||
|
||||
const iconClick = computed(() => {
|
||||
@@ -91,11 +99,11 @@ const iconClick = computed(() => {
|
||||
const iconText = computed(() => {
|
||||
if (!props.isWorkspaceAdmin) return undefined
|
||||
if (isEditing.value) return undefined
|
||||
return props.workspaceInfo.description ? 'Edit description' : 'Add description'
|
||||
return props.workspace?.description ? 'Edit description' : 'Add description'
|
||||
})
|
||||
|
||||
const startEdit = () => {
|
||||
editedDescription.value = props.workspaceInfo.description || ''
|
||||
editedDescription.value = props.workspace?.description || ''
|
||||
isEditing.value = true
|
||||
}
|
||||
|
||||
@@ -105,9 +113,11 @@ const cancelEdit = () => {
|
||||
}
|
||||
|
||||
const saveDescription = async () => {
|
||||
if (!props.workspace?.id) return
|
||||
|
||||
const result = await updateMutation({
|
||||
input: {
|
||||
id: props.workspaceInfo.id,
|
||||
id: props.workspace?.id,
|
||||
description: editedDescription.value
|
||||
}
|
||||
}).catch(convertThrowIntoFetchResult)
|
||||
@@ -120,7 +130,7 @@ const saveDescription = async () => {
|
||||
mixpanel.track('Workspace General Settings Updated', {
|
||||
fields: ['description'],
|
||||
// eslint-disable-next-line camelcase
|
||||
workspace_id: props.workspaceInfo.id,
|
||||
workspace_id: props.workspace?.id,
|
||||
source: 'sidebar'
|
||||
})
|
||||
isEditing.value = false
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<template>
|
||||
<div class="p-4">
|
||||
<div
|
||||
class="p-2 pl-3 bg-info-lighter rounded-md flex items-center justify-between gap-x-2"
|
||||
>
|
||||
<p class="text-primary-focus text-body-3xs font-semibold dark:text-foreground">
|
||||
You're on a free plan.
|
||||
</p>
|
||||
<FormButton
|
||||
size="sm"
|
||||
@click="navigateTo(settingsWorkspaceRoutes.billing.route(slug))"
|
||||
>
|
||||
Upgrade
|
||||
</FormButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { settingsWorkspaceRoutes } from '~/lib/common/helpers/route'
|
||||
|
||||
defineProps<{
|
||||
slug: string
|
||||
}>()
|
||||
</script>
|
||||
@@ -1,96 +1,130 @@
|
||||
<template>
|
||||
<LayoutSidebarMenuGroup
|
||||
:title="collapsible ? 'Members' : undefined"
|
||||
:collapsible="collapsible"
|
||||
:icon="iconName"
|
||||
:icon-click="iconClick"
|
||||
:icon-text="iconText"
|
||||
no-hover
|
||||
>
|
||||
<div class="flex lg:flex-col items-center lg:items-start gap-y-3 pb-0 lg:pb-4 mt-1">
|
||||
<div class="flex gap-y-3 flex-col w-full">
|
||||
<UserAvatarGroup
|
||||
:overlap="false"
|
||||
:users="team.map((teamMember) => teamMember.user)"
|
||||
:max-avatars="isDesktop ? 5 : 3"
|
||||
class="shrink-0"
|
||||
:on-hidden-count-click="
|
||||
() => {
|
||||
navigateTo(settingsWorkspaceRoutes.members.route(workspaceInfo.slug))
|
||||
}
|
||||
"
|
||||
/>
|
||||
<div class="w-full flex items-center gap-x-2">
|
||||
<button
|
||||
v-if="adminWorkspacesJoinRequestsCount && isWorkspaceAdmin"
|
||||
class="hidden md:flex items-center shrink-0 justify-center text-body-3xs px-2 h-8 rounded-full border border-dashed border-outline-2 hover:bg-foundation select-none"
|
||||
@click="
|
||||
navigateTo(
|
||||
settingsWorkspaceRoutes.membersRequests.route(workspaceInfo.slug)
|
||||
)
|
||||
"
|
||||
>
|
||||
{{ adminWorkspacesJoinRequestsCount }} join
|
||||
{{ adminWorkspacesJoinRequestsCount > 1 ? 'requests' : 'request' }}
|
||||
</button>
|
||||
<button
|
||||
v-if="invitedTeamCount && isWorkspaceAdmin"
|
||||
class="hidden md:flex items-center shrink-0 justify-center text-body-3xs px-2 h-8 rounded-full border border-dashed border-outline-2 hover:bg-foundation select-none"
|
||||
@click="
|
||||
navigateTo(
|
||||
settingsWorkspaceRoutes.membersInvites.route(workspaceInfo.slug)
|
||||
)
|
||||
"
|
||||
>
|
||||
{{ invitedTeamCount }} pending
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<FormButton
|
||||
v-if="isWorkspaceAdmin"
|
||||
color="outline"
|
||||
size="sm"
|
||||
@click="$emit('show-invite-dialog')"
|
||||
<div class="lg:px-4 lg:py-2">
|
||||
<LayoutSidebarMenuGroup
|
||||
:title="collapsible ? 'Members' : undefined"
|
||||
:collapsible="collapsible"
|
||||
:icon="iconName"
|
||||
:icon-click="iconClick"
|
||||
:icon-text="iconText"
|
||||
no-hover
|
||||
>
|
||||
<div
|
||||
class="flex lg:flex-col items-center lg:items-start gap-y-3 pb-0 lg:pb-4 mt-1"
|
||||
>
|
||||
Invite your team
|
||||
</FormButton>
|
||||
</div>
|
||||
</LayoutSidebarMenuGroup>
|
||||
<div class="flex gap-y-3 flex-col w-full">
|
||||
<UserAvatarGroup
|
||||
:overlap="false"
|
||||
:users="team.map((teamMember) => teamMember.user)"
|
||||
:max-avatars="5"
|
||||
class="shrink-0"
|
||||
:on-hidden-count-click="
|
||||
() => {
|
||||
navigateTo(settingsWorkspaceRoutes.members.route(workspace?.slug || ''))
|
||||
}
|
||||
"
|
||||
/>
|
||||
<div
|
||||
v-if="
|
||||
isWorkspaceAdmin && (adminWorkspacesJoinRequestsCount || invitedTeamCount)
|
||||
"
|
||||
class="w-full flex items-center gap-x-2"
|
||||
>
|
||||
<button
|
||||
v-if="adminWorkspacesJoinRequestsCount"
|
||||
class="hidden md:flex items-center shrink-0 justify-center text-body-3xs px-2 h-8 rounded-full border border-dashed border-outline-2 hover:bg-foundation select-none"
|
||||
@click="
|
||||
navigateTo(
|
||||
settingsWorkspaceRoutes.membersRequests.route(workspace?.slug || '')
|
||||
)
|
||||
"
|
||||
>
|
||||
{{ adminWorkspacesJoinRequestsCount }} join
|
||||
{{ adminWorkspacesJoinRequestsCount > 1 ? 'requests' : 'request' }}
|
||||
</button>
|
||||
<button
|
||||
v-if="invitedTeamCount"
|
||||
class="hidden md:flex items-center shrink-0 justify-center text-body-3xs px-2 h-8 rounded-full border border-dashed border-outline-2 hover:bg-foundation select-none"
|
||||
@click="
|
||||
navigateTo(
|
||||
settingsWorkspaceRoutes.membersInvites.route(workspace?.slug || '')
|
||||
)
|
||||
"
|
||||
>
|
||||
{{ invitedTeamCount }} pending
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<FormButton
|
||||
v-if="isWorkspaceAdmin"
|
||||
color="outline"
|
||||
size="sm"
|
||||
@click="showInviteDialog = true"
|
||||
>
|
||||
Invite your team
|
||||
</FormButton>
|
||||
</div>
|
||||
</LayoutSidebarMenuGroup>
|
||||
<InviteDialogWorkspace v-model:open="showInviteDialog" :workspace="workspace" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
type WorkspaceTeam_WorkspaceFragment,
|
||||
type WorkspaceSidebarMembers_WorkspaceFragment,
|
||||
WorkspaceJoinRequestStatus
|
||||
} from '~/lib/common/generated/gql/graphql'
|
||||
import { settingsWorkspaceRoutes } from '~/lib/common/helpers/route'
|
||||
import { TailwindBreakpoints } from '~~/lib/common/helpers/tailwind'
|
||||
import { useBreakpoints } from '@vueuse/core'
|
||||
import { graphql } from '~~/lib/common/generated/gql'
|
||||
import type { MaybeNullOrUndefined } from '@speckle/shared'
|
||||
|
||||
defineEmits<{
|
||||
(e: 'show-invite-dialog'): void
|
||||
}>()
|
||||
graphql(`
|
||||
fragment WorkspaceSidebarMembers_Workspace on Workspace {
|
||||
...InviteDialogWorkspace_Workspace
|
||||
id
|
||||
slug
|
||||
team {
|
||||
totalCount
|
||||
items {
|
||||
id
|
||||
user {
|
||||
id
|
||||
name
|
||||
...LimitedUserAvatar
|
||||
}
|
||||
}
|
||||
}
|
||||
invitedTeam(filter: $invitesFilter) {
|
||||
id
|
||||
role
|
||||
email
|
||||
}
|
||||
adminWorkspacesJoinRequests {
|
||||
totalCount
|
||||
items {
|
||||
status
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
const props = defineProps<{
|
||||
workspaceInfo: WorkspaceTeam_WorkspaceFragment
|
||||
workspace: MaybeNullOrUndefined<WorkspaceSidebarMembers_WorkspaceFragment>
|
||||
collapsible?: boolean
|
||||
isWorkspaceAdmin?: boolean
|
||||
isWorkspaceGuest?: boolean
|
||||
}>()
|
||||
|
||||
const breakpoints = useBreakpoints(TailwindBreakpoints)
|
||||
const isDesktop = breakpoints.greaterOrEqual('lg')
|
||||
const showInviteDialog = ref(false)
|
||||
|
||||
const team = computed(() => props.workspaceInfo.team.items || [])
|
||||
const team = computed(() => props.workspace?.team.items || [])
|
||||
|
||||
const iconName = computed(() => {
|
||||
if (props.isWorkspaceAdmin) return 'edit'
|
||||
return 'view'
|
||||
})
|
||||
const iconName = computed(() => (props.isWorkspaceAdmin ? 'edit' : 'view'))
|
||||
|
||||
const iconClick = computed(() => {
|
||||
if (props.isWorkspaceGuest) return undefined
|
||||
return () =>
|
||||
navigateTo(settingsWorkspaceRoutes.members.route(props.workspaceInfo.slug))
|
||||
navigateTo(settingsWorkspaceRoutes.members.route(props.workspace?.slug || ''))
|
||||
})
|
||||
|
||||
const iconText = computed(() => {
|
||||
@@ -98,10 +132,11 @@ const iconText = computed(() => {
|
||||
return 'View members'
|
||||
})
|
||||
|
||||
const invitedTeamCount = computed(() => props.workspaceInfo?.invitedTeam?.length ?? 0)
|
||||
const invitedTeamCount = computed(() => props.workspace?.invitedTeam?.length ?? 0)
|
||||
|
||||
const adminWorkspacesJoinRequestsCount = computed(
|
||||
() =>
|
||||
props.workspaceInfo?.adminWorkspacesJoinRequests?.items.filter(
|
||||
props.workspace?.adminWorkspacesJoinRequests?.items.filter(
|
||||
(request) => request.status === WorkspaceJoinRequestStatus.Pending
|
||||
).length
|
||||
)
|
||||
|
||||
@@ -1,42 +1,50 @@
|
||||
<template>
|
||||
<LayoutSidebarMenuGroup
|
||||
title="Security"
|
||||
collapsible
|
||||
icon="add"
|
||||
:icon-click="
|
||||
() => navigateTo(settingsWorkspaceRoutes.security.route(workspaceInfo.slug))
|
||||
"
|
||||
icon-text="Add domain"
|
||||
no-hover
|
||||
>
|
||||
<div class="text-body-2xs text-foreground-2 pb-4 mt-1">
|
||||
<div class="flex flex-col gap-4">
|
||||
Verified domains not set.
|
||||
<FormButton
|
||||
color="outline"
|
||||
size="sm"
|
||||
@click="
|
||||
navigateTo(settingsWorkspaceRoutes.security.route(workspaceInfo.slug))
|
||||
"
|
||||
>
|
||||
Improve security
|
||||
</FormButton>
|
||||
<div class="px-4 py-2">
|
||||
<LayoutSidebarMenuGroup
|
||||
title="Security"
|
||||
collapsible
|
||||
icon="add"
|
||||
:icon-click="
|
||||
() => navigateTo(settingsWorkspaceRoutes.security.route(workspace?.slug || ''))
|
||||
"
|
||||
icon-text="Add domain"
|
||||
no-hover
|
||||
>
|
||||
<div class="text-body-2xs text-foreground-2 pb-4 mt-1">
|
||||
<div class="flex flex-col gap-4">
|
||||
Verified domains not set.
|
||||
<FormButton
|
||||
color="outline"
|
||||
size="sm"
|
||||
@click="
|
||||
navigateTo(settingsWorkspaceRoutes.security.route(workspace?.slug || ''))
|
||||
"
|
||||
>
|
||||
Improve security
|
||||
</FormButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</LayoutSidebarMenuGroup>
|
||||
</LayoutSidebarMenuGroup>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { graphql } from '~~/lib/common/generated/gql'
|
||||
import { settingsWorkspaceRoutes } from '~/lib/common/helpers/route'
|
||||
import type { WorkspaceSidebarSecurity_WorkspaceFragment } from '~/lib/common/generated/gql/graphql'
|
||||
import type { MaybeNullOrUndefined } from '@speckle/shared'
|
||||
|
||||
graphql(`
|
||||
fragment WorkspaceSidebarSecurity_Workspace on Workspace {
|
||||
...WorkspaceSecurity_Workspace
|
||||
id
|
||||
slug
|
||||
domains {
|
||||
id
|
||||
domain
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
defineProps<{
|
||||
workspaceInfo: WorkspaceSidebarSecurity_WorkspaceFragment
|
||||
workspace: MaybeNullOrUndefined<WorkspaceSidebarSecurity_WorkspaceFragment>
|
||||
}>()
|
||||
</script>
|
||||
|
||||
@@ -1,86 +1,63 @@
|
||||
<template>
|
||||
<div class="w-full">
|
||||
<div class="w-full">
|
||||
<LayoutSidebar>
|
||||
<div class="flex flex-col divide-y divide-outline-3">
|
||||
<div v-if="!isWorkspaceGuest && isFreePlan" class="p-4">
|
||||
<div
|
||||
class="p-2 pl-3 bg-info-lighter rounded-md flex items-center justify-between gap-x-2"
|
||||
>
|
||||
<p
|
||||
class="text-primary-focus text-body-3xs font-semibold dark:text-foreground"
|
||||
>
|
||||
You're on a free plan.
|
||||
</p>
|
||||
<FormButton
|
||||
size="sm"
|
||||
@click="
|
||||
navigateTo(settingsWorkspaceRoutes.billing.route(workspaceInfo.slug))
|
||||
"
|
||||
>
|
||||
Upgrade
|
||||
</FormButton>
|
||||
</div>
|
||||
</div>
|
||||
<div class="px-4 py-2">
|
||||
<WorkspaceSidebarAbout
|
||||
:workspace-info="workspaceInfo"
|
||||
collapsible
|
||||
:is-workspace-admin="isWorkspaceAdmin"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="!isWorkspaceGuest" class="px-4 py-2">
|
||||
<WorkspaceSidebarMembers
|
||||
:workspace-info="workspaceInfo"
|
||||
:is-workspace-admin="isWorkspaceAdmin"
|
||||
collapsible
|
||||
@show-invite-dialog="$emit('show-invite-dialog')"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="isWorkspaceAdmin && !hasDomains" class="px-4 py-2">
|
||||
<WorkspaceSidebarSecurity :workspace-info="workspaceInfo" />
|
||||
</div>
|
||||
</div>
|
||||
</LayoutSidebar>
|
||||
<LayoutSidebar class="w-full">
|
||||
<div class="flex flex-col divide-y divide-outline-3">
|
||||
<WorkspaceSidebarFreePlanAlert
|
||||
v-if="!isWorkspaceGuest && isFreePlan"
|
||||
:slug="workspaceSlug"
|
||||
/>
|
||||
<WorkspaceSidebarAbout
|
||||
:workspace="workspace"
|
||||
:is-workspace-admin="isWorkspaceAdmin"
|
||||
/>
|
||||
<WorkspaceSidebarMembers
|
||||
v-if="!isWorkspaceGuest"
|
||||
:workspace="workspace"
|
||||
:is-workspace-admin="isWorkspaceAdmin"
|
||||
collapsible
|
||||
/>
|
||||
<WorkspaceSidebarSecurity
|
||||
v-if="isWorkspaceAdmin && !hasDomains"
|
||||
:workspace="workspace"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</LayoutSidebar>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Roles } from '@speckle/shared'
|
||||
import { LayoutSidebar } from '@speckle/ui-components'
|
||||
import type { WorkspaceProjectList_WorkspaceFragment } from '~/lib/common/generated/gql/graphql'
|
||||
import { graphql } from '~~/lib/common/generated/gql'
|
||||
import { settingsWorkspaceRoutes } from '~/lib/common/helpers/route'
|
||||
import { useWorkspacePlan } from '~/lib/workspaces/composables/plan'
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import { workspaceSidebarQuery } from '~/lib/workspaces/graphql/queries'
|
||||
|
||||
graphql(`
|
||||
fragment WorkspaceSidebar_Workspace on Workspace {
|
||||
...WorkspaceDashboardAbout_Workspace
|
||||
...WorkspaceTeam_Workspace
|
||||
...WorkspaceSecurity_Workspace
|
||||
...WorkspaceSidebarMembers_Workspace
|
||||
...WorkspaceSidebarAbout_Workspace
|
||||
...WorkspaceSidebarSecurity_Workspace
|
||||
id
|
||||
role
|
||||
slug
|
||||
plan {
|
||||
status
|
||||
domains {
|
||||
id
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
defineEmits<{
|
||||
(e: 'show-invite-dialog'): void
|
||||
(e: 'show-move-projects-dialog'): void
|
||||
}>()
|
||||
|
||||
const props = defineProps<{
|
||||
workspaceInfo: WorkspaceProjectList_WorkspaceFragment
|
||||
workspaceSlug: string
|
||||
}>()
|
||||
|
||||
const { isFreePlan } = useWorkspacePlan(props.workspaceInfo.slug)
|
||||
const { result: workspaceResult } = useQuery(workspaceSidebarQuery, () => ({
|
||||
workspaceSlug: props.workspaceSlug
|
||||
}))
|
||||
|
||||
const isWorkspaceGuest = computed(
|
||||
() => props.workspaceInfo.role === Roles.Workspace.Guest
|
||||
)
|
||||
const isWorkspaceAdmin = computed(
|
||||
() => props.workspaceInfo.role === Roles.Workspace.Admin
|
||||
)
|
||||
const hasDomains = computed(() => props.workspaceInfo.domains?.length)
|
||||
const workspace = computed(() => workspaceResult.value?.workspaceBySlug)
|
||||
|
||||
const { isFreePlan } = useWorkspacePlan(props.workspaceSlug)
|
||||
|
||||
const isWorkspaceGuest = computed(() => workspace.value?.slug === Roles.Workspace.Guest)
|
||||
const isWorkspaceAdmin = computed(() => workspace.value?.role === Roles.Workspace.Admin)
|
||||
const hasDomains = computed(() => workspace.value?.domains?.length)
|
||||
</script>
|
||||
|
||||
@@ -8,24 +8,7 @@
|
||||
|
||||
<div class="relative flex h-[calc(100dvh-3rem)]">
|
||||
<DashboardSidebar />
|
||||
|
||||
<main class="w-full h-full overflow-y-auto simple-scrollbar pt-4 lg:pt-6 pb-16">
|
||||
<div class="container mx-auto px-6 md:px-8">
|
||||
<slot />
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div
|
||||
class="hidden lg:flex h-full w-[17rem] shrink-0 border-l border-outline-3 bg-foundation-page"
|
||||
>
|
||||
<ClientOnly>
|
||||
<PortalTarget name="right-sidebar">
|
||||
<div class="h-full w-full flex items-center justify-center">
|
||||
<CommonLoadingIcon />
|
||||
</div>
|
||||
</PortalTarget>
|
||||
</ClientOnly>
|
||||
</div>
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { WorkspacePlans } from '@speckle/shared'
|
||||
import type { MaybeNullOrUndefined } from '@speckle/shared'
|
||||
|
||||
export const formatPrice = (price?: { amount: number; currency: string }) => {
|
||||
if (!price) return ''
|
||||
@@ -13,7 +14,7 @@ export const formatPrice = (price?: { amount: number; currency: string }) => {
|
||||
}
|
||||
|
||||
// Internal plan names dont match the names we use in the product
|
||||
export const formatName = (plan?: WorkspacePlans) => {
|
||||
export const formatName = (plan?: MaybeNullOrUndefined<WorkspacePlans>) => {
|
||||
if (!plan) return ''
|
||||
|
||||
const formattedPlanNames: Record<WorkspacePlans, string> = {
|
||||
|
||||
@@ -45,11 +45,11 @@ type Documents = {
|
||||
"\n fragment FormSelectModels_Model on Model {\n id\n name\n }\n": typeof types.FormSelectModels_ModelFragmentDoc,
|
||||
"\n fragment FormSelectProjects_Project on Project {\n id\n name\n }\n": typeof types.FormSelectProjects_ProjectFragmentDoc,
|
||||
"\n fragment FormUsersSelectItem on LimitedUser {\n id\n name\n avatar\n }\n": typeof types.FormUsersSelectItemFragmentDoc,
|
||||
"\n fragment HeaderWorkspaceSwitcherActiveWorkspace_Workspace on Workspace {\n id\n name\n logo\n ...HeaderWorkspaceSwitcherHeaderWorkspace_Workspace\n }\n": typeof types.HeaderWorkspaceSwitcherActiveWorkspace_WorkspaceFragmentDoc,
|
||||
"\n fragment HeaderWorkspaceSwitcherActiveWorkspace_Workspace on Workspace {\n ...HeaderWorkspaceSwitcherHeaderWorkspace_Workspace\n ...InviteDialogWorkspace_Workspace\n id\n name\n logo\n }\n": typeof types.HeaderWorkspaceSwitcherActiveWorkspace_WorkspaceFragmentDoc,
|
||||
"\n fragment HeaderWorkspaceSwitcherWorkspaceList_Workspace on Workspace {\n id\n name\n logo\n role\n slug\n creationState {\n completed\n }\n plan {\n name\n }\n }\n": typeof types.HeaderWorkspaceSwitcherWorkspaceList_WorkspaceFragmentDoc,
|
||||
"\n fragment HeaderWorkspaceSwitcherWorkspaceList_User on User {\n id\n expiredSsoSessions {\n id\n ...HeaderWorkspaceSwitcherHeaderExpiredSso_LimitedWorkspace\n }\n workspaces {\n items {\n id\n ...HeaderWorkspaceSwitcherWorkspaceList_Workspace\n }\n }\n }\n": typeof types.HeaderWorkspaceSwitcherWorkspaceList_UserFragmentDoc,
|
||||
"\n fragment HeaderWorkspaceSwitcherHeaderExpiredSso_LimitedWorkspace on LimitedWorkspace {\n id\n slug\n name\n logo\n }\n": typeof types.HeaderWorkspaceSwitcherHeaderExpiredSso_LimitedWorkspaceFragmentDoc,
|
||||
"\n fragment HeaderWorkspaceSwitcherHeaderWorkspace_Workspace on Workspace {\n ...InviteDialogWorkspace_Workspace\n id\n name\n logo\n role\n plan {\n name\n }\n team {\n totalCount\n }\n }\n": typeof types.HeaderWorkspaceSwitcherHeaderWorkspace_WorkspaceFragmentDoc,
|
||||
"\n fragment HeaderWorkspaceSwitcherHeaderWorkspace_Workspace on Workspace {\n id\n name\n logo\n role\n plan {\n name\n }\n team {\n totalCount\n }\n }\n": typeof types.HeaderWorkspaceSwitcherHeaderWorkspace_WorkspaceFragmentDoc,
|
||||
"\n fragment HeaderNavShare_Project on Project {\n id\n visibility\n ...ProjectsModelPageEmbed_Project\n }\n": typeof types.HeaderNavShare_ProjectFragmentDoc,
|
||||
"\n fragment HeaderNavNotificationsProjectInvite_PendingStreamCollaborator on PendingStreamCollaborator {\n id\n invitedBy {\n ...LimitedUserAvatar\n }\n projectId\n projectName\n token\n user {\n id\n }\n }\n": typeof types.HeaderNavNotificationsProjectInvite_PendingStreamCollaboratorFragmentDoc,
|
||||
"\n fragment HeaderNavNotificationsWorkspaceInvite_PendingWorkspaceCollaborator on PendingWorkspaceCollaborator {\n id\n invitedBy {\n id\n ...LimitedUserAvatar\n }\n workspaceId\n workspaceName\n token\n user {\n id\n }\n ...UseWorkspaceInviteManager_PendingWorkspaceCollaborator\n }\n": typeof types.HeaderNavNotificationsWorkspaceInvite_PendingWorkspaceCollaboratorFragmentDoc,
|
||||
@@ -102,8 +102,7 @@ type Documents = {
|
||||
"\n fragment ProjectsHiddenProjectWarning_User on User {\n id\n expiredSsoSessions {\n id\n slug\n name\n logo\n }\n }\n": typeof types.ProjectsHiddenProjectWarning_UserFragmentDoc,
|
||||
"\n fragment ProjectsWorkspaceSelect_Workspace on Workspace {\n id\n role\n name\n logo\n readOnly\n slug\n }\n": typeof types.ProjectsWorkspaceSelect_WorkspaceFragmentDoc,
|
||||
"\n fragment ProjectsInviteBanner on PendingStreamCollaborator {\n id\n invitedBy {\n ...LimitedUserAvatar\n }\n projectId\n projectName\n token\n user {\n id\n }\n }\n": typeof types.ProjectsInviteBannerFragmentDoc,
|
||||
"\n fragment SettingsSidebar_Workspace on Workspace {\n ...SettingsMenu_Workspace\n id\n slug\n role\n name\n logo\n plan {\n status\n name\n }\n creationState {\n completed\n }\n }\n": typeof types.SettingsSidebar_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsSidebar_User on User {\n id\n workspaces {\n items {\n ...SettingsSidebar_Workspace\n }\n }\n }\n": typeof types.SettingsSidebar_UserFragmentDoc,
|
||||
"\n fragment SettingsSidebar_Workspace on Workspace {\n ...SettingsMenu_Workspace\n id\n slug\n role\n }\n": typeof types.SettingsSidebar_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsServerRegionsAddEditDialog_ServerRegionItem on ServerRegionItem {\n id\n name\n description\n key\n }\n": typeof types.SettingsServerRegionsAddEditDialog_ServerRegionItemFragmentDoc,
|
||||
"\n fragment SettingsServerRegionsTable_ServerRegionItem on ServerRegionItem {\n id\n name\n key\n description\n }\n": typeof types.SettingsServerRegionsTable_ServerRegionItemFragmentDoc,
|
||||
"\n fragment SettingsSharedProjects_Project on Project {\n ...ProjectsDeleteDialog_Project\n id\n name\n visibility\n createdAt\n updatedAt\n models(limit: 0) {\n totalCount\n }\n versions(limit: 0) {\n totalCount\n }\n team {\n id\n user {\n name\n id\n avatar\n }\n }\n permissions {\n canDelete {\n ...FullPermissionCheckResult\n }\n canReadSettings {\n ...FullPermissionCheckResult\n }\n canRead {\n ...FullPermissionCheckResult\n }\n }\n }\n": typeof types.SettingsSharedProjects_ProjectFragmentDoc,
|
||||
@@ -133,9 +132,11 @@ type Documents = {
|
||||
"\n fragment ViewerCommentsListItem on Comment {\n id\n rawText\n archived\n author {\n ...LimitedUserAvatar\n }\n createdAt\n viewedAt\n replies {\n totalCount\n cursor\n items {\n ...ViewerCommentsReplyItem\n }\n }\n replyAuthors(limit: 4) {\n totalCount\n items {\n ...FormUsersSelectItem\n }\n }\n resources {\n resourceId\n resourceType\n }\n }\n": typeof types.ViewerCommentsListItemFragmentDoc,
|
||||
"\n fragment ViewerGendoPanel_Project on Project {\n id\n permissions {\n canRequestRender {\n ...FullPermissionCheckResult\n }\n }\n }\n": typeof types.ViewerGendoPanel_ProjectFragmentDoc,
|
||||
"\n fragment ViewerModelVersionCardItem on Version {\n id\n message\n referencedObject\n sourceApplication\n createdAt\n previewUrl\n authorUser {\n ...LimitedUserAvatar\n }\n }\n": typeof types.ViewerModelVersionCardItemFragmentDoc,
|
||||
"\n fragment WorkspaceProjectList_Workspace on Workspace {\n id\n ...WorkspaceBase_Workspace\n ...WorkspaceTeam_Workspace\n ...WorkspaceSecurity_Workspace\n ...WorkspaceHeader_Workspace\n ...BillingAlert_Workspace\n ...InviteDialogWorkspace_Workspace\n projects {\n ...WorkspaceProjectList_ProjectCollection\n }\n creationState {\n completed\n state\n }\n permissions {\n canCreateProject {\n ...FullPermissionCheckResult\n }\n }\n }\n": typeof types.WorkspaceProjectList_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceProjectList_ProjectCollection on ProjectCollection {\n totalCount\n items {\n ...ProjectDashboardItem\n }\n cursor\n }\n": typeof types.WorkspaceProjectList_ProjectCollectionFragmentDoc,
|
||||
"\n fragment WorkspaceHeader_Workspace on Workspace {\n ...WorkspaceBase_Workspace\n ...WorkspaceTeam_Workspace\n ...BillingAlert_Workspace\n slug\n readOnly\n permissions {\n canCreateProject {\n ...FullPermissionCheckResult\n }\n canMoveProjectToWorkspace {\n ...FullPermissionCheckResult\n }\n }\n }\n": typeof types.WorkspaceHeader_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceAddProjectMenu_Workspace on Workspace {\n id\n name\n slug\n role\n plan {\n name\n }\n permissions {\n canCreateProject {\n ...FullPermissionCheckResult\n }\n canMoveProjectToWorkspace {\n ...FullPermissionCheckResult\n }\n }\n }\n": typeof types.WorkspaceAddProjectMenu_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceDashboard_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceDashboardHeader_Workspace\n ...WorkspaceDashboardProjectList_Workspace\n id\n name\n role\n creationState {\n completed\n state\n }\n }\n": typeof types.WorkspaceDashboard_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceDashboardHeader_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceAddProjectMenu_Workspace\n ...BillingAlert_Workspace\n id\n role\n plan {\n status\n }\n }\n": typeof types.WorkspaceDashboardHeader_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceDashboardProjectList_ProjectCollection on ProjectCollection {\n totalCount\n items {\n ...ProjectDashboardItem\n }\n cursor\n }\n": typeof types.WorkspaceDashboardProjectList_ProjectCollectionFragmentDoc,
|
||||
"\n fragment WorkspaceDashboardProjectList_Workspace on Workspace {\n ...WorkspaceAddProjectMenu_Workspace\n id\n }\n": typeof types.WorkspaceDashboardProjectList_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceInviteBanner_PendingWorkspaceCollaborator on PendingWorkspaceCollaborator {\n id\n invitedBy {\n id\n ...LimitedUserAvatar\n }\n workspaceId\n workspaceName\n token\n user {\n id\n }\n ...UseWorkspaceInviteManager_PendingWorkspaceCollaborator\n }\n": typeof types.WorkspaceInviteBanner_PendingWorkspaceCollaboratorFragmentDoc,
|
||||
"\n fragment WorkspaceInviteBlock_PendingWorkspaceCollaborator on PendingWorkspaceCollaborator {\n id\n workspaceId\n workspaceName\n token\n user {\n id\n name\n ...LimitedUserAvatar\n }\n title\n email\n ...UseWorkspaceInviteManager_PendingWorkspaceCollaborator\n }\n": typeof types.WorkspaceInviteBlock_PendingWorkspaceCollaboratorFragmentDoc,
|
||||
"\n fragment WorkspaceJoinRequestApproveDialog_WorkspaceJoinRequest on WorkspaceJoinRequest {\n id\n user {\n id\n name\n }\n workspace {\n id\n }\n }\n": typeof types.WorkspaceJoinRequestApproveDialog_WorkspaceJoinRequestFragmentDoc,
|
||||
@@ -143,9 +144,10 @@ type Documents = {
|
||||
"\n fragment WorkspaceMoveProjectManager_Project on Project {\n ...WorkspaceMoveProjectManager_ProjectBase\n permissions {\n canMoveToWorkspace {\n ...FullPermissionCheckResult\n }\n }\n workspace {\n id\n slug\n permissions {\n canMoveProjectToWorkspace(projectId: $projectId) {\n ...FullPermissionCheckResult\n }\n }\n }\n }\n": typeof types.WorkspaceMoveProjectManager_ProjectFragmentDoc,
|
||||
"\n fragment WorkspaceMoveProjectManager_Workspace on Workspace {\n id\n role\n name\n logo\n slug\n plan {\n name\n usage {\n projectCount\n modelCount\n }\n }\n permissions {\n canMoveProjectToWorkspace(projectId: $projectId) {\n ...FullPermissionCheckResult\n }\n }\n projects {\n totalCount\n }\n team {\n items {\n user {\n id\n name\n avatar\n }\n }\n }\n }\n": typeof types.WorkspaceMoveProjectManager_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceMoveProjectSelectWorkspace_User on User {\n workspaces {\n items {\n ...WorkspaceMoveProjectManager_Workspace\n }\n }\n projects(cursor: $cursor, filter: $filter) {\n items {\n ...WorkspaceMoveProjectManager_Project\n }\n cursor\n totalCount\n }\n }\n": typeof types.WorkspaceMoveProjectSelectWorkspace_UserFragmentDoc,
|
||||
"\n fragment WorkspaceSidebarAbout_Workspace on Workspace {\n ...WorkspaceDashboardAbout_Workspace\n }\n": typeof types.WorkspaceSidebarAbout_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceSidebarSecurity_Workspace on Workspace {\n ...WorkspaceSecurity_Workspace\n }\n": typeof types.WorkspaceSidebarSecurity_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceSidebar_Workspace on Workspace {\n ...WorkspaceDashboardAbout_Workspace\n ...WorkspaceTeam_Workspace\n ...WorkspaceSecurity_Workspace\n slug\n plan {\n status\n }\n }\n": typeof types.WorkspaceSidebar_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceSidebarAbout_Workspace on Workspace {\n id\n name\n description\n }\n": typeof types.WorkspaceSidebarAbout_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceSidebarMembers_Workspace on Workspace {\n ...InviteDialogWorkspace_Workspace\n id\n slug\n team {\n totalCount\n items {\n id\n user {\n id\n name\n ...LimitedUserAvatar\n }\n }\n }\n invitedTeam(filter: $invitesFilter) {\n id\n role\n email\n }\n adminWorkspacesJoinRequests {\n totalCount\n items {\n status\n id\n }\n }\n }\n": typeof types.WorkspaceSidebarMembers_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceSidebarSecurity_Workspace on Workspace {\n id\n slug\n domains {\n id\n domain\n }\n }\n": typeof types.WorkspaceSidebarSecurity_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceSidebar_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceSidebarAbout_Workspace\n ...WorkspaceSidebarSecurity_Workspace\n id\n role\n slug\n domains {\n id\n }\n }\n": typeof types.WorkspaceSidebar_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceWizard_Workspace on Workspace {\n creationState {\n completed\n state\n }\n name\n slug\n }\n": typeof types.WorkspaceWizard_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceWizardStepRegion_ServerInfo on ServerInfo {\n multiRegion {\n regions {\n id\n ...SettingsWorkspacesRegionsSelect_ServerRegionItem\n }\n }\n }\n": typeof types.WorkspaceWizardStepRegion_ServerInfoFragmentDoc,
|
||||
"\n query ActiveUserMainMetadata {\n activeUser {\n id\n email\n emails {\n id\n email\n verified\n }\n company\n bio\n name\n role\n avatar\n isOnboardingFinished\n createdAt\n verified\n notificationPreferences\n versions(limit: 0) {\n totalCount\n }\n }\n }\n": typeof types.ActiveUserMainMetadataDocument,
|
||||
@@ -311,7 +313,7 @@ type Documents = {
|
||||
"\n mutation DeleteWorkspaceDomain($input: WorkspaceDomainDeleteInput!) {\n workspaceMutations {\n deleteDomain(input: $input) {\n ...SettingsWorkspacesSecurityDomainRemoveDialog_Workspace\n }\n }\n }\n": typeof types.DeleteWorkspaceDomainDocument,
|
||||
"\n mutation SettingsLeaveWorkspace($leaveId: ID!) {\n workspaceMutations {\n leave(id: $leaveId)\n }\n }\n": typeof types.SettingsLeaveWorkspaceDocument,
|
||||
"\n mutation SettingsBillingCancelCheckoutSession($input: CancelCheckoutSessionInput!) {\n workspaceMutations {\n billing {\n cancelCheckoutSession(input: $input)\n }\n }\n }\n": typeof types.SettingsBillingCancelCheckoutSessionDocument,
|
||||
"\n query SettingsSidebar {\n activeUser {\n ...SettingsSidebar_User\n }\n }\n": typeof types.SettingsSidebarDocument,
|
||||
"\n query SettingsSidebar {\n activeUser {\n activeWorkspace {\n ...SettingsSidebar_Workspace\n }\n }\n }\n": typeof types.SettingsSidebarDocument,
|
||||
"\n query SettingsWorkspaceGeneral($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesGeneral_Workspace\n }\n }\n": typeof types.SettingsWorkspaceGeneralDocument,
|
||||
"\n query SettingsWorkspaceBilling($slug: String!) {\n workspaceBySlug(slug: $slug) {\n id\n ...WorkspaceBillingPage_Workspace\n }\n }\n": typeof types.SettingsWorkspaceBillingDocument,
|
||||
"\n query SettingsWorkspaceBillingCustomerPortal($workspaceId: String!) {\n workspace(id: $workspaceId) {\n customerPortalUrl\n }\n }\n": typeof types.SettingsWorkspaceBillingCustomerPortalDocument,
|
||||
@@ -368,12 +370,6 @@ type Documents = {
|
||||
"\n fragment WorkspaceSsoStatus_Workspace on Workspace {\n id\n sso {\n provider {\n id\n name\n clientId\n issuerUrl\n }\n session {\n validUntil\n }\n }\n }\n ": typeof types.WorkspaceSsoStatus_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceSsoStatus_User on User {\n expiredSsoSessions {\n id\n slug\n }\n }\n ": typeof types.WorkspaceSsoStatus_UserFragmentDoc,
|
||||
"\n fragment WorkspaceUsage_Workspace on Workspace {\n id\n slug\n plan {\n usage {\n projectCount\n modelCount\n }\n }\n team {\n totalCount\n }\n teamByRole {\n admins {\n totalCount\n }\n members {\n totalCount\n }\n guests {\n totalCount\n }\n }\n }\n": typeof types.WorkspaceUsage_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceBase_Workspace on Workspace {\n id\n name\n slug\n role\n description\n logo\n plan {\n status\n createdAt\n }\n }\n": typeof types.WorkspaceBase_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceDashboardAbout_Workspace on Workspace {\n id\n name\n description\n }\n": typeof types.WorkspaceDashboardAbout_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceInvitedTeam_Workspace on Workspace {\n id\n invitedTeam(filter: $invitesFilter) {\n id\n role\n email\n }\n }\n": typeof types.WorkspaceInvitedTeam_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceTeam_Workspace on Workspace {\n id\n slug\n team(limit: 250) {\n totalCount\n items {\n id\n user {\n id\n name\n ...LimitedUserAvatar\n }\n }\n }\n adminWorkspacesJoinRequests {\n totalCount\n items {\n status\n id\n }\n }\n ...WorkspaceInvitedTeam_Workspace\n }\n": typeof types.WorkspaceTeam_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceSecurity_Workspace on Workspace {\n id\n slug\n domains {\n id\n domain\n }\n }\n": typeof types.WorkspaceSecurity_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceLastAdminCheck_Workspace on Workspace {\n id\n team(limit: 50, filter: { roles: [\"workspace:admin\"] }) {\n items {\n id\n }\n }\n }\n": typeof types.WorkspaceLastAdminCheck_WorkspaceFragmentDoc,
|
||||
"\n mutation UpdateRole($input: WorkspaceRoleUpdateInput!) {\n workspaceMutations {\n updateRole(input: $input) {\n team {\n items {\n id\n role\n }\n }\n }\n }\n }\n": typeof types.UpdateRoleDocument,
|
||||
"\n mutation WorkspacesUpdateSeatType($input: WorkspaceUpdateSeatTypeInput!) {\n workspaceMutations {\n updateSeatType(input: $input) {\n team {\n items {\n id\n seatType\n }\n }\n }\n }\n }\n": typeof types.WorkspacesUpdateSeatTypeDocument,
|
||||
"\n mutation InviteToWorkspace(\n $workspaceId: String!\n $input: [WorkspaceInviteCreateInput!]!\n ) {\n workspaceMutations {\n invites {\n batchCreate(workspaceId: $workspaceId, input: $input) {\n id\n invitedTeam {\n ...SettingsWorkspacesMembersInvitesTable_PendingWorkspaceCollaborator\n }\n }\n }\n }\n }\n": typeof types.InviteToWorkspaceDocument,
|
||||
@@ -389,8 +385,9 @@ type Documents = {
|
||||
"\n mutation RequestToJoinWorkspace($input: WorkspaceRequestToJoinInput!) {\n workspaceMutations {\n requestToJoin(input: $input)\n }\n }\n": typeof types.RequestToJoinWorkspaceDocument,
|
||||
"\n mutation DismissDiscoverableWorkspace($input: WorkspaceDismissInput!) {\n workspaceMutations {\n dismiss(input: $input)\n }\n }\n": typeof types.DismissDiscoverableWorkspaceDocument,
|
||||
"\n query WorkspaceAccessCheck($slug: String!) {\n workspaceBySlug(slug: $slug) {\n id\n }\n }\n": typeof types.WorkspaceAccessCheckDocument,
|
||||
"\n query WorkspacePageQuery(\n $workspaceSlug: String!\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n $token: String\n ) {\n workspaceBySlug(slug: $workspaceSlug) {\n ...WorkspaceProjectList_Workspace\n }\n workspaceInvite(\n workspaceId: $workspaceSlug\n token: $token\n options: { useSlug: true }\n ) {\n id\n ...WorkspaceInviteBanner_PendingWorkspaceCollaborator\n ...WorkspaceInviteBlock_PendingWorkspaceCollaborator\n }\n }\n": typeof types.WorkspacePageQueryDocument,
|
||||
"\n query WorkspaceProjectsQuery(\n $workspaceSlug: String!\n $filter: WorkspaceProjectsFilter\n $cursor: String\n ) {\n workspaceBySlug(slug: $workspaceSlug) {\n id\n projects(filter: $filter, cursor: $cursor, limit: 10) {\n ...WorkspaceProjectList_ProjectCollection\n }\n }\n }\n": typeof types.WorkspaceProjectsQueryDocument,
|
||||
"\n query WorkspaceSidebar(\n $workspaceSlug: String!\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n ) {\n workspaceBySlug(slug: $workspaceSlug) {\n ...WorkspaceSidebar_Workspace\n }\n }\n": typeof types.WorkspaceSidebarDocument,
|
||||
"\n query WorkspaceDashboard(\n $workspaceSlug: String!\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n ) {\n workspaceBySlug(slug: $workspaceSlug) {\n ...WorkspaceDashboard_Workspace\n }\n }\n": typeof types.WorkspaceDashboardDocument,
|
||||
"\n query WorkspaceProjectsQuery(\n $workspaceSlug: String!\n $filter: WorkspaceProjectsFilter\n $cursor: String\n ) {\n workspaceBySlug(slug: $workspaceSlug) {\n id\n projects(filter: $filter, cursor: $cursor, limit: 10) {\n ...WorkspaceDashboardProjectList_ProjectCollection\n }\n }\n }\n": typeof types.WorkspaceProjectsQueryDocument,
|
||||
"\n query WorkspaceFunctionsQuery($workspaceSlug: String!) {\n ...AutomateFunctionsPageHeader_Query\n workspaceBySlug(slug: $workspaceSlug) {\n id\n name\n automateFunctions {\n items {\n id\n ...AutomationsFunctionsCard_AutomateFunction\n ...AutomateAutomationCreateDialog_AutomateFunction\n }\n }\n }\n }\n": typeof types.WorkspaceFunctionsQueryDocument,
|
||||
"\n query WorkspaceInvite(\n $workspaceId: String\n $token: String\n $options: WorkspaceInviteLookupOptions\n ) {\n workspaceInvite(workspaceId: $workspaceId, token: $token, options: $options) {\n ...WorkspaceInviteBanner_PendingWorkspaceCollaborator\n ...WorkspaceInviteBlock_PendingWorkspaceCollaborator\n }\n }\n": typeof types.WorkspaceInviteDocument,
|
||||
"\n query ValidateWorkspaceSlug($slug: String!) {\n validateWorkspaceSlug(slug: $slug)\n }\n": typeof types.ValidateWorkspaceSlugDocument,
|
||||
@@ -402,13 +399,13 @@ type Documents = {
|
||||
"\n query DiscoverableWorkspacesRequests {\n activeUser {\n id\n ...DiscoverableList_Requests\n }\n }\n": typeof types.DiscoverableWorkspacesRequestsDocument,
|
||||
"\n query WorkspacePlan($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspacesPlan_Workspace\n }\n }\n": typeof types.WorkspacePlanDocument,
|
||||
"\n query activeWorkspace($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...ActiveWorkspace_Workspace\n }\n }\n": typeof types.ActiveWorkspaceDocument,
|
||||
"\n query WorkspaceLastAdminCheck($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspaceLastAdminCheck_Workspace\n }\n }\n": typeof types.WorkspaceLastAdminCheckDocument,
|
||||
"\n query WorkspaceLastAdminCheck($slug: String!) {\n workspaceBySlug(slug: $slug) {\n teamByRole {\n admins {\n totalCount\n }\n }\n }\n }\n": typeof types.WorkspaceLastAdminCheckDocument,
|
||||
"\n query WorkspaceLimits($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspacePlanLimits_Workspace\n }\n }\n": typeof types.WorkspaceLimitsDocument,
|
||||
"\n query WorkspaceUsage($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspaceUsage_Workspace\n }\n }\n": typeof types.WorkspaceUsageDocument,
|
||||
"\n query WorkspaceMoveProjectManagerProject($projectId: String!) {\n project(id: $projectId) {\n ...WorkspaceMoveProjectManager_Project\n }\n }\n": typeof types.WorkspaceMoveProjectManagerProjectDocument,
|
||||
"\n query WorkspaceMoveProjectManagerWorkspace(\n $workspaceSlug: String!\n $projectId: String\n ) {\n workspaceBySlug(slug: $workspaceSlug) {\n ...WorkspaceMoveProjectManager_Workspace\n }\n }\n": typeof types.WorkspaceMoveProjectManagerWorkspaceDocument,
|
||||
"\n query WorkspaceMoveProjectManagerUser(\n $cursor: String\n $filter: UserProjectsFilter\n $projectId: String\n ) {\n activeUser {\n ...WorkspaceMoveProjectSelectWorkspace_User\n }\n }\n": typeof types.WorkspaceMoveProjectManagerUserDocument,
|
||||
"\n subscription onWorkspaceUpdated(\n $workspaceId: String\n $workspaceSlug: String\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n ) {\n workspaceUpdated(workspaceId: $workspaceId, workspaceSlug: $workspaceSlug) {\n id\n workspace {\n id\n ...WorkspaceProjectList_Workspace\n }\n }\n }\n": typeof types.OnWorkspaceUpdatedDocument,
|
||||
"\n subscription onWorkspaceUpdated(\n $workspaceId: String\n $workspaceSlug: String\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n ) {\n workspaceUpdated(workspaceId: $workspaceId, workspaceSlug: $workspaceSlug) {\n id\n workspace {\n id\n ...WorkspaceDashboard_Workspace\n ...WorkspaceDashboardProjectList_Workspace\n }\n }\n }\n": typeof types.OnWorkspaceUpdatedDocument,
|
||||
"\n query LegacyBranchRedirectMetadata($streamId: String!, $branchName: String!) {\n project(id: $streamId) {\n modelByName(name: $branchName) {\n id\n }\n }\n }\n": typeof types.LegacyBranchRedirectMetadataDocument,
|
||||
"\n query LegacyViewerCommitRedirectMetadata($streamId: String!, $commitId: String!) {\n project(id: $streamId) {\n version(id: $commitId) {\n id\n model {\n id\n }\n }\n }\n }\n": typeof types.LegacyViewerCommitRedirectMetadataDocument,
|
||||
"\n query LegacyViewerStreamRedirectMetadata($streamId: String!) {\n project(id: $streamId) {\n id\n versions(limit: 1) {\n totalCount\n items {\n id\n model {\n id\n }\n }\n }\n }\n }\n": typeof types.LegacyViewerStreamRedirectMetadataDocument,
|
||||
@@ -466,11 +463,11 @@ const documents: Documents = {
|
||||
"\n fragment FormSelectModels_Model on Model {\n id\n name\n }\n": types.FormSelectModels_ModelFragmentDoc,
|
||||
"\n fragment FormSelectProjects_Project on Project {\n id\n name\n }\n": types.FormSelectProjects_ProjectFragmentDoc,
|
||||
"\n fragment FormUsersSelectItem on LimitedUser {\n id\n name\n avatar\n }\n": types.FormUsersSelectItemFragmentDoc,
|
||||
"\n fragment HeaderWorkspaceSwitcherActiveWorkspace_Workspace on Workspace {\n id\n name\n logo\n ...HeaderWorkspaceSwitcherHeaderWorkspace_Workspace\n }\n": types.HeaderWorkspaceSwitcherActiveWorkspace_WorkspaceFragmentDoc,
|
||||
"\n fragment HeaderWorkspaceSwitcherActiveWorkspace_Workspace on Workspace {\n ...HeaderWorkspaceSwitcherHeaderWorkspace_Workspace\n ...InviteDialogWorkspace_Workspace\n id\n name\n logo\n }\n": types.HeaderWorkspaceSwitcherActiveWorkspace_WorkspaceFragmentDoc,
|
||||
"\n fragment HeaderWorkspaceSwitcherWorkspaceList_Workspace on Workspace {\n id\n name\n logo\n role\n slug\n creationState {\n completed\n }\n plan {\n name\n }\n }\n": types.HeaderWorkspaceSwitcherWorkspaceList_WorkspaceFragmentDoc,
|
||||
"\n fragment HeaderWorkspaceSwitcherWorkspaceList_User on User {\n id\n expiredSsoSessions {\n id\n ...HeaderWorkspaceSwitcherHeaderExpiredSso_LimitedWorkspace\n }\n workspaces {\n items {\n id\n ...HeaderWorkspaceSwitcherWorkspaceList_Workspace\n }\n }\n }\n": types.HeaderWorkspaceSwitcherWorkspaceList_UserFragmentDoc,
|
||||
"\n fragment HeaderWorkspaceSwitcherHeaderExpiredSso_LimitedWorkspace on LimitedWorkspace {\n id\n slug\n name\n logo\n }\n": types.HeaderWorkspaceSwitcherHeaderExpiredSso_LimitedWorkspaceFragmentDoc,
|
||||
"\n fragment HeaderWorkspaceSwitcherHeaderWorkspace_Workspace on Workspace {\n ...InviteDialogWorkspace_Workspace\n id\n name\n logo\n role\n plan {\n name\n }\n team {\n totalCount\n }\n }\n": types.HeaderWorkspaceSwitcherHeaderWorkspace_WorkspaceFragmentDoc,
|
||||
"\n fragment HeaderWorkspaceSwitcherHeaderWorkspace_Workspace on Workspace {\n id\n name\n logo\n role\n plan {\n name\n }\n team {\n totalCount\n }\n }\n": types.HeaderWorkspaceSwitcherHeaderWorkspace_WorkspaceFragmentDoc,
|
||||
"\n fragment HeaderNavShare_Project on Project {\n id\n visibility\n ...ProjectsModelPageEmbed_Project\n }\n": types.HeaderNavShare_ProjectFragmentDoc,
|
||||
"\n fragment HeaderNavNotificationsProjectInvite_PendingStreamCollaborator on PendingStreamCollaborator {\n id\n invitedBy {\n ...LimitedUserAvatar\n }\n projectId\n projectName\n token\n user {\n id\n }\n }\n": types.HeaderNavNotificationsProjectInvite_PendingStreamCollaboratorFragmentDoc,
|
||||
"\n fragment HeaderNavNotificationsWorkspaceInvite_PendingWorkspaceCollaborator on PendingWorkspaceCollaborator {\n id\n invitedBy {\n id\n ...LimitedUserAvatar\n }\n workspaceId\n workspaceName\n token\n user {\n id\n }\n ...UseWorkspaceInviteManager_PendingWorkspaceCollaborator\n }\n": types.HeaderNavNotificationsWorkspaceInvite_PendingWorkspaceCollaboratorFragmentDoc,
|
||||
@@ -523,8 +520,7 @@ const documents: Documents = {
|
||||
"\n fragment ProjectsHiddenProjectWarning_User on User {\n id\n expiredSsoSessions {\n id\n slug\n name\n logo\n }\n }\n": types.ProjectsHiddenProjectWarning_UserFragmentDoc,
|
||||
"\n fragment ProjectsWorkspaceSelect_Workspace on Workspace {\n id\n role\n name\n logo\n readOnly\n slug\n }\n": types.ProjectsWorkspaceSelect_WorkspaceFragmentDoc,
|
||||
"\n fragment ProjectsInviteBanner on PendingStreamCollaborator {\n id\n invitedBy {\n ...LimitedUserAvatar\n }\n projectId\n projectName\n token\n user {\n id\n }\n }\n": types.ProjectsInviteBannerFragmentDoc,
|
||||
"\n fragment SettingsSidebar_Workspace on Workspace {\n ...SettingsMenu_Workspace\n id\n slug\n role\n name\n logo\n plan {\n status\n name\n }\n creationState {\n completed\n }\n }\n": types.SettingsSidebar_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsSidebar_User on User {\n id\n workspaces {\n items {\n ...SettingsSidebar_Workspace\n }\n }\n }\n": types.SettingsSidebar_UserFragmentDoc,
|
||||
"\n fragment SettingsSidebar_Workspace on Workspace {\n ...SettingsMenu_Workspace\n id\n slug\n role\n }\n": types.SettingsSidebar_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsServerRegionsAddEditDialog_ServerRegionItem on ServerRegionItem {\n id\n name\n description\n key\n }\n": types.SettingsServerRegionsAddEditDialog_ServerRegionItemFragmentDoc,
|
||||
"\n fragment SettingsServerRegionsTable_ServerRegionItem on ServerRegionItem {\n id\n name\n key\n description\n }\n": types.SettingsServerRegionsTable_ServerRegionItemFragmentDoc,
|
||||
"\n fragment SettingsSharedProjects_Project on Project {\n ...ProjectsDeleteDialog_Project\n id\n name\n visibility\n createdAt\n updatedAt\n models(limit: 0) {\n totalCount\n }\n versions(limit: 0) {\n totalCount\n }\n team {\n id\n user {\n name\n id\n avatar\n }\n }\n permissions {\n canDelete {\n ...FullPermissionCheckResult\n }\n canReadSettings {\n ...FullPermissionCheckResult\n }\n canRead {\n ...FullPermissionCheckResult\n }\n }\n }\n": types.SettingsSharedProjects_ProjectFragmentDoc,
|
||||
@@ -554,9 +550,11 @@ const documents: Documents = {
|
||||
"\n fragment ViewerCommentsListItem on Comment {\n id\n rawText\n archived\n author {\n ...LimitedUserAvatar\n }\n createdAt\n viewedAt\n replies {\n totalCount\n cursor\n items {\n ...ViewerCommentsReplyItem\n }\n }\n replyAuthors(limit: 4) {\n totalCount\n items {\n ...FormUsersSelectItem\n }\n }\n resources {\n resourceId\n resourceType\n }\n }\n": types.ViewerCommentsListItemFragmentDoc,
|
||||
"\n fragment ViewerGendoPanel_Project on Project {\n id\n permissions {\n canRequestRender {\n ...FullPermissionCheckResult\n }\n }\n }\n": types.ViewerGendoPanel_ProjectFragmentDoc,
|
||||
"\n fragment ViewerModelVersionCardItem on Version {\n id\n message\n referencedObject\n sourceApplication\n createdAt\n previewUrl\n authorUser {\n ...LimitedUserAvatar\n }\n }\n": types.ViewerModelVersionCardItemFragmentDoc,
|
||||
"\n fragment WorkspaceProjectList_Workspace on Workspace {\n id\n ...WorkspaceBase_Workspace\n ...WorkspaceTeam_Workspace\n ...WorkspaceSecurity_Workspace\n ...WorkspaceHeader_Workspace\n ...BillingAlert_Workspace\n ...InviteDialogWorkspace_Workspace\n projects {\n ...WorkspaceProjectList_ProjectCollection\n }\n creationState {\n completed\n state\n }\n permissions {\n canCreateProject {\n ...FullPermissionCheckResult\n }\n }\n }\n": types.WorkspaceProjectList_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceProjectList_ProjectCollection on ProjectCollection {\n totalCount\n items {\n ...ProjectDashboardItem\n }\n cursor\n }\n": types.WorkspaceProjectList_ProjectCollectionFragmentDoc,
|
||||
"\n fragment WorkspaceHeader_Workspace on Workspace {\n ...WorkspaceBase_Workspace\n ...WorkspaceTeam_Workspace\n ...BillingAlert_Workspace\n slug\n readOnly\n permissions {\n canCreateProject {\n ...FullPermissionCheckResult\n }\n canMoveProjectToWorkspace {\n ...FullPermissionCheckResult\n }\n }\n }\n": types.WorkspaceHeader_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceAddProjectMenu_Workspace on Workspace {\n id\n name\n slug\n role\n plan {\n name\n }\n permissions {\n canCreateProject {\n ...FullPermissionCheckResult\n }\n canMoveProjectToWorkspace {\n ...FullPermissionCheckResult\n }\n }\n }\n": types.WorkspaceAddProjectMenu_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceDashboard_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceDashboardHeader_Workspace\n ...WorkspaceDashboardProjectList_Workspace\n id\n name\n role\n creationState {\n completed\n state\n }\n }\n": types.WorkspaceDashboard_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceDashboardHeader_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceAddProjectMenu_Workspace\n ...BillingAlert_Workspace\n id\n role\n plan {\n status\n }\n }\n": types.WorkspaceDashboardHeader_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceDashboardProjectList_ProjectCollection on ProjectCollection {\n totalCount\n items {\n ...ProjectDashboardItem\n }\n cursor\n }\n": types.WorkspaceDashboardProjectList_ProjectCollectionFragmentDoc,
|
||||
"\n fragment WorkspaceDashboardProjectList_Workspace on Workspace {\n ...WorkspaceAddProjectMenu_Workspace\n id\n }\n": types.WorkspaceDashboardProjectList_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceInviteBanner_PendingWorkspaceCollaborator on PendingWorkspaceCollaborator {\n id\n invitedBy {\n id\n ...LimitedUserAvatar\n }\n workspaceId\n workspaceName\n token\n user {\n id\n }\n ...UseWorkspaceInviteManager_PendingWorkspaceCollaborator\n }\n": types.WorkspaceInviteBanner_PendingWorkspaceCollaboratorFragmentDoc,
|
||||
"\n fragment WorkspaceInviteBlock_PendingWorkspaceCollaborator on PendingWorkspaceCollaborator {\n id\n workspaceId\n workspaceName\n token\n user {\n id\n name\n ...LimitedUserAvatar\n }\n title\n email\n ...UseWorkspaceInviteManager_PendingWorkspaceCollaborator\n }\n": types.WorkspaceInviteBlock_PendingWorkspaceCollaboratorFragmentDoc,
|
||||
"\n fragment WorkspaceJoinRequestApproveDialog_WorkspaceJoinRequest on WorkspaceJoinRequest {\n id\n user {\n id\n name\n }\n workspace {\n id\n }\n }\n": types.WorkspaceJoinRequestApproveDialog_WorkspaceJoinRequestFragmentDoc,
|
||||
@@ -564,9 +562,10 @@ const documents: Documents = {
|
||||
"\n fragment WorkspaceMoveProjectManager_Project on Project {\n ...WorkspaceMoveProjectManager_ProjectBase\n permissions {\n canMoveToWorkspace {\n ...FullPermissionCheckResult\n }\n }\n workspace {\n id\n slug\n permissions {\n canMoveProjectToWorkspace(projectId: $projectId) {\n ...FullPermissionCheckResult\n }\n }\n }\n }\n": types.WorkspaceMoveProjectManager_ProjectFragmentDoc,
|
||||
"\n fragment WorkspaceMoveProjectManager_Workspace on Workspace {\n id\n role\n name\n logo\n slug\n plan {\n name\n usage {\n projectCount\n modelCount\n }\n }\n permissions {\n canMoveProjectToWorkspace(projectId: $projectId) {\n ...FullPermissionCheckResult\n }\n }\n projects {\n totalCount\n }\n team {\n items {\n user {\n id\n name\n avatar\n }\n }\n }\n }\n": types.WorkspaceMoveProjectManager_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceMoveProjectSelectWorkspace_User on User {\n workspaces {\n items {\n ...WorkspaceMoveProjectManager_Workspace\n }\n }\n projects(cursor: $cursor, filter: $filter) {\n items {\n ...WorkspaceMoveProjectManager_Project\n }\n cursor\n totalCount\n }\n }\n": types.WorkspaceMoveProjectSelectWorkspace_UserFragmentDoc,
|
||||
"\n fragment WorkspaceSidebarAbout_Workspace on Workspace {\n ...WorkspaceDashboardAbout_Workspace\n }\n": types.WorkspaceSidebarAbout_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceSidebarSecurity_Workspace on Workspace {\n ...WorkspaceSecurity_Workspace\n }\n": types.WorkspaceSidebarSecurity_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceSidebar_Workspace on Workspace {\n ...WorkspaceDashboardAbout_Workspace\n ...WorkspaceTeam_Workspace\n ...WorkspaceSecurity_Workspace\n slug\n plan {\n status\n }\n }\n": types.WorkspaceSidebar_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceSidebarAbout_Workspace on Workspace {\n id\n name\n description\n }\n": types.WorkspaceSidebarAbout_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceSidebarMembers_Workspace on Workspace {\n ...InviteDialogWorkspace_Workspace\n id\n slug\n team {\n totalCount\n items {\n id\n user {\n id\n name\n ...LimitedUserAvatar\n }\n }\n }\n invitedTeam(filter: $invitesFilter) {\n id\n role\n email\n }\n adminWorkspacesJoinRequests {\n totalCount\n items {\n status\n id\n }\n }\n }\n": types.WorkspaceSidebarMembers_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceSidebarSecurity_Workspace on Workspace {\n id\n slug\n domains {\n id\n domain\n }\n }\n": types.WorkspaceSidebarSecurity_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceSidebar_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceSidebarAbout_Workspace\n ...WorkspaceSidebarSecurity_Workspace\n id\n role\n slug\n domains {\n id\n }\n }\n": types.WorkspaceSidebar_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceWizard_Workspace on Workspace {\n creationState {\n completed\n state\n }\n name\n slug\n }\n": types.WorkspaceWizard_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceWizardStepRegion_ServerInfo on ServerInfo {\n multiRegion {\n regions {\n id\n ...SettingsWorkspacesRegionsSelect_ServerRegionItem\n }\n }\n }\n": types.WorkspaceWizardStepRegion_ServerInfoFragmentDoc,
|
||||
"\n query ActiveUserMainMetadata {\n activeUser {\n id\n email\n emails {\n id\n email\n verified\n }\n company\n bio\n name\n role\n avatar\n isOnboardingFinished\n createdAt\n verified\n notificationPreferences\n versions(limit: 0) {\n totalCount\n }\n }\n }\n": types.ActiveUserMainMetadataDocument,
|
||||
@@ -732,7 +731,7 @@ const documents: Documents = {
|
||||
"\n mutation DeleteWorkspaceDomain($input: WorkspaceDomainDeleteInput!) {\n workspaceMutations {\n deleteDomain(input: $input) {\n ...SettingsWorkspacesSecurityDomainRemoveDialog_Workspace\n }\n }\n }\n": types.DeleteWorkspaceDomainDocument,
|
||||
"\n mutation SettingsLeaveWorkspace($leaveId: ID!) {\n workspaceMutations {\n leave(id: $leaveId)\n }\n }\n": types.SettingsLeaveWorkspaceDocument,
|
||||
"\n mutation SettingsBillingCancelCheckoutSession($input: CancelCheckoutSessionInput!) {\n workspaceMutations {\n billing {\n cancelCheckoutSession(input: $input)\n }\n }\n }\n": types.SettingsBillingCancelCheckoutSessionDocument,
|
||||
"\n query SettingsSidebar {\n activeUser {\n ...SettingsSidebar_User\n }\n }\n": types.SettingsSidebarDocument,
|
||||
"\n query SettingsSidebar {\n activeUser {\n activeWorkspace {\n ...SettingsSidebar_Workspace\n }\n }\n }\n": types.SettingsSidebarDocument,
|
||||
"\n query SettingsWorkspaceGeneral($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesGeneral_Workspace\n }\n }\n": types.SettingsWorkspaceGeneralDocument,
|
||||
"\n query SettingsWorkspaceBilling($slug: String!) {\n workspaceBySlug(slug: $slug) {\n id\n ...WorkspaceBillingPage_Workspace\n }\n }\n": types.SettingsWorkspaceBillingDocument,
|
||||
"\n query SettingsWorkspaceBillingCustomerPortal($workspaceId: String!) {\n workspace(id: $workspaceId) {\n customerPortalUrl\n }\n }\n": types.SettingsWorkspaceBillingCustomerPortalDocument,
|
||||
@@ -789,12 +788,6 @@ const documents: Documents = {
|
||||
"\n fragment WorkspaceSsoStatus_Workspace on Workspace {\n id\n sso {\n provider {\n id\n name\n clientId\n issuerUrl\n }\n session {\n validUntil\n }\n }\n }\n ": types.WorkspaceSsoStatus_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceSsoStatus_User on User {\n expiredSsoSessions {\n id\n slug\n }\n }\n ": types.WorkspaceSsoStatus_UserFragmentDoc,
|
||||
"\n fragment WorkspaceUsage_Workspace on Workspace {\n id\n slug\n plan {\n usage {\n projectCount\n modelCount\n }\n }\n team {\n totalCount\n }\n teamByRole {\n admins {\n totalCount\n }\n members {\n totalCount\n }\n guests {\n totalCount\n }\n }\n }\n": types.WorkspaceUsage_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceBase_Workspace on Workspace {\n id\n name\n slug\n role\n description\n logo\n plan {\n status\n createdAt\n }\n }\n": types.WorkspaceBase_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceDashboardAbout_Workspace on Workspace {\n id\n name\n description\n }\n": types.WorkspaceDashboardAbout_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceInvitedTeam_Workspace on Workspace {\n id\n invitedTeam(filter: $invitesFilter) {\n id\n role\n email\n }\n }\n": types.WorkspaceInvitedTeam_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceTeam_Workspace on Workspace {\n id\n slug\n team(limit: 250) {\n totalCount\n items {\n id\n user {\n id\n name\n ...LimitedUserAvatar\n }\n }\n }\n adminWorkspacesJoinRequests {\n totalCount\n items {\n status\n id\n }\n }\n ...WorkspaceInvitedTeam_Workspace\n }\n": types.WorkspaceTeam_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceSecurity_Workspace on Workspace {\n id\n slug\n domains {\n id\n domain\n }\n }\n": types.WorkspaceSecurity_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceLastAdminCheck_Workspace on Workspace {\n id\n team(limit: 50, filter: { roles: [\"workspace:admin\"] }) {\n items {\n id\n }\n }\n }\n": types.WorkspaceLastAdminCheck_WorkspaceFragmentDoc,
|
||||
"\n mutation UpdateRole($input: WorkspaceRoleUpdateInput!) {\n workspaceMutations {\n updateRole(input: $input) {\n team {\n items {\n id\n role\n }\n }\n }\n }\n }\n": types.UpdateRoleDocument,
|
||||
"\n mutation WorkspacesUpdateSeatType($input: WorkspaceUpdateSeatTypeInput!) {\n workspaceMutations {\n updateSeatType(input: $input) {\n team {\n items {\n id\n seatType\n }\n }\n }\n }\n }\n": types.WorkspacesUpdateSeatTypeDocument,
|
||||
"\n mutation InviteToWorkspace(\n $workspaceId: String!\n $input: [WorkspaceInviteCreateInput!]!\n ) {\n workspaceMutations {\n invites {\n batchCreate(workspaceId: $workspaceId, input: $input) {\n id\n invitedTeam {\n ...SettingsWorkspacesMembersInvitesTable_PendingWorkspaceCollaborator\n }\n }\n }\n }\n }\n": types.InviteToWorkspaceDocument,
|
||||
@@ -810,8 +803,9 @@ const documents: Documents = {
|
||||
"\n mutation RequestToJoinWorkspace($input: WorkspaceRequestToJoinInput!) {\n workspaceMutations {\n requestToJoin(input: $input)\n }\n }\n": types.RequestToJoinWorkspaceDocument,
|
||||
"\n mutation DismissDiscoverableWorkspace($input: WorkspaceDismissInput!) {\n workspaceMutations {\n dismiss(input: $input)\n }\n }\n": types.DismissDiscoverableWorkspaceDocument,
|
||||
"\n query WorkspaceAccessCheck($slug: String!) {\n workspaceBySlug(slug: $slug) {\n id\n }\n }\n": types.WorkspaceAccessCheckDocument,
|
||||
"\n query WorkspacePageQuery(\n $workspaceSlug: String!\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n $token: String\n ) {\n workspaceBySlug(slug: $workspaceSlug) {\n ...WorkspaceProjectList_Workspace\n }\n workspaceInvite(\n workspaceId: $workspaceSlug\n token: $token\n options: { useSlug: true }\n ) {\n id\n ...WorkspaceInviteBanner_PendingWorkspaceCollaborator\n ...WorkspaceInviteBlock_PendingWorkspaceCollaborator\n }\n }\n": types.WorkspacePageQueryDocument,
|
||||
"\n query WorkspaceProjectsQuery(\n $workspaceSlug: String!\n $filter: WorkspaceProjectsFilter\n $cursor: String\n ) {\n workspaceBySlug(slug: $workspaceSlug) {\n id\n projects(filter: $filter, cursor: $cursor, limit: 10) {\n ...WorkspaceProjectList_ProjectCollection\n }\n }\n }\n": types.WorkspaceProjectsQueryDocument,
|
||||
"\n query WorkspaceSidebar(\n $workspaceSlug: String!\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n ) {\n workspaceBySlug(slug: $workspaceSlug) {\n ...WorkspaceSidebar_Workspace\n }\n }\n": types.WorkspaceSidebarDocument,
|
||||
"\n query WorkspaceDashboard(\n $workspaceSlug: String!\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n ) {\n workspaceBySlug(slug: $workspaceSlug) {\n ...WorkspaceDashboard_Workspace\n }\n }\n": types.WorkspaceDashboardDocument,
|
||||
"\n query WorkspaceProjectsQuery(\n $workspaceSlug: String!\n $filter: WorkspaceProjectsFilter\n $cursor: String\n ) {\n workspaceBySlug(slug: $workspaceSlug) {\n id\n projects(filter: $filter, cursor: $cursor, limit: 10) {\n ...WorkspaceDashboardProjectList_ProjectCollection\n }\n }\n }\n": types.WorkspaceProjectsQueryDocument,
|
||||
"\n query WorkspaceFunctionsQuery($workspaceSlug: String!) {\n ...AutomateFunctionsPageHeader_Query\n workspaceBySlug(slug: $workspaceSlug) {\n id\n name\n automateFunctions {\n items {\n id\n ...AutomationsFunctionsCard_AutomateFunction\n ...AutomateAutomationCreateDialog_AutomateFunction\n }\n }\n }\n }\n": types.WorkspaceFunctionsQueryDocument,
|
||||
"\n query WorkspaceInvite(\n $workspaceId: String\n $token: String\n $options: WorkspaceInviteLookupOptions\n ) {\n workspaceInvite(workspaceId: $workspaceId, token: $token, options: $options) {\n ...WorkspaceInviteBanner_PendingWorkspaceCollaborator\n ...WorkspaceInviteBlock_PendingWorkspaceCollaborator\n }\n }\n": types.WorkspaceInviteDocument,
|
||||
"\n query ValidateWorkspaceSlug($slug: String!) {\n validateWorkspaceSlug(slug: $slug)\n }\n": types.ValidateWorkspaceSlugDocument,
|
||||
@@ -823,13 +817,13 @@ const documents: Documents = {
|
||||
"\n query DiscoverableWorkspacesRequests {\n activeUser {\n id\n ...DiscoverableList_Requests\n }\n }\n": types.DiscoverableWorkspacesRequestsDocument,
|
||||
"\n query WorkspacePlan($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspacesPlan_Workspace\n }\n }\n": types.WorkspacePlanDocument,
|
||||
"\n query activeWorkspace($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...ActiveWorkspace_Workspace\n }\n }\n": types.ActiveWorkspaceDocument,
|
||||
"\n query WorkspaceLastAdminCheck($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspaceLastAdminCheck_Workspace\n }\n }\n": types.WorkspaceLastAdminCheckDocument,
|
||||
"\n query WorkspaceLastAdminCheck($slug: String!) {\n workspaceBySlug(slug: $slug) {\n teamByRole {\n admins {\n totalCount\n }\n }\n }\n }\n": types.WorkspaceLastAdminCheckDocument,
|
||||
"\n query WorkspaceLimits($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspacePlanLimits_Workspace\n }\n }\n": types.WorkspaceLimitsDocument,
|
||||
"\n query WorkspaceUsage($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspaceUsage_Workspace\n }\n }\n": types.WorkspaceUsageDocument,
|
||||
"\n query WorkspaceMoveProjectManagerProject($projectId: String!) {\n project(id: $projectId) {\n ...WorkspaceMoveProjectManager_Project\n }\n }\n": types.WorkspaceMoveProjectManagerProjectDocument,
|
||||
"\n query WorkspaceMoveProjectManagerWorkspace(\n $workspaceSlug: String!\n $projectId: String\n ) {\n workspaceBySlug(slug: $workspaceSlug) {\n ...WorkspaceMoveProjectManager_Workspace\n }\n }\n": types.WorkspaceMoveProjectManagerWorkspaceDocument,
|
||||
"\n query WorkspaceMoveProjectManagerUser(\n $cursor: String\n $filter: UserProjectsFilter\n $projectId: String\n ) {\n activeUser {\n ...WorkspaceMoveProjectSelectWorkspace_User\n }\n }\n": types.WorkspaceMoveProjectManagerUserDocument,
|
||||
"\n subscription onWorkspaceUpdated(\n $workspaceId: String\n $workspaceSlug: String\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n ) {\n workspaceUpdated(workspaceId: $workspaceId, workspaceSlug: $workspaceSlug) {\n id\n workspace {\n id\n ...WorkspaceProjectList_Workspace\n }\n }\n }\n": types.OnWorkspaceUpdatedDocument,
|
||||
"\n subscription onWorkspaceUpdated(\n $workspaceId: String\n $workspaceSlug: String\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n ) {\n workspaceUpdated(workspaceId: $workspaceId, workspaceSlug: $workspaceSlug) {\n id\n workspace {\n id\n ...WorkspaceDashboard_Workspace\n ...WorkspaceDashboardProjectList_Workspace\n }\n }\n }\n": types.OnWorkspaceUpdatedDocument,
|
||||
"\n query LegacyBranchRedirectMetadata($streamId: String!, $branchName: String!) {\n project(id: $streamId) {\n modelByName(name: $branchName) {\n id\n }\n }\n }\n": types.LegacyBranchRedirectMetadataDocument,
|
||||
"\n query LegacyViewerCommitRedirectMetadata($streamId: String!, $commitId: String!) {\n project(id: $streamId) {\n version(id: $commitId) {\n id\n model {\n id\n }\n }\n }\n }\n": types.LegacyViewerCommitRedirectMetadataDocument,
|
||||
"\n query LegacyViewerStreamRedirectMetadata($streamId: String!) {\n project(id: $streamId) {\n id\n versions(limit: 1) {\n totalCount\n items {\n id\n model {\n id\n }\n }\n }\n }\n }\n": types.LegacyViewerStreamRedirectMetadataDocument,
|
||||
@@ -997,7 +991,7 @@ export function graphql(source: "\n fragment FormUsersSelectItem on LimitedUser
|
||||
/**
|
||||
* 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 HeaderWorkspaceSwitcherActiveWorkspace_Workspace on Workspace {\n id\n name\n logo\n ...HeaderWorkspaceSwitcherHeaderWorkspace_Workspace\n }\n"): (typeof documents)["\n fragment HeaderWorkspaceSwitcherActiveWorkspace_Workspace on Workspace {\n id\n name\n logo\n ...HeaderWorkspaceSwitcherHeaderWorkspace_Workspace\n }\n"];
|
||||
export function graphql(source: "\n fragment HeaderWorkspaceSwitcherActiveWorkspace_Workspace on Workspace {\n ...HeaderWorkspaceSwitcherHeaderWorkspace_Workspace\n ...InviteDialogWorkspace_Workspace\n id\n name\n logo\n }\n"): (typeof documents)["\n fragment HeaderWorkspaceSwitcherActiveWorkspace_Workspace on Workspace {\n ...HeaderWorkspaceSwitcherHeaderWorkspace_Workspace\n ...InviteDialogWorkspace_Workspace\n id\n name\n logo\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -1013,7 +1007,7 @@ export function graphql(source: "\n fragment HeaderWorkspaceSwitcherHeaderExpir
|
||||
/**
|
||||
* 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 HeaderWorkspaceSwitcherHeaderWorkspace_Workspace on Workspace {\n ...InviteDialogWorkspace_Workspace\n id\n name\n logo\n role\n plan {\n name\n }\n team {\n totalCount\n }\n }\n"): (typeof documents)["\n fragment HeaderWorkspaceSwitcherHeaderWorkspace_Workspace on Workspace {\n ...InviteDialogWorkspace_Workspace\n id\n name\n logo\n role\n plan {\n name\n }\n team {\n totalCount\n }\n }\n"];
|
||||
export function graphql(source: "\n fragment HeaderWorkspaceSwitcherHeaderWorkspace_Workspace on Workspace {\n id\n name\n logo\n role\n plan {\n name\n }\n team {\n totalCount\n }\n }\n"): (typeof documents)["\n fragment HeaderWorkspaceSwitcherHeaderWorkspace_Workspace on Workspace {\n id\n name\n logo\n role\n plan {\n name\n }\n team {\n totalCount\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -1225,11 +1219,7 @@ export function graphql(source: "\n fragment ProjectsInviteBanner on PendingStr
|
||||
/**
|
||||
* 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 SettingsSidebar_Workspace on Workspace {\n ...SettingsMenu_Workspace\n id\n slug\n role\n name\n logo\n plan {\n status\n name\n }\n creationState {\n completed\n }\n }\n"): (typeof documents)["\n fragment SettingsSidebar_Workspace on Workspace {\n ...SettingsMenu_Workspace\n id\n slug\n role\n name\n logo\n plan {\n status\n name\n }\n creationState {\n completed\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 fragment SettingsSidebar_User on User {\n id\n workspaces {\n items {\n ...SettingsSidebar_Workspace\n }\n }\n }\n"): (typeof documents)["\n fragment SettingsSidebar_User on User {\n id\n workspaces {\n items {\n ...SettingsSidebar_Workspace\n }\n }\n }\n"];
|
||||
export function graphql(source: "\n fragment SettingsSidebar_Workspace on Workspace {\n ...SettingsMenu_Workspace\n id\n slug\n role\n }\n"): (typeof documents)["\n fragment SettingsSidebar_Workspace on Workspace {\n ...SettingsMenu_Workspace\n id\n slug\n role\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -1349,15 +1339,23 @@ export function graphql(source: "\n fragment ViewerModelVersionCardItem on Vers
|
||||
/**
|
||||
* 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 WorkspaceProjectList_Workspace on Workspace {\n id\n ...WorkspaceBase_Workspace\n ...WorkspaceTeam_Workspace\n ...WorkspaceSecurity_Workspace\n ...WorkspaceHeader_Workspace\n ...BillingAlert_Workspace\n ...InviteDialogWorkspace_Workspace\n projects {\n ...WorkspaceProjectList_ProjectCollection\n }\n creationState {\n completed\n state\n }\n permissions {\n canCreateProject {\n ...FullPermissionCheckResult\n }\n }\n }\n"): (typeof documents)["\n fragment WorkspaceProjectList_Workspace on Workspace {\n id\n ...WorkspaceBase_Workspace\n ...WorkspaceTeam_Workspace\n ...WorkspaceSecurity_Workspace\n ...WorkspaceHeader_Workspace\n ...BillingAlert_Workspace\n ...InviteDialogWorkspace_Workspace\n projects {\n ...WorkspaceProjectList_ProjectCollection\n }\n creationState {\n completed\n state\n }\n permissions {\n canCreateProject {\n ...FullPermissionCheckResult\n }\n }\n }\n"];
|
||||
export function graphql(source: "\n fragment WorkspaceAddProjectMenu_Workspace on Workspace {\n id\n name\n slug\n role\n plan {\n name\n }\n permissions {\n canCreateProject {\n ...FullPermissionCheckResult\n }\n canMoveProjectToWorkspace {\n ...FullPermissionCheckResult\n }\n }\n }\n"): (typeof documents)["\n fragment WorkspaceAddProjectMenu_Workspace on Workspace {\n id\n name\n slug\n role\n plan {\n name\n }\n permissions {\n canCreateProject {\n ...FullPermissionCheckResult\n }\n canMoveProjectToWorkspace {\n ...FullPermissionCheckResult\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 fragment WorkspaceProjectList_ProjectCollection on ProjectCollection {\n totalCount\n items {\n ...ProjectDashboardItem\n }\n cursor\n }\n"): (typeof documents)["\n fragment WorkspaceProjectList_ProjectCollection on ProjectCollection {\n totalCount\n items {\n ...ProjectDashboardItem\n }\n cursor\n }\n"];
|
||||
export function graphql(source: "\n fragment WorkspaceDashboard_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceDashboardHeader_Workspace\n ...WorkspaceDashboardProjectList_Workspace\n id\n name\n role\n creationState {\n completed\n state\n }\n }\n"): (typeof documents)["\n fragment WorkspaceDashboard_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceDashboardHeader_Workspace\n ...WorkspaceDashboardProjectList_Workspace\n id\n name\n role\n creationState {\n completed\n state\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 fragment WorkspaceHeader_Workspace on Workspace {\n ...WorkspaceBase_Workspace\n ...WorkspaceTeam_Workspace\n ...BillingAlert_Workspace\n slug\n readOnly\n permissions {\n canCreateProject {\n ...FullPermissionCheckResult\n }\n canMoveProjectToWorkspace {\n ...FullPermissionCheckResult\n }\n }\n }\n"): (typeof documents)["\n fragment WorkspaceHeader_Workspace on Workspace {\n ...WorkspaceBase_Workspace\n ...WorkspaceTeam_Workspace\n ...BillingAlert_Workspace\n slug\n readOnly\n permissions {\n canCreateProject {\n ...FullPermissionCheckResult\n }\n canMoveProjectToWorkspace {\n ...FullPermissionCheckResult\n }\n }\n }\n"];
|
||||
export function graphql(source: "\n fragment WorkspaceDashboardHeader_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceAddProjectMenu_Workspace\n ...BillingAlert_Workspace\n id\n role\n plan {\n status\n }\n }\n"): (typeof documents)["\n fragment WorkspaceDashboardHeader_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceAddProjectMenu_Workspace\n ...BillingAlert_Workspace\n id\n role\n plan {\n status\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 fragment WorkspaceDashboardProjectList_ProjectCollection on ProjectCollection {\n totalCount\n items {\n ...ProjectDashboardItem\n }\n cursor\n }\n"): (typeof documents)["\n fragment WorkspaceDashboardProjectList_ProjectCollection on ProjectCollection {\n totalCount\n items {\n ...ProjectDashboardItem\n }\n cursor\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 fragment WorkspaceDashboardProjectList_Workspace on Workspace {\n ...WorkspaceAddProjectMenu_Workspace\n id\n }\n"): (typeof documents)["\n fragment WorkspaceDashboardProjectList_Workspace on Workspace {\n ...WorkspaceAddProjectMenu_Workspace\n id\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -1389,15 +1387,19 @@ export function graphql(source: "\n fragment WorkspaceMoveProjectSelectWorkspac
|
||||
/**
|
||||
* 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 WorkspaceSidebarAbout_Workspace on Workspace {\n ...WorkspaceDashboardAbout_Workspace\n }\n"): (typeof documents)["\n fragment WorkspaceSidebarAbout_Workspace on Workspace {\n ...WorkspaceDashboardAbout_Workspace\n }\n"];
|
||||
export function graphql(source: "\n fragment WorkspaceSidebarAbout_Workspace on Workspace {\n id\n name\n description\n }\n"): (typeof documents)["\n fragment WorkspaceSidebarAbout_Workspace on Workspace {\n id\n name\n description\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 fragment WorkspaceSidebarSecurity_Workspace on Workspace {\n ...WorkspaceSecurity_Workspace\n }\n"): (typeof documents)["\n fragment WorkspaceSidebarSecurity_Workspace on Workspace {\n ...WorkspaceSecurity_Workspace\n }\n"];
|
||||
export function graphql(source: "\n fragment WorkspaceSidebarMembers_Workspace on Workspace {\n ...InviteDialogWorkspace_Workspace\n id\n slug\n team {\n totalCount\n items {\n id\n user {\n id\n name\n ...LimitedUserAvatar\n }\n }\n }\n invitedTeam(filter: $invitesFilter) {\n id\n role\n email\n }\n adminWorkspacesJoinRequests {\n totalCount\n items {\n status\n id\n }\n }\n }\n"): (typeof documents)["\n fragment WorkspaceSidebarMembers_Workspace on Workspace {\n ...InviteDialogWorkspace_Workspace\n id\n slug\n team {\n totalCount\n items {\n id\n user {\n id\n name\n ...LimitedUserAvatar\n }\n }\n }\n invitedTeam(filter: $invitesFilter) {\n id\n role\n email\n }\n adminWorkspacesJoinRequests {\n totalCount\n items {\n status\n id\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 fragment WorkspaceSidebar_Workspace on Workspace {\n ...WorkspaceDashboardAbout_Workspace\n ...WorkspaceTeam_Workspace\n ...WorkspaceSecurity_Workspace\n slug\n plan {\n status\n }\n }\n"): (typeof documents)["\n fragment WorkspaceSidebar_Workspace on Workspace {\n ...WorkspaceDashboardAbout_Workspace\n ...WorkspaceTeam_Workspace\n ...WorkspaceSecurity_Workspace\n slug\n plan {\n status\n }\n }\n"];
|
||||
export function graphql(source: "\n fragment WorkspaceSidebarSecurity_Workspace on Workspace {\n id\n slug\n domains {\n id\n domain\n }\n }\n"): (typeof documents)["\n fragment WorkspaceSidebarSecurity_Workspace on Workspace {\n id\n slug\n domains {\n id\n domain\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 fragment WorkspaceSidebar_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceSidebarAbout_Workspace\n ...WorkspaceSidebarSecurity_Workspace\n id\n role\n slug\n domains {\n id\n }\n }\n"): (typeof documents)["\n fragment WorkspaceSidebar_Workspace on Workspace {\n ...WorkspaceSidebarMembers_Workspace\n ...WorkspaceSidebarAbout_Workspace\n ...WorkspaceSidebarSecurity_Workspace\n id\n role\n slug\n domains {\n id\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -2061,7 +2063,7 @@ export function graphql(source: "\n mutation SettingsBillingCancelCheckoutSessi
|
||||
/**
|
||||
* 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 SettingsSidebar {\n activeUser {\n ...SettingsSidebar_User\n }\n }\n"): (typeof documents)["\n query SettingsSidebar {\n activeUser {\n ...SettingsSidebar_User\n }\n }\n"];
|
||||
export function graphql(source: "\n query SettingsSidebar {\n activeUser {\n activeWorkspace {\n ...SettingsSidebar_Workspace\n }\n }\n }\n"): (typeof documents)["\n query SettingsSidebar {\n activeUser {\n activeWorkspace {\n ...SettingsSidebar_Workspace\n }\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -2286,30 +2288,6 @@ export function graphql(source: "\n fragment WorkspaceSsoStatus_User on User
|
||||
* 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 WorkspaceUsage_Workspace on Workspace {\n id\n slug\n plan {\n usage {\n projectCount\n modelCount\n }\n }\n team {\n totalCount\n }\n teamByRole {\n admins {\n totalCount\n }\n members {\n totalCount\n }\n guests {\n totalCount\n }\n }\n }\n"): (typeof documents)["\n fragment WorkspaceUsage_Workspace on Workspace {\n id\n slug\n plan {\n usage {\n projectCount\n modelCount\n }\n }\n team {\n totalCount\n }\n teamByRole {\n admins {\n totalCount\n }\n members {\n totalCount\n }\n guests {\n totalCount\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 fragment WorkspaceBase_Workspace on Workspace {\n id\n name\n slug\n role\n description\n logo\n plan {\n status\n createdAt\n }\n }\n"): (typeof documents)["\n fragment WorkspaceBase_Workspace on Workspace {\n id\n name\n slug\n role\n description\n logo\n plan {\n status\n createdAt\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 fragment WorkspaceDashboardAbout_Workspace on Workspace {\n id\n name\n description\n }\n"): (typeof documents)["\n fragment WorkspaceDashboardAbout_Workspace on Workspace {\n id\n name\n description\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 fragment WorkspaceInvitedTeam_Workspace on Workspace {\n id\n invitedTeam(filter: $invitesFilter) {\n id\n role\n email\n }\n }\n"): (typeof documents)["\n fragment WorkspaceInvitedTeam_Workspace on Workspace {\n id\n invitedTeam(filter: $invitesFilter) {\n id\n role\n email\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 fragment WorkspaceTeam_Workspace on Workspace {\n id\n slug\n team(limit: 250) {\n totalCount\n items {\n id\n user {\n id\n name\n ...LimitedUserAvatar\n }\n }\n }\n adminWorkspacesJoinRequests {\n totalCount\n items {\n status\n id\n }\n }\n ...WorkspaceInvitedTeam_Workspace\n }\n"): (typeof documents)["\n fragment WorkspaceTeam_Workspace on Workspace {\n id\n slug\n team(limit: 250) {\n totalCount\n items {\n id\n user {\n id\n name\n ...LimitedUserAvatar\n }\n }\n }\n adminWorkspacesJoinRequests {\n totalCount\n items {\n status\n id\n }\n }\n ...WorkspaceInvitedTeam_Workspace\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 fragment WorkspaceSecurity_Workspace on Workspace {\n id\n slug\n domains {\n id\n domain\n }\n }\n"): (typeof documents)["\n fragment WorkspaceSecurity_Workspace on Workspace {\n id\n slug\n domains {\n id\n domain\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 fragment WorkspaceLastAdminCheck_Workspace on Workspace {\n id\n team(limit: 50, filter: { roles: [\"workspace:admin\"] }) {\n items {\n id\n }\n }\n }\n"): (typeof documents)["\n fragment WorkspaceLastAdminCheck_Workspace on Workspace {\n id\n team(limit: 50, filter: { roles: [\"workspace:admin\"] }) {\n items {\n id\n }\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -2373,11 +2351,15 @@ export function graphql(source: "\n query WorkspaceAccessCheck($slug: 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 WorkspacePageQuery(\n $workspaceSlug: String!\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n $token: String\n ) {\n workspaceBySlug(slug: $workspaceSlug) {\n ...WorkspaceProjectList_Workspace\n }\n workspaceInvite(\n workspaceId: $workspaceSlug\n token: $token\n options: { useSlug: true }\n ) {\n id\n ...WorkspaceInviteBanner_PendingWorkspaceCollaborator\n ...WorkspaceInviteBlock_PendingWorkspaceCollaborator\n }\n }\n"): (typeof documents)["\n query WorkspacePageQuery(\n $workspaceSlug: String!\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n $token: String\n ) {\n workspaceBySlug(slug: $workspaceSlug) {\n ...WorkspaceProjectList_Workspace\n }\n workspaceInvite(\n workspaceId: $workspaceSlug\n token: $token\n options: { useSlug: true }\n ) {\n id\n ...WorkspaceInviteBanner_PendingWorkspaceCollaborator\n ...WorkspaceInviteBlock_PendingWorkspaceCollaborator\n }\n }\n"];
|
||||
export function graphql(source: "\n query WorkspaceSidebar(\n $workspaceSlug: String!\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n ) {\n workspaceBySlug(slug: $workspaceSlug) {\n ...WorkspaceSidebar_Workspace\n }\n }\n"): (typeof documents)["\n query WorkspaceSidebar(\n $workspaceSlug: String!\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n ) {\n workspaceBySlug(slug: $workspaceSlug) {\n ...WorkspaceSidebar_Workspace\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 WorkspaceProjectsQuery(\n $workspaceSlug: String!\n $filter: WorkspaceProjectsFilter\n $cursor: String\n ) {\n workspaceBySlug(slug: $workspaceSlug) {\n id\n projects(filter: $filter, cursor: $cursor, limit: 10) {\n ...WorkspaceProjectList_ProjectCollection\n }\n }\n }\n"): (typeof documents)["\n query WorkspaceProjectsQuery(\n $workspaceSlug: String!\n $filter: WorkspaceProjectsFilter\n $cursor: String\n ) {\n workspaceBySlug(slug: $workspaceSlug) {\n id\n projects(filter: $filter, cursor: $cursor, limit: 10) {\n ...WorkspaceProjectList_ProjectCollection\n }\n }\n }\n"];
|
||||
export function graphql(source: "\n query WorkspaceDashboard(\n $workspaceSlug: String!\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n ) {\n workspaceBySlug(slug: $workspaceSlug) {\n ...WorkspaceDashboard_Workspace\n }\n }\n"): (typeof documents)["\n query WorkspaceDashboard(\n $workspaceSlug: String!\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n ) {\n workspaceBySlug(slug: $workspaceSlug) {\n ...WorkspaceDashboard_Workspace\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 WorkspaceProjectsQuery(\n $workspaceSlug: String!\n $filter: WorkspaceProjectsFilter\n $cursor: String\n ) {\n workspaceBySlug(slug: $workspaceSlug) {\n id\n projects(filter: $filter, cursor: $cursor, limit: 10) {\n ...WorkspaceDashboardProjectList_ProjectCollection\n }\n }\n }\n"): (typeof documents)["\n query WorkspaceProjectsQuery(\n $workspaceSlug: String!\n $filter: WorkspaceProjectsFilter\n $cursor: String\n ) {\n workspaceBySlug(slug: $workspaceSlug) {\n id\n projects(filter: $filter, cursor: $cursor, limit: 10) {\n ...WorkspaceDashboardProjectList_ProjectCollection\n }\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -2425,7 +2407,7 @@ export function graphql(source: "\n query activeWorkspace($slug: String!) {\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 WorkspaceLastAdminCheck($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspaceLastAdminCheck_Workspace\n }\n }\n"): (typeof documents)["\n query WorkspaceLastAdminCheck($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspaceLastAdminCheck_Workspace\n }\n }\n"];
|
||||
export function graphql(source: "\n query WorkspaceLastAdminCheck($slug: String!) {\n workspaceBySlug(slug: $slug) {\n teamByRole {\n admins {\n totalCount\n }\n }\n }\n }\n"): (typeof documents)["\n query WorkspaceLastAdminCheck($slug: String!) {\n workspaceBySlug(slug: $slug) {\n teamByRole {\n admins {\n totalCount\n }\n }\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -2449,7 +2431,7 @@ export function graphql(source: "\n query WorkspaceMoveProjectManagerUser(\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 subscription onWorkspaceUpdated(\n $workspaceId: String\n $workspaceSlug: String\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n ) {\n workspaceUpdated(workspaceId: $workspaceId, workspaceSlug: $workspaceSlug) {\n id\n workspace {\n id\n ...WorkspaceProjectList_Workspace\n }\n }\n }\n"): (typeof documents)["\n subscription onWorkspaceUpdated(\n $workspaceId: String\n $workspaceSlug: String\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n ) {\n workspaceUpdated(workspaceId: $workspaceId, workspaceSlug: $workspaceSlug) {\n id\n workspace {\n id\n ...WorkspaceProjectList_Workspace\n }\n }\n }\n"];
|
||||
export function graphql(source: "\n subscription onWorkspaceUpdated(\n $workspaceId: String\n $workspaceSlug: String\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n ) {\n workspaceUpdated(workspaceId: $workspaceId, workspaceSlug: $workspaceSlug) {\n id\n workspace {\n id\n ...WorkspaceDashboard_Workspace\n ...WorkspaceDashboardProjectList_Workspace\n }\n }\n }\n"): (typeof documents)["\n subscription onWorkspaceUpdated(\n $workspaceId: String\n $workspaceSlug: String\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n ) {\n workspaceUpdated(workspaceId: $workspaceId, workspaceSlug: $workspaceSlug) {\n id\n workspace {\n id\n ...WorkspaceDashboard_Workspace\n ...WorkspaceDashboardProjectList_Workspace\n }\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -41,39 +41,39 @@ export const settingsServerRoutes = {
|
||||
export const settingsWorkspaceRoutes = {
|
||||
general: {
|
||||
name: 'settings-workspaces-slug-general',
|
||||
route: (slug: string) => `/settings/workspaces/${slug}/general`
|
||||
route: (slug?: string) => `/settings/workspaces/${slug}/general`
|
||||
},
|
||||
members: {
|
||||
name: 'settings-workspaces-slug-members',
|
||||
route: (slug: string) => `/settings/workspaces/${slug}/members`
|
||||
route: (slug?: string) => `/settings/workspaces/${slug}/members`
|
||||
},
|
||||
membersGuests: {
|
||||
name: 'settings-workspaces-slug-members-guests',
|
||||
route: (slug: string) => `/settings/workspaces/${slug}/members/guests`
|
||||
route: (slug?: string) => `/settings/workspaces/${slug}/members/guests`
|
||||
},
|
||||
membersInvites: {
|
||||
name: 'settings-workspaces-slug-members-invites',
|
||||
route: (slug: string) => `/settings/workspaces/${slug}/members/invites`
|
||||
route: (slug?: string) => `/settings/workspaces/${slug}/members/invites`
|
||||
},
|
||||
membersRequests: {
|
||||
name: 'settings-workspaces-slug-members-requests',
|
||||
route: (slug: string) => `/settings/workspaces/${slug}/members/requests`
|
||||
route: (slug?: string) => `/settings/workspaces/${slug}/members/requests`
|
||||
},
|
||||
projects: {
|
||||
name: 'settings-workspaces-slug-projects',
|
||||
route: (slug: string) => `/settings/workspaces/${slug}/projects`
|
||||
route: (slug?: string) => `/settings/workspaces/${slug}/projects`
|
||||
},
|
||||
security: {
|
||||
name: 'settings-workspaces-slug-security',
|
||||
route: (slug: string) => `/settings/workspaces/${slug}/security`
|
||||
route: (slug?: string) => `/settings/workspaces/${slug}/security`
|
||||
},
|
||||
billing: {
|
||||
name: 'settings-workspaces-slug-billing',
|
||||
route: (slug: string) => `/settings/workspaces/${slug}/billing`
|
||||
route: (slug?: string) => `/settings/workspaces/${slug}/billing`
|
||||
},
|
||||
regions: {
|
||||
name: 'settings-workspaces-slug-regions',
|
||||
route: (slug: string) => `/settings/workspaces/${slug}/regions`
|
||||
route: (slug?: string) => `/settings/workspaces/${slug}/regions`
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,37 +39,37 @@ export const useSettingsMenu = () => {
|
||||
{
|
||||
title: 'General',
|
||||
name: settingsWorkspaceRoutes.general.name,
|
||||
route: (slug: string) => settingsWorkspaceRoutes.general.route(slug),
|
||||
route: (slug?: string) => settingsWorkspaceRoutes.general.route(slug),
|
||||
permission: [Roles.Workspace.Admin, Roles.Workspace.Member, Roles.Workspace.Guest]
|
||||
},
|
||||
{
|
||||
title: 'People',
|
||||
name: settingsWorkspaceRoutes.members.name,
|
||||
route: (slug: string) => settingsWorkspaceRoutes.members.route(slug),
|
||||
route: (slug?: string) => settingsWorkspaceRoutes.members.route(slug),
|
||||
permission: [Roles.Workspace.Admin, Roles.Workspace.Member]
|
||||
},
|
||||
{
|
||||
title: 'Projects',
|
||||
name: settingsWorkspaceRoutes.projects.name,
|
||||
route: (slug: string) => settingsWorkspaceRoutes.projects.route(slug),
|
||||
route: (slug?: string) => settingsWorkspaceRoutes.projects.route(slug),
|
||||
permission: [Roles.Workspace.Admin, Roles.Workspace.Member]
|
||||
},
|
||||
{
|
||||
title: 'Security',
|
||||
name: settingsWorkspaceRoutes.security.name,
|
||||
route: (slug: string) => settingsWorkspaceRoutes.security.route(slug),
|
||||
route: (slug?: string) => settingsWorkspaceRoutes.security.route(slug),
|
||||
permission: [Roles.Workspace.Admin]
|
||||
},
|
||||
{
|
||||
title: 'Billing',
|
||||
name: settingsWorkspaceRoutes.billing.name,
|
||||
route: (slug: string) => settingsWorkspaceRoutes.billing.route(slug),
|
||||
route: (slug?: string) => settingsWorkspaceRoutes.billing.route(slug),
|
||||
permission: [Roles.Workspace.Admin, Roles.Workspace.Member]
|
||||
},
|
||||
{
|
||||
title: 'Data residency',
|
||||
name: settingsWorkspaceRoutes.regions.name,
|
||||
route: (slug: string) => settingsWorkspaceRoutes.regions.route(slug),
|
||||
route: (slug?: string) => settingsWorkspaceRoutes.regions.route(slug),
|
||||
permission: [Roles.Workspace.Admin, Roles.Workspace.Member],
|
||||
...(!isMultiRegionEnabled
|
||||
? {
|
||||
@@ -149,7 +149,7 @@ export const useSettingsMembersActions = (params: {
|
||||
}) => {
|
||||
const { activeUser } = useActiveUser()
|
||||
|
||||
const { hasSingleAdmin } = useWorkspaceLastAdminCheck({
|
||||
const { isLastAdmin } = useWorkspaceLastAdminCheck({
|
||||
workspaceSlug: params.workspaceSlug.value || ''
|
||||
})
|
||||
|
||||
@@ -164,7 +164,7 @@ export const useSettingsMembersActions = (params: {
|
||||
)
|
||||
|
||||
const isOnlyAdmin = computed(
|
||||
() => hasSingleAdmin.value && isActiveUserWorkspaceAdmin.value
|
||||
() => isLastAdmin.value && isActiveUserWorkspaceAdmin.value
|
||||
)
|
||||
|
||||
const isActiveUserTargetUser = computed(
|
||||
|
||||
@@ -3,7 +3,9 @@ import { graphql } from '~~/lib/common/generated/gql'
|
||||
export const settingsSidebarQuery = graphql(`
|
||||
query SettingsSidebar {
|
||||
activeUser {
|
||||
...SettingsSidebar_User
|
||||
activeWorkspace {
|
||||
...SettingsSidebar_Workspace
|
||||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
@@ -13,7 +13,7 @@ export type GenericSettingsMenuItem = BaseSettingsMenuItem & {
|
||||
|
||||
export type WorkspaceSettingsMenuItem = BaseSettingsMenuItem & {
|
||||
name: string
|
||||
route: (slug: string) => string
|
||||
route: (slug?: string) => string
|
||||
}
|
||||
|
||||
export enum WorkspaceUserActionTypes {
|
||||
|
||||
@@ -2,7 +2,6 @@ import { graphql } from '~/lib/common/generated/gql/gql'
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import { workspaceLimitsQuery } from '~/lib/workspaces/graphql/queries'
|
||||
import { WorkspacePlanConfigs } from '@speckle/shared'
|
||||
import { useWorkspaceUsage } from '~/lib/workspaces/composables/usage'
|
||||
import type { WorkspacePlanLimits_WorkspaceFragment } from '~/lib/common/generated/gql/graphql'
|
||||
|
||||
graphql(`
|
||||
@@ -19,7 +18,6 @@ export const useLimitsState = () =>
|
||||
useState<WorkspacePlanLimits_WorkspaceFragment | null>('limits', () => null)
|
||||
|
||||
export const useWorkspaceLimits = (slug: string) => {
|
||||
const { modelCount, projectCount } = useWorkspaceUsage(slug)
|
||||
const limitsState = useLimitsState()
|
||||
|
||||
const { onResult } = useQuery(
|
||||
@@ -67,19 +65,8 @@ export const useWorkspaceLimits = (slug: string) => {
|
||||
return `${value} ${unit}`
|
||||
})
|
||||
|
||||
const remainingProjectCount = computed(() =>
|
||||
limits.value.projectCount ? limits.value.projectCount - projectCount.value : 0
|
||||
)
|
||||
|
||||
const remainingModelCount = computed(() =>
|
||||
limits.value.modelCount ? limits.value.modelCount - modelCount.value : 0
|
||||
)
|
||||
return {
|
||||
projectCount,
|
||||
modelCount,
|
||||
limits,
|
||||
remainingProjectCount,
|
||||
remainingModelCount,
|
||||
versionLimitFormatted,
|
||||
commentLimitFormatted
|
||||
}
|
||||
|
||||
@@ -658,12 +658,11 @@ export const useWorkspaceLastAdminCheck = (params: { workspaceSlug: string }) =>
|
||||
slug: workspaceSlug
|
||||
})
|
||||
|
||||
const hasSingleAdmin = computed(() => {
|
||||
const admins = result.value?.workspaceBySlug?.team.items || []
|
||||
return admins.length === 1
|
||||
})
|
||||
const isLastAdmin = computed(
|
||||
() => result.value?.workspaceBySlug?.teamByRole?.admins?.totalCount === 1
|
||||
)
|
||||
|
||||
return {
|
||||
hasSingleAdmin
|
||||
isLastAdmin
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
import { graphql } from '~~/lib/common/generated/gql'
|
||||
|
||||
// Base workspace fragment
|
||||
export const workspaceBaseFragment = graphql(`
|
||||
fragment WorkspaceBase_Workspace on Workspace {
|
||||
id
|
||||
name
|
||||
slug
|
||||
role
|
||||
description
|
||||
logo
|
||||
plan {
|
||||
status
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
export const workspaceDashboardAboutFragment = graphql(`
|
||||
fragment WorkspaceDashboardAbout_Workspace on Workspace {
|
||||
id
|
||||
name
|
||||
description
|
||||
}
|
||||
`)
|
||||
|
||||
export const workspaceInvitedTeamFragment = graphql(`
|
||||
fragment WorkspaceInvitedTeam_Workspace on Workspace {
|
||||
id
|
||||
invitedTeam(filter: $invitesFilter) {
|
||||
id
|
||||
role
|
||||
email
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
export const workspaceTeamFragment = graphql(`
|
||||
fragment WorkspaceTeam_Workspace on Workspace {
|
||||
id
|
||||
slug
|
||||
team(limit: 250) {
|
||||
totalCount
|
||||
items {
|
||||
id
|
||||
user {
|
||||
id
|
||||
name
|
||||
...LimitedUserAvatar
|
||||
}
|
||||
}
|
||||
}
|
||||
adminWorkspacesJoinRequests {
|
||||
totalCount
|
||||
items {
|
||||
status
|
||||
id
|
||||
}
|
||||
}
|
||||
...WorkspaceInvitedTeam_Workspace
|
||||
}
|
||||
`)
|
||||
|
||||
export const workspaceSecurityFragment = graphql(`
|
||||
fragment WorkspaceSecurity_Workspace on Workspace {
|
||||
id
|
||||
slug
|
||||
domains {
|
||||
id
|
||||
domain
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
export const workspaceLastAdminCheckFragment = graphql(`
|
||||
fragment WorkspaceLastAdminCheck_Workspace on Workspace {
|
||||
id
|
||||
team(limit: 50, filter: { roles: ["workspace:admin"] }) {
|
||||
items {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
@@ -8,23 +8,24 @@ export const workspaceAccessCheckQuery = graphql(`
|
||||
}
|
||||
`)
|
||||
|
||||
export const workspacePageQuery = graphql(`
|
||||
query WorkspacePageQuery(
|
||||
export const workspaceSidebarQuery = graphql(`
|
||||
query WorkspaceSidebar(
|
||||
$workspaceSlug: String!
|
||||
$invitesFilter: PendingWorkspaceCollaboratorsFilter
|
||||
$token: String
|
||||
) {
|
||||
workspaceBySlug(slug: $workspaceSlug) {
|
||||
...WorkspaceProjectList_Workspace
|
||||
...WorkspaceSidebar_Workspace
|
||||
}
|
||||
workspaceInvite(
|
||||
workspaceId: $workspaceSlug
|
||||
token: $token
|
||||
options: { useSlug: true }
|
||||
) {
|
||||
id
|
||||
...WorkspaceInviteBanner_PendingWorkspaceCollaborator
|
||||
...WorkspaceInviteBlock_PendingWorkspaceCollaborator
|
||||
}
|
||||
`)
|
||||
|
||||
export const workspaceDashboardQuery = graphql(`
|
||||
query WorkspaceDashboard(
|
||||
$workspaceSlug: String!
|
||||
$invitesFilter: PendingWorkspaceCollaboratorsFilter
|
||||
) {
|
||||
workspaceBySlug(slug: $workspaceSlug) {
|
||||
...WorkspaceDashboard_Workspace
|
||||
}
|
||||
}
|
||||
`)
|
||||
@@ -38,7 +39,7 @@ export const workspaceProjectsQuery = graphql(`
|
||||
workspaceBySlug(slug: $workspaceSlug) {
|
||||
id
|
||||
projects(filter: $filter, cursor: $cursor, limit: 10) {
|
||||
...WorkspaceProjectList_ProjectCollection
|
||||
...WorkspaceDashboardProjectList_ProjectCollection
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -153,7 +154,11 @@ export const activeWorkspaceQuery = graphql(`
|
||||
export const workspaceLastAdminCheckQuery = graphql(`
|
||||
query WorkspaceLastAdminCheck($slug: String!) {
|
||||
workspaceBySlug(slug: $slug) {
|
||||
...WorkspaceLastAdminCheck_Workspace
|
||||
teamByRole {
|
||||
admins {
|
||||
totalCount
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
@@ -10,7 +10,8 @@ export const onWorkspaceUpdatedSubscription = graphql(`
|
||||
id
|
||||
workspace {
|
||||
id
|
||||
...WorkspaceProjectList_Workspace
|
||||
...WorkspaceDashboard_Workspace
|
||||
...WorkspaceDashboardProjectList_Workspace
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,24 @@
|
||||
<template>
|
||||
<div>
|
||||
<WorkspaceInviteWrapper
|
||||
v-if="token"
|
||||
:workspace-slug="workspaceSlug"
|
||||
:token="token"
|
||||
/>
|
||||
<WorkspaceProjectList v-else :workspace-slug="workspaceSlug" />
|
||||
<div class="flex w-full">
|
||||
<main class="flex-1 h-full overflow-y-auto simple-scrollbar pt-4 lg:pt-6 pb-16">
|
||||
<div class="container mx-auto px-6 md:px-8">
|
||||
<WorkspaceInviteWrapper
|
||||
v-if="token"
|
||||
:workspace-slug="workspaceSlug"
|
||||
:token="token"
|
||||
/>
|
||||
<WorkspaceDashboard v-else :workspace-slug="workspaceSlug" />
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div
|
||||
v-if="!token"
|
||||
class="hidden lg:flex h-full w-[17rem] shrink-0 border-l border-outline-3 bg-foundation-page"
|
||||
>
|
||||
<div class="h-full w-full">
|
||||
<WorkspaceSidebar :workspace-slug="workspaceSlug" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<nav class="flex flex-col space-y-4">
|
||||
<nav class="flex flex-col">
|
||||
<slot></slot>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user