Skip to content

Commit

Permalink
feat: register a module
Browse files Browse the repository at this point in the history
Co-authored-by: Kelvin Steiner <[email protected]>
Co-authored-by: PsicoThePato <[email protected]>
  • Loading branch information
3 people committed Oct 16, 2024
1 parent ffd29da commit 56d2223
Show file tree
Hide file tree
Showing 6 changed files with 307 additions and 33 deletions.
8 changes: 7 additions & 1 deletion apps/commune-governance/src/app/components/modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
Select,
SelectContent,
SelectItem,
SelectSeparator,
SelectTrigger,
SelectValue,
Separator,
Expand All @@ -22,6 +23,7 @@ import {
import { CreateDao } from "./dao/create-dao";
import { CreateProposal } from "./proposal/create-proposal";
import { CreateTransferDaoTreasuryProposal } from "./proposal/create-transfer-dao-treasury-proposal";
import { RegisterModule } from "./proposal/register-module";

export function CreateModal() {
const [selectedView, setSelectedView] = useState("proposal");
Expand Down Expand Up @@ -49,15 +51,19 @@ export function CreateModal() {
<SelectItem value="create-transfer-dao-treasury">
Create Transfer Dao Treasury Proposal
</SelectItem>
<SelectSeparator />
<SelectItem value="register-module">Register a Module</SelectItem>
</SelectContent>
</Select>
<Separator />
{selectedView === "proposal" ? (
<CreateProposal />
) : selectedView === "dao" ? (
<CreateDao />
) : (
) : selectedView === "create-transfer-dao-treasury" ? (
<CreateTransferDaoTreasuryProposal />
) : (
<RegisterModule />
)}
</DialogContent>
</Dialog>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
import { useState } from "react";
import { useRouter } from "next/navigation";
import MarkdownPreview from "@uiw/react-markdown-preview";
import { z } from "zod";

import type { TransactionResult } from "@commune-ts/types";
import { useCommune } from "@commune-ts/providers/use-commune";
import { toast } from "@commune-ts/providers/use-toast";
import {
Button,
Input,
Label,
Separator,
Tabs,
TabsContent,
TabsList,
TabsTrigger,
Textarea,
TransactionStatus,
} from "@commune-ts/ui";

import { cairo } from "~/utils/fonts";

const moduleSchema = z.object({
title: z.string().min(1, "Title is required"),
body: z.string().min(1, "Body is required"),
});

export function RegisterModule(): JSX.Element {
const router = useRouter();
const { isConnected, registerModule, balance } = useCommune();

const [subnetName, setSubnetName] = useState("");
const [address, setAddress] = useState("");
const [name, setName] = useState("");
const [moduleId, setModuleId] = useState("");

const [title, setTitle] = useState("");
const [body, setBody] = useState("");

const [uploading, setUploading] = useState(false);
const [activeTab, setActiveTab] = useState("edit");

const [transactionStatus, setTransactionStatus] = useState<TransactionResult>(
{
status: null,
message: null,
finalized: false,
},
);

function handleCallback(callbackReturn: TransactionResult): void {
setTransactionStatus(callbackReturn);
}

async function uploadFile(fileToUpload: File): Promise<void> {
try {
setUploading(true);
const data = new FormData();
data.set("file", fileToUpload);
const res = await fetch("/api/files", {
method: "POST",
body: data,
});
const ipfs = (await res.json()) as { IpfsHash: string };
setUploading(false);

if (ipfs.IpfsHash === "undefined" || !ipfs.IpfsHash) {
toast.error("Error uploading transfer dao treasury moduleCost");
return;
}

if (!balance) {
toast.error("Balance is still loading");
return;
}

const moduleCost = 2000;

if (Number(balance) > moduleCost) {
void registerModule({
subnetName,
address,
name,
moduleId,
metadata: `ipfs://${ipfs.IpfsHash}`,
callback: handleCallback,
});
} else {
toast.error(
`Insufficient balance to create module. Required: ${moduleCost} but got ${balance}`,
);
setTransactionStatus({
status: "ERROR",
finalized: true,
message: "Insufficient balance",
});
}
router.refresh();
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (e) {
setUploading(false);
toast.error("Error uploading module");
}
}

function HandleSubmit(event: React.FormEvent<HTMLFormElement>): void {
event.preventDefault();
setTransactionStatus({
status: "STARTING",
finalized: false,
message: "Starting module creation...",
});

const result = moduleSchema.safeParse({
title,
body,
});

if (!result.success) {
toast.error(result.error.errors.map((e) => e.message).join(", "));
setTransactionStatus({
status: "ERROR",
finalized: true,
message: "Error on form validation",
});
return;
}

const moduleData = JSON.stringify({
title,
body,
});
const blob = new Blob([moduleData], { type: "application/json" });
const fileToUpload = new File([blob], "proposal.json", {
type: "application/json",
});
void uploadFile(fileToUpload);
}

return (
<form
onSubmit={HandleSubmit}
className="flex flex-col gap-4 text-green-500"
>
<Tabs value={activeTab} onValueChange={setActiveTab}>
<TabsList>
<TabsTrigger value="edit">Edit Content</TabsTrigger>
<TabsTrigger value="preview">Preview Content</TabsTrigger>
</TabsList>
<TabsContent value="edit" className="flex flex-col gap-3">
<Input
onChange={(e) => setName(e.target.value)}
placeholder="Module Name (eg. ren-labs)"
type="text"
value={name}
/>
<Input
onChange={(e) => setModuleId(e.target.value)}
placeholder="Module ID (SS58 Address)"
type="text"
value={moduleId}
/>
<Input
onChange={(e) => setSubnetName(e.target.value)}
placeholder="Subnet Name (eg. General)"
type="text"
value={subnetName}
/>
<Input
onChange={(e) => setAddress(e.target.value)}
placeholder="Address (eg. 0.0.0.0:8000)"
type="text"
value={address}
/>
<Separator />
<Input
onChange={(e) => setTitle(e.target.value)}
placeholder="Your Module title here..."
type="text"
value={title}
/>
<Textarea
onChange={(e) => setBody(e.target.value)}
placeholder="Your module body here... (Markdown supported / HTML tags are not supported)"
rows={5}
value={body}
/>
</TabsContent>
<TabsContent value="preview" className="bg-muted p-4">
{body ? (
<MarkdownPreview
className={`${cairo.className} max-h-[40vh] overflow-auto`}
source={`# ${title}\n${body}`}
style={{
backgroundColor: "transparent",
color: "white",
}}
/>
) : (
<Label className="text-sm text-white">
Fill the body to preview here :)
</Label>
)}
</TabsContent>
</Tabs>
<Button
size="xl"
type="submit"
variant="default-green"
disabled={!isConnected}
>
{uploading ? "Uploading..." : "Submit Module"}
</Button>
{transactionStatus.status && (
<TransactionStatus
status={transactionStatus.status}
message={transactionStatus.message}
/>
)}
</form>
);
}
36 changes: 19 additions & 17 deletions apps/commune-validator/src/app/components/charts/_common.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import { assert } from "tsafe";

const separateTopAndOther =
<T>(
numTop: number,
compare: (a: T, b: T) => number,
reduceRest: (xs: T[]) => T,
) =>
(xs: T[]) => {
assert(xs.length >= numTop);
const sorted = xs.sort(compare);
const top = sorted.slice(0, numTop);
const rest = sorted.slice(numTop);
const other = reduceRest(rest);
return [...top, other];
};
const separateTopAndOther = <T>(
numTop: number,
compare: (a: T, b: T) => number,
reduceRest: (xs: T[]) => T,
xs: T[],
) => {
assert(xs.length >= numTop);
const sorted = xs.sort(compare);
const top = sorted.slice(0, numTop);
const rest = sorted.slice(numTop);
const other = reduceRest(rest);
return [...top, other];
};

interface ModuleStakeItem {
moduleName: string | null;
Expand All @@ -37,9 +36,12 @@ const reduceModuleItems =
},
);

export const separateTopNModules = () =>
const nonZeroModuleItem = (x: ModuleStakeItem) => x.stakeWeight > 0n;

export const separateTopNModules = (n: number) => (xs: ModuleStakeItem[]) =>
separateTopAndOther(
8,
n,
(a, b) => Number(-(a.stakeWeight - b.stakeWeight)),
reduceModuleItems("Other"),
);
xs,
).filter(nonZeroModuleItem);
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ interface ModuleData {
moduleName: string;
stakeWeight: string;
percWeight: number;
percFormat: string;
}

interface ModuleBarChartProps {
Expand Down Expand Up @@ -94,7 +95,7 @@ export function ModuleBarChart({ chartData }: ModuleBarChartProps) {
fontSize={12}
/>
<LabelList
dataKey="percWeight"
dataKey="percFormat"
position="right"
offset={8}
className="fill-foreground"
Expand Down
Loading

0 comments on commit 56d2223

Please sign in to comment.