Merge branch 'main' of github.com:specklesystems/speckle-server into alessandro/web-2728-full-seat-products-for-new-paid-plans
This commit is contained in:
Executable
+38
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
|
||||
GIT_ROOT="$(git rev-parse --show-toplevel)"
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
|
||||
# shellcheck disable=SC1090,SC1091
|
||||
source "${SCRIPT_DIR}/common.sh"
|
||||
|
||||
FE2_DIR_PATH="${FE2_DIR_PATH:-"packages/frontend-2"}"
|
||||
FE2_DATADOG_SERVICE="${FE2_DATADOG_SERVICE:-"web-app-2"}"
|
||||
DATADOG_SITE="${DATADOG_SITE:-"datadoghq.eu"}"
|
||||
|
||||
if [[ -z "${DATADOG_API_KEY}" ]]; then
|
||||
echo "DATADOG_API_KEY is not set"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Build same prod docker image just w/ sourcemaps enabled
|
||||
export DOCKER_BUILDKIT=1
|
||||
docker build --build-arg BUILD_SOURCEMAPS=true --build-arg SPECKLE_SERVER_VERSION="${IMAGE_VERSION_TAG}" --tag "${DOCKER_IMAGE_TAG}:${IMAGE_VERSION_TAG}-sourcemaps" --file "${FE2_DIR_PATH}/Dockerfile" .
|
||||
container_id=$(docker create "${DOCKER_IMAGE_TAG}:${IMAGE_VERSION_TAG}-sourcemaps")
|
||||
|
||||
# Clean target location and copy sourcemaps into it
|
||||
rm -rf "${GIT_ROOT}/${FE2_DIR_PATH}/.output"
|
||||
docker cp "$container_id":/speckle-server "${GIT_ROOT}/${FE2_DIR_PATH}/.output"
|
||||
docker rm "$container_id"
|
||||
|
||||
# Publish sourcemaps
|
||||
pushd "${GIT_ROOT}/${FE2_DIR_PATH}"
|
||||
DATADOG_SITE="${DATADOG_SITE}" npx --yes @datadog/datadog-ci sourcemaps upload ./.output/public/_nuxt \
|
||||
--service="${FE2_DATADOG_SERVICE}" \
|
||||
--release-version="${IMAGE_VERSION_TAG}" \
|
||||
--minified-path-prefix=/_nuxt
|
||||
popd
|
||||
|
||||
# Clean up
|
||||
rm -rf "${GIT_ROOT}/${FE2_DIR_PATH}/.output"
|
||||
+68
-43
@@ -44,6 +44,9 @@ workflows:
|
||||
- test-objectsender:
|
||||
filters: *filters-allow-all
|
||||
|
||||
- test-shared:
|
||||
filters: *filters-allow-all
|
||||
|
||||
- test-preview-service:
|
||||
filters: *filters-allow-all
|
||||
|
||||
@@ -184,6 +187,7 @@ workflows:
|
||||
- test-frontend-2
|
||||
- test-viewer
|
||||
- test-objectsender
|
||||
- test-shared
|
||||
- test-server
|
||||
- test-server-no-ff
|
||||
- test-server-multiregion
|
||||
@@ -200,11 +204,20 @@ workflows:
|
||||
- test-frontend-2
|
||||
- test-viewer
|
||||
- test-objectsender
|
||||
- test-shared
|
||||
- test-server
|
||||
- test-server-no-ff
|
||||
- test-server-multiregion
|
||||
- test-preview-service
|
||||
|
||||
- docker-publish-frontend-2-sourcemaps:
|
||||
context:
|
||||
- github-readonly-public-repos
|
||||
- datadog-sourcemaps-publish
|
||||
filters: *filters-publish
|
||||
requires:
|
||||
- get-version
|
||||
|
||||
- docker-publish-webhooks:
|
||||
context: *docker-hub-context
|
||||
filters: *filters-publish
|
||||
@@ -216,6 +229,7 @@ workflows:
|
||||
- test-frontend-2
|
||||
- test-viewer
|
||||
- test-objectsender
|
||||
- test-shared
|
||||
- test-server
|
||||
- test-server-no-ff
|
||||
- test-server-multiregion
|
||||
@@ -232,6 +246,7 @@ workflows:
|
||||
- test-frontend-2
|
||||
- test-viewer
|
||||
- test-objectsender
|
||||
- test-shared
|
||||
- test-server
|
||||
- test-server-no-ff
|
||||
- test-server-multiregion
|
||||
@@ -248,6 +263,7 @@ workflows:
|
||||
- test-frontend-2
|
||||
- test-viewer
|
||||
- test-objectsender
|
||||
- test-shared
|
||||
- test-server
|
||||
- test-server-no-ff
|
||||
- test-server-multiregion
|
||||
@@ -264,6 +280,7 @@ workflows:
|
||||
- test-frontend-2
|
||||
- test-viewer
|
||||
- test-objectsender
|
||||
- test-shared
|
||||
- test-server
|
||||
- test-server-no-ff
|
||||
- test-server-multiregion
|
||||
@@ -286,6 +303,7 @@ workflows:
|
||||
- test-frontend-2
|
||||
- test-viewer
|
||||
- test-objectsender
|
||||
- test-shared
|
||||
- test-server
|
||||
- test-server-no-ff
|
||||
- test-server-multiregion
|
||||
@@ -302,6 +320,7 @@ workflows:
|
||||
- test-frontend-2
|
||||
- test-viewer
|
||||
- test-objectsender
|
||||
- test-shared
|
||||
- test-server
|
||||
- test-server-no-ff
|
||||
- test-server-multiregion
|
||||
@@ -349,6 +368,7 @@ workflows:
|
||||
- test-frontend-2
|
||||
- test-viewer
|
||||
- test-objectsender
|
||||
- test-shared
|
||||
- test-preview-service
|
||||
|
||||
- publish-viewer-sandbox-cloudflare-pages:
|
||||
@@ -358,16 +378,6 @@ workflows:
|
||||
requires:
|
||||
- test-viewer
|
||||
|
||||
- frontend-2-sourcemaps:
|
||||
context:
|
||||
- datadog-sourcemaps-publish
|
||||
filters: *filters-publish
|
||||
requires:
|
||||
- get-version
|
||||
- docker-build-frontend-2
|
||||
- test-frontend-2
|
||||
- publish-helm-chart
|
||||
|
||||
jobs:
|
||||
get-version:
|
||||
docker: &docker-base-image
|
||||
@@ -729,6 +739,36 @@ jobs:
|
||||
command: yarn test
|
||||
working_directory: 'packages/preview-service'
|
||||
|
||||
test-shared:
|
||||
docker: *docker-node-browsers-image
|
||||
resource_class: medium+
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
name: Restore Yarn Package Cache
|
||||
keys:
|
||||
- yarn-packages-server-{{ checksum "yarn.lock" }}
|
||||
- run:
|
||||
name: Install Dependencies
|
||||
command: yarn
|
||||
|
||||
- save_cache:
|
||||
name: Save Yarn Package Cache
|
||||
key: yarn-packages-server-{{ checksum "yarn.lock" }}
|
||||
paths:
|
||||
- .yarn/cache
|
||||
- .yarn/unplugged
|
||||
|
||||
- run:
|
||||
name: Lint
|
||||
command: yarn lint:ci
|
||||
working_directory: 'packages/shared'
|
||||
|
||||
- run:
|
||||
name: Run tests
|
||||
command: yarn test:single-run
|
||||
working_directory: 'packages/shared'
|
||||
|
||||
test-objectsender:
|
||||
docker: *docker-node-browsers-image
|
||||
resource_class: large
|
||||
@@ -1005,6 +1045,24 @@ jobs:
|
||||
environment:
|
||||
SPECKLE_SERVER_PACKAGE: frontend-2
|
||||
|
||||
docker-publish-frontend-2-sourcemaps:
|
||||
docker: *docker-node-image
|
||||
resource_class: xlarge
|
||||
working_directory: *work-dir
|
||||
environment:
|
||||
SPECKLE_SERVER_PACKAGE: frontend-2
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: /tmp/ci/workspace
|
||||
- run: cat workspace/env-vars >> $BASH_ENV
|
||||
- setup_remote_docker:
|
||||
version: default
|
||||
docker_layer_caching: true
|
||||
- run:
|
||||
name: Build and Save
|
||||
command: ./.circleci/build_publish_fe2_sourcemaps.sh
|
||||
|
||||
docker-build-previews:
|
||||
<<: *build-job
|
||||
environment:
|
||||
@@ -1216,36 +1274,3 @@ jobs:
|
||||
environment:
|
||||
CLOUDFLARE_PAGES_PROJECT_NAME: viewer
|
||||
VIEWER_SANDBOX_DIR_PATH: packages/viewer-sandbox
|
||||
|
||||
frontend-2-sourcemaps:
|
||||
docker: *docker-node-image
|
||||
resource_class: large
|
||||
working_directory: *work-dir
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: /tmp/ci/workspace
|
||||
- run: cat workspace/env-vars >> $BASH_ENV
|
||||
- restore_cache:
|
||||
name: Restore Yarn Package Cache
|
||||
keys:
|
||||
- yarn-packages-server-{{ checksum "yarn.lock" }}
|
||||
- run:
|
||||
name: Install Dependencies
|
||||
command: yarn
|
||||
- save_cache:
|
||||
name: Save Yarn Package Cache
|
||||
key: yarn-packages-server-{{ checksum "yarn.lock" }}
|
||||
paths:
|
||||
- .yarn/cache
|
||||
- .yarn/unplugged
|
||||
- run:
|
||||
name: Build public packages
|
||||
command: yarn build:public
|
||||
- run:
|
||||
name: Build FE2
|
||||
command: NODE_ENV=production SPECKLE_SERVER_VERSION="${IMAGE_VERSION_TAG}" yarn build:sourcemaps
|
||||
working_directory: 'packages/frontend-2'
|
||||
- run:
|
||||
name: Upload source maps
|
||||
command: ./.circleci/publish_fe2_sourcemaps.sh
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
|
||||
GIT_ROOT="$(git rev-parse --show-toplevel)"
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
# shellcheck disable=SC1090,SC1091
|
||||
source "${SCRIPT_DIR}/common.sh"
|
||||
|
||||
FE2_DIR_PATH="${FE2_DIR_PATH:-"packages/frontend-2"}"
|
||||
FE2_DATADOG_SERVICE="${FE2_DATADOG_SERVICE:-"web-app-2"}"
|
||||
|
||||
if [[ -z "${DATADOG_API_KEY}" ]]; then
|
||||
echo "DATADOG_API_KEY is not set"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
pushd "${GIT_ROOT}/${FE2_DIR_PATH}"
|
||||
DATADOG_SITE="${DATADOG_SITE:-"datadoghq.eu"}" yarn datadog-ci sourcemaps upload ./.output/public/_nuxt \
|
||||
--service="${FE2_DATADOG_SERVICE}" \
|
||||
--release-version="${IMAGE_VERSION_TAG}" \
|
||||
--minified-path-prefix=/_nuxt
|
||||
popd
|
||||
+3
-1
@@ -63,6 +63,7 @@
|
||||
"prettier": "^2.5.1",
|
||||
"ts-node": "^10.9.1",
|
||||
"tsconfig-paths": "^4.0.0",
|
||||
"vitest": "^3.0.7",
|
||||
"zx": "^8.1.2"
|
||||
},
|
||||
"resolutions": {
|
||||
@@ -91,7 +92,8 @@
|
||||
"typescript": "^5.7.3",
|
||||
"typescript-eslint": "^8.20.0",
|
||||
"wait-on": ">=7.2.0",
|
||||
"vue-tsc@npm:2.2.2/@vue/language-core": "2.2.0"
|
||||
"vue-tsc@npm:2.2.2/@vue/language-core": "2.2.0",
|
||||
"vitest": "^3.0.7"
|
||||
},
|
||||
"config": {
|
||||
"commitizen": {
|
||||
|
||||
@@ -37,8 +37,5 @@ NUXT_PUBLIC_ENABLE_AUTOMATE_MODULE=false
|
||||
# Survicate
|
||||
NUXT_PUBLIC_SURVICATE_WORKSPACE_KEY=
|
||||
|
||||
# Enable direct preview image loading - way quicker, but requres server & frontend to be on the same origin
|
||||
NUXT_PUBLIC_ENABLE_DIRECT_PREVIEWS=true
|
||||
|
||||
# Ghost API
|
||||
NUXT_PUBLIC_GHOST_API_KEY=
|
||||
@@ -1,6 +1,7 @@
|
||||
FROM node:18-bookworm-slim@sha256:408f8cbbb7b33a5bb94bdb8862795a94d2b64c2d516856824fd86c4a5594a443 AS build-stage
|
||||
ARG NODE_ENV=production
|
||||
ARG SPECKLE_SERVER_VERSION=custom
|
||||
ARG BUILD_SOURCEMAPS=false
|
||||
|
||||
WORKDIR /speckle-server
|
||||
|
||||
@@ -30,8 +31,6 @@ COPY packages/frontend-2 ./packages/frontend-2/
|
||||
RUN yarn workspaces focus -A
|
||||
# hadolint ignore=DL3059
|
||||
RUN yarn workspaces foreach -W run build
|
||||
# hadolint ignore=DL3059
|
||||
RUN find ./packages/frontend-2/.output/ -type f \( -name "*.js.map" -o -name "*.mjs.map" -o -name "*.cjs.map" \) -exec rm -f {} \;
|
||||
|
||||
ENV TINI_VERSION v0.19.0
|
||||
RUN apt-get update -y \
|
||||
|
||||
@@ -23,6 +23,7 @@ const config: CodegenConfig = {
|
||||
'./lib/common/generated/gql/': {
|
||||
preset: 'client',
|
||||
config: {
|
||||
enumsAsConst: true,
|
||||
useTypeImports: true,
|
||||
fragmentMasking: false,
|
||||
dedupeFragments: true,
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
v-model="email"
|
||||
type="email"
|
||||
name="email"
|
||||
label="Email"
|
||||
label="Work email"
|
||||
placeholder="Email"
|
||||
size="lg"
|
||||
color="foundation"
|
||||
@@ -69,17 +69,14 @@ import { ToastNotificationType, useGlobalToast } from '~~/lib/common/composables
|
||||
import { ensureError } from '@speckle/shared'
|
||||
import { useAuthManager } from '~~/lib/auth/composables/auth'
|
||||
import { loginRoute } from '~~/lib/common/helpers/route'
|
||||
import { passwordRules } from '~~/lib/auth/helpers/validation'
|
||||
import {
|
||||
passwordRules,
|
||||
doesNotContainBlockedDomain
|
||||
} from '~~/lib/auth/helpers/validation'
|
||||
import { graphql } from '~~/lib/common/generated/gql'
|
||||
import type { ServerTermsOfServicePrivacyPolicyFragmentFragment } from '~~/lib/common/generated/gql/graphql'
|
||||
import { useMounted } from '@vueuse/core'
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
* - (BE) Password strength check? Do we want to use it anymore?
|
||||
* - Dim's answer: no, `passwordRules` are legit enough for now.
|
||||
*/
|
||||
|
||||
graphql(`
|
||||
fragment ServerTermsOfServicePrivacyPolicyFragment on ServerInfo {
|
||||
termsOfService
|
||||
@@ -99,13 +96,18 @@ const router = useRouter()
|
||||
const { signUpWithEmail, inviteToken } = useAuthManager()
|
||||
const { triggerNotification } = useGlobalToast()
|
||||
const isMounted = useMounted()
|
||||
const isNoPersonalEmailsEnabled = useIsNoPersonalEmailsEnabled()
|
||||
|
||||
const newsletterConsent = defineModel<boolean>('newsletterConsent', { required: true })
|
||||
const loading = ref(false)
|
||||
const password = ref('')
|
||||
const email = ref('')
|
||||
|
||||
const emailRules = [isEmail]
|
||||
const emailRules = computed(() =>
|
||||
inviteToken.value || !isNoPersonalEmailsEnabled.value
|
||||
? [isEmail]
|
||||
: [isEmail, doesNotContainBlockedDomain]
|
||||
)
|
||||
const nameRules = [isRequired]
|
||||
|
||||
const isEmailDisabled = computed(() => !!props.inviteEmail?.length || loading.value)
|
||||
|
||||
@@ -22,13 +22,7 @@
|
||||
<div class="flex flex-col sm:flex-row gap-2 sm:items-center truncate">
|
||||
<div class="sm:truncate">
|
||||
<div
|
||||
v-if="
|
||||
[
|
||||
AutomateRunStatus.Initializing,
|
||||
AutomateRunStatus.Running,
|
||||
AutomateRunStatus.Pending
|
||||
].includes(functionRun.status)
|
||||
"
|
||||
v-if="isStartingOrRunning"
|
||||
class="text-body-2xs text-foreground-2 italic whitespace-normal sm:truncate"
|
||||
>
|
||||
Function is {{ functionRun.status.toLowerCase() }}.
|
||||
@@ -141,4 +135,14 @@ const results = useAutomationFunctionRunResults({
|
||||
const showAttachmentDialog = ref(false)
|
||||
|
||||
const attachments = computed(() => results.value?.values.blobIds || [])
|
||||
|
||||
const isStartingOrRunning = computed(() =>
|
||||
(
|
||||
[
|
||||
AutomateRunStatus.Initializing,
|
||||
AutomateRunStatus.Running,
|
||||
AutomateRunStatus.Pending
|
||||
] as string[]
|
||||
).includes(props.functionRun.status)
|
||||
)
|
||||
</script>
|
||||
|
||||
@@ -156,11 +156,13 @@ const hasValidContextView = computed(() => {
|
||||
})
|
||||
|
||||
const statusMessage = computed(() => {
|
||||
const isFinished = ![
|
||||
AutomateRunStatus.Initializing,
|
||||
AutomateRunStatus.Running,
|
||||
AutomateRunStatus.Pending
|
||||
].includes(props.functionRun.status)
|
||||
const isFinished = !(
|
||||
[
|
||||
AutomateRunStatus.Initializing,
|
||||
AutomateRunStatus.Running,
|
||||
AutomateRunStatus.Pending
|
||||
] as string[]
|
||||
).includes(props.functionRun.status)
|
||||
|
||||
return isFinished
|
||||
? props.functionRun.statusMessage ?? 'No status message'
|
||||
|
||||
@@ -3,7 +3,8 @@ import {
|
||||
waitIntervalUntil,
|
||||
type Nullable,
|
||||
timeoutAt,
|
||||
WaitIntervalUntilCanceledError
|
||||
WaitIntervalUntilCanceledError,
|
||||
TimeoutError
|
||||
} from '@speckle/shared'
|
||||
import { until } from '@vueuse/core'
|
||||
import type { CSSProperties } from 'vue'
|
||||
@@ -26,6 +27,8 @@ export default defineComponent({
|
||||
}
|
||||
},
|
||||
setup(props, { slots, expose }) {
|
||||
const logger = useLogger()
|
||||
|
||||
const transitioning = ref(false)
|
||||
const newWrapperRef = ref(null as Nullable<HTMLDivElement>)
|
||||
const oldWrapperRef = ref(null as Nullable<HTMLDivElement>)
|
||||
@@ -102,6 +105,8 @@ export default defineComponent({
|
||||
* Cause default slot to update with an opacity transition
|
||||
*/
|
||||
const updateContents = async () => {
|
||||
transitioning.value = true
|
||||
|
||||
// Stage 1: Just move new -> old w/o any transitions (visually should look the same)
|
||||
oldContents.value = newContents.value
|
||||
newContents.value = slots.default?.()
|
||||
@@ -155,15 +160,23 @@ export default defineComponent({
|
||||
|
||||
const triggerTransition = async () => {
|
||||
if (!transitioning.value) {
|
||||
transitioning.value = true
|
||||
await updateContents()
|
||||
return
|
||||
}
|
||||
|
||||
await Promise.race([
|
||||
until(transitioning).toBe(false),
|
||||
timeoutAt(props.duration + 1000)
|
||||
])
|
||||
try {
|
||||
await Promise.race([
|
||||
until(transitioning).toBe(false),
|
||||
timeoutAt(props.duration + 1000, 'Waiting for transition to finish timed out')
|
||||
])
|
||||
} catch (e) {
|
||||
if (!(e instanceof TimeoutError)) {
|
||||
throw e
|
||||
} else {
|
||||
logger.warn(e)
|
||||
}
|
||||
}
|
||||
|
||||
await updateContents()
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
class="md:min-w-80"
|
||||
allow-unset
|
||||
:items="categories"
|
||||
size="base"
|
||||
color="foundation"
|
||||
>
|
||||
<template #something-selected="{ value }">
|
||||
{{ isArray(value) ? value[0].name : value.name }}
|
||||
|
||||
@@ -38,4 +38,7 @@ const dialogButtons = computed((): LayoutDialogButton[] => [
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
// testing deployments in prod, ignore this
|
||||
markUsed('a')
|
||||
</script>
|
||||
|
||||
@@ -26,11 +26,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useForm } from 'vee-validate'
|
||||
import type {
|
||||
OnboardingRole,
|
||||
OnboardingPlan,
|
||||
OnboardingSource
|
||||
} from '~/lib/auth/helpers/onboarding'
|
||||
import type { OnboardingRole, OnboardingPlan, OnboardingSource } from '@speckle/shared'
|
||||
import { useProcessOnboarding } from '~~/lib/auth/composables/onboarding'
|
||||
import { homeRoute } from '~/lib/common/helpers/route'
|
||||
|
||||
@@ -50,7 +46,11 @@ const onSubmit = handleSubmit(async () => {
|
||||
if (values.role) {
|
||||
setMixpanelSegments({ role: values.role })
|
||||
}
|
||||
await setUserOnboardingComplete()
|
||||
await setUserOnboardingComplete({
|
||||
role: values.role,
|
||||
plans: values.plan,
|
||||
source: values.source
|
||||
})
|
||||
navigateTo(homeRoute)
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useFormSelectChildInternals } from '@speckle/ui-components'
|
||||
import { OnboardingPlan, PlanTitleMap } from '~/lib/auth/helpers/onboarding'
|
||||
import { PlanTitleMap } from '~/lib/auth/helpers/onboarding'
|
||||
import { OnboardingPlan } from '@speckle/shared'
|
||||
import { isRequired } from '~~/lib/common/helpers/validation'
|
||||
|
||||
const props = defineProps<{
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useFormSelectChildInternals } from '@speckle/ui-components'
|
||||
import { OnboardingRole, RoleTitleMap } from '~/lib/auth/helpers/onboarding'
|
||||
import { RoleTitleMap } from '~/lib/auth/helpers/onboarding'
|
||||
import { OnboardingRole } from '@speckle/shared'
|
||||
import { isRequired } from '~~/lib/common/helpers/validation'
|
||||
|
||||
const props = defineProps<{
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useFormSelectChildInternals } from '@speckle/ui-components'
|
||||
import { OnboardingSource, SourceTitleMap } from '~/lib/auth/helpers/onboarding'
|
||||
import { SourceTitleMap } from '~/lib/auth/helpers/onboarding'
|
||||
import { OnboardingSource } from '@speckle/shared'
|
||||
import { isRequired } from '~~/lib/common/helpers/validation'
|
||||
|
||||
const props = defineProps<{
|
||||
|
||||
@@ -93,14 +93,20 @@
|
||||
<NuxtLink
|
||||
v-for="workspaceMenuItem in workspaceMenuItems"
|
||||
:key="`workspace-menu-item-${workspaceMenuItem.name}-${workspaceItem.slug}`"
|
||||
:to="workspaceMenuItem.route(workspaceItem.slug)"
|
||||
:to="
|
||||
!isAdmin &&
|
||||
(workspaceMenuItem.disabled ||
|
||||
needsSsoSession(workspaceItem, workspaceMenuItem.name))
|
||||
? undefined
|
||||
: workspaceMenuItem.route(workspaceItem.slug)
|
||||
"
|
||||
@click="isOpenMobile = false"
|
||||
>
|
||||
<LayoutSidebarMenuGroupItem
|
||||
v-if="workspaceMenuItem.permission?.includes(workspaceItem.role as WorkspaceRoles)"
|
||||
:label="workspaceMenuItem.title"
|
||||
:active="
|
||||
route.name === workspaceMenuItem.name &&
|
||||
route.name?.toString().startsWith(workspaceMenuItem.name) &&
|
||||
route.params.slug === workspaceItem.slug
|
||||
"
|
||||
:tooltip-text="
|
||||
@@ -117,13 +123,6 @@
|
||||
/>
|
||||
</NuxtLink>
|
||||
</LayoutSidebarMenuGroup>
|
||||
<NuxtLink v-if="!isGuest" :to="workspacesRoute">
|
||||
<LayoutSidebarMenuGroupItem label="Create workspace">
|
||||
<template #icon>
|
||||
<PlusIcon class="h-4 w-4 text-foreground-2" />
|
||||
</template>
|
||||
</LayoutSidebarMenuGroupItem>
|
||||
</NuxtLink>
|
||||
</LayoutSidebarMenuGroup>
|
||||
</LayoutSidebarMenu>
|
||||
</LayoutSidebar>
|
||||
@@ -132,11 +131,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Roles } from '@speckle/shared'
|
||||
import { useIsWorkspacesEnabled } from '~/composables/globals'
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import { settingsSidebarQuery } from '~/lib/settings/graphql/queries'
|
||||
import { PlusIcon, ChevronLeftIcon } from '@heroicons/vue/24/outline'
|
||||
import { ChevronLeftIcon } from '@heroicons/vue/24/outline'
|
||||
import { useActiveUser } from '~/lib/auth/composables/activeUser'
|
||||
import { useSettingsMenu, useSettingsMenuState } from '~/lib/settings/composables/menu'
|
||||
import {
|
||||
@@ -146,11 +144,7 @@ import {
|
||||
} from '@speckle/ui-components'
|
||||
import { graphql } from '~~/lib/common/generated/gql'
|
||||
import type { WorkspaceRoles } from '@speckle/shared'
|
||||
import {
|
||||
workspacesRoute,
|
||||
homeRoute,
|
||||
settingsWorkspaceRoutes
|
||||
} from '~/lib/common/helpers/route'
|
||||
import { homeRoute, settingsWorkspaceRoutes } from '~/lib/common/helpers/route'
|
||||
import {
|
||||
WorkspacePlanStatuses,
|
||||
type SettingsMenu_WorkspaceFragment
|
||||
@@ -187,7 +181,7 @@ graphql(`
|
||||
`)
|
||||
|
||||
const settingsMenuState = useSettingsMenuState()
|
||||
const { activeUser: user } = useActiveUser()
|
||||
const { isAdmin } = useActiveUser()
|
||||
const route = useRoute()
|
||||
const isWorkspacesEnabled = useIsWorkspacesEnabled()
|
||||
const { result: workspaceResult } = useQuery(settingsSidebarQuery, null, {
|
||||
@@ -206,8 +200,6 @@ const workspaceItems = computed(
|
||||
(item) => item.creationState?.completed !== false // Removed workspaces that are not completely created
|
||||
) || []
|
||||
)
|
||||
const isAdmin = computed(() => user.value?.role === Roles.Server.Admin)
|
||||
const isGuest = computed(() => user.value?.role === Roles.Server.Guest)
|
||||
|
||||
const needsSsoSession = (
|
||||
workspace: SettingsMenu_WorkspaceFragment,
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<template>
|
||||
<LayoutDialog
|
||||
v-model:open="isOpen"
|
||||
:title="cancel ? 'Cancel adding email' : 'Delete email address'"
|
||||
:title="isAdding ? 'Stop adding email?' : 'Delete email address'"
|
||||
max-width="xs"
|
||||
:buttons="dialogButtons"
|
||||
>
|
||||
<p class="text-body-xs text-foreground mb-2">
|
||||
{{
|
||||
cancel
|
||||
? `Are you sure you want to cancel adding ${email?.email} to your account?`
|
||||
isAdding
|
||||
? `Do you want to stop adding ${email?.email}? Any progress will be discarded.`
|
||||
: `Are you sure you want to delete ${email?.email} from your account?`
|
||||
}}
|
||||
</p>
|
||||
@@ -22,7 +22,7 @@ import { useUserEmails } from '~/lib/user/composables/emails'
|
||||
|
||||
const props = defineProps<{
|
||||
email?: UserEmail
|
||||
cancel?: boolean
|
||||
isAdding?: boolean
|
||||
}>()
|
||||
|
||||
const isOpen = defineModel<boolean>('open', { required: true })
|
||||
@@ -31,14 +31,14 @@ const { deleteUserEmail } = useUserEmails()
|
||||
|
||||
const dialogButtons = computed((): LayoutDialogButton[] => [
|
||||
{
|
||||
text: 'Cancel',
|
||||
text: props.isAdding ? 'No' : 'Cancel',
|
||||
props: { color: 'outline' },
|
||||
onClick: () => {
|
||||
isOpen.value = false
|
||||
}
|
||||
},
|
||||
{
|
||||
text: props.cancel ? 'Confirm' : 'Delete',
|
||||
text: props.isAdding ? 'Yes' : 'Delete',
|
||||
props: { color: 'primary' },
|
||||
onClick: () => {
|
||||
onDeleteEmail()
|
||||
@@ -48,7 +48,10 @@ const dialogButtons = computed((): LayoutDialogButton[] => [
|
||||
|
||||
const onDeleteEmail = async () => {
|
||||
if (!props.email) return
|
||||
const success = await deleteUserEmail(props.email)
|
||||
const success = await deleteUserEmail({
|
||||
email: props.email,
|
||||
hideToast: props.isAdding
|
||||
})
|
||||
if (success) {
|
||||
isOpen.value = false
|
||||
}
|
||||
|
||||
@@ -62,11 +62,7 @@
|
||||
:email="emailData.email"
|
||||
/>
|
||||
|
||||
<SettingsUserEmailDeleteDialog
|
||||
v-model:open="showDeleteDialog"
|
||||
:email="emailData"
|
||||
:is-verifying="!emailData.verified"
|
||||
/>
|
||||
<SettingsUserEmailDeleteDialog v-model:open="showDeleteDialog" :email="emailData" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<div class="flex items-center gap-x-2">
|
||||
<h4 class="text-body font-medium">
|
||||
Workspace
|
||||
<span class="capitalize">{{ plan.name }}</span>
|
||||
<span class="capitalize">{{ plan }}</span>
|
||||
</h4>
|
||||
<CommonBadge v-if="badgeText" rounded>
|
||||
{{ badgeText }}
|
||||
@@ -15,8 +15,8 @@
|
||||
<span class="font-medium">
|
||||
£{{
|
||||
yearlyIntervalSelected
|
||||
? plan.cost.yearly[Roles.Workspace.Member]
|
||||
: plan.cost.monthly[Roles.Workspace.Member]
|
||||
? planPrices.yearly[Roles.Workspace.Member]
|
||||
: planPrices.monthly[Roles.Workspace.Member]
|
||||
}}
|
||||
</span>
|
||||
per seat/month
|
||||
@@ -40,7 +40,7 @@
|
||||
<div v-else>
|
||||
<!-- Key to fix tippy reactivity -->
|
||||
<div
|
||||
:key="`tooltip-${yearlyIntervalSelected}-${plan.name}-${currentPlan?.name}`"
|
||||
:key="`tooltip-${yearlyIntervalSelected}-${plan}-${currentPlan?.name}`"
|
||||
v-tippy="buttonTooltip"
|
||||
>
|
||||
<FormButton
|
||||
@@ -56,32 +56,35 @@
|
||||
</div>
|
||||
<ul class="flex flex-col gap-y-2 mt-4 pt-3 border-t border-outline-3">
|
||||
<li
|
||||
v-for="feature in features"
|
||||
:key="feature.name"
|
||||
v-for="(featureMetadata, feature) in WorkspacePlanFeaturesMetadata"
|
||||
:key="feature"
|
||||
class="flex items-center text-body-xs"
|
||||
:class="{
|
||||
'lg:hidden': !plan.features.includes(feature.name as PlanFeaturesList)
|
||||
}"
|
||||
'lg:hidden': !planFeatures.includes(feature)
|
||||
}"
|
||||
>
|
||||
<IconCheck
|
||||
v-if="plan.features.includes(feature.name as PlanFeaturesList)"
|
||||
v-if="planFeatures.includes(feature)"
|
||||
class="w-4 h-4 text-foreground mx-2"
|
||||
/>
|
||||
<XMarkIcon v-else class="w-4 h-4 mx-2 text-foreground-3" />
|
||||
<span
|
||||
v-tippy="
|
||||
feature.description(
|
||||
yearlyIntervalSelected
|
||||
? plan.cost.yearly[Roles.Workspace.Guest]
|
||||
: plan.cost.monthly[Roles.Workspace.Guest]
|
||||
)
|
||||
isFunction(featureMetadata.description)
|
||||
? featureMetadata.description({
|
||||
price: (yearlyIntervalSelected
|
||||
? planPrices.yearly[Roles.Workspace.Guest]
|
||||
: planPrices.monthly[Roles.Workspace.Guest]
|
||||
).toString()
|
||||
})
|
||||
: featureMetadata.description
|
||||
"
|
||||
class="underline decoration-outline-5 decoration-dashed underline-offset-4 cursor-help"
|
||||
:class="{
|
||||
'text-foreground-2': !plan.features.includes(feature.name as PlanFeaturesList)
|
||||
'text-foreground-2': !planFeatures.includes(feature)
|
||||
}"
|
||||
>
|
||||
{{ feature.name }}
|
||||
{{ featureMetadata.displayName }}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -89,7 +92,7 @@
|
||||
<SettingsWorkspacesBillingUpgradeDialog
|
||||
v-if="currentPlan?.name && workspaceId"
|
||||
v-model:open="isUpgradeDialogOpen"
|
||||
:plan="plan.name"
|
||||
:plan="plan"
|
||||
:billing-interval="
|
||||
yearlyIntervalSelected ? BillingInterval.Yearly : BillingInterval.Monthly
|
||||
"
|
||||
@@ -99,28 +102,30 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { PricingPlan } from '@/lib/billing/helpers/types'
|
||||
import { Roles } from '@speckle/shared'
|
||||
import {
|
||||
type PaidWorkspacePlansOld,
|
||||
type MaybeNullOrUndefined,
|
||||
WorkspacePlans,
|
||||
WorkspacePlanFeaturesMetadata
|
||||
} from '@speckle/shared'
|
||||
import { Roles, WorkspacePlanConfigs } from '@speckle/shared'
|
||||
import {
|
||||
type WorkspacePlan,
|
||||
WorkspacePlanStatuses,
|
||||
WorkspacePlans,
|
||||
BillingInterval
|
||||
} from '~/lib/common/generated/gql/graphql'
|
||||
import type { MaybeNullOrUndefined } from '@speckle/shared'
|
||||
import { startCase } from 'lodash'
|
||||
import { pricingPlansConfig } from '~/lib/billing/helpers/constants'
|
||||
import type { PlanFeaturesList } from '~/lib/billing/helpers/types'
|
||||
import { startCase, isFunction } from 'lodash'
|
||||
import { XMarkIcon } from '@heroicons/vue/24/outline'
|
||||
import type { SetupContext } from 'vue'
|
||||
import { WorkspaceOldPaidPlanPrices } from '~/lib/billing/helpers/constants'
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'onYearlyIntervalSelected', value: boolean): void
|
||||
(e: 'onPlanSelected', value: WorkspacePlans): void
|
||||
(e: 'onPlanSelected', value: PaidWorkspacePlansOld): void
|
||||
}>()
|
||||
|
||||
const props = defineProps<{
|
||||
plan: PricingPlan
|
||||
plan: PaidWorkspacePlansOld
|
||||
yearlyIntervalSelected: boolean
|
||||
badgeText?: string
|
||||
// The following props are optional if the table is for informational purposes
|
||||
@@ -132,10 +137,12 @@ const props = defineProps<{
|
||||
|
||||
const slots: SetupContext['slots'] = useSlots()
|
||||
|
||||
const features = ref(pricingPlansConfig.features)
|
||||
const isUpgradeDialogOpen = ref(false)
|
||||
const isYearlyIntervalSelected = ref(props.yearlyIntervalSelected)
|
||||
|
||||
const planPrices = computed(() => WorkspaceOldPaidPlanPrices[props.plan])
|
||||
const planFeatures = computed(() => WorkspacePlanConfigs[props.plan].features)
|
||||
|
||||
const hasCta = computed(() => !!slots.cta)
|
||||
const canUpgradeToPlan = computed(() => {
|
||||
if (!props.currentPlan) return false
|
||||
@@ -149,10 +156,13 @@ const canUpgradeToPlan = computed(() => {
|
||||
[WorkspacePlans.StarterInvoiced]: [],
|
||||
[WorkspacePlans.PlusInvoiced]: [],
|
||||
[WorkspacePlans.BusinessInvoiced]: [],
|
||||
[WorkspacePlans.Free]: []
|
||||
// New
|
||||
[WorkspacePlans.Free]: [],
|
||||
[WorkspacePlans.Team]: [],
|
||||
[WorkspacePlans.Pro]: []
|
||||
}
|
||||
|
||||
return allowedUpgrades[props.currentPlan.name].includes(props.plan.name)
|
||||
return allowedUpgrades[props.currentPlan.name].includes(props.plan)
|
||||
})
|
||||
|
||||
const statusIsTrial = computed(
|
||||
@@ -166,17 +176,17 @@ const isMatchingInterval = computed(
|
||||
)
|
||||
|
||||
const isDowngrade = computed(() => {
|
||||
return !canUpgradeToPlan.value && props.currentPlan?.name !== props.plan.name
|
||||
return !canUpgradeToPlan.value && props.currentPlan?.name !== props.plan
|
||||
})
|
||||
|
||||
const isCurrentPlan = computed(
|
||||
() => isMatchingInterval.value && props.currentPlan?.name === props.plan.name
|
||||
() => isMatchingInterval.value && props.currentPlan?.name === props.plan
|
||||
)
|
||||
|
||||
const isAnnualToMonthly = computed(() => {
|
||||
return (
|
||||
!isMatchingInterval.value &&
|
||||
props.currentPlan?.name === props.plan.name &&
|
||||
props.currentPlan?.name === props.plan &&
|
||||
!props.yearlyIntervalSelected
|
||||
)
|
||||
})
|
||||
@@ -184,7 +194,7 @@ const isAnnualToMonthly = computed(() => {
|
||||
const isMonthlyToAnnual = computed(() => {
|
||||
return (
|
||||
!isMatchingInterval.value &&
|
||||
props.currentPlan?.name === props.plan.name &&
|
||||
props.currentPlan?.name === props.plan &&
|
||||
props.yearlyIntervalSelected
|
||||
)
|
||||
})
|
||||
@@ -200,8 +210,7 @@ const isSelectable = computed(() => {
|
||||
return true
|
||||
|
||||
// Allow selection if switching from monthly to yearly for the same plan
|
||||
if (isMonthlyToAnnual.value && props.currentPlan?.name === props.plan.name)
|
||||
return true
|
||||
if (isMonthlyToAnnual.value && props.currentPlan?.name === props.plan) return true
|
||||
|
||||
// Disable if current plan and intervals match
|
||||
if (isCurrentPlan.value) return false
|
||||
@@ -227,7 +236,7 @@ const buttonColor = computed(() => {
|
||||
statusIsTrial.value ||
|
||||
props.currentPlan?.status === WorkspacePlanStatuses.Expired
|
||||
) {
|
||||
return props.plan.name === WorkspacePlans.Starter ? 'primary' : 'outline'
|
||||
return props.plan === WorkspacePlans.Starter ? 'primary' : 'outline'
|
||||
}
|
||||
return 'outline'
|
||||
})
|
||||
@@ -239,7 +248,7 @@ const buttonText = computed(() => {
|
||||
props.currentPlan?.status === WorkspacePlanStatuses.Expired ||
|
||||
props.currentPlan?.status === WorkspacePlanStatuses.Canceled
|
||||
) {
|
||||
return `Subscribe to ${startCase(props.plan.name)}`
|
||||
return `Subscribe to ${startCase(props.plan)}`
|
||||
}
|
||||
// Current plan case
|
||||
if (isCurrentPlan.value) {
|
||||
@@ -247,7 +256,7 @@ const buttonText = computed(() => {
|
||||
}
|
||||
// Billing interval and lower plan case
|
||||
if (isDowngrade.value) {
|
||||
return `Downgrade to ${props.plan.name}`
|
||||
return `Downgrade to ${props.plan}`
|
||||
}
|
||||
// Billing interval change and current plan
|
||||
if (isAnnualToMonthly.value) {
|
||||
@@ -257,7 +266,7 @@ const buttonText = computed(() => {
|
||||
return 'Change to annual plan'
|
||||
}
|
||||
// Upgrade case
|
||||
return canUpgradeToPlan.value ? `Upgrade to ${startCase(props.plan.name)}` : ''
|
||||
return canUpgradeToPlan.value ? `Upgrade to ${startCase(props.plan)}` : ''
|
||||
})
|
||||
|
||||
const buttonTooltip = computed(() => {
|
||||
@@ -293,7 +302,7 @@ const buttonTooltip = computed(() => {
|
||||
})
|
||||
|
||||
const onCtaClick = () => {
|
||||
emit('onPlanSelected', props.plan.name)
|
||||
emit('onPlanSelected', props.plan)
|
||||
}
|
||||
|
||||
watch(
|
||||
|
||||
+10
-12
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="flex flex-col lg:grid lg:grid-cols-3 gap-4 w-full">
|
||||
<SettingsWorkspacesBillingPricingTablePlan
|
||||
v-for="plan in plans"
|
||||
:key="plan.name"
|
||||
v-for="plan in oldPlans"
|
||||
:key="plan"
|
||||
:plan="plan"
|
||||
:yearly-interval-selected="isYearlySelected"
|
||||
v-bind="$props"
|
||||
@@ -13,16 +13,14 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
type WorkspacePlan,
|
||||
BillingInterval,
|
||||
type WorkspacePlans
|
||||
} from '~/lib/common/generated/gql/graphql'
|
||||
import { pricingPlansConfig } from '~/lib/billing/helpers/constants'
|
||||
import type { MaybeNullOrUndefined } from '@speckle/shared'
|
||||
import { type WorkspacePlan, BillingInterval } from '~/lib/common/generated/gql/graphql'
|
||||
import { type MaybeNullOrUndefined, PaidWorkspacePlansOld } from '@speckle/shared'
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'onPlanSelected', value: { name: WorkspacePlans; cycle: BillingInterval }): void
|
||||
(
|
||||
e: 'onPlanSelected',
|
||||
value: { name: PaidWorkspacePlansOld; cycle: BillingInterval }
|
||||
): void
|
||||
}>()
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -32,14 +30,14 @@ const props = defineProps<{
|
||||
activeBillingInterval?: BillingInterval
|
||||
}>()
|
||||
|
||||
const plans = ref(pricingPlansConfig.plans)
|
||||
const isYearlySelected = ref(false)
|
||||
const oldPlans = computed(() => Object.values(PaidWorkspacePlansOld))
|
||||
|
||||
const onYearlyIntervalSelected = (newValue: boolean) => {
|
||||
isYearlySelected.value = newValue
|
||||
}
|
||||
|
||||
const onPlanSelected = (value: WorkspacePlans) => {
|
||||
const onPlanSelected = (value: PaidWorkspacePlansOld) => {
|
||||
emit('onPlanSelected', {
|
||||
name: value,
|
||||
cycle: isYearlySelected.value ? BillingInterval.Yearly : BillingInterval.Monthly
|
||||
|
||||
@@ -22,18 +22,18 @@
|
||||
<script setup lang="ts">
|
||||
import type { LayoutDialogButton } from '@speckle/ui-components'
|
||||
import {
|
||||
type WorkspacePlans,
|
||||
BillingInterval,
|
||||
type PaidWorkspacePlans
|
||||
} from '~/lib/common/generated/gql/graphql'
|
||||
import { useBillingActions } from '~/lib/billing/composables/actions'
|
||||
import { startCase } from 'lodash'
|
||||
import { pricingPlansConfig } from '~/lib/billing/helpers/constants'
|
||||
import type { PaidWorkspacePlansOld } from '@speckle/shared'
|
||||
import { Roles } from '@speckle/shared'
|
||||
import { isPaidPlan } from '~/lib/billing/helpers/types'
|
||||
import { WorkspaceOldPaidPlanPrices } from '~/lib/billing/helpers/constants'
|
||||
|
||||
const props = defineProps<{
|
||||
plan: WorkspacePlans
|
||||
plan: PaidWorkspacePlansOld
|
||||
billingInterval: BillingInterval
|
||||
workspaceId: string
|
||||
}>()
|
||||
@@ -43,9 +43,8 @@ const { upgradePlan } = useBillingActions()
|
||||
|
||||
const seatPrice = computed(() => {
|
||||
if (isPaidPlan(props.plan)) {
|
||||
const planConfig =
|
||||
pricingPlansConfig.plans[props.plan as unknown as PaidWorkspacePlans]
|
||||
return planConfig.cost[props.billingInterval][Roles.Workspace.Member]
|
||||
const prices = WorkspaceOldPaidPlanPrices[props.plan]
|
||||
return prices[props.billingInterval][Roles.Workspace.Member]
|
||||
}
|
||||
|
||||
return 0
|
||||
|
||||
@@ -11,9 +11,8 @@
|
||||
:columns="[
|
||||
{ id: 'name', header: 'Name', classes: 'col-span-3' },
|
||||
{ id: 'company', header: 'Company', classes: 'col-span-3' },
|
||||
{ id: 'verified', header: 'Status', classes: 'col-span-3' },
|
||||
{ id: 'projects', header: 'Projects', classes: 'col-span-2' },
|
||||
{ id: 'actions', header: '', classes: 'col-span-1 flex justify-end' }
|
||||
{ id: 'actions', header: '', classes: 'col-span-4 flex justify-end' }
|
||||
]"
|
||||
:items="guests"
|
||||
:loading="searchResultLoading"
|
||||
@@ -36,11 +35,6 @@
|
||||
{{ item.user.company ? item.user.company : '-' }}
|
||||
</span>
|
||||
</template>
|
||||
<template #verified="{ item }">
|
||||
<span class="text-body-xs text-foreground-2">
|
||||
{{ item.user.verified ? 'Verified' : 'Unverified' }}
|
||||
</span>
|
||||
</template>
|
||||
<template #projects="{ item }">
|
||||
<span class="text-body-xs text-foreground-2">
|
||||
<CommonBadge color-classes="bg-foundation-2 text-foreground-2" rounded>
|
||||
@@ -121,7 +115,6 @@ graphql(`
|
||||
avatar
|
||||
name
|
||||
company
|
||||
verified
|
||||
}
|
||||
projectRoles {
|
||||
role
|
||||
|
||||
@@ -108,7 +108,7 @@ graphql(`
|
||||
fragment SettingsWorkspacesMembersInvitesTable_Workspace on Workspace {
|
||||
id
|
||||
...SettingsWorkspacesMembersTableHeader_Workspace
|
||||
invitedTeam(filter: $invitesFilter) {
|
||||
invitedTeam {
|
||||
...SettingsWorkspacesMembersInvitesTable_PendingWorkspaceCollaborator
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
:columns="[
|
||||
{ id: 'name', header: 'Name', classes: 'col-span-3' },
|
||||
{ id: 'createdAt', header: 'Requested at', classes: 'col-span-3' },
|
||||
{ id: 'status', header: 'Status', classes: 'col-span-3' },
|
||||
{
|
||||
id: 'actions',
|
||||
header: '',
|
||||
classes: 'col-span-3 lg:col-span-6 flex items-center justify-end'
|
||||
classes: 'col-span-3 flex items-center justify-end'
|
||||
}
|
||||
]"
|
||||
:items="joinRequests"
|
||||
@@ -27,13 +28,22 @@
|
||||
{{ formattedFullDate(item.createdAt) }}
|
||||
</p>
|
||||
</template>
|
||||
<template #status="{ item }">
|
||||
<span class="truncate text-body-xs text-foreground capitalize">
|
||||
{{ item.status }}
|
||||
</span>
|
||||
</template>
|
||||
<template #actions="{ item }">
|
||||
<div class="flex items-center gap-x-2">
|
||||
<div
|
||||
v-if="item.status === WorkspaceJoinRequestStatus.Pending"
|
||||
class="flex items-center gap-x-2"
|
||||
>
|
||||
<FormButton color="outline" size="sm" @click="onApprove(item)">
|
||||
Approve
|
||||
</FormButton>
|
||||
<FormButton color="outline" size="sm" @click="onDeny(item)">Deny</FormButton>
|
||||
</div>
|
||||
<span v-else />
|
||||
</template>
|
||||
</LayoutTable>
|
||||
|
||||
@@ -45,10 +55,13 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { orderBy } from 'lodash-es'
|
||||
import dayjs from 'dayjs'
|
||||
import type { MaybeNullOrUndefined } from '@speckle/shared'
|
||||
import type {
|
||||
SettingsWorkspacesMembersRequestsTable_WorkspaceFragment,
|
||||
WorkspaceJoinRequestApproveDialog_WorkspaceJoinRequestFragment
|
||||
import {
|
||||
type SettingsWorkspacesMembersRequestsTable_WorkspaceFragment,
|
||||
type WorkspaceJoinRequestApproveDialog_WorkspaceJoinRequestFragment,
|
||||
WorkspaceJoinRequestStatus
|
||||
} from '~~/lib/common/generated/gql/graphql'
|
||||
import { graphql } from '~/lib/common/generated/gql'
|
||||
import { useWorkspaceJoinRequest } from '~/lib/workspaces/composables/joinRequests'
|
||||
@@ -57,7 +70,7 @@ graphql(`
|
||||
fragment SettingsWorkspacesMembersRequestsTable_Workspace on Workspace {
|
||||
...SettingsWorkspacesMembersTableHeader_Workspace
|
||||
id
|
||||
adminWorkspacesJoinRequests(filter: $joinRequestsFilter) {
|
||||
adminWorkspacesJoinRequests {
|
||||
totalCount
|
||||
items {
|
||||
...WorkspaceJoinRequestApproveDialog_WorkspaceJoinRequest
|
||||
@@ -84,9 +97,24 @@ const showApproveJoinRequestDialog = ref(false)
|
||||
const requestToApprove =
|
||||
ref<WorkspaceJoinRequestApproveDialog_WorkspaceJoinRequestFragment>()
|
||||
|
||||
const joinRequests = computed(
|
||||
() => props.workspace?.adminWorkspacesJoinRequests?.items || []
|
||||
)
|
||||
const joinRequests = computed(() => {
|
||||
const thirtyDaysAgo = dayjs().subtract(30, 'days')
|
||||
|
||||
const filtered =
|
||||
props.workspace?.adminWorkspacesJoinRequests?.items.filter((request) => {
|
||||
if (request.status === WorkspaceJoinRequestStatus.Pending) return true
|
||||
return dayjs(request.createdAt).isAfter(thirtyDaysAgo)
|
||||
}) ?? []
|
||||
|
||||
return orderBy(
|
||||
filtered,
|
||||
[
|
||||
(request) => (request.status === WorkspaceJoinRequestStatus.Pending ? 1 : 0),
|
||||
'createdAt'
|
||||
],
|
||||
['desc', 'desc']
|
||||
)
|
||||
})
|
||||
|
||||
const onApprove = (
|
||||
request: WorkspaceJoinRequestApproveDialog_WorkspaceJoinRequestFragment
|
||||
|
||||
@@ -13,12 +13,11 @@
|
||||
:columns="[
|
||||
{ id: 'name', header: 'Name', classes: 'col-span-3' },
|
||||
{ id: 'company', header: 'Company', classes: 'col-span-3' },
|
||||
{ id: 'verified', header: 'Status', classes: 'col-span-3' },
|
||||
{ id: 'role', header: 'Role', classes: 'col-span-2' },
|
||||
{
|
||||
id: 'actions',
|
||||
header: '',
|
||||
classes: 'col-span-1 flex items-center justify-end'
|
||||
classes: 'col-span-4 flex items-center justify-end'
|
||||
}
|
||||
]"
|
||||
:items="members"
|
||||
@@ -49,11 +48,6 @@
|
||||
{{ item.company ? item.company : '-' }}
|
||||
</span>
|
||||
</template>
|
||||
<template #verified="{ item }">
|
||||
<span class="text-body-xs text-foreground-2">
|
||||
{{ item.verified ? 'Verified' : 'Unverified' }}
|
||||
</span>
|
||||
</template>
|
||||
<template #role="{ item }">
|
||||
<span class="text-foreground-2">
|
||||
<span>
|
||||
@@ -105,7 +99,7 @@
|
||||
import { Roles, type WorkspaceRoles, type MaybeNullOrUndefined } from '@speckle/shared'
|
||||
import { settingsWorkspacesMembersSearchQuery } from '~~/lib/settings/graphql/queries'
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import type { SettingsWorkspacesMembersMembersTable_WorkspaceFragment } from '~~/lib/common/generated/gql/graphql'
|
||||
import type { SettingsWorkspacesMembersTable_WorkspaceFragment } from '~~/lib/common/generated/gql/graphql'
|
||||
import { graphql } from '~/lib/common/generated/gql'
|
||||
import {
|
||||
EllipsisHorizontalIcon,
|
||||
@@ -120,7 +114,7 @@ import { getRoleLabel } from '~~/lib/settings/helpers/utils'
|
||||
type UserItem = (typeof members)['value'][0]
|
||||
|
||||
graphql(`
|
||||
fragment SettingsWorkspacesMembersMembersTable_WorkspaceCollaborator on WorkspaceCollaborator {
|
||||
fragment SettingsWorkspacesMembersTable_WorkspaceCollaborator on WorkspaceCollaborator {
|
||||
id
|
||||
role
|
||||
user {
|
||||
@@ -128,14 +122,13 @@ graphql(`
|
||||
avatar
|
||||
name
|
||||
company
|
||||
verified
|
||||
workspaceDomainPolicyCompliant
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
graphql(`
|
||||
fragment SettingsWorkspacesMembersMembersTable_Workspace on Workspace {
|
||||
fragment SettingsWorkspacesMembersTable_Workspace on Workspace {
|
||||
id
|
||||
name
|
||||
...SettingsSharedDeleteUserDialog_Workspace
|
||||
@@ -144,7 +137,7 @@ graphql(`
|
||||
team {
|
||||
items {
|
||||
id
|
||||
...SettingsWorkspacesMembersMembersTable_WorkspaceCollaborator
|
||||
...SettingsWorkspacesMembersTable_WorkspaceCollaborator
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -157,7 +150,7 @@ enum ActionTypes {
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
workspace: MaybeNullOrUndefined<SettingsWorkspacesMembersMembersTable_WorkspaceFragment>
|
||||
workspace: MaybeNullOrUndefined<SettingsWorkspacesMembersTable_WorkspaceFragment>
|
||||
workspaceSlug: string
|
||||
}>()
|
||||
|
||||
|
||||
@@ -24,7 +24,8 @@
|
||||
navigateTo(settingsWorkspaceRoutes.members.route(workspaceInfo.slug))
|
||||
"
|
||||
>
|
||||
{{ adminWorkspacesJoinRequestsCount }} join requests
|
||||
{{ adminWorkspacesJoinRequestsCount }} join
|
||||
{{ adminWorkspacesJoinRequestsCount > 1 ? 'requests' : 'request' }}
|
||||
</button>
|
||||
<button
|
||||
v-if="invitedTeamCount && isWorkspaceAdmin"
|
||||
@@ -49,24 +50,20 @@
|
||||
</LayoutSidebarMenuGroup>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { graphql } from '~~/lib/common/generated/gql'
|
||||
import type { WorkspaceSidebarMembers_WorkspaceFragment } from '~/lib/common/generated/gql/graphql'
|
||||
import {
|
||||
type WorkspaceTeam_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'
|
||||
|
||||
graphql(`
|
||||
fragment WorkspaceSidebarMembers_Workspace on Workspace {
|
||||
...WorkspaceTeam_Workspace
|
||||
}
|
||||
`)
|
||||
|
||||
defineEmits<{
|
||||
(e: 'show-invite-dialog'): void
|
||||
}>()
|
||||
|
||||
const props = defineProps<{
|
||||
workspaceInfo: WorkspaceSidebarMembers_WorkspaceFragment
|
||||
workspaceInfo: WorkspaceTeam_WorkspaceFragment
|
||||
collapsible?: boolean
|
||||
isWorkspaceAdmin?: boolean
|
||||
}>()
|
||||
@@ -94,6 +91,9 @@ const iconText = computed(() => {
|
||||
|
||||
const invitedTeamCount = computed(() => props.workspaceInfo?.invitedTeam?.length ?? 0)
|
||||
const adminWorkspacesJoinRequestsCount = computed(
|
||||
() => props.workspaceInfo?.adminWorkspacesJoinRequests?.totalCount
|
||||
() =>
|
||||
props.workspaceInfo?.adminWorkspacesJoinRequests?.items.filter(
|
||||
(request) => request.status === WorkspaceJoinRequestStatus.Pending
|
||||
).length
|
||||
)
|
||||
</script>
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
<div class="flex flex-col max-w-5xl w-full items-center">
|
||||
<div class="grid lg:grid-cols-3 gap-y-2 gap-x-2 w-full">
|
||||
<SettingsWorkspacesBillingPricingTablePlan
|
||||
v-for="plan in plans"
|
||||
:key="plan.name"
|
||||
v-for="plan in oldPlans"
|
||||
:key="plan"
|
||||
:plan="plan"
|
||||
:yearly-interval-selected="isYearlySelected"
|
||||
:badge-text="
|
||||
plan.name === WorkspacePlans.Starter && !isYearlySelected
|
||||
plan === WorkspacePlans.Starter && !isYearlySelected
|
||||
? '30-day free trial'
|
||||
: undefined
|
||||
"
|
||||
@@ -16,14 +16,14 @@
|
||||
>
|
||||
<template #cta>
|
||||
<FormButton
|
||||
:color="plan.name === WorkspacePlans.Starter ? 'primary' : 'outline'"
|
||||
:color="plan === WorkspacePlans.Starter ? 'primary' : 'outline'"
|
||||
full-width
|
||||
@click="onCtaClick(plan.name)"
|
||||
@click="onCtaClick(plan)"
|
||||
>
|
||||
{{
|
||||
plan.name === WorkspacePlans.Starter && !isYearlySelected
|
||||
plan === WorkspacePlans.Starter && !isYearlySelected
|
||||
? 'Start 30-day free trial'
|
||||
: `Subscribe to ${startCase(plan.name)}`
|
||||
: `Subscribe to ${startCase(plan)}`
|
||||
}}
|
||||
</FormButton>
|
||||
</template>
|
||||
@@ -45,16 +45,17 @@ import {
|
||||
WorkspacePlans
|
||||
} from '~/lib/common/generated/gql/graphql'
|
||||
import { useWorkspacesWizard } from '~/lib/workspaces/composables/wizard'
|
||||
import { pricingPlansConfig } from '~/lib/billing/helpers/constants'
|
||||
import { useMixpanel } from '~/lib/core/composables/mp'
|
||||
import { startCase } from 'lodash'
|
||||
import { PaidWorkspacePlansOld } from '@speckle/shared'
|
||||
|
||||
const { goToNextStep, goToPreviousStep, state } = useWorkspacesWizard()
|
||||
const mixpanel = useMixpanel()
|
||||
|
||||
const plans = ref(pricingPlansConfig.plans)
|
||||
const isYearlySelected = ref(false)
|
||||
|
||||
const oldPlans = computed(() => Object.values(PaidWorkspacePlansOld))
|
||||
|
||||
const onCtaClick = (plan: WorkspacePlans) => {
|
||||
state.value.plan = plan as unknown as PaidWorkspacePlans
|
||||
state.value.billingInterval = isYearlySelected.value
|
||||
|
||||
@@ -71,4 +71,12 @@ export const useIsBillingIntegrationEnabled = () => {
|
||||
return ref(FF_BILLING_INTEGRATION_ENABLED)
|
||||
}
|
||||
|
||||
export const useIsNoPersonalEmailsEnabled = () => {
|
||||
const {
|
||||
public: { FF_NO_PERSONAL_EMAILS_ENABLED }
|
||||
} = useRuntimeConfig()
|
||||
|
||||
return ref(FF_NO_PERSONAL_EMAILS_ENABLED)
|
||||
}
|
||||
|
||||
export { useGlobalToast, useActiveUser, usePageQueryStandardFetchPolicy }
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import { useApolloClient } from '@vue/apollo-composable'
|
||||
import { useMixpanel } from '~~/lib/core/composables/mp'
|
||||
import { UnsupportedEnvironmentError } from '~~/lib/core/errors/base'
|
||||
import type { OnboardingState } from '~~/lib/auth/helpers/onboarding'
|
||||
import type {
|
||||
OnboardingPlan,
|
||||
OnboardingRole,
|
||||
OnboardingSource,
|
||||
OnboardingState
|
||||
} from '@speckle/shared'
|
||||
import { useActiveUser } from '~~/lib/auth/composables/activeUser'
|
||||
import { OnboardingError } from '~~/lib/auth/errors/errors'
|
||||
import { finishOnboardingMutation } from '~~/lib/auth/graphql/mutations'
|
||||
@@ -86,14 +91,22 @@ export const useProcessOnboarding = () => {
|
||||
|
||||
/**
|
||||
* Marks the current user as having completed the onboarding - we're using this as a flag to
|
||||
* know that we've set up the sample project once.
|
||||
* know that we've set up the sample project once. Also updates their Mailchimp tags.
|
||||
*/
|
||||
const setUserOnboardingComplete = async () => {
|
||||
const setUserOnboardingComplete = async (onboardingData?: {
|
||||
role?: OnboardingRole
|
||||
plans?: OnboardingPlan[]
|
||||
source?: OnboardingSource
|
||||
}) => {
|
||||
const user = activeUser.value
|
||||
if (!user) throw new OnboardingError('Attempting to onboard unidentified user')
|
||||
|
||||
await apollo
|
||||
.mutate({
|
||||
mutation: finishOnboardingMutation,
|
||||
variables: {
|
||||
input: onboardingData
|
||||
},
|
||||
update: (cache, { data }) => {
|
||||
if (!data?.activeUserMutations.finishOnboarding) return
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { graphql } from '~~/lib/common/generated/gql'
|
||||
|
||||
export const finishOnboardingMutation = graphql(`
|
||||
mutation FinishOnboarding {
|
||||
mutation FinishOnboarding($input: OnboardingCompletionInput) {
|
||||
activeUserMutations {
|
||||
finishOnboarding
|
||||
finishOnboarding(input: $input)
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
@@ -1,32 +1,4 @@
|
||||
export enum OnboardingRole {
|
||||
ComputationalDesign = 'computational-design',
|
||||
BIM = 'bim',
|
||||
ArchitecturePlanning = 'architecture-planning',
|
||||
EngineeringAEC = 'engineering-aec',
|
||||
EngineeringSoftware = 'engineering-software',
|
||||
Education = 'education',
|
||||
Management = 'management',
|
||||
Other = 'other'
|
||||
}
|
||||
|
||||
export enum OnboardingPlan {
|
||||
Exploring = 'exploring',
|
||||
DataExchange = 'data-exchange',
|
||||
Analytics = 'analytics',
|
||||
Collaboration = 'collaboration',
|
||||
DataWarehouse = 'data-warehouse',
|
||||
Development = 'development',
|
||||
Other = 'other'
|
||||
}
|
||||
|
||||
export enum OnboardingSource {
|
||||
SocialMedia = 'social-media',
|
||||
Search = 'internet-search',
|
||||
Referral = 'friend-or-colleague',
|
||||
Event = 'event-conference',
|
||||
Education = 'university-course',
|
||||
Other = 'other'
|
||||
}
|
||||
import { OnboardingRole, OnboardingPlan, OnboardingSource } from '@speckle/shared'
|
||||
|
||||
export const RoleTitleMap: Record<OnboardingRole, string> = {
|
||||
[OnboardingRole.ComputationalDesign]: 'Computational Design',
|
||||
@@ -58,9 +30,3 @@ export const SourceTitleMap: Record<OnboardingSource, string> = {
|
||||
[OnboardingSource.Education]: 'University or course',
|
||||
[OnboardingSource.Other]: 'Other'
|
||||
}
|
||||
|
||||
export type OnboardingState = {
|
||||
role?: OnboardingRole
|
||||
plans?: OnboardingPlan[]
|
||||
source?: OnboardingSource
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { isStringOfLength, stringContains } from '~~/lib/common/helpers/validation'
|
||||
import { blockedDomains } from '@speckle/shared'
|
||||
|
||||
export const passwordLongEnough = isStringOfLength({ minLength: 8 })
|
||||
export const passwordHasAtLeastOneNumber = stringContains({
|
||||
@@ -20,3 +21,10 @@ export const passwordRules = [
|
||||
passwordHasAtLeastOneLowercaseLetter,
|
||||
passwordHasAtLeastOneUppercaseLetter
|
||||
]
|
||||
|
||||
export const doesNotContainBlockedDomain = (val: string) => {
|
||||
const domain = val.split('@')[1]?.toLowerCase()
|
||||
return domain && blockedDomains.includes(domain)
|
||||
? 'Please use your work email instead of a personal email address'
|
||||
: true
|
||||
}
|
||||
|
||||
@@ -62,12 +62,14 @@ export const useAutomationRunSummary = (params: {
|
||||
?.functionRuns.filter(
|
||||
(r): r is SetFullyRequired<typeof r, 'statusMessage'> =>
|
||||
!!(
|
||||
[
|
||||
AutomateRunStatus.Failed,
|
||||
AutomateRunStatus.Canceled,
|
||||
AutomateRunStatus.Exception,
|
||||
AutomateRunStatus.Timeout
|
||||
].includes(r.status) && r.statusMessage?.length
|
||||
(
|
||||
[
|
||||
AutomateRunStatus.Failed,
|
||||
AutomateRunStatus.Canceled,
|
||||
AutomateRunStatus.Exception,
|
||||
AutomateRunStatus.Timeout
|
||||
] as string[]
|
||||
).includes(r.status) && r.statusMessage?.length
|
||||
)
|
||||
)
|
||||
.map((r) => r.statusMessage) || []
|
||||
@@ -141,9 +143,9 @@ export const useAutomationRunDetailsFns = () => {
|
||||
const end =
|
||||
run.status === AutomateRunStatus.Running
|
||||
? now.value
|
||||
: [AutomateRunStatus.Initializing, AutomateRunStatus.Pending].includes(
|
||||
run.status
|
||||
)
|
||||
: (
|
||||
[AutomateRunStatus.Initializing, AutomateRunStatus.Pending] as string[]
|
||||
).includes(run.status)
|
||||
? undefined
|
||||
: run.updatedAt
|
||||
if (!end) return undefined
|
||||
|
||||
@@ -1,114 +1,48 @@
|
||||
import { WorkspacePlans, BillingInterval } from '~/lib/common/generated/gql/graphql'
|
||||
import { Roles } from '@speckle/shared'
|
||||
import { PlanFeaturesList, type PricingPlan } from '@/lib/billing/helpers/types'
|
||||
import {
|
||||
PaidWorkspacePlansOld,
|
||||
Roles,
|
||||
WorkspacePlanBillingIntervals,
|
||||
type WorkspacePlanPriceStructure
|
||||
} from '@speckle/shared'
|
||||
|
||||
const baseFeatures = [
|
||||
PlanFeaturesList.Workspaces,
|
||||
PlanFeaturesList.RoleManagement,
|
||||
PlanFeaturesList.GuestUsers,
|
||||
PlanFeaturesList.PrivateAutomateFunctions,
|
||||
PlanFeaturesList.DomainSecurity
|
||||
]
|
||||
|
||||
export const pricingPlansConfig: {
|
||||
features: Record<
|
||||
PlanFeaturesList,
|
||||
{ name: string; description: (price?: number) => string }
|
||||
>
|
||||
plans: Record<
|
||||
WorkspacePlans.Starter | WorkspacePlans.Plus | WorkspacePlans.Business,
|
||||
PricingPlan
|
||||
>
|
||||
// TODO: Read these from API, especially for new plans
|
||||
export const WorkspaceOldPaidPlanPrices: {
|
||||
[plan in PaidWorkspacePlansOld]: WorkspacePlanPriceStructure
|
||||
} = {
|
||||
features: {
|
||||
[PlanFeaturesList.Workspaces]: {
|
||||
name: PlanFeaturesList.Workspaces,
|
||||
description: () => `A shared space for your team and projects`
|
||||
[PaidWorkspacePlansOld.Starter]: {
|
||||
[WorkspacePlanBillingIntervals.Monthly]: {
|
||||
[Roles.Workspace.Guest]: 15,
|
||||
[Roles.Workspace.Member]: 15,
|
||||
[Roles.Workspace.Admin]: 15
|
||||
},
|
||||
[PlanFeaturesList.RoleManagement]: {
|
||||
name: PlanFeaturesList.RoleManagement,
|
||||
description: () => `Control individual members' access and edit rights`
|
||||
},
|
||||
[PlanFeaturesList.GuestUsers]: {
|
||||
name: PlanFeaturesList.GuestUsers,
|
||||
description: (price?: number) =>
|
||||
`Give guests access to specific projects in the workspace at £${price}/month/guest`
|
||||
},
|
||||
[PlanFeaturesList.PrivateAutomateFunctions]: {
|
||||
name: PlanFeaturesList.PrivateAutomateFunctions,
|
||||
description: () =>
|
||||
`Create and manage private automation functions securely within your workspace`
|
||||
},
|
||||
[PlanFeaturesList.DomainSecurity]: {
|
||||
name: PlanFeaturesList.DomainSecurity,
|
||||
description: () => `Require workspace members to use a verified company email`
|
||||
},
|
||||
[PlanFeaturesList.SSO]: {
|
||||
name: PlanFeaturesList.SSO,
|
||||
description: () => `Require workspace members to log in with your SSO provider`
|
||||
},
|
||||
[PlanFeaturesList.CustomDataRegion]: {
|
||||
name: PlanFeaturesList.CustomDataRegion,
|
||||
description: () => `Store the workspace data in a custom region`
|
||||
},
|
||||
[PlanFeaturesList.PrioritySupport]: {
|
||||
name: PlanFeaturesList.PrioritySupport,
|
||||
description: () => `Personal and fast support`
|
||||
[WorkspacePlanBillingIntervals.Yearly]: {
|
||||
[Roles.Workspace.Guest]: 12,
|
||||
[Roles.Workspace.Member]: 12,
|
||||
[Roles.Workspace.Admin]: 12
|
||||
}
|
||||
},
|
||||
plans: {
|
||||
[WorkspacePlans.Starter]: {
|
||||
name: WorkspacePlans.Starter,
|
||||
features: [...baseFeatures],
|
||||
cost: {
|
||||
[BillingInterval.Monthly]: {
|
||||
[Roles.Workspace.Guest]: 15,
|
||||
[Roles.Workspace.Member]: 15,
|
||||
[Roles.Workspace.Admin]: 15
|
||||
},
|
||||
[BillingInterval.Yearly]: {
|
||||
[Roles.Workspace.Guest]: 12,
|
||||
[Roles.Workspace.Member]: 12,
|
||||
[Roles.Workspace.Admin]: 12
|
||||
}
|
||||
}
|
||||
[PaidWorkspacePlansOld.Plus]: {
|
||||
[WorkspacePlanBillingIntervals.Monthly]: {
|
||||
[Roles.Workspace.Guest]: 15,
|
||||
[Roles.Workspace.Member]: 50,
|
||||
[Roles.Workspace.Admin]: 50
|
||||
},
|
||||
[WorkspacePlans.Plus]: {
|
||||
name: WorkspacePlans.Plus,
|
||||
features: [...baseFeatures, PlanFeaturesList.SSO],
|
||||
cost: {
|
||||
[BillingInterval.Monthly]: {
|
||||
[Roles.Workspace.Guest]: 15,
|
||||
[Roles.Workspace.Member]: 50,
|
||||
[Roles.Workspace.Admin]: 50
|
||||
},
|
||||
[BillingInterval.Yearly]: {
|
||||
[Roles.Workspace.Guest]: 12,
|
||||
[Roles.Workspace.Member]: 40,
|
||||
[Roles.Workspace.Admin]: 40
|
||||
}
|
||||
}
|
||||
[WorkspacePlanBillingIntervals.Yearly]: {
|
||||
[Roles.Workspace.Guest]: 12,
|
||||
[Roles.Workspace.Member]: 40,
|
||||
[Roles.Workspace.Admin]: 40
|
||||
}
|
||||
},
|
||||
[PaidWorkspacePlansOld.Business]: {
|
||||
[WorkspacePlanBillingIntervals.Monthly]: {
|
||||
[Roles.Workspace.Guest]: 15,
|
||||
[Roles.Workspace.Member]: 75,
|
||||
[Roles.Workspace.Admin]: 75
|
||||
},
|
||||
[WorkspacePlans.Business]: {
|
||||
name: WorkspacePlans.Business,
|
||||
features: [
|
||||
...baseFeatures,
|
||||
PlanFeaturesList.SSO,
|
||||
PlanFeaturesList.CustomDataRegion,
|
||||
PlanFeaturesList.PrioritySupport
|
||||
],
|
||||
cost: {
|
||||
[BillingInterval.Monthly]: {
|
||||
[Roles.Workspace.Guest]: 15,
|
||||
[Roles.Workspace.Member]: 75,
|
||||
[Roles.Workspace.Admin]: 75
|
||||
},
|
||||
[BillingInterval.Yearly]: {
|
||||
[Roles.Workspace.Guest]: 12,
|
||||
[Roles.Workspace.Member]: 60,
|
||||
[Roles.Workspace.Admin]: 60
|
||||
}
|
||||
}
|
||||
[WorkspacePlanBillingIntervals.Yearly]: {
|
||||
[Roles.Workspace.Guest]: 12,
|
||||
[Roles.Workspace.Member]: 60,
|
||||
[Roles.Workspace.Admin]: 60
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,31 +1,6 @@
|
||||
import {
|
||||
type BillingInterval,
|
||||
type WorkspacePlans,
|
||||
PaidWorkspacePlans
|
||||
} from '~/lib/common/generated/gql/graphql'
|
||||
import type { WorkspaceRoles } from '@speckle/shared'
|
||||
|
||||
export enum PlanFeaturesList {
|
||||
Workspaces = 'Workspaces',
|
||||
RoleManagement = 'Role management',
|
||||
GuestUsers = 'Guest users',
|
||||
PrivateAutomateFunctions = 'Private automate functions',
|
||||
DomainSecurity = 'Domain security',
|
||||
SSO = 'Single Sign-On (SSO)',
|
||||
CustomDataRegion = 'Custom data residency',
|
||||
PrioritySupport = 'Priority support'
|
||||
}
|
||||
|
||||
export type PricingPlan = {
|
||||
name: WorkspacePlans
|
||||
features: PlanFeaturesList[]
|
||||
cost: {
|
||||
[I in BillingInterval]: Record<WorkspaceRoles, number>
|
||||
}
|
||||
}
|
||||
import type { WorkspacePlans } from '@speckle/shared'
|
||||
import { PaidWorkspacePlans } from '@speckle/shared'
|
||||
|
||||
// Check if the plan matches PaidWorkspacePlans
|
||||
export const isPaidPlan = (plan?: WorkspacePlans): boolean =>
|
||||
plan
|
||||
? Object.values(PaidWorkspacePlans).includes(plan as unknown as PaidWorkspacePlans)
|
||||
: false
|
||||
plan ? (Object.values(PaidWorkspacePlans) as string[]).includes(plan) : false
|
||||
|
||||
@@ -13,7 +13,394 @@ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-
|
||||
* Therefore it is highly recommended to use the babel or swc plugin for production.
|
||||
* Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size
|
||||
*/
|
||||
const documents = {
|
||||
type Documents = {
|
||||
"\n fragment AuthLoginWithEmailBlock_PendingWorkspaceCollaborator on PendingWorkspaceCollaborator {\n id\n email\n user {\n id\n }\n }\n": typeof types.AuthLoginWithEmailBlock_PendingWorkspaceCollaboratorFragmentDoc,
|
||||
"\n query AuthRegisterPanelWorkspaceInvite($token: String) {\n workspaceInvite(token: $token) {\n id\n ...AuthWorkspaceInviteHeader_PendingWorkspaceCollaborator\n }\n }\n": typeof types.AuthRegisterPanelWorkspaceInviteDocument,
|
||||
"\n fragment ServerTermsOfServicePrivacyPolicyFragment on ServerInfo {\n termsOfService\n }\n": typeof types.ServerTermsOfServicePrivacyPolicyFragmentFragmentDoc,
|
||||
"\n fragment AuthWorkspaceInviteHeader_PendingWorkspaceCollaborator on PendingWorkspaceCollaborator {\n id\n workspaceName\n email\n user {\n id\n ...LimitedUserAvatar\n }\n }\n": typeof types.AuthWorkspaceInviteHeader_PendingWorkspaceCollaboratorFragmentDoc,
|
||||
"\n fragment AuthSsoLogin_Workspace on LimitedWorkspace {\n id\n slug\n name\n logo\n }\n": typeof types.AuthSsoLogin_WorkspaceFragmentDoc,
|
||||
"\n fragment AuthStategiesServerInfoFragment on ServerInfo {\n authStrategies {\n id\n name\n url\n }\n ...AuthThirdPartyLoginButtonOIDC_ServerInfo\n }\n": typeof types.AuthStategiesServerInfoFragmentFragmentDoc,
|
||||
"\n fragment AuthThirdPartyLoginButtonOIDC_ServerInfo on ServerInfo {\n authStrategies {\n id\n name\n }\n }\n": typeof types.AuthThirdPartyLoginButtonOidc_ServerInfoFragmentDoc,
|
||||
"\n fragment AutomateAutomationCreateDialog_AutomateFunction on AutomateFunction {\n id\n ...AutomationsFunctionsCard_AutomateFunction\n ...AutomateAutomationCreateDialogFunctionParametersStep_AutomateFunction\n }\n": typeof types.AutomateAutomationCreateDialog_AutomateFunctionFragmentDoc,
|
||||
"\n fragment AutomateAutomationCreateDialogFunctionParametersStep_AutomateFunction on AutomateFunction {\n id\n releases(limit: 1) {\n items {\n id\n inputSchema\n }\n }\n }\n": typeof types.AutomateAutomationCreateDialogFunctionParametersStep_AutomateFunctionFragmentDoc,
|
||||
"\n query AutomationCreateDialogFunctionsSearch(\n $workspaceId: String!\n $search: String\n $cursor: String = null\n ) {\n workspace(id: $workspaceId) {\n automateFunctions(limit: 20, filter: { search: $search }, cursor: $cursor) {\n cursor\n totalCount\n items {\n id\n ...AutomateAutomationCreateDialog_AutomateFunction\n }\n }\n }\n }\n": typeof types.AutomationCreateDialogFunctionsSearchDocument,
|
||||
"\n fragment AutomationsFunctionsCard_AutomateFunction on AutomateFunction {\n id\n name\n isFeatured\n description\n logo\n repo {\n id\n url\n owner\n name\n }\n }\n": typeof types.AutomationsFunctionsCard_AutomateFunctionFragmentDoc,
|
||||
"\n fragment AutomateFunctionCreateDialog_Workspace on Workspace {\n id\n name\n slug\n }\n": typeof types.AutomateFunctionCreateDialog_WorkspaceFragmentDoc,
|
||||
"\n fragment AutomateFunctionEditDialog_Workspace on Workspace {\n id\n name\n }\n": typeof types.AutomateFunctionEditDialog_WorkspaceFragmentDoc,
|
||||
"\n fragment AutomateFunctionCreateDialogDoneStep_AutomateFunction on AutomateFunction {\n id\n repo {\n id\n url\n owner\n name\n }\n ...AutomationsFunctionsCard_AutomateFunction\n }\n": typeof types.AutomateFunctionCreateDialogDoneStep_AutomateFunctionFragmentDoc,
|
||||
"\n fragment AutomateFunctionCreateDialogTemplateStep_AutomateFunctionTemplate on AutomateFunctionTemplate {\n id\n title\n logo\n url\n }\n": typeof types.AutomateFunctionCreateDialogTemplateStep_AutomateFunctionTemplateFragmentDoc,
|
||||
"\n fragment AutomateFunctionPageHeader_Function on AutomateFunction {\n id\n name\n logo\n repo {\n id\n url\n owner\n name\n }\n releases(limit: 1) {\n totalCount\n }\n workspaceIds\n }\n\n fragment AutomateFunctionPageHeader_Workspace on Workspace {\n id\n name\n slug\n }\n": typeof types.AutomateFunctionPageHeader_FunctionFragmentDoc,
|
||||
"\n fragment AutomateFunctionPageInfo_AutomateFunction on AutomateFunction {\n id\n repo {\n id\n url\n owner\n name\n }\n description\n releases(limit: 1) {\n items {\n id\n inputSchema\n createdAt\n commitId\n ...AutomateFunctionPageParametersDialog_AutomateFunctionRelease\n }\n }\n }\n": typeof types.AutomateFunctionPageInfo_AutomateFunctionFragmentDoc,
|
||||
"\n fragment AutomateFunctionPageParametersDialog_AutomateFunctionRelease on AutomateFunctionRelease {\n id\n inputSchema\n }\n": typeof types.AutomateFunctionPageParametersDialog_AutomateFunctionReleaseFragmentDoc,
|
||||
"\n fragment AutomateFunctionsPageHeader_Query on Query {\n activeUser {\n id\n role\n automateInfo {\n hasAutomateGithubApp\n availableGithubOrgs\n }\n }\n serverInfo {\n automate {\n availableFunctionTemplates {\n ...AutomateFunctionCreateDialogTemplateStep_AutomateFunctionTemplate\n }\n }\n }\n }\n": typeof types.AutomateFunctionsPageHeader_QueryFragmentDoc,
|
||||
"\n fragment AutomateFunctionsPageItems_Query on Query {\n automateFunctions(limit: 6, filter: { search: $search }, cursor: $cursor) {\n totalCount\n items {\n id\n ...AutomationsFunctionsCard_AutomateFunction\n ...AutomateAutomationCreateDialog_AutomateFunction\n }\n cursor\n }\n }\n": typeof types.AutomateFunctionsPageItems_QueryFragmentDoc,
|
||||
"\n fragment AutomateRunsTriggerStatus_TriggeredAutomationsStatus on TriggeredAutomationsStatus {\n id\n ...TriggeredAutomationsStatusSummary\n ...AutomateRunsTriggerStatusDialog_TriggeredAutomationsStatus\n }\n": typeof types.AutomateRunsTriggerStatus_TriggeredAutomationsStatusFragmentDoc,
|
||||
"\n fragment AutomateRunsTriggerStatusDialog_TriggeredAutomationsStatus on TriggeredAutomationsStatus {\n id\n automationRuns {\n id\n ...AutomateRunsTriggerStatusDialogRunsRows_AutomateRun\n }\n }\n": typeof types.AutomateRunsTriggerStatusDialog_TriggeredAutomationsStatusFragmentDoc,
|
||||
"\n fragment AutomateRunsTriggerStatusDialogFunctionRun_AutomateFunctionRun on AutomateFunctionRun {\n id\n results\n status\n statusMessage\n contextView\n function {\n id\n logo\n name\n }\n createdAt\n updatedAt\n }\n": typeof types.AutomateRunsTriggerStatusDialogFunctionRun_AutomateFunctionRunFragmentDoc,
|
||||
"\n fragment AutomateRunsTriggerStatusDialogRunsRows_AutomateRun on AutomateRun {\n id\n functionRuns {\n id\n ...AutomateRunsTriggerStatusDialogFunctionRun_AutomateFunctionRun\n }\n ...AutomationsStatusOrderedRuns_AutomationRun\n }\n": typeof types.AutomateRunsTriggerStatusDialogRunsRows_AutomateRunFragmentDoc,
|
||||
"\n fragment AutomateViewerPanel_AutomateRun on AutomateRun {\n id\n functionRuns {\n id\n ...AutomateViewerPanelFunctionRunRow_AutomateFunctionRun\n }\n ...AutomationsStatusOrderedRuns_AutomationRun\n }\n": typeof types.AutomateViewerPanel_AutomateRunFragmentDoc,
|
||||
"\n fragment AutomateViewerPanelFunctionRunRow_AutomateFunctionRun on AutomateFunctionRun {\n id\n results\n status\n statusMessage\n contextView\n function {\n id\n logo\n name\n }\n createdAt\n updatedAt\n }\n": typeof types.AutomateViewerPanelFunctionRunRow_AutomateFunctionRunFragmentDoc,
|
||||
"\n fragment BillingAlert_Workspace on Workspace {\n id\n plan {\n name\n status\n createdAt\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n }\n }\n": typeof types.BillingAlert_WorkspaceFragmentDoc,
|
||||
"\n fragment CommonModelSelectorModel on Model {\n id\n name\n }\n": typeof types.CommonModelSelectorModelFragmentDoc,
|
||||
"\n fragment DashboardProjectCard_Project on Project {\n id\n name\n role\n updatedAt\n models {\n totalCount\n }\n team {\n user {\n ...LimitedUserAvatar\n }\n }\n workspace {\n id\n slug\n name\n logo\n }\n }\n": typeof types.DashboardProjectCard_ProjectFragmentDoc,
|
||||
"\n fragment Sidebar_User on User {\n id\n automateFunctions {\n items {\n id\n name\n description\n logo\n }\n }\n }\n": typeof types.Sidebar_UserFragmentDoc,
|
||||
"\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 HeaderNavShare_Project on Project {\n id\n visibility\n ...ProjectsModelPageEmbed_Project\n }\n": typeof types.HeaderNavShare_ProjectFragmentDoc,
|
||||
"\n fragment InviteDialogWorkspace_Workspace on Workspace {\n id\n domainBasedMembershipProtectionEnabled\n domains {\n domain\n id\n }\n plan {\n status\n name\n }\n subscription {\n seats {\n guest\n plan\n }\n }\n }\n": typeof types.InviteDialogWorkspace_WorkspaceFragmentDoc,
|
||||
"\n fragment InviteDialogProject_Project on Project {\n id\n name\n ...InviteDialogProjectWorkspaceMembers_Project\n workspace {\n id\n name\n defaultProjectRole\n role\n domainBasedMembershipProtectionEnabled\n domains {\n domain\n id\n }\n plan {\n status\n name\n }\n subscription {\n seats {\n guest\n plan\n }\n }\n }\n }\n": typeof types.InviteDialogProject_ProjectFragmentDoc,
|
||||
"\n fragment InviteDialogProjectWorkspaceMembersRow_WorkspaceCollaborator on WorkspaceCollaborator {\n role\n id\n user {\n id\n name\n bio\n company\n avatar\n verified\n role\n }\n }\n": typeof types.InviteDialogProjectWorkspaceMembersRow_WorkspaceCollaboratorFragmentDoc,
|
||||
"\n fragment InviteDialogProjectWorkspaceMembers_Project on Project {\n id\n ...ProjectPageTeamInternals_Project\n workspace {\n team {\n items {\n ...InviteDialogProjectWorkspaceMembersRow_WorkspaceCollaborator\n }\n }\n }\n }\n": typeof types.InviteDialogProjectWorkspaceMembers_ProjectFragmentDoc,
|
||||
"\n fragment ProjectModelPageHeaderProject on Project {\n id\n name\n model(id: $modelId) {\n id\n name\n description\n }\n workspace {\n id\n slug\n name\n }\n }\n": typeof types.ProjectModelPageHeaderProjectFragmentDoc,
|
||||
"\n fragment ProjectModelPageVersionsPagination on Project {\n id\n visibility\n model(id: $modelId) {\n id\n versions(limit: 16, cursor: $versionsCursor) {\n cursor\n totalCount\n items {\n ...ProjectModelPageVersionsCardVersion\n }\n }\n }\n ...ProjectsModelPageEmbed_Project\n }\n": typeof types.ProjectModelPageVersionsPaginationFragmentDoc,
|
||||
"\n fragment ProjectModelPageVersionsProject on Project {\n ...ProjectPageProjectHeader\n model(id: $modelId) {\n id\n name\n pendingImportedVersions {\n ...PendingFileUpload\n }\n }\n ...ProjectModelPageVersionsPagination\n ...ProjectsModelPageEmbed_Project\n workspace {\n id\n readOnly\n }\n }\n": typeof types.ProjectModelPageVersionsProjectFragmentDoc,
|
||||
"\n fragment ProjectModelPageDialogDeleteVersion on Version {\n id\n message\n }\n": typeof types.ProjectModelPageDialogDeleteVersionFragmentDoc,
|
||||
"\n fragment ProjectModelPageDialogEditMessageVersion on Version {\n id\n message\n }\n": typeof types.ProjectModelPageDialogEditMessageVersionFragmentDoc,
|
||||
"\n fragment ProjectModelPageDialogMoveToVersion on Version {\n id\n message\n }\n": typeof types.ProjectModelPageDialogMoveToVersionFragmentDoc,
|
||||
"\n fragment ProjectsModelPageEmbed_Project on Project {\n id\n ...ProjectsPageTeamDialogManagePermissions_Project\n }\n": typeof types.ProjectsModelPageEmbed_ProjectFragmentDoc,
|
||||
"\n fragment ProjectModelPageVersionsCardVersion on Version {\n id\n message\n authorUser {\n ...LimitedUserAvatar\n }\n createdAt\n previewUrl\n sourceApplication\n commentThreadCount: commentThreads(limit: 0) {\n totalCount\n }\n ...ProjectModelPageDialogDeleteVersion\n ...ProjectModelPageDialogMoveToVersion\n automationsStatus {\n ...AutomateRunsTriggerStatus_TriggeredAutomationsStatus\n }\n }\n": typeof types.ProjectModelPageVersionsCardVersionFragmentDoc,
|
||||
"\n fragment ProjectPageProjectHeader on Project {\n id\n role\n name\n description\n visibility\n allowPublicComments\n workspace {\n id\n slug\n name\n logo\n }\n }\n": typeof types.ProjectPageProjectHeaderFragmentDoc,
|
||||
"\n fragment ProjectPageAutomationFunctionSettingsDialog_AutomationRevisionFunction on AutomationRevisionFunction {\n parameters\n release {\n id\n versionTag\n createdAt\n inputSchema\n function {\n id\n }\n }\n }\n": typeof types.ProjectPageAutomationFunctionSettingsDialog_AutomationRevisionFunctionFragmentDoc,
|
||||
"\n fragment ProjectPageAutomationFunctionSettingsDialog_AutomationRevision on AutomationRevision {\n id\n triggerDefinitions {\n ... on VersionCreatedTriggerDefinition {\n type\n model {\n id\n ...CommonModelSelectorModel\n }\n }\n }\n }\n": typeof types.ProjectPageAutomationFunctionSettingsDialog_AutomationRevisionFragmentDoc,
|
||||
"\n fragment ProjectPageAutomationFunctions_Automation on Automation {\n id\n currentRevision {\n id\n ...ProjectPageAutomationFunctionSettingsDialog_AutomationRevision\n functions {\n release {\n id\n inputSchema\n function {\n id\n ...AutomationsFunctionsCard_AutomateFunction\n releases(limit: 1) {\n items {\n id\n }\n }\n }\n }\n ...ProjectPageAutomationFunctionSettingsDialog_AutomationRevisionFunction\n }\n }\n }\n": typeof types.ProjectPageAutomationFunctions_AutomationFragmentDoc,
|
||||
"\n fragment ProjectPageAutomationHeader_Automation on Automation {\n id\n name\n enabled\n isTestAutomation\n currentRevision {\n id\n triggerDefinitions {\n ... on VersionCreatedTriggerDefinition {\n model {\n ...ProjectPageLatestItemsModelItem\n }\n }\n }\n }\n }\n": typeof types.ProjectPageAutomationHeader_AutomationFragmentDoc,
|
||||
"\n fragment ProjectPageAutomationHeader_Project on Project {\n id\n role\n workspaceId\n ...ProjectPageModelsCardProject\n }\n": typeof types.ProjectPageAutomationHeader_ProjectFragmentDoc,
|
||||
"\n fragment ProjectPageAutomationModels_Project on Project {\n id\n ...ProjectPageModelsCardProject\n }\n": typeof types.ProjectPageAutomationModels_ProjectFragmentDoc,
|
||||
"\n fragment ProjectPageAutomationRuns_Automation on Automation {\n id\n name\n enabled\n isTestAutomation\n runs(limit: 10) {\n items {\n ...AutomationRunDetails\n }\n totalCount\n cursor\n }\n }\n": typeof types.ProjectPageAutomationRuns_AutomationFragmentDoc,
|
||||
"\n fragment ProjectPageAutomationsRow_Automation on Automation {\n id\n name\n enabled\n isTestAutomation\n currentRevision {\n id\n triggerDefinitions {\n ... on VersionCreatedTriggerDefinition {\n model {\n id\n name\n }\n }\n }\n }\n runs(limit: 10) {\n totalCount\n items {\n ...AutomationRunDetails\n }\n cursor\n }\n }\n": typeof types.ProjectPageAutomationsRow_AutomationFragmentDoc,
|
||||
"\n fragment ProjectDiscussionsPageHeader_Project on Project {\n id\n name\n }\n": typeof types.ProjectDiscussionsPageHeader_ProjectFragmentDoc,
|
||||
"\n fragment ProjectDiscussionsPageResults_Project on Project {\n id\n }\n": typeof types.ProjectDiscussionsPageResults_ProjectFragmentDoc,
|
||||
"\n fragment ProjectPageModelsActions on Model {\n id\n name\n }\n": typeof types.ProjectPageModelsActionsFragmentDoc,
|
||||
"\n fragment ProjectPageModelsActions_Project on Project {\n id\n ...ProjectsModelPageEmbed_Project\n }\n": typeof types.ProjectPageModelsActions_ProjectFragmentDoc,
|
||||
"\n fragment ProjectPageModelsCardProject on Project {\n id\n role\n visibility\n ...ProjectPageModelsActions_Project\n workspace {\n id\n readOnly\n }\n }\n": typeof types.ProjectPageModelsCardProjectFragmentDoc,
|
||||
"\n fragment ProjectModelsPageHeader_Project on Project {\n id\n name\n sourceApps\n role\n models {\n totalCount\n }\n team {\n id\n user {\n ...FormUsersSelectItem\n }\n }\n workspace {\n id\n readOnly\n }\n }\n": typeof types.ProjectModelsPageHeader_ProjectFragmentDoc,
|
||||
"\n fragment ProjectModelsPageResults_Project on Project {\n ...ProjectPageLatestItemsModels\n }\n": typeof types.ProjectModelsPageResults_ProjectFragmentDoc,
|
||||
"\n fragment ProjectPageModelsStructureItem_Project on Project {\n id\n workspace {\n id\n readOnly\n }\n ...ProjectPageModelsActions_Project\n }\n": typeof types.ProjectPageModelsStructureItem_ProjectFragmentDoc,
|
||||
"\n fragment SingleLevelModelTreeItem on ModelsTreeItem {\n id\n name\n fullName\n model {\n ...ProjectPageLatestItemsModelItem\n }\n hasChildren\n updatedAt\n }\n": typeof types.SingleLevelModelTreeItemFragmentDoc,
|
||||
"\n fragment ProjectPageModelsCardDeleteDialog on Model {\n id\n name\n }\n": typeof types.ProjectPageModelsCardDeleteDialogFragmentDoc,
|
||||
"\n fragment ProjectPageModelsCardRenameDialog on Model {\n id\n name\n description\n }\n": typeof types.ProjectPageModelsCardRenameDialogFragmentDoc,
|
||||
"\n query ProjectPageSettingsCollaborators($projectId: String!) {\n project(id: $projectId) {\n id\n ...ProjectPageTeamInternals_Project\n ...InviteDialogProject_Project\n workspaceId\n }\n }\n": typeof types.ProjectPageSettingsCollaboratorsDocument,
|
||||
"\n query ProjectPageSettingsCollaboratorsWorkspace($workspaceId: String!) {\n workspace(id: $workspaceId) {\n ...ProjectPageTeamInternals_Workspace\n }\n }\n": typeof types.ProjectPageSettingsCollaboratorsWorkspaceDocument,
|
||||
"\n query ProjectPageSettingsGeneral($projectId: String!) {\n project(id: $projectId) {\n id\n role\n ...ProjectPageSettingsGeneralBlockProjectInfo_Project\n ...ProjectPageSettingsGeneralBlockAccess_Project\n ...ProjectPageSettingsGeneralBlockDiscussions_Project\n ...ProjectPageSettingsGeneralBlockLeave_Project\n ...ProjectPageSettingsGeneralBlockDelete_Project\n ...ProjectPageTeamInternals_Project\n }\n }\n": typeof types.ProjectPageSettingsGeneralDocument,
|
||||
"\n fragment ProjectPageSettingsGeneralBlockAccess_Project on Project {\n id\n visibility\n }\n": typeof types.ProjectPageSettingsGeneralBlockAccess_ProjectFragmentDoc,
|
||||
"\n fragment ProjectPageSettingsGeneralBlockDelete_Project on Project {\n ...ProjectsDeleteDialog_Project\n }\n": typeof types.ProjectPageSettingsGeneralBlockDelete_ProjectFragmentDoc,
|
||||
"\n fragment ProjectPageSettingsGeneralBlockDiscussions_Project on Project {\n id\n visibility\n allowPublicComments\n }\n": typeof types.ProjectPageSettingsGeneralBlockDiscussions_ProjectFragmentDoc,
|
||||
"\n fragment ProjectPageSettingsGeneralBlockLeave_Project on Project {\n id\n name\n role\n team {\n role\n user {\n ...LimitedUserAvatar\n role\n }\n }\n workspace {\n id\n }\n }\n": typeof types.ProjectPageSettingsGeneralBlockLeave_ProjectFragmentDoc,
|
||||
"\n fragment ProjectPageSettingsGeneralBlockProjectInfo_Project on Project {\n id\n role\n name\n description\n }\n": typeof types.ProjectPageSettingsGeneralBlockProjectInfo_ProjectFragmentDoc,
|
||||
"\n fragment ProjectPageTeamDialog on Project {\n id\n name\n role\n allowPublicComments\n visibility\n team {\n id\n role\n user {\n ...LimitedUserAvatar\n role\n }\n }\n invitedTeam {\n id\n title\n inviteId\n role\n user {\n ...LimitedUserAvatar\n role\n }\n }\n ...ProjectsPageTeamDialogManagePermissions_Project\n }\n": typeof types.ProjectPageTeamDialogFragmentDoc,
|
||||
"\n fragment ProjectsPageTeamDialogManagePermissions_Project on Project {\n id\n visibility\n role\n }\n": typeof types.ProjectsPageTeamDialogManagePermissions_ProjectFragmentDoc,
|
||||
"\n fragment ProjectsAddDialog_Workspace on Workspace {\n id\n ...ProjectsWorkspaceSelect_Workspace\n }\n": typeof types.ProjectsAddDialog_WorkspaceFragmentDoc,
|
||||
"\n fragment ProjectsAddDialog_User on User {\n workspaces {\n items {\n ...ProjectsAddDialog_Workspace\n }\n }\n }\n": typeof types.ProjectsAddDialog_UserFragmentDoc,
|
||||
"\n fragment ProjectsDashboard_UserProjectCollection on UserProjectCollection {\n numberOfHidden\n }\n": typeof types.ProjectsDashboard_UserProjectCollectionFragmentDoc,
|
||||
"\n fragment ProjectsDashboardFilledProject on ProjectCollection {\n items {\n ...ProjectDashboardItem\n }\n }\n": typeof types.ProjectsDashboardFilledProjectFragmentDoc,
|
||||
"\n fragment ProjectsDashboardFilledUser on UserProjectCollection {\n items {\n ...ProjectDashboardItem\n }\n }\n": typeof types.ProjectsDashboardFilledUserFragmentDoc,
|
||||
"\n fragment ProjectsDashboardHeaderProjects_User on User {\n projectInvites {\n ...ProjectsInviteBanner\n }\n }\n": typeof types.ProjectsDashboardHeaderProjects_UserFragmentDoc,
|
||||
"\n fragment ProjectsDashboardHeaderWorkspaces_User on User {\n discoverableWorkspaces {\n ...WorkspaceInviteDiscoverableWorkspaceBanner_LimitedWorkspace\n }\n workspaceInvites {\n ...WorkspaceInviteBanner_PendingWorkspaceCollaborator\n }\n }\n": typeof types.ProjectsDashboardHeaderWorkspaces_UserFragmentDoc,
|
||||
"\n fragment ProjectsDeleteDialog_Project on Project {\n id\n name\n role\n models(limit: 0) {\n totalCount\n }\n workspace {\n slug\n id\n }\n versions(limit: 0) {\n totalCount\n }\n }\n": typeof types.ProjectsDeleteDialog_ProjectFragmentDoc,
|
||||
"\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 ProjectsMoveToWorkspaceDialog_Workspace on Workspace {\n id\n role\n name\n logo\n ...WorkspaceHasCustomDataResidency_Workspace\n ...ProjectsWorkspaceSelect_Workspace\n }\n": typeof types.ProjectsMoveToWorkspaceDialog_WorkspaceFragmentDoc,
|
||||
"\n fragment ProjectsMoveToWorkspaceDialog_User on User {\n workspaces {\n items {\n ...ProjectsMoveToWorkspaceDialog_Workspace\n }\n }\n }\n": typeof types.ProjectsMoveToWorkspaceDialog_UserFragmentDoc,
|
||||
"\n fragment ProjectsMoveToWorkspaceDialog_Project on Project {\n id\n name\n modelCount: models(limit: 0) {\n totalCount\n }\n versions(limit: 0) {\n totalCount\n }\n }\n": typeof types.ProjectsMoveToWorkspaceDialog_ProjectFragmentDoc,
|
||||
"\n query ProjectsMoveToWorkspaceDialog {\n activeUser {\n id\n ...ProjectsMoveToWorkspaceDialog_User\n }\n }\n": typeof types.ProjectsMoveToWorkspaceDialogDocument,
|
||||
"\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 SettingsDialog_Workspace on Workspace {\n ...SettingsMenu_Workspace\n id\n slug\n role\n name\n logo\n plan {\n status\n }\n creationState {\n completed\n }\n }\n": typeof types.SettingsDialog_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsDialog_User on User {\n id\n workspaces {\n items {\n ...SettingsDialog_Workspace\n }\n }\n }\n": typeof types.SettingsDialog_UserFragmentDoc,
|
||||
"\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 SettingsSharedDeleteUserDialog_Workspace on Workspace {\n id\n plan {\n status\n name\n }\n subscription {\n currentBillingCycleEnd\n seats {\n guest\n plan\n }\n }\n }\n": typeof types.SettingsSharedDeleteUserDialog_WorkspaceFragmentDoc,
|
||||
"\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 }\n": typeof types.SettingsSharedProjects_ProjectFragmentDoc,
|
||||
"\n fragment SettingsUserProfileChangePassword_User on User {\n id\n email\n }\n": typeof types.SettingsUserProfileChangePassword_UserFragmentDoc,
|
||||
"\n fragment SettingsUserProfileDeleteAccount_User on User {\n id\n email\n }\n": typeof types.SettingsUserProfileDeleteAccount_UserFragmentDoc,
|
||||
"\n fragment SettingsUserProfileDetails_User on User {\n id\n name\n company\n ...UserProfileEditDialogAvatar_User\n }\n": typeof types.SettingsUserProfileDetails_UserFragmentDoc,
|
||||
"\n fragment UserProfileEditDialogAvatar_User on User {\n id\n avatar\n ...ActiveUserAvatar\n }\n": typeof types.UserProfileEditDialogAvatar_UserFragmentDoc,
|
||||
"\n fragment SettingsWorkspaceGeneralDeleteDialog_Workspace on Workspace {\n id\n name\n }\n": typeof types.SettingsWorkspaceGeneralDeleteDialog_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesGeneralEditAvatar_Workspace on Workspace {\n id\n logo\n name\n }\n": typeof types.SettingsWorkspacesGeneralEditAvatar_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesGeneralEditSlugDialog_Workspace on Workspace {\n id\n name\n slug\n }\n": typeof types.SettingsWorkspacesGeneralEditSlugDialog_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesMembersChangeRoleDialog_Workspace on Workspace {\n id\n plan {\n status\n name\n }\n subscription {\n currentBillingCycleEnd\n seats {\n guest\n plan\n }\n }\n }\n": typeof types.SettingsWorkspacesMembersChangeRoleDialog_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesMembersGuestsTable_WorkspaceCollaborator on WorkspaceCollaborator {\n id\n role\n user {\n id\n avatar\n name\n company\n }\n projectRoles {\n role\n project {\n id\n name\n }\n }\n }\n": typeof types.SettingsWorkspacesMembersGuestsTable_WorkspaceCollaboratorFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesMembersGuestsTable_Workspace on Workspace {\n id\n ...SettingsWorkspacesMembersTableHeader_Workspace\n ...SettingsSharedDeleteUserDialog_Workspace\n ...SettingsWorkspacesMembersChangeRoleDialog_Workspace\n team {\n items {\n id\n ...SettingsWorkspacesMembersGuestsTable_WorkspaceCollaborator\n }\n }\n }\n": typeof types.SettingsWorkspacesMembersGuestsTable_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesMembersInvitesTable_PendingWorkspaceCollaborator on PendingWorkspaceCollaborator {\n id\n inviteId\n role\n title\n updatedAt\n user {\n id\n ...LimitedUserAvatar\n }\n invitedBy {\n id\n ...LimitedUserAvatar\n }\n }\n": typeof types.SettingsWorkspacesMembersInvitesTable_PendingWorkspaceCollaboratorFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesMembersInvitesTable_Workspace on Workspace {\n id\n ...SettingsWorkspacesMembersTableHeader_Workspace\n invitedTeam {\n ...SettingsWorkspacesMembersInvitesTable_PendingWorkspaceCollaborator\n }\n }\n": typeof types.SettingsWorkspacesMembersInvitesTable_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesMembersRequestsTable_Workspace on Workspace {\n ...SettingsWorkspacesMembersTableHeader_Workspace\n id\n adminWorkspacesJoinRequests {\n totalCount\n items {\n ...WorkspaceJoinRequestApproveDialog_WorkspaceJoinRequest\n id\n createdAt\n status\n user {\n id\n avatar\n name\n }\n }\n }\n }\n": typeof types.SettingsWorkspacesMembersRequestsTable_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesMembersTable_WorkspaceCollaborator on WorkspaceCollaborator {\n id\n role\n user {\n id\n avatar\n name\n company\n workspaceDomainPolicyCompliant\n }\n }\n": typeof types.SettingsWorkspacesMembersTable_WorkspaceCollaboratorFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesMembersTable_Workspace on Workspace {\n id\n name\n ...SettingsSharedDeleteUserDialog_Workspace\n ...SettingsWorkspacesMembersTableHeader_Workspace\n ...SettingsWorkspacesMembersChangeRoleDialog_Workspace\n team {\n items {\n id\n ...SettingsWorkspacesMembersTable_WorkspaceCollaborator\n }\n }\n }\n": typeof types.SettingsWorkspacesMembersTable_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesMembersTableHeader_Workspace on Workspace {\n id\n role\n ...InviteDialogWorkspace_Workspace\n }\n": typeof types.SettingsWorkspacesMembersTableHeader_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesRegionsSelect_ServerRegionItem on ServerRegionItem {\n id\n key\n name\n description\n }\n": typeof types.SettingsWorkspacesRegionsSelect_ServerRegionItemFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesSecurityDomainRemoveDialog_WorkspaceDomain on WorkspaceDomain {\n id\n domain\n }\n": typeof types.SettingsWorkspacesSecurityDomainRemoveDialog_WorkspaceDomainFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesSecurityDomainRemoveDialog_Workspace on Workspace {\n id\n domains {\n ...SettingsWorkspacesSecurityDomainRemoveDialog_WorkspaceDomain\n }\n }\n": typeof types.SettingsWorkspacesSecurityDomainRemoveDialog_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesSecuritySsoWrapper_Workspace on Workspace {\n id\n role\n slug\n sso {\n provider {\n id\n name\n clientId\n issuerUrl\n }\n }\n hasAccessToSSO: hasAccessToFeature(featureName: oidcSso)\n }\n": typeof types.SettingsWorkspacesSecuritySsoWrapper_WorkspaceFragmentDoc,
|
||||
"\n fragment ModelPageProject on Project {\n id\n createdAt\n name\n visibility\n workspace {\n id\n slug\n name\n }\n }\n": typeof types.ModelPageProjectFragmentDoc,
|
||||
"\n fragment ThreadCommentAttachment on Comment {\n text {\n attachments {\n id\n fileName\n fileType\n fileSize\n }\n }\n }\n": typeof types.ThreadCommentAttachmentFragmentDoc,
|
||||
"\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 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 MoveProjectsDialog_Workspace on Workspace {\n id\n ...ProjectsMoveToWorkspaceDialog_Workspace\n projects {\n items {\n id\n modelCount: models(limit: 0) {\n totalCount\n }\n versions(limit: 0) {\n totalCount\n }\n }\n }\n }\n": typeof types.MoveProjectsDialog_WorkspaceFragmentDoc,
|
||||
"\n fragment MoveProjectsDialog_User on User {\n projects {\n items {\n ...ProjectsMoveToWorkspaceDialog_Project\n role\n workspace {\n id\n }\n }\n }\n }\n": typeof types.MoveProjectsDialog_UserFragmentDoc,
|
||||
"\n fragment WorkspaceProjectList_Workspace on Workspace {\n id\n ...WorkspaceBase_Workspace\n ...WorkspaceTeam_Workspace\n ...WorkspaceSecurity_Workspace\n ...BillingAlert_Workspace\n ...MoveProjectsDialog_Workspace\n ...InviteDialogWorkspace_Workspace\n projects {\n ...WorkspaceProjectList_ProjectCollection\n }\n creationState {\n completed\n state\n }\n readOnly\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 }\n": typeof types.WorkspaceHeader_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 WorkspaceInviteDiscoverableWorkspaceBanner_LimitedWorkspace on LimitedWorkspace {\n id\n name\n slug\n description\n logo\n }\n": typeof types.WorkspaceInviteDiscoverableWorkspaceBanner_LimitedWorkspaceFragmentDoc,
|
||||
"\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,
|
||||
"\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 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 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,
|
||||
"\n mutation CreateOnboardingProject {\n projectMutations {\n createForOnboarding {\n ...ProjectPageProject\n ...ProjectDashboardItem\n }\n }\n }\n ": typeof types.CreateOnboardingProjectDocument,
|
||||
"\n mutation FinishOnboarding($input: OnboardingCompletionInput) {\n activeUserMutations {\n finishOnboarding(input: $input)\n }\n }\n": typeof types.FinishOnboardingDocument,
|
||||
"\n mutation RequestVerificationByEmail($email: String!) {\n requestVerificationByEmail(email: $email)\n }\n": typeof types.RequestVerificationByEmailDocument,
|
||||
"\n query AuthLoginPanel {\n serverInfo {\n authStrategies {\n id\n }\n ...AuthStategiesServerInfoFragment\n }\n }\n": typeof types.AuthLoginPanelDocument,
|
||||
"\n query AuthRegisterPanel($token: String) {\n serverInfo {\n inviteOnly\n authStrategies {\n id\n }\n ...AuthStategiesServerInfoFragment\n ...ServerTermsOfServicePrivacyPolicyFragment\n }\n serverInviteByToken(token: $token) {\n id\n email\n }\n }\n": typeof types.AuthRegisterPanelDocument,
|
||||
"\n query AuthLoginPanelWorkspaceInvite($token: String) {\n workspaceInvite(token: $token) {\n id\n email\n ...AuthWorkspaceInviteHeader_PendingWorkspaceCollaborator\n ...AuthLoginWithEmailBlock_PendingWorkspaceCollaborator\n }\n }\n": typeof types.AuthLoginPanelWorkspaceInviteDocument,
|
||||
"\n query AuthorizableAppMetadata($id: String!) {\n app(id: $id) {\n id\n name\n description\n trustByDefault\n redirectUrl\n scopes {\n name\n description\n }\n author {\n name\n id\n avatar\n }\n }\n }\n": typeof types.AuthorizableAppMetadataDocument,
|
||||
"\n fragment FunctionRunStatusForSummary on AutomateFunctionRun {\n id\n status\n }\n": typeof types.FunctionRunStatusForSummaryFragmentDoc,
|
||||
"\n fragment TriggeredAutomationsStatusSummary on TriggeredAutomationsStatus {\n id\n automationRuns {\n id\n functionRuns {\n id\n ...FunctionRunStatusForSummary\n }\n }\n }\n": typeof types.TriggeredAutomationsStatusSummaryFragmentDoc,
|
||||
"\n fragment AutomationRunDetails on AutomateRun {\n id\n status\n functionRuns {\n ...FunctionRunStatusForSummary\n statusMessage\n }\n trigger {\n ... on VersionCreatedTrigger {\n version {\n id\n }\n model {\n id\n }\n }\n }\n createdAt\n updatedAt\n }\n": typeof types.AutomationRunDetailsFragmentDoc,
|
||||
"\n fragment AutomationsStatusOrderedRuns_AutomationRun on AutomateRun {\n id\n automation {\n id\n name\n }\n functionRuns {\n id\n updatedAt\n }\n }\n": typeof types.AutomationsStatusOrderedRuns_AutomationRunFragmentDoc,
|
||||
"\n fragment SearchAutomateFunctionReleaseItem on AutomateFunctionRelease {\n id\n versionTag\n createdAt\n inputSchema\n }\n": typeof types.SearchAutomateFunctionReleaseItemFragmentDoc,
|
||||
"\n mutation CreateAutomateFunction($input: CreateAutomateFunctionInput!) {\n automateMutations {\n createFunction(input: $input) {\n id\n ...AutomationsFunctionsCard_AutomateFunction\n ...AutomateFunctionCreateDialogDoneStep_AutomateFunction\n }\n }\n }\n": typeof types.CreateAutomateFunctionDocument,
|
||||
"\n mutation UpdateAutomateFunction($input: UpdateAutomateFunctionInput!) {\n automateMutations {\n updateFunction(input: $input) {\n id\n ...AutomateFunctionPage_AutomateFunction\n }\n }\n }\n": typeof types.UpdateAutomateFunctionDocument,
|
||||
"\n query SearchAutomateFunctionReleases(\n $functionId: ID!\n $cursor: String\n $limit: Int\n $filter: AutomateFunctionReleasesFilter\n ) {\n automateFunction(id: $functionId) {\n id\n releases(cursor: $cursor, limit: $limit, filter: $filter) {\n cursor\n totalCount\n items {\n ...SearchAutomateFunctionReleaseItem\n }\n }\n }\n }\n": typeof types.SearchAutomateFunctionReleasesDocument,
|
||||
"\n query FunctionAccessCheck($id: ID!) {\n automateFunction(id: $id) {\n id\n }\n }\n": typeof types.FunctionAccessCheckDocument,
|
||||
"\n query ProjectAutomationCreationPublicKeys(\n $projectId: String!\n $automationId: String!\n ) {\n project(id: $projectId) {\n id\n automation(id: $automationId) {\n id\n creationPublicKeys\n }\n }\n }\n": typeof types.ProjectAutomationCreationPublicKeysDocument,
|
||||
"\n query AutomateFunctionsPagePagination($search: String, $cursor: String) {\n ...AutomateFunctionsPageItems_Query\n }\n": typeof types.AutomateFunctionsPagePaginationDocument,
|
||||
"\n query ActiveUserFunctions {\n activeUser {\n automateFunctions(limit: 2) {\n items {\n id\n ...AutomationsFunctionsCard_AutomateFunction\n }\n }\n }\n }\n": typeof types.ActiveUserFunctionsDocument,
|
||||
"\n fragment BillingActions_Workspace on Workspace {\n id\n name\n invitedTeam(filter: $invitesFilter) {\n id\n }\n plan {\n name\n status\n }\n subscription {\n billingInterval\n }\n team {\n totalCount\n }\n defaultRegion {\n name\n }\n }\n": typeof types.BillingActions_WorkspaceFragmentDoc,
|
||||
"\n mutation BillingCreateCheckoutSession($input: CheckoutSessionInput!) {\n workspaceMutations {\n billing {\n createCheckoutSession(input: $input) {\n url\n id\n }\n }\n }\n }\n": typeof types.BillingCreateCheckoutSessionDocument,
|
||||
"\n mutation BillingUpgradePlan($input: UpgradePlanInput!) {\n workspaceMutations {\n billing {\n upgradePlan(input: $input)\n }\n }\n }\n": typeof types.BillingUpgradePlanDocument,
|
||||
"\n mutation AdminUpdateWorkspacePlan($input: AdminUpdateWorkspacePlanInput!) {\n admin {\n updateWorkspacePlan(input: $input)\n }\n }\n": typeof types.AdminUpdateWorkspacePlanDocument,
|
||||
"\n query MentionsUserSearch($query: String!, $projectId: String) {\n users(input: { query: $query, limit: 5, cursor: null, projectId: $projectId }) {\n items {\n id\n name\n company\n }\n }\n }\n": typeof types.MentionsUserSearchDocument,
|
||||
"\n query UserSearch(\n $query: String!\n $limit: Int\n $cursor: String\n $archived: Boolean\n $workspaceId: String\n ) {\n userSearch(query: $query, limit: $limit, cursor: $cursor, archived: $archived) {\n cursor\n items {\n id\n name\n bio\n company\n avatar\n verified\n role\n workspaceDomainPolicyCompliant(workspaceId: $workspaceId)\n }\n }\n }\n": typeof types.UserSearchDocument,
|
||||
"\n query ServerInfoBlobSizeLimit {\n serverInfo {\n configuration {\n blobSizeLimitBytes\n }\n }\n }\n": typeof types.ServerInfoBlobSizeLimitDocument,
|
||||
"\n query ServerInfoAllScopes {\n serverInfo {\n scopes {\n name\n description\n }\n }\n }\n": typeof types.ServerInfoAllScopesDocument,
|
||||
"\n query ProjectModelsSelectorValues($projectId: String!, $cursor: String) {\n project(id: $projectId) {\n id\n models(limit: 100, cursor: $cursor) {\n cursor\n totalCount\n items {\n ...CommonModelSelectorModel\n }\n }\n }\n }\n": typeof types.ProjectModelsSelectorValuesDocument,
|
||||
"\n query MainServerInfoData {\n serverInfo {\n adminContact\n canonicalUrl\n company\n description\n guestModeEnabled\n inviteOnly\n name\n termsOfService\n version\n automateUrl\n }\n }\n": typeof types.MainServerInfoDataDocument,
|
||||
"\n mutation DashboardRequestToJoinWorkspace($input: WorkspaceRequestToJoinInput!) {\n workspaceMutations {\n requestToJoin(input: $input)\n }\n }\n": typeof types.DashboardRequestToJoinWorkspaceDocument,
|
||||
"\n query DashboardProjectsPageQuery {\n activeUser {\n id\n projects(limit: 3) {\n items {\n ...DashboardProjectCard_Project\n }\n }\n ...ProjectsDashboardHeaderProjects_User\n }\n }\n": typeof types.DashboardProjectsPageQueryDocument,
|
||||
"\n query DashboardProjectsPageWorkspaceQuery {\n activeUser {\n id\n ...ProjectsDashboardHeaderWorkspaces_User\n }\n }\n": typeof types.DashboardProjectsPageWorkspaceQueryDocument,
|
||||
"\n mutation DeleteAccessToken($token: String!) {\n apiTokenRevoke(token: $token)\n }\n": typeof types.DeleteAccessTokenDocument,
|
||||
"\n mutation CreateAccessToken($token: ApiTokenCreateInput!) {\n apiTokenCreate(token: $token)\n }\n": typeof types.CreateAccessTokenDocument,
|
||||
"\n mutation DeleteApplication($appId: String!) {\n appDelete(appId: $appId)\n }\n": typeof types.DeleteApplicationDocument,
|
||||
"\n mutation CreateApplication($app: AppCreateInput!) {\n appCreate(app: $app)\n }\n": typeof types.CreateApplicationDocument,
|
||||
"\n mutation EditApplication($app: AppUpdateInput!) {\n appUpdate(app: $app)\n }\n": typeof types.EditApplicationDocument,
|
||||
"\n mutation RevokeAppAccess($appId: String!) {\n appRevokeAccess(appId: $appId)\n }\n": typeof types.RevokeAppAccessDocument,
|
||||
"\n query DeveloperSettingsAccessTokens {\n activeUser {\n id\n apiTokens {\n id\n name\n lastUsed\n lastChars\n createdAt\n scopes\n }\n }\n }\n": typeof types.DeveloperSettingsAccessTokensDocument,
|
||||
"\n query DeveloperSettingsApplications {\n activeUser {\n createdApps {\n id\n secret\n name\n description\n redirectUrl\n scopes {\n name\n description\n }\n }\n id\n }\n }\n": typeof types.DeveloperSettingsApplicationsDocument,
|
||||
"\n query DeveloperSettingsAuthorizedApps {\n activeUser {\n id\n authorizedApps {\n id\n description\n name\n author {\n id\n name\n avatar\n }\n }\n }\n }\n": typeof types.DeveloperSettingsAuthorizedAppsDocument,
|
||||
"\n query SearchProjects(\n $search: String\n $onlyWithRoles: [String!] = null\n $workspaceId: ID\n ) {\n activeUser {\n projects(\n limit: 10\n filter: {\n search: $search\n onlyWithRoles: $onlyWithRoles\n workspaceId: $workspaceId\n }\n ) {\n totalCount\n items {\n ...FormSelectProjects_Project\n }\n }\n }\n }\n": typeof types.SearchProjectsDocument,
|
||||
"\n query SearchProjectModels($search: String, $projectId: String!) {\n project(id: $projectId) {\n id\n models(limit: 10, filter: { search: $search }) {\n totalCount\n items {\n ...FormSelectModels_Model\n }\n }\n }\n }\n": typeof types.SearchProjectModelsDocument,
|
||||
"\n query ActiveUserGendoLimits {\n activeUser {\n id\n gendoAICredits {\n used\n limit\n resetDate\n }\n }\n }\n": typeof types.ActiveUserGendoLimitsDocument,
|
||||
"\n mutation requestGendoAIRender($input: GendoAIRenderInput!) {\n versionMutations {\n requestGendoAIRender(input: $input)\n }\n }\n": typeof types.RequestGendoAiRenderDocument,
|
||||
"\n query GendoAIRender(\n $gendoAiRenderId: String!\n $versionId: String!\n $projectId: String!\n ) {\n project(id: $projectId) {\n id\n version(id: $versionId) {\n id\n gendoAIRender(id: $gendoAiRenderId) {\n id\n projectId\n modelId\n versionId\n createdAt\n updatedAt\n gendoGenerationId\n status\n prompt\n camera\n responseImage\n user {\n name\n avatar\n id\n }\n }\n }\n }\n }\n": typeof types.GendoAiRenderDocument,
|
||||
"\n query GendoAIRenders($versionId: String!, $projectId: String!) {\n project(id: $projectId) {\n id\n version(id: $versionId) {\n id\n gendoAIRenders {\n totalCount\n items {\n id\n createdAt\n updatedAt\n status\n gendoGenerationId\n prompt\n camera\n }\n }\n }\n }\n }\n": typeof types.GendoAiRendersDocument,
|
||||
"\n subscription ProjectVersionGendoAIRenderCreated($id: String!, $versionId: String!) {\n projectVersionGendoAIRenderCreated(id: $id, versionId: $versionId) {\n id\n createdAt\n updatedAt\n status\n gendoGenerationId\n prompt\n camera\n }\n }\n": typeof types.ProjectVersionGendoAiRenderCreatedDocument,
|
||||
"\n subscription ProjectVersionGendoAIRenderUpdated($id: String!, $versionId: String!) {\n projectVersionGendoAIRenderUpdated(id: $id, versionId: $versionId) {\n id\n projectId\n modelId\n versionId\n createdAt\n updatedAt\n gendoGenerationId\n status\n prompt\n camera\n responseImage\n }\n }\n": typeof types.ProjectVersionGendoAiRenderUpdatedDocument,
|
||||
"\n query InviteUserSearch($input: UsersRetrievalInput!) {\n users(input: $input) {\n items {\n id\n name\n avatar\n }\n }\n }\n": typeof types.InviteUserSearchDocument,
|
||||
"\n mutation CreateNewRegion($input: CreateServerRegionInput!) {\n serverInfoMutations {\n multiRegion {\n create(input: $input) {\n id\n ...SettingsServerRegionsAddEditDialog_ServerRegionItem\n ...SettingsServerRegionsTable_ServerRegionItem\n }\n }\n }\n }\n": typeof types.CreateNewRegionDocument,
|
||||
"\n mutation UpdateRegion($input: UpdateServerRegionInput!) {\n serverInfoMutations {\n multiRegion {\n update(input: $input) {\n id\n ...SettingsServerRegionsAddEditDialog_ServerRegionItem\n ...SettingsServerRegionsTable_ServerRegionItem\n }\n }\n }\n }\n": typeof types.UpdateRegionDocument,
|
||||
"\n query PagesOnboardingDiscoverableWorkspaces_ActiveUser {\n activeUser {\n id\n ...PagesOnboarding_DiscoverableWorkspaces\n }\n }\n": typeof types.PagesOnboardingDiscoverableWorkspaces_ActiveUserDocument,
|
||||
"\n fragment ProjectPageTeamInternals_Project on Project {\n id\n role\n invitedTeam {\n id\n title\n role\n inviteId\n user {\n role\n ...LimitedUserAvatar\n }\n }\n team {\n role\n user {\n id\n role\n ...LimitedUserAvatar\n }\n }\n }\n": typeof types.ProjectPageTeamInternals_ProjectFragmentDoc,
|
||||
"\n fragment ProjectPageTeamInternals_Workspace on Workspace {\n id\n team {\n items {\n id\n role\n user {\n id\n }\n }\n }\n }\n": typeof types.ProjectPageTeamInternals_WorkspaceFragmentDoc,
|
||||
"\n fragment ProjectDashboardItemNoModels on Project {\n id\n name\n createdAt\n updatedAt\n role\n team {\n id\n user {\n id\n name\n avatar\n }\n }\n ...ProjectPageModelsCardProject\n }\n": typeof types.ProjectDashboardItemNoModelsFragmentDoc,
|
||||
"\n fragment ProjectDashboardItem on Project {\n id\n ...ProjectDashboardItemNoModels\n models(limit: 4) {\n totalCount\n items {\n ...ProjectPageLatestItemsModelItem\n }\n }\n workspace {\n id\n slug\n name\n logo\n readOnly\n }\n pendingImportedModels(limit: 4) {\n ...PendingFileUpload\n }\n }\n": typeof types.ProjectDashboardItemFragmentDoc,
|
||||
"\n fragment PendingFileUpload on FileUpload {\n id\n projectId\n modelName\n convertedStatus\n convertedMessage\n uploadDate\n convertedLastUpdate\n fileType\n fileName\n }\n": typeof types.PendingFileUploadFragmentDoc,
|
||||
"\n fragment ProjectPageLatestItemsModelItem on Model {\n id\n name\n displayName\n versionCount: versions(limit: 0) {\n totalCount\n }\n commentThreadCount: commentThreads(limit: 0) {\n totalCount\n }\n pendingImportedVersions(limit: 1) {\n ...PendingFileUpload\n }\n previewUrl\n createdAt\n updatedAt\n ...ProjectPageModelsCardRenameDialog\n ...ProjectPageModelsCardDeleteDialog\n ...ProjectPageModelsActions\n automationsStatus {\n ...AutomateRunsTriggerStatus_TriggeredAutomationsStatus\n }\n }\n": typeof types.ProjectPageLatestItemsModelItemFragmentDoc,
|
||||
"\n fragment ProjectUpdatableMetadata on Project {\n id\n name\n description\n visibility\n allowPublicComments\n }\n": typeof types.ProjectUpdatableMetadataFragmentDoc,
|
||||
"\n fragment ProjectPageLatestItemsModels on Project {\n id\n role\n visibility\n workspace {\n id\n readOnly\n }\n modelCount: models(limit: 0) {\n totalCount\n }\n ...ProjectPageModelsStructureItem_Project\n }\n": typeof types.ProjectPageLatestItemsModelsFragmentDoc,
|
||||
"\n fragment ProjectPageLatestItemsComments on Project {\n id\n commentThreadCount: commentThreads(limit: 0) {\n totalCount\n }\n }\n": typeof types.ProjectPageLatestItemsCommentsFragmentDoc,
|
||||
"\n fragment ProjectPageLatestItemsCommentItem on Comment {\n id\n author {\n ...FormUsersSelectItem\n }\n screenshot\n rawText\n createdAt\n updatedAt\n archived\n repliesCount: replies(limit: 0) {\n totalCount\n }\n replyAuthors(limit: 4) {\n totalCount\n items {\n ...FormUsersSelectItem\n }\n }\n }\n": typeof types.ProjectPageLatestItemsCommentItemFragmentDoc,
|
||||
"\n mutation CreateModel($input: CreateModelInput!) {\n modelMutations {\n create(input: $input) {\n ...ProjectPageLatestItemsModelItem\n }\n }\n }\n": typeof types.CreateModelDocument,
|
||||
"\n mutation CreateProject($input: ProjectCreateInput) {\n projectMutations {\n create(input: $input) {\n ...ProjectPageProject\n ...ProjectDashboardItem\n }\n }\n }\n": typeof types.CreateProjectDocument,
|
||||
"\n mutation CreateWorkspaceProject($input: WorkspaceProjectCreateInput!) {\n workspaceMutations {\n projects {\n create(input: $input) {\n ...ProjectPageProject\n ...ProjectDashboardItem\n }\n }\n }\n }\n": typeof types.CreateWorkspaceProjectDocument,
|
||||
"\n mutation UpdateModel($input: UpdateModelInput!) {\n modelMutations {\n update(input: $input) {\n ...ProjectPageLatestItemsModelItem\n }\n }\n }\n": typeof types.UpdateModelDocument,
|
||||
"\n mutation DeleteModel($input: DeleteModelInput!) {\n modelMutations {\n delete(input: $input)\n }\n }\n": typeof types.DeleteModelDocument,
|
||||
"\n mutation UpdateProjectRole($input: ProjectUpdateRoleInput!) {\n projectMutations {\n updateRole(input: $input) {\n id\n team {\n id\n role\n user {\n ...LimitedUserAvatar\n }\n }\n }\n }\n }\n": typeof types.UpdateProjectRoleDocument,
|
||||
"\n mutation UpdateWorkspaceProjectRole($input: ProjectUpdateRoleInput!) {\n workspaceMutations {\n projects {\n updateRole(input: $input) {\n id\n team {\n id\n role\n }\n }\n }\n }\n }\n": typeof types.UpdateWorkspaceProjectRoleDocument,
|
||||
"\n mutation InviteProjectUser($projectId: ID!, $input: [ProjectInviteCreateInput!]!) {\n projectMutations {\n invites {\n batchCreate(projectId: $projectId, input: $input) {\n ...ProjectPageTeamDialog\n }\n }\n }\n }\n": typeof types.InviteProjectUserDocument,
|
||||
"\n mutation InviteWorkspaceProjectUser(\n $projectId: ID!\n $inputs: [WorkspaceProjectInviteCreateInput!]!\n ) {\n projectMutations {\n invites {\n createForWorkspace(projectId: $projectId, inputs: $inputs) {\n ...ProjectPageTeamDialog\n }\n }\n }\n }\n": typeof types.InviteWorkspaceProjectUserDocument,
|
||||
"\n mutation CancelProjectInvite($projectId: ID!, $inviteId: String!) {\n projectMutations {\n invites {\n cancel(projectId: $projectId, inviteId: $inviteId) {\n ...ProjectPageTeamDialog\n }\n }\n }\n }\n": typeof types.CancelProjectInviteDocument,
|
||||
"\n mutation UpdateProjectMetadata($update: ProjectUpdateInput!) {\n projectMutations {\n update(update: $update) {\n id\n ...ProjectUpdatableMetadata\n }\n }\n }\n": typeof types.UpdateProjectMetadataDocument,
|
||||
"\n mutation DeleteProject($id: String!) {\n projectMutations {\n delete(id: $id)\n }\n }\n": typeof types.DeleteProjectDocument,
|
||||
"\n mutation UseProjectInvite($input: ProjectInviteUseInput!) {\n projectMutations {\n invites {\n use(input: $input)\n }\n }\n }\n": typeof types.UseProjectInviteDocument,
|
||||
"\n mutation LeaveProject($projectId: String!) {\n projectMutations {\n leave(id: $projectId)\n }\n }\n": typeof types.LeaveProjectDocument,
|
||||
"\n mutation DeleteVersions($input: DeleteVersionsInput!) {\n versionMutations {\n delete(input: $input)\n }\n }\n": typeof types.DeleteVersionsDocument,
|
||||
"\n mutation MoveVersions($input: MoveVersionsInput!) {\n versionMutations {\n moveToModel(input: $input) {\n id\n }\n }\n }\n": typeof types.MoveVersionsDocument,
|
||||
"\n mutation UpdateVersion($input: UpdateVersionInput!) {\n versionMutations {\n update(input: $input) {\n id\n message\n }\n }\n }\n": typeof types.UpdateVersionDocument,
|
||||
"\n mutation deleteWebhook($webhook: WebhookDeleteInput!) {\n webhookDelete(webhook: $webhook)\n }\n": typeof types.DeleteWebhookDocument,
|
||||
"\n mutation createWebhook($webhook: WebhookCreateInput!) {\n webhookCreate(webhook: $webhook)\n }\n": typeof types.CreateWebhookDocument,
|
||||
"\n mutation updateWebhook($webhook: WebhookUpdateInput!) {\n webhookUpdate(webhook: $webhook)\n }\n": typeof types.UpdateWebhookDocument,
|
||||
"\n mutation CreateAutomation($projectId: ID!, $input: ProjectAutomationCreateInput!) {\n projectMutations {\n automationMutations(projectId: $projectId) {\n create(input: $input) {\n id\n ...ProjectPageAutomationsRow_Automation\n }\n }\n }\n }\n": typeof types.CreateAutomationDocument,
|
||||
"\n mutation UpdateAutomation($projectId: ID!, $input: ProjectAutomationUpdateInput!) {\n projectMutations {\n automationMutations(projectId: $projectId) {\n update(input: $input) {\n id\n name\n enabled\n }\n }\n }\n }\n": typeof types.UpdateAutomationDocument,
|
||||
"\n mutation CreateAutomationRevision(\n $projectId: ID!\n $input: ProjectAutomationRevisionCreateInput!\n ) {\n projectMutations {\n automationMutations(projectId: $projectId) {\n createRevision(input: $input) {\n id\n }\n }\n }\n }\n": typeof types.CreateAutomationRevisionDocument,
|
||||
"\n mutation TriggerAutomation($projectId: ID!, $automationId: ID!) {\n projectMutations {\n automationMutations(projectId: $projectId) {\n trigger(automationId: $automationId)\n }\n }\n }\n": typeof types.TriggerAutomationDocument,
|
||||
"\n mutation CreateTestAutomation(\n $projectId: ID!\n $input: ProjectTestAutomationCreateInput!\n ) {\n projectMutations {\n automationMutations(projectId: $projectId) {\n createTestAutomation(input: $input) {\n id\n ...ProjectPageAutomationsRow_Automation\n }\n }\n }\n }\n": typeof types.CreateTestAutomationDocument,
|
||||
"\n mutation MoveProjectToWorkspace($workspaceId: String!, $projectId: String!) {\n workspaceMutations {\n projects {\n moveToWorkspace(workspaceId: $workspaceId, projectId: $projectId) {\n id\n workspace {\n id\n projects {\n items {\n id\n }\n }\n ...ProjectsMoveToWorkspaceDialog_Workspace\n ...MoveProjectsDialog_Workspace\n }\n }\n }\n }\n }\n": typeof types.MoveProjectToWorkspaceDocument,
|
||||
"\n query ProjectAccessCheck($id: String!) {\n project(id: $id) {\n id\n visibility\n workspace {\n id\n slug\n }\n }\n }\n": typeof types.ProjectAccessCheckDocument,
|
||||
"\n query ProjectRoleCheck($id: String!) {\n project(id: $id) {\n id\n role\n }\n }\n": typeof types.ProjectRoleCheckDocument,
|
||||
"\n query ProjectsDashboardQuery($filter: UserProjectsFilter, $cursor: String) {\n activeUser {\n id\n projects(filter: $filter, limit: 6, cursor: $cursor) {\n ...ProjectsDashboard_UserProjectCollection\n cursor\n totalCount\n items {\n ...ProjectDashboardItem\n }\n }\n ...ProjectsHiddenProjectWarning_User\n ...ProjectsDashboardHeaderProjects_User\n }\n }\n": typeof types.ProjectsDashboardQueryDocument,
|
||||
"\n query ProjectsDashboardWorkspaceQuery {\n activeUser {\n id\n ...ProjectsDashboardHeaderWorkspaces_User\n }\n }\n": typeof types.ProjectsDashboardWorkspaceQueryDocument,
|
||||
"\n query ProjectPageQuery($id: String!, $token: String) {\n project(id: $id) {\n ...ProjectPageProject\n }\n projectInvite(projectId: $id, token: $token) {\n ...ProjectsInviteBanner\n }\n }\n": typeof types.ProjectPageQueryDocument,
|
||||
"\n query ProjectLatestModels($projectId: String!, $filter: ProjectModelsFilter) {\n project(id: $projectId) {\n id\n models(cursor: null, limit: 16, filter: $filter) {\n totalCount\n cursor\n items {\n ...ProjectPageLatestItemsModelItem\n }\n }\n pendingImportedModels {\n ...PendingFileUpload\n }\n }\n }\n": typeof types.ProjectLatestModelsDocument,
|
||||
"\n query ProjectLatestModelsPagination(\n $projectId: String!\n $filter: ProjectModelsFilter\n $cursor: String = null\n ) {\n project(id: $projectId) {\n id\n models(cursor: $cursor, limit: 16, filter: $filter) {\n totalCount\n cursor\n items {\n ...ProjectPageLatestItemsModelItem\n }\n }\n }\n }\n": typeof types.ProjectLatestModelsPaginationDocument,
|
||||
"\n query ProjectModelsTreeTopLevel(\n $projectId: String!\n $filter: ProjectModelsTreeFilter\n ) {\n project(id: $projectId) {\n id\n modelsTree(cursor: null, limit: 8, filter: $filter) {\n totalCount\n cursor\n items {\n ...SingleLevelModelTreeItem\n }\n }\n pendingImportedModels {\n ...PendingFileUpload\n }\n }\n }\n": typeof types.ProjectModelsTreeTopLevelDocument,
|
||||
"\n query ProjectModelsTreeTopLevelPagination(\n $projectId: String!\n $filter: ProjectModelsTreeFilter\n $cursor: String = null\n ) {\n project(id: $projectId) {\n id\n modelsTree(cursor: $cursor, limit: 8, filter: $filter) {\n totalCount\n cursor\n items {\n ...SingleLevelModelTreeItem\n }\n }\n }\n }\n": typeof types.ProjectModelsTreeTopLevelPaginationDocument,
|
||||
"\n query ProjectModelChildrenTree($projectId: String!, $parentName: String!) {\n project(id: $projectId) {\n id\n modelChildrenTree(fullName: $parentName) {\n ...SingleLevelModelTreeItem\n }\n }\n }\n": typeof types.ProjectModelChildrenTreeDocument,
|
||||
"\n query ProjectLatestCommentThreads(\n $projectId: String!\n $cursor: String = null\n $filter: ProjectCommentsFilter = null\n ) {\n project(id: $projectId) {\n id\n commentThreads(cursor: $cursor, limit: 8, filter: $filter) {\n totalCount\n cursor\n items {\n ...ProjectPageLatestItemsCommentItem\n }\n }\n }\n }\n": typeof types.ProjectLatestCommentThreadsDocument,
|
||||
"\n query ProjectInvite($projectId: String!, $token: String) {\n projectInvite(projectId: $projectId, token: $token) {\n ...ProjectsInviteBanner\n }\n }\n": typeof types.ProjectInviteDocument,
|
||||
"\n query ProjectModelCheck($projectId: String!, $modelId: String!) {\n project(id: $projectId) {\n visibility\n model(id: $modelId) {\n id\n }\n }\n }\n": typeof types.ProjectModelCheckDocument,
|
||||
"\n query ProjectModelPage(\n $projectId: String!\n $modelId: String!\n $versionsCursor: String\n ) {\n project(id: $projectId) {\n id\n ...ProjectModelPageHeaderProject\n ...ProjectModelPageVersionsProject\n }\n }\n": typeof types.ProjectModelPageDocument,
|
||||
"\n query ProjectModelVersions(\n $projectId: String!\n $modelId: String!\n $versionsCursor: String\n ) {\n project(id: $projectId) {\n id\n ...ProjectModelPageVersionsPagination\n }\n }\n": typeof types.ProjectModelVersionsDocument,
|
||||
"\n query ProjectModelsPage($projectId: String!) {\n project(id: $projectId) {\n id\n ...ProjectModelsPageHeader_Project\n ...ProjectModelsPageResults_Project\n }\n }\n": typeof types.ProjectModelsPageDocument,
|
||||
"\n query ProjectDiscussionsPage($projectId: String!) {\n project(id: $projectId) {\n id\n ...ProjectDiscussionsPageHeader_Project\n ...ProjectDiscussionsPageResults_Project\n }\n }\n": typeof types.ProjectDiscussionsPageDocument,
|
||||
"\n query ProjectAutomationsTab($projectId: String!) {\n project(id: $projectId) {\n id\n role\n models(limit: 1) {\n items {\n id\n }\n }\n automations(filter: null, cursor: null, limit: 5) {\n totalCount\n items {\n id\n ...ProjectPageAutomationsRow_Automation\n }\n cursor\n }\n workspace {\n id\n automateFunctions(limit: 0) {\n totalCount\n }\n ...AutomateFunctionCreateDialog_Workspace\n }\n ...FormSelectProjects_Project\n }\n ...AutomateFunctionsPageHeader_Query\n }\n": typeof types.ProjectAutomationsTabDocument,
|
||||
"\n query ProjectAutomationsTabAutomationsPagination(\n $projectId: String!\n $search: String = null\n $cursor: String = null\n ) {\n project(id: $projectId) {\n id\n automations(filter: $search, cursor: $cursor, limit: 5) {\n totalCount\n cursor\n items {\n id\n ...ProjectPageAutomationsRow_Automation\n }\n }\n }\n }\n": typeof types.ProjectAutomationsTabAutomationsPaginationDocument,
|
||||
"\n query ProjectAutomationPage($projectId: String!, $automationId: String!) {\n project(id: $projectId) {\n id\n ...ProjectPageAutomationPage_Project\n automation(id: $automationId) {\n id\n ...ProjectPageAutomationPage_Automation\n }\n }\n }\n": typeof types.ProjectAutomationPageDocument,
|
||||
"\n query ProjectAutomationPagePaginatedRuns(\n $projectId: String!\n $automationId: String!\n $cursor: String = null\n ) {\n project(id: $projectId) {\n id\n automation(id: $automationId) {\n id\n runs(cursor: $cursor, limit: 10) {\n totalCount\n cursor\n items {\n id\n ...AutomationRunDetails\n }\n }\n }\n }\n }\n": typeof types.ProjectAutomationPagePaginatedRunsDocument,
|
||||
"\n query ProjectAutomationAccessCheck($projectId: String!) {\n project(id: $projectId) {\n id\n automations(limit: 0) {\n totalCount\n }\n }\n }\n": typeof types.ProjectAutomationAccessCheckDocument,
|
||||
"\n query ProjectWebhooks($projectId: String!) {\n project(id: $projectId) {\n id\n name\n webhooks {\n items {\n streamId\n triggers\n enabled\n url\n id\n description\n history(limit: 5) {\n items {\n status\n statusInfo\n }\n }\n }\n totalCount\n }\n }\n }\n": typeof types.ProjectWebhooksDocument,
|
||||
"\n query ProjectBlobInfo($blobId: String!, $projectId: String!) {\n project(id: $projectId) {\n id\n blob(id: $blobId) {\n id\n fileName\n fileType\n fileSize\n createdAt\n }\n }\n }\n": typeof types.ProjectBlobInfoDocument,
|
||||
"\n query ProjectWorkspaceSelect {\n activeUser {\n id\n ...ProjectsAddDialog_User\n }\n }\n": typeof types.ProjectWorkspaceSelectDocument,
|
||||
"\n subscription OnProjectUpdated($id: String!) {\n projectUpdated(id: $id) {\n id\n type\n project {\n ...ProjectPageProject\n ...ProjectDashboardItemNoModels\n }\n }\n }\n": typeof types.OnProjectUpdatedDocument,
|
||||
"\n subscription OnProjectModelsUpdate($id: String!) {\n projectModelsUpdated(id: $id) {\n id\n type\n model {\n id\n versions(limit: 1) {\n items {\n id\n referencedObject\n }\n }\n ...ProjectPageLatestItemsModelItem\n }\n }\n }\n": typeof types.OnProjectModelsUpdateDocument,
|
||||
"\n subscription OnProjectVersionsUpdate($id: String!) {\n projectVersionsUpdated(id: $id) {\n id\n modelId\n type\n version {\n id\n ...ViewerModelVersionCardItem\n ...ProjectModelPageVersionsCardVersion\n model {\n id\n ...ProjectPageLatestItemsModelItem\n }\n }\n }\n }\n": typeof types.OnProjectVersionsUpdateDocument,
|
||||
"\n subscription OnProjectVersionsPreviewGenerated($id: String!) {\n projectVersionsPreviewGenerated(id: $id) {\n projectId\n objectId\n versionId\n }\n }\n": typeof types.OnProjectVersionsPreviewGeneratedDocument,
|
||||
"\n subscription OnProjectPendingModelsUpdated($id: String!) {\n projectPendingModelsUpdated(id: $id) {\n id\n type\n model {\n ...PendingFileUpload\n model {\n ...ProjectPageLatestItemsModelItem\n }\n }\n }\n }\n": typeof types.OnProjectPendingModelsUpdatedDocument,
|
||||
"\n subscription OnProjectPendingVersionsUpdated($id: String!) {\n projectPendingVersionsUpdated(id: $id) {\n id\n type\n version {\n ...PendingFileUpload\n model {\n ...ProjectPageLatestItemsModelItem\n }\n }\n }\n }\n": typeof types.OnProjectPendingVersionsUpdatedDocument,
|
||||
"\n subscription OnProjectTriggeredAutomationsStatusUpdated($id: String!) {\n projectTriggeredAutomationsStatusUpdated(projectId: $id) {\n type\n version {\n id\n automationsStatus {\n automationRuns {\n ...AutomateViewerPanel_AutomateRun\n }\n ...TriggeredAutomationsStatusSummary\n ...AutomateRunsTriggerStatusDialog_TriggeredAutomationsStatus\n }\n }\n model {\n id\n }\n run {\n id\n automationId\n ...AutomationRunDetails\n }\n }\n }\n": typeof types.OnProjectTriggeredAutomationsStatusUpdatedDocument,
|
||||
"\n subscription OnProjectAutomationsUpdated($id: String!) {\n projectAutomationsUpdated(projectId: $id) {\n type\n automationId\n automation {\n id\n ...ProjectPageAutomationPage_Automation\n ...ProjectPageAutomationsRow_Automation\n }\n }\n }\n": typeof types.OnProjectAutomationsUpdatedDocument,
|
||||
"\n mutation ServerInfoUpdate($info: ServerInfoUpdateInput!) {\n serverInfoUpdate(info: $info)\n }\n": typeof types.ServerInfoUpdateDocument,
|
||||
"\n mutation AdminPanelDeleteUser($userConfirmation: UserDeleteInput!) {\n adminDeleteUser(userConfirmation: $userConfirmation)\n }\n": typeof types.AdminPanelDeleteUserDocument,
|
||||
"\n mutation AdminPanelDeleteProject($ids: [String!]!) {\n projectMutations {\n batchDelete(ids: $ids)\n }\n }\n": typeof types.AdminPanelDeleteProjectDocument,
|
||||
"\n mutation AdminPanelResendInvite($inviteId: String!) {\n inviteResend(inviteId: $inviteId)\n }\n": typeof types.AdminPanelResendInviteDocument,
|
||||
"\n mutation AdminPanelDeleteInvite($inviteId: String!) {\n inviteDelete(inviteId: $inviteId)\n }\n": typeof types.AdminPanelDeleteInviteDocument,
|
||||
"\n mutation AdminChangeUseRole($userRoleInput: UserRoleInput!) {\n userRoleChange(userRoleInput: $userRoleInput)\n }\n": typeof types.AdminChangeUseRoleDocument,
|
||||
"\n query ServerManagementDataPage {\n admin {\n userList {\n totalCount\n }\n projectList {\n totalCount\n }\n inviteList {\n totalCount\n }\n }\n serverInfo {\n name\n version\n }\n }\n": typeof types.ServerManagementDataPageDocument,
|
||||
"\n query ServerSettingsDialogData {\n serverInfo {\n name\n description\n adminContact\n company\n termsOfService\n inviteOnly\n guestModeEnabled\n }\n }\n": typeof types.ServerSettingsDialogDataDocument,
|
||||
"\n query AdminPanelUsersList($limit: Int!, $cursor: String, $query: String) {\n admin {\n userList(limit: $limit, cursor: $cursor, query: $query) {\n totalCount\n cursor\n items {\n id\n email\n avatar\n name\n role\n verified\n company\n }\n }\n }\n }\n": typeof types.AdminPanelUsersListDocument,
|
||||
"\n query AdminPanelProjectsList(\n $query: String\n $orderBy: String\n $limit: Int!\n $visibility: String\n $cursor: String\n ) {\n admin {\n projectList(\n query: $query\n orderBy: $orderBy\n limit: $limit\n visibility: $visibility\n cursor: $cursor\n ) {\n cursor\n ...SettingsServerProjects_ProjectCollection\n }\n }\n }\n": typeof types.AdminPanelProjectsListDocument,
|
||||
"\n query AdminPanelInvitesList($limit: Int!, $cursor: String, $query: String) {\n admin {\n inviteList(limit: $limit, cursor: $cursor, query: $query) {\n cursor\n items {\n email\n id\n invitedBy {\n id\n name\n }\n }\n totalCount\n }\n }\n }\n": typeof types.AdminPanelInvitesListDocument,
|
||||
"\n query UsersCount {\n admin {\n userList {\n totalCount\n }\n }\n }\n": typeof types.UsersCountDocument,
|
||||
"\n query InvitesCount {\n admin {\n inviteList {\n totalCount\n }\n }\n }\n": typeof types.InvitesCountDocument,
|
||||
"\n mutation InviteServerUser($input: [ServerInviteCreateInput!]!) {\n serverInviteBatchCreate(input: $input)\n }\n": typeof types.InviteServerUserDocument,
|
||||
"\n fragment AddDomainWorkspace on Workspace {\n slug\n }\n ": typeof types.AddDomainWorkspaceFragmentDoc,
|
||||
"\n fragment SettingsMenu_Workspace on Workspace {\n id\n sso {\n provider {\n id\n }\n session {\n validUntil\n }\n }\n }\n": typeof types.SettingsMenu_WorkspaceFragmentDoc,
|
||||
"\n mutation SettingsUpdateWorkspace($input: WorkspaceUpdateInput!) {\n workspaceMutations {\n update(input: $input) {\n ...SettingsWorkspacesGeneral_Workspace\n }\n }\n }\n": typeof types.SettingsUpdateWorkspaceDocument,
|
||||
"\n mutation SettingsCreateUserEmail($input: CreateUserEmailInput!) {\n activeUserMutations {\n emailMutations {\n create(input: $input) {\n id\n emails {\n ...EmailFields\n }\n }\n }\n }\n }\n": typeof types.SettingsCreateUserEmailDocument,
|
||||
"\n mutation SettingsDeleteUserEmail($input: DeleteUserEmailInput!) {\n activeUserMutations {\n emailMutations {\n delete(input: $input) {\n id\n emails {\n ...EmailFields\n }\n }\n }\n }\n }\n": typeof types.SettingsDeleteUserEmailDocument,
|
||||
"\n mutation SettingsSetPrimaryUserEmail($input: SetPrimaryUserEmailInput!) {\n activeUserMutations {\n emailMutations {\n setPrimary(input: $input) {\n id\n emails {\n ...EmailFields\n }\n }\n }\n }\n }\n": typeof types.SettingsSetPrimaryUserEmailDocument,
|
||||
"\n mutation SettingsNewEmailVerification($input: EmailVerificationRequestInput!) {\n activeUserMutations {\n emailMutations {\n requestNewEmailVerification(input: $input)\n }\n }\n }\n": typeof types.SettingsNewEmailVerificationDocument,
|
||||
"\n mutation SettingsUpdateWorkspaceSecurity($input: WorkspaceUpdateInput!) {\n workspaceMutations {\n update(input: $input) {\n id\n domainBasedMembershipProtectionEnabled\n discoverabilityEnabled\n }\n }\n }\n": typeof types.SettingsUpdateWorkspaceSecurityDocument,
|
||||
"\n mutation SettingsDeleteWorkspace($workspaceId: String!) {\n workspaceMutations {\n delete(workspaceId: $workspaceId)\n }\n }\n": typeof types.SettingsDeleteWorkspaceDocument,
|
||||
"\n mutation SettingsResendWorkspaceInvite($input: WorkspaceInviteResendInput!) {\n workspaceMutations {\n invites {\n resend(input: $input)\n }\n }\n }\n": typeof types.SettingsResendWorkspaceInviteDocument,
|
||||
"\n mutation SettingsCancelWorkspaceInvite($workspaceId: String!, $inviteId: String!) {\n workspaceMutations {\n invites {\n cancel(workspaceId: $workspaceId, inviteId: $inviteId) {\n id\n }\n }\n }\n }\n": typeof types.SettingsCancelWorkspaceInviteDocument,
|
||||
"\n mutation AddWorkspaceDomain($input: AddDomainToWorkspaceInput!) {\n workspaceMutations {\n addDomain(input: $input) {\n ...SettingsWorkspacesSecurity_Workspace\n }\n }\n }\n": typeof types.AddWorkspaceDomainDocument,
|
||||
"\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 ...SettingsDialog_User\n }\n }\n": typeof types.SettingsSidebarDocument,
|
||||
"\n query SettingsSidebarAutomateFunctions {\n activeUser {\n ...Sidebar_User\n }\n }\n": typeof types.SettingsSidebarAutomateFunctionsDocument,
|
||||
"\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 ...SettingsWorkspacesBilling_Workspace\n }\n }\n": typeof types.SettingsWorkspaceBillingDocument,
|
||||
"\n query SettingsWorkspaceBillingCustomerPortal($workspaceId: String!) {\n workspace(id: $workspaceId) {\n customerPortalUrl\n }\n }\n": typeof types.SettingsWorkspaceBillingCustomerPortalDocument,
|
||||
"\n query SettingsWorkspaceRegions($slug: String!) {\n workspaceBySlug(slug: $slug) {\n id\n ...SettingsWorkspacesRegions_Workspace\n }\n serverInfo {\n ...SettingsWorkspacesRegions_ServerInfo\n }\n }\n": typeof types.SettingsWorkspaceRegionsDocument,
|
||||
"\n query SettingsWorkspacesMembers($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesMembers_Workspace\n }\n }\n": typeof types.SettingsWorkspacesMembersDocument,
|
||||
"\n query SettingsWorkspacesMembersTable($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesMembersTable_Workspace\n }\n }\n": typeof types.SettingsWorkspacesMembersTableDocument,
|
||||
"\n query SettingsWorkspacesMembersGuests($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesMembersGuestsTable_Workspace\n }\n }\n": typeof types.SettingsWorkspacesMembersGuestsDocument,
|
||||
"\n query SettingsWorkspacesMembersInvites($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesMembersInvitesTable_Workspace\n }\n }\n": typeof types.SettingsWorkspacesMembersInvitesDocument,
|
||||
"\n query SettingsWorkspacesMembersRequests($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesMembersRequestsTable_Workspace\n }\n }\n": typeof types.SettingsWorkspacesMembersRequestsDocument,
|
||||
"\n query SettingsWorkspacesMembersSearch($slug: String!, $filter: WorkspaceTeamFilter) {\n workspaceBySlug(slug: $slug) {\n id\n team(filter: $filter) {\n items {\n id\n ...SettingsWorkspacesMembersTable_WorkspaceCollaborator\n }\n }\n }\n }\n": typeof types.SettingsWorkspacesMembersSearchDocument,
|
||||
"\n query SettingsWorkspacesInvitesSearch(\n $slug: String!\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n ) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesMembersInvitesTable_Workspace\n }\n }\n": typeof types.SettingsWorkspacesInvitesSearchDocument,
|
||||
"\n query SettingsWorkspacesProjects(\n $slug: String!\n $limit: Int!\n $cursor: String\n $filter: WorkspaceProjectsFilter\n ) {\n workspaceBySlug(slug: $slug) {\n id\n slug\n readOnly\n projects(limit: $limit, cursor: $cursor, filter: $filter) {\n cursor\n ...SettingsWorkspacesProjects_ProjectCollection\n }\n }\n }\n": typeof types.SettingsWorkspacesProjectsDocument,
|
||||
"\n query SettingsWorkspaceSecurity($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesSecurity_Workspace\n }\n activeUser {\n ...SettingsWorkspacesSecurity_User\n }\n }\n": typeof types.SettingsWorkspaceSecurityDocument,
|
||||
"\n fragment AppAuthorAvatar on AppAuthor {\n id\n name\n avatar\n }\n": typeof types.AppAuthorAvatarFragmentDoc,
|
||||
"\n fragment LimitedUserAvatar on LimitedUser {\n id\n name\n avatar\n }\n": typeof types.LimitedUserAvatarFragmentDoc,
|
||||
"\n fragment ActiveUserAvatar on User {\n id\n name\n avatar\n }\n": typeof types.ActiveUserAvatarFragmentDoc,
|
||||
"\n subscription OnUserProjectsUpdate {\n userProjectsUpdated {\n type\n id\n project {\n ...ProjectDashboardItem\n }\n }\n }\n ": typeof types.OnUserProjectsUpdateDocument,
|
||||
"\n mutation UpdateUser($input: UserUpdateInput!) {\n activeUserMutations {\n update(user: $input) {\n id\n name\n bio\n company\n avatar\n }\n }\n }\n": typeof types.UpdateUserDocument,
|
||||
"\n mutation UpdateNotificationPreferences($input: JSONObject!) {\n userNotificationPreferencesUpdate(preferences: $input)\n }\n": typeof types.UpdateNotificationPreferencesDocument,
|
||||
"\n mutation DeleteAccount($input: UserDeleteInput!) {\n userDelete(userConfirmation: $input)\n }\n": typeof types.DeleteAccountDocument,
|
||||
"\n mutation verifyEmail($input: VerifyUserEmailInput!) {\n activeUserMutations {\n emailMutations {\n verify(input: $input)\n }\n }\n }\n": typeof types.VerifyEmailDocument,
|
||||
"\n fragment EmailFields on UserEmail {\n id\n email\n verified\n primary\n userId\n }\n": typeof types.EmailFieldsFragmentDoc,
|
||||
"\n query UserEmails {\n activeUser {\n id\n emails {\n ...EmailFields\n }\n hasPendingVerification\n }\n }\n": typeof types.UserEmailsDocument,
|
||||
"\n fragment ViewerCommentBubblesData on Comment {\n id\n viewedAt\n viewerState\n }\n": typeof types.ViewerCommentBubblesDataFragmentDoc,
|
||||
"\n fragment ViewerCommentThread on Comment {\n ...ViewerCommentsListItem\n ...ViewerCommentBubblesData\n ...ViewerCommentsReplyItem\n }\n": typeof types.ViewerCommentThreadFragmentDoc,
|
||||
"\n fragment ViewerCommentsReplyItem on Comment {\n id\n archived\n rawText\n text {\n doc\n }\n author {\n ...LimitedUserAvatar\n }\n createdAt\n ...ThreadCommentAttachment\n }\n": typeof types.ViewerCommentsReplyItemFragmentDoc,
|
||||
"\n mutation BroadcastViewerUserActivity(\n $projectId: String!\n $resourceIdString: String!\n $message: ViewerUserActivityMessageInput!\n ) {\n broadcastViewerUserActivity(\n projectId: $projectId\n resourceIdString: $resourceIdString\n message: $message\n )\n }\n": typeof types.BroadcastViewerUserActivityDocument,
|
||||
"\n mutation MarkCommentViewed($input: MarkCommentViewedInput!) {\n commentMutations {\n markViewed(input: $input)\n }\n }\n": typeof types.MarkCommentViewedDocument,
|
||||
"\n mutation CreateCommentThread($input: CreateCommentInput!) {\n commentMutations {\n create(input: $input) {\n ...ViewerCommentThread\n }\n }\n }\n": typeof types.CreateCommentThreadDocument,
|
||||
"\n mutation CreateCommentReply($input: CreateCommentReplyInput!) {\n commentMutations {\n reply(input: $input) {\n ...ViewerCommentsReplyItem\n }\n }\n }\n": typeof types.CreateCommentReplyDocument,
|
||||
"\n mutation ArchiveComment($input: ArchiveCommentInput!) {\n commentMutations {\n archive(input: $input)\n }\n }\n": typeof types.ArchiveCommentDocument,
|
||||
"\n query ProjectViewerResources($projectId: String!, $resourceUrlString: String!) {\n project(id: $projectId) {\n id\n viewerResources(resourceIdString: $resourceUrlString) {\n identifier\n items {\n modelId\n versionId\n objectId\n }\n }\n }\n }\n": typeof types.ProjectViewerResourcesDocument,
|
||||
"\n query ViewerLoadedResources(\n $projectId: String!\n $modelIds: [String!]!\n $versionIds: [String!]\n ) {\n project(id: $projectId) {\n id\n role\n allowPublicComments\n models(filter: { ids: $modelIds }) {\n totalCount\n items {\n id\n name\n updatedAt\n loadedVersion: versions(\n filter: { priorityIds: $versionIds, priorityIdsOnly: true }\n ) {\n items {\n ...ViewerModelVersionCardItem\n automationsStatus {\n id\n automationRuns {\n ...AutomateViewerPanel_AutomateRun\n }\n }\n }\n }\n versions(limit: 5) {\n totalCount\n cursor\n items {\n ...ViewerModelVersionCardItem\n }\n }\n }\n }\n ...ProjectPageLatestItemsModels\n ...ModelPageProject\n ...HeaderNavShare_Project\n }\n }\n": typeof types.ViewerLoadedResourcesDocument,
|
||||
"\n query ViewerModelVersions(\n $projectId: String!\n $modelId: String!\n $versionsCursor: String\n ) {\n project(id: $projectId) {\n id\n role\n model(id: $modelId) {\n id\n versions(cursor: $versionsCursor, limit: 5) {\n totalCount\n cursor\n items {\n ...ViewerModelVersionCardItem\n }\n }\n }\n }\n }\n": typeof types.ViewerModelVersionsDocument,
|
||||
"\n query ViewerDiffVersions(\n $projectId: String!\n $modelId: String!\n $versionAId: String!\n $versionBId: String!\n ) {\n project(id: $projectId) {\n id\n model(id: $modelId) {\n id\n versionA: version(id: $versionAId) {\n ...ViewerModelVersionCardItem\n }\n versionB: version(id: $versionBId) {\n ...ViewerModelVersionCardItem\n }\n }\n }\n }\n": typeof types.ViewerDiffVersionsDocument,
|
||||
"\n query ViewerLoadedThreads(\n $projectId: String!\n $filter: ProjectCommentsFilter!\n $cursor: String\n $limit: Int\n ) {\n project(id: $projectId) {\n id\n commentThreads(filter: $filter, cursor: $cursor, limit: $limit) {\n totalCount\n totalArchivedCount\n items {\n ...ViewerCommentThread\n ...LinkableComment\n }\n }\n }\n }\n": typeof types.ViewerLoadedThreadsDocument,
|
||||
"\n query ViewerRawProjectObject($projectId: String!, $objectId: String!) {\n project(id: $projectId) {\n id\n object(id: $objectId) {\n id\n data\n }\n }\n }\n": typeof types.ViewerRawProjectObjectDocument,
|
||||
"\n subscription OnViewerUserActivityBroadcasted(\n $target: ViewerUpdateTrackingTarget!\n $sessionId: String!\n ) {\n viewerUserActivityBroadcasted(target: $target, sessionId: $sessionId) {\n userName\n userId\n user {\n ...LimitedUserAvatar\n }\n state\n status\n sessionId\n }\n }\n": typeof types.OnViewerUserActivityBroadcastedDocument,
|
||||
"\n subscription OnViewerCommentsUpdated($target: ViewerUpdateTrackingTarget!) {\n projectCommentsUpdated(target: $target) {\n id\n type\n comment {\n id\n parent {\n id\n }\n ...ViewerCommentThread\n }\n }\n }\n": typeof types.OnViewerCommentsUpdatedDocument,
|
||||
"\n fragment LinkableComment on Comment {\n id\n viewerResources {\n modelId\n versionId\n objectId\n }\n }\n": typeof types.LinkableCommentFragmentDoc,
|
||||
"\n fragment UseWorkspaceInviteManager_PendingWorkspaceCollaborator on PendingWorkspaceCollaborator {\n id\n token\n workspaceId\n workspaceSlug\n user {\n id\n }\n }\n": typeof types.UseWorkspaceInviteManager_PendingWorkspaceCollaboratorFragmentDoc,
|
||||
"\n subscription OnWorkspaceProjectsUpdate($slug: String!) {\n workspaceProjectsUpdated(workspaceId: null, workspaceSlug: $slug) {\n projectId\n workspaceId\n type\n project {\n ...ProjectDashboardItem\n }\n }\n }\n ": typeof types.OnWorkspaceProjectsUpdateDocument,
|
||||
"\n fragment WorkspaceHasCustomDataResidency_Workspace on Workspace {\n id\n defaultRegion {\n id\n name\n }\n }\n": typeof types.WorkspaceHasCustomDataResidency_WorkspaceFragmentDoc,
|
||||
"\n query CheckProjectWorkspaceDataResidency($projectId: String!) {\n project(id: $projectId) {\n id\n workspace {\n ...WorkspaceHasCustomDataResidency_Workspace\n }\n }\n }\n": typeof types.CheckProjectWorkspaceDataResidencyDocument,
|
||||
"\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 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 {\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 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 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,
|
||||
"\n mutation CreateWorkspace($input: WorkspaceCreateInput!) {\n workspaceMutations {\n create(input: $input) {\n id\n ...SettingsDialog_Workspace\n }\n }\n }\n": typeof types.CreateWorkspaceDocument,
|
||||
"\n mutation ProcessWorkspaceInvite($input: WorkspaceInviteUseInput!) {\n workspaceMutations {\n invites {\n use(input: $input)\n }\n }\n }\n": typeof types.ProcessWorkspaceInviteDocument,
|
||||
"\n mutation SetDefaultWorkspaceRegion($workspaceId: String!, $regionKey: String!) {\n workspaceMutations {\n setDefaultRegion(workspaceId: $workspaceId, regionKey: $regionKey) {\n id\n defaultRegion {\n id\n ...SettingsWorkspacesRegionsSelect_ServerRegionItem\n }\n }\n }\n }\n": typeof types.SetDefaultWorkspaceRegionDocument,
|
||||
"\n mutation DeleteWorkspaceSsoProvider($workspaceId: String!) {\n workspaceMutations {\n deleteSsoProvider(workspaceId: $workspaceId)\n }\n }\n": typeof types.DeleteWorkspaceSsoProviderDocument,
|
||||
"\n mutation SetWorkspaceCreationState($input: WorkspaceCreationStateInput!) {\n workspaceMutations {\n updateCreationState(input: $input)\n }\n }\n": typeof types.SetWorkspaceCreationStateDocument,
|
||||
"\n mutation WorkspaceUpdateDomainProtectionMutation($input: WorkspaceUpdateInput!) {\n workspaceMutations {\n update(input: $input) {\n id\n domainBasedMembershipProtectionEnabled\n }\n }\n }\n": typeof types.WorkspaceUpdateDomainProtectionMutationDocument,
|
||||
"\n mutation WorkspaceUpdateDiscoverabilityMutation($input: WorkspaceUpdateInput!) {\n workspaceMutations {\n update(input: $input) {\n id\n discoverabilityEnabled\n }\n }\n }\n": typeof types.WorkspaceUpdateDiscoverabilityMutationDocument,
|
||||
"\n mutation ApproveWorkspaceJoinRequest($input: ApproveWorkspaceJoinRequestInput!) {\n workspaceJoinRequestMutations {\n approve(input: $input)\n }\n }\n": typeof types.ApproveWorkspaceJoinRequestDocument,
|
||||
"\n mutation DenyWorkspaceJoinRequest($input: DenyWorkspaceJoinRequestInput!) {\n workspaceJoinRequestMutations {\n deny(input: $input)\n }\n }\n": typeof types.DenyWorkspaceJoinRequestDocument,
|
||||
"\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 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 MoveProjectsDialog {\n activeUser {\n ...MoveProjectsDialog_User\n }\n }\n": typeof types.MoveProjectsDialogDocument,
|
||||
"\n query ValidateWorkspaceSlug($slug: String!) {\n validateWorkspaceSlug(slug: $slug)\n }\n": typeof types.ValidateWorkspaceSlugDocument,
|
||||
"\n query WorkspaceSsoByEmail($email: String!) {\n workspaceSsoByEmail(email: $email) {\n ...AuthSsoLogin_Workspace\n }\n }\n": typeof types.WorkspaceSsoByEmailDocument,
|
||||
"\n query WorkspaceSsoCheck($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...WorkspaceSsoStatus_Workspace\n }\n activeUser {\n ...WorkspaceSsoStatus_User\n }\n }\n": typeof types.WorkspaceSsoCheckDocument,
|
||||
"\n query WorkspaceWizard($workspaceId: String!) {\n workspace(id: $workspaceId) {\n id\n ...WorkspaceWizard_Workspace\n }\n }\n": typeof types.WorkspaceWizardDocument,
|
||||
"\n query WorkspaceWizardRegion {\n serverInfo {\n ...WorkspaceWizardStepRegion_ServerInfo\n }\n }\n": typeof types.WorkspaceWizardRegionDocument,
|
||||
"\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 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,
|
||||
"\n query AutoAcceptableWorkspaceInvite(\n $token: String!\n $workspaceId: String!\n $options: WorkspaceInviteLookupOptions\n ) {\n workspaceInvite(token: $token, workspaceId: $workspaceId, options: $options) {\n id\n ...UseWorkspaceInviteManager_PendingWorkspaceCollaborator\n }\n }\n": typeof types.AutoAcceptableWorkspaceInviteDocument,
|
||||
"\n query ResolveCommentLink($commentId: String!, $projectId: String!) {\n project(id: $projectId) {\n comment(id: $commentId) {\n id\n ...LinkableComment\n }\n }\n }\n": typeof types.ResolveCommentLinkDocument,
|
||||
"\n fragment AutomateFunctionPage_AutomateFunction on AutomateFunction {\n id\n name\n description\n logo\n supportedSourceApps\n tags\n ...AutomateFunctionPageHeader_Function\n ...AutomateFunctionPageInfo_AutomateFunction\n ...AutomateAutomationCreateDialog_AutomateFunction\n creator {\n id\n }\n }\n": typeof types.AutomateFunctionPage_AutomateFunctionFragmentDoc,
|
||||
"\n query AutomateFunctionPage($functionId: ID!) {\n automateFunction(id: $functionId) {\n ...AutomateFunctionPage_AutomateFunction\n }\n activeUser {\n workspaces {\n items {\n ...AutomateFunctionCreateDialog_Workspace\n ...AutomateFunctionEditDialog_Workspace\n }\n }\n }\n }\n": typeof types.AutomateFunctionPageDocument,
|
||||
"\n query AutomateFunctionPageWorkspace($workspaceId: String!) {\n workspace(id: $workspaceId) {\n id\n ...AutomateFunctionPageHeader_Workspace\n }\n }\n": typeof types.AutomateFunctionPageWorkspaceDocument,
|
||||
"\n fragment PagesOnboarding_DiscoverableWorkspaces on User {\n discoverableWorkspaces {\n id\n name\n logo\n description\n slug\n }\n }\n": typeof types.PagesOnboarding_DiscoverableWorkspacesFragmentDoc,
|
||||
"\n fragment ProjectPageProject on Project {\n id\n createdAt\n modelCount: models(limit: 0) {\n totalCount\n }\n commentThreadCount: commentThreads(limit: 0) {\n totalCount\n }\n workspace {\n id\n }\n ...ProjectPageTeamInternals_Project\n ...ProjectPageProjectHeader\n ...ProjectPageTeamDialog\n ...ProjectsMoveToWorkspaceDialog_Project\n }\n": typeof types.ProjectPageProjectFragmentDoc,
|
||||
"\n fragment ProjectPageAutomationPage_Automation on Automation {\n id\n ...ProjectPageAutomationHeader_Automation\n ...ProjectPageAutomationFunctions_Automation\n ...ProjectPageAutomationRuns_Automation\n }\n": typeof types.ProjectPageAutomationPage_AutomationFragmentDoc,
|
||||
"\n fragment ProjectPageAutomationPage_Project on Project {\n id\n workspaceId\n ...ProjectPageAutomationHeader_Project\n }\n": typeof types.ProjectPageAutomationPage_ProjectFragmentDoc,
|
||||
"\n fragment ProjectPageSettingsTab_Project on Project {\n id\n role\n }\n": typeof types.ProjectPageSettingsTab_ProjectFragmentDoc,
|
||||
"\n fragment SettingsServerProjects_ProjectCollection on ProjectCollection {\n totalCount\n items {\n ...SettingsSharedProjects_Project\n }\n }\n": typeof types.SettingsServerProjects_ProjectCollectionFragmentDoc,
|
||||
"\n query SettingsServerRegions {\n serverInfo {\n multiRegion {\n regions {\n id\n ...SettingsServerRegionsTable_ServerRegionItem\n }\n availableKeys\n }\n }\n }\n": typeof types.SettingsServerRegionsDocument,
|
||||
"\n fragment SettingsWorkspacesBilling_Workspace on Workspace {\n ...BillingAlert_Workspace\n id\n role\n plan {\n name\n status\n createdAt\n paymentMethod\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n seats {\n guest\n plan\n }\n }\n team {\n items {\n id\n role\n }\n }\n }\n": typeof types.SettingsWorkspacesBilling_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesGeneral_Workspace on Workspace {\n ...SettingsWorkspacesGeneralEditAvatar_Workspace\n ...SettingsWorkspaceGeneralDeleteDialog_Workspace\n ...SettingsWorkspacesGeneralEditSlugDialog_Workspace\n id\n name\n slug\n description\n logo\n role\n defaultProjectRole\n plan {\n status\n name\n }\n }\n": typeof types.SettingsWorkspacesGeneral_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesMembers_Workspace on Workspace {\n id\n role\n team {\n items {\n id\n role\n }\n }\n invitedTeam {\n user {\n id\n }\n }\n adminWorkspacesJoinRequests {\n items {\n id\n status\n }\n totalCount\n }\n }\n": typeof types.SettingsWorkspacesMembers_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesProjects_ProjectCollection on ProjectCollection {\n totalCount\n items {\n ...SettingsSharedProjects_Project\n }\n }\n": typeof types.SettingsWorkspacesProjects_ProjectCollectionFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesRegions_Workspace on Workspace {\n id\n role\n defaultRegion {\n id\n ...SettingsWorkspacesRegionsSelect_ServerRegionItem\n }\n hasAccessToMultiRegion: hasAccessToFeature(\n featureName: workspaceDataRegionSpecificity\n )\n hasProjects: projects(limit: 0) {\n totalCount\n }\n }\n": typeof types.SettingsWorkspacesRegions_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesRegions_ServerInfo on ServerInfo {\n multiRegion {\n regions {\n id\n ...SettingsWorkspacesRegionsSelect_ServerRegionItem\n }\n }\n }\n": typeof types.SettingsWorkspacesRegions_ServerInfoFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesSecurity_Workspace on Workspace {\n id\n slug\n domains {\n id\n domain\n ...SettingsWorkspacesSecurityDomainRemoveDialog_WorkspaceDomain\n }\n ...SettingsWorkspacesSecuritySsoWrapper_Workspace\n domainBasedMembershipProtectionEnabled\n discoverabilityEnabled\n }\n\n fragment SettingsWorkspacesSecurity_User on User {\n id\n emails {\n id\n email\n verified\n }\n }\n": typeof types.SettingsWorkspacesSecurity_WorkspaceFragmentDoc,
|
||||
};
|
||||
const documents: Documents = {
|
||||
"\n fragment AuthLoginWithEmailBlock_PendingWorkspaceCollaborator on PendingWorkspaceCollaborator {\n id\n email\n user {\n id\n }\n }\n": types.AuthLoginWithEmailBlock_PendingWorkspaceCollaboratorFragmentDoc,
|
||||
"\n query AuthRegisterPanelWorkspaceInvite($token: String) {\n workspaceInvite(token: $token) {\n id\n ...AuthWorkspaceInviteHeader_PendingWorkspaceCollaborator\n }\n }\n": types.AuthRegisterPanelWorkspaceInviteDocument,
|
||||
"\n fragment ServerTermsOfServicePrivacyPolicyFragment on ServerInfo {\n termsOfService\n }\n": types.ServerTermsOfServicePrivacyPolicyFragmentFragmentDoc,
|
||||
@@ -119,13 +506,13 @@ const documents = {
|
||||
"\n fragment SettingsWorkspacesGeneralEditAvatar_Workspace on Workspace {\n id\n logo\n name\n }\n": types.SettingsWorkspacesGeneralEditAvatar_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesGeneralEditSlugDialog_Workspace on Workspace {\n id\n name\n slug\n }\n": types.SettingsWorkspacesGeneralEditSlugDialog_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesMembersChangeRoleDialog_Workspace on Workspace {\n id\n plan {\n status\n name\n }\n subscription {\n currentBillingCycleEnd\n seats {\n guest\n plan\n }\n }\n }\n": types.SettingsWorkspacesMembersChangeRoleDialog_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesMembersGuestsTable_WorkspaceCollaborator on WorkspaceCollaborator {\n id\n role\n user {\n id\n avatar\n name\n company\n verified\n }\n projectRoles {\n role\n project {\n id\n name\n }\n }\n }\n": types.SettingsWorkspacesMembersGuestsTable_WorkspaceCollaboratorFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesMembersGuestsTable_WorkspaceCollaborator on WorkspaceCollaborator {\n id\n role\n user {\n id\n avatar\n name\n company\n }\n projectRoles {\n role\n project {\n id\n name\n }\n }\n }\n": types.SettingsWorkspacesMembersGuestsTable_WorkspaceCollaboratorFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesMembersGuestsTable_Workspace on Workspace {\n id\n ...SettingsWorkspacesMembersTableHeader_Workspace\n ...SettingsSharedDeleteUserDialog_Workspace\n ...SettingsWorkspacesMembersChangeRoleDialog_Workspace\n team {\n items {\n id\n ...SettingsWorkspacesMembersGuestsTable_WorkspaceCollaborator\n }\n }\n }\n": types.SettingsWorkspacesMembersGuestsTable_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesMembersInvitesTable_PendingWorkspaceCollaborator on PendingWorkspaceCollaborator {\n id\n inviteId\n role\n title\n updatedAt\n user {\n id\n ...LimitedUserAvatar\n }\n invitedBy {\n id\n ...LimitedUserAvatar\n }\n }\n": types.SettingsWorkspacesMembersInvitesTable_PendingWorkspaceCollaboratorFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesMembersInvitesTable_Workspace on Workspace {\n id\n ...SettingsWorkspacesMembersTableHeader_Workspace\n invitedTeam(filter: $invitesFilter) {\n ...SettingsWorkspacesMembersInvitesTable_PendingWorkspaceCollaborator\n }\n }\n": types.SettingsWorkspacesMembersInvitesTable_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesMembersRequestsTable_Workspace on Workspace {\n ...SettingsWorkspacesMembersTableHeader_Workspace\n id\n adminWorkspacesJoinRequests(filter: $joinRequestsFilter) {\n totalCount\n items {\n ...WorkspaceJoinRequestApproveDialog_WorkspaceJoinRequest\n id\n createdAt\n status\n user {\n id\n avatar\n name\n }\n }\n }\n }\n": types.SettingsWorkspacesMembersRequestsTable_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesMembersMembersTable_WorkspaceCollaborator on WorkspaceCollaborator {\n id\n role\n user {\n id\n avatar\n name\n company\n verified\n workspaceDomainPolicyCompliant\n }\n }\n": types.SettingsWorkspacesMembersMembersTable_WorkspaceCollaboratorFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesMembersMembersTable_Workspace on Workspace {\n id\n name\n ...SettingsSharedDeleteUserDialog_Workspace\n ...SettingsWorkspacesMembersTableHeader_Workspace\n ...SettingsWorkspacesMembersChangeRoleDialog_Workspace\n team {\n items {\n id\n ...SettingsWorkspacesMembersMembersTable_WorkspaceCollaborator\n }\n }\n }\n": types.SettingsWorkspacesMembersMembersTable_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesMembersInvitesTable_Workspace on Workspace {\n id\n ...SettingsWorkspacesMembersTableHeader_Workspace\n invitedTeam {\n ...SettingsWorkspacesMembersInvitesTable_PendingWorkspaceCollaborator\n }\n }\n": types.SettingsWorkspacesMembersInvitesTable_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesMembersRequestsTable_Workspace on Workspace {\n ...SettingsWorkspacesMembersTableHeader_Workspace\n id\n adminWorkspacesJoinRequests {\n totalCount\n items {\n ...WorkspaceJoinRequestApproveDialog_WorkspaceJoinRequest\n id\n createdAt\n status\n user {\n id\n avatar\n name\n }\n }\n }\n }\n": types.SettingsWorkspacesMembersRequestsTable_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesMembersTable_WorkspaceCollaborator on WorkspaceCollaborator {\n id\n role\n user {\n id\n avatar\n name\n company\n workspaceDomainPolicyCompliant\n }\n }\n": types.SettingsWorkspacesMembersTable_WorkspaceCollaboratorFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesMembersTable_Workspace on Workspace {\n id\n name\n ...SettingsSharedDeleteUserDialog_Workspace\n ...SettingsWorkspacesMembersTableHeader_Workspace\n ...SettingsWorkspacesMembersChangeRoleDialog_Workspace\n team {\n items {\n id\n ...SettingsWorkspacesMembersTable_WorkspaceCollaborator\n }\n }\n }\n": types.SettingsWorkspacesMembersTable_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesMembersTableHeader_Workspace on Workspace {\n id\n role\n ...InviteDialogWorkspace_Workspace\n }\n": types.SettingsWorkspacesMembersTableHeader_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesRegionsSelect_ServerRegionItem on ServerRegionItem {\n id\n key\n name\n description\n }\n": types.SettingsWorkspacesRegionsSelect_ServerRegionItemFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesSecurityDomainRemoveDialog_WorkspaceDomain on WorkspaceDomain {\n id\n domain\n }\n": types.SettingsWorkspacesSecurityDomainRemoveDialog_WorkspaceDomainFragmentDoc,
|
||||
@@ -145,14 +532,13 @@ const documents = {
|
||||
"\n fragment WorkspaceInviteDiscoverableWorkspaceBanner_LimitedWorkspace on LimitedWorkspace {\n id\n name\n slug\n description\n logo\n }\n": types.WorkspaceInviteDiscoverableWorkspaceBanner_LimitedWorkspaceFragmentDoc,
|
||||
"\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,
|
||||
"\n fragment WorkspaceSidebarAbout_Workspace on Workspace {\n ...WorkspaceDashboardAbout_Workspace\n }\n": types.WorkspaceSidebarAbout_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceSidebarMembers_Workspace on Workspace {\n ...WorkspaceTeam_Workspace\n }\n": types.WorkspaceSidebarMembers_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 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 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,
|
||||
"\n mutation CreateOnboardingProject {\n projectMutations {\n createForOnboarding {\n ...ProjectPageProject\n ...ProjectDashboardItem\n }\n }\n }\n ": types.CreateOnboardingProjectDocument,
|
||||
"\n mutation FinishOnboarding {\n activeUserMutations {\n finishOnboarding\n }\n }\n": types.FinishOnboardingDocument,
|
||||
"\n mutation FinishOnboarding($input: OnboardingCompletionInput) {\n activeUserMutations {\n finishOnboarding(input: $input)\n }\n }\n": types.FinishOnboardingDocument,
|
||||
"\n mutation RequestVerificationByEmail($email: String!) {\n requestVerificationByEmail(email: $email)\n }\n": types.RequestVerificationByEmailDocument,
|
||||
"\n query AuthLoginPanel {\n serverInfo {\n authStrategies {\n id\n }\n ...AuthStategiesServerInfoFragment\n }\n }\n": types.AuthLoginPanelDocument,
|
||||
"\n query AuthRegisterPanel($token: String) {\n serverInfo {\n inviteOnly\n authStrategies {\n id\n }\n ...AuthStategiesServerInfoFragment\n ...ServerTermsOfServicePrivacyPolicyFragment\n }\n serverInviteByToken(token: $token) {\n id\n email\n }\n }\n": types.AuthRegisterPanelDocument,
|
||||
@@ -308,9 +694,12 @@ const documents = {
|
||||
"\n query SettingsWorkspaceBilling($slug: String!) {\n workspaceBySlug(slug: $slug) {\n id\n ...SettingsWorkspacesBilling_Workspace\n }\n }\n": types.SettingsWorkspaceBillingDocument,
|
||||
"\n query SettingsWorkspaceBillingCustomerPortal($workspaceId: String!) {\n workspace(id: $workspaceId) {\n customerPortalUrl\n }\n }\n": types.SettingsWorkspaceBillingCustomerPortalDocument,
|
||||
"\n query SettingsWorkspaceRegions($slug: String!) {\n workspaceBySlug(slug: $slug) {\n id\n ...SettingsWorkspacesRegions_Workspace\n }\n serverInfo {\n ...SettingsWorkspacesRegions_ServerInfo\n }\n }\n": types.SettingsWorkspaceRegionsDocument,
|
||||
"\n query SettingsWorkspacesMembers(\n $slug: String!\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n $joinRequestsFilter: AdminWorkspaceJoinRequestFilter\n ) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesMembers_Workspace\n ...SettingsWorkspacesMembersMembersTable_Workspace\n ...SettingsWorkspacesMembersGuestsTable_Workspace\n ...SettingsWorkspacesMembersInvitesTable_Workspace\n ...SettingsWorkspacesMembersRequestsTable_Workspace\n }\n }\n": types.SettingsWorkspacesMembersDocument,
|
||||
"\n query SettingsWorkspacesMembersSearch($slug: String!, $filter: WorkspaceTeamFilter) {\n workspaceBySlug(slug: $slug) {\n id\n team(filter: $filter) {\n items {\n id\n ...SettingsWorkspacesMembersMembersTable_WorkspaceCollaborator\n }\n }\n }\n }\n": types.SettingsWorkspacesMembersSearchDocument,
|
||||
"\n query SettingsWorkspacesJoinRequestsSearch(\n $slug: String!\n $joinRequestsFilter: AdminWorkspaceJoinRequestFilter\n ) {\n workspaceBySlug(slug: $slug) {\n id\n ...SettingsWorkspacesMembersRequestsTable_Workspace\n }\n }\n": types.SettingsWorkspacesJoinRequestsSearchDocument,
|
||||
"\n query SettingsWorkspacesMembers($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesMembers_Workspace\n }\n }\n": types.SettingsWorkspacesMembersDocument,
|
||||
"\n query SettingsWorkspacesMembersTable($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesMembersTable_Workspace\n }\n }\n": types.SettingsWorkspacesMembersTableDocument,
|
||||
"\n query SettingsWorkspacesMembersGuests($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesMembersGuestsTable_Workspace\n }\n }\n": types.SettingsWorkspacesMembersGuestsDocument,
|
||||
"\n query SettingsWorkspacesMembersInvites($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesMembersInvitesTable_Workspace\n }\n }\n": types.SettingsWorkspacesMembersInvitesDocument,
|
||||
"\n query SettingsWorkspacesMembersRequests($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesMembersRequestsTable_Workspace\n }\n }\n": types.SettingsWorkspacesMembersRequestsDocument,
|
||||
"\n query SettingsWorkspacesMembersSearch($slug: String!, $filter: WorkspaceTeamFilter) {\n workspaceBySlug(slug: $slug) {\n id\n team(filter: $filter) {\n items {\n id\n ...SettingsWorkspacesMembersTable_WorkspaceCollaborator\n }\n }\n }\n }\n": types.SettingsWorkspacesMembersSearchDocument,
|
||||
"\n query SettingsWorkspacesInvitesSearch(\n $slug: String!\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n ) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesMembersInvitesTable_Workspace\n }\n }\n": types.SettingsWorkspacesInvitesSearchDocument,
|
||||
"\n query SettingsWorkspacesProjects(\n $slug: String!\n $limit: Int!\n $cursor: String\n $filter: WorkspaceProjectsFilter\n ) {\n workspaceBySlug(slug: $slug) {\n id\n slug\n readOnly\n projects(limit: $limit, cursor: $cursor, filter: $filter) {\n cursor\n ...SettingsWorkspacesProjects_ProjectCollection\n }\n }\n }\n": types.SettingsWorkspacesProjectsDocument,
|
||||
"\n query SettingsWorkspaceSecurity($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesSecurity_Workspace\n }\n activeUser {\n ...SettingsWorkspacesSecurity_User\n }\n }\n": types.SettingsWorkspaceSecurityDocument,
|
||||
@@ -350,7 +739,7 @@ const 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": 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 {\n totalCount\n items {\n id\n user {\n id\n name\n ...LimitedUserAvatar\n }\n }\n }\n adminWorkspacesJoinRequests {\n totalCount\n }\n ...WorkspaceInvitedTeam_Workspace\n }\n": types.WorkspaceTeam_WorkspaceFragmentDoc,
|
||||
"\n fragment WorkspaceTeam_Workspace on 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 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 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 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,
|
||||
@@ -392,7 +781,7 @@ const documents = {
|
||||
"\n query SettingsServerRegions {\n serverInfo {\n multiRegion {\n regions {\n id\n ...SettingsServerRegionsTable_ServerRegionItem\n }\n availableKeys\n }\n }\n }\n": types.SettingsServerRegionsDocument,
|
||||
"\n fragment SettingsWorkspacesBilling_Workspace on Workspace {\n ...BillingAlert_Workspace\n id\n role\n plan {\n name\n status\n createdAt\n paymentMethod\n }\n subscription {\n billingInterval\n currentBillingCycleEnd\n seats {\n guest\n plan\n }\n }\n team {\n items {\n id\n role\n }\n }\n }\n": types.SettingsWorkspacesBilling_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesGeneral_Workspace on Workspace {\n ...SettingsWorkspacesGeneralEditAvatar_Workspace\n ...SettingsWorkspaceGeneralDeleteDialog_Workspace\n ...SettingsWorkspacesGeneralEditSlugDialog_Workspace\n id\n name\n slug\n description\n logo\n role\n defaultProjectRole\n plan {\n status\n name\n }\n }\n": types.SettingsWorkspacesGeneral_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesMembers_Workspace on Workspace {\n id\n role\n team {\n items {\n id\n }\n }\n invitedTeam(filter: $invitesFilter) {\n user {\n id\n }\n }\n adminWorkspacesJoinRequests(filter: $joinRequestsFilter) {\n totalCount\n }\n }\n": types.SettingsWorkspacesMembers_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesMembers_Workspace on Workspace {\n id\n role\n team {\n items {\n id\n role\n }\n }\n invitedTeam {\n user {\n id\n }\n }\n adminWorkspacesJoinRequests {\n items {\n id\n status\n }\n totalCount\n }\n }\n": types.SettingsWorkspacesMembers_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesProjects_ProjectCollection on ProjectCollection {\n totalCount\n items {\n ...SettingsSharedProjects_Project\n }\n }\n": types.SettingsWorkspacesProjects_ProjectCollectionFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesRegions_Workspace on Workspace {\n id\n role\n defaultRegion {\n id\n ...SettingsWorkspacesRegionsSelect_ServerRegionItem\n }\n hasAccessToMultiRegion: hasAccessToFeature(\n featureName: workspaceDataRegionSpecificity\n )\n hasProjects: projects(limit: 0) {\n totalCount\n }\n }\n": types.SettingsWorkspacesRegions_WorkspaceFragmentDoc,
|
||||
"\n fragment SettingsWorkspacesRegions_ServerInfo on ServerInfo {\n multiRegion {\n regions {\n id\n ...SettingsWorkspacesRegionsSelect_ServerRegionItem\n }\n }\n }\n": types.SettingsWorkspacesRegions_ServerInfoFragmentDoc,
|
||||
@@ -836,7 +1225,7 @@ export function graphql(source: "\n fragment SettingsWorkspacesMembersChangeRol
|
||||
/**
|
||||
* 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 SettingsWorkspacesMembersGuestsTable_WorkspaceCollaborator on WorkspaceCollaborator {\n id\n role\n user {\n id\n avatar\n name\n company\n verified\n }\n projectRoles {\n role\n project {\n id\n name\n }\n }\n }\n"): (typeof documents)["\n fragment SettingsWorkspacesMembersGuestsTable_WorkspaceCollaborator on WorkspaceCollaborator {\n id\n role\n user {\n id\n avatar\n name\n company\n verified\n }\n projectRoles {\n role\n project {\n id\n name\n }\n }\n }\n"];
|
||||
export function graphql(source: "\n fragment SettingsWorkspacesMembersGuestsTable_WorkspaceCollaborator on WorkspaceCollaborator {\n id\n role\n user {\n id\n avatar\n name\n company\n }\n projectRoles {\n role\n project {\n id\n name\n }\n }\n }\n"): (typeof documents)["\n fragment SettingsWorkspacesMembersGuestsTable_WorkspaceCollaborator on WorkspaceCollaborator {\n id\n role\n user {\n id\n avatar\n name\n company\n }\n projectRoles {\n role\n project {\n id\n name\n }\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -848,19 +1237,19 @@ export function graphql(source: "\n fragment SettingsWorkspacesMembersInvitesTa
|
||||
/**
|
||||
* 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 SettingsWorkspacesMembersInvitesTable_Workspace on Workspace {\n id\n ...SettingsWorkspacesMembersTableHeader_Workspace\n invitedTeam(filter: $invitesFilter) {\n ...SettingsWorkspacesMembersInvitesTable_PendingWorkspaceCollaborator\n }\n }\n"): (typeof documents)["\n fragment SettingsWorkspacesMembersInvitesTable_Workspace on Workspace {\n id\n ...SettingsWorkspacesMembersTableHeader_Workspace\n invitedTeam(filter: $invitesFilter) {\n ...SettingsWorkspacesMembersInvitesTable_PendingWorkspaceCollaborator\n }\n }\n"];
|
||||
export function graphql(source: "\n fragment SettingsWorkspacesMembersInvitesTable_Workspace on Workspace {\n id\n ...SettingsWorkspacesMembersTableHeader_Workspace\n invitedTeam {\n ...SettingsWorkspacesMembersInvitesTable_PendingWorkspaceCollaborator\n }\n }\n"): (typeof documents)["\n fragment SettingsWorkspacesMembersInvitesTable_Workspace on Workspace {\n id\n ...SettingsWorkspacesMembersTableHeader_Workspace\n invitedTeam {\n ...SettingsWorkspacesMembersInvitesTable_PendingWorkspaceCollaborator\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 SettingsWorkspacesMembersRequestsTable_Workspace on Workspace {\n ...SettingsWorkspacesMembersTableHeader_Workspace\n id\n adminWorkspacesJoinRequests(filter: $joinRequestsFilter) {\n totalCount\n items {\n ...WorkspaceJoinRequestApproveDialog_WorkspaceJoinRequest\n id\n createdAt\n status\n user {\n id\n avatar\n name\n }\n }\n }\n }\n"): (typeof documents)["\n fragment SettingsWorkspacesMembersRequestsTable_Workspace on Workspace {\n ...SettingsWorkspacesMembersTableHeader_Workspace\n id\n adminWorkspacesJoinRequests(filter: $joinRequestsFilter) {\n totalCount\n items {\n ...WorkspaceJoinRequestApproveDialog_WorkspaceJoinRequest\n id\n createdAt\n status\n user {\n id\n avatar\n name\n }\n }\n }\n }\n"];
|
||||
export function graphql(source: "\n fragment SettingsWorkspacesMembersRequestsTable_Workspace on Workspace {\n ...SettingsWorkspacesMembersTableHeader_Workspace\n id\n adminWorkspacesJoinRequests {\n totalCount\n items {\n ...WorkspaceJoinRequestApproveDialog_WorkspaceJoinRequest\n id\n createdAt\n status\n user {\n id\n avatar\n name\n }\n }\n }\n }\n"): (typeof documents)["\n fragment SettingsWorkspacesMembersRequestsTable_Workspace on Workspace {\n ...SettingsWorkspacesMembersTableHeader_Workspace\n id\n adminWorkspacesJoinRequests {\n totalCount\n items {\n ...WorkspaceJoinRequestApproveDialog_WorkspaceJoinRequest\n id\n createdAt\n status\n user {\n id\n avatar\n name\n }\n }\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "\n fragment SettingsWorkspacesMembersMembersTable_WorkspaceCollaborator on WorkspaceCollaborator {\n id\n role\n user {\n id\n avatar\n name\n company\n verified\n workspaceDomainPolicyCompliant\n }\n }\n"): (typeof documents)["\n fragment SettingsWorkspacesMembersMembersTable_WorkspaceCollaborator on WorkspaceCollaborator {\n id\n role\n user {\n id\n avatar\n name\n company\n verified\n workspaceDomainPolicyCompliant\n }\n }\n"];
|
||||
export function graphql(source: "\n fragment SettingsWorkspacesMembersTable_WorkspaceCollaborator on WorkspaceCollaborator {\n id\n role\n user {\n id\n avatar\n name\n company\n workspaceDomainPolicyCompliant\n }\n }\n"): (typeof documents)["\n fragment SettingsWorkspacesMembersTable_WorkspaceCollaborator on WorkspaceCollaborator {\n id\n role\n user {\n id\n avatar\n name\n company\n workspaceDomainPolicyCompliant\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 SettingsWorkspacesMembersMembersTable_Workspace on Workspace {\n id\n name\n ...SettingsSharedDeleteUserDialog_Workspace\n ...SettingsWorkspacesMembersTableHeader_Workspace\n ...SettingsWorkspacesMembersChangeRoleDialog_Workspace\n team {\n items {\n id\n ...SettingsWorkspacesMembersMembersTable_WorkspaceCollaborator\n }\n }\n }\n"): (typeof documents)["\n fragment SettingsWorkspacesMembersMembersTable_Workspace on Workspace {\n id\n name\n ...SettingsSharedDeleteUserDialog_Workspace\n ...SettingsWorkspacesMembersTableHeader_Workspace\n ...SettingsWorkspacesMembersChangeRoleDialog_Workspace\n team {\n items {\n id\n ...SettingsWorkspacesMembersMembersTable_WorkspaceCollaborator\n }\n }\n }\n"];
|
||||
export function graphql(source: "\n fragment SettingsWorkspacesMembersTable_Workspace on Workspace {\n id\n name\n ...SettingsSharedDeleteUserDialog_Workspace\n ...SettingsWorkspacesMembersTableHeader_Workspace\n ...SettingsWorkspacesMembersChangeRoleDialog_Workspace\n team {\n items {\n id\n ...SettingsWorkspacesMembersTable_WorkspaceCollaborator\n }\n }\n }\n"): (typeof documents)["\n fragment SettingsWorkspacesMembersTable_Workspace on Workspace {\n id\n name\n ...SettingsSharedDeleteUserDialog_Workspace\n ...SettingsWorkspacesMembersTableHeader_Workspace\n ...SettingsWorkspacesMembersChangeRoleDialog_Workspace\n team {\n items {\n id\n ...SettingsWorkspacesMembersTable_WorkspaceCollaborator\n }\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -937,10 +1326,6 @@ export function graphql(source: "\n fragment WorkspaceJoinRequestApproveDialog_
|
||||
* 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"];
|
||||
/**
|
||||
* 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 WorkspaceSidebarMembers_Workspace on Workspace {\n ...WorkspaceTeam_Workspace\n }\n"): (typeof documents)["\n fragment WorkspaceSidebarMembers_Workspace on Workspace {\n ...WorkspaceTeam_Workspace\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -968,7 +1353,7 @@ export function graphql(source: "\n mutation CreateOnboardingProject {\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 mutation FinishOnboarding {\n activeUserMutations {\n finishOnboarding\n }\n }\n"): (typeof documents)["\n mutation FinishOnboarding {\n activeUserMutations {\n finishOnboarding\n }\n }\n"];
|
||||
export function graphql(source: "\n mutation FinishOnboarding($input: OnboardingCompletionInput) {\n activeUserMutations {\n finishOnboarding(input: $input)\n }\n }\n"): (typeof documents)["\n mutation FinishOnboarding($input: OnboardingCompletionInput) {\n activeUserMutations {\n finishOnboarding(input: $input)\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -1592,15 +1977,27 @@ export function graphql(source: "\n query SettingsWorkspaceRegions($slug: Strin
|
||||
/**
|
||||
* 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 SettingsWorkspacesMembers(\n $slug: String!\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n $joinRequestsFilter: AdminWorkspaceJoinRequestFilter\n ) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesMembers_Workspace\n ...SettingsWorkspacesMembersMembersTable_Workspace\n ...SettingsWorkspacesMembersGuestsTable_Workspace\n ...SettingsWorkspacesMembersInvitesTable_Workspace\n ...SettingsWorkspacesMembersRequestsTable_Workspace\n }\n }\n"): (typeof documents)["\n query SettingsWorkspacesMembers(\n $slug: String!\n $invitesFilter: PendingWorkspaceCollaboratorsFilter\n $joinRequestsFilter: AdminWorkspaceJoinRequestFilter\n ) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesMembers_Workspace\n ...SettingsWorkspacesMembersMembersTable_Workspace\n ...SettingsWorkspacesMembersGuestsTable_Workspace\n ...SettingsWorkspacesMembersInvitesTable_Workspace\n ...SettingsWorkspacesMembersRequestsTable_Workspace\n }\n }\n"];
|
||||
export function graphql(source: "\n query SettingsWorkspacesMembers($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesMembers_Workspace\n }\n }\n"): (typeof documents)["\n query SettingsWorkspacesMembers($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesMembers_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 SettingsWorkspacesMembersSearch($slug: String!, $filter: WorkspaceTeamFilter) {\n workspaceBySlug(slug: $slug) {\n id\n team(filter: $filter) {\n items {\n id\n ...SettingsWorkspacesMembersMembersTable_WorkspaceCollaborator\n }\n }\n }\n }\n"): (typeof documents)["\n query SettingsWorkspacesMembersSearch($slug: String!, $filter: WorkspaceTeamFilter) {\n workspaceBySlug(slug: $slug) {\n id\n team(filter: $filter) {\n items {\n id\n ...SettingsWorkspacesMembersMembersTable_WorkspaceCollaborator\n }\n }\n }\n }\n"];
|
||||
export function graphql(source: "\n query SettingsWorkspacesMembersTable($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesMembersTable_Workspace\n }\n }\n"): (typeof documents)["\n query SettingsWorkspacesMembersTable($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesMembersTable_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 SettingsWorkspacesJoinRequestsSearch(\n $slug: String!\n $joinRequestsFilter: AdminWorkspaceJoinRequestFilter\n ) {\n workspaceBySlug(slug: $slug) {\n id\n ...SettingsWorkspacesMembersRequestsTable_Workspace\n }\n }\n"): (typeof documents)["\n query SettingsWorkspacesJoinRequestsSearch(\n $slug: String!\n $joinRequestsFilter: AdminWorkspaceJoinRequestFilter\n ) {\n workspaceBySlug(slug: $slug) {\n id\n ...SettingsWorkspacesMembersRequestsTable_Workspace\n }\n }\n"];
|
||||
export function graphql(source: "\n query SettingsWorkspacesMembersGuests($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesMembersGuestsTable_Workspace\n }\n }\n"): (typeof documents)["\n query SettingsWorkspacesMembersGuests($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesMembersGuestsTable_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 SettingsWorkspacesMembersInvites($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesMembersInvitesTable_Workspace\n }\n }\n"): (typeof documents)["\n query SettingsWorkspacesMembersInvites($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesMembersInvitesTable_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 SettingsWorkspacesMembersRequests($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesMembersRequestsTable_Workspace\n }\n }\n"): (typeof documents)["\n query SettingsWorkspacesMembersRequests($slug: String!) {\n workspaceBySlug(slug: $slug) {\n ...SettingsWorkspacesMembersRequestsTable_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 SettingsWorkspacesMembersSearch($slug: String!, $filter: WorkspaceTeamFilter) {\n workspaceBySlug(slug: $slug) {\n id\n team(filter: $filter) {\n items {\n id\n ...SettingsWorkspacesMembersTable_WorkspaceCollaborator\n }\n }\n }\n }\n"): (typeof documents)["\n query SettingsWorkspacesMembersSearch($slug: String!, $filter: WorkspaceTeamFilter) {\n workspaceBySlug(slug: $slug) {\n id\n team(filter: $filter) {\n items {\n id\n ...SettingsWorkspacesMembersTable_WorkspaceCollaborator\n }\n }\n }\n }\n"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
@@ -1760,7 +2157,7 @@ export function graphql(source: "\n fragment WorkspaceInvitedTeam_Workspace on
|
||||
/**
|
||||
* 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 {\n totalCount\n items {\n id\n user {\n id\n name\n ...LimitedUserAvatar\n }\n }\n }\n adminWorkspacesJoinRequests {\n totalCount\n }\n ...WorkspaceInvitedTeam_Workspace\n }\n"): (typeof documents)["\n fragment WorkspaceTeam_Workspace on 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 adminWorkspacesJoinRequests {\n totalCount\n }\n ...WorkspaceInvitedTeam_Workspace\n }\n"];
|
||||
export function graphql(source: "\n fragment WorkspaceTeam_Workspace on 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 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 {\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.
|
||||
*/
|
||||
@@ -1928,7 +2325,7 @@ export function graphql(source: "\n fragment SettingsWorkspacesGeneral_Workspac
|
||||
/**
|
||||
* 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 SettingsWorkspacesMembers_Workspace on Workspace {\n id\n role\n team {\n items {\n id\n }\n }\n invitedTeam(filter: $invitesFilter) {\n user {\n id\n }\n }\n adminWorkspacesJoinRequests(filter: $joinRequestsFilter) {\n totalCount\n }\n }\n"): (typeof documents)["\n fragment SettingsWorkspacesMembers_Workspace on Workspace {\n id\n role\n team {\n items {\n id\n }\n }\n invitedTeam(filter: $invitesFilter) {\n user {\n id\n }\n }\n adminWorkspacesJoinRequests(filter: $joinRequestsFilter) {\n totalCount\n }\n }\n"];
|
||||
export function graphql(source: "\n fragment SettingsWorkspacesMembers_Workspace on Workspace {\n id\n role\n team {\n items {\n id\n role\n }\n }\n invitedTeam {\n user {\n id\n }\n }\n adminWorkspacesJoinRequests {\n items {\n id\n status\n }\n totalCount\n }\n }\n"): (typeof documents)["\n fragment SettingsWorkspacesMembers_Workspace on Workspace {\n id\n role\n team {\n items {\n id\n role\n }\n }\n invitedTeam {\n user {\n id\n }\n }\n adminWorkspacesJoinRequests {\n items {\n id\n status\n }\n totalCount\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
@@ -47,6 +47,18 @@ export const settingsWorkspaceRoutes = {
|
||||
name: '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`
|
||||
},
|
||||
membersInvites: {
|
||||
name: '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`
|
||||
},
|
||||
projects: {
|
||||
name: 'settings-workspaces-slug-projects',
|
||||
route: (slug: string) => `/settings/workspaces/${slug}/projects`
|
||||
|
||||
@@ -382,6 +382,7 @@ function createLink(params: {
|
||||
// only log as error if at least one error has a status code of 5xx or has no status code
|
||||
const shouldLogAsWarn = gqlErrors.every(
|
||||
(e) =>
|
||||
e.extensions &&
|
||||
'statusCode' in e.extensions &&
|
||||
typeof e.extensions.statusCode === 'number' &&
|
||||
e.extensions.statusCode < 500
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { BaseError } from '@speckle/ui-components'
|
||||
|
||||
export {
|
||||
BaseError,
|
||||
LogicError,
|
||||
@@ -5,3 +7,7 @@ export {
|
||||
ComposableInvokedOutOfScopeError,
|
||||
UnsupportedEnvironmentError
|
||||
} from '@speckle/ui-components'
|
||||
|
||||
export class ResourceLoadError extends BaseError {
|
||||
static defaultMessage = 'External resource failed to load'
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
noop
|
||||
} from 'lodash-es'
|
||||
import type { Logger, Level } from 'pino'
|
||||
import { ResourceLoadError } from '~/lib/core/errors/base'
|
||||
|
||||
/**
|
||||
* Add pino-pretty like formatting
|
||||
@@ -103,6 +104,12 @@ export const formatAppError = (err: SimpleError): SimpleError => {
|
||||
finalStatusCode = 429
|
||||
}
|
||||
|
||||
if (finalMessage.match(/\/_nuxt\/builds\/meta.*?404/i)) {
|
||||
finalMessage =
|
||||
'Speckle is currently upgrading to a newer version. Please reload the page in a few seconds.'
|
||||
finalStatusCode = 500
|
||||
}
|
||||
|
||||
finalMessage = upperFirst(finalMessage)
|
||||
|
||||
return {
|
||||
@@ -152,12 +159,30 @@ export function enableCustomLoggerHandling(params: {
|
||||
return (...args: unknown[]) => {
|
||||
const log = logMethod.bind(target)
|
||||
|
||||
// Format passed in data, if needed
|
||||
args = args
|
||||
.map((arg) => {
|
||||
// Convert error events to error type
|
||||
if (arg instanceof Event && arg.type === 'error') {
|
||||
return new ResourceLoadError()
|
||||
}
|
||||
|
||||
return arg
|
||||
})
|
||||
.filter((arg) => {
|
||||
// Filter out falsy values
|
||||
return !!arg && !(['null', 'undefined'] as unknown[]).includes(arg)
|
||||
})
|
||||
|
||||
// If nothing valid to log, skip entirely
|
||||
if (args.length === 0) return
|
||||
|
||||
const level = prop as Level
|
||||
const firstError = args.find((arg): arg is Error => arg instanceof Error)
|
||||
|
||||
const firstString = args.find(isString)
|
||||
const otherData: unknown[] = args.filter(
|
||||
(o) => !(o instanceof Error) && o !== firstString
|
||||
(o) => o !== firstString && o !== firstError
|
||||
)
|
||||
|
||||
const errorMessage = firstError?.message ?? firstString ?? `Unknown error`
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { MaybeRef } from '@vueuse/core'
|
||||
import type { MaybeNullOrUndefined, Nullable } from '@speckle/shared'
|
||||
import { useAuthCookie } from '~~/lib/auth/composables/auth'
|
||||
import { onProjectVersionsPreviewGeneratedSubscription } from '~~/lib/projects/graphql/subscriptions'
|
||||
import { useSubscription } from '@vue/apollo-composable'
|
||||
import { useLock } from '~~/lib/common/composables/singleton'
|
||||
@@ -26,11 +25,7 @@ export function usePreviewImageBlob(
|
||||
}>
|
||||
) {
|
||||
const { enabled = ref(true) } = options || {}
|
||||
const authToken = useAuthCookie()
|
||||
const logger = useLogger()
|
||||
const {
|
||||
public: { enableDirectPreviews }
|
||||
} = useRuntimeConfig()
|
||||
|
||||
const url = ref(PreviewPlaceholder as Nullable<string>)
|
||||
const hasDoneFirstLoad = ref(false)
|
||||
@@ -49,21 +44,15 @@ export function usePreviewImageBlob(
|
||||
hasDoneFirstLoad: computed(() => hasDoneFirstLoad.value)
|
||||
}
|
||||
|
||||
if (enableDirectPreviews) {
|
||||
const directPreviewUrl = unref(previewUrl)
|
||||
// const directPanoramicUrl = basePanoramaUrl.value
|
||||
|
||||
useHead({
|
||||
link: [
|
||||
...(directPreviewUrl?.length
|
||||
? [{ rel: 'preload', as: <const>'image', href: directPreviewUrl }]
|
||||
: [])
|
||||
// ...(directPanoramicUrl?.length
|
||||
// ? [{ rel: 'prefetch', as: <const>'image', href: directPanoramicUrl }]
|
||||
// : [])
|
||||
]
|
||||
})
|
||||
}
|
||||
// Preload the image
|
||||
const directPreviewUrl = unref(previewUrl)
|
||||
useHead({
|
||||
link: [
|
||||
...(directPreviewUrl?.length
|
||||
? [{ rel: 'preload', as: <const>'image', href: directPreviewUrl }]
|
||||
: [])
|
||||
]
|
||||
})
|
||||
|
||||
if (import.meta.server) return ret
|
||||
|
||||
@@ -133,23 +122,9 @@ export function usePreviewImageBlob(
|
||||
return
|
||||
}
|
||||
|
||||
let blobUrl: string
|
||||
if (enableDirectPreviews || import.meta.server) {
|
||||
const blobUrlConfig = new URL(basePreviewUrl)
|
||||
blobUrlConfig.searchParams.set('v', cacheBust.value.toString())
|
||||
blobUrl = blobUrlConfig.toString()
|
||||
} else {
|
||||
const res = await fetch(basePreviewUrl, {
|
||||
headers: authToken.value ? { Authorization: `Bearer ${authToken.value}` } : {}
|
||||
})
|
||||
|
||||
if (res.headers.has('X-Preview-Error')) {
|
||||
throw new Error('Failed getting preview')
|
||||
}
|
||||
|
||||
const blob = await res.blob()
|
||||
blobUrl = URL.createObjectURL(blob)
|
||||
}
|
||||
const blobUrlConfig = new URL(basePreviewUrl)
|
||||
blobUrlConfig.searchParams.set('v', cacheBust.value.toString())
|
||||
const blobUrl = blobUrlConfig.toString()
|
||||
|
||||
// Load img in browser first, before we set the url
|
||||
if (import.meta.client) {
|
||||
@@ -181,30 +156,9 @@ export function usePreviewImageBlob(
|
||||
return
|
||||
}
|
||||
|
||||
let blobUrl: string
|
||||
if (enableDirectPreviews || import.meta.server) {
|
||||
const blobUrlConfig = new URL(basePanoramaUrl.value)
|
||||
blobUrlConfig.searchParams.set('v', cacheBust.value.toString())
|
||||
blobUrl = blobUrlConfig.toString()
|
||||
} else {
|
||||
const res = await fetch(basePanoramaUrl.value, {
|
||||
headers: authToken.value ? { Authorization: `Bearer ${authToken.value}` } : {}
|
||||
})
|
||||
|
||||
const errCode = res.headers.get('X-Preview-Error-Code')
|
||||
if (errCode?.length) {
|
||||
if (errCode === 'ANGLE_NOT_FOUND') {
|
||||
throw new AngleNotFoundError()
|
||||
}
|
||||
}
|
||||
|
||||
if (res.headers.has('X-Preview-Error')) {
|
||||
throw new Error('Failed getting preview')
|
||||
}
|
||||
|
||||
const blob = await res.blob()
|
||||
blobUrl = URL.createObjectURL(blob)
|
||||
}
|
||||
const blobUrlConfig = new URL(basePanoramaUrl.value)
|
||||
blobUrlConfig.searchParams.set('v', cacheBust.value.toString())
|
||||
const blobUrl = blobUrlConfig.toString()
|
||||
|
||||
// Load img in browser first, before we set the url
|
||||
if (import.meta.client) {
|
||||
|
||||
@@ -85,10 +85,12 @@ export function useProjectVersionUpdateTracking(
|
||||
const event = res.data.projectVersionsUpdated
|
||||
const version = event.version
|
||||
if (
|
||||
[
|
||||
ProjectVersionsUpdatedMessageType.Created,
|
||||
ProjectVersionsUpdatedMessageType.Updated
|
||||
].includes(event.type) &&
|
||||
(
|
||||
[
|
||||
ProjectVersionsUpdatedMessageType.Created,
|
||||
ProjectVersionsUpdatedMessageType.Updated
|
||||
] as string[]
|
||||
).includes(event.type) &&
|
||||
version
|
||||
) {
|
||||
// Added new model w/ versions OR updated model that now has versions (it might not have had them previously)
|
||||
|
||||
@@ -54,16 +54,40 @@ export const settingsWorkspaceRegionsQuery = graphql(`
|
||||
`)
|
||||
|
||||
export const settingsWorkspacesMembersQuery = graphql(`
|
||||
query SettingsWorkspacesMembers(
|
||||
$slug: String!
|
||||
$invitesFilter: PendingWorkspaceCollaboratorsFilter
|
||||
$joinRequestsFilter: AdminWorkspaceJoinRequestFilter
|
||||
) {
|
||||
query SettingsWorkspacesMembers($slug: String!) {
|
||||
workspaceBySlug(slug: $slug) {
|
||||
...SettingsWorkspacesMembers_Workspace
|
||||
...SettingsWorkspacesMembersMembersTable_Workspace
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
export const settingsWorkspacesMembersTableQuery = graphql(`
|
||||
query SettingsWorkspacesMembersTable($slug: String!) {
|
||||
workspaceBySlug(slug: $slug) {
|
||||
...SettingsWorkspacesMembersTable_Workspace
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
export const settingsWorkspacesMembersGuestsQuery = graphql(`
|
||||
query SettingsWorkspacesMembersGuests($slug: String!) {
|
||||
workspaceBySlug(slug: $slug) {
|
||||
...SettingsWorkspacesMembersGuestsTable_Workspace
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
export const settingsWorkspacesMembersInvitesQuery = graphql(`
|
||||
query SettingsWorkspacesMembersInvites($slug: String!) {
|
||||
workspaceBySlug(slug: $slug) {
|
||||
...SettingsWorkspacesMembersInvitesTable_Workspace
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
export const settingsWorkspacesMembersRequestsQuery = graphql(`
|
||||
query SettingsWorkspacesMembersRequests($slug: String!) {
|
||||
workspaceBySlug(slug: $slug) {
|
||||
...SettingsWorkspacesMembersRequestsTable_Workspace
|
||||
}
|
||||
}
|
||||
@@ -76,25 +100,13 @@ export const settingsWorkspacesMembersSearchQuery = graphql(`
|
||||
team(filter: $filter) {
|
||||
items {
|
||||
id
|
||||
...SettingsWorkspacesMembersMembersTable_WorkspaceCollaborator
|
||||
...SettingsWorkspacesMembersTable_WorkspaceCollaborator
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
export const settingsWorkspacesJoinRequestsSearchQuery = graphql(`
|
||||
query SettingsWorkspacesJoinRequestsSearch(
|
||||
$slug: String!
|
||||
$joinRequestsFilter: AdminWorkspaceJoinRequestFilter
|
||||
) {
|
||||
workspaceBySlug(slug: $slug) {
|
||||
id
|
||||
...SettingsWorkspacesMembersRequestsTable_Workspace
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
export const settingsWorkspacesInvitesSearchQuery = graphql(`
|
||||
query SettingsWorkspacesInvitesSearch(
|
||||
$slug: String!
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import type { AvailableRoles } from '@speckle/shared'
|
||||
import { isObjectLike, has } from 'lodash'
|
||||
import type { WorkspacePlans } from '~/lib/common/generated/gql/graphql'
|
||||
|
||||
type BaseSettingsMenuItem = {
|
||||
title: string
|
||||
@@ -17,22 +15,3 @@ export type WorkspaceSettingsMenuItem = BaseSettingsMenuItem & {
|
||||
name: string
|
||||
route: (slug: string) => string
|
||||
}
|
||||
|
||||
export type WorkspacePricingPlans = {
|
||||
workspacePricingPlans: {
|
||||
workspacePlanInformation: {
|
||||
[key: string]: {
|
||||
name: WorkspacePlans
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function isWorkspacePricingPlans(
|
||||
pricingPlans: unknown
|
||||
): pricingPlans is WorkspacePricingPlans {
|
||||
return (
|
||||
isObjectLike(pricingPlans) &&
|
||||
has(pricingPlans, 'workspacePricingPlans.workspacePlanInformation')
|
||||
)
|
||||
}
|
||||
|
||||
@@ -87,17 +87,23 @@ export function useUserEmails() {
|
||||
return false
|
||||
}
|
||||
|
||||
const deleteUserEmail = async (email: UserEmail, cancel = false) => {
|
||||
const deleteUserEmail = async (options: {
|
||||
email: UserEmail
|
||||
hideToast?: boolean
|
||||
}) => {
|
||||
const { email, hideToast } = options
|
||||
const result = await deleteMutation({
|
||||
input: { id: email.id }
|
||||
}).catch(convertThrowIntoFetchResult)
|
||||
|
||||
if (result?.data) {
|
||||
triggerNotification({
|
||||
type: ToastNotificationType.Success,
|
||||
title: `${cancel ? 'Cancelled adding email' : 'Deleted email'}`,
|
||||
description: email.email
|
||||
})
|
||||
if (!hideToast) {
|
||||
triggerNotification({
|
||||
type: ToastNotificationType.Success,
|
||||
title: 'Deleted email',
|
||||
description: email.email
|
||||
})
|
||||
}
|
||||
mixpanel.track('Email Deleted')
|
||||
|
||||
// If we're on the verify email page and there are no more unverified emails, redirect home
|
||||
|
||||
@@ -3,9 +3,10 @@ import {
|
||||
approveWorkspaceJoinRequestMutation,
|
||||
denyWorkspaceJoinRequestMutation
|
||||
} from '~/lib/workspaces/graphql/mutations'
|
||||
import type {
|
||||
ApproveWorkspaceJoinRequestInput,
|
||||
DenyWorkspaceJoinRequestInput
|
||||
import {
|
||||
type ApproveWorkspaceJoinRequestInput,
|
||||
type DenyWorkspaceJoinRequestInput,
|
||||
WorkspaceJoinRequestStatus
|
||||
} from '~~/lib/common/generated/gql/graphql'
|
||||
import { ToastNotificationType, useGlobalToast } from '~~/lib/common/composables/toast'
|
||||
import {
|
||||
@@ -30,22 +31,11 @@ export const useWorkspaceJoinRequest = () => {
|
||||
{ input },
|
||||
{
|
||||
update: (cache) => {
|
||||
cache.evict({
|
||||
id: getCacheId('WorkspaceJoinRequest', requestId)
|
||||
})
|
||||
|
||||
modifyObjectField(
|
||||
cache,
|
||||
getCacheId('Workspace', input.workspaceId),
|
||||
'adminWorkspacesJoinRequests',
|
||||
({ helpers: { createUpdatedValue } }) => {
|
||||
return createUpdatedValue(({ update }) => {
|
||||
update('totalCount', (totalCount) => totalCount - 1)
|
||||
})
|
||||
},
|
||||
{
|
||||
autoEvictFiltered: true
|
||||
}
|
||||
getCacheId('WorkspaceJoinRequest', requestId),
|
||||
'status',
|
||||
() => WorkspaceJoinRequestStatus.Approved
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -76,22 +66,11 @@ export const useWorkspaceJoinRequest = () => {
|
||||
{ input },
|
||||
{
|
||||
update: (cache) => {
|
||||
cache.evict({
|
||||
id: getCacheId('WorkspaceJoinRequest', requestId)
|
||||
})
|
||||
|
||||
modifyObjectField(
|
||||
cache,
|
||||
getCacheId('Workspace', input.workspaceId),
|
||||
'adminWorkspacesJoinRequests',
|
||||
({ helpers: { createUpdatedValue } }) => {
|
||||
return createUpdatedValue(({ update }) => {
|
||||
update('totalCount', (totalCount) => totalCount - 1)
|
||||
})
|
||||
},
|
||||
{
|
||||
autoEvictFiltered: true
|
||||
}
|
||||
getCacheId('WorkspaceJoinRequest', requestId),
|
||||
'status',
|
||||
() => WorkspaceJoinRequestStatus.Denied
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,10 @@ export const workspaceTeamFragment = graphql(`
|
||||
}
|
||||
adminWorkspacesJoinRequests {
|
||||
totalCount
|
||||
items {
|
||||
status
|
||||
id
|
||||
}
|
||||
}
|
||||
...WorkspaceInvitedTeam_Workspace
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -73,7 +73,7 @@ export default defineNuxtRouteMiddleware(async (to) => {
|
||||
const apollo = useApolloClientFromNuxt()
|
||||
const resourceBuilder = () => SpeckleViewer.ViewerRoute.resourceBuilder()
|
||||
|
||||
if (['/streams', '/commits'].includes(path)) {
|
||||
if (['/streams', '/commits', '/streams/', '/commits/'].includes(path)) {
|
||||
return navigateTo(homeRoute)
|
||||
}
|
||||
|
||||
|
||||
@@ -70,11 +70,14 @@ export default defineNuxtConfig({
|
||||
datadogSite: '',
|
||||
datadogService: '',
|
||||
datadogEnv: '',
|
||||
enableDirectPreviews: true,
|
||||
ghostApiKey: ''
|
||||
}
|
||||
},
|
||||
|
||||
experimental: {
|
||||
emitRouteChunkError: 'automatic-immediate'
|
||||
},
|
||||
|
||||
alias: {
|
||||
// Rewriting all lodash calls to lodash-es for proper tree-shaking & chunk splitting
|
||||
// lodash: 'lodash-es'
|
||||
|
||||
@@ -89,11 +89,11 @@
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@datadog/datadog-ci": "^2.37.0",
|
||||
"@eslint/config-inspector": "^0.4.10",
|
||||
"@graphql-codegen/cli": "^5.0.3",
|
||||
"@graphql-codegen/client-preset": "^4.5.0",
|
||||
"@graphql-codegen/cli": "^5.0.5",
|
||||
"@graphql-codegen/client-preset": "^4.6.4",
|
||||
"@graphql-codegen/plugin-helpers": "^5.1.0",
|
||||
"@graphql-codegen/typescript": "^4.1.1",
|
||||
"@graphql-codegen/visitor-plugin-common": "5.5.0",
|
||||
"@graphql-codegen/typescript": "^4.1.5",
|
||||
"@graphql-codegen/visitor-plugin-common": "^5.7.1",
|
||||
"@nuxt/devtools": "^1.7.0",
|
||||
"@nuxt/eslint": "^1.1.0",
|
||||
"@nuxt/image": "^1.8.1",
|
||||
|
||||
@@ -183,7 +183,13 @@ const actionsItems = computed<LayoutMenuItem[][]>(() => {
|
||||
})
|
||||
|
||||
useHead({
|
||||
title: projectName
|
||||
title: projectName,
|
||||
meta: [
|
||||
{
|
||||
name: 'robots',
|
||||
content: 'noindex, nofollow'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const onInviteAccepted = async (params: { accepted: boolean }) => {
|
||||
|
||||
@@ -217,13 +217,14 @@ import {
|
||||
type PaidWorkspacePlans
|
||||
} from '~/lib/common/generated/gql/graphql'
|
||||
import { useBillingActions } from '~/lib/billing/composables/actions'
|
||||
import { pricingPlansConfig } from '~/lib/billing/helpers/constants'
|
||||
import type { PaidWorkspacePlansOld } from '@speckle/shared'
|
||||
import { Roles } from '@speckle/shared'
|
||||
import { InformationCircleIcon } from '@heroicons/vue/24/outline'
|
||||
import { isPaidPlan } from '@/lib/billing/helpers/types'
|
||||
import { useMixpanel } from '~/lib/core/composables/mp'
|
||||
import { guideBillingUrl } from '~/lib/common/helpers/route'
|
||||
import { adminUpdateWorkspacePlanMutation } from '~/lib/billing/graphql/mutations'
|
||||
import { WorkspaceOldPaidPlanPrices } from '~/lib/billing/helpers/constants'
|
||||
|
||||
graphql(`
|
||||
fragment SettingsWorkspacesBilling_Workspace on Workspace {
|
||||
@@ -280,15 +281,15 @@ const { billingPortalRedirect, redirectToCheckout } = useBillingActions()
|
||||
const mixpanel = useMixpanel()
|
||||
const { mutate: mutateWorkspacePlan } = useMutation(adminUpdateWorkspacePlanMutation)
|
||||
|
||||
const seatPrices = ref({
|
||||
[WorkspacePlans.Starter]: pricingPlansConfig.plans[WorkspacePlans.Starter].cost,
|
||||
[WorkspacePlans.Plus]: pricingPlansConfig.plans[WorkspacePlans.Plus].cost,
|
||||
[WorkspacePlans.Business]: pricingPlansConfig.plans[WorkspacePlans.Business].cost
|
||||
})
|
||||
const selectedPlanName = ref<WorkspacePlans>()
|
||||
const selectedPlanName = ref<PaidWorkspacePlansOld>()
|
||||
const selectedPlanCycle = ref<BillingInterval>()
|
||||
const isUpgradeDialogOpen = ref(false)
|
||||
|
||||
const seatPrices = computed(() => ({
|
||||
[WorkspacePlans.Starter]: WorkspaceOldPaidPlanPrices[WorkspacePlans.Starter],
|
||||
[WorkspacePlans.Plus]: WorkspaceOldPaidPlanPrices[WorkspacePlans.Plus],
|
||||
[WorkspacePlans.Business]: WorkspaceOldPaidPlanPrices[WorkspacePlans.Business]
|
||||
}))
|
||||
const workspace = computed(() => workspaceResult.value?.workspaceBySlug)
|
||||
const currentPlan = computed(() => workspace.value?.plan)
|
||||
const subscription = computed(() => workspace.value?.subscription)
|
||||
@@ -422,7 +423,10 @@ const showStatusBadge = computed(() => {
|
||||
)
|
||||
})
|
||||
|
||||
const onPlanSelected = (plan: { name: WorkspacePlans; cycle: BillingInterval }) => {
|
||||
const onPlanSelected = (plan: {
|
||||
name: PaidWorkspacePlansOld
|
||||
cycle: BillingInterval
|
||||
}) => {
|
||||
const { name, cycle } = plan
|
||||
if (!isPaidPlan(name) || !workspace.value?.id) return
|
||||
|
||||
|
||||
@@ -244,11 +244,13 @@ const canDeleteWorkspace = computed(
|
||||
!needsSsoLogin.value &&
|
||||
(!isBillingIntegrationEnabled ||
|
||||
!(
|
||||
[
|
||||
WorkspacePlanStatuses.Valid,
|
||||
WorkspacePlanStatuses.PaymentFailed,
|
||||
WorkspacePlanStatuses.CancelationScheduled
|
||||
].includes(
|
||||
(
|
||||
[
|
||||
WorkspacePlanStatuses.Valid,
|
||||
WorkspacePlanStatuses.PaymentFailed,
|
||||
WorkspacePlanStatuses.CancelationScheduled
|
||||
] as string[]
|
||||
).includes(
|
||||
workspaceResult.value?.workspaceBySlug?.plan?.status as WorkspacePlanStatuses
|
||||
) && isPaidPlan(workspaceResult.value?.workspaceBySlug?.plan?.name)
|
||||
))
|
||||
|
||||
@@ -8,28 +8,7 @@
|
||||
class="mb-6"
|
||||
/>
|
||||
<LayoutTabsHorizontal v-model:active-item="activeTab" :items="tabItems">
|
||||
<template #default="{ activeItem }">
|
||||
<SettingsWorkspacesMembersTable
|
||||
v-if="activeItem.id === 'members'"
|
||||
:workspace="workspace"
|
||||
:workspace-slug="slug"
|
||||
/>
|
||||
<SettingsWorkspacesMembersGuestsTable
|
||||
v-if="activeItem.id === 'guests'"
|
||||
:workspace="workspace"
|
||||
:workspace-slug="slug"
|
||||
/>
|
||||
<SettingsWorkspacesMembersInvitesTable
|
||||
v-if="activeItem.id === 'invites'"
|
||||
:workspace="workspace"
|
||||
:workspace-slug="slug"
|
||||
/>
|
||||
<SettingsWorkspacesMembersJoinRequestsTable
|
||||
v-if="activeItem.id === 'joinRequests'"
|
||||
:workspace="workspace"
|
||||
:workspace-slug="slug"
|
||||
/>
|
||||
</template>
|
||||
<NuxtPage />
|
||||
</LayoutTabsHorizontal>
|
||||
</div>
|
||||
</section>
|
||||
@@ -42,7 +21,8 @@ import { graphql } from '~/lib/common/generated/gql'
|
||||
import { settingsWorkspacesMembersQuery } from '~/lib/settings/graphql/queries'
|
||||
import type { LayoutPageTabItem } from '~~/lib/layout/helpers/components'
|
||||
import { useOnWorkspaceUpdated } from '~/lib/workspaces/composables/management'
|
||||
import { WorkspaceJoinRequestStatus } from '~/lib/common/generated/gql/graphql'
|
||||
import { WorkspaceJoinRequestStatus } from '~~/lib/common/generated/gql/graphql'
|
||||
import { settingsWorkspaceRoutes } from '~/lib/common/helpers/route'
|
||||
|
||||
graphql(`
|
||||
fragment SettingsWorkspacesMembers_Workspace on Workspace {
|
||||
@@ -51,14 +31,19 @@ graphql(`
|
||||
team {
|
||||
items {
|
||||
id
|
||||
role
|
||||
}
|
||||
}
|
||||
invitedTeam(filter: $invitesFilter) {
|
||||
invitedTeam {
|
||||
user {
|
||||
id
|
||||
}
|
||||
}
|
||||
adminWorkspacesJoinRequests(filter: $joinRequestsFilter) {
|
||||
adminWorkspacesJoinRequests {
|
||||
items {
|
||||
id
|
||||
status
|
||||
}
|
||||
totalCount
|
||||
}
|
||||
}
|
||||
@@ -75,11 +60,9 @@ useHead({
|
||||
const route = useRoute()
|
||||
const slug = computed(() => (route.params.slug as string) || '')
|
||||
|
||||
const router = useRouter()
|
||||
const { result } = useQuery(settingsWorkspacesMembersQuery, () => ({
|
||||
slug: slug.value,
|
||||
joinRequestsFilter: {
|
||||
status: WorkspaceJoinRequestStatus.Pending
|
||||
}
|
||||
slug: slug.value
|
||||
}))
|
||||
|
||||
const workspace = computed(() => result.value?.workspaceBySlug)
|
||||
@@ -96,7 +79,10 @@ const guestCount = computed(
|
||||
)
|
||||
const invitedCount = computed(() => workspace.value?.invitedTeam?.length)
|
||||
const joinRequestCount = computed(
|
||||
() => workspace.value?.adminWorkspacesJoinRequests?.totalCount
|
||||
() =>
|
||||
workspace.value?.adminWorkspacesJoinRequests?.items.filter(
|
||||
(item) => item.status === WorkspaceJoinRequestStatus.Pending
|
||||
).length
|
||||
)
|
||||
const tabItems = computed<LayoutPageTabItem[]>(() => [
|
||||
{ title: 'Members', id: 'members', count: memberCount.value },
|
||||
@@ -117,7 +103,32 @@ const tabItems = computed<LayoutPageTabItem[]>(() => [
|
||||
}
|
||||
])
|
||||
|
||||
const activeTab = ref(tabItems.value[0])
|
||||
const activeTab = computed({
|
||||
get: () => {
|
||||
const path = route.path
|
||||
if (path.includes('/members/guests')) return tabItems.value[1]
|
||||
if (path.includes('/members/invites')) return tabItems.value[2]
|
||||
if (path.includes('/members/requests')) return tabItems.value[3]
|
||||
if (path.includes('/members')) return tabItems.value[0]
|
||||
return tabItems.value[0]
|
||||
},
|
||||
set: (val: LayoutPageTabItem) => {
|
||||
switch (val.id) {
|
||||
case 'members':
|
||||
router.push(settingsWorkspaceRoutes.members.route(slug.value))
|
||||
break
|
||||
case 'guests':
|
||||
router.push(settingsWorkspaceRoutes.membersGuests.route(slug.value))
|
||||
break
|
||||
case 'invites':
|
||||
router.push(settingsWorkspaceRoutes.membersInvites.route(slug.value))
|
||||
break
|
||||
case 'joinRequests':
|
||||
router.push(settingsWorkspaceRoutes.membersRequests.route(slug.value))
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
useOnWorkspaceUpdated({ workspaceSlug: slug })
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<template>
|
||||
<SettingsWorkspacesMembersGuestsTable :workspace="workspace" :workspace-slug="slug" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import { settingsWorkspacesMembersGuestsQuery } from '~/lib/settings/graphql/queries'
|
||||
|
||||
const route = useRoute()
|
||||
const slug = computed(() => (route.params.slug as string) || '')
|
||||
|
||||
const { result } = useQuery(settingsWorkspacesMembersGuestsQuery, () => ({
|
||||
slug: slug.value
|
||||
}))
|
||||
|
||||
const workspace = computed(() => result.value?.workspaceBySlug)
|
||||
</script>
|
||||
@@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<SettingsWorkspacesMembersTable :workspace="workspace" :workspace-slug="slug" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import { settingsWorkspacesMembersTableQuery } from '~/lib/settings/graphql/queries'
|
||||
|
||||
const route = useRoute()
|
||||
const slug = computed(() => (route.params.slug as string) || '')
|
||||
const { result } = useQuery(settingsWorkspacesMembersTableQuery, () => ({
|
||||
slug: slug.value
|
||||
}))
|
||||
const workspace = computed(() => result.value?.workspaceBySlug)
|
||||
</script>
|
||||
@@ -0,0 +1,20 @@
|
||||
<template>
|
||||
<SettingsWorkspacesMembersInvitesTable
|
||||
:workspace="workspace"
|
||||
:workspace-slug="slug"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import { settingsWorkspacesMembersInvitesQuery } from '~/lib/settings/graphql/queries'
|
||||
|
||||
const route = useRoute()
|
||||
const slug = computed(() => (route.params.slug as string) || '')
|
||||
|
||||
const { result } = useQuery(settingsWorkspacesMembersInvitesQuery, () => ({
|
||||
slug: slug.value
|
||||
}))
|
||||
|
||||
const workspace = computed(() => result.value?.workspaceBySlug)
|
||||
</script>
|
||||
@@ -0,0 +1,20 @@
|
||||
<template>
|
||||
<SettingsWorkspacesMembersJoinRequestsTable
|
||||
:workspace="workspace"
|
||||
:workspace-slug="slug"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import { settingsWorkspacesMembersRequestsQuery } from '~/lib/settings/graphql/queries'
|
||||
|
||||
const route = useRoute()
|
||||
const slug = computed(() => (route.params.slug as string) || '')
|
||||
|
||||
const { result } = useQuery(settingsWorkspacesMembersRequestsQuery, () => ({
|
||||
slug: slug.value
|
||||
}))
|
||||
|
||||
const workspace = computed(() => result.value?.workspaceBySlug)
|
||||
</script>
|
||||
@@ -73,7 +73,7 @@
|
||||
<SettingsUserEmailDeleteDialog
|
||||
v-model:open="showDeleteDialog"
|
||||
:email="currentEmail"
|
||||
cancel
|
||||
is-adding
|
||||
/>
|
||||
</div>
|
||||
</HeaderWithEmptyPage>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { collectLongTrace } from '@speckle/shared'
|
||||
import { omit } from 'lodash-es'
|
||||
import type { SetRequired } from 'type-fest'
|
||||
import { useReadUserId } from '~/lib/auth/composables/activeUser'
|
||||
@@ -170,6 +171,7 @@ export default defineNuxtPlugin(async (nuxtApp) => {
|
||||
}) => {
|
||||
if (!args.length) return
|
||||
|
||||
const stack = collectLongTrace()
|
||||
const isError = ['error', 'fatal'].includes(level)
|
||||
const isImportant = !!otherData?.important
|
||||
if (!isError && !isImportant) return
|
||||
@@ -189,6 +191,9 @@ export default defineNuxtPlugin(async (nuxtApp) => {
|
||||
properties: {
|
||||
mainSeqErrorMessage: errorMessage, // weird name to avoid collision with otherData
|
||||
extraData: nonObjectOtherData,
|
||||
stack,
|
||||
firstError,
|
||||
firstString,
|
||||
...otherData,
|
||||
...collectCoreInfo()
|
||||
},
|
||||
@@ -202,6 +207,7 @@ export default defineNuxtPlugin(async (nuxtApp) => {
|
||||
properties: {
|
||||
extraData: nonObjectOtherData,
|
||||
firstError,
|
||||
stack,
|
||||
...otherData,
|
||||
...collectCoreInfo()
|
||||
}
|
||||
@@ -318,7 +324,8 @@ export default defineNuxtPlugin(async (nuxtApp) => {
|
||||
if (!import.meta.server) {
|
||||
nuxtApp.hook('app:mounted', () => {
|
||||
logger.info('App mounted in the client', {
|
||||
important: true
|
||||
important: true,
|
||||
speckleServerVersion
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -22,9 +22,7 @@
|
||||
"imports": {
|
||||
"#lodash": {
|
||||
"require": "lodash",
|
||||
"import": "lodash-es",
|
||||
"node": "lodash",
|
||||
"default": "lodash-es"
|
||||
"import": "lodash-es"
|
||||
}
|
||||
},
|
||||
"homepage": "https://speckle.systems",
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@typescript-eslint/eslint-plugin": "^7.12.0",
|
||||
"@typescript-eslint/parser": "^7.12.0",
|
||||
"@vitest/coverage-v8": "^1.6.0",
|
||||
"@vitest/coverage-v8": "^3.0.7",
|
||||
"eslint": "^9.4.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"prettier": "^3.3.2",
|
||||
@@ -54,21 +54,19 @@
|
||||
"exports": {
|
||||
".": {
|
||||
"import": {
|
||||
"default": "./dist/objectsender.js",
|
||||
"types": "./dist/index.d.ts"
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/objectsender.js"
|
||||
},
|
||||
"require": {
|
||||
"default": "./dist/objectsender.cjs",
|
||||
"types": "./dist/index.d.ts"
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/objectsender.cjs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"imports": {
|
||||
"#lodash": {
|
||||
"require": "lodash",
|
||||
"import": "lodash-es",
|
||||
"node": "lodash",
|
||||
"default": "lodash-es"
|
||||
"import": "lodash-es"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-3
@@ -1,3 +1 @@
|
||||
{
|
||||
"vitest.disableWorkspaceWarning": true
|
||||
}
|
||||
{}
|
||||
|
||||
+14
-135
@@ -31,8 +31,7 @@ import { expressMiddleware } from '@apollo/server/express4'
|
||||
import { ApolloServerPluginLandingPageLocalDefault } from '@apollo/server/plugin/landingPage/default'
|
||||
import { ApolloServerPluginUsageReporting } from '@apollo/server/plugin/usageReporting'
|
||||
import { ApolloServerPluginUsageReportingDisabled } from '@apollo/server/plugin/disabled'
|
||||
|
||||
import type { ConnectionContext, ExecutionParams } from 'subscriptions-transport-ws'
|
||||
import type { ConnectionContext } from 'subscriptions-transport-ws'
|
||||
import { SubscriptionServer } from 'subscriptions-transport-ws'
|
||||
import { execute, subscribe } from 'graphql'
|
||||
|
||||
@@ -67,15 +66,12 @@ import {
|
||||
requestBodyParsingMiddlewareFactory,
|
||||
setContentSecurityPolicyHeaderMiddleware
|
||||
} from '@/modules/shared/middleware'
|
||||
import { GraphQLError } from 'graphql'
|
||||
import { redactSensitiveVariables } from '@/logging/loggingHelper'
|
||||
import { buildMocksConfig } from '@/modules/mocks'
|
||||
import { defaultErrorHandler } from '@/modules/core/rest/defaultErrorHandler'
|
||||
import { migrateDbToLatest } from '@/db/migrations'
|
||||
import { statusCodePlugin } from '@/modules/core/graph/plugins/statusCode'
|
||||
import { BadRequestError, BaseError, ForbiddenError } from '@/modules/shared/errors'
|
||||
import { BadRequestError, ForbiddenError } from '@/modules/shared/errors'
|
||||
import { loggingPluginFactory } from '@/modules/core/graph/plugins/logging'
|
||||
import { shouldLogAsInfoLevel } from '@/logging/graphqlError'
|
||||
import { getUserFactory } from '@/modules/core/repositories/users'
|
||||
import { initFactory as healthchecksInitFactory } from '@/healthchecks'
|
||||
import type { ReadinessHandler } from '@/healthchecks/types'
|
||||
@@ -88,62 +84,16 @@ import {
|
||||
initiateRequestContextMiddleware
|
||||
} from '@/logging/requestContext'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { onOperationHandlerFactory } from '@/logging/apolloSubscriptions'
|
||||
import { initApolloSubscriptionMonitoring } from './logging/apolloSubscriptionMonitoring'
|
||||
|
||||
const GRAPHQL_PATH = '/graphql'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type SubscriptionResponse = { errors?: GraphQLError[]; data?: any }
|
||||
|
||||
/**
|
||||
* In mocked Ws connections, request will be undefined
|
||||
*/
|
||||
type PossiblyMockedConnectionContext = SetOptional<ConnectionContext, 'request'>
|
||||
|
||||
function logSubscriptionOperation(params: {
|
||||
ctx: GraphQLContext
|
||||
execParams: ExecutionParams
|
||||
error?: Error
|
||||
response?: SubscriptionResponse
|
||||
}) {
|
||||
const { error, response, ctx, execParams } = params
|
||||
const userId = ctx.userId
|
||||
if (!error && !response) return
|
||||
|
||||
const reqCtx = getRequestContext()
|
||||
|
||||
const logger = ctx.log.child({
|
||||
graphql_query: execParams.query.toString(),
|
||||
graphql_variables: redactSensitiveVariables(execParams.variables),
|
||||
graphql_operation_name: execParams.operationName,
|
||||
graphql_operation_type: 'subscription',
|
||||
userId,
|
||||
...(reqCtx
|
||||
? {
|
||||
req: { id: reqCtx.requestId },
|
||||
dbMetrics: reqCtx.dbMetrics
|
||||
}
|
||||
: {})
|
||||
})
|
||||
|
||||
const errMsg = 'GQL subscription event {graphql_operation_name} errored'
|
||||
const errors = response?.errors || (error ? [error] : [])
|
||||
if (errors.length) {
|
||||
for (const error of errors) {
|
||||
let errorLogger = logger
|
||||
if (error instanceof BaseError) {
|
||||
errorLogger = errorLogger.child({ ...error.info() })
|
||||
}
|
||||
if (shouldLogAsInfoLevel(error)) {
|
||||
errorLogger.info({ err: error }, errMsg)
|
||||
} else {
|
||||
errorLogger.error({ err: error }, errMsg)
|
||||
}
|
||||
}
|
||||
} else if (response?.data) {
|
||||
logger.info('GQL subscription event {graphql_operation_name} emitted')
|
||||
}
|
||||
}
|
||||
|
||||
const isWsServer = (server: http.Server | MockWsServer): server is MockWsServer => {
|
||||
return 'on' in server && 'clients' in server
|
||||
}
|
||||
@@ -163,35 +113,12 @@ export function buildApolloSubscriptionServer(
|
||||
const wsServer = mockServer ? (mockServer as unknown as ws.Server) : undefined
|
||||
const schema = ModulesSetup.graphSchema()
|
||||
|
||||
// Init metrics
|
||||
prometheusClient.register.removeSingleMetric('speckle_server_apollo_connect')
|
||||
const metricConnectCounter = new prometheusClient.Counter({
|
||||
name: 'speckle_server_apollo_connect',
|
||||
help: 'Number of connects'
|
||||
})
|
||||
prometheusClient.register.removeSingleMetric('speckle_server_apollo_clients')
|
||||
const metricConnectedClients = new prometheusClient.Gauge({
|
||||
name: 'speckle_server_apollo_clients',
|
||||
help: 'Number of currently connected clients'
|
||||
})
|
||||
|
||||
prometheusClient.register.removeSingleMetric(
|
||||
'speckle_server_apollo_graphql_total_subscription_operations'
|
||||
)
|
||||
const metricSubscriptionTotalOperations = new prometheusClient.Counter({
|
||||
name: 'speckle_server_apollo_graphql_total_subscription_operations',
|
||||
help: 'Number of total subscription operations served by this instance',
|
||||
labelNames: ['subscriptionType'] as const
|
||||
})
|
||||
|
||||
prometheusClient.register.removeSingleMetric(
|
||||
'speckle_server_apollo_graphql_total_subscription_responses'
|
||||
)
|
||||
const metricSubscriptionTotalResponses = new prometheusClient.Counter({
|
||||
name: 'speckle_server_apollo_graphql_total_subscription_responses',
|
||||
help: 'Number of total subscription responses served by this instance',
|
||||
labelNames: ['subscriptionType', 'status'] as const
|
||||
})
|
||||
const {
|
||||
metricConnectCounter,
|
||||
metricConnectedClients,
|
||||
metricSubscriptionTotalOperations,
|
||||
metricSubscriptionTotalResponses
|
||||
} = initApolloSubscriptionMonitoring()
|
||||
|
||||
const getHeaders = (params: {
|
||||
connContext?: PossiblyMockedConnectionContext
|
||||
@@ -302,58 +229,10 @@ export function buildApolloSubscriptionServer(
|
||||
)
|
||||
metricConnectedClients.dec()
|
||||
},
|
||||
onOperation: (...params: [() => void, ExecutionParams]) => {
|
||||
// kinda hacky, but we're using this as an "subscription event emitted"
|
||||
// callback to clear subscription connection dataloaders to avoid stale cache
|
||||
const baseParams = params[1]
|
||||
|
||||
metricSubscriptionTotalOperations.inc({
|
||||
subscriptionType: baseParams.operationName // FIXME: operationName can be empty
|
||||
})
|
||||
const ctx = baseParams.context as GraphQLContext
|
||||
|
||||
const reqCtx = getRequestContext()
|
||||
if (reqCtx) {
|
||||
// Reset db metrics for each event
|
||||
reqCtx.dbMetrics.totalCount = 0
|
||||
reqCtx.dbMetrics.totalDuration = 0
|
||||
}
|
||||
|
||||
const logger = ctx.log || subscriptionLogger
|
||||
logger.info(
|
||||
{
|
||||
graphql_operation_name: baseParams.operationName,
|
||||
userId: baseParams.context.userId,
|
||||
graphql_query: baseParams.query.toString(),
|
||||
graphql_variables: redactSensitiveVariables(baseParams.variables),
|
||||
graphql_operation_type: 'subscription',
|
||||
...(reqCtx ? { req: { id: reqCtx.requestId } } : {})
|
||||
},
|
||||
'Subscription event fired for {graphql_operation_name}'
|
||||
)
|
||||
|
||||
baseParams.formatResponse = (val: SubscriptionResponse) => {
|
||||
ctx.loaders.clearAll()
|
||||
logSubscriptionOperation({ ctx, execParams: baseParams, response: val })
|
||||
metricSubscriptionTotalResponses.inc({
|
||||
subscriptionType: baseParams.operationName,
|
||||
status: 'success'
|
||||
})
|
||||
return val
|
||||
}
|
||||
baseParams.formatError = (e: Error) => {
|
||||
ctx.loaders.clearAll()
|
||||
logSubscriptionOperation({ ctx, execParams: baseParams, error: e })
|
||||
|
||||
metricSubscriptionTotalResponses.inc({
|
||||
subscriptionType: baseParams.operationName,
|
||||
status: 'error'
|
||||
})
|
||||
return e
|
||||
}
|
||||
|
||||
return baseParams
|
||||
},
|
||||
onOperation: onOperationHandlerFactory({
|
||||
metricSubscriptionTotalOperations,
|
||||
metricSubscriptionTotalResponses
|
||||
}),
|
||||
keepAlive: 30000 //milliseconds. Loadbalancers may close the connection after inactivity. e.g. nginx default is 60000ms.
|
||||
},
|
||||
wsServer || {
|
||||
|
||||
@@ -173,11 +173,17 @@ type UserSearchResultCollection {
|
||||
items: [LimitedUser!]!
|
||||
}
|
||||
|
||||
input OnboardingCompletionInput {
|
||||
role: String
|
||||
plans: [String!]
|
||||
source: String
|
||||
}
|
||||
|
||||
type ActiveUserMutations {
|
||||
"""
|
||||
Mark onboarding as complete
|
||||
"""
|
||||
finishOnboarding: Boolean!
|
||||
finishOnboarding(input: OnboardingCompletionInput): Boolean!
|
||||
|
||||
"""
|
||||
Edit a user's profile
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
extend type Query {
|
||||
workspacePricingPlans: JSONObject!
|
||||
}
|
||||
|
||||
extend type WorkspaceMutations {
|
||||
billing: WorkspaceBillingMutations! @hasScope(scope: "workspace:billing")
|
||||
}
|
||||
@@ -66,6 +62,8 @@ enum WorkspacePlans {
|
||||
starterInvoiced
|
||||
plusInvoiced
|
||||
businessInvoiced
|
||||
team
|
||||
pro
|
||||
}
|
||||
|
||||
enum WorkspacePlanStatuses {
|
||||
|
||||
@@ -23,3 +23,32 @@ type WorkspaceJoinRequestMutations {
|
||||
@hasScope(scope: "workspace:update")
|
||||
@hasWorkspaceRole(role: ADMIN)
|
||||
}
|
||||
|
||||
type LimitedWorkspaceJoinRequest {
|
||||
id: String!
|
||||
workspace: LimitedWorkspace!
|
||||
user: LimitedUser!
|
||||
status: WorkspaceJoinRequestStatus!
|
||||
createdAt: DateTime!
|
||||
}
|
||||
|
||||
type LimitedWorkspaceJoinRequestCollection {
|
||||
totalCount: Int!
|
||||
cursor: String
|
||||
items: [LimitedWorkspaceJoinRequest!]!
|
||||
}
|
||||
|
||||
input WorkspaceJoinRequestFilter {
|
||||
status: WorkspaceJoinRequestStatus
|
||||
}
|
||||
|
||||
extend type User {
|
||||
workspaceJoinRequests(
|
||||
filter: WorkspaceJoinRequestFilter
|
||||
cursor: String
|
||||
limit: Int! = 25
|
||||
): LimitedWorkspaceJoinRequestCollection
|
||||
@hasServerRole(role: SERVER_GUEST)
|
||||
@hasScope(scope: "workspace:read")
|
||||
@isOwner
|
||||
}
|
||||
|
||||
@@ -367,6 +367,20 @@ type LimitedWorkspace {
|
||||
Optional base64 encoded workspace logo image
|
||||
"""
|
||||
logo: String
|
||||
"""
|
||||
Workspace members visible to people with verified email domain
|
||||
"""
|
||||
team(cursor: String, limit: Int! = 25): DiscoverableWorkspaceCollaboratorCollection
|
||||
}
|
||||
|
||||
type DiscoverableWorkspaceCollaboratorCollection {
|
||||
totalCount: Int!
|
||||
cursor: String
|
||||
items: [DiscoverableWorkspaceCollaborator!]!
|
||||
}
|
||||
|
||||
type DiscoverableWorkspaceCollaborator {
|
||||
avatar: String
|
||||
}
|
||||
|
||||
type WorkspaceDomain {
|
||||
|
||||
@@ -8,6 +8,7 @@ generates:
|
||||
- 'typescript'
|
||||
- 'typescript-resolvers'
|
||||
config:
|
||||
enumsAsConst: true
|
||||
contextType: '@/modules/shared/helpers/typeHelper#GraphQLContext'
|
||||
mappers:
|
||||
Stream: '@/modules/core/helpers/graphTypes#StreamGraphQLReturn'
|
||||
@@ -66,6 +67,7 @@ generates:
|
||||
PendingWorkspaceCollaborator: '@/modules/workspacesCore/helpers/graphTypes#PendingWorkspaceCollaboratorGraphQLReturn'
|
||||
WorkspaceCollaborator: '@/modules/workspacesCore/helpers/graphTypes#WorkspaceCollaboratorGraphQLReturn'
|
||||
WorkspaceJoinRequest: '@/modules/workspacesCore/helpers/graphTypes#WorkspaceJoinRequestGraphQLReturn'
|
||||
LimitedWorkspaceJoinRequest: '@/modules/workspacesCore/helpers/graphTypes#LimitedWorkspaceJoinRequestGraphQLReturn'
|
||||
Webhook: '@/modules/webhooks/helpers/graphTypes#WebhookGraphQLReturn'
|
||||
SmartTextEditorValue: '@/modules/core/services/richTextEditorService#SmartTextEditorValueGraphQLReturn'
|
||||
BlobMetadata: '@/modules/blobstorage/domain/types#BlobStorageItem'
|
||||
@@ -88,6 +90,7 @@ generates:
|
||||
documents:
|
||||
- 'modules/cross-server-sync/**/*.{js,ts}'
|
||||
config:
|
||||
enumsAsConst: true
|
||||
scalars:
|
||||
JSONObject: Record<string, unknown>
|
||||
DateTime: string
|
||||
@@ -100,10 +103,12 @@ generates:
|
||||
- 'test/graphql/*.{js,ts}'
|
||||
- 'modules/**/tests/helpers/graphql.ts'
|
||||
config:
|
||||
enumsAsConst: true
|
||||
scalars:
|
||||
JSONObject: Record<string, unknown>
|
||||
DateTime: string
|
||||
config:
|
||||
enumsAsConst: true
|
||||
scalars:
|
||||
JSONObject: Record<string, unknown>
|
||||
DateTime: Date
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
import prometheusClient from 'prom-client'
|
||||
|
||||
let apolloSubscriptionMonitoringIsInitialized = false
|
||||
|
||||
let metricConnectCounter: prometheusClient.Counter<string>
|
||||
let metricConnectedClients: prometheusClient.Gauge<string>
|
||||
let metricSubscriptionTotalOperations: prometheusClient.Counter<'subscriptionType'>
|
||||
let metricSubscriptionTotalResponses: prometheusClient.Counter<
|
||||
'subscriptionType' | 'status'
|
||||
>
|
||||
|
||||
export const initApolloSubscriptionMonitoring = () => {
|
||||
if (apolloSubscriptionMonitoringIsInitialized)
|
||||
return {
|
||||
metricConnectCounter,
|
||||
metricConnectedClients,
|
||||
metricSubscriptionTotalOperations,
|
||||
metricSubscriptionTotalResponses
|
||||
}
|
||||
|
||||
// Init metrics
|
||||
prometheusClient.register.removeSingleMetric('speckle_server_apollo_connect')
|
||||
metricConnectCounter = new prometheusClient.Counter({
|
||||
name: 'speckle_server_apollo_connect',
|
||||
help: 'Number of connects'
|
||||
})
|
||||
prometheusClient.register.removeSingleMetric('speckle_server_apollo_clients')
|
||||
metricConnectedClients = new prometheusClient.Gauge({
|
||||
name: 'speckle_server_apollo_clients',
|
||||
help: 'Number of currently connected clients'
|
||||
})
|
||||
|
||||
prometheusClient.register.removeSingleMetric(
|
||||
'speckle_server_apollo_graphql_total_subscription_operations'
|
||||
)
|
||||
metricSubscriptionTotalOperations = new prometheusClient.Counter({
|
||||
name: 'speckle_server_apollo_graphql_total_subscription_operations',
|
||||
help: 'Number of total subscription operations served by this instance',
|
||||
labelNames: ['subscriptionType'] as const
|
||||
})
|
||||
|
||||
prometheusClient.register.removeSingleMetric(
|
||||
'speckle_server_apollo_graphql_total_subscription_responses'
|
||||
)
|
||||
metricSubscriptionTotalResponses = new prometheusClient.Counter({
|
||||
name: 'speckle_server_apollo_graphql_total_subscription_responses',
|
||||
help: 'Number of total subscription responses served by this instance',
|
||||
labelNames: ['subscriptionType', 'status'] as const
|
||||
})
|
||||
|
||||
apolloSubscriptionMonitoringIsInitialized = true
|
||||
|
||||
return {
|
||||
metricConnectCounter,
|
||||
metricConnectedClients,
|
||||
metricSubscriptionTotalOperations,
|
||||
metricSubscriptionTotalResponses
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/* eslint-disable camelcase */
|
||||
import type { GraphQLContext } from '@/modules/shared/helpers/typeHelper'
|
||||
import type { ExecutionParams } from 'subscriptions-transport-ws'
|
||||
import { shouldLogAsInfoLevel, shouldLogAsWarnLevel } from '@/logging/graphqlError'
|
||||
import { BaseError } from '@/modules/shared/errors'
|
||||
import { GraphQLError } from 'graphql'
|
||||
import { redactSensitiveVariables } from '@/logging/loggingHelper'
|
||||
import type { Counter } from 'prom-client'
|
||||
import { getRequestContext } from '@/logging/requestContext'
|
||||
import { subscriptionLogger } from '@/logging/logging'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type SubscriptionResponse = { errors?: GraphQLError[]; data?: any }
|
||||
|
||||
export const onOperationHandlerFactory = (deps: {
|
||||
metricSubscriptionTotalOperations: Counter<'subscriptionType' | 'status'>
|
||||
metricSubscriptionTotalResponses: Counter<'subscriptionType' | 'status'>
|
||||
}) => {
|
||||
const { metricSubscriptionTotalOperations, metricSubscriptionTotalResponses } = deps
|
||||
return (...params: [() => void, ExecutionParams]) => {
|
||||
// kinda hacky, but we're using this as an "subscription event emitted"
|
||||
// callback to clear subscription connection dataloaders to avoid stale cache
|
||||
const baseParams = params[1]
|
||||
|
||||
metricSubscriptionTotalOperations.inc({
|
||||
subscriptionType: baseParams.operationName // FIXME: operationName can be empty
|
||||
})
|
||||
const ctx = baseParams.context as GraphQLContext
|
||||
|
||||
const reqCtx = getRequestContext()
|
||||
if (reqCtx) {
|
||||
// Reset db metrics for each event
|
||||
reqCtx.dbMetrics.totalCount = 0
|
||||
reqCtx.dbMetrics.totalDuration = 0
|
||||
}
|
||||
|
||||
const logger = ctx.log || subscriptionLogger
|
||||
logger.info(
|
||||
{
|
||||
graphql_operation_name: baseParams.operationName,
|
||||
userId: baseParams.context.userId,
|
||||
graphql_query: baseParams.query.toString(),
|
||||
graphql_variables: redactSensitiveVariables(baseParams.variables),
|
||||
graphql_operation_type: 'subscription',
|
||||
...(reqCtx ? { req: { id: reqCtx.requestId } } : {})
|
||||
},
|
||||
'Subscription event fired for {graphql_operation_name}'
|
||||
)
|
||||
|
||||
baseParams.formatResponse = (val: SubscriptionResponse) => {
|
||||
ctx.loaders.clearAll()
|
||||
logSubscriptionOperation({ ctx, execParams: baseParams, response: val })
|
||||
metricSubscriptionTotalResponses.inc({
|
||||
subscriptionType: baseParams.operationName,
|
||||
status: 'success'
|
||||
})
|
||||
return val
|
||||
}
|
||||
baseParams.formatError = (e: Error) => {
|
||||
ctx.loaders.clearAll()
|
||||
logSubscriptionOperation({ ctx, execParams: baseParams, error: e })
|
||||
|
||||
metricSubscriptionTotalResponses.inc({
|
||||
subscriptionType: baseParams.operationName,
|
||||
status: 'error'
|
||||
})
|
||||
return e
|
||||
}
|
||||
|
||||
return baseParams
|
||||
}
|
||||
}
|
||||
|
||||
export function logSubscriptionOperation(params: {
|
||||
ctx: GraphQLContext
|
||||
execParams: ExecutionParams
|
||||
error?: Error
|
||||
response?: SubscriptionResponse
|
||||
}) {
|
||||
const { error, response, ctx, execParams } = params
|
||||
const userId = ctx.userId
|
||||
if (!error && !response) return
|
||||
|
||||
const reqCtx = getRequestContext()
|
||||
|
||||
const logger = ctx.log.child({
|
||||
graphql_query: execParams.query.toString(),
|
||||
graphql_variables: redactSensitiveVariables(execParams.variables),
|
||||
graphql_operation_name: execParams.operationName,
|
||||
graphql_operation_type: 'subscription',
|
||||
userId,
|
||||
...(reqCtx
|
||||
? {
|
||||
req: { id: reqCtx.requestId },
|
||||
dbMetrics: reqCtx.dbMetrics
|
||||
}
|
||||
: {})
|
||||
})
|
||||
|
||||
const errMsg = 'GQL subscription event {graphql_operation_name} errored'
|
||||
const errors = response?.errors || (error ? [error] : [])
|
||||
if (errors.length) {
|
||||
for (const error of errors) {
|
||||
let errorLogger = logger
|
||||
if (error instanceof BaseError) {
|
||||
errorLogger = errorLogger.child({ ...error.info() })
|
||||
}
|
||||
if (shouldLogAsInfoLevel(error)) {
|
||||
errorLogger.info({ err: error }, errMsg)
|
||||
} else if (shouldLogAsWarnLevel(error)) {
|
||||
errorLogger.warn({ err: error }, errMsg)
|
||||
} else {
|
||||
errorLogger.error({ err: error }, errMsg)
|
||||
}
|
||||
}
|
||||
} else if (response?.data) {
|
||||
logger.info('GQL subscription event {graphql_operation_name} emitted')
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import { GraphQLError } from 'graphql'
|
||||
export const shouldLogAsInfoLevel = (err: unknown): boolean => {
|
||||
if (err instanceof GraphQLError) {
|
||||
if (isUserGraphqlError(err)) return true
|
||||
if (err.message === 'Connection is closed.') return true
|
||||
if (!!err.cause && shouldLogAsInfoLevel(err.cause)) return true
|
||||
if (!!err.originalError && shouldLogAsInfoLevel(err.originalError)) return true
|
||||
}
|
||||
@@ -20,3 +21,25 @@ export const shouldLogAsInfoLevel = (err: unknown): boolean => {
|
||||
|
||||
return err instanceof ApolloError
|
||||
}
|
||||
|
||||
export const shouldLogAsWarnLevel = (err: unknown): boolean => {
|
||||
if (!(err instanceof GraphQLError)) return false
|
||||
|
||||
if (err.message.startsWith('Cannot return null for non-nullable field')) return true
|
||||
if (
|
||||
/Variable\s"(\$[^\s]+)"\sof non-null type\s"([^\s]+)"\smust not be null\./.test(
|
||||
err.message
|
||||
)
|
||||
)
|
||||
return true
|
||||
if (
|
||||
/Cannot query field\s"([^\s]+)"\son type\s"([^\s]+)"\. Did you mean\s"([^\s]+)"\?/.test(
|
||||
err.message
|
||||
)
|
||||
)
|
||||
return true
|
||||
if (!!err.cause && shouldLogAsWarnLevel(err.cause)) return true
|
||||
if (!!err.originalError && shouldLogAsWarnLevel(err.originalError)) return true
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -72,6 +72,13 @@ export const finalizeAuthMiddlewareFactory =
|
||||
throw new ForbiddenError('Cannot finalize auth - No user attached to session')
|
||||
}
|
||||
|
||||
if (res.headersSent) {
|
||||
req.log.info(
|
||||
'Headers already sent, probably by Passport if prior steps fail; skipping auth finalization'
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
const ac = await deps.createAuthorizationCode({
|
||||
appId: 'spklwebapp',
|
||||
userId: req.user.id,
|
||||
|
||||
@@ -4,6 +4,7 @@ import { md5 } from '@/modules/shared/helpers/cryptoHelper'
|
||||
import { getMailchimpConfig } from '@/modules/shared/helpers/envHelper'
|
||||
import { UserRecord } from '@/modules/core/helpers/types'
|
||||
import { MisconfiguredEnvironmentError } from '@/modules/shared/errors'
|
||||
import { OnboardingCompletionInput } from '@/modules/core/graph/generated/graphql'
|
||||
|
||||
let mailchimpInitialized = false
|
||||
|
||||
@@ -63,4 +64,55 @@ async function triggerMailchimpCustomerJourney(
|
||||
})
|
||||
}
|
||||
|
||||
export { addToMailchimpAudience, triggerMailchimpCustomerJourney }
|
||||
async function updateMailchimpMemberTags(
|
||||
user: UserRecord,
|
||||
listId: string,
|
||||
onboardingData: OnboardingCompletionInput
|
||||
) {
|
||||
initializeMailchimp()
|
||||
const subscriberHash = md5(user.email.toLowerCase())
|
||||
|
||||
// Check if user is already in audience (meaning they consented to marketing emails)
|
||||
try {
|
||||
await mailchimp.lists.getListMember(listId, subscriberHash)
|
||||
} catch {
|
||||
throw new Error(
|
||||
`User ${user.email} not found in Mailchimp audience. They should have been added during registration.`
|
||||
)
|
||||
}
|
||||
|
||||
const tags: { name: string; status: 'active' | 'inactive' }[] = []
|
||||
|
||||
if (onboardingData.role) {
|
||||
tags.push({
|
||||
name: `Role: ${onboardingData.role}`,
|
||||
status: 'active'
|
||||
})
|
||||
}
|
||||
|
||||
if (onboardingData.plans?.length) {
|
||||
onboardingData.plans.forEach((plan) => {
|
||||
tags.push({
|
||||
name: `Use case: ${plan}`,
|
||||
status: 'active'
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if (onboardingData.source) {
|
||||
tags.push({
|
||||
name: `Source: ${onboardingData.source}`,
|
||||
status: 'active'
|
||||
})
|
||||
}
|
||||
|
||||
await mailchimp.lists.updateListMemberTags(listId, subscriberHash, {
|
||||
tags
|
||||
})
|
||||
}
|
||||
|
||||
export {
|
||||
addToMailchimpAudience,
|
||||
triggerMailchimpCustomerJourney,
|
||||
updateMailchimpMemberTags
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import passport, { Strategy, AuthenticateOptions } from 'passport'
|
||||
import { logger } from '@/logging/logging'
|
||||
import { getFrontendOrigin } from '@/modules/shared/helpers/envHelper'
|
||||
import {
|
||||
UnverifiedEmailSSOLoginError,
|
||||
UserInputError
|
||||
} from '@/modules/core/errors/userinput'
|
||||
import type { Handler } from 'express'
|
||||
import type { Request, Response, NextFunction, RequestHandler } from 'express'
|
||||
import { Optional } from '@speckle/shared'
|
||||
import { get, isArray, isObjectLike, isString } from 'lodash'
|
||||
import { PassportAuthenticateHandlerBuilder } from '@/modules/auth/domain/operations'
|
||||
@@ -27,6 +26,48 @@ const resolveInfoMessage = (
|
||||
return null
|
||||
}
|
||||
|
||||
export const passportAuthenticationCallbackFactory =
|
||||
(context: {
|
||||
strategy: Strategy | string
|
||||
req: Request
|
||||
res: Response
|
||||
next: NextFunction
|
||||
}) =>
|
||||
(
|
||||
err: unknown,
|
||||
user: Optional<Express.User>,
|
||||
info: Optional<string | Record<string, unknown> | Array<string | undefined>>
|
||||
) => {
|
||||
const { strategy, req, res, next } = context
|
||||
if (err && !(err instanceof UserInputError))
|
||||
req.log.error({ err, strategy }, 'Authentication error for strategy "{strategy}"')
|
||||
|
||||
if (!user) {
|
||||
const infoMsg = resolveInfoMessage(info)
|
||||
const errMsg = err instanceof UserInputError ? err.message : null
|
||||
const finalMessage =
|
||||
infoMsg ||
|
||||
errMsg ||
|
||||
(err
|
||||
? 'An issue occurred during authentication, contact server admins'
|
||||
: 'Failed to authenticate, contact server admins')
|
||||
|
||||
let errPath = `/error?message=${finalMessage}`
|
||||
|
||||
if (err instanceof UnverifiedEmailSSOLoginError) {
|
||||
const email = err.info()?.email || ''
|
||||
errPath = `/error-email-verify?email=${email}`
|
||||
}
|
||||
|
||||
res.redirect(new URL(errPath, getFrontendOrigin()).toString())
|
||||
return
|
||||
}
|
||||
|
||||
if (err && !(err instanceof UserInputError)) return next(err)
|
||||
req.user = user
|
||||
next()
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for passport.authenticate that handles success & failure scenarios correctly
|
||||
* (passport.authenticate() by default doesn't, so don't use it)
|
||||
@@ -36,42 +77,12 @@ export const passportAuthenticateHandlerBuilderFactory =
|
||||
(
|
||||
strategy: Strategy | string,
|
||||
options: Optional<AuthenticateOptions> = undefined
|
||||
): Handler => {
|
||||
): RequestHandler => {
|
||||
return (req, res, next) => {
|
||||
passport.authenticate(
|
||||
strategy,
|
||||
options || {},
|
||||
// Not sure why types aren't automatically picked up
|
||||
(
|
||||
err: unknown,
|
||||
user: Optional<Express.User>,
|
||||
info: Optional<string | Record<string, unknown> | Array<string | undefined>>
|
||||
) => {
|
||||
if (err && !(err instanceof UserInputError)) logger.error(err)
|
||||
|
||||
if (!user) {
|
||||
const infoMsg = resolveInfoMessage(info)
|
||||
const errMsg = err instanceof UserInputError ? err.message : null
|
||||
const finalMessage =
|
||||
infoMsg ||
|
||||
errMsg ||
|
||||
(err
|
||||
? 'An issue occurred during authentication, contact server admins'
|
||||
: 'Failed to authenticate, contact server admins')
|
||||
|
||||
let errPath = `/error?message=${finalMessage}`
|
||||
|
||||
if (err instanceof UnverifiedEmailSSOLoginError) {
|
||||
const email = err.info()?.email || ''
|
||||
errPath = `/error-email-verify?email=${email}`
|
||||
}
|
||||
|
||||
res.redirect(new URL(errPath, getFrontendOrigin()).toString())
|
||||
}
|
||||
|
||||
req.user = user
|
||||
next()
|
||||
}
|
||||
passportAuthenticationCallbackFactory({ strategy, req, res, next })
|
||||
)(req, res, next)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,14 +199,15 @@ const azureAdStrategyBuilderFactory =
|
||||
case UnverifiedEmailSSOLoginError:
|
||||
case InviteNotFoundError:
|
||||
logger.info(
|
||||
{ e },
|
||||
{ err: e },
|
||||
'User input error during Entra ID authentication callback.'
|
||||
)
|
||||
break
|
||||
default:
|
||||
logger.error(e, 'Error during Entra ID authentication callback.')
|
||||
}
|
||||
return next()
|
||||
//skip remaining route handlers and go to error handler
|
||||
return next(e)
|
||||
}
|
||||
},
|
||||
finalizeAuthMiddleware
|
||||
|
||||
@@ -163,12 +163,13 @@ const githubStrategyBuilderFactory =
|
||||
case UserInputError:
|
||||
case InviteNotFoundError:
|
||||
case UnverifiedEmailSSOLoginError:
|
||||
logger.info(err)
|
||||
return done(null, false, { message: e.message })
|
||||
logger.info({ err: e }, 'Auth error for GitHub strategy')
|
||||
// note; passportjs suggests that err should be null for user input errors.
|
||||
// However, we are relying on the error being passed to `passportAuthenticationCallbackFactory` and handling it there
|
||||
return done(e, false, { message: e.message })
|
||||
default:
|
||||
logger.error(err)
|
||||
// Only when the server is operating abnormally should err be set, to indicate an internal error.
|
||||
return done(err, false, { message: e.message })
|
||||
logger.error({ err: e }, 'Auth error for GitHub strategy')
|
||||
return done(e, false, { message: e.message })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,11 +146,12 @@ const googleStrategyBuilderFactory =
|
||||
case UnverifiedEmailSSOLoginError:
|
||||
case UserInputError:
|
||||
case InviteNotFoundError:
|
||||
logger.info({ err: e })
|
||||
return done(null, false, { message: e.message })
|
||||
logger.info({ err: e }, 'Auth error for Google strategy')
|
||||
// note; passportjs suggests that err should be null for user input errors.
|
||||
// However, we are relying on the error being passed to `passportAuthenticationCallbackFactory` and handling it there
|
||||
return done(e, false, { message: e.message })
|
||||
default:
|
||||
logger.error({ err: e })
|
||||
// Only when the server is operating abnormally should err be set, to indicate an internal error.
|
||||
logger.error({ err: e }, 'Auth error for Google strategy')
|
||||
return done(e, false, { message: e.message })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,11 @@ import {
|
||||
} from '@/modules/core/services/ratelimiter'
|
||||
import { getIpFromRequest } from '@/modules/shared/utils/ip'
|
||||
import { InviteNotFoundError } from '@/modules/serverinvites/errors'
|
||||
import { UserInputError, PasswordTooShortError } from '@/modules/core/errors/userinput'
|
||||
|
||||
import {
|
||||
UserInputError,
|
||||
PasswordTooShortError,
|
||||
BlockedEmailDomainError
|
||||
} from '@/modules/core/errors/userinput'
|
||||
import { ServerInviteResourceType } from '@/modules/serverinvites/domain/constants'
|
||||
import { getResourceTypeRole } from '@/modules/serverinvites/helpers/core'
|
||||
import { AuthStrategyMetadata, AuthStrategyBuilder } from '@/modules/auth/helpers/types'
|
||||
@@ -117,7 +120,7 @@ const localStrategyBuilderFactory =
|
||||
invite = await deps.validateServerInvite(user.email, req.session.token)
|
||||
}
|
||||
|
||||
// 3. at this point we know, that we have one of these cases:
|
||||
// 3.. at this point we know, that we have one of these cases:
|
||||
// * the server is invite only and the user has a valid invite
|
||||
// * the server public and the user has a valid invite
|
||||
// * the server public and the user doesn't have an invite
|
||||
@@ -155,6 +158,7 @@ const localStrategyBuilderFactory =
|
||||
case PasswordTooShortError:
|
||||
case UserInputError:
|
||||
case InviteNotFoundError:
|
||||
case BlockedEmailDomainError:
|
||||
req.log.info({ err }, 'Error while registering.')
|
||||
return res.status(400).send({ err: e.message })
|
||||
default:
|
||||
|
||||
@@ -161,11 +161,12 @@ const oidcStrategyBuilderFactory =
|
||||
case UnverifiedEmailSSOLoginError:
|
||||
case UserInputError:
|
||||
case InviteNotFoundError:
|
||||
logger.info({ err: e })
|
||||
return done(null, undefined)
|
||||
logger.info({ err: e }, 'Auth error for OIDC strategy')
|
||||
// note; passportjs suggests that err should be null for user input errors.
|
||||
// However, we are relying on the error being passed to `passportAuthenticationCallbackFactory` and handling it there
|
||||
return done(e, undefined)
|
||||
default:
|
||||
logger.error({ err: e })
|
||||
// Only when the server is operating abnormally should err be set, to indicate an internal error.
|
||||
logger.error({ err: e }, 'Auth error for OIDC strategy')
|
||||
return done(e, undefined)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ describe('GraphQL @apps-api', () => {
|
||||
;({ sendRequest } = await initializeTestServer(ctx))
|
||||
testUser = {
|
||||
name: 'Dimitrie Stefanescu',
|
||||
email: 'didimitrie@gmail.com',
|
||||
email: 'didimitrie@example.org',
|
||||
password: 'wtfwtfwtf'
|
||||
}
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ const validateToken = validateTokenFactory({
|
||||
describe('Services @apps-services', () => {
|
||||
const actor = {
|
||||
name: 'Dimitrie Stefanescu',
|
||||
email: 'didimitrie@gmail.com',
|
||||
email: 'didimitrie@example.org',
|
||||
password: 'wtfwtfwtf'
|
||||
}
|
||||
|
||||
@@ -495,7 +495,7 @@ describe('Services @apps-services', () => {
|
||||
})
|
||||
const secondUser = {
|
||||
name: 'Dimitrie Stefanescu',
|
||||
email: 'didimitrie.wow@gmail.com',
|
||||
email: 'didimitrie.wow@example.org',
|
||||
password: 'wtfwtfwtf'
|
||||
}
|
||||
|
||||
|
||||
+195
-62
@@ -1,77 +1,62 @@
|
||||
const crs = require('crypto-random-string')
|
||||
const chai = require('chai')
|
||||
const request = require('supertest')
|
||||
|
||||
const { TIME } = require('@speckle/shared')
|
||||
const { RATE_LIMITERS, createConsumer } = require('@/modules/core/services/ratelimiter')
|
||||
const { beforeEachContext, initializeTestServer } = require('@/test/hooks')
|
||||
const { createStreamInviteDirectly } = require('@/test/speckle-helpers/inviteHelper')
|
||||
const { RateLimiterMemory } = require('rate-limiter-flexible')
|
||||
const {
|
||||
import crs from 'crypto-random-string'
|
||||
import chai from 'chai'
|
||||
import request from 'supertest'
|
||||
import httpMocks from 'node-mocks-http'
|
||||
import { TIME } from '@speckle/shared'
|
||||
import { RATE_LIMITERS, createConsumer } from '@/modules/core/services/ratelimiter'
|
||||
import { beforeEachContext, initializeTestServer } from '@/test/hooks'
|
||||
import { createStreamInviteDirectly } from '@/test/speckle-helpers/inviteHelper'
|
||||
import { RateLimiterMemory } from 'rate-limiter-flexible'
|
||||
import {
|
||||
findInviteFactory,
|
||||
findUserByTargetFactory,
|
||||
insertInviteAndDeleteOldFactory,
|
||||
deleteServerOnlyInvitesFactory,
|
||||
updateAllInviteTargetsFactory
|
||||
} = require('@/modules/serverinvites/repositories/serverInvites')
|
||||
const { db } = require('@/db/knex')
|
||||
const {
|
||||
} from '@/modules/serverinvites/repositories/serverInvites'
|
||||
import { db } from '@/db/knex'
|
||||
import {
|
||||
legacyCreateStreamFactory,
|
||||
createStreamReturnRecordFactory
|
||||
} = require('@/modules/core/services/streams/management')
|
||||
const {
|
||||
inviteUsersToProjectFactory
|
||||
} = require('@/modules/serverinvites/services/projectInviteManagement')
|
||||
const {
|
||||
createAndSendInviteFactory
|
||||
} = require('@/modules/serverinvites/services/creation')
|
||||
const {
|
||||
collectAndValidateCoreTargetsFactory
|
||||
} = require('@/modules/serverinvites/services/coreResourceCollection')
|
||||
const {
|
||||
} from '@/modules/core/services/streams/management'
|
||||
import { inviteUsersToProjectFactory } from '@/modules/serverinvites/services/projectInviteManagement'
|
||||
import { createAndSendInviteFactory } from '@/modules/serverinvites/services/creation'
|
||||
import { collectAndValidateCoreTargetsFactory } from '@/modules/serverinvites/services/coreResourceCollection'
|
||||
import {
|
||||
getStreamFactory,
|
||||
createStreamFactory
|
||||
} = require('@/modules/core/repositories/streams')
|
||||
const {
|
||||
buildCoreInviteEmailContentsFactory
|
||||
} = require('@/modules/serverinvites/services/coreEmailContents')
|
||||
const { getEventBus } = require('@/modules/shared/services/eventBus')
|
||||
const { createBranchFactory } = require('@/modules/core/repositories/branches')
|
||||
const {
|
||||
} from '@/modules/core/repositories/streams'
|
||||
import { buildCoreInviteEmailContentsFactory } from '@/modules/serverinvites/services/coreEmailContents'
|
||||
import { getEventBus } from '@/modules/shared/services/eventBus'
|
||||
import { createBranchFactory } from '@/modules/core/repositories/branches'
|
||||
import {
|
||||
getUsersFactory,
|
||||
getUserFactory,
|
||||
storeUserFactory,
|
||||
countAdminUsersFactory,
|
||||
storeUserAclFactory,
|
||||
legacyGetUserByEmailFactory
|
||||
} = require('@/modules/core/repositories/users')
|
||||
const {
|
||||
} from '@/modules/core/repositories/users'
|
||||
import {
|
||||
findEmailFactory,
|
||||
createUserEmailFactory,
|
||||
ensureNoPrimaryEmailForUserFactory
|
||||
} = require('@/modules/core/repositories/userEmails')
|
||||
const {
|
||||
requestNewEmailVerificationFactory
|
||||
} = require('@/modules/emails/services/verification/request')
|
||||
const {
|
||||
deleteOldAndInsertNewVerificationFactory
|
||||
} = require('@/modules/emails/repositories')
|
||||
const { renderEmail } = require('@/modules/emails/services/emailRendering')
|
||||
const { sendEmail } = require('@/modules/emails/services/sending')
|
||||
const { createUserFactory } = require('@/modules/core/services/users/management')
|
||||
const {
|
||||
validateAndCreateUserEmailFactory
|
||||
} = require('@/modules/core/services/userEmails')
|
||||
const {
|
||||
finalizeInvitedServerRegistrationFactory
|
||||
} = require('@/modules/serverinvites/services/processing')
|
||||
const {
|
||||
} from '@/modules/core/repositories/userEmails'
|
||||
import { requestNewEmailVerificationFactory } from '@/modules/emails/services/verification/request'
|
||||
import { deleteOldAndInsertNewVerificationFactory } from '@/modules/emails/repositories'
|
||||
import { renderEmail } from '@/modules/emails/services/emailRendering'
|
||||
import { sendEmail } from '@/modules/emails/services/sending'
|
||||
import { createUserFactory } from '@/modules/core/services/users/management'
|
||||
import { validateAndCreateUserEmailFactory } from '@/modules/core/services/userEmails'
|
||||
import { finalizeInvitedServerRegistrationFactory } from '@/modules/serverinvites/services/processing'
|
||||
import {
|
||||
getServerInfoFactory,
|
||||
updateServerInfoFactory
|
||||
} = require('@/modules/core/repositories/server')
|
||||
const {
|
||||
temporarilyEnableRateLimiter
|
||||
} = require('@/modules/core/tests/ratelimiter.spec')
|
||||
} from '@/modules/core/repositories/server'
|
||||
import { temporarilyEnableRateLimiter } from '@/modules/core/tests/ratelimiter.spec'
|
||||
import { passportAuthenticationCallbackFactory } from '@/modules/auth/services/passportService'
|
||||
import { testLogger } from '@/logging/logging'
|
||||
import { Application } from 'express'
|
||||
|
||||
const getServerInfo = getServerInfoFactory({ db })
|
||||
const getUser = getUserFactory({ db })
|
||||
@@ -139,14 +124,20 @@ const updateServerInfo = updateServerInfoFactory({ db })
|
||||
|
||||
const expect = chai.expect
|
||||
|
||||
let app
|
||||
let sendRequest
|
||||
let app: Application
|
||||
let sendRequest: Awaited<ReturnType<typeof initializeTestServer>>['sendRequest']
|
||||
|
||||
describe('Auth @auth', () => {
|
||||
describe('Local authN & authZ (token endpoints)', () => {
|
||||
const registeredUserEmail = 'registered@speckle.systems'
|
||||
|
||||
const me = {
|
||||
const me: {
|
||||
name: string
|
||||
company: string
|
||||
email: string
|
||||
password: string
|
||||
id?: string
|
||||
} = {
|
||||
name: 'dimitrie stefanescu',
|
||||
company: 'speckle',
|
||||
email: registeredUserEmail,
|
||||
@@ -154,7 +145,11 @@ describe('Auth @auth', () => {
|
||||
id: undefined
|
||||
}
|
||||
|
||||
const myPrivateStream = {
|
||||
const myPrivateStream: {
|
||||
name: string
|
||||
isPublic: boolean
|
||||
id?: string
|
||||
} = {
|
||||
name: 'My Private Stream 1',
|
||||
isPublic: false,
|
||||
id: undefined
|
||||
@@ -169,7 +164,7 @@ describe('Auth @auth', () => {
|
||||
await createUser(me).then((id) => (me.id = id))
|
||||
|
||||
// Create a test stream for testing stream invites
|
||||
await createStream({ ...myPrivateStream, ownerId: me.id }).then(
|
||||
await createStream({ ...myPrivateStream, ownerId: me.id! }).then(
|
||||
(id) => (myPrivateStream.id = id)
|
||||
)
|
||||
})
|
||||
@@ -219,7 +214,7 @@ describe('Auth @auth', () => {
|
||||
: {
|
||||
email: targetEmail
|
||||
},
|
||||
inviterUser.id
|
||||
inviterUser!.id
|
||||
)
|
||||
|
||||
// No invite
|
||||
@@ -483,7 +478,7 @@ describe('Auth @auth', () => {
|
||||
.expect(401)
|
||||
})
|
||||
|
||||
let frontendCredentials
|
||||
let frontendCredentials: { token: string; refreshToken: string }
|
||||
|
||||
it('Should get an access code (redirected response)', async () => {
|
||||
const appId = 'spklwebapp'
|
||||
@@ -565,7 +560,7 @@ describe('Auth @auth', () => {
|
||||
})
|
||||
|
||||
it('Should rate-limit user creation', async () => {
|
||||
const newUser = async (id, ip, expectCode) => {
|
||||
const newUser = async (id: string, ip: string, expectCode: number) => {
|
||||
await request(app)
|
||||
.post(`/auth/local/register?challenge=test`)
|
||||
.set('CF-Connecting-IP', ip)
|
||||
@@ -609,4 +604,142 @@ describe('Auth @auth', () => {
|
||||
RATE_LIMITERS.USER_CREATE = oldRateLimiter
|
||||
})
|
||||
})
|
||||
|
||||
describe('passportAuthenticationCallbackFactory', () => {
|
||||
it('Should handle a successful passport authentication (a user exists)', async () => {
|
||||
const req = httpMocks.createRequest({})
|
||||
const res = httpMocks.createResponse()
|
||||
let errorCalledCounter = 0
|
||||
let nextCalledCounter = 0
|
||||
const next = (err: unknown) => {
|
||||
if (err) {
|
||||
errorCalledCounter++
|
||||
}
|
||||
nextCalledCounter++
|
||||
}
|
||||
const SUT = passportAuthenticationCallbackFactory({
|
||||
strategy: 'wotStrategy',
|
||||
req,
|
||||
res,
|
||||
next
|
||||
})
|
||||
|
||||
SUT(null, { id: '123', email: 'weLoveAuth@example.org' }, undefined)
|
||||
|
||||
expect(req).to.have.property('user')
|
||||
expect(req.user?.id).to.equal('123')
|
||||
expect(
|
||||
errorCalledCounter,
|
||||
'error request handler "next(err)" should not have been called'
|
||||
).to.equal(0)
|
||||
expect(
|
||||
nextCalledCounter,
|
||||
'next request handler should have been called'
|
||||
).to.equal(1)
|
||||
})
|
||||
it('Should handle case where there is an error but no user', async () => {
|
||||
const req = httpMocks.createRequest()
|
||||
req.log = testLogger
|
||||
const res = httpMocks.createResponse()
|
||||
let errorCalledCounter = 0
|
||||
let nextCalledCounter = 0
|
||||
const next = (err: unknown) => {
|
||||
if (err) {
|
||||
errorCalledCounter++
|
||||
}
|
||||
nextCalledCounter++
|
||||
}
|
||||
const SUT = passportAuthenticationCallbackFactory({
|
||||
strategy: 'wotStrategy',
|
||||
req,
|
||||
res,
|
||||
next
|
||||
})
|
||||
|
||||
SUT(new Error('I brrrrroke'), undefined, undefined)
|
||||
expect(
|
||||
res._getRedirectUrl().includes('/error'),
|
||||
`Redirect url was '${res._getRedirectUrl()}'`
|
||||
).to.be.true
|
||||
expect(req).not.to.have.property('user')
|
||||
expect(
|
||||
errorCalledCounter,
|
||||
'error request handler "next(err)" should not have been called'
|
||||
).to.equal(0)
|
||||
expect(
|
||||
nextCalledCounter,
|
||||
'next request handler should not have been called'
|
||||
).to.equal(0)
|
||||
})
|
||||
it('Should handle case where there is an error and a user', async () => {
|
||||
const req = httpMocks.createRequest()
|
||||
req.log = testLogger
|
||||
const res = httpMocks.createResponse()
|
||||
let errorCalledCounter = 0
|
||||
let nextCalledCounter = 0
|
||||
const next = (err: unknown) => {
|
||||
if (err) {
|
||||
errorCalledCounter++
|
||||
}
|
||||
nextCalledCounter++
|
||||
}
|
||||
const SUT = passportAuthenticationCallbackFactory({
|
||||
strategy: 'wotStrategy',
|
||||
req,
|
||||
res,
|
||||
next
|
||||
})
|
||||
|
||||
SUT(
|
||||
new Error('I brrrrrooooken'),
|
||||
{ id: '1234', email: 'allFizzy@example.org' },
|
||||
undefined
|
||||
)
|
||||
|
||||
// Should not have set the user if there was an error
|
||||
expect(req).to.not.have.property('user')
|
||||
expect(
|
||||
errorCalledCounter,
|
||||
'error request handler "next(err)" should have been called'
|
||||
).to.equal(1)
|
||||
expect(
|
||||
nextCalledCounter,
|
||||
'next request handler should have been called'
|
||||
).to.equal(1)
|
||||
})
|
||||
it('Should handle the case where there is no user and no error', async () => {
|
||||
const req = httpMocks.createRequest()
|
||||
req.log = testLogger
|
||||
const res = httpMocks.createResponse()
|
||||
let errorCalledCounter = 0
|
||||
let nextCalledCounter = 0
|
||||
const next = (err: unknown) => {
|
||||
if (err) {
|
||||
errorCalledCounter++
|
||||
}
|
||||
nextCalledCounter++
|
||||
}
|
||||
const SUT = passportAuthenticationCallbackFactory({
|
||||
strategy: 'wotStrategy',
|
||||
req,
|
||||
res,
|
||||
next
|
||||
})
|
||||
|
||||
SUT(null, undefined, undefined)
|
||||
expect(
|
||||
res._getRedirectUrl().includes('/error'),
|
||||
`Redirect url was '${res._getRedirectUrl()}'`
|
||||
).to.be.true
|
||||
expect(req).not.to.have.property('user')
|
||||
expect(
|
||||
errorCalledCounter,
|
||||
'error request handler "next(err)" should not have been called'
|
||||
).to.equal(0)
|
||||
expect(
|
||||
nextCalledCounter,
|
||||
'next request handler should not have been called'
|
||||
).to.equal(0)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -233,7 +233,7 @@ export type LocalAuthRestApiHelpers = ReturnType<typeof localAuthRestApi>
|
||||
export const generateRegistrationParams = (): RegisterParams => ({
|
||||
challenge: faker.string.uuid(),
|
||||
user: {
|
||||
email: (random(0, 1000) + faker.internet.email()).toLowerCase(),
|
||||
email: `${random(0, 1000)}@example.org`.toLowerCase(),
|
||||
password: faker.internet.password(),
|
||||
name: faker.person.fullName()
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
import { AllScopes } from '@/modules/core/helpers/mainConstants'
|
||||
import { updateServerInfoFactory } from '@/modules/core/repositories/server'
|
||||
import { findInviteFactory } from '@/modules/serverinvites/repositories/serverInvites'
|
||||
import { getFeatureFlags } from '@/modules/shared/helpers/envHelper'
|
||||
import { expectToThrow, itEach } from '@/test/assertionHelper'
|
||||
import { BasicTestUser, createTestUsers } from '@/test/authHelper'
|
||||
import {
|
||||
@@ -33,6 +34,8 @@ import {
|
||||
import { Roles } from '@speckle/shared'
|
||||
import { expect } from 'chai'
|
||||
|
||||
const { FF_NO_PERSONAL_EMAILS_ENABLED } = getFeatureFlags()
|
||||
|
||||
const updateServerInfo = updateServerInfoFactory({ db })
|
||||
|
||||
describe('Server registration', () => {
|
||||
@@ -96,6 +99,18 @@ describe('Server registration', () => {
|
||||
expect(user.emails.every((e) => !e.verified)).to.be.true
|
||||
})
|
||||
|
||||
FF_NO_PERSONAL_EMAILS_ENABLED
|
||||
? it('rejects registration with blocked email domain', async () => {
|
||||
const params = generateRegistrationParams()
|
||||
params.user.email = 'test@gmail.com'
|
||||
|
||||
const error = await expectToThrow(() => restApi.register(params))
|
||||
expect(error.message).to.contain(
|
||||
'Please use your work email instead of a personal email address'
|
||||
)
|
||||
})
|
||||
: null
|
||||
|
||||
it('fails without challenge', async () => {
|
||||
const params = generateRegistrationParams()
|
||||
params.challenge = ''
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
export const getObjectKey = (projectId: string, blobId: string): string =>
|
||||
`assets/${projectId}/${blobId}`
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
import { MaybeNullOrUndefined, Nullable } from '@speckle/shared'
|
||||
import { Knex } from 'knex'
|
||||
|
||||
const BlobStorage = buildTableHelper('blob_storage', [
|
||||
export const BlobStorage = buildTableHelper('blob_storage', [
|
||||
'id',
|
||||
'streamId',
|
||||
'userId',
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
UpsertBlob
|
||||
} from '@/modules/blobstorage/domain/operations'
|
||||
import { BlobStorageItem } from '@/modules/blobstorage/domain/types'
|
||||
import { getObjectKey } from '@/modules/blobstorage/helpers/blobs'
|
||||
import { BadRequestError } from '@/modules/shared/errors'
|
||||
import { getFileSizeLimitMB } from '@/modules/shared/helpers/envHelper'
|
||||
import { MaybeAsync } from '@speckle/shared'
|
||||
@@ -31,7 +32,7 @@ export const uploadFileStreamFactory =
|
||||
if (!userId || userId.length !== 10)
|
||||
throw new BadRequestError('The user id has to be of length 10')
|
||||
|
||||
const objectKey = `assets/${streamId}/${blobId}`
|
||||
const objectKey = getObjectKey(streamId, blobId)
|
||||
const dbFile = {
|
||||
id: blobId,
|
||||
streamId,
|
||||
@@ -40,8 +41,9 @@ export const uploadFileStreamFactory =
|
||||
fileName,
|
||||
fileType
|
||||
}
|
||||
|
||||
// need to insert the upload data before starting otherwise the upload finished
|
||||
// even might fire faster, than the db insert, causing missing asset data in the db
|
||||
// event might fire faster, than the db insert, causing missing asset data in the db
|
||||
await deps.upsertBlob(dbFile)
|
||||
|
||||
const { fileHash } = await deps.storeFileStream({ objectKey, fileStream })
|
||||
|
||||
@@ -3,11 +3,8 @@ import { cliLogger } from '@/logging/logging'
|
||||
import { getWorkspaceBySlugOrIdFactory } from '@/modules/workspaces/repositories/workspaces'
|
||||
import { db } from '@/db/knex'
|
||||
import { upsertPaidWorkspacePlanFactory } from '@/modules/gatekeeper/repositories/billing'
|
||||
import {
|
||||
PaidWorkspacePlans,
|
||||
PaidWorkspacePlanStatuses
|
||||
} from '@/modules/gatekeeperCore/domain/billing'
|
||||
import { WorkspaceNotFoundError } from '@/modules/workspaces/errors/workspace'
|
||||
import { PaidWorkspacePlans, PaidWorkspacePlanStatuses } from '@speckle/shared'
|
||||
|
||||
const command: CommandModule<
|
||||
unknown,
|
||||
|
||||
@@ -319,3 +319,8 @@ export type GetPaginatedProjectComments = (
|
||||
items: CommentRecord[]
|
||||
cursor: string | null
|
||||
}>
|
||||
|
||||
export type GetStreamCommentCount = (
|
||||
streamId: string,
|
||||
options?: Partial<{ threadsOnly: boolean; includeArchived: boolean }>
|
||||
) => Promise<number>
|
||||
|
||||
@@ -6,12 +6,14 @@ export type ResourceIdentifier = {
|
||||
resourceType: ResourceType
|
||||
}
|
||||
|
||||
export enum ResourceType {
|
||||
Comment = 'comment',
|
||||
Commit = 'commit',
|
||||
Object = 'object',
|
||||
Stream = 'stream'
|
||||
}
|
||||
export const ResourceType = {
|
||||
Comment: 'comment',
|
||||
Commit: 'commit',
|
||||
Object: 'object',
|
||||
Stream: 'stream'
|
||||
} as const
|
||||
|
||||
export type ResourceType = (typeof ResourceType)[keyof typeof ResourceType]
|
||||
|
||||
export type ExtendedComment = CommentRecord & {
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { ProjectVisibility } from '@/modules/core/domain/projects/operations'
|
||||
import { Project } from '@/modules/core/domain/streams/types'
|
||||
import {
|
||||
ProjectCreateInput,
|
||||
@@ -7,7 +6,6 @@ import {
|
||||
StreamUpdateInput
|
||||
} from '@/modules/core/graph/generated/graphql'
|
||||
import { StreamRoles } from '@speckle/shared'
|
||||
import { OverrideProperties } from 'type-fest'
|
||||
|
||||
export const projectEventsNamespace = 'projects' as const
|
||||
|
||||
@@ -24,23 +22,13 @@ export type ProjectEventsPayloads = {
|
||||
[ProjectEvents.Created]: {
|
||||
project: Project
|
||||
ownerId: string
|
||||
input:
|
||||
| StreamCreateInput
|
||||
| OverrideProperties<
|
||||
ProjectCreateInput,
|
||||
{ visibility: ProjectCreateInput['visibility'] | ProjectVisibility }
|
||||
>
|
||||
input: StreamCreateInput | ProjectCreateInput
|
||||
}
|
||||
[ProjectEvents.Updated]: {
|
||||
updaterId: string
|
||||
oldProject: Project
|
||||
newProject: Project
|
||||
update:
|
||||
| OverrideProperties<
|
||||
ProjectUpdateInput,
|
||||
{ visibility: ProjectUpdateInput['visibility'] | ProjectVisibility }
|
||||
>
|
||||
| StreamUpdateInput
|
||||
update: ProjectUpdateInput | StreamUpdateInput
|
||||
}
|
||||
[ProjectEvents.Deleted]: {
|
||||
deleterId: string
|
||||
|
||||
@@ -25,3 +25,9 @@ export class UnverifiedEmailSSOLoginError extends UserInputError<UnverifiedEmail
|
||||
'Email already in use by a user with unverified email. Verify the email on the existing user to be able to log in with this method.'
|
||||
static code = 'UNVERIFIED_EMAIL_SSO_LOGIN_ERROR'
|
||||
}
|
||||
|
||||
export class BlockedEmailDomainError extends UserInputError {
|
||||
static defaultMessage =
|
||||
'Please use your work email instead of a personal email address'
|
||||
static code = 'BLOCKED_EMAIL_DOMAIN_ERROR'
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { CommentReplyAuthorCollectionGraphQLReturn, CommentGraphQLReturn } from
|
||||
import { PendingStreamCollaboratorGraphQLReturn } from '@/modules/serverinvites/helpers/graphTypes';
|
||||
import { FileUploadGraphQLReturn } from '@/modules/fileuploads/helpers/types';
|
||||
import { AutomateFunctionGraphQLReturn, AutomateFunctionReleaseGraphQLReturn, AutomationGraphQLReturn, AutomationRevisionGraphQLReturn, AutomationRevisionFunctionGraphQLReturn, AutomateRunGraphQLReturn, AutomationRunTriggerGraphQLReturn, AutomationRevisionTriggerDefinitionGraphQLReturn, AutomateFunctionRunGraphQLReturn, TriggeredAutomationsStatusGraphQLReturn, ProjectAutomationMutationsGraphQLReturn, ProjectTriggeredAutomationsStatusUpdatedMessageGraphQLReturn, ProjectAutomationsUpdatedMessageGraphQLReturn, UserAutomateInfoGraphQLReturn } from '@/modules/automate/helpers/graphTypes';
|
||||
import { WorkspaceGraphQLReturn, WorkspaceSsoGraphQLReturn, WorkspaceMutationsGraphQLReturn, WorkspaceJoinRequestMutationsGraphQLReturn, WorkspaceInviteMutationsGraphQLReturn, WorkspaceProjectMutationsGraphQLReturn, PendingWorkspaceCollaboratorGraphQLReturn, WorkspaceCollaboratorGraphQLReturn, WorkspaceJoinRequestGraphQLReturn, ProjectRoleGraphQLReturn } from '@/modules/workspacesCore/helpers/graphTypes';
|
||||
import { WorkspaceGraphQLReturn, WorkspaceSsoGraphQLReturn, WorkspaceMutationsGraphQLReturn, WorkspaceJoinRequestMutationsGraphQLReturn, WorkspaceInviteMutationsGraphQLReturn, WorkspaceProjectMutationsGraphQLReturn, PendingWorkspaceCollaboratorGraphQLReturn, WorkspaceCollaboratorGraphQLReturn, WorkspaceJoinRequestGraphQLReturn, LimitedWorkspaceJoinRequestGraphQLReturn, ProjectRoleGraphQLReturn } from '@/modules/workspacesCore/helpers/graphTypes';
|
||||
import { WorkspaceBillingMutationsGraphQLReturn } from '@/modules/gatekeeper/helpers/graphTypes';
|
||||
import { WebhookGraphQLReturn } from '@/modules/webhooks/helpers/graphTypes';
|
||||
import { SmartTextEditorValueGraphQLReturn } from '@/modules/core/services/richTextEditorService';
|
||||
@@ -49,6 +49,11 @@ export type ActiveUserMutations = {
|
||||
};
|
||||
|
||||
|
||||
export type ActiveUserMutationsFinishOnboardingArgs = {
|
||||
input?: InputMaybe<OnboardingCompletionInput>;
|
||||
};
|
||||
|
||||
|
||||
export type ActiveUserMutationsUpdateArgs = {
|
||||
user: UserUpdateInput;
|
||||
};
|
||||
@@ -348,12 +353,13 @@ export type AutomateFunctionTemplate = {
|
||||
url: Scalars['String']['output'];
|
||||
};
|
||||
|
||||
export enum AutomateFunctionTemplateLanguage {
|
||||
DotNet = 'DOT_NET',
|
||||
Python = 'PYTHON',
|
||||
Typescript = 'TYPESCRIPT'
|
||||
}
|
||||
export const AutomateFunctionTemplateLanguage = {
|
||||
DotNet: 'DOT_NET',
|
||||
Python: 'PYTHON',
|
||||
Typescript: 'TYPESCRIPT'
|
||||
} as const;
|
||||
|
||||
export type AutomateFunctionTemplateLanguage = typeof AutomateFunctionTemplateLanguage[keyof typeof AutomateFunctionTemplateLanguage];
|
||||
export type AutomateFunctionToken = {
|
||||
__typename?: 'AutomateFunctionToken';
|
||||
functionId: Scalars['String']['output'];
|
||||
@@ -407,21 +413,23 @@ export type AutomateRunCollection = {
|
||||
totalCount: Scalars['Int']['output'];
|
||||
};
|
||||
|
||||
export enum AutomateRunStatus {
|
||||
Canceled = 'CANCELED',
|
||||
Exception = 'EXCEPTION',
|
||||
Failed = 'FAILED',
|
||||
Initializing = 'INITIALIZING',
|
||||
Pending = 'PENDING',
|
||||
Running = 'RUNNING',
|
||||
Succeeded = 'SUCCEEDED',
|
||||
Timeout = 'TIMEOUT'
|
||||
}
|
||||
export const AutomateRunStatus = {
|
||||
Canceled: 'CANCELED',
|
||||
Exception: 'EXCEPTION',
|
||||
Failed: 'FAILED',
|
||||
Initializing: 'INITIALIZING',
|
||||
Pending: 'PENDING',
|
||||
Running: 'RUNNING',
|
||||
Succeeded: 'SUCCEEDED',
|
||||
Timeout: 'TIMEOUT'
|
||||
} as const;
|
||||
|
||||
export enum AutomateRunTriggerType {
|
||||
VersionCreated = 'VERSION_CREATED'
|
||||
}
|
||||
export type AutomateRunStatus = typeof AutomateRunStatus[keyof typeof AutomateRunStatus];
|
||||
export const AutomateRunTriggerType = {
|
||||
VersionCreated: 'VERSION_CREATED'
|
||||
} as const;
|
||||
|
||||
export type AutomateRunTriggerType = typeof AutomateRunTriggerType[keyof typeof AutomateRunTriggerType];
|
||||
export type Automation = {
|
||||
__typename?: 'Automation';
|
||||
createdAt: Scalars['DateTime']['output'];
|
||||
@@ -482,11 +490,12 @@ export type BasicGitRepositoryMetadata = {
|
||||
url: Scalars['String']['output'];
|
||||
};
|
||||
|
||||
export enum BillingInterval {
|
||||
Monthly = 'monthly',
|
||||
Yearly = 'yearly'
|
||||
}
|
||||
export const BillingInterval = {
|
||||
Monthly: 'monthly',
|
||||
Yearly: 'yearly'
|
||||
} as const;
|
||||
|
||||
export type BillingInterval = typeof BillingInterval[keyof typeof BillingInterval];
|
||||
export type BlobMetadata = {
|
||||
__typename?: 'BlobMetadata';
|
||||
createdAt: Scalars['DateTime']['output'];
|
||||
@@ -950,16 +959,29 @@ export type DenyWorkspaceJoinRequestInput = {
|
||||
workspaceId: Scalars['String']['input'];
|
||||
};
|
||||
|
||||
export enum DiscoverableStreamsSortType {
|
||||
CreatedDate = 'CREATED_DATE',
|
||||
FavoritesCount = 'FAVORITES_COUNT'
|
||||
}
|
||||
export const DiscoverableStreamsSortType = {
|
||||
CreatedDate: 'CREATED_DATE',
|
||||
FavoritesCount: 'FAVORITES_COUNT'
|
||||
} as const;
|
||||
|
||||
export type DiscoverableStreamsSortType = typeof DiscoverableStreamsSortType[keyof typeof DiscoverableStreamsSortType];
|
||||
export type DiscoverableStreamsSortingInput = {
|
||||
direction: SortDirection;
|
||||
type: DiscoverableStreamsSortType;
|
||||
};
|
||||
|
||||
export type DiscoverableWorkspaceCollaborator = {
|
||||
__typename?: 'DiscoverableWorkspaceCollaborator';
|
||||
avatar?: Maybe<Scalars['String']['output']>;
|
||||
};
|
||||
|
||||
export type DiscoverableWorkspaceCollaboratorCollection = {
|
||||
__typename?: 'DiscoverableWorkspaceCollaboratorCollection';
|
||||
cursor?: Maybe<Scalars['String']['output']>;
|
||||
items: Array<DiscoverableWorkspaceCollaborator>;
|
||||
totalCount: Scalars['Int']['output'];
|
||||
};
|
||||
|
||||
export type EditCommentInput = {
|
||||
commentId: Scalars['String']['input'];
|
||||
content: CommentContentInput;
|
||||
@@ -1173,6 +1195,31 @@ export type LimitedWorkspace = {
|
||||
name: Scalars['String']['output'];
|
||||
/** Unique workspace short id. Used for navigation. */
|
||||
slug: Scalars['String']['output'];
|
||||
/** Workspace members visible to people with verified email domain */
|
||||
team?: Maybe<DiscoverableWorkspaceCollaboratorCollection>;
|
||||
};
|
||||
|
||||
|
||||
/** Workspace metadata visible to non-workspace members. */
|
||||
export type LimitedWorkspaceTeamArgs = {
|
||||
cursor?: InputMaybe<Scalars['String']['input']>;
|
||||
limit?: Scalars['Int']['input'];
|
||||
};
|
||||
|
||||
export type LimitedWorkspaceJoinRequest = {
|
||||
__typename?: 'LimitedWorkspaceJoinRequest';
|
||||
createdAt: Scalars['DateTime']['output'];
|
||||
id: Scalars['String']['output'];
|
||||
status: WorkspaceJoinRequestStatus;
|
||||
user: LimitedUser;
|
||||
workspace: LimitedWorkspace;
|
||||
};
|
||||
|
||||
export type LimitedWorkspaceJoinRequestCollection = {
|
||||
__typename?: 'LimitedWorkspaceJoinRequestCollection';
|
||||
cursor?: Maybe<Scalars['String']['output']>;
|
||||
items: Array<LimitedWorkspaceJoinRequest>;
|
||||
totalCount: Scalars['Int']['output'];
|
||||
};
|
||||
|
||||
export type MarkCommentViewedInput = {
|
||||
@@ -1833,12 +1880,19 @@ export type ObjectCreateInput = {
|
||||
streamId: Scalars['String']['input'];
|
||||
};
|
||||
|
||||
export enum PaidWorkspacePlans {
|
||||
Business = 'business',
|
||||
Plus = 'plus',
|
||||
Starter = 'starter'
|
||||
}
|
||||
export type OnboardingCompletionInput = {
|
||||
plans?: InputMaybe<Array<Scalars['String']['input']>>;
|
||||
role?: InputMaybe<Scalars['String']['input']>;
|
||||
source?: InputMaybe<Scalars['String']['input']>;
|
||||
};
|
||||
|
||||
export const PaidWorkspacePlans = {
|
||||
Business: 'business',
|
||||
Plus: 'plus',
|
||||
Starter: 'starter'
|
||||
} as const;
|
||||
|
||||
export type PaidWorkspacePlans = typeof PaidWorkspacePlans[keyof typeof PaidWorkspacePlans];
|
||||
export type PasswordStrengthCheckFeedback = {
|
||||
__typename?: 'PasswordStrengthCheckFeedback';
|
||||
suggestions: Array<Scalars['String']['output']>;
|
||||
@@ -2166,12 +2220,13 @@ export type ProjectAutomationsUpdatedMessage = {
|
||||
type: ProjectAutomationsUpdatedMessageType;
|
||||
};
|
||||
|
||||
export enum ProjectAutomationsUpdatedMessageType {
|
||||
Created = 'CREATED',
|
||||
CreatedRevision = 'CREATED_REVISION',
|
||||
Updated = 'UPDATED'
|
||||
}
|
||||
export const ProjectAutomationsUpdatedMessageType = {
|
||||
Created: 'CREATED',
|
||||
CreatedRevision: 'CREATED_REVISION',
|
||||
Updated: 'UPDATED'
|
||||
} as const;
|
||||
|
||||
export type ProjectAutomationsUpdatedMessageType = typeof ProjectAutomationsUpdatedMessageType[keyof typeof ProjectAutomationsUpdatedMessageType];
|
||||
export type ProjectCollaborator = {
|
||||
__typename?: 'ProjectCollaborator';
|
||||
id: Scalars['ID']['output'];
|
||||
@@ -2218,12 +2273,13 @@ export type ProjectCommentsUpdatedMessage = {
|
||||
type: ProjectCommentsUpdatedMessageType;
|
||||
};
|
||||
|
||||
export enum ProjectCommentsUpdatedMessageType {
|
||||
Archived = 'ARCHIVED',
|
||||
Created = 'CREATED',
|
||||
Updated = 'UPDATED'
|
||||
}
|
||||
export const ProjectCommentsUpdatedMessageType = {
|
||||
Archived: 'ARCHIVED',
|
||||
Created: 'CREATED',
|
||||
Updated: 'UPDATED'
|
||||
} as const;
|
||||
|
||||
export type ProjectCommentsUpdatedMessageType = typeof ProjectCommentsUpdatedMessageType[keyof typeof ProjectCommentsUpdatedMessageType];
|
||||
/** Any values left null will be ignored */
|
||||
export type ProjectCreateInput = {
|
||||
description?: InputMaybe<Scalars['String']['input']>;
|
||||
@@ -2239,11 +2295,12 @@ export type ProjectFileImportUpdatedMessage = {
|
||||
upload: FileUpload;
|
||||
};
|
||||
|
||||
export enum ProjectFileImportUpdatedMessageType {
|
||||
Created = 'CREATED',
|
||||
Updated = 'UPDATED'
|
||||
}
|
||||
export const ProjectFileImportUpdatedMessageType = {
|
||||
Created: 'CREATED',
|
||||
Updated: 'UPDATED'
|
||||
} as const;
|
||||
|
||||
export type ProjectFileImportUpdatedMessageType = typeof ProjectFileImportUpdatedMessageType[keyof typeof ProjectFileImportUpdatedMessageType];
|
||||
export type ProjectInviteCreateInput = {
|
||||
/** Either this or userId must be filled */
|
||||
email?: InputMaybe<Scalars['String']['input']>;
|
||||
@@ -2340,12 +2397,13 @@ export type ProjectModelsUpdatedMessage = {
|
||||
type: ProjectModelsUpdatedMessageType;
|
||||
};
|
||||
|
||||
export enum ProjectModelsUpdatedMessageType {
|
||||
Created = 'CREATED',
|
||||
Deleted = 'DELETED',
|
||||
Updated = 'UPDATED'
|
||||
}
|
||||
export const ProjectModelsUpdatedMessageType = {
|
||||
Created: 'CREATED',
|
||||
Deleted: 'DELETED',
|
||||
Updated: 'UPDATED'
|
||||
} as const;
|
||||
|
||||
export type ProjectModelsUpdatedMessageType = typeof ProjectModelsUpdatedMessageType[keyof typeof ProjectModelsUpdatedMessageType];
|
||||
export type ProjectMutations = {
|
||||
__typename?: 'ProjectMutations';
|
||||
/** Access request related mutations */
|
||||
@@ -2415,11 +2473,12 @@ export type ProjectPendingModelsUpdatedMessage = {
|
||||
type: ProjectPendingModelsUpdatedMessageType;
|
||||
};
|
||||
|
||||
export enum ProjectPendingModelsUpdatedMessageType {
|
||||
Created = 'CREATED',
|
||||
Updated = 'UPDATED'
|
||||
}
|
||||
export const ProjectPendingModelsUpdatedMessageType = {
|
||||
Created: 'CREATED',
|
||||
Updated: 'UPDATED'
|
||||
} as const;
|
||||
|
||||
export type ProjectPendingModelsUpdatedMessageType = typeof ProjectPendingModelsUpdatedMessageType[keyof typeof ProjectPendingModelsUpdatedMessageType];
|
||||
export type ProjectPendingVersionsUpdatedMessage = {
|
||||
__typename?: 'ProjectPendingVersionsUpdatedMessage';
|
||||
/** Upload ID */
|
||||
@@ -2428,11 +2487,12 @@ export type ProjectPendingVersionsUpdatedMessage = {
|
||||
version: FileUpload;
|
||||
};
|
||||
|
||||
export enum ProjectPendingVersionsUpdatedMessageType {
|
||||
Created = 'CREATED',
|
||||
Updated = 'UPDATED'
|
||||
}
|
||||
export const ProjectPendingVersionsUpdatedMessageType = {
|
||||
Created: 'CREATED',
|
||||
Updated: 'UPDATED'
|
||||
} as const;
|
||||
|
||||
export type ProjectPendingVersionsUpdatedMessageType = typeof ProjectPendingVersionsUpdatedMessageType[keyof typeof ProjectPendingVersionsUpdatedMessageType];
|
||||
export type ProjectRole = {
|
||||
__typename?: 'ProjectRole';
|
||||
project: Project;
|
||||
@@ -2454,11 +2514,12 @@ export type ProjectTriggeredAutomationsStatusUpdatedMessage = {
|
||||
version: Version;
|
||||
};
|
||||
|
||||
export enum ProjectTriggeredAutomationsStatusUpdatedMessageType {
|
||||
RunCreated = 'RUN_CREATED',
|
||||
RunUpdated = 'RUN_UPDATED'
|
||||
}
|
||||
export const ProjectTriggeredAutomationsStatusUpdatedMessageType = {
|
||||
RunCreated: 'RUN_CREATED',
|
||||
RunUpdated: 'RUN_UPDATED'
|
||||
} as const;
|
||||
|
||||
export type ProjectTriggeredAutomationsStatusUpdatedMessageType = typeof ProjectTriggeredAutomationsStatusUpdatedMessageType[keyof typeof ProjectTriggeredAutomationsStatusUpdatedMessageType];
|
||||
/** Any values left null will be ignored, so only set the properties that you want updated */
|
||||
export type ProjectUpdateInput = {
|
||||
allowPublicComments?: InputMaybe<Scalars['Boolean']['input']>;
|
||||
@@ -2485,11 +2546,12 @@ export type ProjectUpdatedMessage = {
|
||||
type: ProjectUpdatedMessageType;
|
||||
};
|
||||
|
||||
export enum ProjectUpdatedMessageType {
|
||||
Deleted = 'DELETED',
|
||||
Updated = 'UPDATED'
|
||||
}
|
||||
export const ProjectUpdatedMessageType = {
|
||||
Deleted: 'DELETED',
|
||||
Updated: 'UPDATED'
|
||||
} as const;
|
||||
|
||||
export type ProjectUpdatedMessageType = typeof ProjectUpdatedMessageType[keyof typeof ProjectUpdatedMessageType];
|
||||
export type ProjectVersionsPreviewGeneratedMessage = {
|
||||
__typename?: 'ProjectVersionsPreviewGeneratedMessage';
|
||||
objectId: Scalars['String']['output'];
|
||||
@@ -2508,18 +2570,20 @@ export type ProjectVersionsUpdatedMessage = {
|
||||
version?: Maybe<Version>;
|
||||
};
|
||||
|
||||
export enum ProjectVersionsUpdatedMessageType {
|
||||
Created = 'CREATED',
|
||||
Deleted = 'DELETED',
|
||||
Updated = 'UPDATED'
|
||||
}
|
||||
export const ProjectVersionsUpdatedMessageType = {
|
||||
Created: 'CREATED',
|
||||
Deleted: 'DELETED',
|
||||
Updated: 'UPDATED'
|
||||
} as const;
|
||||
|
||||
export enum ProjectVisibility {
|
||||
Private = 'PRIVATE',
|
||||
Public = 'PUBLIC',
|
||||
Unlisted = 'UNLISTED'
|
||||
}
|
||||
export type ProjectVersionsUpdatedMessageType = typeof ProjectVersionsUpdatedMessageType[keyof typeof ProjectVersionsUpdatedMessageType];
|
||||
export const ProjectVisibility = {
|
||||
Private: 'PRIVATE',
|
||||
Public: 'PUBLIC',
|
||||
Unlisted: 'UNLISTED'
|
||||
} as const;
|
||||
|
||||
export type ProjectVisibility = typeof ProjectVisibility[keyof typeof ProjectVisibility];
|
||||
export type Query = {
|
||||
__typename?: 'Query';
|
||||
/** Stare into the void. */
|
||||
@@ -2643,7 +2707,6 @@ export type Query = {
|
||||
* Either token or workspaceId must be specified, or both
|
||||
*/
|
||||
workspaceInvite?: Maybe<PendingWorkspaceCollaborator>;
|
||||
workspacePricingPlans: Scalars['JSONObject']['output'];
|
||||
/** Find workspaces a given user email can use SSO to sign with */
|
||||
workspaceSsoByEmail: Array<LimitedWorkspace>;
|
||||
};
|
||||
@@ -2830,13 +2893,14 @@ export type ResourceIdentifierInput = {
|
||||
resourceType: ResourceType;
|
||||
};
|
||||
|
||||
export enum ResourceType {
|
||||
Comment = 'comment',
|
||||
Commit = 'commit',
|
||||
Object = 'object',
|
||||
Stream = 'stream'
|
||||
}
|
||||
export const ResourceType = {
|
||||
Comment: 'comment',
|
||||
Commit: 'commit',
|
||||
Object: 'object',
|
||||
Stream: 'stream'
|
||||
} as const;
|
||||
|
||||
export type ResourceType = typeof ResourceType[keyof typeof ResourceType];
|
||||
export type Role = {
|
||||
__typename?: 'Role';
|
||||
description: Scalars['String']['output'];
|
||||
@@ -3000,13 +3064,14 @@ export type ServerRegionMutationsUpdateArgs = {
|
||||
input: UpdateServerRegionInput;
|
||||
};
|
||||
|
||||
export enum ServerRole {
|
||||
ServerAdmin = 'SERVER_ADMIN',
|
||||
ServerArchivedUser = 'SERVER_ARCHIVED_USER',
|
||||
ServerGuest = 'SERVER_GUEST',
|
||||
ServerUser = 'SERVER_USER'
|
||||
}
|
||||
export const ServerRole = {
|
||||
ServerAdmin: 'SERVER_ADMIN',
|
||||
ServerArchivedUser: 'SERVER_ARCHIVED_USER',
|
||||
ServerGuest: 'SERVER_GUEST',
|
||||
ServerUser: 'SERVER_USER'
|
||||
} as const;
|
||||
|
||||
export type ServerRole = typeof ServerRole[keyof typeof ServerRole];
|
||||
export type ServerRoleItem = {
|
||||
__typename?: 'ServerRoleItem';
|
||||
id: Scalars['String']['output'];
|
||||
@@ -3045,11 +3110,12 @@ export type ServerWorkspacesInfo = {
|
||||
workspacesEnabled: Scalars['Boolean']['output'];
|
||||
};
|
||||
|
||||
export enum SessionPaymentStatus {
|
||||
Paid = 'paid',
|
||||
Unpaid = 'unpaid'
|
||||
}
|
||||
export const SessionPaymentStatus = {
|
||||
Paid: 'paid',
|
||||
Unpaid: 'unpaid'
|
||||
} as const;
|
||||
|
||||
export type SessionPaymentStatus = typeof SessionPaymentStatus[keyof typeof SessionPaymentStatus];
|
||||
export type SetPrimaryUserEmailInput = {
|
||||
id: Scalars['ID']['input'];
|
||||
};
|
||||
@@ -3069,11 +3135,12 @@ export type SmartTextEditorValue = {
|
||||
version: Scalars['String']['output'];
|
||||
};
|
||||
|
||||
export enum SortDirection {
|
||||
Asc = 'ASC',
|
||||
Desc = 'DESC'
|
||||
}
|
||||
export const SortDirection = {
|
||||
Asc: 'ASC',
|
||||
Desc: 'DESC'
|
||||
} as const;
|
||||
|
||||
export type SortDirection = typeof SortDirection[keyof typeof SortDirection];
|
||||
export type Stream = {
|
||||
__typename?: 'Stream';
|
||||
/**
|
||||
@@ -3268,12 +3335,13 @@ export type StreamRevokePermissionInput = {
|
||||
userId: Scalars['String']['input'];
|
||||
};
|
||||
|
||||
export enum StreamRole {
|
||||
StreamContributor = 'STREAM_CONTRIBUTOR',
|
||||
StreamOwner = 'STREAM_OWNER',
|
||||
StreamReviewer = 'STREAM_REVIEWER'
|
||||
}
|
||||
export const StreamRole = {
|
||||
StreamContributor: 'STREAM_CONTRIBUTOR',
|
||||
StreamOwner: 'STREAM_OWNER',
|
||||
StreamReviewer: 'STREAM_REVIEWER'
|
||||
} as const;
|
||||
|
||||
export type StreamRole = typeof StreamRole[keyof typeof StreamRole];
|
||||
export type StreamUpdateInput = {
|
||||
allowPublicComments?: InputMaybe<Scalars['Boolean']['input']>;
|
||||
description?: InputMaybe<Scalars['String']['input']>;
|
||||
@@ -3589,11 +3657,12 @@ export type TokenResourceIdentifierInput = {
|
||||
type: TokenResourceIdentifierType;
|
||||
};
|
||||
|
||||
export enum TokenResourceIdentifierType {
|
||||
Project = 'project',
|
||||
Workspace = 'workspace'
|
||||
}
|
||||
export const TokenResourceIdentifierType = {
|
||||
Project: 'project',
|
||||
Workspace: 'workspace'
|
||||
} as const;
|
||||
|
||||
export type TokenResourceIdentifierType = typeof TokenResourceIdentifierType[keyof typeof TokenResourceIdentifierType];
|
||||
export type TriggeredAutomationsStatus = {
|
||||
__typename?: 'TriggeredAutomationsStatus';
|
||||
automationRuns: Array<AutomateRun>;
|
||||
@@ -3729,6 +3798,7 @@ export type User = {
|
||||
versions: CountOnlyCollection;
|
||||
/** Get all invitations to workspaces that the active user has */
|
||||
workspaceInvites: Array<PendingWorkspaceCollaborator>;
|
||||
workspaceJoinRequests?: Maybe<LimitedWorkspaceJoinRequestCollection>;
|
||||
/** Get the workspaces for the user */
|
||||
workspaces: WorkspaceCollection;
|
||||
};
|
||||
@@ -3830,6 +3900,17 @@ export type UserVersionsArgs = {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Full user type, should only be used in the context of admin operations or
|
||||
* when a user is reading/writing info about himself
|
||||
*/
|
||||
export type UserWorkspaceJoinRequestsArgs = {
|
||||
cursor?: InputMaybe<Scalars['String']['input']>;
|
||||
filter?: InputMaybe<WorkspaceJoinRequestFilter>;
|
||||
limit?: Scalars['Int']['input'];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Full user type, should only be used in the context of admin operations or
|
||||
* when a user is reading/writing info about himself
|
||||
@@ -3926,11 +4007,12 @@ export type UserProjectsUpdatedMessage = {
|
||||
type: UserProjectsUpdatedMessageType;
|
||||
};
|
||||
|
||||
export enum UserProjectsUpdatedMessageType {
|
||||
Added = 'ADDED',
|
||||
Removed = 'REMOVED'
|
||||
}
|
||||
export const UserProjectsUpdatedMessageType = {
|
||||
Added: 'ADDED',
|
||||
Removed: 'REMOVED'
|
||||
} as const;
|
||||
|
||||
export type UserProjectsUpdatedMessageType = typeof UserProjectsUpdatedMessageType[keyof typeof UserProjectsUpdatedMessageType];
|
||||
export type UserRoleInput = {
|
||||
id: Scalars['String']['input'];
|
||||
role: Scalars['String']['input'];
|
||||
@@ -4120,11 +4202,12 @@ export type ViewerUserActivityMessageInput = {
|
||||
userName: Scalars['String']['input'];
|
||||
};
|
||||
|
||||
export enum ViewerUserActivityStatus {
|
||||
Disconnected = 'DISCONNECTED',
|
||||
Viewing = 'VIEWING'
|
||||
}
|
||||
export const ViewerUserActivityStatus = {
|
||||
Disconnected: 'DISCONNECTED',
|
||||
Viewing: 'VIEWING'
|
||||
} as const;
|
||||
|
||||
export type ViewerUserActivityStatus = typeof ViewerUserActivityStatus[keyof typeof ViewerUserActivityStatus];
|
||||
export type Webhook = {
|
||||
__typename?: 'Webhook';
|
||||
description?: Maybe<Scalars['String']['output']>;
|
||||
@@ -4352,12 +4435,13 @@ export type WorkspaceDomainDeleteInput = {
|
||||
workspaceId: Scalars['ID']['input'];
|
||||
};
|
||||
|
||||
export enum WorkspaceFeatureName {
|
||||
DomainBasedSecurityPolicies = 'domainBasedSecurityPolicies',
|
||||
OidcSso = 'oidcSso',
|
||||
WorkspaceDataRegionSpecificity = 'workspaceDataRegionSpecificity'
|
||||
}
|
||||
export const WorkspaceFeatureName = {
|
||||
DomainBasedSecurityPolicies: 'domainBasedSecurityPolicies',
|
||||
OidcSso: 'oidcSso',
|
||||
WorkspaceDataRegionSpecificity: 'workspaceDataRegionSpecificity'
|
||||
} as const;
|
||||
|
||||
export type WorkspaceFeatureName = typeof WorkspaceFeatureName[keyof typeof WorkspaceFeatureName];
|
||||
export type WorkspaceInviteCreateInput = {
|
||||
/** Either this or userId must be filled */
|
||||
email?: InputMaybe<Scalars['String']['input']>;
|
||||
@@ -4442,6 +4526,10 @@ export type WorkspaceJoinRequestCollection = {
|
||||
totalCount: Scalars['Int']['output'];
|
||||
};
|
||||
|
||||
export type WorkspaceJoinRequestFilter = {
|
||||
status?: InputMaybe<WorkspaceJoinRequestStatus>;
|
||||
};
|
||||
|
||||
export type WorkspaceJoinRequestMutations = {
|
||||
__typename?: 'WorkspaceJoinRequestMutations';
|
||||
approve: Scalars['Boolean']['output'];
|
||||
@@ -4458,12 +4546,13 @@ export type WorkspaceJoinRequestMutationsDenyArgs = {
|
||||
input: DenyWorkspaceJoinRequestInput;
|
||||
};
|
||||
|
||||
export enum WorkspaceJoinRequestStatus {
|
||||
Approved = 'approved',
|
||||
Denied = 'denied',
|
||||
Pending = 'pending'
|
||||
}
|
||||
export const WorkspaceJoinRequestStatus = {
|
||||
Approved: 'approved',
|
||||
Denied: 'denied',
|
||||
Pending: 'pending'
|
||||
} as const;
|
||||
|
||||
export type WorkspaceJoinRequestStatus = typeof WorkspaceJoinRequestStatus[keyof typeof WorkspaceJoinRequestStatus];
|
||||
export type WorkspaceMutations = {
|
||||
__typename?: 'WorkspaceMutations';
|
||||
addDomain: Workspace;
|
||||
@@ -4552,12 +4641,13 @@ export type WorkspaceMutationsUpdateRoleArgs = {
|
||||
input: WorkspaceRoleUpdateInput;
|
||||
};
|
||||
|
||||
export enum WorkspacePaymentMethod {
|
||||
Billing = 'billing',
|
||||
Invoice = 'invoice',
|
||||
Unpaid = 'unpaid'
|
||||
}
|
||||
export const WorkspacePaymentMethod = {
|
||||
Billing: 'billing',
|
||||
Invoice: 'invoice',
|
||||
Unpaid: 'unpaid'
|
||||
} as const;
|
||||
|
||||
export type WorkspacePaymentMethod = typeof WorkspacePaymentMethod[keyof typeof WorkspacePaymentMethod];
|
||||
export type WorkspacePlan = {
|
||||
__typename?: 'WorkspacePlan';
|
||||
createdAt: Scalars['DateTime']['output'];
|
||||
@@ -4566,27 +4656,31 @@ export type WorkspacePlan = {
|
||||
status: WorkspacePlanStatuses;
|
||||
};
|
||||
|
||||
export enum WorkspacePlanStatuses {
|
||||
CancelationScheduled = 'cancelationScheduled',
|
||||
Canceled = 'canceled',
|
||||
Expired = 'expired',
|
||||
PaymentFailed = 'paymentFailed',
|
||||
Trial = 'trial',
|
||||
Valid = 'valid'
|
||||
}
|
||||
export const WorkspacePlanStatuses = {
|
||||
CancelationScheduled: 'cancelationScheduled',
|
||||
Canceled: 'canceled',
|
||||
Expired: 'expired',
|
||||
PaymentFailed: 'paymentFailed',
|
||||
Trial: 'trial',
|
||||
Valid: 'valid'
|
||||
} as const;
|
||||
|
||||
export enum WorkspacePlans {
|
||||
Academia = 'academia',
|
||||
Business = 'business',
|
||||
BusinessInvoiced = 'businessInvoiced',
|
||||
Free = 'free',
|
||||
Plus = 'plus',
|
||||
PlusInvoiced = 'plusInvoiced',
|
||||
Starter = 'starter',
|
||||
StarterInvoiced = 'starterInvoiced',
|
||||
Unlimited = 'unlimited'
|
||||
}
|
||||
export type WorkspacePlanStatuses = typeof WorkspacePlanStatuses[keyof typeof WorkspacePlanStatuses];
|
||||
export const WorkspacePlans = {
|
||||
Academia: 'academia',
|
||||
Business: 'business',
|
||||
BusinessInvoiced: 'businessInvoiced',
|
||||
Free: 'free',
|
||||
Plus: 'plus',
|
||||
PlusInvoiced: 'plusInvoiced',
|
||||
Pro: 'pro',
|
||||
Starter: 'starter',
|
||||
StarterInvoiced: 'starterInvoiced',
|
||||
Team: 'team',
|
||||
Unlimited: 'unlimited'
|
||||
} as const;
|
||||
|
||||
export type WorkspacePlans = typeof WorkspacePlans[keyof typeof WorkspacePlans];
|
||||
export type WorkspaceProjectCreateInput = {
|
||||
description?: InputMaybe<Scalars['String']['input']>;
|
||||
name?: InputMaybe<Scalars['String']['input']>;
|
||||
@@ -4658,21 +4752,23 @@ export type WorkspaceProjectsUpdatedMessage = {
|
||||
workspaceId: Scalars['String']['output'];
|
||||
};
|
||||
|
||||
export enum WorkspaceProjectsUpdatedMessageType {
|
||||
Added = 'ADDED',
|
||||
Removed = 'REMOVED'
|
||||
}
|
||||
export const WorkspaceProjectsUpdatedMessageType = {
|
||||
Added: 'ADDED',
|
||||
Removed: 'REMOVED'
|
||||
} as const;
|
||||
|
||||
export type WorkspaceProjectsUpdatedMessageType = typeof WorkspaceProjectsUpdatedMessageType[keyof typeof WorkspaceProjectsUpdatedMessageType];
|
||||
export type WorkspaceRequestToJoinInput = {
|
||||
workspaceId: Scalars['ID']['input'];
|
||||
};
|
||||
|
||||
export enum WorkspaceRole {
|
||||
Admin = 'ADMIN',
|
||||
Guest = 'GUEST',
|
||||
Member = 'MEMBER'
|
||||
}
|
||||
export const WorkspaceRole = {
|
||||
Admin: 'ADMIN',
|
||||
Guest: 'GUEST',
|
||||
Member: 'MEMBER'
|
||||
} as const;
|
||||
|
||||
export type WorkspaceRole = typeof WorkspaceRole[keyof typeof WorkspaceRole];
|
||||
export type WorkspaceRoleDeleteInput = {
|
||||
userId: Scalars['String']['input'];
|
||||
workspaceId: Scalars['String']['input'];
|
||||
@@ -4915,6 +5011,8 @@ export type ResolversTypes = {
|
||||
DenyWorkspaceJoinRequestInput: DenyWorkspaceJoinRequestInput;
|
||||
DiscoverableStreamsSortType: DiscoverableStreamsSortType;
|
||||
DiscoverableStreamsSortingInput: DiscoverableStreamsSortingInput;
|
||||
DiscoverableWorkspaceCollaborator: ResolverTypeWrapper<DiscoverableWorkspaceCollaborator>;
|
||||
DiscoverableWorkspaceCollaboratorCollection: ResolverTypeWrapper<DiscoverableWorkspaceCollaboratorCollection>;
|
||||
EditCommentInput: EditCommentInput;
|
||||
EmailVerificationRequestInput: EmailVerificationRequestInput;
|
||||
FileUpload: ResolverTypeWrapper<FileUploadGraphQLReturn>;
|
||||
@@ -4929,6 +5027,8 @@ export type ResolversTypes = {
|
||||
LegacyCommentViewerData: ResolverTypeWrapper<LegacyCommentViewerData>;
|
||||
LimitedUser: ResolverTypeWrapper<LimitedUserGraphQLReturn>;
|
||||
LimitedWorkspace: ResolverTypeWrapper<LimitedWorkspace>;
|
||||
LimitedWorkspaceJoinRequest: ResolverTypeWrapper<LimitedWorkspaceJoinRequestGraphQLReturn>;
|
||||
LimitedWorkspaceJoinRequestCollection: ResolverTypeWrapper<Omit<LimitedWorkspaceJoinRequestCollection, 'items'> & { items: Array<ResolversTypes['LimitedWorkspaceJoinRequest']> }>;
|
||||
MarkCommentViewedInput: MarkCommentViewedInput;
|
||||
MarkReceivedVersionInput: MarkReceivedVersionInput;
|
||||
Model: ResolverTypeWrapper<ModelGraphQLReturn>;
|
||||
@@ -4942,6 +5042,7 @@ export type ResolversTypes = {
|
||||
Object: ResolverTypeWrapper<ObjectGraphQLReturn>;
|
||||
ObjectCollection: ResolverTypeWrapper<Omit<ObjectCollection, 'objects'> & { objects: Array<ResolversTypes['Object']> }>;
|
||||
ObjectCreateInput: ObjectCreateInput;
|
||||
OnboardingCompletionInput: OnboardingCompletionInput;
|
||||
PaidWorkspacePlans: PaidWorkspacePlans;
|
||||
PasswordStrengthCheckFeedback: ResolverTypeWrapper<PasswordStrengthCheckFeedback>;
|
||||
PasswordStrengthCheckResults: ResolverTypeWrapper<PasswordStrengthCheckResults>;
|
||||
@@ -5097,6 +5198,7 @@ export type ResolversTypes = {
|
||||
WorkspaceInviteUseInput: WorkspaceInviteUseInput;
|
||||
WorkspaceJoinRequest: ResolverTypeWrapper<WorkspaceJoinRequestGraphQLReturn>;
|
||||
WorkspaceJoinRequestCollection: ResolverTypeWrapper<Omit<WorkspaceJoinRequestCollection, 'items'> & { items: Array<ResolversTypes['WorkspaceJoinRequest']> }>;
|
||||
WorkspaceJoinRequestFilter: WorkspaceJoinRequestFilter;
|
||||
WorkspaceJoinRequestMutations: ResolverTypeWrapper<WorkspaceJoinRequestMutationsGraphQLReturn>;
|
||||
WorkspaceJoinRequestStatus: WorkspaceJoinRequestStatus;
|
||||
WorkspaceMutations: ResolverTypeWrapper<WorkspaceMutationsGraphQLReturn>;
|
||||
@@ -5217,6 +5319,8 @@ export type ResolversParentTypes = {
|
||||
DeleteVersionsInput: DeleteVersionsInput;
|
||||
DenyWorkspaceJoinRequestInput: DenyWorkspaceJoinRequestInput;
|
||||
DiscoverableStreamsSortingInput: DiscoverableStreamsSortingInput;
|
||||
DiscoverableWorkspaceCollaborator: DiscoverableWorkspaceCollaborator;
|
||||
DiscoverableWorkspaceCollaboratorCollection: DiscoverableWorkspaceCollaboratorCollection;
|
||||
EditCommentInput: EditCommentInput;
|
||||
EmailVerificationRequestInput: EmailVerificationRequestInput;
|
||||
FileUpload: FileUploadGraphQLReturn;
|
||||
@@ -5231,6 +5335,8 @@ export type ResolversParentTypes = {
|
||||
LegacyCommentViewerData: LegacyCommentViewerData;
|
||||
LimitedUser: LimitedUserGraphQLReturn;
|
||||
LimitedWorkspace: LimitedWorkspace;
|
||||
LimitedWorkspaceJoinRequest: LimitedWorkspaceJoinRequestGraphQLReturn;
|
||||
LimitedWorkspaceJoinRequestCollection: Omit<LimitedWorkspaceJoinRequestCollection, 'items'> & { items: Array<ResolversParentTypes['LimitedWorkspaceJoinRequest']> };
|
||||
MarkCommentViewedInput: MarkCommentViewedInput;
|
||||
MarkReceivedVersionInput: MarkReceivedVersionInput;
|
||||
Model: ModelGraphQLReturn;
|
||||
@@ -5244,6 +5350,7 @@ export type ResolversParentTypes = {
|
||||
Object: ObjectGraphQLReturn;
|
||||
ObjectCollection: Omit<ObjectCollection, 'objects'> & { objects: Array<ResolversParentTypes['Object']> };
|
||||
ObjectCreateInput: ObjectCreateInput;
|
||||
OnboardingCompletionInput: OnboardingCompletionInput;
|
||||
PasswordStrengthCheckFeedback: PasswordStrengthCheckFeedback;
|
||||
PasswordStrengthCheckResults: PasswordStrengthCheckResults;
|
||||
PendingStreamCollaborator: PendingStreamCollaboratorGraphQLReturn;
|
||||
@@ -5379,6 +5486,7 @@ export type ResolversParentTypes = {
|
||||
WorkspaceInviteUseInput: WorkspaceInviteUseInput;
|
||||
WorkspaceJoinRequest: WorkspaceJoinRequestGraphQLReturn;
|
||||
WorkspaceJoinRequestCollection: Omit<WorkspaceJoinRequestCollection, 'items'> & { items: Array<ResolversParentTypes['WorkspaceJoinRequest']> };
|
||||
WorkspaceJoinRequestFilter: WorkspaceJoinRequestFilter;
|
||||
WorkspaceJoinRequestMutations: WorkspaceJoinRequestMutationsGraphQLReturn;
|
||||
WorkspaceMutations: WorkspaceMutationsGraphQLReturn;
|
||||
WorkspacePlan: WorkspacePlan;
|
||||
@@ -5436,7 +5544,7 @@ export type IsOwnerDirectiveResolver<Result, Parent, ContextType = GraphQLContex
|
||||
|
||||
export type ActiveUserMutationsResolvers<ContextType = GraphQLContext, ParentType extends ResolversParentTypes['ActiveUserMutations'] = ResolversParentTypes['ActiveUserMutations']> = {
|
||||
emailMutations?: Resolver<ResolversTypes['UserEmailMutations'], ParentType, ContextType>;
|
||||
finishOnboarding?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType>;
|
||||
finishOnboarding?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType, Partial<ActiveUserMutationsFinishOnboardingArgs>>;
|
||||
update?: Resolver<ResolversTypes['User'], ParentType, ContextType, RequireFields<ActiveUserMutationsUpdateArgs, 'user'>>;
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
};
|
||||
@@ -5844,6 +5952,18 @@ export interface DateTimeScalarConfig extends GraphQLScalarTypeConfig<ResolversT
|
||||
name: 'DateTime';
|
||||
}
|
||||
|
||||
export type DiscoverableWorkspaceCollaboratorResolvers<ContextType = GraphQLContext, ParentType extends ResolversParentTypes['DiscoverableWorkspaceCollaborator'] = ResolversParentTypes['DiscoverableWorkspaceCollaborator']> = {
|
||||
avatar?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type DiscoverableWorkspaceCollaboratorCollectionResolvers<ContextType = GraphQLContext, ParentType extends ResolversParentTypes['DiscoverableWorkspaceCollaboratorCollection'] = ResolversParentTypes['DiscoverableWorkspaceCollaboratorCollection']> = {
|
||||
cursor?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
|
||||
items?: Resolver<Array<ResolversTypes['DiscoverableWorkspaceCollaborator']>, ParentType, ContextType>;
|
||||
totalCount?: Resolver<ResolversTypes['Int'], ParentType, ContextType>;
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type FileUploadResolvers<ContextType = GraphQLContext, ParentType extends ResolversParentTypes['FileUpload'] = ResolversParentTypes['FileUpload']> = {
|
||||
branchName?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
|
||||
convertedCommitId?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
|
||||
@@ -5925,6 +6045,23 @@ export type LimitedWorkspaceResolvers<ContextType = GraphQLContext, ParentType e
|
||||
logo?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
|
||||
name?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
|
||||
slug?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
|
||||
team?: Resolver<Maybe<ResolversTypes['DiscoverableWorkspaceCollaboratorCollection']>, ParentType, ContextType, RequireFields<LimitedWorkspaceTeamArgs, 'limit'>>;
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type LimitedWorkspaceJoinRequestResolvers<ContextType = GraphQLContext, ParentType extends ResolversParentTypes['LimitedWorkspaceJoinRequest'] = ResolversParentTypes['LimitedWorkspaceJoinRequest']> = {
|
||||
createdAt?: Resolver<ResolversTypes['DateTime'], ParentType, ContextType>;
|
||||
id?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
|
||||
status?: Resolver<ResolversTypes['WorkspaceJoinRequestStatus'], ParentType, ContextType>;
|
||||
user?: Resolver<ResolversTypes['LimitedUser'], ParentType, ContextType>;
|
||||
workspace?: Resolver<ResolversTypes['LimitedWorkspace'], ParentType, ContextType>;
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type LimitedWorkspaceJoinRequestCollectionResolvers<ContextType = GraphQLContext, ParentType extends ResolversParentTypes['LimitedWorkspaceJoinRequestCollection'] = ResolversParentTypes['LimitedWorkspaceJoinRequestCollection']> = {
|
||||
cursor?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
|
||||
items?: Resolver<Array<ResolversTypes['LimitedWorkspaceJoinRequest']>, ParentType, ContextType>;
|
||||
totalCount?: Resolver<ResolversTypes['Int'], ParentType, ContextType>;
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
};
|
||||
|
||||
@@ -6330,7 +6467,6 @@ export type QueryResolvers<ContextType = GraphQLContext, ParentType extends Reso
|
||||
workspace?: Resolver<ResolversTypes['Workspace'], ParentType, ContextType, RequireFields<QueryWorkspaceArgs, 'id'>>;
|
||||
workspaceBySlug?: Resolver<ResolversTypes['Workspace'], ParentType, ContextType, RequireFields<QueryWorkspaceBySlugArgs, 'slug'>>;
|
||||
workspaceInvite?: Resolver<Maybe<ResolversTypes['PendingWorkspaceCollaborator']>, ParentType, ContextType, Partial<QueryWorkspaceInviteArgs>>;
|
||||
workspacePricingPlans?: Resolver<ResolversTypes['JSONObject'], ParentType, ContextType>;
|
||||
workspaceSsoByEmail?: Resolver<Array<ResolversTypes['LimitedWorkspace']>, ParentType, ContextType, RequireFields<QueryWorkspaceSsoByEmailArgs, 'email'>>;
|
||||
};
|
||||
|
||||
@@ -6653,6 +6789,7 @@ export type UserResolvers<ContextType = GraphQLContext, ParentType extends Resol
|
||||
verified?: Resolver<Maybe<ResolversTypes['Boolean']>, ParentType, ContextType>;
|
||||
versions?: Resolver<ResolversTypes['CountOnlyCollection'], ParentType, ContextType, RequireFields<UserVersionsArgs, 'authoredOnly' | 'limit'>>;
|
||||
workspaceInvites?: Resolver<Array<ResolversTypes['PendingWorkspaceCollaborator']>, ParentType, ContextType>;
|
||||
workspaceJoinRequests?: Resolver<Maybe<ResolversTypes['LimitedWorkspaceJoinRequestCollection']>, ParentType, ContextType, RequireFields<UserWorkspaceJoinRequestsArgs, 'limit'>>;
|
||||
workspaces?: Resolver<ResolversTypes['WorkspaceCollection'], ParentType, ContextType, RequireFields<UserWorkspacesArgs, 'cursor' | 'limit'>>;
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
};
|
||||
@@ -7058,6 +7195,8 @@ export type Resolvers<ContextType = GraphQLContext> = {
|
||||
CommitCollection?: CommitCollectionResolvers<ContextType>;
|
||||
CountOnlyCollection?: CountOnlyCollectionResolvers<ContextType>;
|
||||
DateTime?: GraphQLScalarType;
|
||||
DiscoverableWorkspaceCollaborator?: DiscoverableWorkspaceCollaboratorResolvers<ContextType>;
|
||||
DiscoverableWorkspaceCollaboratorCollection?: DiscoverableWorkspaceCollaboratorCollectionResolvers<ContextType>;
|
||||
FileUpload?: FileUploadResolvers<ContextType>;
|
||||
GendoAIRender?: GendoAiRenderResolvers<ContextType>;
|
||||
GendoAIRenderCollection?: GendoAiRenderCollectionResolvers<ContextType>;
|
||||
@@ -7065,6 +7204,8 @@ export type Resolvers<ContextType = GraphQLContext> = {
|
||||
LegacyCommentViewerData?: LegacyCommentViewerDataResolvers<ContextType>;
|
||||
LimitedUser?: LimitedUserResolvers<ContextType>;
|
||||
LimitedWorkspace?: LimitedWorkspaceResolvers<ContextType>;
|
||||
LimitedWorkspaceJoinRequest?: LimitedWorkspaceJoinRequestResolvers<ContextType>;
|
||||
LimitedWorkspaceJoinRequestCollection?: LimitedWorkspaceJoinRequestCollectionResolvers<ContextType>;
|
||||
Model?: ModelResolvers<ContextType>;
|
||||
ModelCollection?: ModelCollectionResolvers<ContextType>;
|
||||
ModelMutations?: ModelMutationsResolvers<ContextType>;
|
||||
|
||||
@@ -40,6 +40,11 @@ import { getAdminUsersListCollectionFactory } from '@/modules/core/services/user
|
||||
import { Resolvers } from '@/modules/core/graph/generated/graphql'
|
||||
import { getServerInfoFactory } from '@/modules/core/repositories/server'
|
||||
import { getEventBus } from '@/modules/shared/services/eventBus'
|
||||
import {
|
||||
getMailchimpStatus,
|
||||
getMailchimpOnboardingIds
|
||||
} from '@/modules/shared/helpers/envHelper'
|
||||
import { updateMailchimpMemberTags } from '@/modules/auth/services/mailchimp'
|
||||
|
||||
const getUser = legacyGetUserFactory({ db })
|
||||
const getUserByEmail = legacyGetUserByEmailFactory({ db })
|
||||
@@ -248,8 +253,30 @@ export = {
|
||||
activeUserMutations: () => ({})
|
||||
},
|
||||
ActiveUserMutations: {
|
||||
async finishOnboarding(_parent, _args, ctx) {
|
||||
return await markOnboardingComplete(ctx.userId || '')
|
||||
async finishOnboarding(_parent, args, ctx) {
|
||||
const userId = ctx.userId
|
||||
if (!userId) return false
|
||||
|
||||
const success = await markOnboardingComplete(userId)
|
||||
|
||||
// If onboarding was marked complete successfully and we have onboarding data
|
||||
if (success && args.input && getMailchimpStatus()) {
|
||||
try {
|
||||
const user = await getUser(userId)
|
||||
const { listId } = getMailchimpOnboardingIds()
|
||||
|
||||
await updateMailchimpMemberTags(user, listId, {
|
||||
role: args.input?.role || undefined,
|
||||
plans: args.input?.plans || undefined,
|
||||
source: args.input?.source || undefined
|
||||
})
|
||||
} catch (error) {
|
||||
// Log but don't fail the request
|
||||
ctx.log.warn({ err: error }, 'Failed to update Mailchimp tags')
|
||||
}
|
||||
}
|
||||
|
||||
return success
|
||||
},
|
||||
async update(_parent, args, context) {
|
||||
const newUser = await updateUserAndNotify(context.userId!, args.user)
|
||||
|
||||
@@ -21,11 +21,16 @@ import {
|
||||
UserUpdateError,
|
||||
UserValidationError
|
||||
} from '@/modules/core/errors/user'
|
||||
import { PasswordTooShortError, UserInputError } from '@/modules/core/errors/userinput'
|
||||
import {
|
||||
BlockedEmailDomainError,
|
||||
PasswordTooShortError,
|
||||
UserInputError
|
||||
} from '@/modules/core/errors/userinput'
|
||||
import { UserUpdateInput } from '@/modules/core/graph/generated/graphql'
|
||||
import type { UserRecord } from '@/modules/core/helpers/userHelper'
|
||||
import { sanitizeImageUrl } from '@/modules/shared/helpers/sanitization'
|
||||
import {
|
||||
blockedDomains,
|
||||
isNullOrUndefined,
|
||||
NullableKeysToOptional,
|
||||
Roles,
|
||||
@@ -48,6 +53,9 @@ import { DeleteAllUserInvites } from '@/modules/serverinvites/domain/operations'
|
||||
import { GetServerInfo } from '@/modules/core/domain/server/operations'
|
||||
import { EventBusEmit } from '@/modules/shared/services/eventBus'
|
||||
import { UserEvents } from '@/modules/core/domain/users/events'
|
||||
import { getFeatureFlags } from '@/modules/shared/helpers/envHelper'
|
||||
|
||||
const { FF_NO_PERSONAL_EMAILS_ENABLED } = getFeatureFlags()
|
||||
|
||||
export const MINIMUM_PASSWORD_LENGTH = 8
|
||||
|
||||
@@ -163,6 +171,15 @@ export const createUserFactory =
|
||||
|
||||
if (!finalUser.email?.length) throw new UserInputError('E-mail address is required')
|
||||
|
||||
// Temporary experiment: require work emails for all new users
|
||||
const isBlockedDomain = blockedDomains.includes(
|
||||
finalUser.email.split('@')[1]?.toLowerCase()
|
||||
)
|
||||
const requireWorkDomain =
|
||||
!user?.signUpContext?.isInvite && FF_NO_PERSONAL_EMAILS_ENABLED
|
||||
|
||||
if (requireWorkDomain && isBlockedDomain) throw new BlockedEmailDomainError()
|
||||
|
||||
let expectedRole = null
|
||||
if (finalUser.role) {
|
||||
const isValidRole = Object.values(Roles.Server).includes(finalUser.role)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user