diff --git a/resolver/src/serdes/deserialize.ts b/resolver/src/serdes/deserialize.ts index bc45358b0..46eb26123 100644 --- a/resolver/src/serdes/deserialize.ts +++ b/resolver/src/serdes/deserialize.ts @@ -1,4 +1,9 @@ -import { FlydeFlow, flydeFlowSchema } from "@flyde/core"; +import { + FlydeFlow, + NodeInstance, + flydeFlowSchema, + isRefNodeInstance, +} from "@flyde/core"; import * as yaml from "yaml"; import _ = require("lodash"); import { readFileSync } from "fs"; @@ -11,6 +16,56 @@ require("ts-node").register({ // } }); +const macroMigrationsMap = { + "GET Request": { + id: "Http", + data: { + method: { mode: "static", value: "GET" }, + url: { mode: "dynamic" }, + headers: { mode: "static", value: {} }, + params: { mode: "static", value: {} }, + }, + }, + "POST Request": { + id: "Http", + data: { + method: { mode: "static", value: "POST" }, + data: { mode: "dynamic" }, + url: { mode: "dynamic" }, + headers: { mode: "static", value: {} }, + params: { mode: "static", value: {} }, + }, + }, + Debounce: { + id: "Debounce", + data: { + mode: "static", + timeMs: 1000, + }, + }, + Delay: { + id: "Delay", + data: { + type: "static", + timeMs: 1000, + }, + }, + Throttle: { + id: "Throttle", + data: { + type: "static", + timeMs: 1000, + }, + }, + Interval: { + id: "Interval", + data: { + type: "static", + timeMs: 1000, + }, + }, +}; + export function deserializeFlow(flowContents: string, path: string): FlydeFlow { const unsafeflow = yaml.parse(flowContents); @@ -27,6 +82,23 @@ export function deserializeFlow(flowContents: string, path: string): FlydeFlow { data.imports = imports; + // migrate old stdlib nodes + for (const ins of data.node?.instances) { + if (isRefNodeInstance(ins as NodeInstance) && !ins.macroId) { + const migration = macroMigrationsMap[ins.nodeId]; + if (macroMigrationsMap[ins.nodeId]) { + ins.macroId = migration.id; + ins.macroData = migration.data; + + const stdlibImports = (data.imports["@flyde/stdlib"] as string[]) ?? []; + if (!stdlibImports.includes(migration.id)) { + stdlibImports.push(migration.id); + data.imports["@flyde/stdlib"] = stdlibImports; + } + } + } + } + if (!data.node.inputsPosition) { data.node.inputsPosition = {}; } diff --git a/stdlib/package.json b/stdlib/package.json index 63359696f..72fbdc8e6 100644 --- a/stdlib/package.json +++ b/stdlib/package.json @@ -51,9 +51,9 @@ "dev": "pnpm run watch", "bundle": "webpack --config webpack.config.js", "bundle:watch": "webpack --config webpack.config.js --watch", - "build": "tsc -p . && pnpm run bundle && pnpm run build:docs-data", + "build": "rm -rf dist && tsc -p . && pnpm run bundle && pnpm run build:docs-data", "build:docs-data": "ts-node scripts/docs-data.ts", "prod": "node dist/index.js", "__publish": "npm version patch && npm publish" } -} +} \ No newline at end of file diff --git a/stdlib/src/ControlFlow/ControlFlow.flyde.ts b/stdlib/src/ControlFlow/ControlFlow.flyde.ts index b853fe9c0..f2b97b91b 100644 --- a/stdlib/src/ControlFlow/ControlFlow.flyde.ts +++ b/stdlib/src/ControlFlow/ControlFlow.flyde.ts @@ -52,6 +52,8 @@ export const RoundRobin: MacroNode = { displayName: `Round Robin ${count}`, description: `Item will be emitted to one of the ${count} outputs in a round robin fashion`, inputs: { value: { mode: "required", description: "The value to emit" } }, + completionOutputs: [], + reactiveInputs: ["value"], outputs: Array.from({ length: count }).reduce( (obj, _, i) => ({ ...obj, @@ -81,8 +83,8 @@ export const RoundRobin: MacroNode = { const nextCurr = (curr + 1) % count; - o.next(inputs.item); state.set("curr", nextCurr); + o.next(inputs.item); }; }, editorComponentBundlePath: "../../../dist/ui/RoundRobin.js", diff --git a/stdlib/src/Http/Http.flyde.ts b/stdlib/src/Http/Http.flyde.ts index c0cf0251e..0e43ab4bb 100644 --- a/stdlib/src/Http/Http.flyde.ts +++ b/stdlib/src/Http/Http.flyde.ts @@ -11,15 +11,13 @@ export interface HttpConfig { } | { mode: "dynamic" }; url: { mode: "static"; value: string } | { mode: "dynamic" }; - headers?: + headers: | { mode: "static"; value: Record } | { mode: "dynamic" }; - params?: - | { mode: "static"; value: Record } - | { mode: "dynamic" }; - data?: + params: | { mode: "static"; value: Record } | { mode: "dynamic" }; + data: { mode: "static"; value: Record } | { mode: "dynamic" }; } export const Http: MacroNode = { @@ -45,7 +43,7 @@ export const Http: MacroNode = { }; return axios .request({ url: urlValue, data: dataValue, ...requestConfig }) - .then((res) => outputs.data.next(res.data)) + .then((res) => outputs.data!.next(res.data)) .catch((e) => adv.onError(e)); }; }, diff --git a/stdlib/src/Http/HttpConfigEditor.tsx b/stdlib/src/Http/HttpConfigEditor.tsx index 50f6136ab..0d428bb7f 100644 --- a/stdlib/src/Http/HttpConfigEditor.tsx +++ b/stdlib/src/Http/HttpConfigEditor.tsx @@ -40,7 +40,7 @@ const HttpConfigEditor: MacroEditorComp = function HttpConfigEditor( - {value.data.mode === "static" && ( + {value.data?.mode === "static" && ( = function HttpConfigEditor( {value.headers.mode === "static" && ( onChange({ ...value, headers: { mode: "static", value: data } }) } diff --git a/stdlib/tsconfig.json b/stdlib/tsconfig.json index b9866c22a..dd1f74c27 100644 --- a/stdlib/tsconfig.json +++ b/stdlib/tsconfig.json @@ -1,8 +1,7 @@ { "extends": "../tsconfig.json", "compilerOptions": { - "outDir": "dist", - "noFallthroughCasesInSwitch": true + "outDir": "dist" }, "include": ["src/**/*.ts", "src/**/*.tsx"], "exclude": ["node_modules", "dist"] diff --git a/website/src/pages/_hero-example/ExampleDebounceThrottle.flyde b/website/src/pages/_hero-example/ExampleDebounceThrottle.flyde index 79dec36b7..e956c03b4 100644 --- a/website/src/pages/_hero-example/ExampleDebounceThrottle.flyde +++ b/website/src/pages/_hero-example/ExampleDebounceThrottle.flyde @@ -7,29 +7,38 @@ imports: node: instances: - pos: - x: -777.6441479492187 - y: -230.75769625127003 + x: -783.4504223632812 + y: -226.9698239368169 id: wj31gd73i5l111q999pv4kor inputConfig: wait: mode: static value: 4200 visibleOutputs: - - result + - throttledValue - __error - nodeId: Throttle + nodeId: Throttle__wj31gd73i5l111q999pv4kor + macroId: Throttle + macroData: + type: static + timeMs: 1000 - pos: x: -960.8631420898437 - y: -227.77420626103566 + y: -226.77420626103566 id: eaa2b80mmdusjvxi3fve0du1 inputConfig: wait: mode: static value: 4200 - nodeId: Debounce + nodeId: Debounce__eaa2b80mmdusjvxi3fve0du1 + macroId: Debounce + macroData: + mode: static + timeMs: 1000 + type: static - pos: - x: -1007.762890625 - y: -141.30592895507812 + x: -997.7967041015625 + y: -133.89296508789062 id: "Inline-value-Debounce: ${in-qj1486n" inputConfig: {} node: @@ -83,8 +92,8 @@ node: size: small icon: fa-list - pos: - x: -764.763251953125 - y: -141.78481811523437 + x: -777.236396484375 + y: -122.0756201171875 id: ApisCombination-7b048r2 inputConfig: {} node: @@ -120,12 +129,6 @@ node: to: insId: __this pinId: output - - from: - insId: wj31gd73i5l111q999pv4kor - pinId: result - to: - insId: __this - pinId: output - from: insId: dimxqnz6n9uhawffzb6urp0y pinId: list @@ -144,24 +147,24 @@ node: to: insId: wj31gd73i5l111q999pv4kor pinId: value + - from: + insId: ApisCombination-7b048r2 + pinId: value + to: + insId: __this + pinId: output - from: insId: eaa2b80mmdusjvxi3fve0du1 - pinId: result + pinId: debouncedValue to: insId: "Inline-value-Debounce: ${in-qj1486n" pinId: __trigger - from: insId: wj31gd73i5l111q999pv4kor - pinId: __error + pinId: throttledValue to: insId: ApisCombination-7b048r2 pinId: __trigger - - from: - insId: ApisCombination-7b048r2 - pinId: value - to: - insId: __this - pinId: output id: ApisCombination inputs: {} outputs: @@ -176,7 +179,7 @@ node: Bob: x: -464.39225613814307 y: -267.86263932413937 - ? "גכעכגע" + ? "גכעכגע" : x: -879.2823974609375 y: -510.9079638671875 outputsPosition: @@ -198,6 +201,6 @@ node: Bob 42: x: -736.217912287027 y: 209.40813992513762 - ? "גככג" + ? "גככג" : x: -589.98 y: -561 diff --git a/website/src/pages/_hero-example/ExampleHTTPRequests.flyde b/website/src/pages/_hero-example/ExampleHTTPRequests.flyde index 0d7a76128..9567c0afa 100644 --- a/website/src/pages/_hero-example/ExampleHTTPRequests.flyde +++ b/website/src/pages/_hero-example/ExampleHTTPRequests.flyde @@ -1,8 +1,7 @@ imports: "@flyde/stdlib": - - GET Request - - POST Request - Get Attribute + - Http node: instances: - pos: @@ -19,7 +18,20 @@ node: visibleOutputs: - data - __error - nodeId: GET Request + nodeId: Http__GET Request-907 + macroId: Http + macroData: + method: + mode: static + value: GET + url: + mode: dynamic + headers: + mode: static + value: {} + params: + mode: static + value: {} style: size: regular icon: fa-server @@ -67,12 +79,25 @@ node: mode: static value: https://countriesnow.space/api/v0.1/countries/capital visibleInputs: - - url - - headers - - params - data + - url - __trigger - nodeId: POST Request + nodeId: Http__POST Request-624 + macroId: Http + macroData: + method: + mode: static + value: POST + data: + mode: dynamic + url: + mode: dynamic + headers: + mode: static + value: {} + params: + mode: static + value: {} style: size: regular icon: fa-server diff --git a/website/src/pages/_hero-example/ExampleHelloWorld.flyde b/website/src/pages/_hero-example/ExampleHelloWorld.flyde index 57e8390ec..499591dd7 100644 --- a/website/src/pages/_hero-example/ExampleHelloWorld.flyde +++ b/website/src/pages/_hero-example/ExampleHelloWorld.flyde @@ -5,14 +5,18 @@ imports: node: instances: - pos: - x: -745.6308628148531 - y: -164.62084499951794 + x: -743.4960971898531 + y: -180.6268874799867 id: hvnxp46iusf1g91k6dua576w inputConfig: delay: mode: static value: 4200 - nodeId: Delay + nodeId: Delay__hvnxp46iusf1g91k6dua576w + macroId: Delay + macroData: + type: static + timeMs: 1000 style: size: small icon: fa-clock @@ -50,8 +54,8 @@ node: fontFamily: monospace fontWeight: "500" - pos: - x: -769.3590283203125 - y: -276.35265625 + x: -781.0328564453125 + y: -277.4243420410156 id: ApisCombination-4z1481x inputConfig: {} node: @@ -136,7 +140,7 @@ node: Bob: x: -464.39225613814307 y: -267.86263932413937 - "גכעכגע": + "גכעכגע": x: -879.2823974609375 y: -510.9079638671875 outputsPosition: @@ -158,6 +162,6 @@ node: Bob 42: x: -736.217912287027 y: 209.40813992513762 - "גככג": + "גככג": x: -589.98 y: -561 diff --git a/website/src/pages/_hero-example/ExampleReactivity.flyde b/website/src/pages/_hero-example/ExampleReactivity.flyde index 6970b51fa..b0004bdbe 100644 --- a/website/src/pages/_hero-example/ExampleReactivity.flyde +++ b/website/src/pages/_hero-example/ExampleReactivity.flyde @@ -7,8 +7,8 @@ imports: node: instances: - pos: - x: -628.0026402763253 - y: -420.65284818026043 + x: -670.4256749442941 + y: -418.16716092440106 id: ghunnjxvc8lzz9ir1n7a5cv9 inputConfig: interval: @@ -18,8 +18,13 @@ node: mode: static value: "" visibleInputs: - - interval - nodeId: Interval + - value + - __trigger + nodeId: Interval__ghunnjxvc8lzz9ir1n7a5cv9 + macroId: Interval + macroData: + type: static + timeMs: 1000 - pos: x: -621.8109288505441 y: -147.24308865877606 diff --git a/website/src/pages/playground/_OutputLogs/OutputJsx.tsx b/website/src/pages/playground/_OutputLogs/OutputJsx.tsx deleted file mode 100644 index abacab0e0..000000000 --- a/website/src/pages/playground/_OutputLogs/OutputJsx.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { DynamicOutput } from "@site/../core/dist"; -import * as React from "react"; - -import "./OutputLogs.scss"; - -export interface OutputLogsProps { - element: JSX.Element; -} - -export const OutputJsx: React.FC = (props) => { - return ( -
-
Output JSX
-
{props.element}
-
- ); -}; diff --git a/website/src/pages/playground/_OutputLogs/OutputLogs.scss b/website/src/pages/playground/_OutputLogs/OutputLogs.scss deleted file mode 100644 index 53624209c..000000000 --- a/website/src/pages/playground/_OutputLogs/OutputLogs.scss +++ /dev/null @@ -1,100 +0,0 @@ -.output-log, -.output-jsx { - background: #fafafa; - flex: 1; - display: flex; - flex-direction: column; - - header { - display: flex; - padding: 5px 20px; - font-size: 18px; - font-weight: 600; - // background: #003d60; - color: #202020; - border-bottom: 1px solid #dfdfdf; - margin-bottom: 2px; - - .clear-btn { - margin-left: auto; - } - } - - > main { - overflow: auto; - - li { - margin: 0; - padding: 0; - } - - ul { - list-style: none; - padding: 0; - margin: 0; - } - } - - .empty-state { - padding: 10px 20px; - font-size: 16px; - font-weight: 300; - color: #9e9e9e; - } - - .log-item { - padding: 3px 20px; - display: flex; - align-items: center; - // padding: 3px 0px; - - &:hover { - background-color: #efefef; - } - - > main { - flex: 1; - // text-overflow: ellipsis; - // overflow: hidden; - // white-space: nowrap; - margin-right: 5px; - - display: -webkit-box; - -webkit-box-orient: vertical; - -webkit-line-clamp: 3; - overflow: hidden; - } - - > aside { - font-size: 12px; - font-weight: 600; - color: #9e9e9e; - // flex: 0; - } - } - } - - .output-jsx { - - > main { - padding: 20px; - - - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - - button { - font-size: 30px; - } - - span { - font-size: 40px; - margin: 0 20px; - min-width: 50px; - text-align: center; - display: inline-block; - } - } - } \ No newline at end of file diff --git a/website/src/pages/playground/_OutputLogs/OutputLogs.tsx b/website/src/pages/playground/_OutputLogs/OutputLogs.tsx deleted file mode 100644 index c0cb951f1..000000000 --- a/website/src/pages/playground/_OutputLogs/OutputLogs.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { DynamicOutput } from "@site/../core/dist"; -import * as React from "react"; - -import "./OutputLogs.scss"; - -export interface OutputLogsProps { - output: DynamicOutput; -} - -export type LogItemProps = { - value: string | JSX.Element; - time: number; -}; - -export const LogItem: React.FC = (props) => { - return ( -
  • -
    {props.value}
    - -
  • - ); -}; - -export const OutputLogs: React.FC = (props) => { - const [log, setLog] = React.useState([]); - - React.useEffect(() => { - props.output.subscribe((rawValue) => { - const value = - typeof rawValue === "object" && React.isValidElement(rawValue) - ? rawValue - : `${rawValue}`; - setLog((logs) => [...logs, { value, time: Date.now() }]); - }); - }, []); - - return ( -
    -
    - Output Log{" "} - -
    -
    -
      - {log.map((o, i) => ( - - ))} -
    - {log.length === 0 ? ( -
    - Nothing to show. Interact with the example to emit some outputs! -
    - ) : null} -
    -
    - ); -}; diff --git a/website/src/pages/playground/_PlaygroundTemplate/PlaygroundTemplate.scss b/website/src/pages/playground/_PlaygroundTemplate/PlaygroundTemplate.scss deleted file mode 100644 index cac2f235d..000000000 --- a/website/src/pages/playground/_PlaygroundTemplate/PlaygroundTemplate.scss +++ /dev/null @@ -1,165 +0,0 @@ -@at-root .bp3-overlay { - z-index: 201; -} - -.examples__menu { - display: flex; - list-style: none; - margin-top: 20px; - justify-content: center; - flex-wrap: wrap; - gap: 10px; - - > li { - font-size: 18px; - font-weight: 700; - - a { - color: white; - } - - // &:not(:last-of-type) { - // // content: "•"; - // margin: 0 10px; - // } - } -} - -.playground-container { - padding: 2rem 0; - position: relative; - max-width: 1200px; - margin: 0 auto; - - - hr { - margin: 5px; - } - - .handle { - top: 0; - width: 3px; - height: 100%; - background: #aeaeae; - position: absolute; - cursor: col-resize; - flex-shrink: 0; - flex-grow: 0; - left: 0; - bottom: 0; - transition: opacity 0.05s linear; - - &:after { - display: block; - content: ""; - background-color: #cecece; - position: absolute; - height: 80%; - width: 1px; - left: 1px; - top: 10%; - } - } - - .playground-extra { - margin-bottom: 10px; - padding: 1rem; - font-size: 1.25rem; - } - - h2 { - font-size: 2rem; - } - - .playground-description { - font-size: 1.25rem; - margin-bottom: 10px; - padding: 1rem; - - } - - .emit-btn { - margin: 10px 5px; - } - - > header { - max-width: var(--ifm-container-width); - margin: 0 auto; - text-align: center; - } - - .playground { - display: flex; - flex-direction: row; - margin: 10px 0px; - border: 1px solid rgb(204, 204, 204); - max-height: 500px; - - .flow-container { - flex: 1; - border-right: rgb(204, 204, 204) 1px solid; - position: relative; - - - .delay-container { - background: #ffffff; - border: 1px solid #dedede; - position: absolute; - top: 0px; - right: 20px; - z-index: 1; - padding: 5px 10px; - display: flex; - align-items: center; - gap: 20px; - align-content: space-between; - font-size: 14px; - } - } - - } - - .output-container { - flex: 0 0; - display: flex; - position: relative; - user-select: none; - } - - -} - - -.playground-hero { - padding: 0.5rem 0; - - h1 { - font-size: 2rem; - } - - .hero__subtitle { - font-size: 1.25rem; - margin-bottom: 5px; - } -} - -.mobile-warning { - padding: 15px 10px; - // yellowish background - background: #fff3cd; - text-align: center; -} - -.star-hint { - - font-style: italic; - - display: inline-flex; - align-items: center; - flex-wrap: wrap; - gap: 0.1rem 0.5rem; - - .star-wrapper { - display: inline-flex; - } -} \ No newline at end of file diff --git a/website/src/pages/playground/_PlaygroundTemplate/PlaygroundTemplate.tsx b/website/src/pages/playground/_PlaygroundTemplate/PlaygroundTemplate.tsx deleted file mode 100644 index a5715cf93..000000000 --- a/website/src/pages/playground/_PlaygroundTemplate/PlaygroundTemplate.tsx +++ /dev/null @@ -1,249 +0,0 @@ -import React, { Fragment, useCallback, useState } from "react"; -import Layout from "@theme/Layout"; -import clsx from "clsx"; -import { RuntimePlayer } from "@flyde/flow-editor"; -import Link from "@docusaurus/Link"; -import { - DynamicNodeInput, - FlydeFlow, - NodeInputs, - NodeOutput, - ResolvedDependencies, - ResolvedFlydeRuntimeFlow, -} from "@flyde/core"; -import { createHistoryPlayer } from "../../../components/EmbeddedFlyde/createHistoryPlayer"; -import styles from "../../index.module.css"; - -import "./PlaygroundTemplate.scss"; -import "@flyde/flow-editor/src/index.scss"; - -import { Resizable } from "react-resizable"; -import { EmbeddedFlyde } from "@site/src/components/EmbeddedFlyde/EmbeddedFlyde"; - -const historyPlayer = createHistoryPlayer(); - -const EXAMPLES_LIST = [ - { - title: "Hello World", - key: "hello-world", - }, - { - title: "React Counter", - key: "react-counter", - }, - { - title: "BMI Calculator", - key: "bmi", - }, - { - title: "REST API Usage", - key: "apis", - }, - { - title: "Debounce vs. Throttling", - key: "debounce-throttling", - }, - { - title: "Fibonacci Seq.", - key: "fibonacci", - }, -]; - -export interface PlaygroundTemplateProps { - meta: { - title: string; - key: string; - description: string; - extraInfo?: string | JSX.Element; - }; - flowProps: { - inputs: Record; - flow: FlydeFlow; - dependencies: ResolvedDependencies; - output: NodeOutput; - }; - prefixComponent?: JSX.Element; - extraInfo?: string; - defaultDelay?: number; - hideDelay?: boolean; - initWidth?: number; -} - -export type PlaygroundFlowDto = { - flow: ResolvedFlydeRuntimeFlow; - output: NodeOutput; - inputs: NodeInputs; - onError: any; - debugDelay?: number; - player: RuntimePlayer; -}; - -export const PlaygroundTemplate: React.FC = ( - props -) => { - const [childrenWidth, setChildrenWidth] = useState(props.initWidth || 500); - - const [debugDelay, setDebugDelay] = useState(props.defaultDelay || 0); - - const [outputReceived, setOutputReceived] = useState(false); - - const onResizeChildren = useCallback((_, { size }) => { - setChildrenWidth(size.width); - - // setFlowEditorState((state) => { - // const container = document.querySelector(".flow-container"); // yack - // const vpSize = container - // ? container.getBoundingClientRect() - // : { width: 500, height: 500 }; - // return produce(state, (draft) => { - // draft.boardData.viewPort = fitViewPortToNode( - // draft.flow.node as any, - // resolvedFlow.dependencies, - // vpSize - // ); - // }); - // }); - }, []); - - const debugDelayElem = ( -
    - setDebugDelay(Number(e.target.value))} - /> - -
    - ); - - const exampleIdx = EXAMPLES_LIST.findIndex((ex) => ex.key === props.meta.key); - const nextExample = EXAMPLES_LIST[exampleIdx + 1]; - const prevExample = EXAMPLES_LIST[exampleIdx - 1]; - - return ( - -
    -
    -

    Welcome to Flyde's Online Playground

    -

    - Choose one of the examples below to get started. Feel free to play - around with the canvas and see how your changes affect the result! -

    -
    -
    - -
    - Flyde is currently not optimized for mobile devices. Please{" "} - use a desktop computer for the best experience. -
    - -
      - {EXAMPLES_LIST.map((ex) => { - return ( -
    • - - {ex.title} - -
    • - ); - })} -
    - -
    -
    -

    {props.meta.title}

    -
    {props.meta.description}
    - {outputReceived ? ( - -
    -
    - {props.extraInfo || props.meta.extraInfo} -
    -   PS: Did you like this example? - Please consider giving a ⭐️ to the project{" "} - -