diff --git a/packages/frontend-2/components/automate/automation/CreateDialog.vue b/packages/frontend-2/components/automate/automation/CreateDialog.vue index 758f103da..8fffa059a 100644 --- a/packages/frontend-2/components/automate/automation/CreateDialog.vue +++ b/packages/frontend-2/components/automate/automation/CreateDialog.vue @@ -43,6 +43,7 @@ :show-label="false" :show-required="false" :preselected-function="validatedPreselectedFunction" + :workspace-id="workspaceId" /> @@ -124,6 +126,7 @@ graphql(` `) const props = defineProps<{ + workspaceId?: string preselectedFunction?: Optional preselectedProject?: Optional }>() diff --git a/packages/frontend-2/components/automate/automation/create-dialog/SelectFunctionStep.vue b/packages/frontend-2/components/automate/automation/create-dialog/SelectFunctionStep.vue index f6d8254cf..46c327ae7 100644 --- a/packages/frontend-2/components/automate/automation/create-dialog/SelectFunctionStep.vue +++ b/packages/frontend-2/components/automate/automation/create-dialog/SelectFunctionStep.vue @@ -43,13 +43,19 @@ import type { Optional } from '@speckle/shared' import { usePaginatedQuery } from '~/lib/common/composables/graphql' const searchQuery = graphql(` - query AutomationCreateDialogFunctionsSearch($search: String, $cursor: String = null) { - automateFunctions(limit: 20, filter: { search: $search }, cursor: $cursor) { - cursor - totalCount - items { - id - ...AutomateAutomationCreateDialog_AutomateFunction + query AutomationCreateDialogFunctionsSearch( + $workspaceId: String! + $search: String + $cursor: String = null + ) { + workspace(id: $workspaceId) { + automateFunctions(limit: 20, filter: { search: $search }, cursor: $cursor) { + cursor + totalCount + items { + id + ...AutomateAutomationCreateDialog_AutomateFunction + } } } } @@ -57,6 +63,7 @@ const searchQuery = graphql(` const props = withDefaults( defineProps<{ + workspaceId?: string preselectedFunction: Optional pageSize?: Optional showLabel?: Optional @@ -83,10 +90,11 @@ const { } = usePaginatedQuery({ query: searchQuery, baseVariables: computed(() => ({ - search: search.value?.length ? search.value : null + workspaceId: props.workspaceId ?? '', + search: search.value?.length ? search.value : '' })), resolveKey: (vars) => [vars.search || ''], - resolveCurrentResult: (res) => res?.automateFunctions, + resolveCurrentResult: (res) => res?.workspace?.automateFunctions, resolveNextPageVariables: (baseVars, cursor) => ({ ...baseVars, cursor @@ -94,7 +102,9 @@ const { resolveCursorFromVariables: (vars) => vars.cursor }) -const queryItems = computed(() => result.value?.automateFunctions.items) +const queryItems = computed(() => { + return result.value?.workspace?.automateFunctions.items +}) const items = computed(() => { const baseItems = (queryItems.value || []).slice(0, props.pageSize) const preselectedFn = props.preselectedFunction diff --git a/packages/frontend-2/components/automate/function/CreateDialog.vue b/packages/frontend-2/components/automate/function/CreateDialog.vue index d47ed751e..de18f06c1 100644 --- a/packages/frontend-2/components/automate/function/CreateDialog.vue +++ b/packages/frontend-2/components/automate/function/CreateDialog.vue @@ -56,7 +56,10 @@ import { } from '~/lib/common/helpers/route' import { useEnumSteps, useEnumStepsWidgetSetup } from '~/lib/form/composables/steps' import { useForm } from 'vee-validate' -import { useCreateAutomateFunction } from '~/lib/automate/composables/management' +import { + useCreateAutomateFunction, + useUpdateAutomateFunction +} from '~/lib/automate/composables/management' import { useMutationLoading } from '@vue/apollo-composable' import type { AutomateFunctionCreateDialogDoneStep_AutomateFunctionFragment } from '~~/lib/common/generated/gql/graphql' import { useMixpanel } from '~/lib/core/composables/mp' @@ -74,6 +77,7 @@ const props = defineProps<{ isAuthorized: boolean templates: CreatableFunctionTemplate[] githubOrgs: string[] + workspaceId?: string }>() const open = defineModel('open', { required: true }) @@ -81,6 +85,7 @@ const mixpanel = useMixpanel() const logger = useLogger() const mutationLoading = useMutationLoading() const createFunction = useCreateAutomateFunction() +const updateFunction = useUpdateAutomateFunction() const { handleSubmit: handleDetailsSubmit } = useForm() const onDetailsSubmit = handleDetailsSubmit(async (values) => { if (!selectedTemplate.value) { @@ -99,15 +104,29 @@ const onDetailsSubmit = handleDetailsSubmit(async (values) => { } }) - if (res?.id) { - mixpanel.track('Automate Function Created', { - functionId: res.id, - templateId: selectedTemplate.value.id, - name: values.name - }) - createdFunction.value = res - step.value++ + if (!res?.id) { + // TODO: Error toast with butter + return } + + mixpanel.track('Automate Function Created', { + functionId: res.id, + templateId: selectedTemplate.value.id, + name: values.name + }) + createdFunction.value = res + step.value++ + + if (!props.workspaceId) { + return + } + + await updateFunction({ + input: { + id: res.id, + workspaceIds: [props.workspaceId] + } + }) }) const onSubmit = computed(() => { diff --git a/packages/frontend-2/components/automate/function/EditDialog.vue b/packages/frontend-2/components/automate/function/EditDialog.vue index d903c18ce..d4faaf47f 100644 --- a/packages/frontend-2/components/automate/function/EditDialog.vue +++ b/packages/frontend-2/components/automate/function/EditDialog.vue @@ -18,10 +18,12 @@ import { difference, differenceBy } from 'lodash-es' import { useForm } from 'vee-validate' import { useUpdateAutomateFunction } from '~/lib/automate/composables/management' import type { FunctionDetailsFormValues } from '~/lib/automate/helpers/functions' +import type { Workspace } from '~/lib/common/generated/gql/graphql' const props = defineProps<{ model: FunctionDetailsFormValues fnId: string + workspaces?: Pick[] }>() const open = defineModel('open', { required: true }) const { handleSubmit, setValues } = useForm() @@ -53,6 +55,7 @@ const onSubmit = handleSubmit(async (values) => { values.description !== props.model.description ? values.description : null, logo: values.image !== props.model.image ? values.image : null, tags: difference(values.tags, props.model.tags || []).length ? values.tags : null, + workspaceIds: values.workspace ? [values.workspace.id] : [], supportedSourceApps: differenceBy( values.allowedSourceApps, props.model.allowedSourceApps || [], diff --git a/packages/frontend-2/components/automate/function/create-dialog/DetailsStep.vue b/packages/frontend-2/components/automate/function/create-dialog/DetailsStep.vue index f9d9c538f..bf0aa467e 100644 --- a/packages/frontend-2/components/automate/function/create-dialog/DetailsStep.vue +++ b/packages/frontend-2/components/automate/function/create-dialog/DetailsStep.vue @@ -33,6 +33,30 @@ :rules="descriptionRules" validate-on-value-update /> + + + + import { ValidationHelpers } from '@speckle/ui-components' import { isArray } from 'lodash-es' +import { graphql } from '~/lib/common/generated/gql' +import type { Workspace } from '~/lib/common/generated/gql/graphql' + +graphql(` + fragment AutomateFunctionCreateDialog_Workspace on Workspace { + id + name + } +`) defineProps<{ githubOrgs?: string[] + workspaces?: Pick[] }>() const avatarEditMode = ref(false) diff --git a/packages/frontend-2/components/automate/function/page/Header.vue b/packages/frontend-2/components/automate/function/page/Header.vue index f0336c0ca..5c03b9f6a 100644 --- a/packages/frontend-2/components/automate/function/page/Header.vue +++ b/packages/frontend-2/components/automate/function/page/Header.vue @@ -11,23 +11,10 @@

{{ fn.name }}

- - Edit -
-
- - Use in automation +
+ + Edit
@@ -40,11 +27,6 @@ import { automationFunctionsRoute } from '~/lib/common/helpers/route' -defineEmits<{ - createAutomation: [] - edit: [] -}>() - graphql(` fragment AutomateFunctionPageHeader_Function on AutomateFunction { id @@ -59,13 +41,17 @@ graphql(` releases(limit: 1) { totalCount } + workspaceIds } `) -const props = defineProps<{ +defineProps<{ fn: AutomateFunctionPageHeader_FunctionFragment isOwner: boolean }>() -const hasReleases = computed(() => props.fn.releases.totalCount > 0) +defineEmits<{ + createAutomation: [] + edit: [] +}>() diff --git a/packages/frontend-2/components/automate/functions/page/Header.vue b/packages/frontend-2/components/automate/functions/page/Header.vue index 86d6e471a..1cded9174 100644 --- a/packages/frontend-2/components/automate/functions/page/Header.vue +++ b/packages/frontend-2/components/automate/functions/page/Header.vue @@ -1,27 +1,30 @@ + diff --git a/packages/frontend-2/components/dashboard/Sidebar.vue b/packages/frontend-2/components/dashboard/Sidebar.vue index 90a4de260..c098b0a86 100644 --- a/packages/frontend-2/components/dashboard/Sidebar.vue +++ b/packages/frontend-2/components/dashboard/Sidebar.vue @@ -193,8 +193,23 @@ import { useActiveUser } from '~~/lib/auth/composables/activeUser' import { HomeIcon } from '@heroicons/vue/24/outline' import { useMixpanel } from '~~/lib/core/composables/mp' import { Roles } from '@speckle/shared' +import { graphql } from '~/lib/common/generated/gql' import { WorkspacePlanStatuses } from '~/lib/common/generated/gql/graphql' +graphql(` + fragment Sidebar_User on User { + id + automateFunctions { + items { + id + name + description + logo + } + } + } +`) + const { isLoggedIn } = useActiveUser() const isWorkspacesEnabled = useIsWorkspacesEnabled() const route = useRoute() diff --git a/packages/frontend-2/components/global/icon/Bolt.vue b/packages/frontend-2/components/global/icon/Bolt.vue new file mode 100644 index 000000000..35be1f097 --- /dev/null +++ b/packages/frontend-2/components/global/icon/Bolt.vue @@ -0,0 +1,18 @@ + diff --git a/packages/frontend-2/components/project/page/automation/Functions.vue b/packages/frontend-2/components/project/page/automation/Functions.vue index 3a5a274c8..0b0678b72 100644 --- a/packages/frontend-2/components/project/page/automation/Functions.vue +++ b/packages/frontend-2/components/project/page/automation/Functions.vue @@ -7,7 +7,7 @@ :key="fn.fn.id" :fn="fn.fn" :is-outdated="isOutdated(fn)" - show-edit + :show-edit="isEditable" @edit="onEdit(fn.fn)" /> @@ -65,6 +65,7 @@ graphql(` const props = defineProps<{ projectId: string automation: ProjectPageAutomationFunctions_AutomationFragment + isEditable: boolean }>() const dialogOpen = ref(false) diff --git a/packages/frontend-2/components/project/page/automation/Header.vue b/packages/frontend-2/components/project/page/automation/Header.vue index a7e9a4e69..67c1e158c 100644 --- a/packages/frontend-2/components/project/page/automation/Header.vue +++ b/packages/frontend-2/components/project/page/automation/Header.vue @@ -8,7 +8,7 @@
() const switchId = useId() diff --git a/packages/frontend-2/components/project/page/automation/Models.vue b/packages/frontend-2/components/project/page/automation/Models.vue index 15c0afcdb..e466940dc 100644 --- a/packages/frontend-2/components/project/page/automation/Models.vue +++ b/packages/frontend-2/components/project/page/automation/Models.vue @@ -44,7 +44,7 @@ graphql(` `) graphql(` - fragment ProjectPageAutomationHeader_Project on Project { + fragment ProjectPageAutomationModels_Project on Project { id ...ProjectPageModelsCardProject } diff --git a/packages/frontend-2/components/project/page/automation/Runs.vue b/packages/frontend-2/components/project/page/automation/Runs.vue index 5ea42de33..d86186cdb 100644 --- a/packages/frontend-2/components/project/page/automation/Runs.vue +++ b/packages/frontend-2/components/project/page/automation/Runs.vue @@ -3,7 +3,7 @@

Runs

@@ -47,6 +47,7 @@ graphql(` const props = defineProps<{ automation: ProjectPageAutomationRuns_AutomationFragment projectId: string + isEditable: boolean }>() const { identifier, onInfiniteLoad } = usePaginatedQuery({ diff --git a/packages/frontend-2/components/project/page/automations/EmptyState.vue b/packages/frontend-2/components/project/page/automations/EmptyState.vue index cc9f38cc2..f5b339897 100644 --- a/packages/frontend-2/components/project/page/automations/EmptyState.vue +++ b/packages/frontend-2/components/project/page/automations/EmptyState.vue @@ -9,9 +9,9 @@ faults, and effortlessly creating delivery artifacts.
-
+
New automation @@ -38,9 +38,9 @@
-

Featured functions

- - Explore all +

Public functions

+ + {{ functionGalleryLabel }}
@@ -58,12 +58,15 @@ diff --git a/packages/frontend-2/components/project/page/automations/Header.vue b/packages/frontend-2/components/project/page/automations/Header.vue index 3a52949dd..410789fa5 100644 --- a/packages/frontend-2/components/project/page/automations/Header.vue +++ b/packages/frontend-2/components/project/page/automations/Header.vue @@ -13,34 +13,47 @@ v-bind="bind" v-on="on" /> -
+ + {{ exploreFunctionsMessage }} + +
New automation
- - Explore functions -
diff --git a/packages/frontend-2/components/project/page/automations/Tab.vue b/packages/frontend-2/components/project/page/automations/Tab.vue index 854219802..4d867651f 100644 --- a/packages/frontend-2/components/project/page/automations/Tab.vue +++ b/packages/frontend-2/components/project/page/automations/Tab.vue @@ -2,10 +2,9 @@
@@ -57,6 +58,13 @@ const pageQuery = graphql(` automateFunction(id: $functionId) { ...AutomateFunctionPage_AutomateFunction } + activeUser { + workspaces { + items { + ...AutomateFunctionCreateDialog_Workspace + } + } + } } `) @@ -92,6 +100,9 @@ const isOwner = computed( activeUser.value.id === fn.value.creator.id ) ) +const activeUserWorkspaces = computed( + () => result.value?.activeUser?.workspaces.items ?? [] +) const { html: plaintextDescription } = useMarkdown( computed(() => fn.value?.description || ''), @@ -102,6 +113,8 @@ const editModel = computed((): Optional => { const func = fn.value if (!func) return undefined + const workspaceId = func.workspaceIds?.at(0) + return { name: func.name, description: func.description, @@ -109,7 +122,10 @@ const editModel = computed((): Optional => { allowedSourceApps: SourceApps.filter((app) => func.supportedSourceApps.includes(app.name) ), - tags: func.tags + tags: func.tags, + workspace: activeUserWorkspaces.value.find( + (workspace) => workspace.id === workspaceId + ) } }) diff --git a/packages/frontend-2/pages/functions/index.vue b/packages/frontend-2/pages/functions/index.vue index b3840e9de..6266092df 100644 --- a/packages/frontend-2/pages/functions/index.vue +++ b/packages/frontend-2/pages/functions/index.vue @@ -1,12 +1,24 @@