Skip to content

Commit

Permalink
Add resource group modal and adjust tables
Browse files Browse the repository at this point in the history
  • Loading branch information
heisbrot committed Jan 13, 2025
1 parent 92eef5f commit 449344f
Show file tree
Hide file tree
Showing 8 changed files with 240 additions and 68 deletions.
36 changes: 36 additions & 0 deletions src/modules/networks/NetworkProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Network, NetworkResource, NetworkRouter } from "@/interfaces/Network";
import { AccessControlModalContent } from "@/modules/access-control/AccessControlModal";
import NetworkModal from "@/modules/networks/NetworkModal";
import NetworkResourceModal from "@/modules/networks/resources/NetworkResourceModal";
import { ResourceGroupModal } from "@/modules/networks/resources/ResourceGroupModal";
import NetworkRoutingPeerModal from "@/modules/networks/routing-peers/NetworkRoutingPeerModal";

type Props = {
Expand All @@ -23,6 +24,10 @@ const NetworksContext = React.createContext(
openEditNetworkModal: (network: Network) => void;
openCreateNetworkModal: () => void;
openResourceModal: (network: Network, resource?: NetworkResource) => void;
openResourceGroupModal: (
network: Network,
resource?: NetworkResource,
) => void;
openPolicyModal: (network?: Network, resource?: NetworkResource) => void;
deleteNetwork: (network: Network) => void;
deleteResource: (network: Network, resource: NetworkResource) => void;
Expand All @@ -49,6 +54,7 @@ export const NetworkProvider = ({ children, network }: Props) => {
const [routingPeerModal, setRoutingPeerModal] = useState(false);
const [networkModal, setNetworkModal] = useState(false);
const [resourceModal, setResourceModal] = useState(false);
const [resourceGroupModal, setResourceGroupModal] = useState(false);
const [policyModal, setPolicyModal] = useState(false);

const openAddRoutingPeerModal = (
Expand Down Expand Up @@ -76,6 +82,15 @@ export const NetworkProvider = ({ children, network }: Props) => {
setResourceModal(true);
};

const openResourceGroupModal = (
network: Network,
resource?: NetworkResource,
) => {
setCurrentNetwork(network);
resource && setCurrentResource(resource);
setResourceGroupModal(true);
};

const openPolicyModal = (network?: Network, resource?: NetworkResource) => {
setPolicyDefaultSettings({
destinationGroups: resource?.groups,
Expand Down Expand Up @@ -217,6 +232,7 @@ export const NetworkProvider = ({ children, network }: Props) => {
openEditNetworkModal,
openCreateNetworkModal,
openResourceModal,
openResourceGroupModal,
openPolicyModal,
deleteNetwork,
deleteResource,
Expand Down Expand Up @@ -294,6 +310,26 @@ export const NetworkProvider = ({ children, network }: Props) => {
setRoutingPeerModal(state);
}}
/>

<ResourceGroupModal
network={currentNetwork}
resource={currentResource}
open={resourceGroupModal}
onOpenChange={(state) => {
setCurrentResource(undefined);
setResourceGroupModal(state);
}}
onUpdated={() => {
setResourceGroupModal(false);
setCurrentResource(undefined);
mutate("/groups");
if (network) {
mutate(`/networks/${network.id}/resources`);
mutate(`/networks/${network.id}`);
}
}}
/>

<NetworkResourceModal
network={currentNetwork}
resource={currentResource}
Expand Down
2 changes: 1 addition & 1 deletion src/modules/networks/resources/ResourceActionCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const ResourceActionCell = ({ resource }: Props) => {
const { deleteResource, network, openResourceModal } = useNetworksContext();

return (
<div className={"flex justify-end pr-4"}>
<div className={"flex justify-end"}>
<DropdownMenu modal={false}>
<DropdownMenuTrigger
asChild={true}
Expand Down
4 changes: 2 additions & 2 deletions src/modules/networks/resources/ResourceGroupCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ type Props = {
resource?: NetworkResource;
};
export const ResourceGroupCell = ({ resource }: Props) => {
const { network, openResourceModal } = useNetworksContext();
const { network, openResourceGroupModal } = useNetworksContext();

return (
<button
className={"flex cursor-pointer"}
onClick={() => {
if (!network) return;
openResourceModal(network, resource);
openResourceGroupModal(network, resource);
}}
>
<MultipleGroups groups={resource?.groups as Group[]} />
Expand Down
121 changes: 121 additions & 0 deletions src/modules/networks/resources/ResourceGroupModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import Button from "@components/Button";
import {
Modal,
ModalClose,
ModalContent,
ModalFooter,
} from "@components/modal/Modal";
import ModalHeader from "@components/modal/ModalHeader";
import { notify } from "@components/Notification";
import { PeerGroupSelector } from "@components/PeerGroupSelector";
import Separator from "@components/Separator";
import { useApiCall } from "@utils/api";
import { FolderGit2 } from "lucide-react";
import * as React from "react";
import { useMemo } from "react";
import { Network, NetworkResource } from "@/interfaces/Network";
import useGroupHelper from "@/modules/groups/useGroupHelper";

type ResourceGroupModalProps = {
resource?: NetworkResource;
network?: Network;
open: boolean;
onOpenChange: (open: boolean) => void;
onUpdated?: (r: NetworkResource) => void;
};
export const ResourceGroupModal = ({
resource,
network,
open,
onOpenChange,
onUpdated,
}: ResourceGroupModalProps) => {
return (
<Modal open={open} onOpenChange={onOpenChange}>
{network && resource && (
<ResourceGroupModalContent
network={network}
resource={resource}
onUpdated={onUpdated}
key={open ? "1" : "0"}
/>
)}
</Modal>
);
};

type ModalProps = {
onUpdated?: (r: NetworkResource) => void;
network?: Network;
resource?: NetworkResource;
};

const ResourceGroupModalContent = ({
resource,
network,
onUpdated,
}: ModalProps) => {
const update = useApiCall<NetworkResource>(
`/networks/${network?.id}/resources/${resource?.id}`,
).put;

const [groups, setGroups, { save: saveGroups }] = useGroupHelper({
initial: resource?.groups || [],
});

const updateResource = async () => {
const savedGroups = await saveGroups();
notify({
title: "Update Resource",
description: `'${resource?.name}' groups updated`,
loadingMessage: "Updating resource groups...",
promise: update({
...resource,
groups: savedGroups.map((g) => g.id),
}).then((r) => {
onUpdated?.(r);
}),
});
};

const canSave = useMemo(() => {
return groups.length > 0;
}, [groups]);

return (
<ModalContent maxWidthClass={"max-w-xl"}>
<ModalHeader
icon={<FolderGit2 size={18} />}
title={"Assigned Groups"}
description={
"Add this resource to groups and use them as destinations when creating policies"
}
color={"blue"}
/>

<Separator />

<div className={"px-8 py-6 flex flex-col gap-8"}>
<div>
<PeerGroupSelector onChange={setGroups} values={groups} />
</div>
</div>

<ModalFooter className={"items-center"}>
<div className={"flex gap-3 w-full justify-end"}>
<ModalClose asChild={true}>
<Button variant={"secondary"}>Cancel</Button>
</ModalClose>

<Button
variant={"primary"}
onClick={updateResource}
disabled={!canSave}
>
Save Groups
</Button>
</div>
</ModalFooter>
</ModalContent>
);
};
100 changes: 47 additions & 53 deletions src/modules/networks/resources/ResourcesTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,62 +91,56 @@ export default function ResourcesTable({
resources,
isLoading,
headingTarget,
}: Props) {
}: Readonly<Props>) {
const [sorting, setSorting] = useState<SortingState>([]);
const { openResourceModal, network } = useNetworksContext();

return (
<>
<DataTable
wrapperComponent={Card}
wrapperProps={{ className: "mt-6 w-full" }}
headingTarget={headingTarget}
sorting={sorting}
setSorting={setSorting}
minimal={true}
showSearchAndFilters={true}
inset={false}
tableClassName={"mt-0"}
text={"Resources"}
columns={NetworkResourceColumns}
keepStateInLocalStorage={false}
data={resources}
searchPlaceholder={"Search by name, address or group..."}
isLoading={isLoading}
getStartedCard={
<NoResults
className={"py-4"}
title={"This network has no resources"}
description={
"Add resources to this network to control what peers can access. Resources can be anything from a single IP, a subnet, or a domain."
}
icon={<Layers3Icon size={20} />}
/>
}
columnVisibility={{}}
paginationPaddingClassName={"px-0 pt-8"}
rightSide={() => (
<>
<Button
variant={"primary"}
className={"ml-auto"}
onClick={() => network && openResourceModal(network)}
>
<IconCirclePlus size={16} />
Add Resource
</Button>
</>
)}
>
{(table) => (
<>
<DataTableRowsPerPage
table={table}
disabled={!resources || resources?.length == 0}
/>
</>
)}
</DataTable>
</>
<DataTable
wrapperComponent={Card}
wrapperProps={{ className: "mt-6 pb-2 w-full" }}
headingTarget={headingTarget}
sorting={sorting}
setSorting={setSorting}
minimal={true}
showSearchAndFilters={true}
inset={false}
tableClassName={"mt-0"}
text={"Resources"}
columns={NetworkResourceColumns}
keepStateInLocalStorage={false}
data={resources}
searchPlaceholder={"Search by name, address or group..."}
isLoading={isLoading}
getStartedCard={
<NoResults
className={"py-4"}
title={"This network has no resources"}
description={
"Add resources to this network to control what peers can access. Resources can be anything from a single IP, a subnet, or a domain."
}
icon={<Layers3Icon size={20} />}
/>
}
columnVisibility={{}}
paginationPaddingClassName={"px-0 pt-8"}
rightSide={() => (
<Button
variant={"primary"}
className={"ml-auto"}
onClick={() => network && openResourceModal(network)}
>
<IconCirclePlus size={16} />
Add Resource
</Button>
)}
>
{(table) => (
<DataTableRowsPerPage
table={table}
disabled={!resources || resources?.length == 0}
/>
)}
</DataTable>
);
}
12 changes: 5 additions & 7 deletions src/modules/networks/routing-peers/NetworkRoutingPeerName.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,11 @@ export const NetworkRoutingPeerName = ({ router }: Props) => {

if (routingPeerGroup) {
return (
<>
<div className={"flex items-center gap-2 max-w-[295px] min-w-[295px]"}>
<GroupBadge group={routingPeerGroup} />
<ArrowRightIcon size={14} className={"shrink-0"} />
<PeerBadge> {routingPeerGroup.peers_count} Peer(s)</PeerBadge>
</div>
</>
<div className={"flex items-center gap-2 max-w-[295px] min-w-[295px]"}>
<GroupBadge group={routingPeerGroup} />
<ArrowRightIcon size={14} className={"shrink-0"} />
<PeerBadge> {routingPeerGroup.peers_count} Peer(s)</PeerBadge>
</div>
);
}
};
Loading

0 comments on commit 449344f

Please sign in to comment.