build: 清理 tinyflow-ui 构建告警
- 收口 Svelte props 响应式引用与 custom element props 声明 - 清理局部未使用样式与类型告警并保持现有业务语义
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
<svelte:options customElement={{
|
||||
tag: "tinyflow-component",
|
||||
shadow: "none",
|
||||
// props: {
|
||||
// options: { reflect: true, type: 'Object', attribute: 'options' },
|
||||
// onInit: { reflect: true, type: 'Object', attribute: 'onInit' }
|
||||
// },
|
||||
props: {
|
||||
options: { type: 'Object', attribute: 'options' },
|
||||
onInit: { type: 'Object', attribute: 'on-init' }
|
||||
},
|
||||
}} />
|
||||
|
||||
<script lang="ts">
|
||||
@@ -14,31 +14,50 @@
|
||||
import type {TinyflowData, TinyflowOptions} from '#types';
|
||||
import {setContext} from 'svelte';
|
||||
|
||||
const { options, onInit }: {
|
||||
const props = $props<{
|
||||
options: TinyflowOptions,
|
||||
onInit: (svelteFlow: ReturnType<typeof useSvelteFlow>) => void,
|
||||
} = $props();
|
||||
}>();
|
||||
|
||||
let { data } = options;
|
||||
let initialViewport = null;
|
||||
|
||||
if (typeof data === 'string') {
|
||||
try {
|
||||
data = JSON.parse(data.trim());
|
||||
} catch (e) {
|
||||
console.error('Invalid JSON data:', data);
|
||||
const parseData = (source: TinyflowOptions['data']) => {
|
||||
let nextData = source;
|
||||
if (typeof nextData === 'string') {
|
||||
try {
|
||||
nextData = JSON.parse(nextData.trim());
|
||||
} catch (error) {
|
||||
console.error('Invalid JSON data:', nextData, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
initialViewport = (data as TinyflowData)?.viewport || null;
|
||||
return nextData as TinyflowData | null | undefined;
|
||||
};
|
||||
|
||||
const getOptions = () => props.options;
|
||||
const contextOptions = new Proxy({} as TinyflowOptions, {
|
||||
get(_target, property) {
|
||||
return (getOptions() as Record<PropertyKey, unknown>)[property];
|
||||
},
|
||||
has(_target, property) {
|
||||
return property in getOptions();
|
||||
},
|
||||
ownKeys() {
|
||||
return Reflect.ownKeys(getOptions());
|
||||
},
|
||||
getOwnPropertyDescriptor(_target, property) {
|
||||
const descriptor = Object.getOwnPropertyDescriptor(getOptions(), property);
|
||||
return descriptor ? { ...descriptor, configurable: true } : undefined;
|
||||
}
|
||||
}) as TinyflowOptions;
|
||||
const data = parseData(getOptions().data);
|
||||
const initialViewport = data?.viewport || null;
|
||||
store.init(
|
||||
(data as TinyflowData)?.nodes || [],
|
||||
(data as TinyflowData)?.edges || [],
|
||||
data?.nodes || [],
|
||||
data?.edges || [],
|
||||
initialViewport,
|
||||
);
|
||||
setContext('tinyflow_options', options);
|
||||
setContext('tinyflow_options', contextOptions);
|
||||
</script>
|
||||
|
||||
|
||||
<SvelteFlowProvider>
|
||||
<TinyflowCore {onInit} />
|
||||
<TinyflowCore onInit={props.onInit} />
|
||||
</SvelteFlowProvider>
|
||||
|
||||
@@ -46,8 +46,6 @@
|
||||
const { onInit }: { onInit: any; [key: string]: any } = $props();
|
||||
const svelteFlow = useSvelteFlow();
|
||||
|
||||
onInit(svelteFlow);
|
||||
|
||||
let showEdgePanel = $state(false);
|
||||
let currentEdge = $state<Edge | null>(null);
|
||||
let nodePickerVisible = $state(false);
|
||||
@@ -342,7 +340,7 @@
|
||||
{ duration: 180 }
|
||||
);
|
||||
} else {
|
||||
svelteFlow.zoomTo(zoom, { duration: 180 });
|
||||
(svelteFlow as any).zoomTo?.(zoom, { duration: 180 });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -726,6 +724,7 @@
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
onInit(svelteFlow);
|
||||
store.updateEdges((edges) => edges.map((edge) => ensureEdgeVisualDefaults(edge)));
|
||||
repairOrphanParentNodes();
|
||||
if (!readonly) {
|
||||
|
||||
@@ -1,18 +1,30 @@
|
||||
<svelte:options customElement={{ props: {} }} />
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
import type {MyHTMLButtonAttributes} from './types';
|
||||
import type {Snippet} from 'svelte';
|
||||
|
||||
const { children, primary, onclick, ...rest }: MyHTMLButtonAttributes & {
|
||||
children?: Snippet;
|
||||
primary?: boolean;
|
||||
} = $props();
|
||||
const {
|
||||
children,
|
||||
primary,
|
||||
onclick,
|
||||
class: className = '',
|
||||
style = '',
|
||||
...rest
|
||||
}: Omit<MyHTMLButtonAttributes, 'class' | 'style'> & {
|
||||
children?: Snippet;
|
||||
primary?: boolean;
|
||||
class?: string;
|
||||
style?: string;
|
||||
} = $props();
|
||||
</script>
|
||||
<button
|
||||
type="button"
|
||||
{...rest}
|
||||
onclick={onclick}
|
||||
class="tf-btn {primary?'tf-btn-primary':''} nopan nodrag {rest.class}"
|
||||
{style}
|
||||
class="tf-btn {primary?'tf-btn-primary':''} nopan nodrag {className}"
|
||||
>
|
||||
{@render children?.()}
|
||||
</button>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<svelte:options customElement={{ props: {} }} />
|
||||
|
||||
<script lang="ts">
|
||||
import type {MyHTMLInputAttributes} from './types';
|
||||
|
||||
|
||||
@@ -1,17 +1,30 @@
|
||||
<svelte:options customElement={{ props: {} }} />
|
||||
|
||||
<script lang="ts">
|
||||
import {Button, Input} from './index';
|
||||
import type {MyHTMLAttributes} from './types';
|
||||
|
||||
const { placeholder, label, value, buttonText = "选择...",onChosen, ...rest }: {
|
||||
placeholder?: string;
|
||||
label?: any;
|
||||
value?: any;
|
||||
buttonText?:string
|
||||
onChosen?: (value?: any, label?: any, event?: Event) => void,
|
||||
} & MyHTMLAttributes = $props();
|
||||
const {
|
||||
placeholder,
|
||||
label,
|
||||
value,
|
||||
buttonText = "选择...",
|
||||
onChosen,
|
||||
class: className = '',
|
||||
style = '',
|
||||
...rest
|
||||
}: Omit<MyHTMLAttributes, 'class' | 'style'> & {
|
||||
placeholder?: string;
|
||||
label?: any;
|
||||
value?: any;
|
||||
buttonText?: string;
|
||||
onChosen?: (value?: any, label?: any, event?: Event) => void;
|
||||
class?: string;
|
||||
style?: string;
|
||||
} = $props();
|
||||
|
||||
</script>
|
||||
<div {...rest} class="tf-chosen nopan nodrag {rest.class}">
|
||||
<div {...rest} {style} class="tf-chosen nopan nodrag {className}">
|
||||
<input type="hidden" value={value}>
|
||||
<Input value={label} {placeholder} style="flex-grow: 1;" disabled/>
|
||||
<Button onclick={(e)=>{
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<svelte:options customElement={{ props: {} }} />
|
||||
|
||||
<script lang="ts">
|
||||
import type {Snippet} from 'svelte';
|
||||
import {Render} from './index';
|
||||
|
||||
@@ -1,6 +1,28 @@
|
||||
<svelte:options customElement={{ props: {} }} />
|
||||
|
||||
<script lang="ts">
|
||||
import type {MyHTMLInputAttributes} from './types';
|
||||
|
||||
const { ...rest }: MyHTMLInputAttributes = $props();
|
||||
const {
|
||||
class: className = '',
|
||||
style = '',
|
||||
type = 'text',
|
||||
variant = 'default',
|
||||
value,
|
||||
...rest
|
||||
}: Omit<MyHTMLInputAttributes, 'class' | 'style' | 'type' | 'value'> & {
|
||||
class?: string;
|
||||
style?: string;
|
||||
type?: string;
|
||||
value?: unknown;
|
||||
variant?: 'default' | 'borderless';
|
||||
} = $props();
|
||||
</script>
|
||||
<input type="text" spellcheck="false" {...rest} class="tf-input nopan nodrag {rest.class}" />
|
||||
<input
|
||||
{type}
|
||||
spellcheck="false"
|
||||
{...rest}
|
||||
{value}
|
||||
{style}
|
||||
class="tf-input {variant === 'borderless' ? 'tf-input-borderless' : ''} nopan nodrag {className}"
|
||||
/>
|
||||
|
||||
@@ -1,11 +1,24 @@
|
||||
<svelte:options customElement={{ props: {} }} />
|
||||
|
||||
<script lang="ts">
|
||||
import Button from './button.svelte';
|
||||
import type {MyHTMLButtonAttributes} from './types';
|
||||
|
||||
const { ...rest }: MyHTMLButtonAttributes = $props();
|
||||
const {
|
||||
class: className = '',
|
||||
style,
|
||||
...rest
|
||||
}: MyHTMLButtonAttributes & {
|
||||
class?: string | null;
|
||||
style?: string | null;
|
||||
} = $props();
|
||||
</script>
|
||||
|
||||
<Button {...rest} class="input-btn-more {rest.class}">
|
||||
<Button
|
||||
{...rest}
|
||||
class="input-btn-more {className}"
|
||||
style={style ?? undefined}
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path
|
||||
d="M4.5 10.5C3.675 10.5 3 11.175 3 12C3 12.825 3.675 13.5 4.5 13.5C5.325 13.5 6 12.825 6 12C6 11.175 5.325 10.5 4.5 10.5ZM19.5 10.5C18.675 10.5 18 11.175 18 12C18 12.825 18.675 13.5 19.5 13.5C20.325 13.5 21 12.825 21 12C21 11.175 20.325 10.5 19.5 10.5ZM12 10.5C11.175 10.5 10.5 11.175 10.5 12C10.5 12.825 11.175 13.5 12 13.5C12.825 13.5 13.5 12.825 13.5 12C13.5 11.175 12.825 10.5 12 10.5Z"></path>
|
||||
|
||||
@@ -29,8 +29,9 @@
|
||||
let floatingRef: any = $state();
|
||||
let hoveredItem: SelectItem | null = $state(null);
|
||||
let isOpen = $state(false);
|
||||
let selectedItem = $state<SelectItem | null>(null);
|
||||
|
||||
let selectedItem = $derived.by(() => {
|
||||
$effect(() => {
|
||||
let found: SelectItem | null = null;
|
||||
const findItem = (items: SelectItem[]) => {
|
||||
for (const it of items) {
|
||||
@@ -41,8 +42,15 @@
|
||||
}
|
||||
};
|
||||
findItem(refOptions);
|
||||
return found;
|
||||
selectedItem = found;
|
||||
});
|
||||
let selectedNodeType = $derived(selectedItem?.nodeType);
|
||||
let selectedNodeIcon = $derived(
|
||||
selectedNodeType ? nodeIcons[selectedNodeType] : undefined,
|
||||
);
|
||||
let selectedLabel = $derived(
|
||||
selectedItem?.displayLabel || selectedItem?.label || '',
|
||||
);
|
||||
|
||||
function closeMenu() {
|
||||
floatingRef?.hide();
|
||||
@@ -111,12 +119,12 @@
|
||||
<div class="tf-mixed-box tf-mixed-ref-box">
|
||||
{#if selectedItem}
|
||||
<div class="tf-mixed-sel-val">
|
||||
{#if selectedItem.nodeType && nodeIcons[selectedItem.nodeType]}
|
||||
{#if selectedNodeType && selectedNodeIcon}
|
||||
<span class="tf-mixed-val-icon">
|
||||
{@html nodeIcons[selectedItem.nodeType]}
|
||||
{@html selectedNodeIcon}
|
||||
</span>
|
||||
{/if}
|
||||
<span class="tf-mixed-val-name">{selectedItem.displayLabel || selectedItem.label}</span>
|
||||
<span class="tf-mixed-val-name">{selectedLabel}</span>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="tf-mixed-placeholder">{placeholder}</div>
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
<svelte:options customElement={{ props: {} }} />
|
||||
|
||||
<script lang="ts">
|
||||
let { target } = $props();
|
||||
if (typeof target === 'undefined') target = "undefined";
|
||||
const props = $props<{ target?: string | (() => unknown) }>();
|
||||
const target = $derived(
|
||||
typeof props.target === 'undefined' ? 'undefined' : props.target
|
||||
);
|
||||
</script>
|
||||
|
||||
|
||||
@@ -9,4 +13,3 @@
|
||||
{:else }
|
||||
{@html target}
|
||||
{/if}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<svelte:options customElement={{ props: {} }} />
|
||||
|
||||
<script lang="ts">
|
||||
import {FloatingTrigger} from './index';
|
||||
import type {SelectItem} from '#types';
|
||||
@@ -541,6 +543,7 @@
|
||||
color: var(--tf-text-secondary);
|
||||
line-height: 1.3;
|
||||
margin-top: 2px;
|
||||
line-clamp: 2;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
|
||||
@@ -1,14 +1,27 @@
|
||||
<svelte:options customElement={{ props: {} }} />
|
||||
|
||||
<script lang="ts">
|
||||
import type {MyHTMLTextareaAttributes} from './types';
|
||||
|
||||
const { value, height, autoHeight = true, maxHeight, onHeightChange, ...rest }: MyHTMLTextareaAttributes & {
|
||||
value?: any;
|
||||
height?: string | number;
|
||||
autoHeight?: boolean;
|
||||
rows?: number;
|
||||
maxHeight?: string | number;
|
||||
onHeightChange?: (height: string) => void;
|
||||
} = $props();
|
||||
const {
|
||||
value,
|
||||
height,
|
||||
autoHeight = true,
|
||||
maxHeight,
|
||||
onHeightChange,
|
||||
class: className = '',
|
||||
style = '',
|
||||
...rest
|
||||
}: Omit<MyHTMLTextareaAttributes, 'value' | 'class' | 'style'> & {
|
||||
value?: unknown;
|
||||
class?: string;
|
||||
style?: string;
|
||||
height?: string | number;
|
||||
autoHeight?: boolean;
|
||||
rows?: number;
|
||||
maxHeight?: string | number;
|
||||
onHeightChange?: (height: string) => void;
|
||||
} = $props();
|
||||
|
||||
let textareaEl: HTMLTextAreaElement;
|
||||
let defaultHeight: number;
|
||||
@@ -69,6 +82,7 @@
|
||||
bind:this={textareaEl}
|
||||
spellcheck="false"
|
||||
{...rest}
|
||||
{style}
|
||||
oninput={(e)=>{
|
||||
adjustHeight();
|
||||
rest.oninput?.(e);
|
||||
@@ -77,5 +91,5 @@
|
||||
adjustHeight();
|
||||
rest.onchange?.(e);
|
||||
}}
|
||||
class="tf-textarea nodrag nowheel {rest.class}"
|
||||
>{value || ""}</textarea>
|
||||
class="tf-textarea nodrag nowheel {className}"
|
||||
>{String(value ?? '')}</textarea>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<svelte:options customElement={{ props: {} }} />
|
||||
|
||||
<script lang="ts">
|
||||
import {onMount} from 'svelte';
|
||||
import {Compartment, EditorState, type Transaction} from '@codemirror/state';
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
});
|
||||
triggerObject?.hide();
|
||||
};
|
||||
let selectItems = useRefOptions(useChildrenOnly);
|
||||
let selectItems = useRefOptions(() => useChildrenOnly === true);
|
||||
|
||||
|
||||
</script>
|
||||
@@ -175,4 +175,3 @@
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
@@ -275,13 +275,6 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.input-item-inline {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
color: var(--tf-text-secondary);
|
||||
}
|
||||
|
||||
.input-more-setting {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
import {useCopyNode} from '../utils/useCopyNode.svelte';
|
||||
import {getOptions} from '../utils/NodeUtils';
|
||||
import {getCurrentNodeId} from '#components/utils/NodeUtils';
|
||||
import type {TinyflowNodeData} from '#types';
|
||||
|
||||
const {
|
||||
data,
|
||||
@@ -32,7 +33,7 @@
|
||||
wrapperClass = '',
|
||||
onCollapse
|
||||
}: {
|
||||
data: NodeProps['data'],
|
||||
data: TinyflowNodeData,
|
||||
id?: NodeProps['id'],
|
||||
icon?: Snippet,
|
||||
handle?: Snippet,
|
||||
@@ -49,7 +50,7 @@
|
||||
onCollapse?: (key: string) => void,
|
||||
} = $props();
|
||||
|
||||
let activeKeys = data.expand ? ['key'] : [];
|
||||
const activeKeys = $derived.by(() => data.expand ? ['key'] : []);
|
||||
const { updateNodeData, getNode } = useSvelteFlow();
|
||||
const updateNodeInternals = useUpdateNodeInternals();
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<svelte:options customElement={{ props: {} }} />
|
||||
|
||||
<script lang="ts">
|
||||
import {defaultKeymap, history, historyKeymap} from '@codemirror/commands';
|
||||
import {Compartment, EditorState, type Extension} from '@codemirror/state';
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
});
|
||||
triggerObject?.hide();
|
||||
};
|
||||
let selectItems = useRefOptions(useChildrenOnly);
|
||||
let selectItems = useRefOptions(() => useChildrenOnly === true);
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<svelte:options customElement={{ props: {} }} />
|
||||
|
||||
<script lang="ts">
|
||||
import NodeWrapper from '../core/NodeWrapper.svelte';
|
||||
import {type NodeProps, useNodesData, useSvelteFlow} from '@xyflow/svelte';
|
||||
@@ -7,11 +9,11 @@
|
||||
import {useAddParameter} from '../utils/useAddParameter.svelte';
|
||||
import OutputDefList from '../core/OutputDefList.svelte';
|
||||
import {onMount} from 'svelte';
|
||||
import type {SelectItem} from '#types';
|
||||
import type {SelectItem, TinyflowNodeData} from '#types';
|
||||
import CodeScriptEditor from '../core/CodeScriptEditor.svelte';
|
||||
|
||||
const { data, ...rest }: {
|
||||
data: NodeProps['data'],
|
||||
data: TinyflowNodeData,
|
||||
[key: string]: any
|
||||
} = $props();
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<svelte:options customElement={{ props: {} }} />
|
||||
|
||||
<script lang="ts">
|
||||
import NodeWrapper from '../core/NodeWrapper.svelte';
|
||||
import {
|
||||
@@ -669,7 +671,20 @@
|
||||
style="flex: 1; height: 100%; min-width: 0;"
|
||||
/>
|
||||
{:else}
|
||||
<div class="condition-branch-name" style="padding-left: 8px" ondblclick={(e) => { e.stopPropagation(); editingBranchId = branch.id; }}>
|
||||
<div
|
||||
class="condition-branch-name"
|
||||
style="padding-left: 8px"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
ondblclick={(e) => { e.stopPropagation(); editingBranchId = branch.id; }}
|
||||
onkeydown={(e) => {
|
||||
e.stopPropagation();
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault();
|
||||
editingBranchId = branch.id;
|
||||
}
|
||||
}}
|
||||
>
|
||||
{branch.label || `条件分支${index + 1}`}
|
||||
</div>
|
||||
{/if}
|
||||
@@ -1181,26 +1196,6 @@
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.input-more-setting {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
padding: 10px;
|
||||
background: var(--tf-bg-surface);
|
||||
border: 1px solid var(--tf-border-color);
|
||||
border-radius: 6px;
|
||||
width: 180px;
|
||||
box-shadow: var(--tf-shadow-medium);
|
||||
|
||||
.input-more-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
font-size: 12px;
|
||||
color: var(--tf-text-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
.condition-expression-panel {
|
||||
min-height: 140px;
|
||||
display: flex;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<svelte:options customElement={{ props: {} }} />
|
||||
|
||||
<script lang="ts">
|
||||
import NodeWrapper from '../core/NodeWrapper.svelte';
|
||||
import {type NodeProps, useSvelteFlow} from '@xyflow/svelte';
|
||||
@@ -7,12 +9,12 @@
|
||||
import {useAddParameter} from '../utils/useAddParameter.svelte';
|
||||
import OutputDefList from '../core/OutputDefList.svelte';
|
||||
import ConfirmParameterList from '../core/ConfirmParameterList.svelte';
|
||||
import type {Parameter} from '#types';
|
||||
import type {Parameter, TinyflowNodeData} from '#types';
|
||||
import {deepEqual} from '#components/utils/deepEqual';
|
||||
|
||||
|
||||
const { data, ...rest }: {
|
||||
data: NodeProps['data'],
|
||||
data: TinyflowNodeData,
|
||||
[key: string]: any
|
||||
} = $props();
|
||||
|
||||
@@ -94,7 +96,7 @@
|
||||
message: e.target.value
|
||||
}
|
||||
})
|
||||
}} value={data.message as string||""} />
|
||||
}} value={String(data.message || '')} />
|
||||
</div>
|
||||
|
||||
|
||||
@@ -128,5 +130,3 @@
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<svelte:options customElement={{ props: {} }} />
|
||||
|
||||
<script lang="ts">
|
||||
import NodeWrapper from '../core/NodeWrapper.svelte';
|
||||
import {type Node, type NodeProps, useNodesData, useSvelteFlow} from '@xyflow/svelte';
|
||||
@@ -8,17 +10,24 @@
|
||||
import {getOptions} from '../utils/NodeUtils';
|
||||
import OutputDefList from '../core/OutputDefList.svelte';
|
||||
import ParamTokenEditor from '../core/ParamTokenEditor.svelte';
|
||||
import type {TinyflowNodeData} from '#types';
|
||||
import {onMount} from 'svelte';
|
||||
|
||||
const { data, ...rest }: {
|
||||
data: NodeProps['data'],
|
||||
const props = $props<{
|
||||
data: TinyflowNodeData,
|
||||
[key: string]: any
|
||||
} = $props();
|
||||
}>();
|
||||
const data = $derived(props.data);
|
||||
|
||||
const currentNodeId = getCurrentNodeId();
|
||||
let currentNode = useNodesData(currentNodeId);
|
||||
const { addParameter } = useAddParameter();
|
||||
const flowInstance = useSvelteFlow();
|
||||
const { updateNodeData: updateNodeDataInner } = flowInstance;
|
||||
const getRestProps = () => {
|
||||
const { data: _data, ...rest } = props;
|
||||
return rest;
|
||||
};
|
||||
const editorParameters = $derived.by(() => {
|
||||
return (currentNode?.current?.data?.parameters as Array<any>) || data.parameters || [];
|
||||
});
|
||||
@@ -49,19 +58,22 @@
|
||||
updateFormValue(form, (event.target as any)?.value);
|
||||
};
|
||||
|
||||
const node = {
|
||||
...rest,
|
||||
const buildNode = (nextData = data) => ({
|
||||
...getRestProps(),
|
||||
id: currentNodeId,
|
||||
data
|
||||
} as Node;
|
||||
data: nextData
|
||||
} as Node);
|
||||
|
||||
const externalElement = document.createElement('div') as HTMLElement;
|
||||
const options = getOptions();
|
||||
const customNode = options.customNodes![rest.type as string];
|
||||
customNode.render?.(externalElement, node, flowInstance);
|
||||
const forms = customNode.forms;
|
||||
const customNode = $derived.by(() => options.customNodes![getRestProps().type as string]);
|
||||
const forms = $derived.by(() => customNode.forms);
|
||||
|
||||
let container: HTMLElement;
|
||||
onMount(() => {
|
||||
customNode.render?.(externalElement, buildNode(), flowInstance);
|
||||
});
|
||||
|
||||
let container = $state<HTMLElement | null>(null);
|
||||
$effect(() => {
|
||||
// 注意:由于 $effect 的 state 自动追踪问题,需要 data.expand 方在 if 里的最前面
|
||||
if (data.expand && container) {
|
||||
@@ -71,7 +83,7 @@
|
||||
|
||||
$effect(() => {
|
||||
if (data) {
|
||||
customNode.onUpdate?.(externalElement, { ...node, data });
|
||||
customNode.onUpdate?.(externalElement, buildNode(data));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -94,7 +106,7 @@
|
||||
</script>
|
||||
|
||||
|
||||
<NodeWrapper data={{...data, description: customNode.description}} {...rest}>
|
||||
<NodeWrapper data={{...data, description: customNode.description}} {...getRestProps()}>
|
||||
|
||||
{#snippet icon()}
|
||||
{@html customNode.icon}
|
||||
@@ -285,6 +297,7 @@
|
||||
background: var(--tf-slider-track-bg);
|
||||
border-radius: 2px;
|
||||
outline: none;
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<svelte:options customElement={{ props: {} }} />
|
||||
|
||||
<script lang="ts">
|
||||
import NodeWrapper from '../core/NodeWrapper.svelte';
|
||||
import {type NodeProps} from '@xyflow/svelte';
|
||||
@@ -5,9 +7,10 @@
|
||||
import {getCurrentNodeId} from '#components/utils/NodeUtils';
|
||||
import RefParameterList from '../core/RefParameterList.svelte';
|
||||
import {useAddParameter} from '../utils/useAddParameter.svelte';
|
||||
import type {TinyflowNodeData} from '#types';
|
||||
|
||||
const { data, ...rest }: {
|
||||
data: NodeProps['data'],
|
||||
data: TinyflowNodeData,
|
||||
[key: string]: any
|
||||
} = $props();
|
||||
|
||||
@@ -46,5 +49,3 @@
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<svelte:options customElement={{ props: {} }} />
|
||||
|
||||
<script lang="ts">
|
||||
import NodeWrapper from '../core/NodeWrapper.svelte';
|
||||
import {type NodeProps, useNodesData, useSvelteFlow} from '@xyflow/svelte';
|
||||
@@ -10,9 +12,10 @@
|
||||
// 添加生命周期函数
|
||||
import {onMount} from 'svelte';
|
||||
import ParamTokenEditor from '../core/ParamTokenEditor.svelte';
|
||||
import type {TinyflowNodeData} from '#types';
|
||||
|
||||
const { data, ...rest }: {
|
||||
data: NodeProps['data'],
|
||||
data: TinyflowNodeData,
|
||||
[key: string]: any
|
||||
} = $props();
|
||||
|
||||
@@ -77,7 +80,7 @@
|
||||
return (currentNode?.current?.data?.parameters as Array<any>) || data.parameters || [];
|
||||
});
|
||||
const bodyMethods = new Set(['post', 'put', 'delete', 'patch']);
|
||||
const showBodyConfig = $derived(bodyMethods.has((data.method || '').toLowerCase()));
|
||||
const showBodyConfig = $derived(bodyMethods.has(String(data.method || '').toLowerCase()));
|
||||
</script>
|
||||
|
||||
|
||||
@@ -215,7 +218,7 @@
|
||||
rows={5}
|
||||
style="width: 100%"
|
||||
parameters={editorParameters}
|
||||
placeholder="请输入 json 信息" value={data.bodyJson}
|
||||
placeholder="请输入 json 信息" value={String(data.bodyJson || '')}
|
||||
oninput={(e:any)=>{
|
||||
updateNodeData(currentNodeId,{
|
||||
bodyJson: e.target.value,
|
||||
@@ -233,7 +236,7 @@
|
||||
rows={5}
|
||||
style="width: 100%"
|
||||
parameters={editorParameters}
|
||||
placeholder="请输入请求信息" value={data.bodyRaw}
|
||||
placeholder="请输入请求信息" value={String(data.bodyRaw || '')}
|
||||
oninput={(e:any)=>{
|
||||
updateNodeData(currentNodeId,{
|
||||
bodyRaw: e.target.value,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<svelte:options customElement={{ props: {} }} />
|
||||
|
||||
<script lang="ts">
|
||||
import NodeWrapper from '../core/NodeWrapper.svelte';
|
||||
import {type NodeProps, useNodesData, useStore, useSvelteFlow} from '@xyflow/svelte';
|
||||
@@ -7,7 +9,7 @@
|
||||
import {getOptions} from '../utils/NodeUtils';
|
||||
import {onMount} from 'svelte';
|
||||
import OutputDefList from '../core/OutputDefList.svelte';
|
||||
import type {Parameter, SelectItem} from '#types';
|
||||
import type {Parameter, SelectItem, TinyflowNodeData} from '#types';
|
||||
import ParamTokenEditor from '../core/ParamTokenEditor.svelte';
|
||||
import {
|
||||
buildEditorReferenceParameters,
|
||||
@@ -17,7 +19,7 @@
|
||||
} from '../../utils/workflowNodeFields';
|
||||
|
||||
const { data, ...rest }: {
|
||||
data: NodeProps['data'],
|
||||
data: TinyflowNodeData,
|
||||
[key: string]: any
|
||||
} = $props();
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<svelte:options customElement={{ props: {} }} />
|
||||
|
||||
<script lang="ts">
|
||||
import NodeWrapper from '../core/NodeWrapper.svelte';
|
||||
import {type NodeProps, useNodesData, useStore, useSvelteFlow} from '@xyflow/svelte';
|
||||
@@ -177,16 +179,6 @@
|
||||
}
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
const validIds = new Set(queryContextOptions.map((item) => String(item.value)));
|
||||
const normalized = queryContextNodeIds.filter((item) => validIds.has(item));
|
||||
if (normalized.length !== queryContextNodeIds.length) {
|
||||
updateNodeData(currentNodeId, {
|
||||
queryContextNodeIds: normalized
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const toggleQueryContextNode = (nodeId: string) => {
|
||||
const currentIds = [...queryContextNodeIds];
|
||||
const exists = currentIds.includes(nodeId);
|
||||
@@ -404,6 +396,7 @@
|
||||
background: var(--tf-slider-track-bg);
|
||||
border-radius: 2px;
|
||||
outline: none;
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<svelte:options customElement={{ props: {} }} />
|
||||
|
||||
<script lang="ts">
|
||||
import NodeWrapper from '../core/NodeWrapper.svelte';
|
||||
import {Handle, type NodeProps, Position} from '@xyflow/svelte';
|
||||
@@ -5,9 +7,10 @@
|
||||
import RefParameterList from '../core/RefParameterList.svelte';
|
||||
import {getCurrentNodeId} from '#components/utils/NodeUtils';
|
||||
import {useAddParameter} from '../utils/useAddParameter.svelte';
|
||||
import type {TinyflowNodeData} from '#types';
|
||||
|
||||
const { data, ...rest }: {
|
||||
data: NodeProps['data'],
|
||||
data: TinyflowNodeData,
|
||||
[key: string]: any
|
||||
} = $props();
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<svelte:options customElement={{ props: {} }} />
|
||||
|
||||
<script lang="ts">
|
||||
import NodeWrapper from '../core/NodeWrapper.svelte';
|
||||
import {type NodeProps, useNodesData, useSvelteFlow} from '@xyflow/svelte';
|
||||
@@ -8,11 +10,11 @@
|
||||
import {getOptions} from '../utils/NodeUtils';
|
||||
import {onMount} from 'svelte';
|
||||
import OutputDefList from '../core/OutputDefList.svelte';
|
||||
import type {SelectItem} from '#types';
|
||||
import type {SelectItem, TinyflowNodeData} from '#types';
|
||||
import ParamTokenEditor from '../core/ParamTokenEditor.svelte';
|
||||
|
||||
const { data, ...rest }: {
|
||||
data: NodeProps['data'],
|
||||
data: TinyflowNodeData,
|
||||
[key: string]: any
|
||||
} = $props();
|
||||
|
||||
@@ -109,9 +111,9 @@
|
||||
placeholder="请输入关键字"
|
||||
style="width: 100%"
|
||||
parameters={editorParameters}
|
||||
value={data.keyword || ''}
|
||||
oninput={(e)=>{
|
||||
const newValue = e.target.value;
|
||||
value={String(data.keyword || '')}
|
||||
oninput={(e: Event)=>{
|
||||
const newValue = (e.target as HTMLInputElement).value;
|
||||
updateNodeData(currentNodeId, ()=>{
|
||||
return {
|
||||
keyword: newValue
|
||||
@@ -127,10 +129,10 @@
|
||||
mode="input"
|
||||
placeholder="搜索的数据条数"
|
||||
style="width: 100%"
|
||||
value={data.limit || ''}
|
||||
value={String(data.limit || '')}
|
||||
parameters={editorParameters}
|
||||
oninput={(e)=>{
|
||||
const newValue = e.target.value;
|
||||
oninput={(e: Event)=>{
|
||||
const newValue = (e.target as HTMLInputElement).value;
|
||||
updateNodeData(currentNodeId, ()=>{
|
||||
return {
|
||||
limit: newValue
|
||||
@@ -170,4 +172,3 @@
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<svelte:options customElement={{ props: {} }} />
|
||||
|
||||
<script lang="ts">
|
||||
import NodeWrapper from '../core/NodeWrapper.svelte';
|
||||
import {Heading, Input, Textarea} from '../base';
|
||||
@@ -12,9 +14,10 @@
|
||||
normalizeStartNodeData,
|
||||
normalizeStartFormMeta,
|
||||
} from '../../utils/workflowNodeFields';
|
||||
import type {TinyflowNodeData} from '#types';
|
||||
|
||||
const { data, ...rest }: {
|
||||
data: NodeProps['data'],
|
||||
data: TinyflowNodeData,
|
||||
[key: string]: any
|
||||
} = $props();
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<svelte:options customElement={{ props: {} }} />
|
||||
|
||||
<script lang="ts">
|
||||
import NodeWrapper from '../core/NodeWrapper.svelte';
|
||||
import {type NodeProps, useSvelteFlow} from '@xyflow/svelte';
|
||||
@@ -7,9 +9,10 @@
|
||||
import {getCurrentNodeId} from '#components/utils/NodeUtils';
|
||||
import {useAddParameter} from '../utils/useAddParameter.svelte';
|
||||
import OutputDefList from '../core/OutputDefList.svelte';
|
||||
import type {TinyflowNodeData} from '#types';
|
||||
|
||||
const { data, ...rest }: {
|
||||
data: NodeProps['data'],
|
||||
data: TinyflowNodeData,
|
||||
[key: string]: any
|
||||
} = $props();
|
||||
|
||||
@@ -62,7 +65,7 @@
|
||||
template: e.target.value
|
||||
}
|
||||
})
|
||||
}} value={data.template ||""} />
|
||||
}} value={String(data.template || '')} />
|
||||
</div>
|
||||
|
||||
|
||||
@@ -89,5 +92,3 @@
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -144,10 +144,16 @@ const nodeToOptions = (
|
||||
}
|
||||
};
|
||||
|
||||
export const useRefOptions: any = (useChildrenOnly: boolean = false) => {
|
||||
export const useRefOptions: any = (
|
||||
useChildrenOnly: boolean | (() => boolean) = false,
|
||||
) => {
|
||||
const currentNodeId = getCurrentNodeId();
|
||||
const currentNode = useNodesData(currentNodeId);
|
||||
const { nodes, edges, nodeLookup } = $derived(useStore());
|
||||
const isChildrenOnly = () =>
|
||||
typeof useChildrenOnly === 'function'
|
||||
? useChildrenOnly()
|
||||
: useChildrenOnly;
|
||||
|
||||
let selectItems = $derived.by(() => {
|
||||
const resultOptions = [];
|
||||
@@ -158,7 +164,7 @@ export const useRefOptions: any = (useChildrenOnly: boolean = false) => {
|
||||
//通过 nodeLookup.get 才会得到有 parentId 的 node
|
||||
const cNode = nodeLookup.get(currentNodeId)!;
|
||||
|
||||
if (useChildrenOnly) {
|
||||
if (isChildrenOnly()) {
|
||||
for (const node of nodes) {
|
||||
const nodeIsChildren = node.parentId === currentNode.current.id;
|
||||
if (nodeIsChildren) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import type { Node, useSvelteFlow } from '@xyflow/svelte';
|
||||
export type TinyflowData = Partial<
|
||||
ReturnType<ReturnType<typeof useSvelteFlow>['toObject']>
|
||||
>;
|
||||
export type TinyflowNodeData = Record<string, any>;
|
||||
export type TinyflowTheme = 'light' | 'dark';
|
||||
|
||||
export type SelectItem = {
|
||||
|
||||
@@ -897,7 +897,10 @@ describe('workflow node fields', () => {
|
||||
expect(normalizedWorkflow.nodes[0]?.data?.parameters?.[0]?.required).toBe(
|
||||
true,
|
||||
);
|
||||
expect(normalizedWorkflow.nodes[0]?.data?.startFormSchema?.[0]?.key).toBe(
|
||||
expect(
|
||||
(normalizedWorkflow.nodes[0]?.data as Record<string, any> | undefined)
|
||||
?.startFormSchema?.[0]?.key,
|
||||
).toBe(
|
||||
'user_input',
|
||||
);
|
||||
expect(normalizedWorkflow.nodes[1]?.data?.parameters).toEqual([]);
|
||||
|
||||
@@ -1237,7 +1237,10 @@ function replaceStartFieldReferenceValue(
|
||||
return value;
|
||||
}
|
||||
|
||||
function collectDownstreamNodeIds(rootNodeId: string, edges: Edge[]) {
|
||||
export function collectDownstreamNodeIds(
|
||||
rootNodeId: string,
|
||||
edges: Edge[],
|
||||
) {
|
||||
const nodeIds = new Set<string>();
|
||||
|
||||
const visit = (nodeId: string) => {
|
||||
@@ -1281,7 +1284,7 @@ export function renameStartFieldReferencesInNodes(
|
||||
const oldRefPath = `${normalizedStartNodeId}.${normalizedCurrentKey}`;
|
||||
const newRefPath = `${normalizedStartNodeId}.${normalizedNextKey}`;
|
||||
|
||||
const nextNodes = nodes.map((node) => {
|
||||
const nextNodes: Node[] = nodes.map((node) => {
|
||||
if (node.id === normalizedStartNodeId) {
|
||||
return node;
|
||||
}
|
||||
@@ -1295,7 +1298,7 @@ export function renameStartFieldReferencesInNodes(
|
||||
}
|
||||
return {
|
||||
...node,
|
||||
data: nextData,
|
||||
data: nextData ?? {},
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user