Skip to content

Commit

Permalink
fix: refresh pages automatically when a slice or subscriber is added/…
Browse files Browse the repository at this point in the history
…deleted/edited (#701)

Signed-off-by: gatici <[email protected]>
  • Loading branch information
gatici authored Jan 10, 2025
1 parent 386a2de commit 478e850
Show file tree
Hide file tree
Showing 4 changed files with 232 additions and 49 deletions.
118 changes: 95 additions & 23 deletions app/(nms)/network-configuration/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ import NetworkSliceModal from "@/components/NetworkSliceModal";
import NetworkSliceEmptyState from "@/components/NetworkSliceEmptyState";
import { NetworkSliceTable } from "@/components/NetworkSliceTable";
import Loader from "@/components/Loader";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { queryKeys } from "@/utils/queryKeys";
import PageHeader from "@/components/PageHeader";
import PageContent from "@/components/PageContent";
import { NetworkSlice } from "@/components/types";
import { useAuth } from "@/utils/auth";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { apiPostNetworkSlice } from "@/utils/callNetworkSliceApi";

const NetworkConfiguration = () => {
const queryClient = useQueryClient();
Expand All @@ -28,41 +29,103 @@ const NetworkConfiguration = () => {
const { data: networkSlices = [], isLoading: loading, status: networkSlicesQueryStatus, error: networkSlicesQueryError } = useQuery({
queryKey: [queryKeys.networkSlices, auth.user?.authToken],
queryFn: () => getNetworkSlices(auth.user ? auth.user.authToken : ""),
enabled: auth.user ? true : false,
retry: (failureCount, error): boolean => {
if (error.message.includes("401")) {
return false
}
return true
}
enabled: Boolean(auth.user),
retry: (failureCount, error) => !(error instanceof Error && error.message.includes("401"))
});
if (networkSlicesQueryStatus == "error") {
if (networkSlicesQueryError.message.includes("401")) {
auth.logout()
}
return <p>{networkSlicesQueryError.message}</p>
}

const toggleCreateNetworkSliceModal = () =>
const addNetworkSlice = async (newSlice: NetworkSlice): Promise<Response> => {
return await apiPostNetworkSlice(newSlice["slice-name"], newSlice, auth.user?.authToken || "");
};

// Mutation hook to add a new Network Slice
const addNetworkSliceMutation = useMutation<unknown, Error, NetworkSlice>({
mutationFn: addNetworkSlice,
onSuccess: () => {
// Invalidate and refetch the network slices query
queryClient.invalidateQueries({ queryKey: [queryKeys.networkSlices] });
// Close model on success
setCreateModalVisible(false);
},
onError: (error) => {
console.error("Error adding network slice:", error);
},
});

const handleAddNetworkSlice = (newSlice: NetworkSlice) => {
addNetworkSliceMutation.mutate(newSlice, {
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [queryKeys.networkSlices] });
setCreateModalVisible(false); // Close modal on success
},
});
};

const editNetworkSlice = async (updatedSlice: NetworkSlice): Promise<Response> => {
return await apiPostNetworkSlice(updatedSlice["slice-name"], updatedSlice, auth.user?.authToken || "");
};

// Mutation hook to edit Network Slice
const editNetworkSliceMutation = useMutation<unknown, Error, NetworkSlice>({
mutationFn: editNetworkSlice,
onSuccess: () => {
// Invalidate and refetch network slices
queryClient.invalidateQueries({ queryKey: [queryKeys.networkSlices] });
setEditModalVisible(false);
},
onError: (error) => {
console.error("Error editing network slice:", error);
},
});

const handleEditNetworkSlice = (updatedSlice: NetworkSlice) => {
editNetworkSliceMutation.mutate(updatedSlice, {
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [queryKeys.networkSlices] });
// Close modal on success
setEditModalVisible(false);
},
});
};

const deleteNetworkSliceMutation = useMutation<void, Error, string>({
mutationFn: async (sliceName: string) => {
await deleteNetworkSlice(sliceName, auth.user?.authToken || "");
},
onSuccess: () => {
// Invalidate and refetch network slices
queryClient.invalidateQueries({ queryKey: [queryKeys.networkSlices] });
},
onError: (error) => {
console.error("Error deleting network slice:", error);
},
});

const handleConfirmDelete = (sliceName: string) => {
deleteNetworkSliceMutation.mutate(sliceName, {
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [queryKeys.networkSlices] });
},
});
};

const toggleCreateNetworkSliceModal = () => {
setCreateModalVisible((prev) => !prev);
// Clear selection when closing modal
setNetworkSlice(undefined);
};

