chore: make eslint happy
📊 Benchmark the Runtime / benchmark (pull_request) Successful in 1m6s
🚀 Lint & Test & Deploy / quality (pull_request) Failing after 1m7s
🚀 Lint & Test & Deploy / test-unit (pull_request) Successful in 31s
🚀 Lint & Test & Deploy / test-e2e (pull_request) Failing after 32s
🚀 Lint & Test & Deploy / deploy (pull_request) Has been skipped
📊 Benchmark the Runtime / benchmark (pull_request) Successful in 1m6s
🚀 Lint & Test & Deploy / quality (pull_request) Failing after 1m7s
🚀 Lint & Test & Deploy / test-unit (pull_request) Successful in 31s
🚀 Lint & Test & Deploy / test-e2e (pull_request) Failing after 32s
🚀 Lint & Test & Deploy / deploy (pull_request) Has been skipped
This commit is contained in:
+1
-1
@@ -7,7 +7,7 @@
|
||||
"dev": "vite dev",
|
||||
"predev": "rm static/CHANGELOG.md && ln -s ../../CHANGELOG.md static/CHANGELOG.md",
|
||||
"build": "svelte-kit sync && vite build",
|
||||
"test:unit": "vitest",
|
||||
"test:unit": "vitest --browser=false",
|
||||
"test": "npm run test:unit -- --run && npm run test:e2e",
|
||||
"test:e2e": "playwright test",
|
||||
"preview": "vite preview",
|
||||
|
||||
@@ -19,12 +19,12 @@ import EventEmitter from './helpers/EventEmitter';
|
||||
import { HistoryManager } from './history-manager';
|
||||
|
||||
const logger = createLogger('graph-manager');
|
||||
// logger.mute();
|
||||
logger.mute();
|
||||
|
||||
const remoteRegistry = new RemoteNodeRegistry('');
|
||||
|
||||
const clone = 'structuredClone' in self
|
||||
? self.structuredClone
|
||||
const clone = 'structuredClone' in globalThis
|
||||
? globalThis.structuredClone
|
||||
: (args: unknown) => JSON.parse(JSON.stringify(args));
|
||||
|
||||
function areSocketsCompatible(
|
||||
@@ -104,7 +104,7 @@ export class GraphManager extends EventEmitter<{
|
||||
|
||||
history: HistoryManager = new HistoryManager();
|
||||
|
||||
private serializeFullGraph(): Graph {
|
||||
public serializeFullGraph(): Graph {
|
||||
if (this.graphStack.length === 0) return this.serialize();
|
||||
let merged = this.serialize();
|
||||
for (let i = this.graphStack.length - 1; i >= 0; i--) {
|
||||
@@ -538,7 +538,7 @@ export class GraphManager extends EventEmitter<{
|
||||
const inputs = {
|
||||
'groupId': {
|
||||
type: 'select',
|
||||
label: '',
|
||||
label: 'Group',
|
||||
value: node.props?.groupId,
|
||||
internal: true,
|
||||
options: this.graph.groups.map((g, i) => ({
|
||||
@@ -551,6 +551,10 @@ export class GraphManager extends EventEmitter<{
|
||||
|
||||
const groupType = {
|
||||
...node.state.type,
|
||||
meta: {
|
||||
title: 'Group',
|
||||
...node?.state?.type?.meta || {}
|
||||
},
|
||||
inputs,
|
||||
outputs: groupDefinition?.outputs?.map(o => o.type)
|
||||
} as NodeDefinition;
|
||||
@@ -620,7 +624,6 @@ export class GraphManager extends EventEmitter<{
|
||||
}
|
||||
|
||||
removeNode(node: NodeInstance, { restoreEdges = false } = {}) {
|
||||
console.log('REMOVING NODE', $state.snapshot({ node }));
|
||||
const edgesToNode = this.edges.filter((edge) => edge[2].id === node.id);
|
||||
const edgesFromNode = this.edges.filter((edge) => edge[0].id === node.id);
|
||||
for (const edge of [...edgesToNode, ...edgesFromNode]) {
|
||||
@@ -686,7 +689,7 @@ export class GraphManager extends EventEmitter<{
|
||||
|
||||
this.graphStack.push({
|
||||
rootGraph: this.serialize(),
|
||||
savedNodes: new Map(this.nodes),
|
||||
savedNodes: new SvelteMap(this.nodes),
|
||||
savedEdges: [...this.edges],
|
||||
outerGraph: this.graph,
|
||||
groupId,
|
||||
@@ -743,8 +746,6 @@ export class GraphManager extends EventEmitter<{
|
||||
...this.graph.groups.flatMap(g => g.nodes.map(n => n.id))
|
||||
];
|
||||
|
||||
console.log('CREATE NODE ID', ids);
|
||||
|
||||
let id = 0;
|
||||
while (ids.includes(id)) {
|
||||
id++;
|
||||
@@ -796,7 +797,7 @@ export class GraphManager extends EventEmitter<{
|
||||
}
|
||||
|
||||
removeUnusedGroups() {
|
||||
const usedGroups = new Set(this.getAllNodes().map(n => n.props?.groupId));
|
||||
const usedGroups = new SvelteSet(this.getAllNodes().map(n => n.props?.groupId));
|
||||
const unusedGroupAmount = this.graph.groups.length - usedGroups.size;
|
||||
this.graph.groups = this.graph.groups.filter(g => usedGroups.has(g.id));
|
||||
this.save();
|
||||
@@ -808,14 +809,14 @@ export class GraphManager extends EventEmitter<{
|
||||
this.removeUnusedGroups();
|
||||
|
||||
const nodes = [
|
||||
...new Set(nodeIds).values().map(id => this.getNode(id)).filter(Boolean)
|
||||
...new SvelteSet(nodeIds).values().map(id => this.getNode(id)).filter(Boolean)
|
||||
] as NodeInstance[];
|
||||
|
||||
if (!nodes.length) return;
|
||||
|
||||
logger.log(`Grouping ${nodes.length} nodes`, { nodes });
|
||||
|
||||
const ids = new Set(nodes.map(n => n.id));
|
||||
const ids = new SvelteSet(nodes.map(n => n.id));
|
||||
|
||||
// We use the map to dedupe when one external node is connected to multiple internal nodes
|
||||
// ┌──internal_a
|
||||
@@ -823,14 +824,14 @@ export class GraphManager extends EventEmitter<{
|
||||
// └──internal_b
|
||||
// This should only result in one group input not two
|
||||
const incomingEdges = this.edges.filter((edge) => ids.has(edge[2].id) && !ids.has(edge[0].id));
|
||||
const groupInputs = new Map<string, Edge>();
|
||||
const groupInputs = new SvelteMap<string, Edge>();
|
||||
for (const edge of incomingEdges) {
|
||||
groupInputs.set(`${edge[0].id}-${edge[1]}`, edge);
|
||||
}
|
||||
|
||||
// And the same for the outputs
|
||||
const outgoingEdges = this.edges.filter((edge) => ids.has(edge[0].id) && !ids.has(edge[2].id));
|
||||
const groupOutputs = new Map<string, Edge>();
|
||||
const groupOutputs = new SvelteMap<string, Edge>();
|
||||
for (const edge of outgoingEdges) {
|
||||
groupOutputs.set(`${edge[2].id}-${edge[3]}`, edge);
|
||||
}
|
||||
@@ -864,11 +865,11 @@ export class GraphManager extends EventEmitter<{
|
||||
|
||||
// Map from deduped edge source key → group input index, used for both
|
||||
// internal edge wiring and external edge socket naming.
|
||||
const inputIndexByEdgeKey = new Map<string, number>();
|
||||
const inputIndexByEdgeKey = new SvelteMap<string, number>();
|
||||
[...groupInputs.keys()].forEach((key, i) => inputIndexByEdgeKey.set(key, i));
|
||||
|
||||
// Allocate all needed IDs up front so sequential calls never collide.
|
||||
const usedIds = new Set<number>([
|
||||
const usedIds = new SvelteSet<number>([
|
||||
...this.nodes.keys(),
|
||||
...this.graph.groups.map(g => g.id),
|
||||
...this.graph.groups.flatMap(g => g.nodes.map(n => n.id))
|
||||
@@ -949,7 +950,6 @@ export class GraphManager extends EventEmitter<{
|
||||
this.removeNode(node);
|
||||
}
|
||||
|
||||
console.log('FINISHED', this.serialize());
|
||||
this.saveUndoGroup();
|
||||
|
||||
return groupNode;
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import { assert, beforeEach, describe, expect, it } from 'vitest';
|
||||
import { assert, describe, expect, it } from 'vitest';
|
||||
import { GraphManager } from './graph-manager.svelte';
|
||||
import { GraphState } from './graph-state.svelte';
|
||||
import {
|
||||
createMockNodeRegistry,
|
||||
mockFloatInputNode,
|
||||
mockFloatOutputNode
|
||||
} from './test-utils';
|
||||
import { createMockNodeRegistry, mockFloatInputNode, mockFloatOutputNode } from './test-utils';
|
||||
|
||||
// GraphState constructor reads localStorage synchronously — mock before any instantiation
|
||||
Object.defineProperty(globalThis, 'localStorage', {
|
||||
|
||||
@@ -136,6 +136,12 @@
|
||||
/>
|
||||
<label for="drop-zone"></label>
|
||||
|
||||
{#if graph.isInsideGroup}
|
||||
<button class="exit-group" onclick={() => graphState.exitGroupNode()}>
|
||||
↑ Exit Group
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
<Canvas shadows={false} renderMode="on-demand" colorManagementEnabled={false}>
|
||||
<Camera
|
||||
bind:camera={graphState.camera}
|
||||
@@ -169,14 +175,6 @@
|
||||
{/if}
|
||||
|
||||
{#if graph.status === 'idle'}
|
||||
{#if graph.isInsideGroup}
|
||||
<HTML transform={false}>
|
||||
<button class="exit-group" onclick={() => graphState.exitGroupNode()}>
|
||||
↑ Exit Group
|
||||
</button>
|
||||
</HTML>
|
||||
{/if}
|
||||
|
||||
{#if graphState.addMenuPosition}
|
||||
<AddMenu
|
||||
onnode={handleNodeCreation}
|
||||
@@ -252,11 +250,10 @@
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
:global(.exit-group) {
|
||||
position: fixed;
|
||||
.exit-group {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
left: 12px;
|
||||
z-index: 1000;
|
||||
padding: 4px 12px;
|
||||
background: var(--color-layer-2);
|
||||
@@ -268,7 +265,7 @@
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
:global(.exit-group:hover) {
|
||||
.exit-group:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { createKeyMap } from '$lib/helpers/createKeyMap';
|
||||
import type { Graph, NodeInstance, NodeRegistry } from '@nodarium/types';
|
||||
import { onMount } from 'svelte';
|
||||
import { GraphManager } from '../graph-manager.svelte';
|
||||
import { GraphState, setGraphManager, setGraphState } from '../graph-state.svelte';
|
||||
import { setupKeymaps } from '../keymaps';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { NodeDefinition, NodeInstance } from '@nodarium/types';
|
||||
import type { NodeDefinition } from '@nodarium/types';
|
||||
|
||||
export function getParameterHeight(node: NodeDefinition, inputKey: string) {
|
||||
const input = node.inputs?.[inputKey];
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
{#if appSettings.value.debug.advancedMode}
|
||||
<span class="bg-white text-black! mr-2 px-1 rounded-sm opacity-30">{node.id}</span>
|
||||
{/if}
|
||||
{node.type.split('/').pop()}
|
||||
{nodeType?.meta?.title || node.type?.split('/').pop()}
|
||||
</div>
|
||||
<div
|
||||
class="target"
|
||||
|
||||
@@ -6,11 +6,22 @@ import type {
|
||||
RuntimeExecutor,
|
||||
SyncCache
|
||||
} from '@nodarium/types';
|
||||
import {
|
||||
concatEncodedArrays,
|
||||
createLogger,
|
||||
encodeFloat,
|
||||
fastHashArrayBuffer,
|
||||
type PerformanceStore
|
||||
} from '@nodarium/utils';
|
||||
import type { RuntimeNode } from './types';
|
||||
|
||||
const log = createLogger('runtime-executor');
|
||||
log.mute();
|
||||
|
||||
export function expandGroups(graph: Graph): Graph {
|
||||
if (!graph.groups || graph.groups.length === 0) return graph;
|
||||
|
||||
let nodes = [...graph.nodes];
|
||||
const nodes = [...graph.nodes];
|
||||
let edges = [...graph.edges];
|
||||
|
||||
let changed = true;
|
||||
@@ -87,17 +98,6 @@ export function expandGroups(graph: Graph): Graph {
|
||||
|
||||
return { ...graph, nodes, edges };
|
||||
}
|
||||
import {
|
||||
concatEncodedArrays,
|
||||
createLogger,
|
||||
encodeFloat,
|
||||
fastHashArrayBuffer,
|
||||
type PerformanceStore
|
||||
} from '@nodarium/utils';
|
||||
import type { RuntimeNode } from './types';
|
||||
|
||||
const log = createLogger('runtime-executor');
|
||||
log.mute();
|
||||
|
||||
function getValue(input: NodeInput, value?: unknown) {
|
||||
if (value === undefined && 'value' in input) {
|
||||
@@ -160,7 +160,7 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor {
|
||||
const nonVirtualTypes = graph.nodes
|
||||
.map(node => node.type)
|
||||
.filter(t => !t.startsWith('__internal/'));
|
||||
await this.registry.load(nonVirtualTypes as any);
|
||||
await this.registry.load(nonVirtualTypes);
|
||||
|
||||
const typeMap = new Map<string, NodeDefinition>();
|
||||
for (const node of graph.nodes) {
|
||||
|
||||
@@ -15,10 +15,7 @@
|
||||
isGroupInstance ? manager.getGroup(node!.props?.groupId as number) : undefined
|
||||
);
|
||||
|
||||
let groupName = $state('');
|
||||
$effect(() => {
|
||||
groupName = activeGroup?.name ?? '';
|
||||
});
|
||||
const groupName = $derived(activeGroup?.name ?? '');
|
||||
|
||||
function handleRename(e: Event) {
|
||||
const name = (e.target as HTMLInputElement).value;
|
||||
|
||||
@@ -321,7 +321,7 @@
|
||||
hidden={!appSettings.value.debug.advancedMode}
|
||||
icon="i-[tabler--code]"
|
||||
>
|
||||
<GraphSource graph={manager?.serialize()} />
|
||||
<GraphSource graph={manager?.serializeFullGraph()} />
|
||||
</Panel>
|
||||
<Panel
|
||||
id="benchmark"
|
||||
|
||||
Reference in New Issue
Block a user