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:
Faton Ramadani
2024-07-11 12:00:52 +02:00
committed by GitHub
parent 7ea554a7fd
commit fd4fe15f49
13 changed files with 154 additions and 69 deletions

View File

@@ -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

View File

@@ -290,6 +290,11 @@
return
}
if (!runnableComponent) {
params.successCallback([], 0)
return
}
runnableComponent?.runComponent(undefined, undefined, undefined, currentParams, {
done: (items) => {
let lastRow = -1

View File

@@ -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, {

View File

@@ -629,6 +629,7 @@
onDestroy(() => {
$initialized.initializedComponents = $initialized.initializedComponents.filter((c) => c !== id)
delete $errorByComponent[id]
if ($runnableComponents[id]) {
$runnableComponents[id] = {
...$runnableComponents[id],

View File

@@ -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)
}
}
}

View File

@@ -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}

View File

@@ -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

View File

@@ -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,

View File

@@ -38,7 +38,7 @@
type: 'array',
items: {
type: 'string',
multiselect: allUserGroups
enum: allUserGroups
}
}
}

View File

@@ -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,

View File

@@ -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 {

View File

@@ -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>

View File

@@ -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',