From 50c4c5016939decbdeb44f90aa9a75e6b5cea9eb Mon Sep 17 00:00:00 2001 From: Thomas Trompette Date: Thu, 14 Aug 2025 12:17:07 +0200 Subject: [PATCH] Remove workflow context + clean action config (#13919) - Remove create related version and runs from workflow action config - Remove WorkflowStepContextProvider. Use states instead --- .../hooks/useRelatedRecordActions.ts | 2 + .../contexts/ActionMenuContextProvider.tsx | 26 +++--- ...x => ActionMenuContextProviderDefault.tsx} | 2 +- .../CommandMenuWorkflowEditStep.tsx | 7 +- .../CommandMenuWorkflowRunViewStepContent.tsx | 82 +++++++++---------- .../CommandMenuWorkflowViewStepContent.tsx | 21 ++--- .../ui/form-types/components/VariableChip.tsx | 4 +- .../read-only/useIsRecordFieldReadOnly.ts | 10 +-- .../hooks/useWorkflowVersionIdOrThrow.ts | 15 ++++ .../states/context/WorkflowStepContext.ts | 9 -- .../components/WorkflowVisualizerEffect.tsx | 14 ++++ .../WorkflowStepFilterFieldSelect.tsx | 4 +- .../WorkflowEditActionFormFiller.tsx | 10 +-- .../decorators/WorkflowStepDecorator.tsx | 24 ++++-- 14 files changed, 118 insertions(+), 112 deletions(-) rename packages/twenty-front/src/modules/action-menu/contexts/{ActionMenuContextProviderWorkflowsEnabled.tsx => ActionMenuContextProviderDefault.tsx} (97%) create mode 100644 packages/twenty-front/src/modules/workflow/hooks/useWorkflowVersionIdOrThrow.ts delete mode 100644 packages/twenty-front/src/modules/workflow/states/context/WorkflowStepContext.ts diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-agnostic-actions/hooks/useRelatedRecordActions.ts b/packages/twenty-front/src/modules/action-menu/actions/record-agnostic-actions/hooks/useRelatedRecordActions.ts index 7de731a9cd..6826cd1830 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-agnostic-actions/hooks/useRelatedRecordActions.ts +++ b/packages/twenty-front/src/modules/action-menu/actions/record-agnostic-actions/hooks/useRelatedRecordActions.ts @@ -6,6 +6,7 @@ import { ActionViewType } from '@/action-menu/actions/types/ActionViewType'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { isWorkflowSubObjectMetadata } from '@/object-metadata/utils/isWorkflowSubObjectMetadata'; import { msg } from '@lingui/core/macro'; import React from 'react'; import { isDefined } from 'twenty-shared/utils'; @@ -84,6 +85,7 @@ export const useRelatedRecordActions = ({ (isDefined(selectedRecord) && !selectedRecord.isRemote && objectPermissions.canUpdateObjectRecords && + !isWorkflowSubObjectMetadata(targetObjectNameSingular) && getTargetObjectWritePermission( targetObjectNameSingular === CoreObjectNameSingular.TaskTarget ? CoreObjectNameSingular.Task diff --git a/packages/twenty-front/src/modules/action-menu/contexts/ActionMenuContextProvider.tsx b/packages/twenty-front/src/modules/action-menu/contexts/ActionMenuContextProvider.tsx index bab1ae2b0f..dfdcb566fc 100644 --- a/packages/twenty-front/src/modules/action-menu/contexts/ActionMenuContextProvider.tsx +++ b/packages/twenty-front/src/modules/action-menu/contexts/ActionMenuContextProvider.tsx @@ -1,6 +1,6 @@ import { type ActionMenuContextType } from '@/action-menu/contexts/ActionMenuContext'; +import { ActionMenuContextProviderDefault } from '@/action-menu/contexts/ActionMenuContextProviderDefault'; import { ActionMenuContextProviderWorkflowObjects } from '@/action-menu/contexts/ActionMenuContextProviderWorkflowObjects'; -import { ActionMenuContextProviderWorkflowsEnabled } from '@/action-menu/contexts/ActionMenuContextProviderWorkflowsEnabled'; import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; @@ -27,12 +27,18 @@ export const ActionMenuContextProvider = ({ objectMetadataItem.id === contextStoreCurrentObjectMetadataItemId, ); - const isWorkflowObject = - objectMetadataItem?.nameSingular === CoreObjectNameSingular.Workflow || - objectMetadataItem?.nameSingular === CoreObjectNameSingular.WorkflowRun || - objectMetadataItem?.nameSingular === CoreObjectNameSingular.WorkflowVersion; + if (!isDefined(objectMetadataItem)) { + return null; + } - if (isDefined(objectMetadataItem) && isWorkflowObject) { + const isWorkflowObject = + objectMetadataItem?.nameSingular === CoreObjectNameSingular.Workflow; + + if (!isDefined(objectMetadataItem)) { + return null; + } + + if (isWorkflowObject) { return ( {children} - + ); }; diff --git a/packages/twenty-front/src/modules/action-menu/contexts/ActionMenuContextProviderWorkflowsEnabled.tsx b/packages/twenty-front/src/modules/action-menu/contexts/ActionMenuContextProviderDefault.tsx similarity index 97% rename from packages/twenty-front/src/modules/action-menu/contexts/ActionMenuContextProviderWorkflowsEnabled.tsx rename to packages/twenty-front/src/modules/action-menu/contexts/ActionMenuContextProviderDefault.tsx index 31ec8e013d..6a953a9511 100644 --- a/packages/twenty-front/src/modules/action-menu/contexts/ActionMenuContextProviderWorkflowsEnabled.tsx +++ b/packages/twenty-front/src/modules/action-menu/contexts/ActionMenuContextProviderDefault.tsx @@ -10,7 +10,7 @@ import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/s import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; -export const ActionMenuContextProviderWorkflowsEnabled = ({ +export const ActionMenuContextProviderDefault = ({ objectMetadataItem, isInRightDrawer, displayType, diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStep.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStep.tsx index 3c6b671df1..285f796a1c 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStep.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStep.tsx @@ -1,7 +1,6 @@ import { useCommandMenuWorkflowIdOrThrow } from '@/command-menu/pages/workflow/hooks/useCommandMenuWorkflowIdOrThrow'; import { CommandMenuWorkflowEditStepContent } from '@/command-menu/pages/workflow/step/edit/components/CommandMenuWorkflowEditStepContent'; import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; -import { WorkflowStepContextProvider } from '@/workflow/states/context/WorkflowStepContext'; import { getWorkflowVisualizerComponentInstanceId } from '@/workflow/utils/getWorkflowVisualizerComponentInstanceId'; import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext'; import { isDefined } from 'twenty-shared/utils'; @@ -22,11 +21,7 @@ export const CommandMenuWorkflowEditStep = () => { }), }} > - - - + ); }; diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/components/CommandMenuWorkflowRunViewStepContent.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/components/CommandMenuWorkflowRunViewStepContent.tsx index 72942fef27..349973db73 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/components/CommandMenuWorkflowRunViewStepContent.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view-run/components/CommandMenuWorkflowRunViewStepContent.tsx @@ -10,7 +10,6 @@ import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/ho import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow'; import { useWorkflowRun } from '@/workflow/hooks/useWorkflowRun'; import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow'; -import { WorkflowStepContextProvider } from '@/workflow/states/context/WorkflowStepContext'; import { getStepDefinitionOrThrow } from '@/workflow/utils/getStepDefinitionOrThrow'; import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState'; import { WorkflowRunStepInputDetail } from '@/workflow/workflow-steps/components/WorkflowRunStepInputDetail'; @@ -113,53 +112,46 @@ export const CommandMenuWorkflowRunViewStepContent = () => { ]; return ( - - - {shouldFocusNodeTab ? ( - + {shouldFocusNodeTab ? ( + + ) : ( + <> + - ) : ( - <> - + ) : null} - {activeTabId === WorkflowRunTabId.OUTPUT ? ( - - ) : null} + {activeTabId === WorkflowRunTabId.NODE ? ( + + ) : null} - {activeTabId === WorkflowRunTabId.NODE ? ( - - ) : null} - - {activeTabId === WorkflowRunTabId.INPUT ? ( - - ) : null} - - )} - - + {activeTabId === WorkflowRunTabId.INPUT ? ( + + ) : null} + + )} + ); }; diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/components/CommandMenuWorkflowViewStepContent.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/components/CommandMenuWorkflowViewStepContent.tsx index 4c9f264fdc..ac0f9e8fed 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/components/CommandMenuWorkflowViewStepContent.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/step/view/components/CommandMenuWorkflowViewStepContent.tsx @@ -1,6 +1,5 @@ import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useFlowOrThrow } from '@/workflow/hooks/useFlowOrThrow'; -import { WorkflowStepContextProvider } from '@/workflow/states/context/WorkflowStepContext'; import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState'; import { WorkflowStepDetail } from '@/workflow/workflow-steps/components/WorkflowStepDetail'; import styled from '@emotion/styled'; @@ -23,17 +22,13 @@ export const CommandMenuWorkflowViewStepContent = () => { } return ( - - - - - + + + ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/VariableChip.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/VariableChip.tsx index 63e589dce8..bb9ea29d9f 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/VariableChip.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/VariableChip.tsx @@ -1,4 +1,4 @@ -import { useWorkflowStepContextOrThrow } from '@/workflow/states/context/WorkflowStepContext'; +import { useWorkflowVersionIdOrThrow } from '@/workflow/hooks/useWorkflowVersionIdOrThrow'; import { stepsOutputSchemaFamilySelector } from '@/workflow/states/selectors/stepsOutputSchemaFamilySelector'; import { extractRawVariableNamePart } from '@/workflow/workflow-variables/utils/extractRawVariableNamePart'; import { searchVariableThroughOutputSchema } from '@/workflow/workflow-variables/utils/searchVariableThroughOutputSchema'; @@ -82,7 +82,7 @@ export const VariableChip = ({ }: VariableChipProps) => { const theme = useTheme(); const { t } = useLingui(); - const { workflowVersionId } = useWorkflowStepContextOrThrow(); + const workflowVersionId = useWorkflowVersionIdOrThrow(); const stepId = extractRawVariableNamePart({ rawVariableName, diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/read-only/useIsRecordFieldReadOnly.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/read-only/useIsRecordFieldReadOnly.ts index 2044134800..4c28aeb90f 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/read-only/useIsRecordFieldReadOnly.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/hooks/read-only/useIsRecordFieldReadOnly.ts @@ -23,12 +23,6 @@ export const useIsRecordFieldReadOnly = ({ (field) => field.id === fieldMetadataId, ); - if (!fieldMetadataItem) { - throw new Error( - `Could not load read only property for field ${fieldMetadataId}`, - ); - } - const { objectPermissionsByObjectMetadataId } = useObjectPermissions(); const objectPermissions = getObjectPermissionsForObject( @@ -41,6 +35,10 @@ export const useIsRecordFieldReadOnly = ({ objectMetadataId, }); + if (!fieldMetadataItem) { + return false; + } + return isRecordFieldReadOnly({ isRecordReadOnly, objectPermissions, diff --git a/packages/twenty-front/src/modules/workflow/hooks/useWorkflowVersionIdOrThrow.ts b/packages/twenty-front/src/modules/workflow/hooks/useWorkflowVersionIdOrThrow.ts new file mode 100644 index 0000000000..f21d83cb08 --- /dev/null +++ b/packages/twenty-front/src/modules/workflow/hooks/useWorkflowVersionIdOrThrow.ts @@ -0,0 +1,15 @@ +import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { workflowVisualizerWorkflowVersionIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowVersionIdComponentState'; +import { isDefined } from 'twenty-shared/utils'; + +export const useWorkflowVersionIdOrThrow = () => { + const workflowVersionId = useRecoilComponentValue( + workflowVisualizerWorkflowVersionIdComponentState, + ); + + if (!isDefined(workflowVersionId)) { + throw new Error('Expected the workflow version ID to be defined'); + } + + return workflowVersionId; +}; diff --git a/packages/twenty-front/src/modules/workflow/states/context/WorkflowStepContext.ts b/packages/twenty-front/src/modules/workflow/states/context/WorkflowStepContext.ts deleted file mode 100644 index 0e1186f901..0000000000 --- a/packages/twenty-front/src/modules/workflow/states/context/WorkflowStepContext.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { createRequiredContext } from '~/utils/createRequiredContext'; - -type WorkflowStepContextType = { - workflowVersionId: string; - workflowRunId?: string; -}; - -export const [WorkflowStepContextProvider, useWorkflowStepContextOrThrow] = - createRequiredContext('WorkflowStepContext'); diff --git a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVisualizerEffect.tsx b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVisualizerEffect.tsx index 8cb9a5c049..17962ace0f 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVisualizerEffect.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-diagram/components/WorkflowVisualizerEffect.tsx @@ -1,6 +1,9 @@ import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; +import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState'; +import { workflowVisualizerWorkflowVersionIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowVersionIdComponentState'; import { useEffect } from 'react'; +import { isDefined } from 'twenty-shared/utils'; export const WorkflowVisualizerEffect = ({ workflowId, @@ -10,10 +13,21 @@ export const WorkflowVisualizerEffect = ({ const setWorkflowVisualizerWorkflowId = useSetRecoilComponentState( workflowVisualizerWorkflowIdComponentState, ); + const setWorkflowVisualizerWorkflowVersionId = useSetRecoilComponentState( + workflowVisualizerWorkflowVersionIdComponentState, + ); + + const workflow = useWorkflowWithCurrentVersion(workflowId); useEffect(() => { setWorkflowVisualizerWorkflowId(workflowId); }, [setWorkflowVisualizerWorkflowId, workflowId]); + useEffect(() => { + if (isDefined(workflow)) { + setWorkflowVisualizerWorkflowVersionId(workflow.currentVersion.id); + } + }, [setWorkflowVisualizerWorkflowVersionId, workflow]); + return null; }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterFieldSelect.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterFieldSelect.tsx index fe7b5f0ce2..1106a0c565 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterFieldSelect.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/filter-action/components/WorkflowStepFilterFieldSelect.tsx @@ -1,6 +1,6 @@ import { SelectControl } from '@/ui/input/components/SelectControl'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; -import { useWorkflowStepContextOrThrow } from '@/workflow/states/context/WorkflowStepContext'; +import { useWorkflowVersionIdOrThrow } from '@/workflow/hooks/useWorkflowVersionIdOrThrow'; import { stepsOutputSchemaFamilySelector } from '@/workflow/states/selectors/stepsOutputSchemaFamilySelector'; import { useGetFilterFieldMetadataItem } from '@/workflow/workflow-steps/workflow-actions/filter-action/hooks/useGetFilterFieldMetadataItem'; import { useUpsertStepFilterSettings } from '@/workflow/workflow-steps/workflow-actions/filter-action/hooks/useUpsertStepFilterSettings'; @@ -36,7 +36,7 @@ export const WorkflowStepFilterFieldSelect = ({ const { upsertStepFilterSettings } = useUpsertStepFilterSettings(); const { t } = useLingui(); - const { workflowVersionId } = useWorkflowStepContextOrThrow(); + const workflowVersionId = useWorkflowVersionIdOrThrow(); const stepId = extractRawVariableNamePart({ rawVariableName: stepFilter.stepOutputKey, diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormFiller.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormFiller.tsx index 27fbeb2e70..737302a094 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormFiller.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormFiller.tsx @@ -4,7 +4,7 @@ import { FormFieldInput } from '@/object-record/record-field/ui/components/FormF import { FormSingleRecordPicker } from '@/object-record/record-field/ui/form-types/components/FormSingleRecordPicker'; import { type FieldMetadata } from '@/object-record/record-field/ui/types/FieldMetadata'; import { RightDrawerFooter } from '@/ui/layout/right-drawer/components/RightDrawerFooter'; -import { useWorkflowStepContextOrThrow } from '@/workflow/states/context/WorkflowStepContext'; +import { useWorkflowRunIdOrThrow } from '@/workflow/hooks/useWorkflowRunIdOrThrow'; import { type WorkflowFormAction } from '@/workflow/types/Workflow'; import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody'; import { WorkflowStepHeader } from '@/workflow/workflow-steps/components/WorkflowStepHeader'; @@ -36,16 +36,12 @@ export const WorkflowEditActionFormFiller = ({ const { getIcon } = useIcons(); const { submitFormStep } = useSubmitFormStep(); const [formData, setFormData] = useState(action.settings.input); - const { workflowRunId } = useWorkflowStepContextOrThrow(); + const workflowRunId = useWorkflowRunIdOrThrow(); const { goBackFromCommandMenu } = useCommandMenuHistory(); const { updateWorkflowRunStep } = useUpdateWorkflowRunStep(); const [error, setError] = useState(undefined); + const canSubmit = !actionOptions.readonly && !isDefined(error); - - if (!isDefined(workflowRunId)) { - throw new Error('Form filler action must be used in a workflow run'); - } - const headerTitle = isDefined(action.name) ? action.name : `Form`; const headerIcon = getActionIcon(action.type); diff --git a/packages/twenty-front/src/testing/decorators/WorkflowStepDecorator.tsx b/packages/twenty-front/src/testing/decorators/WorkflowStepDecorator.tsx index e11b178eef..17bbcd77ec 100644 --- a/packages/twenty-front/src/testing/decorators/WorkflowStepDecorator.tsx +++ b/packages/twenty-front/src/testing/decorators/WorkflowStepDecorator.tsx @@ -1,7 +1,8 @@ import { useStepsOutputSchema } from '@/workflow/hooks/useStepsOutputSchema'; -import { WorkflowStepContextProvider } from '@/workflow/states/context/WorkflowStepContext'; import { flowComponentState } from '@/workflow/states/flowComponentState'; import { workflowVisualizerWorkflowIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowIdComponentState'; +import { workflowVisualizerWorkflowRunIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowRunIdComponentState'; +import { workflowVisualizerWorkflowVersionIdComponentState } from '@/workflow/states/workflowVisualizerWorkflowVersionIdComponentState'; import { type WorkflowVersion } from '@/workflow/types/Workflow'; import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext'; import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState'; @@ -30,6 +31,18 @@ export const WorkflowStepDecorator: Decorator = (Story) => { }), getWorkflowMock().id, ); + set( + workflowVisualizerWorkflowVersionIdComponentState.atomFamily({ + instanceId: workflowVisualizerComponentInstanceId, + }), + workflowVersion.id, + ); + set( + workflowVisualizerWorkflowRunIdComponentState.atomFamily({ + instanceId: workflowVisualizerComponentInstanceId, + }), + '123', + ); set( workflowSelectedNodeComponentState.atomFamily({ instanceId: workflowVisualizerComponentInstanceId, @@ -62,14 +75,7 @@ export const WorkflowStepDecorator: Decorator = (Story) => { instanceId: workflowVisualizerComponentInstanceId, }} > - - {ready && } - + {ready && } ); };