feat: added heartbeat and fixed up gateway page

This commit is contained in:
Sheen Capadngan
2025-09-02 21:51:29 +08:00
parent 879361fd7a
commit d5dcaf0d59
13 changed files with 269 additions and 66 deletions
+1 -1
View File
@@ -1 +1 @@
export { gatewaysV2QueryKeys } from "./queries";
export * from "./mutations";
@@ -0,0 +1,17 @@
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { apiRequest } from "@app/config/request";
import { gatewaysQueryKeys } from "../gateways/queries";
export const useDeleteGatewayV2ById = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (id: string) => {
return apiRequest.delete(`/api/v2/gateways/${id}`);
},
onSuccess: () => {
queryClient.invalidateQueries(gatewaysQueryKeys.list());
}
});
};
@@ -1,18 +0,0 @@
import { queryOptions } from "@tanstack/react-query";
import { apiRequest } from "@app/config/request";
import { TGatewayV2 } from "./types";
export const gatewaysV2QueryKeys = {
allKey: () => ["gateways-v2"],
listKey: () => [...gatewaysV2QueryKeys.allKey(), "list"],
list: () =>
queryOptions({
queryKey: gatewaysV2QueryKeys.listKey(),
queryFn: async () => {
const { data } = await apiRequest.get<{ gateways: TGatewayV2[] }>("/api/v2/gateways");
return data.gateways;
}
})
};
@@ -4,6 +4,7 @@ export type TGatewayV2 = {
name: string;
createdAt: string;
updatedAt: string;
heartbeat: string;
identity: {
name: string;
id: string;
+10 -1
View File
@@ -15,7 +15,16 @@ export const gatewaysQueryKeys = {
const { data } = await apiRequest.get<{ gateways: TGateway[] }>("/api/v1/gateways");
const { data: dataV2 } = await apiRequest.get<TGatewayV2[]>("/api/v2/gateways");
return [...data.gateways, ...dataV2];
return [
...data.gateways.map((g) => ({
...g,
isV1: true
})),
...dataV2.map((g) => ({
...g,
isV1: false
}))
];
}
})
};
@@ -14,7 +14,7 @@ import {
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useQuery } from "@tanstack/react-query";
import { format, formatRelative } from "date-fns";
import { formatRelative } from "date-fns";
import { createNotification } from "@app/components/notifications";
import { OrgPermissionCan } from "@app/components/permissions";
@@ -48,13 +48,14 @@ import {
import { withPermission } from "@app/hoc";
import { usePopUp } from "@app/hooks";
import { gatewaysQueryKeys, useDeleteGatewayById } from "@app/hooks/api/gateways";
import { useDeleteGatewayV2ById } from "@app/hooks/api/gateways-v2";
import { EditGatewayDetailsModal } from "./components/EditGatewayDetailsModal";
export const GatewayListPage = withPermission(
() => {
const [search, setSearch] = useState("");
const { data: gateways, isPending: isGatewayLoading } = useQuery(gatewaysQueryKeys.list());
const { data: gateways, isPending: isGatewaysLoading } = useQuery(gatewaysQueryKeys.list());
const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp([
"deleteGateway",
@@ -62,16 +63,20 @@ export const GatewayListPage = withPermission(
] as const);
const deleteGatewayById = useDeleteGatewayById();
const deleteGatewayV2ById = useDeleteGatewayV2ById();
const handleDeleteGateway = async () => {
await deleteGatewayById.mutateAsync((popUp.deleteGateway.data as { id: string }).id, {
onSuccess: () => {
handlePopUpToggle("deleteGateway");
createNotification({
type: "success",
text: "Successfully delete gateway"
});
}
const data = popUp.deleteGateway.data as { id: string; isV1: boolean };
if (data.isV1) {
await deleteGatewayById.mutateAsync(data.id);
} else {
await deleteGatewayV2ById.mutateAsync(data.id);
}
handlePopUpToggle("deleteGateway");
createNotification({
type: "success",
text: "Successfully deleted gateway"
});
};
@@ -127,7 +132,6 @@ export const GatewayListPage = withPermission(
<THead>
<Tr>
<Th className="w-1/3">Name</Th>
<Th>Cert Issued At</Th>
<Th>Identity</Th>
<Th>
Health Check
@@ -143,13 +147,12 @@ export const GatewayListPage = withPermission(
</Tr>
</THead>
<TBody>
{isGatewayLoading && (
{isGatewaysLoading && (
<TableSkeleton innerKey="gateway-table" columns={4} key="gateway-table" />
)}
{filteredGateway?.map((el) => (
<Tr key={el.id}>
<Td>{el.name}</Td>
<Td>{format(new Date(el.issuedAt), "yyyy-MM-dd hh:mm:ss aaa")}</Td>
<Td>{el.identity.name}</Td>
<Td>
{el.heartbeat
@@ -176,20 +179,22 @@ export const GatewayListPage = withPermission(
>
Copy ID
</DropdownMenuItem>
<OrgPermissionCan
I={OrgGatewayPermissionActions.EditGateways}
a={OrgPermissionSubjects.Gateway}
>
{(isAllowed: boolean) => (
<DropdownMenuItem
isDisabled={!isAllowed}
icon={<FontAwesomeIcon icon={faEdit} />}
onClick={() => handlePopUpOpen("editDetails", el)}
>
Edit Details
</DropdownMenuItem>
)}
</OrgPermissionCan>
{el.isV1 && (
<OrgPermissionCan
I={OrgGatewayPermissionActions.EditGateways}
a={OrgPermissionSubjects.Gateway}
>
{(isAllowed: boolean) => (
<DropdownMenuItem
isDisabled={!isAllowed}
icon={<FontAwesomeIcon icon={faEdit} />}
onClick={() => handlePopUpOpen("editDetails", el)}
>
Edit Details
</DropdownMenuItem>
)}
</OrgPermissionCan>
)}
<OrgPermissionCan
I={OrgPermissionAppConnectionActions.Delete}
a={OrgPermissionSubjects.AppConnections}
@@ -224,7 +229,7 @@ export const GatewayListPage = withPermission(
/>
</ModalContent>
</Modal>
{!isGatewayLoading && !filteredGateway?.length && (
{!isGatewaysLoading && !filteredGateway?.length && (
<EmptyState
title={
gateways?.length
@@ -251,8 +256,5 @@ export const GatewayListPage = withPermission(
</div>
);
},
{
action: OrgPermissionAppConnectionActions.Read,
subject: OrgPermissionSubjects.AppConnections
}
{ action: OrgGatewayPermissionActions.ListGateways, subject: OrgPermissionSubjects.Gateway }
);