const toggleEditNetworkSliceModal = () =>
setEditModalVisible((prev) => !prev);

const handleConfirmDelete = async (sliceName: string) => {
await deleteNetworkSlice(sliceName, auth.user ? auth.user.authToken : "");
void queryClient.invalidateQueries({ queryKey: [queryKeys.networkSlices] });
};

const handleEditButton = (networkSlice: NetworkSlice) => {
setNetworkSlice(networkSlice);
toggleEditNetworkSliceModal();
setEditModalVisible(true);
}

const getEditButton = (networkSlice: NetworkSlice) => {
return <Button
appearance=""
onClick={() => { handleEditButton(networkSlice) }}
onClick={() => handleEditButton(networkSlice) }
className="u-no-margin--bottom">
Edit
</Button>
Expand All @@ -77,7 +140,7 @@ const NetworkConfiguration = () => {
confirmationModalProps={{
title: "Warning",
confirmButtonLabel: "Delete",
buttonRow: (null),
buttonRow: null,
onConfirm: () => { },
children: (
<p>
Expand Down Expand Up @@ -115,6 +178,13 @@ const NetworkConfiguration = () => {
return <Loader text="Loading..." />;
}

if (networkSlicesQueryStatus == "error") {
if (networkSlicesQueryError.message.includes("401")) {
auth.logout()
}
return <p>{networkSlicesQueryError.message}</p>
}

return (
<>
{networkSlices.length > 0 && (
Expand Down Expand Up @@ -145,12 +215,14 @@ const NetworkConfiguration = () => {
{isCreateModalVisible && (
<NetworkSliceModal
toggleModal={toggleCreateNetworkSliceModal}
onSave={handleAddNetworkSlice}
/>
)}
{isEditModalVisible && (
<NetworkSliceModal
networkSlice={networkSlice}
toggleModal={toggleEditNetworkSliceModal}
onSave={handleEditNetworkSlice}
/>
)}
</>
Expand Down
145 changes: 127 additions & 18 deletions app/(nms)/subscribers/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { getNetworkSlices } from "@/utils/getNetworkSlices";
import SyncOutlinedIcon from "@mui/icons-material/SyncOutlined";
import { deleteSubscriber } from "@/utils/deleteSubscriber";
import Loader from "@/components/Loader";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { queryKeys } from "@/utils/queryKeys";
import PageHeader from "@/components/PageHeader";
import PageContent from "@/components/PageContent";
Expand All @@ -24,35 +24,136 @@ export type Subscriber = {
ueId: string;
};

const addSubscriber = async (newSubscriber: Subscriber, token: string | undefined) => {
const response = await fetch("/api/subscribers", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify(newSubscriber),
});
if (!response.ok) {
const errorBody = await response.json().catch(() => ({}));
throw new Error(
errorBody.message || "Failed to add subscriber"
);
}
return response.json();
};

const Subscribers = () => {
const queryClient = useQueryClient();
const [isCreateModalVisible, setCreateModalVisible] = useState(false);
const [isEditModalVisible, setEditModalVisible] = useState(false);
const [subscriber, setSubscriber] = useState<any | undefined>(undefined);
const [subscriber, setSubscriber] = useState<Subscriber | undefined>(undefined);
const auth = useAuth()

const { data: subscribers = [], isLoading: isSubscribersLoading, status: subscribersQueryStatus, error: subscribersQueryError } = useQuery({
queryKey: [queryKeys.subscribers, auth.user?.authToken],
queryFn: () => getSubscribers(auth.user ? auth.user.authToken : ""),
enabled: auth.user ? true : false,
queryFn: () => getSubscribers(auth.user?.authToken || ""),
enabled: Boolean(auth.user),
retry: (failureCount, error): boolean => {
if (error.message.includes("401")) {
return false
}
return true
const errorMessage = error?.message || "";
return !errorMessage.includes("401");
}
});

// Mutation to add a subscriber
const mutation = useMutation({
mutationFn: (newSubscriber: Subscriber) => addSubscriber(newSubscriber, auth.user?.authToken || ""),
onSuccess: () => {
// On successful addition, invalidate the query to refresh
handleRefresh()
// Close model
setCreateModalVisible(false);
},
});

const handleCreateSubscriber = async (newSubscriber: Subscriber) => {
try {
// Trigger mutation
await mutation.mutateAsync(newSubscriber);
} catch (error) {
console.error("Error adding subscriber:", error);
}
};

const editSubscriber = async (updatedSubscriber: Subscriber, token: string | undefined) => {
const response = await fetch(`/api/subscribers/${updatedSubscriber.ueId}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify(updatedSubscriber),
});

if (!response.ok) {
const errorBody = await response.json().catch(() => ({}));
throw new Error(errorBody.message || "Failed to edit subscriber");
}

return response.json();
};

const editMutation = useMutation({
mutationFn: (updatedSubscriber: Subscriber) =>
editSubscriber(updatedSubscriber, auth.user?.authToken || ""), // Perform edit request
onSuccess: () => {
handleRefresh();
// Close the modal after success
setEditModalVisible(false);
},
onError: (error) => {
console.error("Error editing subscriber:", error);
},
});

const deleteSubscriberWithImsi = async (subscriberImsi: string) => {
await deleteSubscriber(subscriberImsi, auth.user?.authToken || "");
};

const deleteSubscriberMutation = useMutation({
mutationFn: async (subscriberImsi: string) => {
await deleteSubscriberWithImsi(subscriberImsi)
},
onSuccess: () => {
// Invalidate and refetch subscriber
queryClient.invalidateQueries({ queryKey: [queryKeys.subscribers] });
window.location.reload();
},
onError: (error) => {
console.error("Error deleting subscriber:", error);
},
});

const handleEditSubscriber = async (updatedSubscriber: Subscriber) => {
try {
await editMutation.mutateAsync(updatedSubscriber);
} catch (error) {
console.error("Error editing subscriber:", error);
}
};

const handleConfirmDelete = async (subscriberImsi: string) => {
deleteSubscriberMutation.mutate(subscriberImsi, {
onSuccess: () => {
handleRefresh();
},
});
};

const { data: deviceGroups = [], isLoading: isDeviceGroupsLoading } = useQuery({
queryKey: [queryKeys.deviceGroups, auth.user?.authToken],
queryFn: () => getDeviceGroups(auth.user ? auth.user.authToken : ""),
enabled: auth.user ? true : false,
queryFn: () => getDeviceGroups(auth.user?.authToken || ""),
enabled: Boolean(auth.user),
});

const { data: slices = [], isLoading: isSlicesLoading } = useQuery({
queryKey: [queryKeys.networkSlices, auth.user?.authToken],
queryFn: () => getNetworkSlices(auth.user ? auth.user.authToken : ""),
enabled: auth.user ? true : false,
queryFn: () => getNetworkSlices(auth.user?.authToken || ""),
enabled: Boolean(auth.user),
});

if (subscribersQueryStatus == "error") {
Expand All @@ -68,10 +169,6 @@ const Subscribers = () => {
await queryClient.invalidateQueries({ queryKey: [queryKeys.networkSlices] });
};

const handleConfirmDelete = async (subscriber: string) => {
await deleteSubscriber(subscriber, auth.user ? auth.user.authToken : "");
await handleRefresh();
};

const toggleCreateModal = () => setCreateModalVisible((prev) => !prev);
const toggleEditModal = () => setEditModalVisible((prev) => !prev);
Expand Down Expand Up @@ -165,9 +262,21 @@ const Subscribers = () => {
rows={tableContent}
/>
</PageContent>
{isCreateModalVisible && <SubscriberModal toggleModal={toggleCreateModal} slices={slices} deviceGroups={deviceGroups} />}
{isCreateModalVisible && (
<SubscriberModal
toggleModal={toggleCreateModal}
onSubmit={(newSubscriber: any) => handleCreateSubscriber(newSubscriber)}
slices={slices}
deviceGroups={deviceGroups}
/>)
}
{isEditModalVisible &&
<SubscriberModal toggleModal={toggleEditModal} subscriber={subscriber} slices={slices} deviceGroups={deviceGroups} />}
<SubscriberModal toggleModal={toggleEditModal}
subscriber={subscriber}
slices={slices}
deviceGroups={deviceGroups}
onSubmit={handleEditSubscriber}
/>}
</>
);
};
Expand Down
7 changes: 4 additions & 3 deletions components/NetworkSliceModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@ interface NetworkSliceValues {
}

interface NetworkSliceModalProps {
networkSlice?: NetworkSlice;
toggleModal: () => void;
networkSlice?: NetworkSlice,
toggleModal: () => void,
onSave?: (newSlice: NetworkSlice) => void
}

const NetworkSliceModal = ({ networkSlice, toggleModal }: NetworkSliceModalProps) => {
const NetworkSliceModal = ({ networkSlice, toggleModal, onSave }: NetworkSliceModalProps) => {
const auth = useAuth()
const queryClient = useQueryClient();
const [apiError, setApiError] = useState<string | null>(null);
Expand Down
Loading

0 comments on commit 478e850

Please sign in to comment.