Compare commits

..

5 Commits

Author SHA1 Message Date
Kristaps Fabians Geikins d0b654a097 trigger deploy 2025-05-13 16:11:35 +03:00
Kristaps Fabians Geikins 404fb4ed33 trigger deploy 2025-05-13 16:08:05 +03:00
Kristaps Fabians Geikins ab833decdb vscode settings 2025-05-13 15:08:59 +03:00
Kristaps Fabians Geikins 694eb4056d various fixes 2025-05-13 15:00:54 +03:00
Kristaps Fabians Geikins 785d315868 stuff copied over, but aint workin 2025-05-13 14:16:10 +03:00
46 changed files with 1717 additions and 1361 deletions
+1
View File
File diff suppressed because one or more lines are too long
-44
View File
@@ -1,44 +0,0 @@
name: Linting
on:
pull_request:
branches:
- main
jobs:
lint-and-build:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22.14.0'
- name: Enable Corepack and Install Correct Yarn Version
run: |
corepack enable
corepack prepare yarn@$(jq -r .packageManager package.json | cut -d'@' -f2) --activate
yarn --version
- name: Cache node_modules
uses: actions/cache@v4
with:
path: |
**/node_modules
.yarn/cache
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install Dependencies
run: yarn install --immutable
- name: Run Linter
run: yarn lint
- name: Run generate
run: yarn generate
-35
View File
@@ -1,35 +0,0 @@
node_modules
build
dist
dist2
dist-*
coverage
.nyc_output
.output
.nuxt
**/nuxt-modules/**/templates/*.js
/lib/common/generated/**/*
package-lock.json
yarn.lock
.yarn
# Profiler output
events.json
# Prettier doesn't understand the syntax inside the Yaml files, because of the brackets
utils/helm/speckle-server/templates
# Optional eslint cache
.eslintcache
.venv
venv
.*.{ts,js,vue,tsx,jsx}
**/generated/**/*
**/generated/graphql.ts
storybook-static
.tshy
.tshy-build
-11
View File
@@ -1,11 +0,0 @@
{
"trailingComma": "none",
"tabWidth": 2,
"semi": false,
"endOfLine": "auto",
"bracketSpacing": true,
"vueIndentScriptAndStyle": false,
"htmlWhitespaceSensitivity": "ignore",
"printWidth": 88,
"singleQuote": true
}
+16 -16
View File
@@ -1,18 +1,18 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
// List of extensions which should be recommended for users of this workspace.
"recommendations": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"Vue.volar",
"bradlc.vscode-tailwindcss",
"stylelint.vscode-stylelint",
"cpylua.language-postcss",
"graphql.vscode-graphql",
"graphql.vscode-graphql-syntax"
],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": ["octref.vetur"]
}
// List of extensions which should be recommended for users of this workspace.
"recommendations": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"Vue.volar",
"bradlc.vscode-tailwindcss",
"stylelint.vscode-stylelint",
"cpylua.language-postcss",
"graphql.vscode-graphql",
"graphql.vscode-graphql-syntax"
],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": ["octref.vetur"]
}
+1 -1
View File
@@ -1 +1 @@
nodeLinker: node-modules
nodeLinker: node-modules
+12 -6
View File
@@ -1,6 +1,6 @@
# Speckle Connectors DUI
# dui3
DUI v3 is a Speckle interface embedded inside the desktop connectors that allows users to interact with them - sync streams, manage servers etc. It's built in Vue 3 with Nuxt 3 and only supports client side rendering.
DUIv3 is a Speckle interface embedded inside the desktop connectors that allows users to interact with them - sync streams, manage servers etc. It's built in Vue 3 with Nuxt 3 and only supports client side rendering.
Look at the [Nuxt 3 documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.
@@ -15,12 +15,12 @@ yarn install
And create an `.env` file from `.env.example`.
## Development
## Development Server
Start the development server on `http://localhost:8082`
Start the development server on `http://localhost:3000`
```bash
yarn dev
npm run dev
```
## Production
@@ -28,7 +28,13 @@ yarn dev
Build the application for production:
```bash
yarn build
npm run build
```
Locally preview production build:
```bash
npm run preview
```
Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information...
+1
View File
@@ -52,3 +52,4 @@ onMounted(() => {
})
})
</script>
<style></style>
+1 -2
View File
@@ -1,6 +1,5 @@
/* stylelint-disable selector-id-pattern */
@import url('@speckle/ui-components/style.css');
@import '@speckle/ui-components/style.css';
@tailwind base;
@tailwind components;
@tailwind utilities;
+1 -1
View File
@@ -1,7 +1,7 @@
import type { CodegenConfig } from '@graphql-codegen/cli'
const config: CodegenConfig = {
schema: 'https://app.speckle.systems/graphql',
schema: 'http://127.0.0.1:3000/graphql',
documents: ['{lib,components,layouts,pages,middleware}/**/*.{vue,js,ts}'],
ignoreNoDocuments: true, // for better experience with the watcher
generates: {
+1 -1
View File
@@ -60,7 +60,7 @@
<script setup lang="ts">
import type { DUIAccount } from '~~/store/accounts'
import { TrashIcon } from '@heroicons/vue/24/outline'
import type { BaseBridge } from '~/lib/bridge/base'
import { type BaseBridge } from '~/lib/bridge/base'
const { $accountBinding } = useNuxtApp()
+3 -4
View File
@@ -20,7 +20,7 @@
mount-menu-on-body
>
<template #something-selected="{ value }">
<span>{{ isArray(value) ? value[0].name : value.name }}</span>
<span>{{ value.name }}</span>
</template>
<template #option="{ item }">
<div class="flex items-center">
@@ -80,11 +80,10 @@ import {
createAutomationMutation
} from '~/lib/graphql/mutationsAndQueries'
import { provideApolloClient, useMutation, useQuery } from '@vue/apollo-composable'
import { useAccountStore, type DUIAccount } from '~/store/accounts'
import { useAccountStore } from '~/store/accounts'
import type { ApolloError } from '@apollo/client/errors'
import { formatVersionParams } from '~/lib/common/helpers/jsonSchema'
import { useJsonFormsChangeHandler } from '~/lib/core/composables/jsonSchema'
import { isArray } from 'lodash-es'
const props = defineProps<{
projectId: string
@@ -107,7 +106,7 @@ const toggleDialog = () => {
showAutomateDialog.value = !showAutomateDialog.value
}
const { mutate } = provideApolloClient((activeAccount.value as DUIAccount).client)(() =>
const { mutate } = provideApolloClient(activeAccount.value.client)(() =>
useMutation(createAutomationMutation)
)
-1
View File
@@ -329,7 +329,6 @@ onUnmounted(() => {
html.dialog-open {
overflow: visible !important;
}
html.dialog-open body {
overflow: hidden !important;
}
+2 -20
View File
@@ -19,7 +19,7 @@
<FormButton
v-if="notification.cta"
size="sm"
:color="notificationButtonColor(notification.level)"
:color="notification.level === 'info' ? 'outline' : notification.level"
full-width
@click.stop="notification.cta?.action"
>
@@ -47,10 +47,7 @@
<script setup lang="ts">
import { useTimeoutFn } from '@vueuse/core'
import type {
ModelCardNotification,
ModelCardNotificationLevel
} from '~/lib/models/card/notification'
import type { ModelCardNotification } from '~/lib/models/card/notification'
import { XMarkIcon } from '@heroicons/vue/24/outline'
const props = defineProps<{
notification: ModelCardNotification
@@ -62,21 +59,6 @@ if (props.notification.timeout) {
useTimeoutFn(() => emit('dismiss'), props.notification.timeout)
}
const notificationButtonColor = (notificationLevel: ModelCardNotificationLevel) => {
switch (notificationLevel) {
case 'info':
return 'outline'
case 'danger':
return 'danger'
case 'success':
return 'primary'
case 'warning':
return 'danger'
default:
return 'outline'
}
}
const textClassColor = computed(() => {
switch (props.notification.level) {
case 'danger':
+10 -23
View File
@@ -18,24 +18,18 @@
</div>
</div>
<div
:class="
isPersonalProject ? '' : 'opacity-0 group-hover:opacity-100 transition flex'
"
>
<div class="opacity-0 group-hover:opacity-100 transition flex">
<button
v-tippy="projectNavigatorTippy"
class="hover:text-primary flex items-center space-x-2 p-2 relative animate-pulse"
v-tippy="'Open project in browser'"
class="hover:text-primary flex items-center space-x-2 p-2"
>
<div class="relative w-4 h-4">
<ArrowTopRightOnSquareIcon
class="w-4 h-4"
@click.stop="
$openUrl(projectUrl),
trackEvent('DUI3 Action', { name: 'Project View' }, project.accountId)
"
/>
</div>
<ArrowTopRightOnSquareIcon
class="w-4"
@click.stop="
$openUrl(projectUrl),
trackEvent('DUI3 Action', { name: 'Project View' }, project.accountId)
"
/>
</button>
</div>
</button>
@@ -136,13 +130,6 @@ const projectAccount = computed(() =>
accountStore.accountWithFallback(props.project.accountId, props.project.serverUrl)
)
const isPersonalProject = computed(() => !projectDetails.value?.workspace)
const projectNavigatorTippy = computed(() =>
isPersonalProject.value
? 'Move personal project into a workspace'
: 'Open project in browser'
)
const clientId = projectAccount.value.accountInfo.id
const { result: projectDetailsResult, refetch: refetchProjectDetails } = useQuery(
+1 -1
View File
@@ -8,7 +8,7 @@
</template>
<script setup lang="ts">
import { storeToRefs } from 'pinia'
import type { IDirectSelectionSendFilter, ISendFilter } from '~/lib/models/card/send'
import type { IDirectSelectionSendFilter, ISendFilter } from 'lib/models/card/send'
import { useHostAppStore } from '~~/store/hostApp'
import { useSelectionStore } from '~~/store/selection'
+2 -4
View File
@@ -159,7 +159,7 @@
>
<UserAvatarGroup
size="xs"
:users="[latestCommentNotification.comment?.author as AvatarUserWithId]"
:users="[latestCommentNotification.comment?.author]"
/>
<span class="line-clamp-1">
{{ latestCommentNotification.comment?.author.name }} just left a
@@ -208,7 +208,6 @@ import { useIntervalFn, useTimeoutFn } from '@vueuse/core'
import type { ProjectCommentsUpdatedMessage } from '~/lib/common/generated/gql/graphql'
import { useFunctionRunsStatusSummary } from '~/lib/automate/runStatus'
import { CursorArrowRaysIcon, XCircleIcon } from '@heroicons/vue/24/outline'
import type { AvatarUserWithId } from '@speckle/ui-components'
const app = useNuxtApp()
const store = useHostAppStore()
@@ -431,8 +430,7 @@ const { start: startCommentClearTimeout, stop: stopCommentClearTimeout } = useTi
)
onCommentResult((res) => {
latestCommentNotification.value = res.data
?.projectCommentsUpdated as ProjectCommentsUpdatedMessage
latestCommentNotification.value = res.data?.projectCommentsUpdated
startCommentClearTimeout()
})
+5 -1
View File
@@ -19,7 +19,7 @@
color="subtle"
class="block text-foreground-2 hover:text-foreground overflow-hidden max-w-full !justify-start"
full-width
:disabled="!!modelCard.progress || !canEdit"
:disabled="!!modelCard.progress || noReadAccess"
@click.stop="openVersionsDialog = true"
>
<span>
@@ -269,6 +269,10 @@ const latestVersionCreatedAt = computed(() => {
return dayjs(props.modelCard.latestVersionCreatedAt).from(dayjs())
})
const noReadAccess = computed(() => {
return props.canEdit
})
onMounted(() => {
refetch()
})
+1 -1
View File
@@ -75,7 +75,7 @@ import {
} from '@heroicons/vue/24/solid'
import type { ConversionResult } from '~/lib/conversions/conversionResult'
import { useAccountStore } from '~/store/accounts'
import type { IModelCard } from '~/lib/models/card'
import type { IModelCard } from 'lib/models/card'
import { useHostAppStore } from '~/store/hostApp'
const app = useNuxtApp()
@@ -1,99 +0,0 @@
<template>
<div>
<div
class="px-3 py-1 rounded-md shadow transition overflow-hidden bg-foundation border-foundation-2 hover:shadow-md border-1 group"
>
<div class="flex flex-col sm:flex-row sm:gap-2 text-foreground">
<div class="flex flex-col gap-4">
<div class="text-body-xs">
<h1
class="mb-1 text-sm font-semibold w-full inline-block py-1 bg-clip-text"
>
Move your projects to a workspace
</h1>
<p class="mb-2">
<span class="text-sm"></span>
<span class="text-xs">
We are making workspaces the default way to work in Speckle.
</span>
</p>
<p class="mb-1">
<span class="text-sm"></span>
<span class="text-xs">
Introducing
<FormButton
text
link
external
size="sm"
class="font-semibold"
@click="$openUrl(`https://www.speckle.systems/pricing`)"
>
new pricing
</FormButton>
including limits to the free plan.
</span>
</p>
<FormButton
text
color="primary"
size="sm"
:class="showMore ? `mb-1` : ``"
:icon-right="showMore ? ChevronUpIcon : ChevronDownIcon"
@click="showMore = !showMore"
>
{{ showMore ? 'Show less' : 'Show timeline' }}
</FormButton>
<div v-show="showMore">
<hr />
<h3 class="font-medium text-warning-darker my-1">By June 1st 2025</h3>
<p class="text-xs mb-1">Move your projects to a workspace to:</p>
<ul class="list-disc list-inside pl-2 mb-2">
<li>
<span class="text-xs font-medium">
Create new projects and models
</span>
<span class="text-xs">
(will be disabled for personal projects; existing projects and
models stay editable)
</span>
</li>
<li>
<span class="text-xs font-medium">
Invite new project collaborators
</span>
<span class="text-xs">
(new invites will be unavailable for personal projects)
</span>
</li>
<li>
<span class="text-xs font-medium">
Preserve version and comment history
</span>
<span class="text-xs">
(history is reduced to 7 days for personal projects)
</span>
</li>
</ul>
<h3 class="font-medium text-warning-darker">By Janury 1st 2026</h3>
<span class="text-xs mb-1">
All projects will be archived if not moved into a workspace. Don't
worry, we'll give you plenty of reminders before then.
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ChevronUpIcon, ChevronDownIcon } from '@heroicons/vue/20/solid'
const { $openUrl } = useNuxtApp()
const showMore = ref(false)
</script>
+22 -49
View File
@@ -6,7 +6,6 @@
class="flex items-center space-x-2 bg-foundation -mx-3 -mt-2 px-3 py-2 shadow-sm border-b"
>
<div class="flex-grow min-w-0">
<!-- NO WORKSPACE YET -->
<div v-if="workspaces.length === 0">
<FormButton
full-width
@@ -51,6 +50,16 @@
/>
</div>
</div>
<!-- we can message to user about the non-workspace scenario -->
<!-- <div v-if="workspaces && workspaces.length === 0">
<CommonAlert size="xs" :color="'warning'">
<template #description>
You are listing legacy personal projects which will be deprecated end of
2025. We suggest you to move your personal projects into a workspace before
then.
</template>
</CommonAlert>
</div> -->
<div class="space-y-2">
<div class="flex items-center space-x-1 justify-between">
<FormTextInput
@@ -101,16 +110,6 @@
</div>
</div>
</div>
<div v-if="isPersonalProjectsAsWorkspace">
<!-- <CommonAlert size="xs" :color="'warning'">
<template #description>
You are listing legacy personal projects which will be deprecated end of
2025. We suggest you to move your personal projects into a workspace
before then.
</template>
</CommonAlert> -->
<WizardPersonalProjectsWarning />
</div>
<CommonLoadingBar v-if="loading" loading />
</div>
<div class="grid grid-cols-1 gap-2 relative z-0">
@@ -150,7 +149,7 @@ import { useMutation, provideApolloClient, useQuery } from '@vue/apollo-composab
import type {
ProjectListProjectItemFragment,
WorkspaceListWorkspaceItemFragment
} from '~/lib/common/generated/gql/graphql'
} from 'lib/common/generated/gql/graphql'
import { useMixpanel } from '~/lib/core/composables/mixpanel'
import { useConfigStore } from '~/store/config'
@@ -211,11 +210,7 @@ const handleProjectCreated = (result: ProjectListProjectItemFragment) => {
const { result: serverInfoResult, refetch: refetchServerInfo } = useQuery(
serverInfoQuery,
() => ({}),
() => ({
clientId: accountId.value,
debounce: 500,
fetchPolicy: 'network-only'
})
() => ({ clientId: accountId.value, debounce: 500, fetchPolicy: 'network-only' })
)
const workspacesEnabled = computed(
@@ -227,11 +222,7 @@ const { result: workspacesResult, refetch: refetchWorkspaces } = useQuery(
() => ({
limit: 100
}),
() => ({
clientId: accountId.value,
debounce: 500,
fetchPolicy: 'network-only'
})
() => ({ clientId: accountId.value, debounce: 500, fetchPolicy: 'network-only' })
)
const workspaces = computed(() => workspacesResult.value?.activeUser?.workspaces.items)
@@ -239,11 +230,7 @@ const workspaces = computed(() => workspacesResult.value?.activeUser?.workspaces
const { result: activeWorkspaceResult, refetch: refetchActiveWorkspace } = useQuery(
activeWorkspaceQuery,
() => ({}),
() => ({
clientId: accountId.value,
debounce: 500,
fetchPolicy: 'network-only'
})
() => ({ clientId: accountId.value, debounce: 500, fetchPolicy: 'network-only' })
)
const activeWorkspace = computed(() => {
@@ -256,30 +243,15 @@ const activeWorkspace = computed(() => {
return previouslySelectedWorkspace
}
}
const activeWorkspace = activeWorkspaceResult.value?.activeUser
?.activeWorkspace as WorkspaceListWorkspaceItemFragment
// fallback to activeWorkspace query result
if (activeWorkspace) {
return activeWorkspace
}
// if activeWorkspace is null will mean that it is personal projects - this fallback wont be the case soon
return {
id: 'personalProject',
name: 'Personal Projects'
} as WorkspaceListWorkspaceItemFragment
return activeWorkspaceResult.value?.activeUser
?.activeWorkspace as WorkspaceListWorkspaceItemFragment
})
const selectedWorkspace = ref<WorkspaceListWorkspaceItemFragment | undefined>(
activeWorkspace.value
)
const isPersonalProjectsAsWorkspace = computed(
() => selectedWorkspace.value?.id === 'personalProject'
)
watch(
workspaces,
(newItems) => {
@@ -348,11 +320,12 @@ const {
limit: 10, // stupid hack, increased it since we do manual filter to be able to see more project, see below TODO note, once we have `personalOnly` filter, decrease back to 10
filter: {
search: (searchText.value || '').trim() || null,
workspaceId: isPersonalProjectsAsWorkspace.value
? null
: selectedWorkspace.value?.id,
workspaceId:
selectedWorkspace.value?.id === 'personalProject'
? null
: selectedWorkspace.value?.id,
includeImplicitAccess: true,
personalOnly: isPersonalProjectsAsWorkspace.value
personalOnly: selectedWorkspace.value?.id === 'personalProject'
}
}),
() => ({
@@ -364,7 +337,7 @@ const {
)
const projects = computed(() =>
isPersonalProjectsAsWorkspace.value // TODO: we need to replace this logic with `personalOnly` filter when it is implemented into app.speckle.systems
selectedWorkspace.value?.id === 'personalProject' // TODO: we need to replace this logic with `personalOnly` filter when it is implemented into app.speckle.systems
? projectsResult.value?.activeUser?.projects.items.filter(
(i) => i.workspaceId === null
)
+85
View File
@@ -0,0 +1,85 @@
<template>
<div>
<div class="text-body-2xs mb-2 ml-1">Project workspace</div>
<FormSelectBase
key="name"
v-model="selectedWorkspace"
clearable
label="Workspaces"
placeholder="Nothing selected"
name="Workspaces"
:items="workspaces"
:disabled-item-predicate="userCantCreateWorkspace"
mount-menu-on-body
>
<template #something-selected="{ value }">
<span>{{ value.name }}</span>
</template>
<template #option="{ item }">
<div
v-tippy="{
content: item.readOnly
? 'This workspace is read-only.'
: item.role === 'workspace:guest'
? 'You do not have write access on this workspace.'
: undefined,
disabled: !(item.readOnly || item.role === 'workspace:guest')
}"
class="flex items-center"
>
<span class="truncate">{{ item.name }}</span>
</div>
</template>
</FormSelectBase>
<div
v-if="selectedWorkspace"
class="text-body-sm caption rounded p-2 bg-blue-500/10 my-2"
>
Project will be created in the selected workspace.
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { useQuery } from '@vue/apollo-composable'
import { workspacesListQuery } from '~/lib/graphql/mutationsAndQueries'
import type { WorkspaceListWorkspaceItemFragment } from 'lib/common/generated/gql/graphql'
import { storeToRefs } from 'pinia'
import { useAccountStore } from '~/store/accounts'
const emit = defineEmits<{
(
e: 'update:selectedWorkspace',
value: WorkspaceListWorkspaceItemFragment | undefined
): void
}>()
const accountStore = useAccountStore()
const { activeAccount } = storeToRefs(accountStore)
const accountId = computed(() => activeAccount.value.accountInfo.id)
const searchText = ref<string>()
const { result: workspacesResult } = useQuery(
workspacesListQuery,
() => ({
limit: 5,
filter: {
search: (searchText.value || '').trim() || null
}
}),
() => ({ clientId: accountId.value, debounce: 500, fetchPolicy: 'network-only' })
)
const workspaces = computed(() => workspacesResult.value?.activeUser?.workspaces.items)
const selectedWorkspace = ref<WorkspaceListWorkspaceItemFragment>()
watch(selectedWorkspace, (newVal) => {
emit('update:selectedWorkspace', newVal)
})
// Utility function to check if the user cannot create a workspace
const userCantCreateWorkspace = (item: WorkspaceListWorkspaceItemFragment) =>
(!!item?.role && item.role === 'workspace:guest') || !!item.readOnly
</script>
+1 -1
View File
@@ -5,7 +5,7 @@
>
<UserAvatar
v-tippy="`Authored by ${version.authorUser?.name}`"
:user="{ avatar: version.authorUser?.avatar, name: version.authorUser?.name as string }"
:user="version.authorUser"
size="sm"
class="absolute inset-1"
/>
+7 -53
View File
@@ -1,19 +1,7 @@
import { omit } from 'lodash-es'
import { baseConfigs, globals, getESMDirname } from '../../eslint.config.mjs'
import withNuxt from './.nuxt/eslint.config.mjs'
import pluginVueA11y from 'eslint-plugin-vuejs-accessibility'
import globals from 'globals'
import { fileURLToPath } from 'url'
import { dirname } from 'path'
import prettierConfig from 'eslint-config-prettier'
import js from '@eslint/js'
/**
* Feed in import.meta.url in your .mjs module to get the equivalent of __dirname
* @param {string} importMetaUrl
*/
export const getESMDirname = (importMetaUrl) => {
return dirname(fileURLToPath(importMetaUrl))
}
const configs = await withNuxt([
{
@@ -74,7 +62,6 @@ const configs = await withNuxt([
'@typescript-eslint/require-await': 'error',
'no-undef': 'off',
'@typescript-eslint/no-empty-object-type': 'off', // too restrictive
'@typescript-eslint/unified-signatures': 'off', // DX sucks in vue event definitions
'@typescript-eslint/no-dynamic-delete': 'off', // too restrictive
'@typescript-eslint/restrict-template-expressions': 'off', // too restrictive
@@ -91,7 +78,10 @@ const configs = await withNuxt([
{
files: ['**/*.vue'],
rules: {
'vue/block-order': ['error', { order: ['docs', 'template', 'script', 'style'] }],
'vue/component-tags-order': [
'error',
{ order: ['docs', 'template', 'script', 'style'] }
],
'vue/require-default-prop': 'off',
'vue/multi-word-component-names': 'off',
'vue/component-name-in-template-casing': [
@@ -126,46 +116,10 @@ const configs = await withNuxt([
'./lib/common/generated/**/*',
'storybook-static',
'.nuxt/**',
'.output/**',
'**/dist/**',
'**/dist-*/**',
'**/public/**',
'**/events.json',
'**/generated/**/*'
'.output/**'
]
},
{
files: ['**/*.mjs'],
languageOptions: {
sourceType: 'module'
}
},
{
files: ['**/*.cjs'],
languageOptions: {
sourceType: 'commonjs'
}
},
{
files: ['**/*.{js,mjs,cjs}', '**/.*.{js,mjs,cjs}'],
...js.configs.recommended
},
prettierConfig,
{
rules: {
camelcase: [
1,
{
properties: 'always'
}
],
'no-var': 'error',
'no-alert': 'error',
eqeqeq: 'error',
'prefer-const': 'warn',
'object-shorthand': 'warn'
}
}
...baseConfigs
])
export default configs
+136
View File
@@ -0,0 +1,136 @@
import { ApolloClient, gql } from '@apollo/client/core'
import { ApolloClients } from '@vue/apollo-composable'
import type { ComputedRef, Ref } from 'vue'
import type { Account } from '~/lib/bindings/definitions/IBasicConnectorBinding'
import { resolveClientConfig } from '~/lib/core/configs/apollo'
export type DUIAccount = {
/** account info coming from the host app */
accountInfo: Account
/** the graphql client; a bit superflous */
client?: ApolloClient<unknown>
/** whether an intial serverinfo query succeeded. */
isValid: boolean
}
export type DUIAccountsState = {
accounts: Ref<DUIAccount[]>
validAccounts: ComputedRef<DUIAccount[]>
refreshAccounts: () => Promise<void>
defaultAccount: ComputedRef<DUIAccount | undefined>
loading: Ref<boolean>
}
const AccountsInjectionKey = 'DUI_ACCOUNTS_STATE'
/**
* Use this composable to set up the account bindings and graphql clients at the top of the app.
* TODO: Properly handle cases when user was not connected to the internet,
* and then actually got connected.
*/
export function useAccountsSetup(): DUIAccountsState {
const app = useNuxtApp()
const $baseBinding = app.$baseBinding
const accounts = ref<DUIAccount[]>([])
const apolloClients = {} as Record<string, ApolloClient<unknown>>
// Tries to connect to the accounts and sets their is valid prop to false if fails.
const testAccounts = async (accs: DUIAccount[]) => {
const accountTestQuery = gql`
query AcccountTestQuery {
serverInfo {
version
name
company
}
}
`
for (const acc of accs) {
if (!acc.client) continue
try {
await acc.client.query({ query: accountTestQuery })
acc.isValid = true
} catch {
// TODO: properly dispose and kill this client. It's unclear how to do it.
acc.isValid = false
// NOTE: we do not want to delete the client, as we might want to "refresh" in
// case the user was not connected to the interweb.
// acc.client.disableNetworkFetches = true
// acc.client.stop()
// delete acc.client
}
}
}
const loading = ref(false)
// Matches local accounts coming from the host app to app state.
const refreshAccounts = async () => {
loading.value = true
const accs = await $baseBinding.getAccounts()
// We create a whole new list of accounts that will replace the old list. This way we ensure we drop
// out of scope old accounts that not exist anymore (TODO: test), and we don't need to do complex diffing.
const newAccs = [] as DUIAccount[]
for (const acc of accs) {
const existing = accounts.value.find((a) => a.accountInfo.id === acc.id)
if (existing) {
newAccs.push(existing as DUIAccount)
continue
}
const client = new ApolloClient(
resolveClientConfig({
httpEndpoint: new URL('/graphql', acc.serverInfo.url).href,
authToken: () => acc.token
})
)
apolloClients[acc.id] = client
newAccs.push({
accountInfo: acc,
client,
isValid: true
})
}
// We test accounts here so we try to prevent the app from querying/using invalid accounts.
await testAccounts(newAccs)
// Once we have tested the new accounts, finally set them.
accounts.value = newAccs
loading.value = false
}
void refreshAccounts() // Promise that we do not want to await (convention with void)
const defaultAccount = computed(() =>
accounts.value.find((acc) => acc.accountInfo.isDefault)
)
const validAccounts = computed(() => {
return accounts.value.filter((a) => a.isValid)
})
const accState = {
accounts,
defaultAccount,
validAccounts,
refreshAccounts,
loading
}
app.vueApp.provide(ApolloClients, apolloClients)
provide(AccountsInjectionKey, accState)
return accState // as DUIAccountsState
}
/**
* Use this composable to access the users' local accounts and their corresponding graphql client.
*/
export function useInjectedAccounts(): DUIAccountsState {
const state = inject(AccountsInjectionKey) as DUIAccountsState
return state
}
+1 -4
View File
@@ -1,7 +1,4 @@
import type {
IBinding,
IBindingSharedEvents
} from '~/lib/bindings/definitions/IBinding'
import type { IBinding, IBindingSharedEvents } from 'lib/bindings/definitions/IBinding'
export const IAccountBindingKey = 'accountsBinding'
+1 -1
View File
@@ -1,4 +1,4 @@
import type { ConversionResult } from '~/lib/conversions/conversionResult'
import type { ConversionResult } from 'lib/conversions/conversionResult'
import type { IModelCardSharedEvents } from '~/lib/models/card'
import type { CardSetting } from '~/lib/models/card/setting'
import type {
+1 -1
View File
@@ -5,7 +5,7 @@ import type {
} from '~~/lib/bindings/definitions/IBinding'
import type { CardSetting } from '~/lib/models/card/setting'
import type { IModelCardSharedEvents } from '~/lib/models/card'
import type { ConversionResult } from '~/lib/conversions/conversionResult'
import type { ConversionResult } from 'lib/conversions/conversionResult'
import type { CreateVersionArgs } from '~/lib/bridge/server'
export const ISendBindingKey = 'sendBinding'
+156
View File
@@ -0,0 +1,156 @@
import { ArchicadBridge } from '~/lib/bridge/server'
import { BaseBridge } from '~/lib/bridge/base'
import type { IRawBridge } from '~/lib/bridge/definitions'
/**
* A generic bridge class for Webivew2 or CefSharp.
*/
export class GenericBridge extends BaseBridge {
private bridge: IRawBridge
private archicadBridge: ArchicadBridge | undefined
private requests = {} as Record<
string,
{
methodName: string
resolve: (value: unknown) => void
reject: (reason: string | Error) => void
rejectTimerId: number
}
>
// TOTHINK: as this is a fast timeout, it forces us for long await methods in .net to return results via events. Kind-of not cool, and i'd be in favour of bumping it to "endless", or remove it altogether
// An example is the send or receive operations: they can take fucking long :D
private TIMEOUT_MS = 1000 * 60 // 60 sec
constructor(object: IRawBridge, isArchicadBridge: boolean = false) {
super()
this.bridge = object
if (isArchicadBridge) {
this.archicadBridge = new ArchicadBridge(this.emitter)
}
}
public async create(): Promise<boolean> {
// NOTE: GetMethods is a call to the .NET side.
try {
this.availableMethodNames = await this.bridge.GetBindingsMethodNames()
} catch {
console.warn(`Failed to get method names from binding.`)
return false
}
// NOTE: hoisting original calls as lowerCasedMethodNames, but using the UpperCasedName for the .NET call
// This allows us to follow js convetions and keep .NET ones too (eg. bindings.sayHi('') => public string SayHi(string name) {}
for (const methodName of this.availableMethodNames) {
const lowercasedMethodName = lowercaseMethodName(methodName)
const hoistTarget = this as unknown as Record<string, object>
hoistTarget[lowercasedMethodName] = (...args: unknown[]) =>
this.runMethod(methodName, args)
}
return true
}
private async emitResponseReady(eventName: string, requestId: string) {
this.registerPromise(eventName, requestId)
const data = await this.bridge.GetCallResult(requestId)
const request = this.requests[requestId]
try {
const parsedData = data ? (JSON.parse(data) as Record<string, unknown>) : null
if (parsedData === null) {
throw new Error(`Data is not parsed successfuly on ${eventName}`)
}
if (this.archicadBridge) {
this.archicadBridge.emit(eventName, parsedData, this.runMethod.bind(this))
} else {
this.emitter.emit(eventName, parsedData)
}
request.resolve(parsedData)
} catch (e) {
console.error(e)
request.reject(e as Error)
} finally {
window.clearTimeout(request.rejectTimerId)
delete this.requests[requestId]
}
}
async runMethod(
methodName: string,
args: unknown[],
shouldTimeout: boolean = true
): Promise<unknown> {
const requestId = (Math.random() + 1).toString(36).substring(2) + '_' + methodName
const preserializedArgs = args.map((a) => JSON.stringify(a))
this.bridge.RunMethod(methodName, requestId, JSON.stringify(preserializedArgs))
return this.registerPromise(methodName, requestId, shouldTimeout)
}
private async registerPromise(
methodName: string,
requestId: string,
shouldTimeout: boolean = true
) {
return new Promise((resolve, reject) => {
this.requests[requestId] = {
methodName,
resolve,
reject,
rejectTimerId: window.setTimeout(
() => {
reject(
`.NET response timed out for call to ${methodName} - did not receive anything back in good time (${this.TIMEOUT_MS}ms).`
)
delete this.requests[requestId]
},
shouldTimeout ? this.TIMEOUT_MS : 3600000
)
}
})
}
private async responseReady(requestId: string) {
if (!this.requests[requestId])
throw new Error(
`.NET Bridge found no request to resolve with the id of ${requestId}. Something is weird!`
)
const request = this.requests[requestId]
const data = await this.bridge.GetCallResult(requestId)
try {
const parsedData = data ? (JSON.parse(data) as Record<string, unknown>) : null // TODO: check if data is undefined
// eslint-disable-next-line no-prototype-builtins
if (parsedData && parsedData.hasOwnProperty('error')) {
console.error(data)
this.emitter.emit('errorOnResponse', data)
throw new Error(
`Failed to run ${requestId}. The host app error is logged above.`
)
}
request.resolve(parsedData)
} catch (e) {
console.error(e)
request.reject(e as Error)
} finally {
window.clearTimeout(request.rejectTimerId)
delete this.requests[requestId]
}
}
public showDevTools() {
this.bridge.ShowDevTools()
}
public openUrl(url: string) {
this.bridge.OpenUrl(url)
}
}
const lowercaseMethodName = (name: string) =>
name.charAt(0).toLowerCase() + name.slice(1)
+19 -105
View File
@@ -1,47 +1,30 @@
import { ArchicadBridge } from '~/lib/bridge/server'
import { BaseBridge } from '~/lib/bridge/base'
import type { IRawBridge } from '~/lib/bridge/definitions'
/**
* A generic bridge class for Webivew2 or CefSharp.
*/
export class GenericBridge extends BaseBridge {
private bridge: IRawBridge
private archicadBridge: ArchicadBridge | undefined
private requests = {} as Record<
string,
{
methodName: string
resolve: (value: unknown) => void
reject: (reason: string | Error) => void
rejectTimerId: number
}
>
// TOTHINK: as this is a fast timeout, it forces us for long await methods in .net to return results via events. Kind-of not cool, and i'd be in favour of bumping it to "endless", or remove it altogether
// An example is the send or receive operations: they can take fucking long :D
private TIMEOUT_MS = 1000 * 60 // 60 sec
constructor(object: IRawBridge, isArchicadBridge: boolean = false) {
constructor(object: IRawBridge) {
super()
this.bridge = object
if (isArchicadBridge) {
this.archicadBridge = new ArchicadBridge(this.emitter)
}
}
public async create(): Promise<boolean> {
// NOTE: GetMethods is a call to the .NET side.
let availableMethodNames = [] as string[]
try {
this.availableMethodNames = await this.bridge.GetBindingsMethodNames()
availableMethodNames = await this.bridge.GetBindingsMethodNames()
} catch {
console.warn(`Failed to get method names from binding.`)
console.warn(`Failed to get method names.`)
return false
}
// NOTE: hoisting original calls as lowerCasedMethodNames, but using the UpperCasedName for the .NET call
// This allows us to follow js convetions and keep .NET ones too (eg. bindings.sayHi('') => public string SayHi(string name) {}
for (const methodName of this.availableMethodNames) {
for (const methodName of availableMethodNames) {
const lowercasedMethodName = lowercaseMethodName(methodName)
const hoistTarget = this as unknown as Record<string, object>
hoistTarget[lowercasedMethodName] = (...args: unknown[]) =>
@@ -51,96 +34,27 @@ export class GenericBridge extends BaseBridge {
return true
}
private async emitResponseReady(eventName: string, requestId: string) {
this.registerPromise(eventName, requestId)
const data = await this.bridge.GetCallResult(requestId)
const request = this.requests[requestId]
try {
const parsedData = data ? (JSON.parse(data) as Record<string, unknown>) : null
if (parsedData === null) {
throw new Error(`Data is not parsed successfuly on ${eventName}`)
}
if (this.archicadBridge) {
this.archicadBridge.emit(eventName, parsedData, this.runMethod.bind(this))
} else {
this.emitter.emit(eventName, parsedData)
}
request.resolve(parsedData)
} catch (e) {
console.error(e)
request.reject(e as Error)
} finally {
window.clearTimeout(request.rejectTimerId)
delete this.requests[requestId]
}
}
async runMethod(
methodName: string,
args: unknown[],
shouldTimeout: boolean = true
): Promise<unknown> {
const requestId = (Math.random() + 1).toString(36).substring(2) + '_' + methodName
private async runMethod(methodName: string, args: unknown[]): Promise<unknown> {
const preserializedArgs = args.map((a) => JSON.stringify(a))
this.bridge.RunMethod(methodName, requestId, JSON.stringify(preserializedArgs))
// NOTE: RunMethod is a call to the .NET side.
const result = await this.bridge.RunMethod(
methodName,
JSON.stringify(preserializedArgs)
)
return this.registerPromise(methodName, requestId, shouldTimeout)
}
const parsed = result ? (JSON.parse(result) as Record<string, unknown>) : null
private async registerPromise(
methodName: string,
requestId: string,
shouldTimeout: boolean = true
) {
return new Promise((resolve, reject) => {
this.requests[requestId] = {
methodName,
resolve,
reject,
rejectTimerId: window.setTimeout(
() => {
reject(
`.NET response timed out for call to ${methodName} - did not receive anything back in good time (${this.TIMEOUT_MS}ms).`
)
delete this.requests[requestId]
},
shouldTimeout ? this.TIMEOUT_MS : 3600000
)
}
})
}
private async responseReady(requestId: string) {
if (!this.requests[requestId])
if (parsed && parsed['error']) {
console.error(parsed)
throw new Error(
`.NET Bridge found no request to resolve with the id of ${requestId}. Something is weird!`
`Failed to run ${methodName} with args ${JSON.stringify(
args
)}. The host app error is logged above.`
)
const request = this.requests[requestId]
const data = await this.bridge.GetCallResult(requestId)
try {
const parsedData = data ? (JSON.parse(data) as Record<string, unknown>) : null // TODO: check if data is undefined
// eslint-disable-next-line no-prototype-builtins
if (parsedData && parsedData.hasOwnProperty('error')) {
console.error(data)
this.emitter.emit('errorOnResponse', data)
throw new Error(
`Failed to run ${requestId}. The host app error is logged above.`
)
}
request.resolve(parsedData)
} catch (e) {
console.error(e)
request.reject(e as Error)
} finally {
window.clearTimeout(request.rejectTimerId)
delete this.requests[requestId]
}
return parsed
}
public showDevTools() {
+4 -4
View File
@@ -189,7 +189,7 @@ export class ArchicadBridge {
const body: ArchicadReceiveRequest = {
accountId: eventPayload.accountId,
projectId: eventPayload.projectId,
referencedObject: result.data.project.model.version.referencedObject as string,
referencedObject: result.data.project.model.version.referencedObject,
xmlConverterPath: eventPayload.xmlConverterPath
}
@@ -272,7 +272,7 @@ export class ArchicadBridge {
serverUrl: account?.accountInfo.serverInfo.url as string,
token: account?.accountInfo.token as string,
streamId: eventPayload.projectId,
objectId: result.data.project.model.version.referencedObject as string
objectId: result.data.project.model.version.referencedObject
})
const updateProgress = (e: {
@@ -313,7 +313,7 @@ export class ArchicadBridge {
})
// CONVERSION WILL START AFTER THAT
await runMethod('afterGetObjects', args as unknown as unknown[], false)
await runMethod('afterGetObjects', args as unknown as unknown[])
}
private queuedPromises = {} as Record<string, Promise<Response>[]>
@@ -373,7 +373,7 @@ export class ArchicadBridge {
this.queuedPromises[modelCardId] = []
console.log(`🚀 Upload is completed in ${(performance.now() - start) / 1000} s!`)
const args = [eventPayload.modelCardId, referencedObjectId]
await runMethod('afterSendObjects', args as unknown as unknown[], false)
await runMethod('afterSendObjects', args as unknown as unknown[])
}
}
+2 -2
View File
@@ -86,7 +86,7 @@ export class SketchupBridge extends BaseBridge {
}
// NOTE: Overriden emit as we do not need to parse the data back - the Sketchup bridge already parses it for us.
override emit(eventName: string, payload: string): void {
emit(eventName: string, payload: string): void {
const eventPayload = payload as unknown as Record<string, unknown>
if (eventName === 'sendViaBrowser')
@@ -124,7 +124,7 @@ export class SketchupBridge extends BaseBridge {
serverUrl: account?.accountInfo.serverInfo.url as string,
token: account?.accountInfo.token as string,
streamId: eventPayload.projectId,
objectId: result.data.project.model.version.referencedObject as string
objectId: result.data.project.model.version.referencedObject
})
const updateProgress = (e: {
+6 -42
View File
@@ -11,49 +11,9 @@ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-
* 3. It does not support dead code elimination, so it will add unused operations.
*
* 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
*/
type Documents = {
"\n mutation SetActiveWorkspaceMutation($slug: String) {\n activeUserMutations {\n setActiveWorkspace(slug: $slug)\n }\n }\n": typeof types.SetActiveWorkspaceMutationDocument,
"\n mutation VersionMutations($input: CreateVersionInput!) {\n versionMutations {\n create(input: $input) {\n id\n }\n }\n }\n": typeof types.VersionMutationsDocument,
"\n mutation MarkReceivedVersion($input: MarkReceivedVersionInput!) {\n versionMutations {\n markReceived(input: $input)\n }\n }\n": typeof types.MarkReceivedVersionDocument,
"\n mutation CreateModel($input: CreateModelInput!) {\n modelMutations {\n create(input: $input) {\n ...ModelListModelItem\n }\n }\n }\n": typeof types.CreateModelDocument,
"\n mutation CreateProject($input: ProjectCreateInput) {\n projectMutations {\n create(input: $input) {\n ...ProjectListProjectItem\n }\n }\n }\n": typeof types.CreateProjectDocument,
"\n mutation CreateProjectInWorkspace($input: WorkspaceProjectCreateInput!) {\n workspaceMutations {\n projects {\n create(input: $input) {\n ...ProjectListProjectItem\n }\n }\n }\n }\n": typeof types.CreateProjectInWorkspaceDocument,
"\n mutation StreamAccessRequestCreate($input: String!) {\n streamAccessRequestCreate(streamId: $input) {\n id\n }\n }\n": typeof types.StreamAccessRequestCreateDocument,
"\n fragment WorkspaceListWorkspaceItem on Workspace {\n id\n slug\n name\n description\n createdAt\n updatedAt\n logo\n role\n readOnly\n }\n": typeof types.WorkspaceListWorkspaceItemFragmentDoc,
"\n fragment AutomateFunctionItem on AutomateFunction {\n name\n isFeatured\n id\n creator {\n name\n }\n releases {\n items {\n inputSchema\n }\n }\n }\n": typeof types.AutomateFunctionItemFragmentDoc,
"\n mutation CreateAutomation($projectId: ID!, $input: ProjectAutomationCreateInput!) {\n projectMutations {\n automationMutations(projectId: $projectId) {\n create(input: $input) {\n id\n name\n }\n }\n }\n }\n": typeof types.CreateAutomationDocument,
"\n fragment AutomateFunctionRunItem on AutomateFunctionRun {\n id\n status\n statusMessage\n results\n contextView\n function {\n id\n name\n logo\n }\n }\n": typeof types.AutomateFunctionRunItemFragmentDoc,
"\n fragment AutomationRunItem on AutomateRun {\n id\n status\n automation {\n id\n name\n }\n functionRuns {\n ...AutomateFunctionRunItem\n }\n }\n": typeof types.AutomationRunItemFragmentDoc,
"\n query AutomationStatus($projectId: String!, $modelId: String!) {\n project(id: $projectId) {\n model(id: $modelId) {\n automationsStatus {\n id\n status\n automationRuns {\n ...AutomationRunItem\n }\n }\n }\n }\n }\n": typeof types.AutomationStatusDocument,
"\n query WorkspaceListQuery(\n $limit: Int!\n $filter: UserWorkspacesFilter\n $cursor: String\n ) {\n activeUser {\n id\n workspaces(limit: $limit, filter: $filter, cursor: $cursor) {\n totalCount\n cursor\n items {\n ...WorkspaceListWorkspaceItem\n }\n }\n }\n }\n": typeof types.WorkspaceListQueryDocument,
"\n query CanCreatePersonalProject {\n activeUser {\n permissions {\n canCreatePersonalProject {\n authorized\n code\n message\n payload\n }\n }\n }\n }\n": typeof types.CanCreatePersonalProjectDocument,
"\n query CanCreateProjectInWorkspace($workspaceId: String!) {\n workspace(id: $workspaceId) {\n permissions {\n canCreateProject {\n authorized\n code\n message\n payload\n }\n }\n }\n }\n": typeof types.CanCreateProjectInWorkspaceDocument,
"\n query CanCreateModelInProject($projectId: String!) {\n project(id: $projectId) {\n permissions {\n canCreateModel {\n authorized\n code\n message\n }\n }\n }\n }\n": typeof types.CanCreateModelInProjectDocument,
"\n query ActiveWorkspace {\n activeUser {\n activeWorkspace {\n ...WorkspaceListWorkspaceItem\n }\n }\n }\n": typeof types.ActiveWorkspaceDocument,
"\n fragment ProjectListProjectItem on Project {\n id\n name\n role\n updatedAt\n workspaceId\n workspace {\n id\n name\n slug\n role\n }\n models {\n totalCount\n }\n permissions {\n canLoad {\n authorized\n code\n message\n }\n canPublish {\n authorized\n code\n message\n }\n }\n }\n": typeof types.ProjectListProjectItemFragmentDoc,
"\n query ProjectListQuery($limit: Int!, $filter: UserProjectsFilter, $cursor: String) {\n activeUser {\n id\n projects(limit: $limit, filter: $filter, cursor: $cursor) {\n totalCount\n cursor\n items {\n ...ProjectListProjectItem\n }\n }\n }\n }\n": typeof types.ProjectListQueryDocument,
"\n fragment ModelListModelItem on Model {\n displayName\n name\n id\n previewUrl\n updatedAt\n versions(limit: 1) {\n totalCount\n items {\n ...VersionListItem\n }\n }\n }\n": typeof types.ModelListModelItemFragmentDoc,
"\n query ProjectModels(\n $projectId: String!\n $cursor: String\n $limit: Int!\n $filter: ProjectModelsFilter\n ) {\n project(id: $projectId) {\n id\n models(cursor: $cursor, limit: $limit, filter: $filter) {\n totalCount\n cursor\n items {\n ...ModelListModelItem\n }\n }\n }\n }\n": typeof types.ProjectModelsDocument,
"\n fragment VersionListItem on Version {\n id\n referencedObject\n message\n sourceApplication\n authorUser {\n avatar\n id\n name\n }\n createdAt\n previewUrl\n }\n": typeof types.VersionListItemFragmentDoc,
"\n query ModelVersions(\n $modelId: String!\n $projectId: String!\n $limit: Int!\n $cursor: String\n $filter: ModelVersionsFilter\n ) {\n project(id: $projectId) {\n id\n model(id: $modelId) {\n id\n versions(limit: $limit, cursor: $cursor, filter: $filter) {\n totalCount\n cursor\n items {\n ...VersionListItem\n }\n }\n }\n }\n }\n": typeof types.ModelVersionsDocument,
"\n query ObjectQuery($projectId: String!, $objectId: String!) {\n project(id: $projectId) {\n object(id: $objectId) {\n id\n data\n }\n }\n }\n": typeof types.ObjectQueryDocument,
"\n query ProjectAddByUrlQueryWithVersion(\n $projectId: String!\n $modelId: String!\n $versionId: String!\n ) {\n project(id: $projectId) {\n ...ProjectListProjectItem\n model(id: $modelId) {\n ...ModelListModelItem\n version(id: $versionId) {\n ...VersionListItem\n }\n }\n }\n }\n": typeof types.ProjectAddByUrlQueryWithVersionDocument,
"\n query ProjectAddByUrlQueryWithoutVersion($projectId: String!, $modelId: String!) {\n project(id: $projectId) {\n ...ProjectListProjectItem\n model(id: $modelId) {\n ...ModelListModelItem\n }\n }\n }\n": typeof types.ProjectAddByUrlQueryWithoutVersionDocument,
"\n query ProjectDetails($projectId: String!) {\n project(id: $projectId) {\n id\n role\n name\n workspace {\n name\n slug\n readOnly\n role\n }\n team {\n user {\n avatar\n id\n name\n }\n }\n visibility\n permissions {\n canLoad {\n authorized\n code\n message\n }\n canPublish {\n authorized\n code\n message\n }\n }\n }\n }\n": typeof types.ProjectDetailsDocument,
"\n query AutomateFunctions {\n automateFunctions {\n items {\n ...AutomateFunctionItem\n }\n }\n }\n": typeof types.AutomateFunctionsDocument,
"\n query ModelDetails($modelId: String!, $projectId: String!) {\n project(id: $projectId) {\n id\n name\n model(id: $modelId) {\n id\n displayName\n name\n versions {\n totalCount\n items {\n id\n }\n }\n author {\n id\n name\n avatar\n }\n }\n }\n }\n": typeof types.ModelDetailsDocument,
"\n query VersionDetails($projectId: String!, $versionId: String!, $modelId: String!) {\n project(id: $projectId) {\n id\n name\n model(id: $modelId) {\n id\n name\n versions(limit: 1) {\n items {\n id\n createdAt\n sourceApplication\n authorUser {\n id\n }\n }\n }\n version(id: $versionId) {\n id\n referencedObject\n message\n sourceApplication\n createdAt\n previewUrl\n }\n }\n }\n }\n": typeof types.VersionDetailsDocument,
"\n query ServerInfo {\n serverInfo {\n workspaces {\n workspacesEnabled\n }\n }\n }\n": typeof types.ServerInfoDocument,
"\n subscription OnProjectVersionsUpdate($projectId: String!) {\n projectVersionsUpdated(id: $projectId) {\n id\n type\n version {\n id\n createdAt\n message\n sourceApplication\n authorUser {\n id\n name\n avatar\n }\n model {\n id\n name\n displayName\n }\n }\n }\n }\n": typeof types.OnProjectVersionsUpdateDocument,
"\n subscription ProjectTriggeredAutomationsStatusUpdated($projectId: String!) {\n projectTriggeredAutomationsStatusUpdated(projectId: $projectId) {\n type\n version {\n id\n }\n model {\n id\n }\n project {\n id\n }\n run {\n ...AutomationRunItem\n }\n }\n }\n": typeof types.ProjectTriggeredAutomationsStatusUpdatedDocument,
"\n subscription OnUserProjectsUpdated {\n userProjectsUpdated {\n id\n project {\n id\n visibility\n team {\n id\n role\n }\n }\n }\n }\n": typeof types.OnUserProjectsUpdatedDocument,
"\n subscription ProjectUpdated($projectId: String!) {\n projectUpdated(id: $projectId) {\n id\n project {\n visibility\n }\n }\n }\n": typeof types.ProjectUpdatedDocument,
"\n subscription Subscription($target: ViewerUpdateTrackingTarget!) {\n viewerUserActivityBroadcasted(target: $target) {\n userName\n userId\n sessionId\n user {\n name\n id\n avatar\n }\n status\n }\n }\n": typeof types.SubscriptionDocument,
"\n subscription ProjectCommentsUpdated($target: ViewerUpdateTrackingTarget!) {\n projectCommentsUpdated(target: $target) {\n comment {\n author {\n avatar\n id\n name\n }\n id\n hasParent\n parent {\n id\n }\n }\n type\n }\n }\n": typeof types.ProjectCommentsUpdatedDocument,
};
const documents: Documents = {
const documents = {
"\n query AcccountTestQuery {\n serverInfo {\n version\n name\n company\n }\n }\n ": types.AcccountTestQueryDocument,
"\n mutation SetActiveWorkspaceMutation($slug: String) {\n activeUserMutations {\n setActiveWorkspace(slug: $slug)\n }\n }\n": types.SetActiveWorkspaceMutationDocument,
"\n mutation VersionMutations($input: CreateVersionInput!) {\n versionMutations {\n create(input: $input) {\n id\n }\n }\n }\n": types.VersionMutationsDocument,
"\n mutation MarkReceivedVersion($input: MarkReceivedVersionInput!) {\n versionMutations {\n markReceived(input: $input)\n }\n }\n": types.MarkReceivedVersionDocument,
@@ -108,6 +68,10 @@ const documents: Documents = {
*/
export function graphql(source: string): unknown;
/**
* 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 AcccountTestQuery {\n serverInfo {\n version\n name\n company\n }\n }\n "): (typeof documents)["\n query AcccountTestQuery {\n serverInfo {\n version\n name\n company\n }\n }\n "];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
+23 -40
View File
@@ -2022,8 +2022,6 @@ export type Project = {
commentThreads: ProjectCommentCollection;
createdAt: Scalars['DateTime']['output'];
description?: Maybe<Scalars['String']['output']>;
/** Public project-level configuration for embedded viewer */
embedOptions: ProjectEmbedOptions;
id: Scalars['ID']['output'];
invitableCollaborators: WorkspaceCollaboratorCollection;
/** Collaborators who have been invited, but not yet accepted. */
@@ -2062,7 +2060,7 @@ export type Project = {
versions: VersionCollection;
/** Return metadata about resources being requested in the viewer */
viewerResources: Array<ViewerResourceGroup>;
visibility: ProjectVisibility;
visibility: SimpleProjectVisibility;
webhooks: WebhookCollection;
workspace?: Maybe<Workspace>;
workspaceId?: Maybe<Scalars['String']['output']>;
@@ -2355,11 +2353,6 @@ export type ProjectCreateInput = {
visibility?: InputMaybe<ProjectVisibility>;
};
export type ProjectEmbedOptions = {
__typename?: 'ProjectEmbedOptions';
hideSpeckleBranding: Scalars['Boolean']['output'];
};
export type ProjectFileImportUpdatedMessage = {
__typename?: 'ProjectFileImportUpdatedMessage';
/** Upload ID */
@@ -2580,7 +2573,6 @@ export type ProjectPermissionChecks = {
canCreateComment: PermissionCheckResult;
canCreateModel: PermissionCheckResult;
canDelete: PermissionCheckResult;
canInvite: PermissionCheckResult;
canLeave: PermissionCheckResult;
canLoad: PermissionCheckResult;
canMoveToWorkspace: PermissionCheckResult;
@@ -2679,14 +2671,9 @@ export enum ProjectVersionsUpdatedMessageType {
}
export enum ProjectVisibility {
/** Only accessible to explicit collaborators */
Private = 'PRIVATE',
/** Accessible to everyone (even non-logged in users) */
Public = 'PUBLIC',
/** Legacy - same as public */
Unlisted = 'UNLISTED',
/** Accessible to everyone in the project's workspace */
Workspace = 'WORKSPACE'
Unlisted = 'UNLISTED'
}
export type Query = {
@@ -3232,6 +3219,12 @@ export type SetPrimaryUserEmailInput = {
id: Scalars['ID']['input'];
};
/** Visibility without the "discoverable" option */
export enum SimpleProjectVisibility {
Private = 'PRIVATE',
Unlisted = 'UNLISTED'
}
export type SmartTextEditorValue = {
__typename?: 'SmartTextEditorValue';
/** File attachments, if any */
@@ -3307,7 +3300,6 @@ export type Stream = {
/**
* Whether the stream (if public) can be found on public stream exploration pages
* and searches
* @deprecated Discoverability as a feature has been removed.
*/
isDiscoverable: Scalars['Boolean']['output'];
/** Whether the stream can be viewed by non-contributors */
@@ -4186,7 +4178,6 @@ export type UserUpdateInput = {
};
export type UserWorkspacesFilter = {
completed?: InputMaybe<Scalars['Boolean']['input']>;
search?: InputMaybe<Scalars['String']['input']>;
};
@@ -4452,8 +4443,6 @@ export type Workspace = {
domainBasedMembershipProtectionEnabled: Scalars['Boolean']['output'];
/** Verified workspace domains */
domains?: Maybe<Array<WorkspaceDomain>>;
/** Workspace-level configuration for models in embedded viewer */
embedOptions: WorkspaceEmbedOptions;
hasAccessToFeature: Scalars['Boolean']['output'];
id: Scalars['ID']['output'];
/** Only available to workspace owners/members */
@@ -4605,11 +4594,6 @@ export type WorkspaceDomainDeleteInput = {
workspaceId: Scalars['ID']['input'];
};
export type WorkspaceEmbedOptions = {
__typename?: 'WorkspaceEmbedOptions';
hideSpeckleBranding: Scalars['Boolean']['output'];
};
export enum WorkspaceFeatureName {
DomainBasedSecurityPolicies = 'domainBasedSecurityPolicies',
OidcSso = 'oidcSso',
@@ -4737,6 +4721,7 @@ export type WorkspaceMutations = {
/** Dismiss a workspace from the discoverable list, behind the scene a join request is created with the status "dismissed" */
dismiss: Scalars['Boolean']['output'];
invites: WorkspaceInviteMutations;
join: Workspace;
leave: Scalars['Boolean']['output'];
projects: WorkspaceProjectMutations;
requestToJoin: Scalars['Boolean']['output'];
@@ -4744,7 +4729,6 @@ export type WorkspaceMutations = {
setDefaultRegion: Workspace;
update: Workspace;
updateCreationState: Scalars['Boolean']['output'];
updateEmbedOptions: WorkspaceEmbedOptions;
updateRole: Workspace;
updateSeatType: Workspace;
};
@@ -4780,6 +4764,11 @@ export type WorkspaceMutationsDismissArgs = {
};
export type WorkspaceMutationsJoinArgs = {
input: JoinWorkspaceInput;
};
export type WorkspaceMutationsLeaveArgs = {
id: Scalars['ID']['input'];
};
@@ -4806,11 +4795,6 @@ export type WorkspaceMutationsUpdateCreationStateArgs = {
};
export type WorkspaceMutationsUpdateEmbedOptionsArgs = {
input: WorkspaceUpdateEmbedOptionsInput;
};
export type WorkspaceMutationsUpdateRoleArgs = {
input: WorkspaceRoleUpdateInput;
};
@@ -4837,8 +4821,6 @@ export enum WorkspacePaymentMethod {
export type WorkspacePermissionChecks = {
__typename?: 'WorkspacePermissionChecks';
canCreateProject: PermissionCheckResult;
canEditEmbedOptions: PermissionCheckResult;
canInvite: PermissionCheckResult;
canMoveProjectToWorkspace: PermissionCheckResult;
};
@@ -5070,11 +5052,6 @@ export type WorkspaceTeamFilter = {
seatType?: InputMaybe<WorkspaceSeatType>;
};
export type WorkspaceUpdateEmbedOptionsInput = {
hideSpeckleBranding: Scalars['Boolean']['input'];
workspaceId: Scalars['String']['input'];
};
export type WorkspaceUpdateInput = {
description?: InputMaybe<Scalars['String']['input']>;
discoverabilityEnabled?: InputMaybe<Scalars['Boolean']['input']>;
@@ -5100,6 +5077,11 @@ export type WorkspaceUpdatedMessage = {
workspace: Workspace;
};
export type AcccountTestQueryQueryVariables = Exact<{ [key: string]: never; }>;
export type AcccountTestQueryQuery = { __typename?: 'Query', serverInfo: { __typename?: 'ServerInfo', version?: string | null, name: string, company?: string | null } };
export type SetActiveWorkspaceMutationMutationVariables = Exact<{
slug?: InputMaybe<Scalars['String']['input']>;
}>;
@@ -5272,7 +5254,7 @@ export type ProjectDetailsQueryVariables = Exact<{
}>;
export type ProjectDetailsQuery = { __typename?: 'Query', project: { __typename?: 'Project', id: string, role?: string | null, name: string, visibility: ProjectVisibility, workspace?: { __typename?: 'Workspace', name: string, slug: string, readOnly: boolean, role?: string | null } | null, team: Array<{ __typename?: 'ProjectCollaborator', user: { __typename?: 'LimitedUser', avatar?: string | null, id: string, name: string } }>, permissions: { __typename?: 'ProjectPermissionChecks', canLoad: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string }, canPublish: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string } } } };
export type ProjectDetailsQuery = { __typename?: 'Query', project: { __typename?: 'Project', id: string, role?: string | null, name: string, visibility: SimpleProjectVisibility, workspace?: { __typename?: 'Workspace', name: string, slug: string, readOnly: boolean, role?: string | null } | null, team: Array<{ __typename?: 'ProjectCollaborator', user: { __typename?: 'LimitedUser', avatar?: string | null, id: string, name: string } }>, permissions: { __typename?: 'ProjectPermissionChecks', canLoad: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string }, canPublish: { __typename?: 'PermissionCheckResult', authorized: boolean, code: string, message: string } } } };
export type AutomateFunctionsQueryVariables = Exact<{ [key: string]: never; }>;
@@ -5318,14 +5300,14 @@ export type ProjectTriggeredAutomationsStatusUpdatedSubscription = { __typename?
export type OnUserProjectsUpdatedSubscriptionVariables = Exact<{ [key: string]: never; }>;
export type OnUserProjectsUpdatedSubscription = { __typename?: 'Subscription', userProjectsUpdated: { __typename?: 'UserProjectsUpdatedMessage', id: string, project?: { __typename?: 'Project', id: string, visibility: ProjectVisibility, team: Array<{ __typename?: 'ProjectCollaborator', id: string, role: string }> } | null } };
export type OnUserProjectsUpdatedSubscription = { __typename?: 'Subscription', userProjectsUpdated: { __typename?: 'UserProjectsUpdatedMessage', id: string, project?: { __typename?: 'Project', id: string, visibility: SimpleProjectVisibility, team: Array<{ __typename?: 'ProjectCollaborator', id: string, role: string }> } | null } };
export type ProjectUpdatedSubscriptionVariables = Exact<{
projectId: Scalars['String']['input'];
}>;
export type ProjectUpdatedSubscription = { __typename?: 'Subscription', projectUpdated: { __typename?: 'ProjectUpdatedMessage', id: string, project?: { __typename?: 'Project', visibility: ProjectVisibility } | null } };
export type ProjectUpdatedSubscription = { __typename?: 'Subscription', projectUpdated: { __typename?: 'ProjectUpdatedMessage', id: string, project?: { __typename?: 'Project', visibility: SimpleProjectVisibility } | null } };
export type SubscriptionSubscriptionVariables = Exact<{
target: ViewerUpdateTrackingTarget;
@@ -5348,6 +5330,7 @@ export const AutomationRunItemFragmentDoc = {"kind":"Document","definitions":[{"
export const ProjectListProjectItemFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProjectListProjectItem"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Project"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"workspace"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"role"}}]}},{"kind":"Field","name":{"kind":"Name","value":"models"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}},{"kind":"Field","name":{"kind":"Name","value":"permissions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"canLoad"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"authorized"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"message"}}]}},{"kind":"Field","name":{"kind":"Name","value":"canPublish"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"authorized"}},{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"message"}}]}}]}}]}}]} as unknown as DocumentNode<ProjectListProjectItemFragment, unknown>;
export const VersionListItemFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"VersionListItem"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Version"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"referencedObject"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"sourceApplication"}},{"kind":"Field","name":{"kind":"Name","value":"authorUser"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"avatar"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"previewUrl"}}]}}]} as unknown as DocumentNode<VersionListItemFragment, unknown>;
export const ModelListModelItemFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ModelListModelItem"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Model"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"previewUrl"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"versions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"1"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"VersionListItem"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"VersionListItem"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Version"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"referencedObject"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"sourceApplication"}},{"kind":"Field","name":{"kind":"Name","value":"authorUser"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"avatar"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"previewUrl"}}]}}]} as unknown as DocumentNode<ModelListModelItemFragment, unknown>;
export const AcccountTestQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AcccountTestQuery"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"serverInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"version"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"company"}}]}}]}}]} as unknown as DocumentNode<AcccountTestQueryQuery, AcccountTestQueryQueryVariables>;
export const SetActiveWorkspaceMutationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SetActiveWorkspaceMutation"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"slug"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeUserMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setActiveWorkspace"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"slug"}}}]}]}}]}}]} as unknown as DocumentNode<SetActiveWorkspaceMutationMutation, SetActiveWorkspaceMutationMutationVariables>;
export const VersionMutationsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"VersionMutations"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateVersionInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"versionMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"create"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode<VersionMutationsMutation, VersionMutationsMutationVariables>;
export const MarkReceivedVersionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"MarkReceivedVersion"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"MarkReceivedVersionInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"versionMutations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"markReceived"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]}}]} as unknown as DocumentNode<MarkReceivedVersionMutation, MarkReceivedVersionMutationVariables>;
+3 -3
View File
@@ -1,7 +1,7 @@
import crs from 'crypto-random-string'
import type { AutomationRunItemFragment } from '~/lib/common/generated/gql/graphql'
import type { ConversionResult } from '~/lib/conversions/conversionResult'
import type { CardSetting } from '~/lib/models/card/setting'
import type { AutomationRunItemFragment } from 'lib/common/generated/gql/graphql'
import type { ConversionResult } from 'lib/conversions/conversionResult'
import type { CardSetting } from 'lib/models/card/setting'
import type { IDiscriminatedObject } from '~~/lib/bindings/definitions/common'
import { DiscriminatedObject } from '~~/lib/bindings/definitions/common'
+2 -4
View File
@@ -1,11 +1,9 @@
import type { ConversionResult } from '~/lib/conversions/conversionResult'
export type ModelCardNotificationLevel = 'info' | 'danger' | 'warning' | 'success'
import type { ConversionResult } from 'lib/conversions/conversionResult'
export type ModelCardNotification = {
modelCardId: string
text: string
level: ModelCardNotificationLevel
level: 'info' | 'danger' | 'warning' | 'success'
cta?: {
name: string
action: () => void
-1
View File
@@ -53,7 +53,6 @@ export default defineNuxtConfig({
]
},
ssr: false,
devtools: { enabled: false },
build: {
transpile: [
/^@apollo\/client/,
+8 -9
View File
@@ -15,7 +15,7 @@
"postinstall": "nuxt prepare",
"lint:js": "eslint .",
"lint:tsc": "vue-tsc --noEmit",
"lint:prettier": "prettier --config .prettierrc --ignore-path .prettierignore --check .",
"lint:prettier": "prettier --config ../../.prettierrc --ignore-path ../../.prettierignore --check .",
"lint:css": "stylelint \"**/*.{css,vue}\"",
"lint": "yarn lint:js && yarn lint:tsc && yarn lint:prettier && yarn lint:css",
"lint:ci": "yarn lint:tsc && yarn lint:css",
@@ -55,11 +55,11 @@
"devDependencies": {
"@graphql-codegen/cli": "^5.0.5",
"@graphql-codegen/client-preset": "^4.3.0",
"@nuxt/eslint": "^1.3.1",
"@nuxt/eslint": "^0.3.13",
"@nuxtjs/tailwindcss": "^6.14.0",
"@parcel/watcher": "^2.5.1",
"@types/apollo-upload-client": "^17.0.1",
"@types/eslint": "^9.6.1",
"@types/eslint": "^8.56.10",
"@types/lodash-es": "^4.17.6",
"@types/node": "^18",
"@typescript-eslint/eslint-plugin": "^8.20.0",
@@ -77,9 +77,10 @@
"postcss-html": "^1.8.0",
"postcss-nesting": "^13.0.1",
"prettier": "^2.8.7",
"stylelint": "^16.19.1",
"stylelint-config-recommended-vue": "^1.6.0",
"stylelint-config-standard": "^38.0.0",
"stylelint": "^15.10.1",
"stylelint-config-prettier": "^9.0.3",
"stylelint-config-recommended-vue": "^1.4.0",
"stylelint-config-standard": "^26.0.0",
"tailwindcss": "^3.4.17",
"type-fest": "^3.5.1",
"typescript": "^5.7.3",
@@ -88,9 +89,7 @@
},
"resolutions": {
"core-js": "3.22.4",
"core-js-compat/semver": "^7.5.4",
"@babel/plugin-transform-classes/globals": "13.13.0",
"@babel/traverse/globals": "13.13.0"
"core-js-compat/semver": "^7.5.4"
},
"packageManager": "yarn@4.9.1"
}
+1 -1
View File
@@ -79,7 +79,7 @@
</p>
</div>
<FormButton
:color="'outline'"
color="card"
full-width
class="sticky top-10 top-16"
@click="runTests()"
+1 -1
View File
@@ -1,5 +1,5 @@
import type { IRawBridge } from '~/lib/bridge/definitions'
import { GenericBridge } from '~/lib/bridge/generic'
import { GenericBridge } from '~/lib/bridge/generic-v2'
import { SketchupBridge } from '~/lib/bridge/sketchup'
import type { IBasicConnectorBinding } from '~/lib/bindings/definitions/IBasicConnectorBinding'
+3 -2
View File
@@ -15,6 +15,7 @@ import { onError, type ErrorResponse } from '@apollo/client/link/error'
import { getMainDefinition } from '@apollo/client/utilities'
import { setContext } from '@apollo/client/link/context'
import { useHostAppStore } from '~/store/hostApp'
import type { ToastNotification } from '@speckle/ui-components'
import { ToastNotificationType } from '@speckle/ui-components'
export type DUIAccount = {
@@ -85,7 +86,7 @@ export const useAccountStore = defineStore('accountStore', () => {
try {
await acc.client.query({ query: accountTestQuery })
acc.isValid = true
} catch {
} catch (error) {
// TODO: properly dispose and kill this client. It's unclear how to do it.
acc.isValid = false
// NOTE: we do not want to delete the client, as we might want to "refresh" in
@@ -115,7 +116,7 @@ export const useAccountStore = defineStore('accountStore', () => {
if (res.graphQLErrors) {
if (
res.graphQLErrors?.some(
(err) => err.extensions?.code === 'SSO_SESSION_MISSING_OR_EXPIRED_ERROR'
(err) => err.extensions.code === 'SSO_SESSION_MISSING_OR_EXPIRED_ERROR'
)
) {
hostAppStore.setNotification({
+1 -1
View File
@@ -1,4 +1,4 @@
import type { ConnectorConfig } from '~/lib/bindings/definitions/IConfigBinding'
import type { ConnectorConfig } from 'lib/bindings/definitions/IConfigBinding'
import { defineStore } from 'pinia'
export const useConfigStore = defineStore('configStore', () => {
+4 -7
View File
@@ -2,7 +2,7 @@ import type {
DocumentInfo,
DocumentModelStore
} from '~/lib/bindings/definitions/IBasicConnectorBinding'
import type { IModelCard, ModelCardProgress } from '~/lib/models/card'
import type { IModelCard, ModelCardProgress } from 'lib/models/card'
import { useMixpanel } from '~/lib/core/composables/mixpanel'
import type { IReceiverModelCard } from '~/lib/models/card/receiver'
import type {
@@ -12,11 +12,11 @@ import type {
ISenderModelCard,
RevitViewsSendFilter,
SendFilterSelect
} from '~/lib/models/card/send'
} from 'lib/models/card/send'
import type { ToastNotification } from '@speckle/ui-components'
import type { Nullable } from '@speckle/shared'
import type { HostAppError } from '~/lib/bridge/errorHandler'
import type { ConversionResult } from '~/lib/conversions/conversionResult'
import type { ConversionResult } from 'lib/conversions/conversionResult'
import { defineStore } from 'pinia'
import type { CardSetting } from '~/lib/models/card/setting'
import type { DUIAccount } from '~/store/accounts'
@@ -489,10 +489,7 @@ export const useHostAppStore = defineStore('hostAppStore', () => {
if (typeof args.error === 'string') {
model.error = { errorMessage: args.error as string, dismissible: true }
} else {
model.error = args.error as {
errorMessage: string
dismissible: boolean
}
model.error = args.error as { errorMessage: string; dismissible: boolean }
}
}
+6 -2
View File
@@ -1,5 +1,9 @@
module.exports = {
extends: ['stylelint-config-standard', 'stylelint-config-recommended-vue'],
extends: [
'stylelint-config-standard',
'stylelint-config-recommended-vue',
'stylelint-config-prettier'
],
// add your custom config here
// https://stylelint.io/user-guide/configuration
rules: {
@@ -10,7 +14,7 @@ module.exports = {
ignoreAtRules: ['tailwind', 'apply', 'variants', 'responsive', 'screen']
}
],
'at-rule-no-deprecated': [true, { ignoreAtRules: ['apply'] }],
'declaration-block-trailing-semicolon': null,
'no-descending-specificity': null
},
overrides: [
+1 -1
View File
@@ -1,4 +1,4 @@
import { plugin as speckleThemePlugin } from '@speckle/tailwind-theme'
import {plugin as speckleThemePlugin} from '@speckle/tailwind-theme'
import { tailwindContentEntries as themeEntries } from '@speckle/tailwind-theme/tailwind-configure'
import { tailwindContentEntries as uiLibEntries } from '@speckle/ui-components/tailwind-configure'
import formsPlugin from '@tailwindcss/forms'
+1165 -756
View File
File diff suppressed because it is too large Load Diff