fix(frontend): app editor improvements (#4052)
* fix(frontend): wip * fix(frontend): fix dataflow to error handler module * fix(frontend): add missing flow_input and result properties * fix(frontend): fix build * fix(frontend): improve code
This commit is contained in:
@@ -32,6 +32,9 @@
|
||||
viewJsonSchema = false
|
||||
try {
|
||||
schema = resourceTypeInfo.schema as any
|
||||
|
||||
schema.order = schema.order ?? Object.keys(schema.properties).sort()
|
||||
|
||||
notFound = false
|
||||
} catch (e) {
|
||||
notFound = true
|
||||
|
||||
@@ -290,6 +290,11 @@
|
||||
return
|
||||
}
|
||||
|
||||
if (!runnableComponent) {
|
||||
params.successCallback([], 0)
|
||||
return
|
||||
}
|
||||
|
||||
runnableComponent?.runComponent(undefined, undefined, undefined, currentParams, {
|
||||
done: (items) => {
|
||||
let lastRow = -1
|
||||
|
||||
@@ -90,6 +90,12 @@
|
||||
|
||||
if (!runnableComponent && result) {
|
||||
params.successCallback(result, result.length)
|
||||
return
|
||||
}
|
||||
|
||||
if (!runnableComponent && !result) {
|
||||
params.successCallback([], 0)
|
||||
return
|
||||
}
|
||||
|
||||
runnableComponent?.runComponent(undefined, undefined, undefined, currentParams, {
|
||||
|
||||
@@ -629,6 +629,7 @@
|
||||
onDestroy(() => {
|
||||
$initialized.initializedComponents = $initialized.initializedComponents.filter((c) => c !== id)
|
||||
delete $errorByComponent[id]
|
||||
|
||||
if ($runnableComponents[id]) {
|
||||
$runnableComponents[id] = {
|
||||
...$runnableComponents[id],
|
||||
|
||||
@@ -62,58 +62,51 @@
|
||||
|
||||
const history: string[] = []
|
||||
|
||||
function updateCurrentNode(node, index) {
|
||||
currentNodeId = node.next[index].id
|
||||
history.push(node.id)
|
||||
selectedConditionIndex = index + 1
|
||||
$focusedGrid = {
|
||||
parentComponentId: id,
|
||||
subGridIndex: nodes.findIndex((node) => node.id == currentNodeId)
|
||||
}
|
||||
}
|
||||
|
||||
function next() {
|
||||
const resolvedNodeConditions = resolvedConditions[currentNodeId]
|
||||
const node = nodes.find((node) => node.id == currentNodeId)
|
||||
|
||||
let found: boolean = false
|
||||
if (!node) {
|
||||
return
|
||||
}
|
||||
|
||||
resolvedNodeConditions.forEach((condition, index) => {
|
||||
if (found) return
|
||||
|
||||
const node = nodes.find((node) => node.id == currentNodeId)
|
||||
|
||||
if (condition && node && resolvedNext[node.id] !== false) {
|
||||
found = true
|
||||
currentNodeId = node.next[index].id
|
||||
|
||||
history.push(node.id)
|
||||
|
||||
selectedConditionIndex = index + 1
|
||||
|
||||
$focusedGrid = {
|
||||
parentComponentId: id,
|
||||
subGridIndex: nodes.findIndex((node) => node.id == currentNodeId)
|
||||
}
|
||||
for (let index = 0; index < resolvedNodeConditions.length; index++) {
|
||||
const condition = resolvedNodeConditions[index]
|
||||
if (condition && resolvedNext[node.id] !== false) {
|
||||
updateCurrentNode(node, index)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
function updateFocusedGrid(nodeId) {
|
||||
currentNodeId = nodeId
|
||||
selectedConditionIndex = nodes.findIndex((node) => node.id == currentNodeId)
|
||||
$focusedGrid = {
|
||||
parentComponentId: id,
|
||||
subGridIndex: selectedConditionIndex
|
||||
}
|
||||
}
|
||||
|
||||
function prev() {
|
||||
const previsouNodeId = history.pop()
|
||||
const previousNodeId = history.pop()
|
||||
|
||||
if (previsouNodeId) {
|
||||
currentNodeId = previsouNodeId
|
||||
|
||||
selectedConditionIndex = nodes.findIndex((next) => next.id == currentNodeId)
|
||||
|
||||
$focusedGrid = {
|
||||
parentComponentId: id,
|
||||
subGridIndex: selectedConditionIndex
|
||||
}
|
||||
if (previousNodeId) {
|
||||
updateFocusedGrid(previousNodeId)
|
||||
} else {
|
||||
// if no history, go to first node
|
||||
|
||||
// if no history, go to the first node
|
||||
const node = getFirstNode(nodes)
|
||||
|
||||
if (node) {
|
||||
currentNodeId = node.id
|
||||
|
||||
selectedConditionIndex = nodes.findIndex((next) => next.id == currentNodeId)
|
||||
|
||||
$focusedGrid = {
|
||||
parentComponentId: id,
|
||||
subGridIndex: selectedConditionIndex
|
||||
}
|
||||
updateFocusedGrid(node.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { Button, Drawer, DrawerContent } from '$lib/components/common'
|
||||
import { Alert, Button, Drawer, DrawerContent } from '$lib/components/common'
|
||||
import { Network, Plus, Trash } from 'lucide-svelte'
|
||||
import type { AppComponent, DecisionTreeNode } from '../component'
|
||||
import { Pane, Splitpanes } from 'svelte-splitpanes'
|
||||
@@ -12,6 +12,7 @@
|
||||
import Label from '$lib/components/Label.svelte'
|
||||
import { debounce } from '$lib/utils'
|
||||
import type { AppViewerContext } from '../../types'
|
||||
import Badge from '$lib/components/common/badge/Badge.svelte'
|
||||
|
||||
export let component: AppComponent
|
||||
export let nodes: DecisionTreeNode[]
|
||||
@@ -102,9 +103,9 @@
|
||||
<div class="grow relative">
|
||||
<InputsSpecEditor
|
||||
key={`condition-${selectedNode.id}-${index}`}
|
||||
customTitle={`${index > 0 ? 'Otherwise ' : ''}Goes to branch ${
|
||||
index + 1
|
||||
} (First node: ${nodes?.findIndex((node) => node.id == subNode.id)}) if:`}
|
||||
customTitle={index === 0
|
||||
? 'Goes to the default branch'
|
||||
: `${index > 0 ? 'Otherwise ' : ''}Goes to branch ${index}`}
|
||||
bind:componentInput={subNode.condition}
|
||||
id={selectedNode.id}
|
||||
userInputEnabled={false}
|
||||
@@ -120,10 +121,23 @@
|
||||
displayType={false}
|
||||
fixedOverflowWidgets={false}
|
||||
/>
|
||||
<div class="flex flex-row gap-1 mt-2">
|
||||
<Badge>
|
||||
{`Next node id: ${subNode.id}`}
|
||||
</Badge>
|
||||
<Badge color="indigo">
|
||||
{`Next tab index: ${nodes?.findIndex((node) => node.id == subNode.id)}`}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
<Alert type="info" class="mt-4" title="Multiple branches" size="xs">
|
||||
The conditions above are evaluated in order. The first condition that is met will
|
||||
be the branch that is taken.
|
||||
</Alert>
|
||||
{/if}
|
||||
{#key selectedNode.id}
|
||||
{#if selectedNode.allowed}
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
const current = cleanValueProperties({ ...(modifiedValue ?? {}), path: undefined })
|
||||
if (orderedJsonStringify(draftOrDeployed) === orderedJsonStringify(current)) {
|
||||
bypassBeforeNavigate = true
|
||||
console.log('FOO')
|
||||
goto(goingTo)
|
||||
} else {
|
||||
open = true
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
import FlowModuleCache from './FlowModuleCache.svelte'
|
||||
import FlowModuleDeleteAfterUse from './FlowModuleDeleteAfterUse.svelte'
|
||||
import FlowRetries from './FlowRetries.svelte'
|
||||
import { getStepPropPicker } from '../previousResults'
|
||||
import { getFailureStepPropPicker, getStepPropPicker } from '../previousResults'
|
||||
import { deepEqual } from 'fast-equals'
|
||||
import Section from '$lib/components/Section.svelte'
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
import FlowModuleSleep from './FlowModuleSleep.svelte'
|
||||
import FlowPathViewer from './FlowPathViewer.svelte'
|
||||
import InputTransformSchemaForm from '$lib/components/InputTransformSchemaForm.svelte'
|
||||
import { schemaToObject } from '$lib/schema'
|
||||
import FlowModuleMock from './FlowModuleMock.svelte'
|
||||
import Tooltip from '$lib/components/Tooltip.svelte'
|
||||
import { SecondsInput } from '$lib/components/common'
|
||||
@@ -102,22 +101,7 @@
|
||||
$: editor !== undefined && setCopilotModuleEditor()
|
||||
|
||||
$: stepPropPicker = failureModule
|
||||
? {
|
||||
pickableProperties: {
|
||||
flow_input: schemaToObject($flowStore.schema as any, $previewArgs),
|
||||
priorIds: {},
|
||||
previousId: undefined,
|
||||
hasResume: false
|
||||
},
|
||||
extraLib: `
|
||||
declare const error: {
|
||||
message: string
|
||||
name: string
|
||||
stack: string
|
||||
}
|
||||
|
||||
`
|
||||
}
|
||||
? getFailureStepPropPicker($flowStateStore, $flowStore, $previewArgs)
|
||||
: getStepPropPicker(
|
||||
$flowStateStore,
|
||||
parentModule,
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string',
|
||||
multiselect: allUserGroups
|
||||
enum: allUserGroups
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,6 +119,49 @@ export function getPreviousIds(id: string, flow: OpenFlow, include_node: boolean
|
||||
.flat()
|
||||
}
|
||||
|
||||
export function getFailureStepPropPicker(flowState: FlowState, flow: OpenFlow, args: any) {
|
||||
const allIds = flow.value.modules.map((x) => x.id)
|
||||
let priorIds = Object.fromEntries(
|
||||
allIds.map((id) => [id, flowState[id]?.previewResult ?? {}]).reverse()
|
||||
)
|
||||
|
||||
const flowInput = getFlowInput(
|
||||
dfs(flow.value.modules[0].id, flow),
|
||||
flowState,
|
||||
args,
|
||||
flow.schema as Schema
|
||||
)
|
||||
|
||||
return {
|
||||
pickableProperties: {
|
||||
flow_input: schemaToObject(flow.schema as any, args),
|
||||
priorIds: priorIds,
|
||||
previousId: undefined,
|
||||
hasResume: false
|
||||
},
|
||||
extraLib: `
|
||||
/**
|
||||
* Error object
|
||||
*/
|
||||
declare const error: {
|
||||
message: string
|
||||
name: string
|
||||
stack: string
|
||||
}
|
||||
|
||||
/**
|
||||
* result by id
|
||||
*/
|
||||
declare const results = ${JSON.stringify(priorIds)}
|
||||
|
||||
/**
|
||||
* flow input as an object
|
||||
*/
|
||||
declare const flow_input = ${JSON.stringify(flowInput)};
|
||||
`
|
||||
}
|
||||
}
|
||||
|
||||
export function getStepPropPicker(
|
||||
flowState: FlowState,
|
||||
parentModule: FlowModule | undefined,
|
||||
|
||||
@@ -160,7 +160,7 @@
|
||||
Object.entries(flowModuleStates ?? [])
|
||||
.filter(([k, v]) => k.startsWith('failure'))
|
||||
.forEach(([k, v]) => {
|
||||
nestedNodes.push(createErrorHandler({ id: k } as FlowModule, v.parent_module))
|
||||
nestedNodes.push(createErrorHandler({ id: k } as FlowModule, v.parent_module, k))
|
||||
})
|
||||
}
|
||||
const flatNodes = flattenNestedNodes(nestedNodes)
|
||||
@@ -726,8 +726,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
function createErrorHandler(mod: FlowModule, parent_module?: string): Node {
|
||||
const nId = (-idGenerator.next().value - 1 + 1100).toString()
|
||||
function createErrorHandler(
|
||||
mod: FlowModule,
|
||||
parent_module?: string,
|
||||
customNodeId?: string | undefined
|
||||
): Node {
|
||||
// When needed, we can add a custom node id to the error handler
|
||||
// used for nested error handlers in for loop for example
|
||||
const nId = customNodeId ?? 'failure'
|
||||
parent_module && (errorHandlers[parent_module] = nId)
|
||||
let label = 'Error handler'
|
||||
return {
|
||||
|
||||
@@ -119,6 +119,36 @@
|
||||
on:select
|
||||
/>
|
||||
</div>
|
||||
{#if Object.keys(pickableProperties.priorIds).length > 0}
|
||||
{#if suggestedPropsFiltered && Object.keys(suggestedPropsFiltered).length > 0}
|
||||
<span class="font-bold text-sm">Suggested Results</span>
|
||||
<div class="overflow-y-auto mb-2">
|
||||
<ObjectViewer
|
||||
allowCopy={false}
|
||||
topLevelNode
|
||||
pureViewer={!$propPickerConfig}
|
||||
collapsed={false}
|
||||
json={suggestedPropsFiltered}
|
||||
on:select={(e) => {
|
||||
dispatch('select', `results.${e.detail}`)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
<span class="font-bold text-sm">All Results</span>
|
||||
<div class="overflow-y-auto mb-2">
|
||||
<ObjectViewer
|
||||
allowCopy={false}
|
||||
topLevelNode
|
||||
pureViewer={!$propPickerConfig}
|
||||
collapsed={true}
|
||||
json={resultByIdFiltered}
|
||||
on:select={(e) => {
|
||||
dispatch('select', `results.${e.detail}`)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
{#if previousId}
|
||||
<span class="font-bold text-sm">Previous Result</span>
|
||||
|
||||
@@ -13,6 +13,7 @@ import type { UserExt } from './stores'
|
||||
import { sendUserToast } from './toast'
|
||||
import type { Script } from './gen'
|
||||
import type { EnumType } from './common'
|
||||
import type { Schema } from './common'
|
||||
export { sendUserToast }
|
||||
|
||||
export function validateUsername(username: string): string {
|
||||
@@ -207,7 +208,7 @@ export interface DropdownItem {
|
||||
|
||||
export const DELETE = 'delete' as 'delete'
|
||||
|
||||
export function emptySchema() {
|
||||
export function emptySchema(): Schema {
|
||||
return {
|
||||
$schema: 'https://json-schema.org/draft/2020-12/schema' as string | undefined,
|
||||
properties: {},
|
||||
@@ -216,7 +217,7 @@ export function emptySchema() {
|
||||
}
|
||||
}
|
||||
|
||||
export function simpleSchema() {
|
||||
export function simpleSchema(): Schema {
|
||||
return {
|
||||
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
||||
type: 'object',
|
||||
|
||||
Reference in New Issue
Block a user