-
- {readyForUpgrade ? (
- Start Mesh Wide Transaction
- ) : (
- New version available!
- )}
-
-
- This node version:
-
- {boardData && boardData.release.description}
-
-
-
New available version:
+ let steps: LineChartStep[] = [
+ {
+ text: (
+
+ This node version
+
+ {boardData && boardData.release.version}
+
+ ),
+ status: "SUCCESS",
+ },
+ ];
+
+ if (!readyForUpgrade) {
+ steps = [
+ ...steps,
+ {
+ text: (
+
+ New available version:
+
+ {newVersion && newVersion.version}
+
+ ),
+ status: "SUCCESS",
+ },
+ ];
+ } else {
+ steps = [
+ ...steps,
+ {
+ text: (
+
+ Downloaded version
+
+ {newVersion && newVersion.version}
+
+ ),
+ status: "SUCCESS",
+ },
+ {
+ text:
Start mesh wide upgrade ,
+ status: "SUCCESS",
+ },
+ ];
+ }
+ let title =
New version available! ;
+ if (readyForUpgrade) {
+ title = (
+
+ Ready to start mesh wide
- {newVersion && newVersion.version}
+ firmware upgrade
+
+ );
+ }
+
+ return (
+
+
+
- {readyForUpgrade && (
-
- Is ready for upgrade!
-
-
- )}
-
+
);
};
diff --git a/plugins/lime-plugin-mesh-wide-upgrade/src/components/upgradeState/NoNewVersion.tsx b/plugins/lime-plugin-mesh-wide-upgrade/src/components/upgradeState/NoNewVersion.tsx
index ed09442ee..4b1638b4c 100644
--- a/plugins/lime-plugin-mesh-wide-upgrade/src/components/upgradeState/NoNewVersion.tsx
+++ b/plugins/lime-plugin-mesh-wide-upgrade/src/components/upgradeState/NoNewVersion.tsx
@@ -1,19 +1,15 @@
import { Trans } from "@lingui/macro";
-import { useNewVersion } from "plugins/lime-plugin-firmware/src/firmwareQueries";
-
-import { useBoardData } from "utils/queries";
+import {
+ MeshUpgradeSuccessIcon,
+ UpgradeState,
+} from "plugins/lime-plugin-mesh-wide-upgrade/src/components/upgradeState/UpgradeState";
export const NoNewVersionAvailable = () => {
- const { data: boardData } = useBoardData();
- const { data: newVersion } = useNewVersion();
-
return (
-
-
✓
-
- No new version available!
-
-
+
No new version available!}
+ icon={ }
+ />
);
};
diff --git a/plugins/lime-plugin-mesh-wide-upgrade/src/components/upgradeState/TransactionStarted.tsx b/plugins/lime-plugin-mesh-wide-upgrade/src/components/upgradeState/TransactionStarted.tsx
index 63de80451..50d72f2fb 100644
--- a/plugins/lime-plugin-mesh-wide-upgrade/src/components/upgradeState/TransactionStarted.tsx
+++ b/plugins/lime-plugin-mesh-wide-upgrade/src/components/upgradeState/TransactionStarted.tsx
@@ -1,17 +1,27 @@
+import { Trans } from "@lingui/macro";
+
+import { UpgradeState } from "plugins/lime-plugin-mesh-wide-upgrade/src/components/upgradeState/UpgradeState";
import { useMeshUpgrade } from "plugins/lime-plugin-mesh-wide-upgrade/src/hooks/meshWideUpgradeProvider";
export const TransactionStarted = () => {
const { someNodeDownloading } = useMeshUpgrade();
+ const title = (
+
+ Mesh wide upgrade started!
+
+ );
return (
-
- Transaction started!
+
{someNodeDownloading && (
- Some nodes seems to be downloading, check network page for
- more information
+
+ Some nodes are still downloading the firmware
+
+ check network page for more information
+
)}
-
+
);
};
diff --git a/plugins/lime-plugin-mesh-wide-upgrade/src/components/upgradeState/UpgradeScheduled.tsx b/plugins/lime-plugin-mesh-wide-upgrade/src/components/upgradeState/UpgradeScheduled.tsx
index ac2a9a1f6..ed9d15efb 100644
--- a/plugins/lime-plugin-mesh-wide-upgrade/src/components/upgradeState/UpgradeScheduled.tsx
+++ b/plugins/lime-plugin-mesh-wide-upgrade/src/components/upgradeState/UpgradeScheduled.tsx
@@ -1,25 +1,25 @@
import { Trans } from "@lingui/macro";
-import { ParallelErrors } from "plugins/lime-plugin-mesh-wide-upgrade/src/components/upgradeState/ParallelErrors";
+import {
+ ParallelErrors,
+ UpgradeState,
+} from "plugins/lime-plugin-mesh-wide-upgrade/src/components/upgradeState/UpgradeState";
import { useMeshUpgrade } from "plugins/lime-plugin-mesh-wide-upgrade/src/hooks/meshWideUpgradeProvider";
import { useParallelScheduleUpgrade } from "plugins/lime-plugin-mesh-wide-upgrade/src/meshUpgradeQueries";
export const UpgradeScheduled = () => {
const { totalNodes } = useMeshUpgrade();
const { errors, results } = useParallelScheduleUpgrade();
- const nodesToBeUpgraded = results.length;
+ const nodesToBeUpgraded = results?.length;
return (
- <>
-
- Upgrade is scheduled!
-
-
+ Upgrade is scheduled!}>
+ <>
{nodesToBeUpgraded} of {totalNodes} will be upgraded
-
- {errors?.length > 0 &&
}
- >
+ {errors?.length > 0 &&
}
+ >
+
);
};
diff --git a/plugins/lime-plugin-mesh-wide-upgrade/src/components/upgradeState/ParallelErrors.tsx b/plugins/lime-plugin-mesh-wide-upgrade/src/components/upgradeState/UpgradeState.tsx
similarity index 54%
rename from plugins/lime-plugin-mesh-wide-upgrade/src/components/upgradeState/ParallelErrors.tsx
rename to plugins/lime-plugin-mesh-wide-upgrade/src/components/upgradeState/UpgradeState.tsx
index ce30e1035..3e98c37e9 100644
--- a/plugins/lime-plugin-mesh-wide-upgrade/src/components/upgradeState/ParallelErrors.tsx
+++ b/plugins/lime-plugin-mesh-wide-upgrade/src/components/upgradeState/UpgradeState.tsx
@@ -1,9 +1,32 @@
import { Trans } from "@lingui/macro";
+import { ComponentChildren } from "preact";
+import { GlobeIcon } from "components/icons/globeIcon";
+import { Tick, Warning } from "components/icons/status";
import { StatusMessage } from "components/status/statusMessage";
import { RemoteNodeCallError, SyncCallErrors } from "utils/meshWideSyncCall";
+interface UpgradeStateProps {
+ icon?: ComponentChildren;
+ title: ComponentChildren;
+ children?: ComponentChildren;
+}
+
+export const UpgradeState = ({
+ icon =
,
+ title,
+ children,
+}: UpgradeStateProps) => {
+ return (
+
+ {icon}
+
{title}
+ {children &&
{children}
}
+
+ );
+};
+
export const ParallelErrors = ({ errors }: { errors: SyncCallErrors }) => {
return (
// Important to not add any style to this fragment because could add errors on growing on long lists
@@ -26,3 +49,11 @@ export const ParallelErrors = ({ errors }: { errors: SyncCallErrors }) => {
>
);
};
+
+export const MeshUpgradeSuccessIcon = () => {
+ return
;
+};
+
+export const MeshUpgradeErrorIcon = () => {
+ return
;
+};
diff --git a/plugins/lime-plugin-mesh-wide-upgrade/src/containers/meshWideUpgradeStatus.tsx b/plugins/lime-plugin-mesh-wide-upgrade/src/containers/meshWideUpgradeStatus.tsx
index 036ab60cf..8588d8d16 100644
--- a/plugins/lime-plugin-mesh-wide-upgrade/src/containers/meshWideUpgradeStatus.tsx
+++ b/plugins/lime-plugin-mesh-wide-upgrade/src/containers/meshWideUpgradeStatus.tsx
@@ -1,6 +1,7 @@
import { Trans } from "@lingui/macro";
import { ConfirmationPending } from "plugins/lime-plugin-mesh-wide-upgrade/src/components/upgradeState/ConfirmationPending";
+import { Confirmed } from "plugins/lime-plugin-mesh-wide-upgrade/src/components/upgradeState/Confirmed";
import { ErrorState } from "plugins/lime-plugin-mesh-wide-upgrade/src/components/upgradeState/ErrorState";
import { LoadingPage } from "plugins/lime-plugin-mesh-wide-upgrade/src/components/upgradeState/LoadingPage";
import { NewVersionAvailable } from "plugins/lime-plugin-mesh-wide-upgrade/src/components/upgradeState/NewVersionAvailable";
@@ -65,7 +66,7 @@ const MeshWideUpgradeStatusState = () => {
case "CONFIRMATION_PENDING":
return
;
case "CONFIRMED":
- return <>Confirmed!>;
+ return
;
default:
return
;
}
diff --git a/plugins/lime-plugin-mesh-wide-upgrade/src/hooks/meshWideUpgradeProvider.tsx b/plugins/lime-plugin-mesh-wide-upgrade/src/hooks/meshWideUpgradeProvider.tsx
index 3c52b1224..9692e98f2 100644
--- a/plugins/lime-plugin-mesh-wide-upgrade/src/hooks/meshWideUpgradeProvider.tsx
+++ b/plugins/lime-plugin-mesh-wide-upgrade/src/hooks/meshWideUpgradeProvider.tsx
@@ -1,15 +1,15 @@
import { ComponentChildren, createContext } from "preact";
import { useMemo } from "preact/compat";
-import { useEffect } from "preact/hooks";
+import { useEffect, useState } from "preact/hooks";
import { useCallback, useContext } from "react";
import { useNewVersion } from "plugins/lime-plugin-firmware/src/firmwareQueries";
import { getStepperStatus } from "plugins/lime-plugin-mesh-wide-upgrade/src/hooks/useStepper";
import {
- useAbort,
useBecomeMainNode,
useMeshUpgradeNodeStatus,
useMeshWideUpgradeInfo,
+ useParallelAbort,
useParallelConfirmUpgrade,
useParallelScheduleUpgrade,
useStartFirmwareUpgradeTransaction,
@@ -70,7 +70,7 @@ export const MeshWideUpgradeProvider = ({
}) => {
// UseCallback to invalidate queries
const invalidateQueries = useCallback(() => {
- queryCache.invalidateQueries({
+ return queryCache.invalidateQueries({
queryKey: meshUpgradeQueryKeys.getMeshUpgradeNodeStatus(),
});
}, []);
@@ -90,21 +90,15 @@ export const MeshWideUpgradeProvider = ({
refetchInterval: NODE_STATUS_REFETCH_INTERVAL,
});
- const { mutate: becomeMainNodeMutation } = useBecomeMainNode({
- onSuccess: () => {
- invalidateQueries();
- },
- });
+ const { mutateAsync: becomeMainNodeMutation } = useBecomeMainNode({});
- const { mutate: fwUpgradeTransaction } = useStartFirmwareUpgradeTransaction(
- {
- onSuccess: () => {
- invalidateQueries();
- },
- }
- );
+ const { mutateAsync: fwUpgradeTransaction } =
+ useStartFirmwareUpgradeTransaction({});
- const { mutate: abort, isLoading: isAborting } = useAbort({});
+ // Inner state to control is aborting callback awaiting until query invalidation
+ const [isAborting, setIsAborting] = useState(false);
+ // const { mutateAsync: abortMutation } = useAbort({});
+ const { callMutations: abortMutation } = useParallelAbort();
const { data: session } = useSession();
const { data: newVersionData } = useNewVersion({
@@ -161,13 +155,26 @@ export const MeshWideUpgradeProvider = ({
const meshWideError = getMeshWideError(thisNode);
- const becomeMainNode = useCallback(() => {
- becomeMainNodeMutation({});
- }, [becomeMainNodeMutation]);
-
- const startFwUpgradeTransaction = useCallback(() => {
- fwUpgradeTransaction({});
- }, [fwUpgradeTransaction]);
+ const becomeMainNode = useCallback(async () => {
+ await becomeMainNodeMutation({});
+ await invalidateQueries();
+ }, [becomeMainNodeMutation, invalidateQueries]);
+
+ const startFwUpgradeTransaction = useCallback(async () => {
+ await fwUpgradeTransaction({});
+ await invalidateQueries();
+ }, [fwUpgradeTransaction, invalidateQueries]);
+
+ const abort = useCallback(async () => {
+ setIsAborting(true);
+ abortMutation()
+ .then(() => {
+ return invalidateQueries();
+ })
+ .finally(() => {
+ setIsAborting(false);
+ });
+ }, [abortMutation, invalidateQueries]);
const isLoading = meshWideInfoLoading || thisNodeLoading;
diff --git a/plugins/lime-plugin-mesh-wide-upgrade/src/hooks/useStepper.tsx b/plugins/lime-plugin-mesh-wide-upgrade/src/hooks/useStepper.tsx
index 8b8a351de..65e376640 100644
--- a/plugins/lime-plugin-mesh-wide-upgrade/src/hooks/useStepper.tsx
+++ b/plugins/lime-plugin-mesh-wide-upgrade/src/hooks/useStepper.tsx
@@ -4,6 +4,7 @@ import { useMemo } from "react";
import { IStatusAndButton } from "components/status/statusAndButton";
import {
+ useAbortModal,
useConfirmModal,
useScheduleUpgradeModal,
} from "plugins/lime-plugin-mesh-wide-upgrade/src/components/modals";
@@ -144,21 +145,26 @@ export const useStep = () => {
const { callMutations: startScheduleMeshUpgrade, errors: scheduleErrors } =
useParallelScheduleUpgrade();
- const { callMutations: confirmMeshUpgrade, errors: confirmErrors } =
- useParallelConfirmUpgrade();
+ const { callMutations: confirmMeshUpgrade } = useParallelConfirmUpgrade();
const { showModal: showScheduleModal } = useScheduleUpgradeModal({
- allNodesReady: allNodesReadyForUpgrade,
+ useSuccessBtn: allNodesReadyForUpgrade,
cb: () => {
- startScheduleMeshUpgrade();
+ return startScheduleMeshUpgrade();
},
});
const { showModal: showConfirmationModal } = useConfirmModal({
// Ideally we have to implement some kind of state before run the upgrade to check if all nodes are up again.
- allNodesReady: true,
+ useSuccessBtn: true,
cb: () => {
- confirmMeshUpgrade();
+ return confirmMeshUpgrade();
+ },
+ });
+
+ const { showModal: showAbortModal } = useAbortModal({
+ cb: () => {
+ return abort();
},
});
@@ -249,7 +255,7 @@ export const useStep = () => {
> = {
btnCancel:
Abort ,
onClickCancel: async () => {
- await abort();
+ showAbortModal();
},
};
step = { ...step, ...showAbort };
diff --git a/plugins/lime-plugin-mesh-wide-upgrade/src/meshUpgradeApi.tsx b/plugins/lime-plugin-mesh-wide-upgrade/src/meshUpgradeApi.tsx
index 4704d3410..ca55bd97f 100644
--- a/plugins/lime-plugin-mesh-wide-upgrade/src/meshUpgradeApi.tsx
+++ b/plugins/lime-plugin-mesh-wide-upgrade/src/meshUpgradeApi.tsx
@@ -59,6 +59,13 @@ export async function remoteConfirmUpgrade({ ip }: { ip: string }) {
});
}
+export async function remoteAbort({ ip }: { ip: string }) {
+ return await callToRemoteNode({
+ ip,
+ apiCall: (customApi) => meshUpgradeApiCall("abort", customApi),
+ });
+}
+
const meshUpgradeApiCall = async (
method: string,
customApi?: UhttpdService
diff --git a/plugins/lime-plugin-mesh-wide-upgrade/src/meshUpgradeQueries.tsx b/plugins/lime-plugin-mesh-wide-upgrade/src/meshUpgradeQueries.tsx
index 1a0894e6d..d31e86aba 100644
--- a/plugins/lime-plugin-mesh-wide-upgrade/src/meshUpgradeQueries.tsx
+++ b/plugins/lime-plugin-mesh-wide-upgrade/src/meshUpgradeQueries.tsx
@@ -3,9 +3,9 @@ import { useMutation, useQuery } from "@tanstack/react-query";
import {
getMeshUpgradeNodeStatus,
getMeshWideUpgradeInfo,
+ remoteAbort,
remoteConfirmUpgrade,
remoteScheduleUpgrade,
- setAbort,
setBecomeMainNode,
setStartFirmwareUpgradeTransaction,
} from "plugins/lime-plugin-mesh-wide-upgrade/src/meshUpgradeApi";
@@ -14,7 +14,7 @@ import {
MeshWideUpgradeInfo,
NodeMeshUpgradeInfo,
} from "plugins/lime-plugin-mesh-wide-upgrade/src/meshUpgradeTypes";
-import { getNodeIpsByStatus } from "plugins/lime-plugin-mesh-wide-upgrade/src/utils/api";
+import { getNodeIpsByCondition } from "plugins/lime-plugin-mesh-wide-upgrade/src/utils/api";
import { useMeshWideSyncCall } from "utils/meshWideSyncCall";
@@ -56,13 +56,6 @@ export function useStartFirmwareUpgradeTransaction(params) {
});
}
-export function useAbort(params) {
- return useMutation({
- mutationFn: setAbort,
- ...params,
- });
-}
-
// Parallel queries/mutations
export type UseScheduleMeshSafeUpgradeType = ReturnType<
@@ -71,7 +64,10 @@ export type UseScheduleMeshSafeUpgradeType = ReturnType<
export const useParallelScheduleUpgrade = (opts?) => {
// State to store the errors
const { data: nodes } = useMeshWideUpgradeInfo({});
- const ips = getNodeIpsByStatus(nodes, "READY_FOR_UPGRADE");
+ const ips = getNodeIpsByCondition(
+ nodes,
+ (node) => node.upgrade_state === "READY_FOR_UPGRADE"
+ );
// localStorage.setItem("hideReleaseBannerPlease", value);
return useMeshWideSyncCall({
mutationKey: meshUpgradeQueryKeys.remoteScheduleUpgrade(),
@@ -87,7 +83,10 @@ export type UseConfirmUpgradeType = ReturnType<
export const useParallelConfirmUpgrade = (opts?) => {
// State to store the errors
const { data: nodes } = useMeshWideUpgradeInfo({});
- const ips = getNodeIpsByStatus(nodes, "CONFIRMATION_PENDING");
+ const ips = getNodeIpsByCondition(
+ nodes,
+ (node) => node.upgrade_state === "CONFIRMATION_PENDING"
+ );
return useMeshWideSyncCall({
mutationKey: meshUpgradeQueryKeys.remoteConfirmUpgrade(),
mutationFn: remoteConfirmUpgrade,
@@ -95,3 +94,22 @@ export const useParallelConfirmUpgrade = (opts?) => {
options: opts,
});
};
+
+export const useParallelAbort = (opts?) => {
+ // State to store the errors
+ const { data: nodes } = useMeshWideUpgradeInfo({});
+ const ips = getNodeIpsByCondition(nodes, (node) =>
+ [
+ "READY_FOR_UPGRADE",
+ "UPGRADE_SCHEDULED",
+ "CONFIRMATION_PENDING",
+ "ERROR",
+ ].includes(node.upgrade_state)
+ );
+ return useMeshWideSyncCall({
+ mutationKey: meshUpgradeQueryKeys.remoteAbort(),
+ mutationFn: remoteAbort,
+ ips,
+ options: opts,
+ });
+};
diff --git a/plugins/lime-plugin-mesh-wide-upgrade/src/meshUpgradeQueriesKeys.tsx b/plugins/lime-plugin-mesh-wide-upgrade/src/meshUpgradeQueriesKeys.tsx
index dc947d179..fc54018d5 100644
--- a/plugins/lime-plugin-mesh-wide-upgrade/src/meshUpgradeQueriesKeys.tsx
+++ b/plugins/lime-plugin-mesh-wide-upgrade/src/meshUpgradeQueriesKeys.tsx
@@ -9,6 +9,7 @@ const MeshUpgradeQueryKeys: MeshUpgradeQueryKeysProps = {
getMeshUpgradeNodeStatus: ["lime-mesh-upgrade", "get_node_status"],
remoteScheduleUpgrade: ["lime-mesh-upgrade", "schedule_upgrade"],
remoteConfirmUpgrade: ["lime-mesh-upgrade", "confirm_boot_partition"],
+ remoteAbort: ["lime-mesh-upgrade", "abort"],
};
export const meshUpgradeQueryKeys = {
@@ -20,4 +21,5 @@ export const meshUpgradeQueryKeys = {
MeshUpgradeQueryKeys.remoteScheduleUpgrade,
remoteConfirmUpgrade: (): QueryKey =>
MeshUpgradeQueryKeys.remoteConfirmUpgrade,
+ remoteAbort: (): QueryKey => MeshUpgradeQueryKeys.remoteConfirmUpgrade,
};
diff --git a/plugins/lime-plugin-mesh-wide-upgrade/src/utils/api.ts b/plugins/lime-plugin-mesh-wide-upgrade/src/utils/api.ts
index 64c6e5ab3..76c7d267a 100644
--- a/plugins/lime-plugin-mesh-wide-upgrade/src/utils/api.ts
+++ b/plugins/lime-plugin-mesh-wide-upgrade/src/utils/api.ts
@@ -1,7 +1,7 @@
import {
MeshUpgradeApiErrorTypes,
MeshWideUpgradeInfo,
- UpgradeStatusType,
+ NodeMeshUpgradeInfo,
} from "plugins/lime-plugin-mesh-wide-upgrade/src/meshUpgradeTypes";
import { RemoteNodeCallError } from "utils/meshWideSyncCall";
@@ -21,13 +21,14 @@ export class MeshUpgradeApiError extends Error {
}
/**
- * From a MeshWideUpgradeInfo nodes it returns the ips of the nodes that are in certain status provided
+ * From a MeshWideUpgradeInfo nodes it returns the ips of the nodes that match the condition defined on the function
* @param nodes the nodes to check
- * @param status the status to check the criteria
+ * @param condition function that receives a NodeMeshUpgradeInfo and returns a boolean
*/
-export const getNodeIpsByStatus = (
+export const getNodeIpsByCondition = (
nodes: MeshWideUpgradeInfo,
- status: UpgradeStatusType
+ // status: UpgradeStatusType
+ condition: (node: NodeMeshUpgradeInfo) => boolean
) => {
if (!nodes) return [];
return Object.values(nodes)
@@ -36,7 +37,7 @@ export const getNodeIpsByStatus = (
node.node_ip !== null &&
node.node_ip !== undefined &&
node.node_ip.trim() !== "" &&
- node.upgrade_state === status
+ condition(node)
)
.map((node) => node.node_ip as string); // 'as string' is safe here due to the filter condition
};
diff --git a/plugins/lime-plugin-mesh-wide/src/components/FeatureDetail/NodeDetail.tsx b/plugins/lime-plugin-mesh-wide/src/components/FeatureDetail/NodeDetail.tsx
index 06596cf91..0357bc4f9 100644
--- a/plugins/lime-plugin-mesh-wide/src/components/FeatureDetail/NodeDetail.tsx
+++ b/plugins/lime-plugin-mesh-wide/src/components/FeatureDetail/NodeDetail.tsx
@@ -42,7 +42,10 @@ const NodeDetails = ({ actual, reference, name }: NodeMapFeature) => {
{name}
-
+
diff --git a/plugins/lime-plugin-mesh-wide/src/components/FeatureDetail/UpdateNodeInfoBtn.tsx b/plugins/lime-plugin-mesh-wide/src/components/FeatureDetail/UpdateNodeInfoBtn.tsx
index b8a8b9dbc..3d3e80e32 100644
--- a/plugins/lime-plugin-mesh-wide/src/components/FeatureDetail/UpdateNodeInfoBtn.tsx
+++ b/plugins/lime-plugin-mesh-wide/src/components/FeatureDetail/UpdateNodeInfoBtn.tsx
@@ -13,17 +13,25 @@ import {
import { getFromSharedStateKeys } from "plugins/lime-plugin-mesh-wide/src/meshWideQueriesKeys";
import {
DataTypes,
- INodeInfo,
completeDataTypeKeys,
} from "plugins/lime-plugin-mesh-wide/src/meshWideTypes";
import queryCache from "utils/queryCache";
-const UpdateNodeInfoBtn = ({ node }: { node: INodeInfo }) => {
- const ip = node.ipv4;
+interface INodeInfoProps {
+ ip: string;
+ nodeName: string;
+}
+const UpdateNodeInfoBtn = ({
+ ip,
+ nodeName,
+ updateOnMount = true,
+}: {
+ updateOnMount?: boolean;
+} & INodeInfoProps) => {
const [isLoading, setIsLoading] = useState(false);
- const { showToast, hideToast } = useToast();
+ const { showToast } = useToast();
const { mutateAsync: localNodeSync } = useSyncDataTypes({
ip,
@@ -52,7 +60,7 @@ const UpdateNodeInfoBtn = ({ node }: { node: INodeInfo }) => {
showToast({
text: (
- Error connecting with {node.hostname}, is node up?
+ Error connecting with {nodeName}, is node up?
),
duration: 5000,
@@ -71,25 +79,30 @@ const UpdateNodeInfoBtn = ({ node }: { node: INodeInfo }) => {
ip,
isLoading,
localNodeSync,
- node.hostname,
+ nodeName,
publishOnRemoteNode,
showToast,
]);
// Use effect to sync the node data on mount
useEffect(() => {
+ if (!updateOnMount) return;
(async () => {
await syncNode();
})();
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [node.ipv4]);
+ }, [ip]);
return (
{
+ e.preventDefault();
+ e.stopPropagation();
+ syncNode();
+ }}
>
diff --git a/src/components/PathChart/index.tsx b/src/components/PathChart/index.tsx
new file mode 100644
index 000000000..c88351717
--- /dev/null
+++ b/src/components/PathChart/index.tsx
@@ -0,0 +1,119 @@
+import { ComponentChildren } from "preact";
+import React from "react";
+
+import { GlobeIcon } from "components/icons/globeIcon";
+import LoadingDots from "components/loading/loading-dots";
+
+type StepStatus = "SUCCESS" | "ERROR" | "DISABLED";
+
+export type LineChartStep = {
+ text: ComponentChildren;
+ isLoading?: boolean;
+ status: StepStatus;
+};
+
+type CircleProps = {
+ index: number;
+ color?: string;
+ className?: string;
+ isLast?: boolean;
+ nextStep?: CircleProps; // Used to get the correct color of the line
+} & LineChartStep;
+
+const getColorByStatus = (step?: CircleProps) => {
+ let color = "gray-400";
+ let lineColor = `bg-gray-400`;
+ if (step?.status === "SUCCESS") {
+ if (step.isLast) {
+ color = "internet";
+ lineColor = `bg-internet`;
+ } else {
+ color = "primary-dark";
+ lineColor = `bg-primary-dark`;
+ }
+ } else if (step?.status === "ERROR") {
+ if (step.isLast) {
+ color = "danger";
+ } else {
+ color = "danger";
+ lineColor = `bg-danger`;
+ }
+ }
+ return { color, lineColor };
+};
+
+const LineBall = ({ ...step }: CircleProps) => {
+ const { color } = getColorByStatus(step);
+ const { lineColor } = getColorByStatus(step.nextStep);
+
+ const linePart = "h-14";
+
+ return (
+
+
+ {step.isLast ? (
+
+ ) : (
+
+ )}
+
+
+
+ );
+};
+
+const Step = ({ index, ...step }: CircleProps) => {
+ let color = "gray-400";
+ if (step.isLast) {
+ color = "text-internet";
+ } else if (step.status === "SUCCESS") {
+ color = "text-primary-dark";
+ } else if (step.status === "ERROR") {
+ color = "text-danger";
+ }
+
+ const loadingIndicator = step.isLoading ?
: null;
+
+ return (
+
+
+
+ {step.text} {loadingIndicator}
+
+
+ );
+};
+
+function LineChart({ steps }: { steps: LineChartStep[] }) {
+ if (!steps) return null;
+ return (
+
+ {steps.map((step, index) => {
+ const nextStep = steps[index + 1] ?? null;
+ return (
+
+ );
+ })}
+
+ );
+}
+
+export default LineChart;
diff --git a/src/components/buttons/button.tsx b/src/components/buttons/button.tsx
index c57255d52..319a674cc 100644
--- a/src/components/buttons/button.tsx
+++ b/src/components/buttons/button.tsx
@@ -1,7 +1,7 @@
-import React from "react";
+import React, { useCallback } from "react";
export interface ButtonProps {
- onClick?: (e) => void;
+ onClick?: ((e) => void) | ((e) => Promise
);
children?: any; // type error with Trans component
size?: "sm" | "md" | "lg";
color?: "primary" | "secondary" | "danger" | "info" | "disabled";
@@ -20,6 +20,9 @@ export const Button = ({
outline = false,
...props
}: ButtonProps) => {
+ // button internal state to set loading state
+ const [isLoading, setIsLoading] = React.useState(false);
+
let sizeClasses = "",
colorClasses = "";
switch (size) {
@@ -34,7 +37,7 @@ export const Button = ({
break;
}
- color = disabled ? "disabled" : color;
+ color = disabled || isLoading ? "disabled" : color;
switch (color) {
case "secondary":
@@ -55,7 +58,7 @@ export const Button = ({
case "disabled":
colorClasses = outline
? "border-2 border-button-disabled text-button-disabled hover:bg-button-disabled hover:text-white"
- : "bg-button-disabled text-white border-2 border-button-disabled hover:text-button-disabled hover:bg-white";
+ : "bg-button-disabled border-2 border-button-disabled hover:text-button-disabled hover:bg-white";
break;
case "primary":
default:
@@ -67,10 +70,21 @@ export const Button = ({
const cls = `cursor-pointer font-semibold rounded-xl text-center place-content-center transition-all duration-300
justify-center border-0 ${sizeClasses} ${colorClasses}`;
+
+ // useCallback for button click
+ const handleClick = useCallback(
+ async (e) => {
+ if (isLoading || disabled) return;
+ setIsLoading(true);
+ await onClick(e);
+ setIsLoading(false);
+ },
+ [disabled, isLoading, onClick]
+ );
const Btn = () => (
(!disabled ? onClick(e) : null)}
+ onClick={(e) => handleClick(e)}
className={cls}
{...props}
>
diff --git a/src/components/icons/status.tsx b/src/components/icons/status.tsx
index 684d146de..82ca516f5 100644
--- a/src/components/icons/status.tsx
+++ b/src/components/icons/status.tsx
@@ -14,13 +14,17 @@ export const StatusIcon = ({ status }: { status: StatusIcons }) => {
}
};
-export const Tick = () => ✓ ;
+interface IconsProps {
+ className?: string;
+}
-export const Warning = () => (
+export const Tick = ({ className }: IconsProps) => (
+ ✓
+);
+
+export const Warning = ({ className = "w-8 h-8" }: IconsProps) => (
!