-
Notifications
You must be signed in to change notification settings - Fork 182
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DUI3 Sync To Main #2423
base: main
Are you sure you want to change the base?
DUI3 Sync To Main #2423
Changes from all commits
8e0add7
5231167
930dbc5
8fe8e6f
32e32e4
cb71924
3697fa0
172ce02
885f71d
c2d184b
e9c5815
981e23f
fbc9c4f
91eba5d
c93fed6
94d1692
13e73cd
b4bcee3
45cdd2f
9b5aa78
64d7e32
0a26328
73fc44a
445c793
c17c0b6
9df22e7
c31c95d
f2766b4
c4900c6
5da1aa0
4d83d83
02792ef
80d4df6
02330f0
d52a6d0
75d7446
35ad072
e9cf44d
6aa343b
59e9ded
f978deb
82b64e1
730c844
ed5f5f3
f34b38e
8679285
3e17ab8
4160b5d
3e6e4a6
1c23e08
09ce5bc
03e0bdf
0b462cc
f826d06
09f6ccc
52d6b10
7f2c5be
eacddc5
62287bf
6fef340
8e5203f
ffd70ca
d3efed4
6421476
5a8cdad
70dc7a7
41ce054
6f31d6b
7dbf567
335a264
1c84cdf
324534f
5aa14e9
a33f67d
9150810
69f7cc7
f507ccb
a9297df
cd2a96a
29f9461
683d51c
28b8dca
ed55e53
64ae426
07a65f5
32b2bea
de6bb13
423df89
dbc3a2e
210dc31
5ae1504
e083644
a7eac74
4b6c790
31b9d2c
dc73323
1ed9db5
2f31da4
0348a65
6e01e5e
b3536a7
85cdd40
117a08c
dcdbfc4
7bc2d8d
ed53d48
029d901
b195e3f
e36ee3f
ac6f7aa
f75647a
0a227bc
bdcaa35
cb19847
6c35e5a
31b4c76
f04b0a2
81967f4
8d834a1
1569bda
d33559d
2231e98
815ac46
9c518af
ccd83ed
e1d92e2
6fe9bd5
df6da6e
696d512
c5eb360
9e4ce3c
71807b4
94cf04f
b102a3f
32d8755
01999ca
1b79514
d7f55a7
f87ff23
4953357
c90f2ef
db12a53
98ad2fa
cedbd86
ce9f579
baa0872
cf80961
9f11799
28b20ee
804c667
6b6d99b
1b4650f
41ba4ee
2484cad
5d1135c
9ba2851
e84c3e0
4e7631c
7fea0be
1641144
c2d3492
53c0bb9
2da3beb
1212a71
d4c0325
1f372fb
568a34b
603d06f
a128c50
a00a13f
991ae35
2185e9d
01f71dc
39d69e4
289dc78
9af2049
6b4b922
6cc5382
ae30e21
3f71d9d
3099fcd
9f186cd
32031e9
c05f4d5
387cab4
d19d02d
e778038
f2c3230
059c706
d02249a
fdad60c
4be1c43
cbc779e
10c590d
902995c
c159fa2
c72f341
7fffa18
c806e0d
23605e6
8748d15
3ccb383
9000a6f
5a2717c
472da98
3a93e34
1bb49db
677350f
59679b6
4a9c990
fed2eba
79ba2ce
27e2f8a
6a1dfc3
ddcda1b
390673b
a28647d
789b46b
2b7d72c
687d1bd
f192de4
3467059
2f7d357
5c5bab2
6267d6e
419d93d
77313ef
72a43c6
cec9209
9accdc4
6fb1e3b
80a19ad
cf2cfa2
e9d1e63
269e7ff
496fd94
3302d71
e76ccb3
7c90133
52b795e
a4c23d5
d789d4e
e13be36
b25e8b0
af33991
7799cfd
1ff0887
19e1e75
070fa3f
9168afd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,21 @@ | ||
<template> | ||
<div id="speckle" class="bg-foundation-page text-foreground"> | ||
<div id="speckle" class="bg-foundation-page text-foreground overflow-auto"> | ||
<NuxtLayout> | ||
<NuxtPage /> | ||
</NuxtLayout> | ||
<SingletonToastManager /> | ||
</div> | ||
</template> | ||
<script setup lang="ts"> | ||
import { useMixpanel } from '~/lib/core/composables/mixpanel' | ||
import { useConfigStore } from '~/store/config' | ||
import { useAccountStore } from '~/store/accounts' | ||
import { storeToRefs } from 'pinia' | ||
import { useAccountsSetup } from '~/lib/accounts/composables/setup' | ||
import { useDocumentInfoStore } from '~/store/uiConfig' | ||
import { useUpdateConnector } from '~/lib/core/composables/updateConnector' | ||
|
||
const uiConfigStore = useDocumentInfoStore() | ||
const uiConfigStore = useConfigStore() | ||
const { isDarkTheme } = storeToRefs(uiConfigStore) | ||
|
||
useAccountsSetup() | ||
|
||
useHead({ | ||
// Title suffix | ||
titleTemplate: (titleChunk) => | ||
|
@@ -24,7 +25,33 @@ useHead({ | |
class: computed(() => (isDarkTheme.value ? `dark` : ``)) | ||
}, | ||
bodyAttrs: { | ||
class: 'simple-scrollbar bg-foundation-page text-foreground' | ||
} | ||
class: 'simple-scrollbar bg-foundation-page text-foreground ' | ||
}, | ||
// For standalone vue devtools see: https://devtools.vuejs.org/guide/installation.html#standalone | ||
script: import.meta.dev ? ['http://localhost:8098'] : [] | ||
}) | ||
|
||
onMounted(async () => { | ||
const { trackEvent, addConnectorToProfile, identifyProfile } = useMixpanel() | ||
const { checkUpdate } = useUpdateConnector() | ||
// TODO: some host apps can open DUI3 automatically, with this case we shouldn't mark track event as `"type": "action"`, | ||
// we need to get this info from source app. (TBD which apps: Rhino opens automatically, not sure acad, sketchup and revit needs trigger button to init) | ||
trackEvent('DUI3 Action', { name: 'Launch' }) | ||
|
||
// Checks whether new version available for the connector or not and throws a toast notification if any. | ||
await checkUpdate() | ||
|
||
const { accounts } = useAccountStore() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ditto regarding composables |
||
|
||
const uniqueEmails = new Set<string>() | ||
accounts.forEach((account) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this be a watcher activity that is re-invoked every time the accounts list changes? |
||
const email = account?.accountInfo.userInfo.email | ||
if (email && !uniqueEmails.has(email)) { | ||
addConnectorToProfile(email) | ||
identifyProfile(email) | ||
uniqueEmails.add(email) | ||
} | ||
}) | ||
}) | ||
</script> | ||
store/config |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
<template> | ||
<button | ||
v-tippy="tip" | ||
:class="`group block w-full p-2 text-left items-center space-x-2 select-none group transition hover:bg-primary-muted hover:cursor-pointer hover:text-primary ${ | ||
!account.isValid | ||
? 'text-danger bg-rose-500/10 cursor-not-allowed' | ||
: 'cursor-pointer' | ||
} ${ | ||
currentSelectedAccountId === account.accountInfo.id | ||
? 'bg-blue-500/5 text-primary' | ||
: '' | ||
}`" | ||
:disabled="!account.isValid" | ||
@click="$emit('select', account)" | ||
> | ||
<div class="flex items-center space-x-2"> | ||
<UserAvatar :user="userAvatar" :active="account.accountInfo.isDefault" /> | ||
<div class="min-w-0 grow"> | ||
<div class="truncate overflow-hidden min-w-0 flex items-center space-x-2"> | ||
<span>{{ account.accountInfo.serverInfo.name }}</span> | ||
<span class="text-foreground-2 truncate min-w-0 caption"> | ||
{{ account.accountInfo.serverInfo.url.split('//')[1] }} | ||
</span> | ||
</div> | ||
</div> | ||
</div> | ||
</button> | ||
</template> | ||
<script setup lang="ts"> | ||
import type { DUIAccount } from '~~/store/accounts' | ||
|
||
const props = defineProps<{ | ||
account: DUIAccount | ||
currentSelectedAccountId?: string | ||
}>() | ||
|
||
defineEmits<{ | ||
(e: 'select', account: DUIAccount): void | ||
}>() | ||
|
||
const userAvatar = computed(() => { | ||
return { | ||
name: props.account.accountInfo.userInfo.name, | ||
avatar: props.account.accountInfo.userInfo.avatar | ||
} | ||
}) | ||
|
||
const tip = computed(() => { | ||
let value = '' | ||
if (props.account.accountInfo.isDefault) value += 'This is your default account. ' | ||
if (!props.account.isValid) value += 'This account is not reachable.' | ||
return value === '' ? null : value | ||
}) | ||
</script> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
<template> | ||
<div> | ||
<button v-tippy="`Click to change the account.`" @click="showAccountsDialog = true"> | ||
<UserAvatar v-if="!showAccountsDialog" :user="user" hover-effect /> | ||
<UserAvatar v-else hover-effect> | ||
<XMarkIcon class="w-6 h-6" /> | ||
</UserAvatar> | ||
</button> | ||
<LayoutDialog | ||
v-model:open="showAccountsDialog" | ||
title="Select account" | ||
fullscreen="none" | ||
> | ||
<CommonLoadingBar :loading="isLoading" class="my-0" /> | ||
<AccountsItem | ||
v-for="acc in accounts" | ||
:key="acc.accountInfo.id" | ||
:current-selected-account-id="currentSelectedAccountId" | ||
:account="(acc as DUIAccount)" | ||
class="rounded-lg mb-2" | ||
@select="selectAccount(acc as DUIAccount)" | ||
/> | ||
<FormButton text size="xs" @click="accountStore.refreshAccounts()"> | ||
Refresh accounts | ||
</FormButton> | ||
</LayoutDialog> | ||
</div> | ||
</template> | ||
<script setup lang="ts"> | ||
import { storeToRefs } from 'pinia' | ||
import { XMarkIcon } from '@heroicons/vue/20/solid' | ||
import type { DUIAccount } from '~/store/accounts' | ||
import { useAccountStore } from '~/store/accounts' | ||
import { useMixpanel } from '~/lib/core/composables/mixpanel' | ||
|
||
const { trackEvent } = useMixpanel() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Code is organized pretty randomly/messily across Vue components https://www.notion.so/speckle/General-JavaScript-Review-Guide-1f2bf3dfea634460b3778ac3cf4aa1bb?pvs=4#54d72c9556664e4498f3be4923a1bc93 |
||
const app = useNuxtApp() | ||
|
||
const props = defineProps<{ | ||
currentSelectedAccountId?: string | ||
}>() | ||
|
||
defineEmits<{ | ||
(e: 'select', account: DUIAccount): void | ||
}>() | ||
|
||
const showAccountsDialog = ref(false) | ||
|
||
app.$baseBinding.on('documentChanged', () => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ideally these event handlers should be typed: You can only subscribe to existing events and payloads are typed appropriately |
||
showAccountsDialog.value = false | ||
}) | ||
|
||
watch(showAccountsDialog, (newVal) => { | ||
if (newVal) { | ||
void accountStore.refreshAccounts() | ||
void trackEvent('DUI3 Action', { name: 'Account menu open' }) | ||
} | ||
}) | ||
|
||
const accountStore = useAccountStore() | ||
const { accounts, defaultAccount, userSelectedAccount, isLoading } = | ||
storeToRefs(accountStore) | ||
|
||
const selectAccount = (acc: DUIAccount) => { | ||
userSelectedAccount.value = acc | ||
accountStore.setUserSelectedAccount(acc) // saves the selected account id into DUI3Config.db for later use | ||
showAccountsDialog.value = false | ||
void trackEvent('DUI3 Action', { name: 'Account change' }) | ||
} | ||
|
||
const user = computed(() => { | ||
if (!defaultAccount.value) return undefined | ||
let acc = defaultAccount.value | ||
if (props.currentSelectedAccountId) { | ||
acc = accounts.value.find( | ||
(acc) => acc.accountInfo.id === props.currentSelectedAccountId | ||
) as DUIAccount | ||
} | ||
return { | ||
name: acc.accountInfo.userInfo.name, | ||
avatar: acc.accountInfo.userInfo.avatar | ||
} | ||
}) | ||
</script> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
<!-- NOT WILL BE USED SINCE WE ENABLE AUTOMATION CREATION FROM DUI3 --> | ||
<template> | ||
<div class="p-0"> | ||
<slot name="activator" :toggle="toggleDialog"></slot> | ||
<LayoutDialog | ||
v-model:open="showAutomateDialog" | ||
:title="`Settings`" | ||
fullscreen="none" | ||
> | ||
<div v-if="hasFunctions"> | ||
<FormSelectBase | ||
key="name" | ||
v-model="selectedFunction" | ||
clearable | ||
label="Automate functions" | ||
placeholder="Nothing selected" | ||
name="Functions" | ||
show-label | ||
:items="functions" | ||
mount-menu-on-body | ||
> | ||
<template #something-selected="{ value }"> | ||
<span>{{ value.name }}</span> | ||
</template> | ||
<template #option="{ item }"> | ||
<div class="flex items-center"> | ||
<span class="truncate">{{ item.name }}</span> | ||
</div> | ||
</template> | ||
</FormSelectBase> | ||
</div> | ||
<div v-if="selectedFunction && finalParams && step === 0"> | ||
<FormJsonForm | ||
ref="jsonForm" | ||
:data="data" | ||
:schema="finalParams" | ||
class="space-y-4" | ||
:validate-on-mount="false" | ||
@change="handler" | ||
/> | ||
</div> | ||
<div v-if="step === 1"> | ||
<FormTextInput | ||
v-model="automationName" | ||
name="automationName" | ||
label="Automation name" | ||
color="foundation" | ||
show-label | ||
help="Give your automation a name" | ||
placeholder="Name" | ||
show-required | ||
validate-on-value-update | ||
/> | ||
</div> | ||
<FormButton | ||
v-if="selectedFunction && step === 0" | ||
size="sm" | ||
class="mt-4" | ||
@click="step++" | ||
> | ||
Next | ||
</FormButton> | ||
<FormButton | ||
v-if="selectedFunction && step === 1" | ||
size="sm" | ||
class="mt-4" | ||
@click="createAutomationHandler" | ||
> | ||
Create | ||
</FormButton> | ||
</LayoutDialog> | ||
</div> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
import { storeToRefs } from 'pinia' | ||
import type { AutomateFunctionItemFragment } from '~/lib/common/generated/gql/graphql' | ||
import { | ||
automateFunctionsQuery, | ||
createAutomationMutation | ||
} from '~/lib/graphql/mutationsAndQueries' | ||
import { provideApolloClient, useMutation, useQuery } from '@vue/apollo-composable' | ||
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' | ||
|
||
const props = defineProps<{ | ||
projectId: string | ||
modelId: string | ||
}>() | ||
|
||
const step = ref<number>(0) | ||
|
||
const automationName = ref<string>('') | ||
|
||
const accountStore = useAccountStore() | ||
const { activeAccount } = storeToRefs(accountStore) | ||
const accountId = computed(() => activeAccount.value?.accountInfo.id) // NOTE: none of the tokens here has read, write access to automate, only frontend tokens have. Keep in mind after first pass! | ||
|
||
const selectedFunction = ref<AutomateFunctionItemFragment>() | ||
|
||
const showAutomateDialog = ref(false) | ||
|
||
const toggleDialog = () => { | ||
showAutomateDialog.value = !showAutomateDialog.value | ||
} | ||
|
||
const { mutate } = provideApolloClient(activeAccount.value.client)(() => | ||
useMutation(createAutomationMutation) | ||
) | ||
|
||
const createAutomationHandler = async () => { | ||
const _res = await mutate({ | ||
projectId: props.projectId, | ||
input: { name: automationName.value, enabled: false } | ||
}) | ||
showAutomateDialog.value = false | ||
} | ||
|
||
const { result: functionsResult, onError } = useQuery( | ||
automateFunctionsQuery, | ||
() => ({}), | ||
() => ({ clientId: accountId.value, debounce: 500, fetchPolicy: 'network-only' }) | ||
) | ||
|
||
onError((err: ApolloError) => { | ||
console.warn(err.message) | ||
}) | ||
|
||
const functions = computed(() => functionsResult.value?.automateFunctions.items) | ||
const hasFunctions = computed(() => functions.value?.length !== 0) | ||
|
||
const release = computed(() => | ||
selectedFunction.value?.releases.items.length | ||
? selectedFunction.value?.releases.items[0] | ||
: undefined | ||
) | ||
|
||
const finalParams = computed(() => formatVersionParams(release.value?.inputSchema)) | ||
|
||
const { handler } = useJsonFormsChangeHandler({ | ||
schema: finalParams | ||
}) | ||
|
||
console.log(finalParams) | ||
|
||
type DataType = Record<string, unknown> | ||
const data = computed(() => { | ||
const kvp = {} as DataType | ||
if (finalParams.value) { | ||
Object.entries(finalParams.value).forEach((k, _) => { | ||
kvp[k as unknown as string] = undefined | ||
}) | ||
} | ||
return kvp | ||
}) | ||
</script> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://www.notion.so/speckle/General-JavaScript-Review-Guide-1f2bf3dfea634460b3778ac3cf4aa1bb?pvs=4#2a7cf25d251e403fac1ab53946887102