Skip to content

Commit

Permalink
Merge pull request #6 from kotalco/ipfs
Browse files Browse the repository at this point in the history
Ipfs
  • Loading branch information
mFarghaly authored Oct 11, 2023
2 parents 06517aa + f1e12e8 commit c0493c9
Show file tree
Hide file tree
Showing 30 changed files with 2,435 additions and 15 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@radix-ui/react-dropdown-menu": "^2.0.5",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-popover": "^1.0.6",
"@radix-ui/react-radio-group": "^1.1.3",
"@radix-ui/react-select": "^1.2.2",
"@radix-ui/react-separator": "^1.0.3",
"@radix-ui/react-slot": "^1.0.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ import { zodResolver } from "@hookform/resolvers/zod";

import { client } from "@/lib/client-instance";
import { ChainlinkNode, ExecutionClientNode } from "@/types";
import { Roles, SecretType } from "@/enums";
import { Roles } from "@/enums";
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ export default async function BeaconNodePage({
<TabsContent className="px-4 py-3 sm:px-6 sm:py-4" value="logs">
{token && (
<Logs
url={`ethereum2/beaconnodes/${node.name}/logs?authorization=Bearer ${token}&workspace_id=${params.workspaceId}`}
url={`ethereum2/beaconnodes/${node.name}/logs?authorization=Bearer ${token.value}&workspace_id=${params.workspaceId}`}
/>
)}
</TabsContent>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ export default async function BeaconNodePage({
<TabsContent className="px-4 py-3 sm:px-6 sm:py-4" value="logs">
{token && (
<Logs
url={`ethereum2/validators/${node.name}/logs?authorization=Bearer ${token}&workspace_id=${params.workspaceId}`}
url={`ethereum2/validators/${node.name}/logs?authorization=Bearer ${token.value}&workspace_id=${params.workspaceId}`}
/>
)}
</TabsContent>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
"use client";

import { useState } from "react";
import { useParams, useRouter } from "next/navigation";
import qs from "query-string";

import { AlertModal } from "@/components/modals/alert-modal";
import { DeleteNodeForm } from "@/components/delete-node-form";
import { useToast } from "@/components/ui/use-toast";
import { TabsFooter } from "@/components/ui/tabs";
import { Button } from "@/components/ui/button";
import { IPFSClusterPeer } from "@/types";
import { client } from "@/lib/client-instance";

interface DangerZoneTabProps {
node: IPFSClusterPeer;
}

export const DangerZoneTab: React.FC<DangerZoneTabProps> = ({ node }) => {
const params = useParams();
const router = useRouter();
const { toast } = useToast();

const [open, setOpen] = useState(false);

async function onDeleteIPFSClusterPeer() {
const url = qs.stringifyUrl({
url: `/ipfs/clusterpeers/${node.name}`,
query: { workspace_id: params.workspaceId },
});
await client.delete(url);
router.push(
`/${params.workspaceId}/deployments/ipfs?deployment=cluster-peers`
);
router.refresh();
toast({
title: "Cluster peer has been deleted",
description: `${node.name} peer has been deleted successfully.`,
});
setOpen(false);
}

return (
<>
<div>
<p className="text-muted-foreground">
By deleting this peer, all connected apps will lose access to the
Blockchain Network.
</p>
<p className="text-muted-foreground">
Peer attached volume that persists Blockchain data will not be
removed, you need to delete it yourself.
</p>
<p className="text-muted-foreground">
Are you sure you want to delete this peer?
</p>
<TabsFooter>
<Button
variant="destructive"
className="btn btn-alert"
onClick={() => setOpen(true)}
>
Delete Peer
</Button>
</TabsFooter>
</div>

<AlertModal
isOpen={open}
onClose={() => setOpen(false)}
title="Delete Cluster Peer"
description={`This action cann't be undone. This will permnantly delete (${node.name}) Cluster Peer.`}
>
<DeleteNodeForm
nodeName={node.name}
onDelete={onDeleteIPFSClusterPeer}
/>
</AlertModal>
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
"use client";

import * as z from "zod";
import { isAxiosError } from "axios";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";

import { client } from "@/lib/client-instance";
import { IPFSClusterPeer, IPFSPeer } from "@/types";
import { Roles } from "@/enums";
import {
Form,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Button } from "@/components/ui/button";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { TabsFooter } from "@/components/ui/tabs";
import { SelectWithInput } from "@/components/ui/select-with-input";
import { MultiSelect } from "@/components/ui/multi-select";
import { Label } from "@/components/ui/label";

interface PeersTabProps {
node: IPFSClusterPeer;
role: Roles;
peers: IPFSPeer[];
clusterPeers: IPFSClusterPeer[];
}

const schema = z.object({
peerEndpoint: z
.string({ required_error: "Peer endpoint is required" })
.min(1, "Peer endpoint is required")
.trim(),
bootstrapPeers: z.string().array().optional(),
});

type Schema = z.infer<typeof schema>;

export const PeersTab: React.FC<PeersTabProps> = ({
node,
role,
peers,
clusterPeers,
}) => {
const { peerEndpoint, bootstrapPeers, trustedPeers } = node;
const peerEndpoints = peers.map(({ name }) => ({
label: name,
value: `/dns4/${name}/tcp/5001`,
}));

const ipfsClusterPeers = clusterPeers.map(({ name, id }) => ({
label: name,
value: `/dns4/${name}/tcp/9096/p2p/${id}`,
}));

const form = useForm<Schema>({
resolver: zodResolver(schema),
defaultValues: { peerEndpoint, bootstrapPeers },
});

const {
formState: {
isSubmitted,
isSubmitting,
isValid,
isDirty,
isSubmitSuccessful,
errors,
},
reset,
setError,
} = form;

const onSubmit = async (values: Schema) => {
try {
const { data } = await client.put<IPFSClusterPeer>(
`/ipfs/clusterpeers/${node.name}`,
values
);
const { peerEndpoint, bootstrapPeers } = data;
reset({ peerEndpoint, bootstrapPeers });
} catch (error) {
if (isAxiosError(error)) {
const { response } = error;

setError("root", {
type: response?.status.toString(),
message: "Something went wrong.",
});
}
}
};

return (
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="relative space-y-4"
>
<FormField
control={form.control}
name="peerEndpoint"
render={({ field }) => (
<FormItem className="max-w-xs">
<FormLabel>IPFS Peer</FormLabel>
<SelectWithInput
placeholder="Select a Peer"
disabled={isSubmitting || role === Roles.Reader}
onChange={field.onChange}
defaultValue={field.value}
value={field.value}
options={peerEndpoints}
otherLabel="Use External Peer"
/>
<FormMessage />
</FormItem>
)}
/>

<FormField
shouldUnregister={true}
control={form.control}
name="bootstrapPeers"
render={({ field }) => (
<FormItem>
<FormLabel>Bootstrap Cluster Peers</FormLabel>
<div>
<div className="max-w-xs">
<MultiSelect
defaultValue={field.value}
disabled={isSubmitting || role === Roles.Reader}
value={field.value}
placeholder="Select bootstrap peers"
options={ipfsClusterPeers}
onChange={field.onChange}
emptyText="Enter your own peers"
allowCustomValues
/>
</div>
<FormDescription>
Select cluster peers or enter your own peers
</FormDescription>
</div>

<FormMessage />
</FormItem>
)}
/>

{!!trustedPeers && (
<div className="max-w-xs mt-4">
<Label>Trusted Cluster Peers</Label>
<ul className="ml-5 text-sm">
{trustedPeers.map((peer) => (
<li key={peer} className="text-foreground/50 list-disc">
{peer}
</li>
))}
</ul>
</div>
)}

{isSubmitSuccessful && (
<Alert variant="success" className="text-center">
<AlertDescription>
Peers settings have been updated successfully.
</AlertDescription>
</Alert>
)}

{errors.root && (
<Alert variant="destructive" className="text-center">
<AlertDescription>{errors.root.message}</AlertDescription>
</Alert>
)}

{role !== Roles.Reader && (
<TabsFooter>
<Button
disabled={(isSubmitted && !isValid) || isSubmitting || !isDirty}
data-testid="submit"
type="submit"
>
Save
</Button>
</TabsFooter>
)}
</form>
</Form>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { EditImageVersionForm } from "@/components/edit-image-version-form";
import { ConsensusAlgorithm, Roles } from "@/enums";
import { getEnumKey } from "@/lib/utils";
import { IPFSClusterPeer, Version } from "@/types";

interface ProtocolTabProps {
node: IPFSClusterPeer;
role: Roles;
versions: Version[];
}

export const ProtocolTab: React.FC<ProtocolTabProps> = ({
node,
role,
versions,
}) => {
const { image, name, consensus, id, privatekeySecretName } = node;
return (
<>
<ul className="space-y-3">
<li className="flex flex-col">
<span className="text-sm font-medium text-foreground">Protocol</span>
<span className="text-sm text-foreground/50">IPFS</span>
</li>

<li className="flex flex-col">
<span className="text-sm font-medium text-foreground">Chain</span>
<span className="text-sm text-foreground/50">public-swarm</span>
</li>

<li className="flex flex-col">
<span className="text-sm font-medium text-foreground">Client</span>
<a
href="https://github.com/ipfs/ipfs-cluster"
target="_blank"
rel="noreferrer"
className="text-primary hover:underline"
>
ipfs-cluster-service
</a>
</li>

<li className="flex flex-col">
<span className="text-sm font-medium text-foreground">Consensus</span>
<span className="text-sm text-foreground/50">
{getEnumKey(ConsensusAlgorithm, consensus)}
</span>
</li>

{id && (
<li className="flex flex-col">
<span className="text-sm font-medium text-foreground">ID</span>
<span className="text-sm text-foreground/50">{id}</span>
</li>
)}

{privatekeySecretName && (
<li className="flex flex-col">
<span className="text-sm font-medium text-foreground">From</span>
<span className="text-sm text-foreground/50">
{privatekeySecretName}
</span>
</li>
)}
</ul>
<EditImageVersionForm
role={role}
versions={versions}
image={image}
updateUrl={`/ipfs/clusterpeers/${name}`}
/>
</>
);
};
Loading

0 comments on commit c0493c9

Please sign in to comment.