@octaviaflow/core 3.1.0-beta.67 → 3.1.0-beta.68
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-JMSZOWT2.js +2616 -0
- package/dist/chunk-JMSZOWT2.js.map +1 -0
- package/dist/chunk-KZP2MNBO.js +2516 -0
- package/dist/chunk-KZP2MNBO.js.map +1 -0
- package/dist/chunk-S4LE4BFQ.js +5934 -0
- package/dist/chunk-S4LE4BFQ.js.map +1 -0
- package/dist/chunk-X7YETDK7.js +107 -0
- package/dist/chunk-X7YETDK7.js.map +1 -0
- package/dist/components/WorkflowShowcase/ShowcaseScene.d.ts +20 -0
- package/dist/components/WorkflowShowcase/ShowcaseScene.d.ts.map +1 -0
- package/dist/components/WorkflowShowcase/ShowcaseSignup.d.ts +14 -0
- package/dist/components/WorkflowShowcase/ShowcaseSignup.d.ts.map +1 -0
- package/dist/components/WorkflowShowcase/WorkflowShowcase.d.ts +48 -0
- package/dist/components/WorkflowShowcase/WorkflowShowcase.d.ts.map +1 -0
- package/dist/components/WorkflowShowcase/index.d.ts +3 -0
- package/dist/components/WorkflowShowcase/index.d.ts.map +1 -0
- package/dist/components/WorkflowShowcase/showcaseEngine.d.ts +102 -0
- package/dist/components/WorkflowShowcase/showcaseEngine.d.ts.map +1 -0
- package/dist/index.js +7854 -13331
- package/dist/index.js.map +1 -1
- package/dist/marketing/components/AssistantTranscript/AssistantTranscript.d.ts +15 -0
- package/dist/marketing/components/AssistantTranscript/AssistantTranscript.d.ts.map +1 -0
- package/dist/marketing/components/CtaBanner/CtaBanner.d.ts +16 -0
- package/dist/marketing/components/CtaBanner/CtaBanner.d.ts.map +1 -0
- package/dist/marketing/components/FeatureGrid/FeatureGrid.d.ts +15 -0
- package/dist/marketing/components/FeatureGrid/FeatureGrid.d.ts.map +1 -0
- package/dist/marketing/components/IntegrationsWall/IntegrationsWall.d.ts +19 -0
- package/dist/marketing/components/IntegrationsWall/IntegrationsWall.d.ts.map +1 -0
- package/dist/marketing/components/LiveConsole/LiveConsole.d.ts +21 -0
- package/dist/marketing/components/LiveConsole/LiveConsole.d.ts.map +1 -0
- package/dist/marketing/components/MarketingFooter/MarketingFooter.d.ts +25 -0
- package/dist/marketing/components/MarketingFooter/MarketingFooter.d.ts.map +1 -0
- package/dist/marketing/components/MarketingHero/MarketingHero.d.ts +11 -0
- package/dist/marketing/components/MarketingHero/MarketingHero.d.ts.map +1 -0
- package/dist/marketing/components/MarketingNav/MarketingNav.d.ts +17 -0
- package/dist/marketing/components/MarketingNav/MarketingNav.d.ts.map +1 -0
- package/dist/marketing/components/MarketingSection/MarketingSection.d.ts +15 -0
- package/dist/marketing/components/MarketingSection/MarketingSection.d.ts.map +1 -0
- package/dist/marketing/components/StatBand/StatBand.d.ts +16 -0
- package/dist/marketing/components/StatBand/StatBand.d.ts.map +1 -0
- package/dist/marketing/components/WorkflowShowcase/ShowcaseScene.d.ts +20 -0
- package/dist/marketing/components/WorkflowShowcase/ShowcaseScene.d.ts.map +1 -0
- package/dist/marketing/components/WorkflowShowcase/ShowcaseSignup.d.ts +14 -0
- package/dist/marketing/components/WorkflowShowcase/ShowcaseSignup.d.ts.map +1 -0
- package/dist/marketing/components/WorkflowShowcase/WorkflowShowcase.d.ts +48 -0
- package/dist/marketing/components/WorkflowShowcase/WorkflowShowcase.d.ts.map +1 -0
- package/dist/marketing/components/WorkflowShowcase/index.d.ts +3 -0
- package/dist/marketing/components/WorkflowShowcase/index.d.ts.map +1 -0
- package/dist/marketing/components/WorkflowShowcase/showcaseEngine.d.ts +102 -0
- package/dist/marketing/components/WorkflowShowcase/showcaseEngine.d.ts.map +1 -0
- package/dist/marketing/glyphs.d.ts +20 -0
- package/dist/marketing/glyphs.d.ts.map +1 -0
- package/dist/marketing/index.d.ts +13 -0
- package/dist/marketing/index.d.ts.map +1 -0
- package/dist/marketing.cjs +3985 -0
- package/dist/marketing.cjs.map +1 -0
- package/dist/marketing.js +1669 -0
- package/dist/marketing.js.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/workflow/components/HttpActionPanel/HttpActionPanel.d.ts +29 -0
- package/dist/workflow/components/HttpActionPanel/HttpActionPanel.d.ts.map +1 -0
- package/dist/workflow/components/HttpActionPanel/httpActionTypes.d.ts +135 -0
- package/dist/workflow/components/HttpActionPanel/httpActionTypes.d.ts.map +1 -0
- package/dist/workflow/index.d.ts +2 -0
- package/dist/workflow/index.d.ts.map +1 -1
- package/dist/workflow.cjs +6922 -271
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.js +1587 -56
- package/dist/workflow.js.map +1 -1
- package/package.json +6 -1
package/dist/workflow.js
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
|
+
Accordion,
|
|
2
3
|
ActionNode,
|
|
4
|
+
Badge,
|
|
5
|
+
Banner,
|
|
6
|
+
CodeEditor,
|
|
7
|
+
Combobox,
|
|
3
8
|
ConditionNode,
|
|
4
9
|
DEFAULT_NODE_HEIGHT,
|
|
5
10
|
DEFAULT_NODE_KINDS,
|
|
6
11
|
DEFAULT_NODE_WIDTH,
|
|
12
|
+
Disclosure,
|
|
7
13
|
ErrorNode,
|
|
8
14
|
FlowCanvas,
|
|
9
15
|
FlowEdge,
|
|
@@ -12,10 +18,18 @@ import {
|
|
|
12
18
|
GroupNode,
|
|
13
19
|
Handle,
|
|
14
20
|
HttpRequestNode,
|
|
21
|
+
JsonViewer,
|
|
22
|
+
KeyValueEditor,
|
|
15
23
|
NodeResizer,
|
|
24
|
+
NumberInput,
|
|
16
25
|
OutputNode,
|
|
17
26
|
ParallelNode,
|
|
27
|
+
PasswordInput,
|
|
28
|
+
SegmentedControl,
|
|
29
|
+
Spinner,
|
|
18
30
|
StickyNode,
|
|
31
|
+
Switch,
|
|
32
|
+
Tabs,
|
|
19
33
|
TriggerNode,
|
|
20
34
|
WaitNode,
|
|
21
35
|
WebhookNode,
|
|
@@ -50,7 +64,12 @@ import {
|
|
|
50
64
|
useSelection,
|
|
51
65
|
useViewport,
|
|
52
66
|
useViewportOrNull
|
|
53
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-S4LE4BFQ.js";
|
|
68
|
+
import {
|
|
69
|
+
Button,
|
|
70
|
+
Input,
|
|
71
|
+
Select
|
|
72
|
+
} from "./chunk-KZP2MNBO.js";
|
|
54
73
|
import {
|
|
55
74
|
cn
|
|
56
75
|
} from "./chunk-ZAUUGK2Y.js";
|
|
@@ -620,11 +639,1510 @@ function ConfigPanel({
|
|
|
620
639
|
);
|
|
621
640
|
}
|
|
622
641
|
|
|
642
|
+
// src/workflow/components/HttpActionPanel/HttpActionPanel.tsx
|
|
643
|
+
import {
|
|
644
|
+
CheckmarkIcon,
|
|
645
|
+
CodeIcon,
|
|
646
|
+
CopyIcon,
|
|
647
|
+
DataViewAltIcon,
|
|
648
|
+
GlobeIcon,
|
|
649
|
+
ListIcon,
|
|
650
|
+
LockedIcon,
|
|
651
|
+
PlayIcon,
|
|
652
|
+
RenewIcon,
|
|
653
|
+
TagIcon
|
|
654
|
+
} from "@octaviaflow/icons";
|
|
655
|
+
import { useCallback as useCallback4, useId, useMemo as useMemo2, useRef as useRef4, useState as useState4 } from "react";
|
|
656
|
+
|
|
657
|
+
// src/workflow/components/HttpActionPanel/httpActionTypes.ts
|
|
658
|
+
var HTTP_METHODS = [
|
|
659
|
+
"GET",
|
|
660
|
+
"POST",
|
|
661
|
+
"PUT",
|
|
662
|
+
"PATCH",
|
|
663
|
+
"DELETE",
|
|
664
|
+
"HEAD",
|
|
665
|
+
"OPTIONS"
|
|
666
|
+
];
|
|
667
|
+
var HTTP_ACTION_DEFAULTS = {
|
|
668
|
+
apiType: "rest",
|
|
669
|
+
method: "GET",
|
|
670
|
+
url: "",
|
|
671
|
+
queryParams: [],
|
|
672
|
+
headers: [],
|
|
673
|
+
bodyType: "json",
|
|
674
|
+
formData: [],
|
|
675
|
+
graphqlQuery: "",
|
|
676
|
+
graphqlVariables: {},
|
|
677
|
+
auth: { type: "none" },
|
|
678
|
+
timeout: 3e4,
|
|
679
|
+
failOnError: true,
|
|
680
|
+
followRedirects: true,
|
|
681
|
+
retry: {
|
|
682
|
+
maxAttempts: 1,
|
|
683
|
+
retryOn: [429, 500, 502, 503, 504],
|
|
684
|
+
initialDelayMs: 1e3,
|
|
685
|
+
backoffFactor: 2,
|
|
686
|
+
maxDelayMs: 3e4
|
|
687
|
+
},
|
|
688
|
+
pagination: { type: "none" },
|
|
689
|
+
extract: {},
|
|
690
|
+
responseType: "json",
|
|
691
|
+
expectedContentTypes: []
|
|
692
|
+
};
|
|
693
|
+
function normalizeKeyValues(raw) {
|
|
694
|
+
if (Array.isArray(raw)) {
|
|
695
|
+
return raw.map((r) => ({
|
|
696
|
+
key: String(r.key ?? ""),
|
|
697
|
+
value: String(r.value ?? ""),
|
|
698
|
+
description: r.description,
|
|
699
|
+
enabled: r.enabled !== false
|
|
700
|
+
}));
|
|
701
|
+
}
|
|
702
|
+
if (raw && typeof raw === "object") {
|
|
703
|
+
return Object.entries(raw).map(([key, value]) => ({
|
|
704
|
+
key,
|
|
705
|
+
value: String(value),
|
|
706
|
+
enabled: true
|
|
707
|
+
}));
|
|
708
|
+
}
|
|
709
|
+
return [];
|
|
710
|
+
}
|
|
711
|
+
function normalizeAuth(raw) {
|
|
712
|
+
const r = raw ?? {};
|
|
713
|
+
const rawType = r.type ?? "none";
|
|
714
|
+
const type = rawType === "oauth2" ? "bearer" : rawType;
|
|
715
|
+
return {
|
|
716
|
+
type: ["none", "basic", "bearer", "apikey"].includes(type) ? type : "none",
|
|
717
|
+
username: r.username ?? "",
|
|
718
|
+
password: r.password ?? "",
|
|
719
|
+
token: r.token ?? r.accessToken ?? "",
|
|
720
|
+
apiKeyName: r.apiKeyName ?? "X-API-Key",
|
|
721
|
+
apiKeyValue: r.apiKeyValue ?? "",
|
|
722
|
+
apiKeyLocation: r.apiKeyLocation === "query" ? "query" : "header"
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
function effectiveUrl(baseUrl, url) {
|
|
726
|
+
const base = (baseUrl ?? "").trim();
|
|
727
|
+
if (!base) return url;
|
|
728
|
+
return `${base.replace(/\/$/, "")}/${url.replace(/^\//, "")}`;
|
|
729
|
+
}
|
|
730
|
+
function serializeKeyValues(rows) {
|
|
731
|
+
return rows.filter((r) => r.key || r.value).map((r) => ({
|
|
732
|
+
key: r.key,
|
|
733
|
+
value: r.value,
|
|
734
|
+
enabled: r.enabled !== false,
|
|
735
|
+
...r.description ? { description: r.description } : {}
|
|
736
|
+
}));
|
|
737
|
+
}
|
|
738
|
+
function validateHttpConfig(config) {
|
|
739
|
+
const errors = [];
|
|
740
|
+
const apiType = config.apiType ?? "rest";
|
|
741
|
+
if (apiType === "rest" && !config.method) errors.push("Method is required");
|
|
742
|
+
if (apiType === "graphql" && !String(config.graphqlQuery ?? "").trim()) {
|
|
743
|
+
errors.push("GraphQL query is required");
|
|
744
|
+
}
|
|
745
|
+
const hasConnection = Boolean(config.connectionId);
|
|
746
|
+
if (!config.url && !hasConnection) {
|
|
747
|
+
errors.push("URL is required");
|
|
748
|
+
} else if (config.url && !hasConnection && !config.baseUrl && !config.url.includes("{{")) {
|
|
749
|
+
try {
|
|
750
|
+
new URL(config.url);
|
|
751
|
+
} catch {
|
|
752
|
+
errors.push("Invalid URL format");
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
if (typeof config.timeout === "number" && config.timeout < 1e3) {
|
|
756
|
+
errors.push("Timeout must be at least 1000ms");
|
|
757
|
+
}
|
|
758
|
+
return { valid: errors.length === 0, errors };
|
|
759
|
+
}
|
|
760
|
+
function countGraphqlVariables(query) {
|
|
761
|
+
return new Set(query.match(/\$[A-Za-z_][A-Za-z0-9_]*/g) ?? []).size;
|
|
762
|
+
}
|
|
763
|
+
function shellTokens(input) {
|
|
764
|
+
const tokens = [];
|
|
765
|
+
const flat = input.replace(/\\\r?\n/g, " ");
|
|
766
|
+
const re = /'([^']*)'|"((?:[^"\\]|\\.)*)"|(\S+)/g;
|
|
767
|
+
let m = re.exec(flat);
|
|
768
|
+
while (m !== null) {
|
|
769
|
+
if (m[1] !== void 0) tokens.push(m[1]);
|
|
770
|
+
else if (m[2] !== void 0) tokens.push(m[2].replace(/\\(["\\])/g, "$1"));
|
|
771
|
+
else tokens.push(m[3]);
|
|
772
|
+
m = re.exec(flat);
|
|
773
|
+
}
|
|
774
|
+
return tokens;
|
|
775
|
+
}
|
|
776
|
+
function parseCurl(input) {
|
|
777
|
+
const tokens = shellTokens(input.trim());
|
|
778
|
+
if (!tokens.length || !/^curl$/i.test(tokens[0])) return null;
|
|
779
|
+
let method;
|
|
780
|
+
let url = "";
|
|
781
|
+
const headers = [];
|
|
782
|
+
const formData = [];
|
|
783
|
+
let bodyRaw;
|
|
784
|
+
let basicUser;
|
|
785
|
+
let followRedirects;
|
|
786
|
+
for (let i = 1; i < tokens.length; i++) {
|
|
787
|
+
const t = tokens[i];
|
|
788
|
+
const next = () => tokens[++i] ?? "";
|
|
789
|
+
if (t === "-X" || t === "--request") {
|
|
790
|
+
const m = next().toUpperCase();
|
|
791
|
+
if (HTTP_METHODS.includes(m)) method = m;
|
|
792
|
+
} else if (t === "-H" || t === "--header") {
|
|
793
|
+
const raw = next();
|
|
794
|
+
const idx = raw.indexOf(":");
|
|
795
|
+
if (idx > 0) {
|
|
796
|
+
headers.push({
|
|
797
|
+
key: raw.slice(0, idx).trim(),
|
|
798
|
+
value: raw.slice(idx + 1).trim(),
|
|
799
|
+
enabled: true
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
} else if (t === "-d" || t === "--data" || t === "--data-raw" || t === "--data-binary" || t === "--data-urlencode") {
|
|
803
|
+
bodyRaw = next();
|
|
804
|
+
} else if (t === "-F" || t === "--form") {
|
|
805
|
+
const raw = next();
|
|
806
|
+
const idx = raw.indexOf("=");
|
|
807
|
+
if (idx > 0) {
|
|
808
|
+
formData.push({ key: raw.slice(0, idx), value: raw.slice(idx + 1), enabled: true });
|
|
809
|
+
}
|
|
810
|
+
} else if (t === "-u" || t === "--user") {
|
|
811
|
+
basicUser = next();
|
|
812
|
+
} else if (t === "--url") {
|
|
813
|
+
url = next();
|
|
814
|
+
} else if (t === "-L" || t === "--location") {
|
|
815
|
+
followRedirects = true;
|
|
816
|
+
} else if (t.startsWith("-")) {
|
|
817
|
+
if ([
|
|
818
|
+
"-o",
|
|
819
|
+
"--output",
|
|
820
|
+
"-A",
|
|
821
|
+
"--user-agent",
|
|
822
|
+
"-e",
|
|
823
|
+
"--referer",
|
|
824
|
+
"-b",
|
|
825
|
+
"--cookie",
|
|
826
|
+
"--connect-timeout",
|
|
827
|
+
"-m",
|
|
828
|
+
"--max-time"
|
|
829
|
+
].includes(t)) {
|
|
830
|
+
next();
|
|
831
|
+
}
|
|
832
|
+
} else if (!url) {
|
|
833
|
+
url = t;
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
if (!url) return null;
|
|
837
|
+
const patch = { url, apiType: "rest" };
|
|
838
|
+
const qIdx = url.indexOf("?");
|
|
839
|
+
if (qIdx >= 0) {
|
|
840
|
+
const query = url.slice(qIdx + 1);
|
|
841
|
+
patch.url = url.slice(0, qIdx);
|
|
842
|
+
patch.queryParams = query.split("&").filter(Boolean).map((pair) => {
|
|
843
|
+
const eq = pair.indexOf("=");
|
|
844
|
+
const rawKey = eq >= 0 ? pair.slice(0, eq) : pair;
|
|
845
|
+
const rawValue = eq >= 0 ? pair.slice(eq + 1) : "";
|
|
846
|
+
const decode = (s) => {
|
|
847
|
+
try {
|
|
848
|
+
return decodeURIComponent(s.replace(/\+/g, "%20"));
|
|
849
|
+
} catch {
|
|
850
|
+
return s;
|
|
851
|
+
}
|
|
852
|
+
};
|
|
853
|
+
return { key: decode(rawKey), value: decode(rawValue), enabled: true };
|
|
854
|
+
});
|
|
855
|
+
}
|
|
856
|
+
const authHeaderIdx = headers.findIndex((h) => h.key.toLowerCase() === "authorization");
|
|
857
|
+
if (authHeaderIdx >= 0 && /^bearer\s+/i.test(headers[authHeaderIdx].value)) {
|
|
858
|
+
patch.auth = {
|
|
859
|
+
type: "bearer",
|
|
860
|
+
token: headers[authHeaderIdx].value.replace(/^bearer\s+/i, "")
|
|
861
|
+
};
|
|
862
|
+
headers.splice(authHeaderIdx, 1);
|
|
863
|
+
} else if (basicUser) {
|
|
864
|
+
const sep = basicUser.indexOf(":");
|
|
865
|
+
patch.auth = {
|
|
866
|
+
type: "basic",
|
|
867
|
+
username: sep >= 0 ? basicUser.slice(0, sep) : basicUser,
|
|
868
|
+
password: sep >= 0 ? basicUser.slice(sep + 1) : ""
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
if (headers.length) patch.headers = headers;
|
|
872
|
+
if (followRedirects !== void 0) patch.followRedirects = followRedirects;
|
|
873
|
+
if (formData.length) {
|
|
874
|
+
patch.bodyType = "form-data";
|
|
875
|
+
patch.formData = formData;
|
|
876
|
+
patch.method = method ?? "POST";
|
|
877
|
+
} else if (bodyRaw !== void 0) {
|
|
878
|
+
try {
|
|
879
|
+
patch.body = JSON.parse(bodyRaw);
|
|
880
|
+
patch.bodyType = "json";
|
|
881
|
+
} catch {
|
|
882
|
+
patch.body = bodyRaw;
|
|
883
|
+
patch.bodyType = "raw";
|
|
884
|
+
}
|
|
885
|
+
patch.method = method ?? "POST";
|
|
886
|
+
} else {
|
|
887
|
+
patch.method = method ?? "GET";
|
|
888
|
+
patch.bodyType = "none";
|
|
889
|
+
}
|
|
890
|
+
return patch;
|
|
891
|
+
}
|
|
892
|
+
function shellQuote(value) {
|
|
893
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
894
|
+
}
|
|
895
|
+
function buildCurl(config) {
|
|
896
|
+
const parts = ["curl"];
|
|
897
|
+
const method = config.apiType === "graphql" ? "POST" : config.method ?? "GET";
|
|
898
|
+
if (method !== "GET") parts.push(`-X ${method}`);
|
|
899
|
+
let url = effectiveUrl(config.baseUrl, config.url);
|
|
900
|
+
const params = normalizeKeyValues(config.queryParams).filter((p) => p.enabled !== false && p.key);
|
|
901
|
+
if (params.length) {
|
|
902
|
+
const qs = params.map((p) => `${encodeURIComponent(p.key)}=${encodeURIComponent(p.value)}`).join("&");
|
|
903
|
+
url += (url.includes("?") ? "&" : "?") + qs;
|
|
904
|
+
}
|
|
905
|
+
parts.push(shellQuote(url));
|
|
906
|
+
for (const h of normalizeKeyValues(config.headers).filter((h2) => h2.enabled !== false && h2.key)) {
|
|
907
|
+
parts.push(`-H ${shellQuote(`${h.key}: ${h.value}`)}`);
|
|
908
|
+
}
|
|
909
|
+
const auth = config.auth;
|
|
910
|
+
if (auth?.type === "bearer" && auth.token) {
|
|
911
|
+
parts.push(`-H ${shellQuote(`Authorization: Bearer ${auth.token}`)}`);
|
|
912
|
+
} else if (auth?.type === "basic" && auth.username) {
|
|
913
|
+
parts.push(`-u ${shellQuote(`${auth.username}:${auth.password ?? ""}`)}`);
|
|
914
|
+
} else if (auth?.type === "apikey" && auth.apiKeyName && auth.apiKeyValue) {
|
|
915
|
+
if ((auth.apiKeyLocation ?? "header") === "header") {
|
|
916
|
+
parts.push(`-H ${shellQuote(`${auth.apiKeyName}: ${auth.apiKeyValue}`)}`);
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
if (config.apiType === "graphql") {
|
|
920
|
+
const payload = JSON.stringify({
|
|
921
|
+
query: config.graphqlQuery ?? "",
|
|
922
|
+
variables: typeof config.graphqlVariables === "string" ? config.graphqlVariables : config.graphqlVariables ?? {}
|
|
923
|
+
});
|
|
924
|
+
parts.push(`-H ${shellQuote("Content-Type: application/json")}`);
|
|
925
|
+
parts.push(`-d ${shellQuote(payload)}`);
|
|
926
|
+
} else if (config.bodyType === "form-data") {
|
|
927
|
+
for (const f of normalizeKeyValues(config.formData).filter(
|
|
928
|
+
(f2) => f2.enabled !== false && f2.key
|
|
929
|
+
)) {
|
|
930
|
+
parts.push(`-F ${shellQuote(`${f.key}=${f.value}`)}`);
|
|
931
|
+
}
|
|
932
|
+
} else if (config.bodyType && config.bodyType !== "none" && config.body != null) {
|
|
933
|
+
const raw = typeof config.body === "string" ? config.body : JSON.stringify(config.body);
|
|
934
|
+
if (raw) {
|
|
935
|
+
if (config.bodyType === "json") {
|
|
936
|
+
parts.push(`-H ${shellQuote("Content-Type: application/json")}`);
|
|
937
|
+
}
|
|
938
|
+
parts.push(`-d ${shellQuote(raw)}`);
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
if (config.followRedirects !== false) parts.push("-L");
|
|
942
|
+
return parts.join(" ");
|
|
943
|
+
}
|
|
944
|
+
function inferJsonSchema(value, depth = 0) {
|
|
945
|
+
if (value === null || value === void 0) return { type: "null" };
|
|
946
|
+
if (Array.isArray(value)) {
|
|
947
|
+
if (!value.length || depth > 6) return { type: "array" };
|
|
948
|
+
return { type: "array", items: inferJsonSchema(value[0], depth + 1) };
|
|
949
|
+
}
|
|
950
|
+
if (typeof value === "object") {
|
|
951
|
+
if (depth > 6) return { type: "object" };
|
|
952
|
+
const properties = {};
|
|
953
|
+
for (const [k, v] of Object.entries(value)) {
|
|
954
|
+
properties[k] = inferJsonSchema(v, depth + 1);
|
|
955
|
+
}
|
|
956
|
+
return { type: "object", properties };
|
|
957
|
+
}
|
|
958
|
+
return { type: typeof value };
|
|
959
|
+
}
|
|
960
|
+
function countSchemaPaths(schema, depth = 0) {
|
|
961
|
+
if (!schema || typeof schema !== "object" || depth > 8) return 0;
|
|
962
|
+
const s = schema;
|
|
963
|
+
let count = 0;
|
|
964
|
+
if (s.type === "object" && s.properties) {
|
|
965
|
+
for (const child of Object.values(s.properties)) {
|
|
966
|
+
count += 1 + countSchemaPaths(child, depth + 1);
|
|
967
|
+
}
|
|
968
|
+
} else if (s.type === "array" && s.items) {
|
|
969
|
+
count += countSchemaPaths(s.items, depth + 1);
|
|
970
|
+
}
|
|
971
|
+
return count;
|
|
972
|
+
}
|
|
973
|
+
function statusTone(status) {
|
|
974
|
+
if (status < 300) return "success";
|
|
975
|
+
if (status < 400) return "info";
|
|
976
|
+
if (status < 500) return "warning";
|
|
977
|
+
return "error";
|
|
978
|
+
}
|
|
979
|
+
function formatBytes(size) {
|
|
980
|
+
return size < 1024 ? `${size} B` : `${(size / 1024).toFixed(1)} KB`;
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
// src/workflow/components/HttpActionPanel/HttpActionPanel.tsx
|
|
984
|
+
import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
985
|
+
function toPairs(rows) {
|
|
986
|
+
return rows.map((r) => ({
|
|
987
|
+
key: r.key,
|
|
988
|
+
value: r.value,
|
|
989
|
+
enabled: r.enabled !== false,
|
|
990
|
+
description: r.description
|
|
991
|
+
}));
|
|
992
|
+
}
|
|
993
|
+
function textOf(raw) {
|
|
994
|
+
if (typeof raw === "string") return raw;
|
|
995
|
+
if (raw == null) return "";
|
|
996
|
+
try {
|
|
997
|
+
return JSON.stringify(raw, null, 2);
|
|
998
|
+
} catch {
|
|
999
|
+
return "";
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
function HttpActionPanel({
|
|
1003
|
+
value,
|
|
1004
|
+
onChange,
|
|
1005
|
+
disabled = false,
|
|
1006
|
+
connections,
|
|
1007
|
+
connectionsLoading = false,
|
|
1008
|
+
onSendPreview,
|
|
1009
|
+
className
|
|
1010
|
+
}) {
|
|
1011
|
+
const uid = useId();
|
|
1012
|
+
const cfgRef = useRef4({
|
|
1013
|
+
...HTTP_ACTION_DEFAULTS,
|
|
1014
|
+
...value,
|
|
1015
|
+
queryParams: normalizeKeyValues(value?.queryParams),
|
|
1016
|
+
headers: normalizeKeyValues(value?.headers),
|
|
1017
|
+
formData: normalizeKeyValues(value?.formData),
|
|
1018
|
+
auth: normalizeAuth(value?.auth),
|
|
1019
|
+
retry: {
|
|
1020
|
+
...HTTP_ACTION_DEFAULTS.retry,
|
|
1021
|
+
...value?.retry
|
|
1022
|
+
},
|
|
1023
|
+
pagination: {
|
|
1024
|
+
...HTTP_ACTION_DEFAULTS.pagination,
|
|
1025
|
+
...value?.pagination
|
|
1026
|
+
}
|
|
1027
|
+
});
|
|
1028
|
+
const [, force] = useState4(0);
|
|
1029
|
+
const emit = useCallback4(
|
|
1030
|
+
(patch) => {
|
|
1031
|
+
cfgRef.current = { ...cfgRef.current, ...patch };
|
|
1032
|
+
force((n) => n + 1);
|
|
1033
|
+
onChange?.(cfgRef.current);
|
|
1034
|
+
},
|
|
1035
|
+
[onChange]
|
|
1036
|
+
);
|
|
1037
|
+
const cfg = cfgRef.current;
|
|
1038
|
+
const connectionId = cfg.connectionId ?? "";
|
|
1039
|
+
const selectedConnection = connections?.find((c) => c.id === connectionId) ?? null;
|
|
1040
|
+
const endpoints = selectedConnection?.endpoints ?? [];
|
|
1041
|
+
const method = cfg.method ?? "GET";
|
|
1042
|
+
const url = cfg.url ?? "";
|
|
1043
|
+
const baseUrl = cfg.baseUrl ?? "";
|
|
1044
|
+
const fullUrl = connectionId ? url : effectiveUrl(baseUrl, url);
|
|
1045
|
+
const queryParams = normalizeKeyValues(cfg.queryParams);
|
|
1046
|
+
const headers = normalizeKeyValues(cfg.headers);
|
|
1047
|
+
const formData = normalizeKeyValues(cfg.formData);
|
|
1048
|
+
const auth = normalizeAuth(cfg.auth);
|
|
1049
|
+
const retry = cfg.retry ?? HTTP_ACTION_DEFAULTS.retry;
|
|
1050
|
+
const pagination = cfg.pagination ?? { type: "none" };
|
|
1051
|
+
const responseType = cfg.responseType ?? "json";
|
|
1052
|
+
const [bodyText, setBodyText] = useState4(() => textOf(cfg.body));
|
|
1053
|
+
const [bodyError, setBodyError] = useState4();
|
|
1054
|
+
const [gqlVarsText, setGqlVarsText] = useState4(() => textOf(cfg.graphqlVariables));
|
|
1055
|
+
const [gqlVarsError, setGqlVarsError] = useState4();
|
|
1056
|
+
const [retryOnText, setRetryOnText] = useState4(() => (retry?.retryOn ?? []).join(", "));
|
|
1057
|
+
const [expectedCtText, setExpectedCtText] = useState4(
|
|
1058
|
+
() => (cfg.expectedContentTypes ?? []).join(", ")
|
|
1059
|
+
);
|
|
1060
|
+
const [urlError, setUrlError] = useState4();
|
|
1061
|
+
const [extractRows, setExtractRows] = useState4(
|
|
1062
|
+
() => Object.entries(cfg.extract ?? {}).map(([key, v]) => ({ key, value: v, enabled: true }))
|
|
1063
|
+
);
|
|
1064
|
+
const [curlOpen, setCurlOpen] = useState4(false);
|
|
1065
|
+
const [curlText, setCurlText] = useState4("");
|
|
1066
|
+
const [curlError, setCurlError] = useState4();
|
|
1067
|
+
const [copiedCurl, setCopiedCurl] = useState4(false);
|
|
1068
|
+
const [copiedResult, setCopiedResult] = useState4(false);
|
|
1069
|
+
const applyCurl = () => {
|
|
1070
|
+
const patch = parseCurl(curlText);
|
|
1071
|
+
if (!patch) {
|
|
1072
|
+
setCurlError(
|
|
1073
|
+
"That doesn't look like a cURL command \u2014 it should start with `curl` and include a URL."
|
|
1074
|
+
);
|
|
1075
|
+
return;
|
|
1076
|
+
}
|
|
1077
|
+
setCurlError(void 0);
|
|
1078
|
+
setCurlText("");
|
|
1079
|
+
setCurlOpen(false);
|
|
1080
|
+
setBodyText(textOf(patch.body));
|
|
1081
|
+
setBodyError(void 0);
|
|
1082
|
+
emit({ ...patch, connectionId: void 0, baseUrl: void 0 });
|
|
1083
|
+
};
|
|
1084
|
+
const copyCurl = async () => {
|
|
1085
|
+
try {
|
|
1086
|
+
await navigator.clipboard?.writeText(buildCurl(cfg));
|
|
1087
|
+
setCopiedCurl(true);
|
|
1088
|
+
setTimeout(() => setCopiedCurl(false), 1600);
|
|
1089
|
+
} catch {
|
|
1090
|
+
}
|
|
1091
|
+
};
|
|
1092
|
+
const copyResult = async () => {
|
|
1093
|
+
if (preview.phase !== "success") return;
|
|
1094
|
+
const r = preview.response;
|
|
1095
|
+
const bundle = {
|
|
1096
|
+
request: {
|
|
1097
|
+
method: cfg.apiType === "graphql" ? "POST" : method,
|
|
1098
|
+
url: connectionId ? `${selectedConnection?.name ?? connectionId} \xB7 ${url}` : fullUrl
|
|
1099
|
+
},
|
|
1100
|
+
response: {
|
|
1101
|
+
status: r.status,
|
|
1102
|
+
statusText: r.statusText,
|
|
1103
|
+
ok: r.ok,
|
|
1104
|
+
durationMs: r.duration,
|
|
1105
|
+
sizeBytes: r.size,
|
|
1106
|
+
headers: r.headers,
|
|
1107
|
+
body: r.body
|
|
1108
|
+
}
|
|
1109
|
+
};
|
|
1110
|
+
try {
|
|
1111
|
+
await navigator.clipboard?.writeText(JSON.stringify(bundle, null, 2));
|
|
1112
|
+
setCopiedResult(true);
|
|
1113
|
+
setTimeout(() => setCopiedResult(false), 1600);
|
|
1114
|
+
} catch {
|
|
1115
|
+
}
|
|
1116
|
+
};
|
|
1117
|
+
const validateUrl = (nextUrl, nextBase, hasConnection) => {
|
|
1118
|
+
if (!nextUrl && !nextBase && !hasConnection) {
|
|
1119
|
+
setUrlError("URL is required");
|
|
1120
|
+
return;
|
|
1121
|
+
}
|
|
1122
|
+
if (!nextUrl || hasConnection || nextBase || nextUrl.includes("{{")) {
|
|
1123
|
+
setUrlError(void 0);
|
|
1124
|
+
return;
|
|
1125
|
+
}
|
|
1126
|
+
try {
|
|
1127
|
+
new URL(nextUrl);
|
|
1128
|
+
setUrlError(void 0);
|
|
1129
|
+
} catch {
|
|
1130
|
+
setUrlError("URL does not look valid");
|
|
1131
|
+
}
|
|
1132
|
+
};
|
|
1133
|
+
const bodyMode = cfg.apiType === "graphql" ? "graphql" : cfg.bodyType ?? "json";
|
|
1134
|
+
const gqlVarCount = useMemo2(
|
|
1135
|
+
() => countGraphqlVariables(cfg.graphqlQuery ?? ""),
|
|
1136
|
+
[cfg.graphqlQuery]
|
|
1137
|
+
);
|
|
1138
|
+
const handleBodyMode = (next) => {
|
|
1139
|
+
if (next === "graphql") {
|
|
1140
|
+
emit(method === "GET" ? { apiType: "graphql", method: "POST" } : { apiType: "graphql" });
|
|
1141
|
+
return;
|
|
1142
|
+
}
|
|
1143
|
+
emit({ apiType: "rest", bodyType: next });
|
|
1144
|
+
};
|
|
1145
|
+
const [preview, setPreview] = useState4({ phase: "idle" });
|
|
1146
|
+
const [schemaInfo, setSchemaInfo] = useState4(
|
|
1147
|
+
null
|
|
1148
|
+
);
|
|
1149
|
+
const lastSchemaKey = useRef4("");
|
|
1150
|
+
const inferAndEmitSchema = useCallback4(
|
|
1151
|
+
(response, forceRefresh = false) => {
|
|
1152
|
+
if (responseType === "binary") return;
|
|
1153
|
+
const snapshot = {
|
|
1154
|
+
status: response.status,
|
|
1155
|
+
statusText: response.statusText,
|
|
1156
|
+
ok: response.ok,
|
|
1157
|
+
headers: response.headers,
|
|
1158
|
+
body: response.body,
|
|
1159
|
+
duration: response.duration,
|
|
1160
|
+
attempts: 1,
|
|
1161
|
+
extracted: {}
|
|
1162
|
+
};
|
|
1163
|
+
const inferred = inferJsonSchema(snapshot);
|
|
1164
|
+
const key = JSON.stringify(inferred);
|
|
1165
|
+
if (!forceRefresh && key === lastSchemaKey.current) return;
|
|
1166
|
+
lastSchemaKey.current = key;
|
|
1167
|
+
emit({ _outputSchema: inferred });
|
|
1168
|
+
const bodySchema = inferred.properties?.body;
|
|
1169
|
+
const topKeys = Object.keys(bodySchema?.properties ?? inferred.properties ?? {});
|
|
1170
|
+
setSchemaInfo({ pathCount: countSchemaPaths(inferred), topKeys });
|
|
1171
|
+
},
|
|
1172
|
+
[emit, responseType]
|
|
1173
|
+
);
|
|
1174
|
+
const sendPreview = async () => {
|
|
1175
|
+
if (!onSendPreview) return;
|
|
1176
|
+
setPreview({ phase: "loading" });
|
|
1177
|
+
try {
|
|
1178
|
+
const response = await onSendPreview({
|
|
1179
|
+
method: cfg.apiType === "graphql" ? "POST" : method,
|
|
1180
|
+
url: connectionId ? url : fullUrl,
|
|
1181
|
+
connectionId: connectionId || void 0,
|
|
1182
|
+
headers,
|
|
1183
|
+
queryParams,
|
|
1184
|
+
bodyType: cfg.bodyType ?? "json",
|
|
1185
|
+
body: bodyText,
|
|
1186
|
+
formData,
|
|
1187
|
+
graphqlQuery: cfg.apiType === "graphql" ? cfg.graphqlQuery ?? "" : void 0,
|
|
1188
|
+
graphqlVariables: cfg.apiType === "graphql" ? gqlVarsText : void 0,
|
|
1189
|
+
auth,
|
|
1190
|
+
timeout: cfg.timeout ?? 3e4
|
|
1191
|
+
});
|
|
1192
|
+
setPreview({ phase: "success", response });
|
|
1193
|
+
inferAndEmitSchema(response);
|
|
1194
|
+
} catch (err) {
|
|
1195
|
+
setPreview({
|
|
1196
|
+
phase: "error",
|
|
1197
|
+
message: err instanceof Error ? err.message : "Request failed"
|
|
1198
|
+
});
|
|
1199
|
+
}
|
|
1200
|
+
};
|
|
1201
|
+
const previewUrlOk = Boolean(fullUrl) && !fullUrl.includes("{{");
|
|
1202
|
+
const canSend = Boolean(onSendPreview) && previewUrlOk && preview.phase !== "loading" && !disabled;
|
|
1203
|
+
const paramCount = queryParams.filter((r) => r.enabled !== false && r.key).length;
|
|
1204
|
+
const headerCount = headers.filter((r) => r.enabled !== false && r.key).length;
|
|
1205
|
+
const extractCount = extractRows.filter((r) => r.key).length;
|
|
1206
|
+
const advancedSummary = [];
|
|
1207
|
+
if ((cfg.timeout ?? 3e4) !== 3e4) advancedSummary.push(`${(cfg.timeout ?? 0) / 1e3}s`);
|
|
1208
|
+
if ((retry?.maxAttempts ?? 1) > 1) advancedSummary.push(`retry \xD7${retry?.maxAttempts}`);
|
|
1209
|
+
if (pagination.type !== "none") advancedSummary.push(pagination.type.replace("_", " "));
|
|
1210
|
+
if (extractCount > 0) advancedSummary.push(`${extractCount} extracted`);
|
|
1211
|
+
const kvTab = (rows, key, desc, keyPlaceholder) => /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__tab", children: [
|
|
1212
|
+
/* @__PURE__ */ jsx2("p", { className: "ods-http-panel__desc", children: desc }),
|
|
1213
|
+
/* @__PURE__ */ jsx2(
|
|
1214
|
+
KeyValueEditor,
|
|
1215
|
+
{
|
|
1216
|
+
pairs: toPairs(rows),
|
|
1217
|
+
onChange: (pairs) => emit({ [key]: serializeKeyValues(pairs) }),
|
|
1218
|
+
rowToggle: true,
|
|
1219
|
+
showDescription: true,
|
|
1220
|
+
keyPlaceholder,
|
|
1221
|
+
valuePlaceholder: "value or {{var}}",
|
|
1222
|
+
emptyLabel: "No entries yet \u2014 click Add to begin.",
|
|
1223
|
+
addLabel: "Add",
|
|
1224
|
+
size: "sm",
|
|
1225
|
+
disabled
|
|
1226
|
+
}
|
|
1227
|
+
)
|
|
1228
|
+
] });
|
|
1229
|
+
const paramsTab = kvTab(
|
|
1230
|
+
queryParams,
|
|
1231
|
+
"queryParams",
|
|
1232
|
+
/* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
1233
|
+
"Query parameters appended to the URL. Supports ",
|
|
1234
|
+
/* @__PURE__ */ jsx2("code", { children: "{{variable}}" }),
|
|
1235
|
+
" interpolation."
|
|
1236
|
+
] }),
|
|
1237
|
+
"param name"
|
|
1238
|
+
);
|
|
1239
|
+
const headersTab = kvTab(
|
|
1240
|
+
headers,
|
|
1241
|
+
"headers",
|
|
1242
|
+
/* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
1243
|
+
"Request headers. Auth headers are injected automatically from the Auth tab. Supports",
|
|
1244
|
+
" ",
|
|
1245
|
+
/* @__PURE__ */ jsx2("code", { children: "{{variable}}" }),
|
|
1246
|
+
" interpolation."
|
|
1247
|
+
] }),
|
|
1248
|
+
"Header-Name"
|
|
1249
|
+
);
|
|
1250
|
+
const bodyTab = /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__tab", children: [
|
|
1251
|
+
/* @__PURE__ */ jsx2(
|
|
1252
|
+
SegmentedControl,
|
|
1253
|
+
{
|
|
1254
|
+
size: "sm",
|
|
1255
|
+
"aria-label": "Body type",
|
|
1256
|
+
options: [
|
|
1257
|
+
{ value: "none", label: "None" },
|
|
1258
|
+
{ value: "json", label: "JSON" },
|
|
1259
|
+
{ value: "graphql", label: "GraphQL" },
|
|
1260
|
+
{ value: "raw", label: "Raw" },
|
|
1261
|
+
{ value: "form-data", label: "Form" },
|
|
1262
|
+
{ value: "xml", label: "XML" }
|
|
1263
|
+
],
|
|
1264
|
+
value: bodyMode,
|
|
1265
|
+
onChange: handleBodyMode
|
|
1266
|
+
}
|
|
1267
|
+
),
|
|
1268
|
+
bodyMode === "none" && /* @__PURE__ */ jsx2("p", { className: "ods-http-panel__empty", children: "No request body will be sent." }),
|
|
1269
|
+
(bodyMode === "json" || bodyMode === "raw" || bodyMode === "xml") && /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
1270
|
+
/* @__PURE__ */ jsx2(
|
|
1271
|
+
CodeEditor,
|
|
1272
|
+
{
|
|
1273
|
+
value: bodyText,
|
|
1274
|
+
language: bodyMode === "json" ? "json" : "plain",
|
|
1275
|
+
onChange: (next) => {
|
|
1276
|
+
setBodyText(next);
|
|
1277
|
+
if (bodyMode === "json" && next.trim()) {
|
|
1278
|
+
try {
|
|
1279
|
+
emit({ body: JSON.parse(next) });
|
|
1280
|
+
setBodyError(void 0);
|
|
1281
|
+
} catch {
|
|
1282
|
+
setBodyError("Invalid JSON");
|
|
1283
|
+
emit({ body: next });
|
|
1284
|
+
}
|
|
1285
|
+
} else {
|
|
1286
|
+
setBodyError(void 0);
|
|
1287
|
+
emit({ body: next || void 0 });
|
|
1288
|
+
}
|
|
1289
|
+
},
|
|
1290
|
+
readOnly: disabled,
|
|
1291
|
+
minHeight: 180,
|
|
1292
|
+
ariaLabel: "Request body"
|
|
1293
|
+
}
|
|
1294
|
+
),
|
|
1295
|
+
bodyError && /* @__PURE__ */ jsxs2("p", { className: "ods-http-panel__error", children: [
|
|
1296
|
+
"\u26A0 ",
|
|
1297
|
+
bodyError
|
|
1298
|
+
] }),
|
|
1299
|
+
/* @__PURE__ */ jsxs2("p", { className: "ods-http-panel__desc", children: [
|
|
1300
|
+
"Supports ",
|
|
1301
|
+
/* @__PURE__ */ jsx2("code", { children: "{{variable}}" }),
|
|
1302
|
+
" interpolation."
|
|
1303
|
+
] })
|
|
1304
|
+
] }),
|
|
1305
|
+
bodyMode === "graphql" && /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
1306
|
+
/* @__PURE__ */ jsx2(
|
|
1307
|
+
CodeEditor,
|
|
1308
|
+
{
|
|
1309
|
+
value: cfg.graphqlQuery ?? "",
|
|
1310
|
+
language: "plain",
|
|
1311
|
+
onChange: (next) => emit({ graphqlQuery: next }),
|
|
1312
|
+
readOnly: disabled,
|
|
1313
|
+
minHeight: 160,
|
|
1314
|
+
placeholder: "query ($id: ID!) {\n node(id: $id) { id }\n}",
|
|
1315
|
+
ariaLabel: "GraphQL query"
|
|
1316
|
+
}
|
|
1317
|
+
),
|
|
1318
|
+
/* @__PURE__ */ jsxs2(
|
|
1319
|
+
Disclosure,
|
|
1320
|
+
{
|
|
1321
|
+
size: "sm",
|
|
1322
|
+
title: "Variables",
|
|
1323
|
+
defaultOpen: Boolean(gqlVarsText.trim()) || gqlVarCount > 0,
|
|
1324
|
+
trailing: gqlVarCount > 0 ? /* @__PURE__ */ jsx2(Badge, { size: "sm", variant: "neutral", children: gqlVarCount }) : void 0,
|
|
1325
|
+
children: [
|
|
1326
|
+
/* @__PURE__ */ jsx2(
|
|
1327
|
+
CodeEditor,
|
|
1328
|
+
{
|
|
1329
|
+
value: gqlVarsText,
|
|
1330
|
+
language: "json",
|
|
1331
|
+
onChange: (next) => {
|
|
1332
|
+
setGqlVarsText(next);
|
|
1333
|
+
if (!next.trim()) {
|
|
1334
|
+
setGqlVarsError(void 0);
|
|
1335
|
+
emit({ graphqlVariables: {} });
|
|
1336
|
+
return;
|
|
1337
|
+
}
|
|
1338
|
+
try {
|
|
1339
|
+
emit({ graphqlVariables: JSON.parse(next) });
|
|
1340
|
+
setGqlVarsError(void 0);
|
|
1341
|
+
} catch {
|
|
1342
|
+
setGqlVarsError("Invalid JSON");
|
|
1343
|
+
}
|
|
1344
|
+
},
|
|
1345
|
+
readOnly: disabled,
|
|
1346
|
+
minHeight: 100,
|
|
1347
|
+
ariaLabel: "GraphQL variables (JSON)"
|
|
1348
|
+
}
|
|
1349
|
+
),
|
|
1350
|
+
gqlVarsError && /* @__PURE__ */ jsxs2("p", { className: "ods-http-panel__error", children: [
|
|
1351
|
+
"\u26A0 ",
|
|
1352
|
+
gqlVarsError
|
|
1353
|
+
] })
|
|
1354
|
+
]
|
|
1355
|
+
}
|
|
1356
|
+
)
|
|
1357
|
+
] }),
|
|
1358
|
+
bodyMode === "form-data" && /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
1359
|
+
/* @__PURE__ */ jsx2("p", { className: "ods-http-panel__desc", children: "Multipart form fields. Content-Type is set automatically with the boundary." }),
|
|
1360
|
+
/* @__PURE__ */ jsx2(
|
|
1361
|
+
KeyValueEditor,
|
|
1362
|
+
{
|
|
1363
|
+
pairs: toPairs(formData),
|
|
1364
|
+
onChange: (pairs) => emit({ formData: serializeKeyValues(pairs), bodyType: "form-data" }),
|
|
1365
|
+
rowToggle: true,
|
|
1366
|
+
keyPlaceholder: "field name",
|
|
1367
|
+
valuePlaceholder: "value or {{var}}",
|
|
1368
|
+
emptyLabel: "No fields yet \u2014 click Add to begin.",
|
|
1369
|
+
addLabel: "Add",
|
|
1370
|
+
size: "sm",
|
|
1371
|
+
disabled
|
|
1372
|
+
}
|
|
1373
|
+
)
|
|
1374
|
+
] })
|
|
1375
|
+
] });
|
|
1376
|
+
const authTab = /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__tab", children: [
|
|
1377
|
+
connectionId ? /* @__PURE__ */ jsxs2(Banner, { variant: "success", appearance: "subtle", size: "sm", children: [
|
|
1378
|
+
"Authentication is inherited from ",
|
|
1379
|
+
/* @__PURE__ */ jsx2("strong", { children: selectedConnection?.name }),
|
|
1380
|
+
" and refreshed automatically. Choose a type below only to override it for this step."
|
|
1381
|
+
] }) : /* @__PURE__ */ jsx2(Banner, { variant: "info", appearance: "subtle", size: "sm", children: "For OAuth 2.0 APIs that need a login screen, create an API connection and select it as the Source \u2014 the token is obtained once and refreshed automatically. Inline auth here is for non-interactive credentials only." }),
|
|
1382
|
+
/* @__PURE__ */ jsx2(
|
|
1383
|
+
Select,
|
|
1384
|
+
{
|
|
1385
|
+
id: `${uid}-auth-type`,
|
|
1386
|
+
label: connectionId ? "Override authentication" : "Authentication",
|
|
1387
|
+
value: auth.type,
|
|
1388
|
+
onChange: (next) => emit({ auth: { ...auth, type: next } }),
|
|
1389
|
+
disabled,
|
|
1390
|
+
options: [
|
|
1391
|
+
{ value: "none", label: connectionId ? "Inherit from connection" : "No auth" },
|
|
1392
|
+
{ value: "basic", label: "Basic auth (username + password)" },
|
|
1393
|
+
{ value: "bearer", label: "Bearer token" },
|
|
1394
|
+
{ value: "apikey", label: "API key" }
|
|
1395
|
+
]
|
|
1396
|
+
}
|
|
1397
|
+
),
|
|
1398
|
+
auth.type === "basic" && /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__grid", children: [
|
|
1399
|
+
/* @__PURE__ */ jsx2(
|
|
1400
|
+
Input,
|
|
1401
|
+
{
|
|
1402
|
+
id: `${uid}-auth-user`,
|
|
1403
|
+
label: "Username",
|
|
1404
|
+
value: auth.username ?? "",
|
|
1405
|
+
placeholder: "username or {{var}}",
|
|
1406
|
+
onChange: (e) => emit({ auth: { ...auth, username: e.target.value } }),
|
|
1407
|
+
disabled
|
|
1408
|
+
}
|
|
1409
|
+
),
|
|
1410
|
+
/* @__PURE__ */ jsx2(
|
|
1411
|
+
PasswordInput,
|
|
1412
|
+
{
|
|
1413
|
+
id: `${uid}-auth-pass`,
|
|
1414
|
+
label: "Password",
|
|
1415
|
+
value: auth.password ?? "",
|
|
1416
|
+
placeholder: "password or {{var}}",
|
|
1417
|
+
onChange: (next) => emit({ auth: { ...auth, password: next } }),
|
|
1418
|
+
disabled
|
|
1419
|
+
}
|
|
1420
|
+
)
|
|
1421
|
+
] }),
|
|
1422
|
+
auth.type === "bearer" && /* @__PURE__ */ jsx2(
|
|
1423
|
+
PasswordInput,
|
|
1424
|
+
{
|
|
1425
|
+
id: `${uid}-auth-token`,
|
|
1426
|
+
label: "Token",
|
|
1427
|
+
value: auth.token ?? "",
|
|
1428
|
+
placeholder: "your-token or {{step.token}}",
|
|
1429
|
+
onChange: (next) => emit({ auth: { ...auth, token: next } }),
|
|
1430
|
+
disabled
|
|
1431
|
+
}
|
|
1432
|
+
),
|
|
1433
|
+
auth.type === "apikey" && /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__grid", children: [
|
|
1434
|
+
/* @__PURE__ */ jsx2(
|
|
1435
|
+
Input,
|
|
1436
|
+
{
|
|
1437
|
+
id: `${uid}-auth-keyname`,
|
|
1438
|
+
label: "Key name",
|
|
1439
|
+
value: auth.apiKeyName ?? "",
|
|
1440
|
+
placeholder: "X-API-Key",
|
|
1441
|
+
onChange: (e) => emit({ auth: { ...auth, apiKeyName: e.target.value } }),
|
|
1442
|
+
disabled
|
|
1443
|
+
}
|
|
1444
|
+
),
|
|
1445
|
+
/* @__PURE__ */ jsx2(
|
|
1446
|
+
PasswordInput,
|
|
1447
|
+
{
|
|
1448
|
+
id: `${uid}-auth-keyval`,
|
|
1449
|
+
label: "Key value",
|
|
1450
|
+
value: auth.apiKeyValue ?? "",
|
|
1451
|
+
placeholder: "your-api-key or {{var}}",
|
|
1452
|
+
onChange: (next) => emit({ auth: { ...auth, apiKeyValue: next } }),
|
|
1453
|
+
disabled
|
|
1454
|
+
}
|
|
1455
|
+
),
|
|
1456
|
+
/* @__PURE__ */ jsx2(
|
|
1457
|
+
Select,
|
|
1458
|
+
{
|
|
1459
|
+
id: `${uid}-auth-keyloc`,
|
|
1460
|
+
label: "Send in",
|
|
1461
|
+
value: auth.apiKeyLocation ?? "header",
|
|
1462
|
+
onChange: (next) => emit({ auth: { ...auth, apiKeyLocation: next } }),
|
|
1463
|
+
disabled,
|
|
1464
|
+
options: [
|
|
1465
|
+
{ value: "header", label: "Request header" },
|
|
1466
|
+
{ value: "query", label: "Query parameter" }
|
|
1467
|
+
]
|
|
1468
|
+
}
|
|
1469
|
+
)
|
|
1470
|
+
] }),
|
|
1471
|
+
auth.type === "none" && /* @__PURE__ */ jsx2("p", { className: "ods-http-panel__empty", children: connectionId ? "This step uses the connection's authentication." : "No authentication will be added to this request." })
|
|
1472
|
+
] });
|
|
1473
|
+
const responseTab = /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__tab", children: [
|
|
1474
|
+
/* @__PURE__ */ jsx2(
|
|
1475
|
+
SegmentedControl,
|
|
1476
|
+
{
|
|
1477
|
+
size: "sm",
|
|
1478
|
+
"aria-label": "Response type",
|
|
1479
|
+
options: [
|
|
1480
|
+
{ value: "json", label: "JSON" },
|
|
1481
|
+
{ value: "text", label: "Text" },
|
|
1482
|
+
{ value: "binary", label: "Binary" }
|
|
1483
|
+
],
|
|
1484
|
+
value: responseType,
|
|
1485
|
+
onChange: (next) => emit({ responseType: next })
|
|
1486
|
+
}
|
|
1487
|
+
),
|
|
1488
|
+
/* @__PURE__ */ jsxs2("p", { className: "ods-http-panel__desc", children: [
|
|
1489
|
+
responseType === "json" && "Tries to parse the response body as JSON; falls back to raw text on parse failure.",
|
|
1490
|
+
responseType === "text" && "Returns the raw response body as a string. No JSON parsing.",
|
|
1491
|
+
responseType === "binary" && /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
1492
|
+
"Returns the response as bytes with ",
|
|
1493
|
+
/* @__PURE__ */ jsx2("code", { children: "fileName" }),
|
|
1494
|
+
", ",
|
|
1495
|
+
/* @__PURE__ */ jsx2("code", { children: "contentType" }),
|
|
1496
|
+
" and",
|
|
1497
|
+
" ",
|
|
1498
|
+
/* @__PURE__ */ jsx2("code", { children: "size" }),
|
|
1499
|
+
" on the step output \u2014 for downloads feeding file actions. Pagination is not compatible with binary responses."
|
|
1500
|
+
] })
|
|
1501
|
+
] }),
|
|
1502
|
+
/* @__PURE__ */ jsx2(
|
|
1503
|
+
Input,
|
|
1504
|
+
{
|
|
1505
|
+
id: `${uid}-expected-ct`,
|
|
1506
|
+
label: "Expected content-types (optional)",
|
|
1507
|
+
value: expectedCtText,
|
|
1508
|
+
placeholder: "application/pdf, application/json",
|
|
1509
|
+
helperText: "Comma-separated. A warning is logged when the response Content-Type matches none of these.",
|
|
1510
|
+
onChange: (e) => {
|
|
1511
|
+
setExpectedCtText(e.target.value);
|
|
1512
|
+
const parts = e.target.value.split(",").map((s) => s.trim()).filter(Boolean);
|
|
1513
|
+
emit({ expectedContentTypes: parts.length ? parts : void 0 });
|
|
1514
|
+
},
|
|
1515
|
+
disabled
|
|
1516
|
+
}
|
|
1517
|
+
),
|
|
1518
|
+
/* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__schema", children: [
|
|
1519
|
+
/* @__PURE__ */ jsx2("span", { className: "ods-http-panel__schema-label", children: "Data stream schema" }),
|
|
1520
|
+
schemaInfo ? /* @__PURE__ */ jsxs2("p", { className: "ods-http-panel__desc", children: [
|
|
1521
|
+
/* @__PURE__ */ jsxs2(Badge, { size: "sm", variant: "success", children: [
|
|
1522
|
+
schemaInfo.pathCount,
|
|
1523
|
+
" paths"
|
|
1524
|
+
] }),
|
|
1525
|
+
" ",
|
|
1526
|
+
"Inferred from the last test send. Top-level keys:",
|
|
1527
|
+
" ",
|
|
1528
|
+
/* @__PURE__ */ jsx2("code", { children: schemaInfo.topKeys.join(", ") }),
|
|
1529
|
+
". Downstream binding (Field Mapper, Transform, ForEach) sees this shape immediately; Save persists it."
|
|
1530
|
+
] }) : /* @__PURE__ */ jsxs2("p", { className: "ods-http-panel__desc", children: [
|
|
1531
|
+
"No schema yet \u2014 hit ",
|
|
1532
|
+
/* @__PURE__ */ jsx2("strong", { children: "Send" }),
|
|
1533
|
+
" in the request bar. On success the response shape is inferred so downstream steps bind against real field names."
|
|
1534
|
+
] }),
|
|
1535
|
+
/* @__PURE__ */ jsx2(
|
|
1536
|
+
Button,
|
|
1537
|
+
{
|
|
1538
|
+
variant: "ghost",
|
|
1539
|
+
size: "sm",
|
|
1540
|
+
disabled: preview.phase !== "success" || responseType === "binary" || disabled,
|
|
1541
|
+
onClick: () => {
|
|
1542
|
+
if (preview.phase === "success") inferAndEmitSchema(preview.response, true);
|
|
1543
|
+
},
|
|
1544
|
+
children: "Refresh schema from last send"
|
|
1545
|
+
}
|
|
1546
|
+
)
|
|
1547
|
+
] })
|
|
1548
|
+
] });
|
|
1549
|
+
const tabItems = [
|
|
1550
|
+
{
|
|
1551
|
+
value: "params",
|
|
1552
|
+
label: paramCount ? `Params \xB7 ${paramCount}` : "Params",
|
|
1553
|
+
icon: /* @__PURE__ */ jsx2(ListIcon, { size: "sm" }),
|
|
1554
|
+
children: paramsTab
|
|
1555
|
+
},
|
|
1556
|
+
{
|
|
1557
|
+
value: "headers",
|
|
1558
|
+
label: headerCount ? `Headers \xB7 ${headerCount}` : "Headers",
|
|
1559
|
+
icon: /* @__PURE__ */ jsx2(TagIcon, { size: "sm" }),
|
|
1560
|
+
children: headersTab
|
|
1561
|
+
},
|
|
1562
|
+
{
|
|
1563
|
+
value: "body",
|
|
1564
|
+
label: bodyMode === "none" ? "Body" : `Body \xB7 ${bodyMode === "form-data" ? "form" : bodyMode}`,
|
|
1565
|
+
icon: /* @__PURE__ */ jsx2(CodeIcon, { size: "sm" }),
|
|
1566
|
+
children: bodyTab
|
|
1567
|
+
},
|
|
1568
|
+
{
|
|
1569
|
+
value: "auth",
|
|
1570
|
+
label: auth.type === "none" ? "Auth" : `Auth \xB7 ${auth.type}`,
|
|
1571
|
+
icon: /* @__PURE__ */ jsx2(LockedIcon, { size: "sm" }),
|
|
1572
|
+
children: authTab
|
|
1573
|
+
},
|
|
1574
|
+
{
|
|
1575
|
+
value: "response",
|
|
1576
|
+
label: responseType === "json" ? "Response" : `Response \xB7 ${responseType}`,
|
|
1577
|
+
icon: /* @__PURE__ */ jsx2(DataViewAltIcon, { size: "sm" }),
|
|
1578
|
+
children: responseTab
|
|
1579
|
+
}
|
|
1580
|
+
];
|
|
1581
|
+
return /* @__PURE__ */ jsxs2("div", { className: cn("ods-http-panel", className), children: [
|
|
1582
|
+
connections && /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__source", children: [
|
|
1583
|
+
/* @__PURE__ */ jsx2(
|
|
1584
|
+
Select,
|
|
1585
|
+
{
|
|
1586
|
+
id: `${uid}-connection`,
|
|
1587
|
+
label: "Source",
|
|
1588
|
+
placeholder: connectionsLoading ? "Loading\u2026" : "No connection (manual config)",
|
|
1589
|
+
options: connections.map((c) => ({ value: c.id, label: c.name, icon: c.icon })),
|
|
1590
|
+
value: connectionId,
|
|
1591
|
+
onChange: (next) => emit({ connectionId: next || void 0 }),
|
|
1592
|
+
disabled: disabled || connectionsLoading,
|
|
1593
|
+
helperText: connectionId ? `Base URL and auth are inherited from "${selectedConnection?.name}" at runtime.` : "Select a saved API connection to inherit base URL and auth, or configure manually."
|
|
1594
|
+
}
|
|
1595
|
+
),
|
|
1596
|
+
connectionId && endpoints.length > 0 && /* @__PURE__ */ jsx2(
|
|
1597
|
+
Combobox,
|
|
1598
|
+
{
|
|
1599
|
+
ariaLabel: "Endpoint",
|
|
1600
|
+
placeholder: `Search ${endpoints.length} discovered endpoints\u2026`,
|
|
1601
|
+
value: url,
|
|
1602
|
+
creatable: true,
|
|
1603
|
+
options: endpoints.map((e) => ({
|
|
1604
|
+
value: e.path,
|
|
1605
|
+
label: `${e.method} ${e.path}`,
|
|
1606
|
+
description: e.summary
|
|
1607
|
+
})),
|
|
1608
|
+
onChange: (nextPath) => {
|
|
1609
|
+
const match = endpoints.find((e) => e.path === nextPath);
|
|
1610
|
+
validateUrl(nextPath, baseUrl, true);
|
|
1611
|
+
emit(
|
|
1612
|
+
match && HTTP_METHODS.includes(match.method.toUpperCase()) ? { url: nextPath, method: match.method.toUpperCase() } : { url: nextPath }
|
|
1613
|
+
);
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
|
+
)
|
|
1617
|
+
] }),
|
|
1618
|
+
/* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__bar", children: [
|
|
1619
|
+
/* @__PURE__ */ jsx2(
|
|
1620
|
+
Select,
|
|
1621
|
+
{
|
|
1622
|
+
id: `${uid}-method`,
|
|
1623
|
+
"aria-label": "HTTP method",
|
|
1624
|
+
className: cn(
|
|
1625
|
+
"ods-http-panel__method",
|
|
1626
|
+
`ods-http-panel__method--${method.toLowerCase()}`
|
|
1627
|
+
),
|
|
1628
|
+
value: method,
|
|
1629
|
+
onChange: (next) => emit({ method: next }),
|
|
1630
|
+
disabled,
|
|
1631
|
+
options: HTTP_METHODS.map((m) => ({ value: m, label: m }))
|
|
1632
|
+
}
|
|
1633
|
+
),
|
|
1634
|
+
/* @__PURE__ */ jsx2(
|
|
1635
|
+
Input,
|
|
1636
|
+
{
|
|
1637
|
+
id: `${uid}-url`,
|
|
1638
|
+
"aria-label": connectionId ? "Path" : "URL",
|
|
1639
|
+
"data-fx-droppable": "true",
|
|
1640
|
+
className: "ods-http-panel__url",
|
|
1641
|
+
value: url,
|
|
1642
|
+
placeholder: connectionId ? "/v1/users" : "https://api.example.com/v1/users or {{var}}",
|
|
1643
|
+
error: Boolean(urlError),
|
|
1644
|
+
errorMessage: urlError,
|
|
1645
|
+
onChange: (e) => {
|
|
1646
|
+
validateUrl(e.target.value, baseUrl, Boolean(connectionId));
|
|
1647
|
+
emit({ url: e.target.value });
|
|
1648
|
+
},
|
|
1649
|
+
disabled
|
|
1650
|
+
}
|
|
1651
|
+
),
|
|
1652
|
+
onSendPreview && /* @__PURE__ */ jsx2(
|
|
1653
|
+
Button,
|
|
1654
|
+
{
|
|
1655
|
+
variant: "primary",
|
|
1656
|
+
size: "md",
|
|
1657
|
+
leftIcon: preview.phase === "loading" ? void 0 : /* @__PURE__ */ jsx2(PlayIcon, { size: "sm" }),
|
|
1658
|
+
onClick: sendPreview,
|
|
1659
|
+
disabled: !canSend,
|
|
1660
|
+
children: preview.phase === "loading" ? "Sending\u2026" : "Send"
|
|
1661
|
+
}
|
|
1662
|
+
)
|
|
1663
|
+
] }),
|
|
1664
|
+
!connectionId && baseUrl && /* @__PURE__ */ jsxs2("p", { className: "ods-http-panel__effective", children: [
|
|
1665
|
+
/* @__PURE__ */ jsx2("span", { children: "Effective URL:" }),
|
|
1666
|
+
" ",
|
|
1667
|
+
/* @__PURE__ */ jsx2("code", { children: fullUrl || "\u2014" })
|
|
1668
|
+
] }),
|
|
1669
|
+
fullUrl.includes("{{") && /* @__PURE__ */ jsxs2("p", { className: "ods-http-panel__desc", children: [
|
|
1670
|
+
"\u26A0 URL contains ",
|
|
1671
|
+
/* @__PURE__ */ jsx2("code", { children: "{{variables}}" }),
|
|
1672
|
+
" \u2014 they resolve at run time; testing needs literal values."
|
|
1673
|
+
] }),
|
|
1674
|
+
/* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__tools", children: [
|
|
1675
|
+
/* @__PURE__ */ jsxs2("span", { className: "ods-http-panel__hint", children: [
|
|
1676
|
+
"Use ",
|
|
1677
|
+
/* @__PURE__ */ jsx2("code", { children: "{{stepName.fieldPath}}" }),
|
|
1678
|
+
" to insert data from upstream steps."
|
|
1679
|
+
] }),
|
|
1680
|
+
/* @__PURE__ */ jsxs2("span", { className: "ods-http-panel__tools-actions", children: [
|
|
1681
|
+
/* @__PURE__ */ jsx2(Button, { variant: "ghost", size: "sm", onClick: () => setCurlOpen((o) => !o), children: "Import cURL" }),
|
|
1682
|
+
/* @__PURE__ */ jsx2(
|
|
1683
|
+
Button,
|
|
1684
|
+
{
|
|
1685
|
+
variant: "ghost",
|
|
1686
|
+
size: "sm",
|
|
1687
|
+
className: cn(copiedCurl && "ods-http-panel__copy-done"),
|
|
1688
|
+
leftIcon: copiedCurl ? /* @__PURE__ */ jsx2(CheckmarkIcon, { size: "sm" }) : /* @__PURE__ */ jsx2(CopyIcon, { size: "sm" }),
|
|
1689
|
+
onClick: copyCurl,
|
|
1690
|
+
children: copiedCurl ? "Copied" : "Copy as cURL"
|
|
1691
|
+
}
|
|
1692
|
+
)
|
|
1693
|
+
] })
|
|
1694
|
+
] }),
|
|
1695
|
+
curlOpen && /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__curl", children: [
|
|
1696
|
+
/* @__PURE__ */ jsx2(
|
|
1697
|
+
CodeEditor,
|
|
1698
|
+
{
|
|
1699
|
+
value: curlText,
|
|
1700
|
+
language: "plain",
|
|
1701
|
+
onChange: setCurlText,
|
|
1702
|
+
minHeight: 90,
|
|
1703
|
+
showLineNumbers: false,
|
|
1704
|
+
placeholder: "curl -X POST 'https://api.example.com/v1/users' -H 'Authorization: Bearer \u2026' -d '{\u2026}'",
|
|
1705
|
+
ariaLabel: "cURL command"
|
|
1706
|
+
}
|
|
1707
|
+
),
|
|
1708
|
+
curlError && /* @__PURE__ */ jsxs2("p", { className: "ods-http-panel__error", children: [
|
|
1709
|
+
"\u26A0 ",
|
|
1710
|
+
curlError
|
|
1711
|
+
] }),
|
|
1712
|
+
/* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__curl-actions", children: [
|
|
1713
|
+
/* @__PURE__ */ jsx2(Button, { variant: "secondary", size: "sm", onClick: () => setCurlOpen(false), children: "Cancel" }),
|
|
1714
|
+
/* @__PURE__ */ jsx2(Button, { variant: "primary", size: "sm", onClick: applyCurl, disabled: !curlText.trim(), children: "Apply to request" })
|
|
1715
|
+
] })
|
|
1716
|
+
] }),
|
|
1717
|
+
/* @__PURE__ */ jsx2(Tabs, { items: tabItems, defaultValue: "params", className: "ods-http-panel__tabs" }),
|
|
1718
|
+
/* @__PURE__ */ jsxs2(
|
|
1719
|
+
Disclosure,
|
|
1720
|
+
{
|
|
1721
|
+
size: "sm",
|
|
1722
|
+
icon: /* @__PURE__ */ jsx2(GlobeIcon, { size: "sm" }),
|
|
1723
|
+
title: "Advanced options",
|
|
1724
|
+
description: "Base URL, timeout, retries, pagination, response extraction",
|
|
1725
|
+
trailing: advancedSummary.length ? /* @__PURE__ */ jsx2(Badge, { size: "sm", variant: "info", children: advancedSummary.join(" \xB7 ") }) : void 0,
|
|
1726
|
+
children: [
|
|
1727
|
+
/* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__grid", children: [
|
|
1728
|
+
!connectionId && /* @__PURE__ */ jsx2(
|
|
1729
|
+
Input,
|
|
1730
|
+
{
|
|
1731
|
+
id: `${uid}-base-url`,
|
|
1732
|
+
label: "Base URL (optional)",
|
|
1733
|
+
value: baseUrl,
|
|
1734
|
+
placeholder: "https://api.example.com",
|
|
1735
|
+
helperText: "Combined with the request path to form the full URL.",
|
|
1736
|
+
onChange: (e) => {
|
|
1737
|
+
validateUrl(url, e.target.value, Boolean(connectionId));
|
|
1738
|
+
emit({ baseUrl: e.target.value || void 0 });
|
|
1739
|
+
},
|
|
1740
|
+
disabled
|
|
1741
|
+
}
|
|
1742
|
+
),
|
|
1743
|
+
/* @__PURE__ */ jsx2(
|
|
1744
|
+
NumberInput,
|
|
1745
|
+
{
|
|
1746
|
+
label: "Timeout (ms)",
|
|
1747
|
+
helperText: "Minimum 1000 ms",
|
|
1748
|
+
value: cfg.timeout ?? 3e4,
|
|
1749
|
+
min: 1e3,
|
|
1750
|
+
step: 1e3,
|
|
1751
|
+
onChange: (next) => {
|
|
1752
|
+
if (!Number.isNaN(next) && next >= 1e3) emit({ timeout: next });
|
|
1753
|
+
},
|
|
1754
|
+
disabled
|
|
1755
|
+
}
|
|
1756
|
+
),
|
|
1757
|
+
/* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__switches", children: [
|
|
1758
|
+
/* @__PURE__ */ jsx2(
|
|
1759
|
+
Switch,
|
|
1760
|
+
{
|
|
1761
|
+
id: `${uid}-fail`,
|
|
1762
|
+
label: "Fail on non-2xx",
|
|
1763
|
+
checked: cfg.failOnError !== false,
|
|
1764
|
+
onChange: (next) => emit({ failOnError: next }),
|
|
1765
|
+
disabled,
|
|
1766
|
+
size: "sm"
|
|
1767
|
+
}
|
|
1768
|
+
),
|
|
1769
|
+
/* @__PURE__ */ jsx2(
|
|
1770
|
+
Switch,
|
|
1771
|
+
{
|
|
1772
|
+
id: `${uid}-redirects`,
|
|
1773
|
+
label: "Follow redirects",
|
|
1774
|
+
checked: cfg.followRedirects !== false,
|
|
1775
|
+
onChange: (next) => emit({ followRedirects: next }),
|
|
1776
|
+
disabled,
|
|
1777
|
+
size: "sm"
|
|
1778
|
+
}
|
|
1779
|
+
)
|
|
1780
|
+
] })
|
|
1781
|
+
] }),
|
|
1782
|
+
/* @__PURE__ */ jsx2(
|
|
1783
|
+
Disclosure,
|
|
1784
|
+
{
|
|
1785
|
+
size: "sm",
|
|
1786
|
+
title: "Retry",
|
|
1787
|
+
trailing: (retry?.maxAttempts ?? 1) > 1 ? /* @__PURE__ */ jsxs2(Badge, { size: "sm", variant: "info", children: [
|
|
1788
|
+
retry?.maxAttempts,
|
|
1789
|
+
" attempts"
|
|
1790
|
+
] }) : void 0,
|
|
1791
|
+
children: /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__grid", children: [
|
|
1792
|
+
/* @__PURE__ */ jsx2(
|
|
1793
|
+
NumberInput,
|
|
1794
|
+
{
|
|
1795
|
+
label: "Max attempts",
|
|
1796
|
+
helperText: "1 = no retry",
|
|
1797
|
+
value: retry?.maxAttempts ?? 1,
|
|
1798
|
+
min: 1,
|
|
1799
|
+
max: 10,
|
|
1800
|
+
onChange: (next) => {
|
|
1801
|
+
if (!Number.isNaN(next) && next >= 1 && retry) {
|
|
1802
|
+
emit({ retry: { ...retry, maxAttempts: next } });
|
|
1803
|
+
}
|
|
1804
|
+
},
|
|
1805
|
+
disabled
|
|
1806
|
+
}
|
|
1807
|
+
),
|
|
1808
|
+
/* @__PURE__ */ jsx2(
|
|
1809
|
+
Input,
|
|
1810
|
+
{
|
|
1811
|
+
id: `${uid}-retry-on`,
|
|
1812
|
+
label: "Retry on (status codes)",
|
|
1813
|
+
value: retryOnText,
|
|
1814
|
+
placeholder: "429, 500, 502, 503, 504",
|
|
1815
|
+
helperText: "Comma-separated HTTP status codes",
|
|
1816
|
+
onChange: (e) => {
|
|
1817
|
+
setRetryOnText(e.target.value);
|
|
1818
|
+
const codes = e.target.value.split(",").map((s) => Number.parseInt(s.trim(), 10)).filter((n) => !Number.isNaN(n));
|
|
1819
|
+
if (retry) emit({ retry: { ...retry, retryOn: codes } });
|
|
1820
|
+
},
|
|
1821
|
+
disabled
|
|
1822
|
+
}
|
|
1823
|
+
),
|
|
1824
|
+
/* @__PURE__ */ jsx2(
|
|
1825
|
+
NumberInput,
|
|
1826
|
+
{
|
|
1827
|
+
label: "Initial delay (ms)",
|
|
1828
|
+
value: retry?.initialDelayMs ?? 1e3,
|
|
1829
|
+
min: 100,
|
|
1830
|
+
step: 100,
|
|
1831
|
+
onChange: (next) => {
|
|
1832
|
+
if (!Number.isNaN(next) && retry)
|
|
1833
|
+
emit({ retry: { ...retry, initialDelayMs: next } });
|
|
1834
|
+
},
|
|
1835
|
+
disabled
|
|
1836
|
+
}
|
|
1837
|
+
),
|
|
1838
|
+
/* @__PURE__ */ jsx2(
|
|
1839
|
+
NumberInput,
|
|
1840
|
+
{
|
|
1841
|
+
label: "Backoff factor",
|
|
1842
|
+
helperText: "Delay multiplies by this each retry",
|
|
1843
|
+
value: retry?.backoffFactor ?? 2,
|
|
1844
|
+
min: 1,
|
|
1845
|
+
step: 0.5,
|
|
1846
|
+
onChange: (next) => {
|
|
1847
|
+
if (!Number.isNaN(next) && retry)
|
|
1848
|
+
emit({ retry: { ...retry, backoffFactor: next } });
|
|
1849
|
+
},
|
|
1850
|
+
disabled
|
|
1851
|
+
}
|
|
1852
|
+
),
|
|
1853
|
+
/* @__PURE__ */ jsx2(
|
|
1854
|
+
NumberInput,
|
|
1855
|
+
{
|
|
1856
|
+
label: "Max delay (ms)",
|
|
1857
|
+
value: retry?.maxDelayMs ?? 3e4,
|
|
1858
|
+
min: 1e3,
|
|
1859
|
+
step: 1e3,
|
|
1860
|
+
onChange: (next) => {
|
|
1861
|
+
if (!Number.isNaN(next) && retry) emit({ retry: { ...retry, maxDelayMs: next } });
|
|
1862
|
+
},
|
|
1863
|
+
disabled
|
|
1864
|
+
}
|
|
1865
|
+
)
|
|
1866
|
+
] })
|
|
1867
|
+
}
|
|
1868
|
+
),
|
|
1869
|
+
/* @__PURE__ */ jsxs2(
|
|
1870
|
+
Disclosure,
|
|
1871
|
+
{
|
|
1872
|
+
size: "sm",
|
|
1873
|
+
title: "Pagination",
|
|
1874
|
+
trailing: pagination.type !== "none" ? /* @__PURE__ */ jsx2(Badge, { size: "sm", variant: "success", children: pagination.type.replace("_", " ") }) : void 0,
|
|
1875
|
+
children: [
|
|
1876
|
+
/* @__PURE__ */ jsx2(
|
|
1877
|
+
Select,
|
|
1878
|
+
{
|
|
1879
|
+
id: `${uid}-pag-type`,
|
|
1880
|
+
label: "Strategy",
|
|
1881
|
+
value: pagination.type,
|
|
1882
|
+
onChange: (next) => emit({
|
|
1883
|
+
pagination: { ...pagination, type: next }
|
|
1884
|
+
}),
|
|
1885
|
+
disabled,
|
|
1886
|
+
options: [
|
|
1887
|
+
{ value: "none", label: "None (single request)" },
|
|
1888
|
+
{ value: "offset", label: "Offset / page number" },
|
|
1889
|
+
{ value: "cursor", label: "Cursor-based" },
|
|
1890
|
+
{ value: "link_header", label: 'Link header (rel="next")' },
|
|
1891
|
+
{ value: "next_url", label: "Next URL in response body" }
|
|
1892
|
+
]
|
|
1893
|
+
}
|
|
1894
|
+
),
|
|
1895
|
+
pagination.type !== "none" && /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__grid", children: [
|
|
1896
|
+
/* @__PURE__ */ jsx2(
|
|
1897
|
+
NumberInput,
|
|
1898
|
+
{
|
|
1899
|
+
label: "Max pages",
|
|
1900
|
+
helperText: "Safety cap against infinite loops",
|
|
1901
|
+
value: pagination.maxPages ?? 20,
|
|
1902
|
+
min: 1,
|
|
1903
|
+
onChange: (next) => {
|
|
1904
|
+
if (!Number.isNaN(next)) emit({ pagination: { ...pagination, maxPages: next } });
|
|
1905
|
+
},
|
|
1906
|
+
disabled
|
|
1907
|
+
}
|
|
1908
|
+
),
|
|
1909
|
+
/* @__PURE__ */ jsx2(
|
|
1910
|
+
Input,
|
|
1911
|
+
{
|
|
1912
|
+
id: `${uid}-pag-merge`,
|
|
1913
|
+
label: "Merge key (dot path)",
|
|
1914
|
+
value: pagination.mergeKey ?? "",
|
|
1915
|
+
placeholder: "data.items",
|
|
1916
|
+
helperText: "Array to merge across pages",
|
|
1917
|
+
onChange: (e) => emit({ pagination: { ...pagination, mergeKey: e.target.value } }),
|
|
1918
|
+
disabled
|
|
1919
|
+
}
|
|
1920
|
+
),
|
|
1921
|
+
(pagination.type === "offset" || pagination.type === "cursor") && /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
1922
|
+
/* @__PURE__ */ jsx2(
|
|
1923
|
+
Input,
|
|
1924
|
+
{
|
|
1925
|
+
id: `${uid}-pag-limitp`,
|
|
1926
|
+
label: "Limit param",
|
|
1927
|
+
value: pagination.limitParam ?? "limit",
|
|
1928
|
+
onChange: (e) => emit({ pagination: { ...pagination, limitParam: e.target.value } }),
|
|
1929
|
+
disabled
|
|
1930
|
+
}
|
|
1931
|
+
),
|
|
1932
|
+
/* @__PURE__ */ jsx2(
|
|
1933
|
+
NumberInput,
|
|
1934
|
+
{
|
|
1935
|
+
label: "Page size",
|
|
1936
|
+
value: pagination.limitValue ?? 100,
|
|
1937
|
+
min: 1,
|
|
1938
|
+
onChange: (next) => {
|
|
1939
|
+
if (!Number.isNaN(next)) {
|
|
1940
|
+
emit({ pagination: { ...pagination, limitValue: next } });
|
|
1941
|
+
}
|
|
1942
|
+
},
|
|
1943
|
+
disabled
|
|
1944
|
+
}
|
|
1945
|
+
)
|
|
1946
|
+
] }),
|
|
1947
|
+
pagination.type === "offset" && /* @__PURE__ */ jsx2(
|
|
1948
|
+
Input,
|
|
1949
|
+
{
|
|
1950
|
+
id: `${uid}-pag-offset`,
|
|
1951
|
+
label: "Offset param",
|
|
1952
|
+
value: pagination.offsetParam ?? "offset",
|
|
1953
|
+
onChange: (e) => emit({ pagination: { ...pagination, offsetParam: e.target.value } }),
|
|
1954
|
+
disabled
|
|
1955
|
+
}
|
|
1956
|
+
),
|
|
1957
|
+
pagination.type === "cursor" && /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
1958
|
+
/* @__PURE__ */ jsx2(
|
|
1959
|
+
Input,
|
|
1960
|
+
{
|
|
1961
|
+
id: `${uid}-pag-cres`,
|
|
1962
|
+
label: "Cursor in response (dot path)",
|
|
1963
|
+
value: pagination.cursorResponsePath ?? "",
|
|
1964
|
+
placeholder: "meta.next_cursor",
|
|
1965
|
+
onChange: (e) => emit({ pagination: { ...pagination, cursorResponsePath: e.target.value } }),
|
|
1966
|
+
disabled
|
|
1967
|
+
}
|
|
1968
|
+
),
|
|
1969
|
+
/* @__PURE__ */ jsx2(
|
|
1970
|
+
Input,
|
|
1971
|
+
{
|
|
1972
|
+
id: `${uid}-pag-creq`,
|
|
1973
|
+
label: "Cursor request param",
|
|
1974
|
+
value: pagination.cursorRequestParam ?? "cursor",
|
|
1975
|
+
onChange: (e) => emit({ pagination: { ...pagination, cursorRequestParam: e.target.value } }),
|
|
1976
|
+
disabled
|
|
1977
|
+
}
|
|
1978
|
+
)
|
|
1979
|
+
] }),
|
|
1980
|
+
pagination.type === "next_url" && /* @__PURE__ */ jsx2(
|
|
1981
|
+
Input,
|
|
1982
|
+
{
|
|
1983
|
+
id: `${uid}-pag-next`,
|
|
1984
|
+
label: "Next URL in response (dot path)",
|
|
1985
|
+
value: pagination.nextUrlResponsePath ?? "",
|
|
1986
|
+
placeholder: "links.next",
|
|
1987
|
+
onChange: (e) => emit({ pagination: { ...pagination, nextUrlResponsePath: e.target.value } }),
|
|
1988
|
+
disabled
|
|
1989
|
+
}
|
|
1990
|
+
)
|
|
1991
|
+
] })
|
|
1992
|
+
]
|
|
1993
|
+
}
|
|
1994
|
+
),
|
|
1995
|
+
/* @__PURE__ */ jsxs2(
|
|
1996
|
+
Disclosure,
|
|
1997
|
+
{
|
|
1998
|
+
size: "sm",
|
|
1999
|
+
title: "Response field extraction",
|
|
2000
|
+
trailing: extractCount > 0 ? /* @__PURE__ */ jsxs2(Badge, { size: "sm", variant: "info", children: [
|
|
2001
|
+
extractCount,
|
|
2002
|
+
" field",
|
|
2003
|
+
extractCount === 1 ? "" : "s"
|
|
2004
|
+
] }) : void 0,
|
|
2005
|
+
children: [
|
|
2006
|
+
/* @__PURE__ */ jsxs2("p", { className: "ods-http-panel__desc", children: [
|
|
2007
|
+
"Extract fields from the response with dot paths \u2014 available downstream as",
|
|
2008
|
+
" ",
|
|
2009
|
+
/* @__PURE__ */ jsx2("code", { children: "{{extracted.keyName}}" }),
|
|
2010
|
+
"."
|
|
2011
|
+
] }),
|
|
2012
|
+
/* @__PURE__ */ jsx2(
|
|
2013
|
+
KeyValueEditor,
|
|
2014
|
+
{
|
|
2015
|
+
pairs: extractRows.map((r) => ({ key: r.key, value: r.value })),
|
|
2016
|
+
onChange: (pairs) => {
|
|
2017
|
+
const rows = pairs.map((p) => ({ key: p.key, value: p.value, enabled: true }));
|
|
2018
|
+
setExtractRows(rows);
|
|
2019
|
+
const extract = {};
|
|
2020
|
+
for (const r of rows) if (r.key && r.value) extract[r.key] = r.value;
|
|
2021
|
+
emit({ extract: Object.keys(extract).length ? extract : void 0 });
|
|
2022
|
+
},
|
|
2023
|
+
keyPlaceholder: "outputKey",
|
|
2024
|
+
valuePlaceholder: "data.user.id",
|
|
2025
|
+
emptyLabel: "No extractions yet \u2014 click Add to begin.",
|
|
2026
|
+
addLabel: "Add",
|
|
2027
|
+
size: "sm",
|
|
2028
|
+
disabled
|
|
2029
|
+
}
|
|
2030
|
+
)
|
|
2031
|
+
]
|
|
2032
|
+
}
|
|
2033
|
+
)
|
|
2034
|
+
]
|
|
2035
|
+
}
|
|
2036
|
+
),
|
|
2037
|
+
preview.phase !== "idle" && /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__console", children: [
|
|
2038
|
+
/* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__console-head", children: [
|
|
2039
|
+
/* @__PURE__ */ jsx2(
|
|
2040
|
+
"code",
|
|
2041
|
+
{
|
|
2042
|
+
className: cn(
|
|
2043
|
+
"ods-http-panel__console-method",
|
|
2044
|
+
`ods-http-panel__method--${method.toLowerCase()}`
|
|
2045
|
+
),
|
|
2046
|
+
children: cfg.apiType === "graphql" ? "POST" : method
|
|
2047
|
+
}
|
|
2048
|
+
),
|
|
2049
|
+
/* @__PURE__ */ jsx2("code", { className: "ods-http-panel__console-url", children: connectionId ? `${selectedConnection?.name ?? connectionId} \xB7 ${url || "\u2014"}` : fullUrl || "\u2014" }),
|
|
2050
|
+
preview.phase === "success" && /* @__PURE__ */ jsx2(
|
|
2051
|
+
Button,
|
|
2052
|
+
{
|
|
2053
|
+
variant: "ghost",
|
|
2054
|
+
size: "sm",
|
|
2055
|
+
className: cn(copiedResult && "ods-http-panel__copy-done"),
|
|
2056
|
+
leftIcon: copiedResult ? /* @__PURE__ */ jsx2(CheckmarkIcon, { size: "sm" }) : /* @__PURE__ */ jsx2(CopyIcon, { size: "sm" }),
|
|
2057
|
+
onClick: copyResult,
|
|
2058
|
+
children: copiedResult ? "Copied" : "Copy result"
|
|
2059
|
+
}
|
|
2060
|
+
),
|
|
2061
|
+
/* @__PURE__ */ jsx2(
|
|
2062
|
+
Button,
|
|
2063
|
+
{
|
|
2064
|
+
variant: "ghost",
|
|
2065
|
+
size: "sm",
|
|
2066
|
+
leftIcon: /* @__PURE__ */ jsx2(RenewIcon, { size: "sm" }),
|
|
2067
|
+
onClick: () => {
|
|
2068
|
+
setPreview({ phase: "idle" });
|
|
2069
|
+
},
|
|
2070
|
+
disabled: preview.phase === "loading",
|
|
2071
|
+
children: "Clear"
|
|
2072
|
+
}
|
|
2073
|
+
)
|
|
2074
|
+
] }),
|
|
2075
|
+
preview.phase === "loading" && /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__console-loading", children: [
|
|
2076
|
+
/* @__PURE__ */ jsx2(Spinner, { size: "sm" }),
|
|
2077
|
+
/* @__PURE__ */ jsx2("span", { children: "Sending request\u2026" })
|
|
2078
|
+
] }),
|
|
2079
|
+
preview.phase === "error" && /* @__PURE__ */ jsxs2(Banner, { variant: "error", appearance: "subtle", size: "sm", children: [
|
|
2080
|
+
/* @__PURE__ */ jsx2("strong", { children: "Request failed." }),
|
|
2081
|
+
" ",
|
|
2082
|
+
preview.message
|
|
2083
|
+
] }),
|
|
2084
|
+
preview.phase === "success" && /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__console-result", children: [
|
|
2085
|
+
/* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__console-status", children: [
|
|
2086
|
+
/* @__PURE__ */ jsxs2(Badge, { size: "sm", variant: statusTone(preview.response.status), children: [
|
|
2087
|
+
preview.response.status,
|
|
2088
|
+
" ",
|
|
2089
|
+
preview.response.statusText
|
|
2090
|
+
] }),
|
|
2091
|
+
/* @__PURE__ */ jsxs2("span", { className: "ods-http-panel__meta", children: [
|
|
2092
|
+
preview.response.duration,
|
|
2093
|
+
"ms"
|
|
2094
|
+
] }),
|
|
2095
|
+
/* @__PURE__ */ jsx2("span", { className: "ods-http-panel__meta", children: formatBytes(preview.response.size) })
|
|
2096
|
+
] }),
|
|
2097
|
+
/* @__PURE__ */ jsx2(
|
|
2098
|
+
Accordion,
|
|
2099
|
+
{
|
|
2100
|
+
size: "sm",
|
|
2101
|
+
mode: "multiple",
|
|
2102
|
+
defaultValue: ["res-body"],
|
|
2103
|
+
items: [
|
|
2104
|
+
{
|
|
2105
|
+
id: "res-headers",
|
|
2106
|
+
label: "Response headers",
|
|
2107
|
+
trailing: /* @__PURE__ */ jsx2(Badge, { size: "sm", variant: "neutral", children: Object.keys(preview.response.headers).length }),
|
|
2108
|
+
content: /* @__PURE__ */ jsx2("div", { className: "ods-http-panel__res-headers", children: Object.entries(preview.response.headers).map(([k, v]) => /* @__PURE__ */ jsxs2("div", { className: "ods-http-panel__res-header", children: [
|
|
2109
|
+
/* @__PURE__ */ jsx2("span", { className: "ods-http-panel__res-header-key", children: k }),
|
|
2110
|
+
/* @__PURE__ */ jsx2("span", { className: "ods-http-panel__res-header-val", children: v })
|
|
2111
|
+
] }, k)) })
|
|
2112
|
+
},
|
|
2113
|
+
{
|
|
2114
|
+
id: "res-body",
|
|
2115
|
+
label: "Response body",
|
|
2116
|
+
trailing: !preview.response.ok ? /* @__PURE__ */ jsx2(Badge, { size: "sm", variant: "error", children: "Error" }) : null,
|
|
2117
|
+
content: (
|
|
2118
|
+
// Size guard: the tree view renders recursively (no
|
|
2119
|
+
// virtualization) — very large bodies fall back to text.
|
|
2120
|
+
preview.response.body !== null && typeof preview.response.body === "object" && preview.response.size <= 15e5 ? /* @__PURE__ */ jsx2(
|
|
2121
|
+
JsonViewer,
|
|
2122
|
+
{
|
|
2123
|
+
data: preview.response.body,
|
|
2124
|
+
mode: "view",
|
|
2125
|
+
maxHeight: 320,
|
|
2126
|
+
copyable: true
|
|
2127
|
+
}
|
|
2128
|
+
) : /* @__PURE__ */ jsx2("pre", { className: "ods-http-panel__res-body", children: typeof preview.response.body === "object" ? JSON.stringify(preview.response.body, null, 2) : String(
|
|
2129
|
+
preview.response.bodyRaw ?? preview.response.body ?? "(empty body)"
|
|
2130
|
+
) })
|
|
2131
|
+
)
|
|
2132
|
+
}
|
|
2133
|
+
]
|
|
2134
|
+
}
|
|
2135
|
+
)
|
|
2136
|
+
] })
|
|
2137
|
+
] })
|
|
2138
|
+
] });
|
|
2139
|
+
}
|
|
2140
|
+
|
|
623
2141
|
// src/workflow/components/FxPanel/FxPanel.tsx
|
|
624
2142
|
import {
|
|
625
|
-
useMemo as
|
|
626
|
-
useRef as
|
|
627
|
-
useState as
|
|
2143
|
+
useMemo as useMemo3,
|
|
2144
|
+
useRef as useRef5,
|
|
2145
|
+
useState as useState5
|
|
628
2146
|
} from "react";
|
|
629
2147
|
import {
|
|
630
2148
|
ChevronDownIcon,
|
|
@@ -637,7 +2155,7 @@ import {
|
|
|
637
2155
|
SearchIcon,
|
|
638
2156
|
ValueVariableIcon
|
|
639
2157
|
} from "@octaviaflow/icons";
|
|
640
|
-
import { jsx as
|
|
2158
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
641
2159
|
var KIND_ICON = {
|
|
642
2160
|
function: FunctionMathIcon,
|
|
643
2161
|
variable: ValueVariableIcon
|
|
@@ -696,18 +2214,18 @@ function FxPanel({
|
|
|
696
2214
|
className,
|
|
697
2215
|
style
|
|
698
2216
|
}) {
|
|
699
|
-
const [internalSearch, setInternalSearch] =
|
|
2217
|
+
const [internalSearch, setInternalSearch] = useState5(defaultSearch);
|
|
700
2218
|
const search = controlledSearch ?? internalSearch;
|
|
701
2219
|
const query = search.trim().toLowerCase();
|
|
702
2220
|
const setSearch = (next) => {
|
|
703
2221
|
if (controlledSearch === void 0) setInternalSearch(next);
|
|
704
2222
|
onSearchChange?.(next);
|
|
705
2223
|
};
|
|
706
|
-
const visibleCategories =
|
|
2224
|
+
const visibleCategories = useMemo3(
|
|
707
2225
|
() => categories.filter((c) => c.items.length > 0),
|
|
708
2226
|
[categories]
|
|
709
2227
|
);
|
|
710
|
-
const [internalCat, setInternalCat] =
|
|
2228
|
+
const [internalCat, setInternalCat] = useState5(
|
|
711
2229
|
defaultExpandedCategory !== void 0 ? defaultExpandedCategory : visibleCategories[0]?.id ?? null
|
|
712
2230
|
);
|
|
713
2231
|
const openCategoryId = controlledExpanded ?? internalCat;
|
|
@@ -715,7 +2233,7 @@ function FxPanel({
|
|
|
715
2233
|
if (controlledExpanded === void 0) setInternalCat(id);
|
|
716
2234
|
onExpandedCategoryChange?.(id);
|
|
717
2235
|
};
|
|
718
|
-
const [expandedItems, setExpandedItems] =
|
|
2236
|
+
const [expandedItems, setExpandedItems] = useState5(() => {
|
|
719
2237
|
const ids = /* @__PURE__ */ new Set();
|
|
720
2238
|
for (const cat of categories) {
|
|
721
2239
|
for (const item of cat.items) {
|
|
@@ -744,9 +2262,9 @@ function FxPanel({
|
|
|
744
2262
|
return next;
|
|
745
2263
|
});
|
|
746
2264
|
};
|
|
747
|
-
const [draggingId, setDraggingId] =
|
|
748
|
-
const [focusedId, setFocusedId] =
|
|
749
|
-
const hits =
|
|
2265
|
+
const [draggingId, setDraggingId] = useState5(null);
|
|
2266
|
+
const [focusedId, setFocusedId] = useState5(null);
|
|
2267
|
+
const hits = useMemo3(() => {
|
|
750
2268
|
if (!query) return null;
|
|
751
2269
|
const all = [];
|
|
752
2270
|
for (const cat of visibleCategories) {
|
|
@@ -770,7 +2288,7 @@ function FxPanel({
|
|
|
770
2288
|
e.dataTransfer.effectAllowed = "copy";
|
|
771
2289
|
}
|
|
772
2290
|
};
|
|
773
|
-
const listRef =
|
|
2291
|
+
const listRef = useRef5(null);
|
|
774
2292
|
const focusRow = (id) => {
|
|
775
2293
|
setFocusedId(id);
|
|
776
2294
|
requestAnimationFrame(() => {
|
|
@@ -828,7 +2346,7 @@ function FxPanel({
|
|
|
828
2346
|
break;
|
|
829
2347
|
}
|
|
830
2348
|
};
|
|
831
|
-
const searchRows =
|
|
2349
|
+
const searchRows = useMemo3(
|
|
832
2350
|
() => hits ? hits.map(({ hit }) => ({
|
|
833
2351
|
item: hit.item,
|
|
834
2352
|
depth: 0,
|
|
@@ -842,7 +2360,7 @@ function FxPanel({
|
|
|
842
2360
|
const mono = category.kind === "function";
|
|
843
2361
|
const draggable = !!item.insertValue;
|
|
844
2362
|
const isFocused = focusedId === item.id;
|
|
845
|
-
return /* @__PURE__ */
|
|
2363
|
+
return /* @__PURE__ */ jsxs3(
|
|
846
2364
|
"div",
|
|
847
2365
|
{
|
|
848
2366
|
"data-fx-row": item.id,
|
|
@@ -867,12 +2385,12 @@ function FxPanel({
|
|
|
867
2385
|
},
|
|
868
2386
|
title: item.insertValue,
|
|
869
2387
|
children: [
|
|
870
|
-
Array.from({ length: depth }, (_, i) => /* @__PURE__ */
|
|
871
|
-
hasChildren ? /* @__PURE__ */
|
|
872
|
-
/* @__PURE__ */
|
|
873
|
-
/* @__PURE__ */
|
|
874
|
-
mono ? /* @__PURE__ */
|
|
875
|
-
item.valueType && /* @__PURE__ */
|
|
2388
|
+
Array.from({ length: depth }, (_, i) => /* @__PURE__ */ jsx3("span", { className: "ods-flow-fx-panel__indent", "aria-hidden": "true" }, i)),
|
|
2389
|
+
hasChildren ? /* @__PURE__ */ jsx3("span", { className: "ods-flow-fx-panel__twisty", "aria-hidden": "true", children: expanded ? /* @__PURE__ */ jsx3(ChevronDownIcon, { size: "sm" }) : /* @__PURE__ */ jsx3(ChevronRightIcon, { size: "sm" }) }) : /* @__PURE__ */ jsx3("span", { className: "ods-flow-fx-panel__grip", "aria-hidden": "true", children: /* @__PURE__ */ jsx3(DraggableIcon, { size: "sm" }) }),
|
|
2390
|
+
/* @__PURE__ */ jsxs3("span", { className: "ods-flow-fx-panel__row-main", children: [
|
|
2391
|
+
/* @__PURE__ */ jsxs3("span", { className: "ods-flow-fx-panel__row-line", children: [
|
|
2392
|
+
mono ? /* @__PURE__ */ jsx3("code", { className: "ods-flow-fx-panel__row-label ods-flow-fx-panel__row-label--mono", children: item.label }) : /* @__PURE__ */ jsx3("span", { className: "ods-flow-fx-panel__row-label", children: item.label }),
|
|
2393
|
+
item.valueType && /* @__PURE__ */ jsx3(
|
|
876
2394
|
"span",
|
|
877
2395
|
{
|
|
878
2396
|
className: cn(
|
|
@@ -883,8 +2401,8 @@ function FxPanel({
|
|
|
883
2401
|
}
|
|
884
2402
|
)
|
|
885
2403
|
] }),
|
|
886
|
-
(item.description || crumb) && /* @__PURE__ */
|
|
887
|
-
crumb && /* @__PURE__ */
|
|
2404
|
+
(item.description || crumb) && /* @__PURE__ */ jsxs3("span", { className: "ods-flow-fx-panel__row-sub", children: [
|
|
2405
|
+
crumb && /* @__PURE__ */ jsx3("span", { className: "ods-flow-fx-panel__crumb", children: crumb }),
|
|
888
2406
|
item.description
|
|
889
2407
|
] })
|
|
890
2408
|
] })
|
|
@@ -893,29 +2411,29 @@ function FxPanel({
|
|
|
893
2411
|
item.id
|
|
894
2412
|
);
|
|
895
2413
|
};
|
|
896
|
-
return /* @__PURE__ */
|
|
2414
|
+
return /* @__PURE__ */ jsxs3(
|
|
897
2415
|
"aside",
|
|
898
2416
|
{
|
|
899
2417
|
className: cn("ods-flow-fx-panel", className),
|
|
900
2418
|
style: { width, ...style },
|
|
901
2419
|
"aria-label": typeof title === "string" ? title : "Data References",
|
|
902
2420
|
children: [
|
|
903
|
-
/* @__PURE__ */
|
|
904
|
-
/* @__PURE__ */
|
|
905
|
-
onClose && /* @__PURE__ */
|
|
2421
|
+
/* @__PURE__ */ jsxs3("header", { className: "ods-flow-fx-panel__header", children: [
|
|
2422
|
+
/* @__PURE__ */ jsx3("h3", { className: "ods-flow-fx-panel__title", children: title }),
|
|
2423
|
+
onClose && /* @__PURE__ */ jsx3(
|
|
906
2424
|
"button",
|
|
907
2425
|
{
|
|
908
2426
|
type: "button",
|
|
909
2427
|
className: "ods-flow-fx-panel__close",
|
|
910
2428
|
onClick: onClose,
|
|
911
2429
|
"aria-label": "Close data references",
|
|
912
|
-
children: /* @__PURE__ */
|
|
2430
|
+
children: /* @__PURE__ */ jsx3(CloseIcon, { size: "sm" })
|
|
913
2431
|
}
|
|
914
2432
|
)
|
|
915
2433
|
] }),
|
|
916
|
-
/* @__PURE__ */
|
|
917
|
-
/* @__PURE__ */
|
|
918
|
-
/* @__PURE__ */
|
|
2434
|
+
/* @__PURE__ */ jsxs3("div", { className: "ods-flow-fx-panel__search", children: [
|
|
2435
|
+
/* @__PURE__ */ jsx3("span", { className: "ods-flow-fx-panel__search-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx3(SearchIcon, { size: "sm" }) }),
|
|
2436
|
+
/* @__PURE__ */ jsx3(
|
|
919
2437
|
"input",
|
|
920
2438
|
{
|
|
921
2439
|
type: "text",
|
|
@@ -926,21 +2444,21 @@ function FxPanel({
|
|
|
926
2444
|
onChange: (e) => setSearch(e.target.value)
|
|
927
2445
|
}
|
|
928
2446
|
),
|
|
929
|
-
search && /* @__PURE__ */
|
|
2447
|
+
search && /* @__PURE__ */ jsx3(
|
|
930
2448
|
"button",
|
|
931
2449
|
{
|
|
932
2450
|
type: "button",
|
|
933
2451
|
className: "ods-flow-fx-panel__search-clear",
|
|
934
2452
|
onClick: () => setSearch(""),
|
|
935
2453
|
"aria-label": "Clear search",
|
|
936
|
-
children: /* @__PURE__ */
|
|
2454
|
+
children: /* @__PURE__ */ jsx3(CloseIcon, { size: "sm" })
|
|
937
2455
|
}
|
|
938
2456
|
)
|
|
939
2457
|
] }),
|
|
940
|
-
hint && !query && /* @__PURE__ */
|
|
941
|
-
/* @__PURE__ */
|
|
942
|
-
query && hits && (hits.length > 0 ? /* @__PURE__ */
|
|
943
|
-
/* @__PURE__ */
|
|
2458
|
+
hint && !query && /* @__PURE__ */ jsx3("p", { className: "ods-flow-fx-panel__hint", children: hint }),
|
|
2459
|
+
/* @__PURE__ */ jsxs3("div", { className: "ods-flow-fx-panel__list", ref: listRef, role: "tree", children: [
|
|
2460
|
+
query && hits && (hits.length > 0 ? /* @__PURE__ */ jsxs3("div", { className: "ods-flow-fx-panel__results", children: [
|
|
2461
|
+
/* @__PURE__ */ jsxs3("div", { className: "ods-flow-fx-panel__results-count", children: [
|
|
944
2462
|
hits.length,
|
|
945
2463
|
" ",
|
|
946
2464
|
hits.length === 1 ? "match" : "matches"
|
|
@@ -953,7 +2471,7 @@ function FxPanel({
|
|
|
953
2471
|
hit.ancestors.length ? hit.ancestors.join(" / ") : category.label
|
|
954
2472
|
)
|
|
955
2473
|
)
|
|
956
|
-
] }) : /* @__PURE__ */
|
|
2474
|
+
] }) : /* @__PURE__ */ jsx3("div", { className: "ods-flow-fx-panel__empty", children: emptyLabel })),
|
|
957
2475
|
!query && visibleCategories.map((cat) => {
|
|
958
2476
|
const isOpen = openCategoryId === cat.id;
|
|
959
2477
|
const kind = cat.kind ?? "function";
|
|
@@ -964,8 +2482,8 @@ function FxPanel({
|
|
|
964
2482
|
const rows = [];
|
|
965
2483
|
if (isOpen) flattenTree(cat.items, 0, expandedItems, rows);
|
|
966
2484
|
const allExpanded = hasTree && [...branchIds].every((id) => expandedItems.has(id));
|
|
967
|
-
return /* @__PURE__ */
|
|
968
|
-
/* @__PURE__ */
|
|
2485
|
+
return /* @__PURE__ */ jsxs3("div", { className: "ods-flow-fx-panel__category", children: [
|
|
2486
|
+
/* @__PURE__ */ jsxs3(
|
|
969
2487
|
"div",
|
|
970
2488
|
{
|
|
971
2489
|
className: cn(
|
|
@@ -973,7 +2491,7 @@ function FxPanel({
|
|
|
973
2491
|
isOpen && "ods-flow-fx-panel__cat-header--open"
|
|
974
2492
|
),
|
|
975
2493
|
children: [
|
|
976
|
-
/* @__PURE__ */
|
|
2494
|
+
/* @__PURE__ */ jsxs3(
|
|
977
2495
|
"button",
|
|
978
2496
|
{
|
|
979
2497
|
type: "button",
|
|
@@ -981,7 +2499,7 @@ function FxPanel({
|
|
|
981
2499
|
"aria-expanded": isOpen,
|
|
982
2500
|
onClick: () => setOpenCategory(isOpen ? null : cat.id),
|
|
983
2501
|
children: [
|
|
984
|
-
/* @__PURE__ */
|
|
2502
|
+
/* @__PURE__ */ jsx3(
|
|
985
2503
|
ChevronRightIcon,
|
|
986
2504
|
{
|
|
987
2505
|
size: "sm",
|
|
@@ -991,7 +2509,7 @@ function FxPanel({
|
|
|
991
2509
|
)
|
|
992
2510
|
}
|
|
993
2511
|
),
|
|
994
|
-
/* @__PURE__ */
|
|
2512
|
+
/* @__PURE__ */ jsxs3(
|
|
995
2513
|
"span",
|
|
996
2514
|
{
|
|
997
2515
|
className: cn(
|
|
@@ -999,7 +2517,7 @@ function FxPanel({
|
|
|
999
2517
|
`ods-flow-fx-panel__badge--${kind}`
|
|
1000
2518
|
),
|
|
1001
2519
|
children: [
|
|
1002
|
-
/* @__PURE__ */
|
|
2520
|
+
/* @__PURE__ */ jsx3(
|
|
1003
2521
|
KindIcon,
|
|
1004
2522
|
{
|
|
1005
2523
|
size: "sm",
|
|
@@ -1010,11 +2528,11 @@ function FxPanel({
|
|
|
1010
2528
|
]
|
|
1011
2529
|
}
|
|
1012
2530
|
),
|
|
1013
|
-
/* @__PURE__ */
|
|
2531
|
+
/* @__PURE__ */ jsx3("span", { className: "ods-flow-fx-panel__count", children: countLeaves(cat.items) })
|
|
1014
2532
|
]
|
|
1015
2533
|
}
|
|
1016
2534
|
),
|
|
1017
|
-
isOpen && hasTree && /* @__PURE__ */
|
|
2535
|
+
isOpen && hasTree && /* @__PURE__ */ jsx3(
|
|
1018
2536
|
"button",
|
|
1019
2537
|
{
|
|
1020
2538
|
type: "button",
|
|
@@ -1022,13 +2540,13 @@ function FxPanel({
|
|
|
1022
2540
|
"aria-label": allExpanded ? "Collapse all" : "Expand all",
|
|
1023
2541
|
title: allExpanded ? "Collapse all" : "Expand all",
|
|
1024
2542
|
onClick: () => setCategoryExpansion(cat, !allExpanded),
|
|
1025
|
-
children: allExpanded ? /* @__PURE__ */
|
|
2543
|
+
children: allExpanded ? /* @__PURE__ */ jsx3(CollapseAllIcon, { size: "sm" }) : /* @__PURE__ */ jsx3(ExpandAllIcon, { size: "sm" })
|
|
1026
2544
|
}
|
|
1027
2545
|
)
|
|
1028
2546
|
]
|
|
1029
2547
|
}
|
|
1030
2548
|
),
|
|
1031
|
-
isOpen && /* @__PURE__ */
|
|
2549
|
+
isOpen && /* @__PURE__ */ jsx3(
|
|
1032
2550
|
"div",
|
|
1033
2551
|
{
|
|
1034
2552
|
className: "ods-flow-fx-panel__rows",
|
|
@@ -1047,7 +2565,7 @@ function FxPanel({
|
|
|
1047
2565
|
|
|
1048
2566
|
// src/workflow/components/FxPanel/DataRefButton.tsx
|
|
1049
2567
|
import { DataReferenceIcon } from "@octaviaflow/icons";
|
|
1050
|
-
import { jsx as
|
|
2568
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1051
2569
|
function DataRefButton({
|
|
1052
2570
|
active = false,
|
|
1053
2571
|
label = "Data ref",
|
|
@@ -1055,7 +2573,7 @@ function DataRefButton({
|
|
|
1055
2573
|
type = "button",
|
|
1056
2574
|
...rest
|
|
1057
2575
|
}) {
|
|
1058
|
-
return /* @__PURE__ */
|
|
2576
|
+
return /* @__PURE__ */ jsxs4(
|
|
1059
2577
|
"button",
|
|
1060
2578
|
{
|
|
1061
2579
|
...rest,
|
|
@@ -1069,21 +2587,21 @@ function DataRefButton({
|
|
|
1069
2587
|
"aria-pressed": active,
|
|
1070
2588
|
title: active ? "Hide data references" : "Show data references",
|
|
1071
2589
|
children: [
|
|
1072
|
-
/* @__PURE__ */
|
|
2590
|
+
/* @__PURE__ */ jsx4(
|
|
1073
2591
|
DataReferenceIcon,
|
|
1074
2592
|
{
|
|
1075
2593
|
size: "sm",
|
|
1076
2594
|
className: "ods-flow-dataref-button__icon"
|
|
1077
2595
|
}
|
|
1078
2596
|
),
|
|
1079
|
-
label != null && /* @__PURE__ */
|
|
2597
|
+
label != null && /* @__PURE__ */ jsx4("span", { className: "ods-flow-dataref-button__label", children: label })
|
|
1080
2598
|
]
|
|
1081
2599
|
}
|
|
1082
2600
|
);
|
|
1083
2601
|
}
|
|
1084
2602
|
|
|
1085
2603
|
// src/workflow/components/NodeToolbar/NodeToolbar.tsx
|
|
1086
|
-
import { jsx as
|
|
2604
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
1087
2605
|
function NodeToolbar({
|
|
1088
2606
|
isVisible,
|
|
1089
2607
|
position = "top",
|
|
@@ -1098,7 +2616,7 @@ function NodeToolbar({
|
|
|
1098
2616
|
const show = isVisible ?? node.selected;
|
|
1099
2617
|
if (!show) return null;
|
|
1100
2618
|
const inverseScale = 1 / viewport.zoom;
|
|
1101
|
-
return /* @__PURE__ */
|
|
2619
|
+
return /* @__PURE__ */ jsx5(
|
|
1102
2620
|
"div",
|
|
1103
2621
|
{
|
|
1104
2622
|
className: cn("ods-node-toolbar", `ods-node-toolbar--${position}`, className),
|
|
@@ -1110,7 +2628,7 @@ function NodeToolbar({
|
|
|
1110
2628
|
onPointerDown: (e) => e.stopPropagation(),
|
|
1111
2629
|
onMouseDown: (e) => e.stopPropagation(),
|
|
1112
2630
|
onClick: (e) => e.stopPropagation(),
|
|
1113
|
-
children: /* @__PURE__ */
|
|
2631
|
+
children: /* @__PURE__ */ jsx5(
|
|
1114
2632
|
"div",
|
|
1115
2633
|
{
|
|
1116
2634
|
className: "ods-node-toolbar__inner",
|
|
@@ -1266,7 +2784,10 @@ export {
|
|
|
1266
2784
|
ForEachNode,
|
|
1267
2785
|
FxPanel,
|
|
1268
2786
|
GroupNode,
|
|
2787
|
+
HTTP_ACTION_DEFAULTS,
|
|
2788
|
+
HTTP_METHODS,
|
|
1269
2789
|
Handle,
|
|
2790
|
+
HttpActionPanel,
|
|
1270
2791
|
HttpRequestNode,
|
|
1271
2792
|
NodeResizer,
|
|
1272
2793
|
NodeToolbar,
|
|
@@ -1280,19 +2801,28 @@ export {
|
|
|
1280
2801
|
applyNodeChanges,
|
|
1281
2802
|
bezierPath2 as bezierPath,
|
|
1282
2803
|
bezierPath as bezierPathFn,
|
|
2804
|
+
buildCurl,
|
|
1283
2805
|
buildEdgePath,
|
|
1284
2806
|
buildNodeKindRegistry,
|
|
1285
2807
|
change,
|
|
1286
2808
|
clampToParentExtent,
|
|
1287
2809
|
collapseFor,
|
|
2810
|
+
countGraphqlVariables,
|
|
2811
|
+
countSchemaPaths,
|
|
1288
2812
|
createDagreEngine,
|
|
1289
2813
|
createElkEngine,
|
|
1290
2814
|
descendantsOf,
|
|
2815
|
+
effectiveUrl,
|
|
1291
2816
|
findAncestor,
|
|
1292
2817
|
findContainingGroup,
|
|
1293
2818
|
flowToScreen,
|
|
1294
2819
|
handleCentre,
|
|
2820
|
+
inferJsonSchema,
|
|
2821
|
+
normalizeAuth,
|
|
2822
|
+
normalizeKeyValues,
|
|
2823
|
+
parseCurl,
|
|
1295
2824
|
screenToFlow,
|
|
2825
|
+
serializeKeyValues,
|
|
1296
2826
|
smoothStepPath,
|
|
1297
2827
|
stepPath,
|
|
1298
2828
|
straightPath,
|
|
@@ -1312,6 +2842,7 @@ export {
|
|
|
1312
2842
|
useNodes,
|
|
1313
2843
|
useSelection,
|
|
1314
2844
|
useViewport,
|
|
1315
|
-
useViewportOrNull
|
|
2845
|
+
useViewportOrNull,
|
|
2846
|
+
validateHttpConfig
|
|
1316
2847
|
};
|
|
1317
2848
|
//# sourceMappingURL=workflow.js.map
|