@calimero-network/mero-react 4.0.1 → 4.1.1
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/index.cjs +324 -44
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +56 -2
- package/dist/index.d.ts +56 -2
- package/dist/index.js +320 -45
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -268,14 +268,19 @@ function MeroProvider({
|
|
|
268
268
|
},
|
|
269
269
|
[timeoutMs, tokenStore]
|
|
270
270
|
);
|
|
271
|
-
const checkAuth = useCallback(
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
return
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
271
|
+
const checkAuth = useCallback(
|
|
272
|
+
async (instance) => {
|
|
273
|
+
const accessToken = tokenStore.getTokens()?.access_token;
|
|
274
|
+
if (!accessToken) return false;
|
|
275
|
+
try {
|
|
276
|
+
const { valid } = await instance.auth.validateToken(accessToken);
|
|
277
|
+
return valid;
|
|
278
|
+
} catch {
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
[tokenStore]
|
|
283
|
+
);
|
|
279
284
|
const connectToNode = useCallback(
|
|
280
285
|
(url) => {
|
|
281
286
|
if (!isBrowser) return;
|
|
@@ -473,6 +478,59 @@ function CalimeroLogo({
|
|
|
473
478
|
);
|
|
474
479
|
}
|
|
475
480
|
|
|
481
|
+
// src/utils/nodeDiscovery.ts
|
|
482
|
+
var DEFAULT_LOCAL_NODE_PORTS = [2428, 2429, 2528, 2529];
|
|
483
|
+
var LOCAL_HOST = "localhost";
|
|
484
|
+
var DEFAULT_PROBE_TIMEOUT_MS = 2e3;
|
|
485
|
+
function localNodeUrl(port) {
|
|
486
|
+
return `http://${LOCAL_HOST}:${port}`;
|
|
487
|
+
}
|
|
488
|
+
function nodeEndpoint(baseUrl, path) {
|
|
489
|
+
const base = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
|
|
490
|
+
return new URL(path, base).toString();
|
|
491
|
+
}
|
|
492
|
+
async function probeNodeHealth(baseUrl, options = {}) {
|
|
493
|
+
const { timeoutMs = DEFAULT_PROBE_TIMEOUT_MS, signal } = options;
|
|
494
|
+
if (signal?.aborted) return false;
|
|
495
|
+
const controller = new AbortController();
|
|
496
|
+
const onAbort = () => controller.abort();
|
|
497
|
+
const listenerAdded = !!signal;
|
|
498
|
+
if (listenerAdded) signal.addEventListener("abort", onAbort, { once: true });
|
|
499
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
500
|
+
try {
|
|
501
|
+
const url = nodeEndpoint(baseUrl, "admin-api/health");
|
|
502
|
+
const res = await fetch(url, {
|
|
503
|
+
method: "GET",
|
|
504
|
+
signal: controller.signal
|
|
505
|
+
});
|
|
506
|
+
if (!res.ok) return false;
|
|
507
|
+
try {
|
|
508
|
+
const body = await res.json();
|
|
509
|
+
const status = body?.data?.status !== void 0 ? body?.data?.status : body?.status;
|
|
510
|
+
if (status === void 0) return true;
|
|
511
|
+
return typeof status === "string" && status.toLowerCase() === "alive";
|
|
512
|
+
} catch {
|
|
513
|
+
return true;
|
|
514
|
+
}
|
|
515
|
+
} catch {
|
|
516
|
+
return false;
|
|
517
|
+
} finally {
|
|
518
|
+
clearTimeout(timer);
|
|
519
|
+
if (listenerAdded) signal.removeEventListener("abort", onAbort);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
async function discoverLocalNodes(options = {}) {
|
|
523
|
+
const { ports = DEFAULT_LOCAL_NODE_PORTS, timeoutMs, signal } = options;
|
|
524
|
+
const results = await Promise.all(
|
|
525
|
+
ports.map(async (port) => {
|
|
526
|
+
const url = localNodeUrl(port);
|
|
527
|
+
const ok = await probeNodeHealth(url, { timeoutMs, signal });
|
|
528
|
+
return ok ? url : null;
|
|
529
|
+
})
|
|
530
|
+
);
|
|
531
|
+
return results.filter((url) => url !== null);
|
|
532
|
+
}
|
|
533
|
+
|
|
476
534
|
// src/theme.ts
|
|
477
535
|
var defaultMeroTheme = Object.freeze({
|
|
478
536
|
primary: "#a5ff11",
|
|
@@ -521,6 +579,8 @@ function themeToCssVars(theme) {
|
|
|
521
579
|
function cssVar(theme, key) {
|
|
522
580
|
return `var(${MERO_CSS_VARS[key]}, ${theme[key]})`;
|
|
523
581
|
}
|
|
582
|
+
var DEFAULT_LOCAL_NODE_URL = "http://node1.127.0.0.1.nip.io";
|
|
583
|
+
var CUSTOM_SELECTION = "__custom__";
|
|
524
584
|
function isValidUrl(urlString) {
|
|
525
585
|
if (!urlString || urlString.trim() === "") {
|
|
526
586
|
return false;
|
|
@@ -549,6 +609,9 @@ function isValidUrl(urlString) {
|
|
|
549
609
|
return false;
|
|
550
610
|
}
|
|
551
611
|
}
|
|
612
|
+
function displayNodeUrl(url) {
|
|
613
|
+
return url.replace(/^https?:\/\//, "").replace(/\/+$/, "");
|
|
614
|
+
}
|
|
552
615
|
function tint(color, percent) {
|
|
553
616
|
return `color-mix(in srgb, ${color} ${percent}%, transparent)`;
|
|
554
617
|
}
|
|
@@ -653,10 +716,60 @@ function buildStyles(t) {
|
|
|
653
716
|
transition: "all 0.15s ease"
|
|
654
717
|
},
|
|
655
718
|
radioLabelActive: {
|
|
656
|
-
|
|
719
|
+
border: `1px solid ${accent}`,
|
|
657
720
|
backgroundColor: accentGlow,
|
|
658
721
|
color: text
|
|
659
722
|
},
|
|
723
|
+
radioList: {
|
|
724
|
+
display: "flex",
|
|
725
|
+
flexDirection: "column",
|
|
726
|
+
gap: "0.5rem",
|
|
727
|
+
marginBottom: "1rem"
|
|
728
|
+
},
|
|
729
|
+
radioItem: {
|
|
730
|
+
display: "flex",
|
|
731
|
+
alignItems: "center",
|
|
732
|
+
gap: "0.625rem",
|
|
733
|
+
color: text,
|
|
734
|
+
cursor: "pointer",
|
|
735
|
+
padding: "0.75rem 1rem",
|
|
736
|
+
borderRadius: radius,
|
|
737
|
+
border: `1px solid ${border}`,
|
|
738
|
+
backgroundColor: bgSecondary,
|
|
739
|
+
transition: "all 0.15s ease",
|
|
740
|
+
fontSize: "0.875rem"
|
|
741
|
+
},
|
|
742
|
+
radioItemActive: {
|
|
743
|
+
// Override the full `border` shorthand (not just borderColor) so React
|
|
744
|
+
// never has to mix shorthand + longhand on the same element.
|
|
745
|
+
border: `1px solid ${accent}`,
|
|
746
|
+
backgroundColor: accentGlow,
|
|
747
|
+
color: text
|
|
748
|
+
},
|
|
749
|
+
radioIndicator: {
|
|
750
|
+
flexShrink: 0,
|
|
751
|
+
width: "1rem",
|
|
752
|
+
height: "1rem",
|
|
753
|
+
borderRadius: "50%",
|
|
754
|
+
border: `2px solid ${border}`,
|
|
755
|
+
display: "flex",
|
|
756
|
+
alignItems: "center",
|
|
757
|
+
justifyContent: "center"
|
|
758
|
+
},
|
|
759
|
+
radioIndicatorActive: {
|
|
760
|
+
border: `2px solid ${accent}`
|
|
761
|
+
},
|
|
762
|
+
radioDot: {
|
|
763
|
+
width: "0.5rem",
|
|
764
|
+
height: "0.5rem",
|
|
765
|
+
borderRadius: "50%",
|
|
766
|
+
backgroundColor: accent
|
|
767
|
+
},
|
|
768
|
+
nodeMeta: {
|
|
769
|
+
marginLeft: "auto",
|
|
770
|
+
fontSize: "0.75rem",
|
|
771
|
+
color: textSecondary
|
|
772
|
+
},
|
|
660
773
|
input: {
|
|
661
774
|
width: "100%",
|
|
662
775
|
padding: "0.75rem 1rem",
|
|
@@ -682,6 +795,29 @@ function buildStyles(t) {
|
|
|
682
795
|
localInfoCode: {
|
|
683
796
|
color: accent
|
|
684
797
|
},
|
|
798
|
+
noNodeInfo: {
|
|
799
|
+
color: textSecondary,
|
|
800
|
+
fontSize: "0.875rem",
|
|
801
|
+
textAlign: "center",
|
|
802
|
+
padding: "0.75rem",
|
|
803
|
+
backgroundColor: bgSecondary,
|
|
804
|
+
borderRadius: radius,
|
|
805
|
+
marginBottom: "1rem",
|
|
806
|
+
border: `1px solid ${border}`
|
|
807
|
+
},
|
|
808
|
+
toolbar: {
|
|
809
|
+
display: "flex",
|
|
810
|
+
justifyContent: "center",
|
|
811
|
+
marginBottom: "1rem"
|
|
812
|
+
},
|
|
813
|
+
rescan: {
|
|
814
|
+
background: "none",
|
|
815
|
+
border: "none",
|
|
816
|
+
color: accent,
|
|
817
|
+
cursor: "pointer",
|
|
818
|
+
fontSize: "0.8125rem",
|
|
819
|
+
padding: "0.25rem 0.5rem"
|
|
820
|
+
},
|
|
685
821
|
buttonGroup: {
|
|
686
822
|
display: "flex",
|
|
687
823
|
justifyContent: "center"
|
|
@@ -709,6 +845,15 @@ function buildStyles(t) {
|
|
|
709
845
|
padding: "2rem",
|
|
710
846
|
color: textSecondary
|
|
711
847
|
},
|
|
848
|
+
discovering: {
|
|
849
|
+
display: "flex",
|
|
850
|
+
flexDirection: "column",
|
|
851
|
+
alignItems: "center",
|
|
852
|
+
gap: "0.75rem",
|
|
853
|
+
padding: "1rem",
|
|
854
|
+
color: textSecondary,
|
|
855
|
+
fontSize: "0.875rem"
|
|
856
|
+
},
|
|
712
857
|
spinner: {
|
|
713
858
|
width: "2rem",
|
|
714
859
|
height: "2rem",
|
|
@@ -716,6 +861,14 @@ function buildStyles(t) {
|
|
|
716
861
|
borderTopColor: accent,
|
|
717
862
|
borderRadius: "50%",
|
|
718
863
|
animation: "meroSpin 1s linear infinite"
|
|
864
|
+
},
|
|
865
|
+
spinnerSmall: {
|
|
866
|
+
width: "1.5rem",
|
|
867
|
+
height: "1.5rem",
|
|
868
|
+
border: `3px solid ${border}`,
|
|
869
|
+
borderTopColor: accent,
|
|
870
|
+
borderRadius: "50%",
|
|
871
|
+
animation: "meroSpin 1s linear infinite"
|
|
719
872
|
}
|
|
720
873
|
};
|
|
721
874
|
}
|
|
@@ -724,11 +877,14 @@ function LoginModal({
|
|
|
724
877
|
onClose,
|
|
725
878
|
connectionType,
|
|
726
879
|
isOpen,
|
|
727
|
-
theme
|
|
880
|
+
theme,
|
|
881
|
+
localNodePorts = DEFAULT_LOCAL_NODE_PORTS
|
|
728
882
|
}) {
|
|
729
883
|
const [nodeType, setNodeType] = useState("local");
|
|
730
|
-
const [
|
|
731
|
-
const [
|
|
884
|
+
const [selected, setSelected] = useState(CUSTOM_SELECTION);
|
|
885
|
+
const [discovered, setDiscovered] = useState([]);
|
|
886
|
+
const [discovering, setDiscovering] = useState(false);
|
|
887
|
+
const [customUrl, setCustomUrl] = useState("");
|
|
732
888
|
const [loading, setLoading] = useState(false);
|
|
733
889
|
const [error, setError] = useState(null);
|
|
734
890
|
const resolved = useMemo(() => resolveMeroTheme(theme), [theme]);
|
|
@@ -743,7 +899,7 @@ function LoginModal({
|
|
|
743
899
|
useEffect(() => {
|
|
744
900
|
const savedUrl = localStorage.getItem("mero:node_url");
|
|
745
901
|
if (savedUrl) {
|
|
746
|
-
|
|
902
|
+
setCustomUrl(savedUrl);
|
|
747
903
|
}
|
|
748
904
|
}, []);
|
|
749
905
|
useEffect(() => {
|
|
@@ -753,25 +909,56 @@ function LoginModal({
|
|
|
753
909
|
setNodeType("remote");
|
|
754
910
|
}
|
|
755
911
|
}, [connectionType]);
|
|
912
|
+
const [scanNonce, setScanNonce] = useState(0);
|
|
913
|
+
const portsKey = useMemo(() => localNodePorts.join(","), [localNodePorts]);
|
|
914
|
+
const remoteActive = isOpen && shouldShowRemote && nodeType === "remote";
|
|
756
915
|
useEffect(() => {
|
|
757
|
-
if (
|
|
758
|
-
|
|
759
|
-
} else {
|
|
760
|
-
setIsValid(true);
|
|
916
|
+
if (!remoteActive) {
|
|
917
|
+
return;
|
|
761
918
|
}
|
|
762
|
-
|
|
919
|
+
const controller = new AbortController();
|
|
920
|
+
let active = true;
|
|
921
|
+
setDiscovering(true);
|
|
922
|
+
setDiscovered([]);
|
|
923
|
+
setError(null);
|
|
924
|
+
discoverLocalNodes({ ports: localNodePorts, signal: controller.signal }).then((nodes) => {
|
|
925
|
+
if (!active) return;
|
|
926
|
+
setDiscovered(nodes);
|
|
927
|
+
setSelected(nodes.length > 0 ? nodes[0] : CUSTOM_SELECTION);
|
|
928
|
+
}).catch(() => {
|
|
929
|
+
if (active) setSelected(CUSTOM_SELECTION);
|
|
930
|
+
}).finally(() => {
|
|
931
|
+
if (active) setDiscovering(false);
|
|
932
|
+
});
|
|
933
|
+
return () => {
|
|
934
|
+
active = false;
|
|
935
|
+
controller.abort();
|
|
936
|
+
};
|
|
937
|
+
}, [remoteActive, portsKey, scanNonce]);
|
|
938
|
+
const isCustom = selected === CUSTOM_SELECTION;
|
|
939
|
+
const hasDiscovered = discovered.length > 0;
|
|
940
|
+
const canConnect = !loading && (nodeType === "local" ? true : discovering ? false : isCustom ? isValidUrl(customUrl) : true);
|
|
941
|
+
const canConnectRef = useRef(canConnect);
|
|
942
|
+
canConnectRef.current = canConnect;
|
|
763
943
|
const handleConnect = useCallback(async () => {
|
|
764
|
-
|
|
944
|
+
const targetUrl = nodeType === "local" ? DEFAULT_LOCAL_NODE_URL : selected === CUSTOM_SELECTION ? customUrl : selected;
|
|
945
|
+
const usingDiscovered = nodeType === "remote" && selected !== CUSTOM_SELECTION;
|
|
946
|
+
if (nodeType === "remote" && !usingDiscovered && !isValidUrl(targetUrl)) {
|
|
947
|
+
return;
|
|
948
|
+
}
|
|
949
|
+
const normalizedUrl = targetUrl.replace(/\/+$/, "");
|
|
950
|
+
if (usingDiscovered) {
|
|
951
|
+
onConnect(normalizedUrl);
|
|
952
|
+
return;
|
|
953
|
+
}
|
|
765
954
|
setLoading(true);
|
|
766
955
|
setError(null);
|
|
767
|
-
const baseUrl = nodeType === "local" ? "http://node1.127.0.0.1.nip.io" : nodeUrl;
|
|
768
956
|
try {
|
|
769
957
|
const response = await fetch(
|
|
770
|
-
|
|
958
|
+
nodeEndpoint(normalizedUrl, "admin-api/is-authed")
|
|
771
959
|
);
|
|
772
960
|
if (response.ok || response.status === 401) {
|
|
773
961
|
setLoading(false);
|
|
774
|
-
const normalizedUrl = baseUrl.replace(/\/+$/, "");
|
|
775
962
|
onConnect(normalizedUrl);
|
|
776
963
|
} else {
|
|
777
964
|
throw new Error(`Connection failed: ${response.statusText}`);
|
|
@@ -781,10 +968,108 @@ function LoginModal({
|
|
|
781
968
|
setError("Failed to connect. Please check the URL and try again.");
|
|
782
969
|
setLoading(false);
|
|
783
970
|
}
|
|
784
|
-
}, [
|
|
971
|
+
}, [nodeType, selected, customUrl, onConnect]);
|
|
785
972
|
if (!isOpen) {
|
|
786
973
|
return null;
|
|
787
974
|
}
|
|
975
|
+
const showManualInput = isCustom;
|
|
976
|
+
const renderRadio = (value, label, meta) => {
|
|
977
|
+
const active = selected === value;
|
|
978
|
+
return (
|
|
979
|
+
// Selection is driven solely by the radio input's `onChange` — clicking
|
|
980
|
+
// anywhere on the wrapping label forwards to the input, and keyboard
|
|
981
|
+
// users can tab to / arrow through the (visually hidden but focusable)
|
|
982
|
+
// input. A label `onClick` here would double-fire `setSelected`.
|
|
983
|
+
/* @__PURE__ */ jsxs(
|
|
984
|
+
"label",
|
|
985
|
+
{
|
|
986
|
+
"data-testid": `node-option-${value === CUSTOM_SELECTION ? "custom" : displayNodeUrl(value)}`,
|
|
987
|
+
style: {
|
|
988
|
+
...styles.radioItem,
|
|
989
|
+
...active ? styles.radioItemActive : {}
|
|
990
|
+
},
|
|
991
|
+
children: [
|
|
992
|
+
/* @__PURE__ */ jsx(
|
|
993
|
+
"input",
|
|
994
|
+
{
|
|
995
|
+
type: "radio",
|
|
996
|
+
name: "mero-node",
|
|
997
|
+
value,
|
|
998
|
+
checked: active,
|
|
999
|
+
onChange: () => setSelected(value),
|
|
1000
|
+
style: { position: "absolute", opacity: 0 }
|
|
1001
|
+
}
|
|
1002
|
+
),
|
|
1003
|
+
/* @__PURE__ */ jsx(
|
|
1004
|
+
"span",
|
|
1005
|
+
{
|
|
1006
|
+
style: {
|
|
1007
|
+
...styles.radioIndicator,
|
|
1008
|
+
...active ? styles.radioIndicatorActive : {}
|
|
1009
|
+
},
|
|
1010
|
+
children: active && /* @__PURE__ */ jsx("span", { style: styles.radioDot })
|
|
1011
|
+
}
|
|
1012
|
+
),
|
|
1013
|
+
label,
|
|
1014
|
+
meta && /* @__PURE__ */ jsx("span", { style: styles.nodeMeta, children: meta })
|
|
1015
|
+
]
|
|
1016
|
+
},
|
|
1017
|
+
value
|
|
1018
|
+
)
|
|
1019
|
+
);
|
|
1020
|
+
};
|
|
1021
|
+
const renderRemoteView = () => {
|
|
1022
|
+
if (discovering) {
|
|
1023
|
+
return /* @__PURE__ */ jsxs("div", { style: styles.discovering, "data-testid": "node-discovering", children: [
|
|
1024
|
+
/* @__PURE__ */ jsx("div", { style: styles.spinnerSmall }),
|
|
1025
|
+
/* @__PURE__ */ jsx("p", { children: "Searching for local nodes..." })
|
|
1026
|
+
] });
|
|
1027
|
+
}
|
|
1028
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1029
|
+
/* @__PURE__ */ jsx("p", { style: styles.info, children: hasDiscovered ? "Select a discovered node, or enter a node URL manually." : "No local node found. Enter a node URL to continue." }),
|
|
1030
|
+
hasDiscovered && /* @__PURE__ */ jsxs(
|
|
1031
|
+
"div",
|
|
1032
|
+
{
|
|
1033
|
+
style: styles.radioList,
|
|
1034
|
+
role: "radiogroup",
|
|
1035
|
+
"aria-label": "Available nodes",
|
|
1036
|
+
children: [
|
|
1037
|
+
discovered.map(
|
|
1038
|
+
(url) => renderRadio(url, displayNodeUrl(url), "local")
|
|
1039
|
+
),
|
|
1040
|
+
renderRadio(CUSTOM_SELECTION, "Enter node URL manually")
|
|
1041
|
+
]
|
|
1042
|
+
}
|
|
1043
|
+
),
|
|
1044
|
+
showManualInput && /* @__PURE__ */ jsx(
|
|
1045
|
+
"input",
|
|
1046
|
+
{
|
|
1047
|
+
type: "text",
|
|
1048
|
+
value: customUrl,
|
|
1049
|
+
onChange: (e) => setCustomUrl(e.target.value),
|
|
1050
|
+
placeholder: "https://your-node-url.calimero.network",
|
|
1051
|
+
style: styles.input,
|
|
1052
|
+
"data-testid": "node-url-input",
|
|
1053
|
+
autoFocus: !hasDiscovered,
|
|
1054
|
+
onKeyDown: (e) => {
|
|
1055
|
+
if (e.key === "Enter" && canConnectRef.current) {
|
|
1056
|
+
handleConnect();
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
),
|
|
1061
|
+
/* @__PURE__ */ jsx("div", { style: styles.toolbar, children: /* @__PURE__ */ jsx(
|
|
1062
|
+
"button",
|
|
1063
|
+
{
|
|
1064
|
+
type: "button",
|
|
1065
|
+
style: styles.rescan,
|
|
1066
|
+
onClick: () => setScanNonce((n) => n + 1),
|
|
1067
|
+
"data-testid": "rescan-button",
|
|
1068
|
+
children: "\u21BB Rescan local nodes"
|
|
1069
|
+
}
|
|
1070
|
+
) })
|
|
1071
|
+
] });
|
|
1072
|
+
};
|
|
788
1073
|
const modalContent = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
789
1074
|
/* @__PURE__ */ jsx("style", { children: `
|
|
790
1075
|
@keyframes meroSpin { to { transform: rotate(360deg); } }
|
|
@@ -792,7 +1077,7 @@ function LoginModal({
|
|
|
792
1077
|
@keyframes meroSlideIn { from { transform: translateY(-12px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
|
|
793
1078
|
` }),
|
|
794
1079
|
/* @__PURE__ */ jsx("div", { style: { ...themeVars, ...styles.overlay }, onClick: onClose, children: /* @__PURE__ */ jsxs("div", { style: styles.content, onClick: (e) => e.stopPropagation(), children: [
|
|
795
|
-
/* @__PURE__ */ jsx("button", { style: styles.closeButton, onClick: onClose, children: "\xD7" }),
|
|
1080
|
+
/* @__PURE__ */ jsx("button", { style: styles.closeButton, onClick: onClose, "aria-label": "Close", children: "\xD7" }),
|
|
796
1081
|
/* @__PURE__ */ jsxs("div", { style: styles.header, children: [
|
|
797
1082
|
/* @__PURE__ */ jsx(CalimeroLogo, { size: 44, color: cssVar(resolved, "primary") }),
|
|
798
1083
|
/* @__PURE__ */ jsx("h1", { style: styles.title, children: "Connect to Calimero" })
|
|
@@ -801,12 +1086,13 @@ function LoginModal({
|
|
|
801
1086
|
/* @__PURE__ */ jsx("p", { children: "Connecting to node..." }),
|
|
802
1087
|
/* @__PURE__ */ jsx("div", { style: styles.spinner })
|
|
803
1088
|
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
804
|
-
/* @__PURE__ */ jsx("p", { style: styles.info, children:
|
|
1089
|
+
shouldShowRadioGroup && /* @__PURE__ */ jsx("p", { style: styles.info, children: "Select your Calimero node type to continue." }),
|
|
805
1090
|
error && /* @__PURE__ */ jsx("p", { style: styles.error, children: error }),
|
|
806
1091
|
shouldShowRadioGroup && /* @__PURE__ */ jsxs("div", { style: styles.radioGroup, children: [
|
|
807
1092
|
/* @__PURE__ */ jsxs(
|
|
808
1093
|
"label",
|
|
809
1094
|
{
|
|
1095
|
+
"data-testid": "node-type-local",
|
|
810
1096
|
style: {
|
|
811
1097
|
...styles.radioLabel,
|
|
812
1098
|
...nodeType === "local" ? styles.radioLabelActive : {}
|
|
@@ -830,6 +1116,7 @@ function LoginModal({
|
|
|
830
1116
|
/* @__PURE__ */ jsxs(
|
|
831
1117
|
"label",
|
|
832
1118
|
{
|
|
1119
|
+
"data-testid": "node-type-remote",
|
|
833
1120
|
style: {
|
|
834
1121
|
...styles.radioLabel,
|
|
835
1122
|
...nodeType === "remote" ? styles.radioLabelActive : {}
|
|
@@ -851,34 +1138,22 @@ function LoginModal({
|
|
|
851
1138
|
}
|
|
852
1139
|
)
|
|
853
1140
|
] }),
|
|
854
|
-
/* @__PURE__ */
|
|
855
|
-
"input",
|
|
856
|
-
{
|
|
857
|
-
type: "text",
|
|
858
|
-
value: nodeUrl,
|
|
859
|
-
onChange: (e) => setNodeUrl2(e.target.value),
|
|
860
|
-
placeholder: "https://your-node-url.calimero.network",
|
|
861
|
-
style: styles.input,
|
|
862
|
-
onKeyDown: (e) => {
|
|
863
|
-
if (e.key === "Enter" && isValid) {
|
|
864
|
-
handleConnect();
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
|
-
}
|
|
868
|
-
) : shouldShowLocal ? /* @__PURE__ */ jsxs("p", { style: styles.localInfo, children: [
|
|
1141
|
+
nodeType === "local" && shouldShowLocal && /* @__PURE__ */ jsxs("p", { style: styles.localInfo, children: [
|
|
869
1142
|
"Using default local node: ",
|
|
870
1143
|
/* @__PURE__ */ jsx("br", {}),
|
|
871
|
-
/* @__PURE__ */ jsx("code", { style: styles.localInfoCode, children:
|
|
872
|
-
] })
|
|
1144
|
+
/* @__PURE__ */ jsx("code", { style: styles.localInfoCode, children: DEFAULT_LOCAL_NODE_URL })
|
|
1145
|
+
] }),
|
|
1146
|
+
nodeType === "remote" && shouldShowRemote && renderRemoteView(),
|
|
873
1147
|
/* @__PURE__ */ jsx("div", { style: styles.buttonGroup, children: /* @__PURE__ */ jsx(
|
|
874
1148
|
"button",
|
|
875
1149
|
{
|
|
876
1150
|
onClick: handleConnect,
|
|
877
|
-
disabled: !
|
|
1151
|
+
disabled: !canConnect,
|
|
878
1152
|
style: {
|
|
879
1153
|
...styles.button,
|
|
880
|
-
...!
|
|
1154
|
+
...!canConnect ? styles.buttonDisabled : {}
|
|
881
1155
|
},
|
|
1156
|
+
"data-testid": "connect-button",
|
|
882
1157
|
children: "Connect"
|
|
883
1158
|
}
|
|
884
1159
|
) })
|
|
@@ -2650,6 +2925,6 @@ function MigrationAdminPanel({ namespaceId, pollIntervalMs, className }) {
|
|
|
2650
2925
|
] });
|
|
2651
2926
|
}
|
|
2652
2927
|
|
|
2653
|
-
export { AppMode, CalimeroLogo, ConnectButton, ConnectionType, LoginModal, MERO_CSS_VARS, MeroContext, MeroProvider, MigrationAdminPanel, MigrationPendingBanner, clearAllStorage, clearApplicationId, clearContextId, clearContextIdentity, clearNodeUrl, cssVar, defaultMeroTheme, getApplicationId, getContextId, getContextIdentity, getNodeUrl, localStorageTokenStorage, resolveMeroTheme, setApplicationId, setContextId, setContextIdentity, setNodeUrl, themeToCssVars, useAddGroupMembers, useAppVersion, useApplicationContexts, useContextDiscovery, useContextGroup, useContexts, useCreateContext, useCreateGroupInNamespace, useCreateNamespace, useCreateNamespaceInvitation, useDefaultCapabilities, useDeleteContext, useDeleteGroup, useDeleteNamespace, useDetachContextFromGroup, useExecute, useGroupCapabilities, useGroupContexts, useGroupInfo, useGroupInvitations, useGroupMembers, useGroupMetadata, useGroupUpgradeStatus, useJoinContext, useJoinGroup, useJoinNamespace, useJoinSubgroupInheritance, useLatestVersion, useMemberMetadata, useMero, useMigrationStatus, useMyAuthoredMigration, useNamespace, useNamespaceGroups, useNamespaceIdentity, useNamespaces, useNamespacesForApplication, useRegisterGroupSigningKey, useRemoveGroupMembers, useReparentGroup, useResyncContext, useRetryGroupUpgrade, useSetContextMetadata, useSetDefaultCapabilities, useSetGroupMetadata, useSetMemberMetadata, useSetSubgroupVisibility, useSetTeeAdmissionPolicy, useSubgroupVisibility, useSubgroups, useSubscription, useSyncGroup, useUpdateGroupSettings, useUpdateMemberRole, useUpgradeGroup };
|
|
2928
|
+
export { AppMode, CalimeroLogo, ConnectButton, ConnectionType, DEFAULT_LOCAL_NODE_PORTS, LoginModal, MERO_CSS_VARS, MeroContext, MeroProvider, MigrationAdminPanel, MigrationPendingBanner, clearAllStorage, clearApplicationId, clearContextId, clearContextIdentity, clearNodeUrl, cssVar, defaultMeroTheme, discoverLocalNodes, getApplicationId, getContextId, getContextIdentity, getNodeUrl, localNodeUrl, localStorageTokenStorage, nodeEndpoint, probeNodeHealth, resolveMeroTheme, setApplicationId, setContextId, setContextIdentity, setNodeUrl, themeToCssVars, useAddGroupMembers, useAppVersion, useApplicationContexts, useContextDiscovery, useContextGroup, useContexts, useCreateContext, useCreateGroupInNamespace, useCreateNamespace, useCreateNamespaceInvitation, useDefaultCapabilities, useDeleteContext, useDeleteGroup, useDeleteNamespace, useDetachContextFromGroup, useExecute, useGroupCapabilities, useGroupContexts, useGroupInfo, useGroupInvitations, useGroupMembers, useGroupMetadata, useGroupUpgradeStatus, useJoinContext, useJoinGroup, useJoinNamespace, useJoinSubgroupInheritance, useLatestVersion, useMemberMetadata, useMero, useMigrationStatus, useMyAuthoredMigration, useNamespace, useNamespaceGroups, useNamespaceIdentity, useNamespaces, useNamespacesForApplication, useRegisterGroupSigningKey, useRemoveGroupMembers, useReparentGroup, useResyncContext, useRetryGroupUpgrade, useSetContextMetadata, useSetDefaultCapabilities, useSetGroupMetadata, useSetMemberMetadata, useSetSubgroupVisibility, useSetTeeAdmissionPolicy, useSubgroupVisibility, useSubgroups, useSubscription, useSyncGroup, useUpdateGroupSettings, useUpdateMemberRole, useUpgradeGroup };
|
|
2654
2929
|
//# sourceMappingURL=index.js.map
|
|
2655
2930
|
//# sourceMappingURL=index.js.map
|