337 lines
6.9 KiB
TypeScript
337 lines
6.9 KiB
TypeScript
import type { FlowModule, OpenFlow } from '$lib/gen'
|
|
import { deepEqual } from 'fast-equals'
|
|
import { findGridItem } from '../apps/editor/appUtils'
|
|
import type { App } from '../apps/types'
|
|
|
|
export function setInputBySelector(selector: string, value: string) {
|
|
const input = document.querySelector(selector) as HTMLInputElement
|
|
|
|
if (input) {
|
|
input.value = value
|
|
input.dispatchEvent(new Event('input', { bubbles: true }))
|
|
}
|
|
}
|
|
|
|
export function clickButtonBySelector(selector: string) {
|
|
const button = document.querySelector(selector) as HTMLButtonElement
|
|
|
|
if (button) {
|
|
button.click()
|
|
}
|
|
}
|
|
|
|
export function clickFirstButtonBySelector(selector: string) {
|
|
const buttons = document.querySelector(selector)
|
|
const button = buttons?.childNodes[0] as HTMLButtonElement
|
|
|
|
if (button) {
|
|
button.click()
|
|
}
|
|
}
|
|
|
|
export function triggerAddFlowStep(index: number) {
|
|
const button = document.querySelector(`#flow-editor-add-step-${index}`) as HTMLButtonElement
|
|
|
|
if (button) {
|
|
button.parentElement?.dispatchEvent(new PointerEvent('pointerdown', { bubbles: true }))
|
|
}
|
|
}
|
|
|
|
export function selectFlowStepKind(index: number) {
|
|
const button = document.querySelector(
|
|
`#flow-editor-insert-module > div > button:nth-child(${index})`
|
|
) as HTMLButtonElement
|
|
|
|
if (button) {
|
|
button?.dispatchEvent(new PointerEvent('pointerdown', { bubbles: true }))
|
|
}
|
|
}
|
|
|
|
export function selectOptionsBySelector(selector: string, value: string) {
|
|
const select = document.querySelector(selector) as HTMLSelectElement
|
|
|
|
if (select) {
|
|
select.value = value
|
|
select.dispatchEvent(new Event('change', { bubbles: true }))
|
|
}
|
|
}
|
|
|
|
export function isFlowTainted(flow: OpenFlow) {
|
|
return (
|
|
flow.value.modules.length > 0 || Object.keys((flow?.schema?.properties as any) ?? {}).length > 0
|
|
)
|
|
}
|
|
|
|
const emptyApp = {
|
|
grid: [
|
|
{
|
|
'3': {
|
|
fixed: false,
|
|
x: 0,
|
|
y: 0,
|
|
fullHeight: false,
|
|
w: 6,
|
|
h: 2
|
|
},
|
|
'12': {
|
|
fixed: false,
|
|
x: 0,
|
|
y: 0,
|
|
fullHeight: false,
|
|
w: 12,
|
|
h: 2
|
|
},
|
|
data: {
|
|
type: 'containercomponent',
|
|
configuration: {},
|
|
customCss: {
|
|
container: {
|
|
class: '!p-0',
|
|
style: ''
|
|
}
|
|
},
|
|
actions: [],
|
|
numberOfSubgrids: 1,
|
|
id: 'a'
|
|
},
|
|
id: 'a'
|
|
}
|
|
],
|
|
fullscreen: false,
|
|
unusedInlineScripts: [],
|
|
hiddenInlineScripts: [],
|
|
theme: {
|
|
type: 'path',
|
|
path: 'f/app_themes/theme_0'
|
|
},
|
|
subgrids: {
|
|
'a-0': [
|
|
{
|
|
'3': {
|
|
fixed: false,
|
|
x: 0,
|
|
y: 0,
|
|
fullHeight: false,
|
|
w: 6,
|
|
h: 1
|
|
},
|
|
'12': {
|
|
fixed: false,
|
|
x: 0,
|
|
y: 0,
|
|
fullHeight: false,
|
|
w: 6,
|
|
h: 1
|
|
},
|
|
data: {
|
|
type: 'textcomponent',
|
|
configuration: {
|
|
style: {
|
|
type: 'static',
|
|
value: 'Body'
|
|
},
|
|
copyButton: {
|
|
type: 'static',
|
|
value: false
|
|
},
|
|
tooltip: {
|
|
type: 'evalv2',
|
|
value: '',
|
|
fieldType: 'text',
|
|
expr: '`Author: ${ctx.author}`',
|
|
connections: [
|
|
{
|
|
componentId: 'ctx',
|
|
id: 'author'
|
|
}
|
|
]
|
|
},
|
|
disableNoText: {
|
|
type: 'static',
|
|
value: true,
|
|
fieldType: 'boolean'
|
|
}
|
|
},
|
|
componentInput: {
|
|
type: 'templatev2',
|
|
fieldType: 'template',
|
|
eval: '${ctx.summary}',
|
|
connections: [
|
|
{
|
|
id: 'summary',
|
|
componentId: 'ctx'
|
|
}
|
|
]
|
|
},
|
|
customCss: {
|
|
text: {
|
|
class: 'text-xl font-semibold whitespace-nowrap truncate',
|
|
style: ''
|
|
},
|
|
container: {
|
|
class: '',
|
|
style: ''
|
|
}
|
|
},
|
|
actions: [],
|
|
horizontalAlignment: 'left',
|
|
verticalAlignment: 'center',
|
|
id: 'b'
|
|
},
|
|
id: 'b'
|
|
},
|
|
{
|
|
'3': {
|
|
fixed: false,
|
|
x: 0,
|
|
y: 1,
|
|
fullHeight: false,
|
|
w: 3,
|
|
h: 1
|
|
},
|
|
'12': {
|
|
fixed: false,
|
|
x: 6,
|
|
y: 0,
|
|
fullHeight: false,
|
|
w: 6,
|
|
h: 1
|
|
},
|
|
data: {
|
|
type: 'recomputeallcomponent',
|
|
configuration: {},
|
|
actions: [],
|
|
menuItems: [],
|
|
horizontalAlignment: 'right',
|
|
verticalAlignment: 'center',
|
|
id: 'c'
|
|
},
|
|
id: 'c'
|
|
}
|
|
]
|
|
},
|
|
hideLegacyTopBar: true,
|
|
norefreshbar: false
|
|
}
|
|
|
|
export function isAppTainted(app: App) {
|
|
if (app.hideLegacyTopBar === true) {
|
|
// An empty app should have only have a topbar and no hidden inline scripts
|
|
|
|
if (Array.isArray(app.hiddenInlineScripts) && app.hiddenInlineScripts?.length > 0) {
|
|
return true
|
|
}
|
|
|
|
// New apps have only a single component which is the topbar
|
|
if (Array.isArray(app.grid) && app.grid.length > 1) {
|
|
return true
|
|
}
|
|
|
|
// Check if the current app is different from an empty app
|
|
return !deepEqual(app, emptyApp)
|
|
} else {
|
|
// For older apps,
|
|
return !(app.grid.length === 0 && app.hiddenInlineScripts?.length === 0)
|
|
}
|
|
}
|
|
|
|
export function updateFlowModuleById(
|
|
flow: OpenFlow,
|
|
id: string,
|
|
callback: (module: FlowModule) => void
|
|
) {
|
|
const dfs = (modules: FlowModule[]) => {
|
|
for (const module of modules) {
|
|
if (module.id === id) {
|
|
callback(module)
|
|
return
|
|
}
|
|
|
|
if (module.value.type === 'forloopflow') {
|
|
dfs(module.value.modules)
|
|
} else if (module.value.type === 'branchone') {
|
|
module.value.branches.forEach((branch) => dfs(branch.modules))
|
|
} else if (module.value.type === 'branchall') {
|
|
module.value.branches.forEach((branch) => dfs(branch.modules))
|
|
}
|
|
}
|
|
}
|
|
|
|
dfs(flow.value.modules)
|
|
|
|
flow = flow
|
|
}
|
|
|
|
export function updateBackgroundRunnableCode(app: App, index: number, newCode: string) {
|
|
const script = app.hiddenInlineScripts[index]
|
|
if (script.type === 'runnableByName' && script.inlineScript) {
|
|
script.inlineScript.content = newCode
|
|
}
|
|
|
|
app = app
|
|
}
|
|
|
|
export function updateInlineRunnableCode(app: App, componentId: string, newCode: string) {
|
|
const gridItem = findGridItem(app, componentId)
|
|
|
|
if (gridItem?.data.componentInput?.type === 'runnable') {
|
|
if (
|
|
gridItem.data.componentInput.runnable?.type === 'runnableByName' &&
|
|
gridItem.data.componentInput.runnable.inlineScript
|
|
) {
|
|
gridItem.data.componentInput.runnable.inlineScript.content = newCode
|
|
}
|
|
}
|
|
|
|
app = app
|
|
}
|
|
|
|
export function connectComponentSourceToOutput(app: App, componentId: string, targetId: string) {
|
|
const gridItem = findGridItem(app, componentId)
|
|
|
|
if (gridItem) {
|
|
gridItem.data.componentInput = {
|
|
type: 'evalv2',
|
|
fieldType: 'object',
|
|
|
|
expr: `${targetId}.result`,
|
|
connections: [
|
|
{
|
|
componentId: targetId,
|
|
id: 'result'
|
|
}
|
|
]
|
|
}
|
|
}
|
|
|
|
app = app
|
|
}
|
|
|
|
export function connectInlineRunnableInputToComponentOutput(
|
|
app: App,
|
|
sourceComponentId: string,
|
|
sourceField: string,
|
|
targetComponentId: string,
|
|
targetField: string,
|
|
fieldType: string = 'text'
|
|
) {
|
|
const gridItem = findGridItem(app, sourceComponentId)
|
|
|
|
if (gridItem?.data.componentInput?.type === 'runnable') {
|
|
// @ts-ignore
|
|
gridItem.data.componentInput.fields = {
|
|
[sourceField]: {
|
|
type: 'evalv2',
|
|
expr: `${targetComponentId}.${targetField}`,
|
|
fieldType: fieldType,
|
|
connections: [
|
|
{
|
|
componentId: targetComponentId,
|
|
id: targetField
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
}
|