Skip to content

Commit

Permalink
gogo
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanleecode committed Jun 11, 2024
1 parent b0b4898 commit 59398fa
Show file tree
Hide file tree
Showing 10 changed files with 9,755 additions and 7,949 deletions.
16,854 changes: 9,376 additions & 7,478 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions projects/wallet-template/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,6 @@
"wxt": "^0.17.12"
},
"dependencies": {
"@substrate/connect-discovery": "workspace:^",
"@substrate/discovery": "workspace:^",
"@headlessui/react": "^1.7.19",
"@hookform/resolvers": "^3.4.0",
"@noble/ciphers": "^0.5.2",
Expand Down Expand Up @@ -100,7 +98,9 @@
"@radix-ui/react-tooltip": "^1.0.7",
"@react-rxjs/core": "^0.10.7",
"@react-rxjs/utils": "^0.9.7",
"@substrate/connect-discovery": "workspace:^",
"@substrate/connect-extension-protocol": "workspace:*",
"@substrate/discovery": "workspace:^",
"@substrate/light-client-extension-helpers": "workspace:^",
"@zag-js/clipboard": "^0.47.0",
"@zag-js/react": "^0.47.0",
Expand All @@ -122,11 +122,12 @@
"react-resizable-panels": "^2.0.19",
"react-router-dom": "^6.22.3",
"rxjs": "^7.8.1",
"sonner": "^1.4.41",
"smoldot": "2.0.26",
"sonner": "^1.4.41",
"swr": "^2.2.5",
"tailwind-merge": "^2.3.0",
"tailwindcss-animate": "^1.0.7",
"usehooks-ts": "^3.1.0",
"vaul": "^0.9.1",
"zod": "^3.23.8"
}
Expand Down
5 changes: 2 additions & 3 deletions projects/wallet-template/src/containers/Options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ import pckg from "../../package.json"
import { FaGithub } from "react-icons/fa"
import * as environment from "../environment"
import { BraveModal, Logo, MenuContent, Bootnodes } from "../components"
import { ChainSpecs } from "./WalletPopup/pages/Options/Chainspecs"
import { Link } from "react-router-dom"
import { useActiveChains } from "@/hooks/useActiveChains"
import { NetworkTabProps } from "@/types"
import { NetworkTab } from "./WalletPopup/components"
import { Accordion } from "@/components/ui/accordion"
import ChainSpecs2 from "./WalletPopup/pages/Options/ChainSpecs2"
import { ChainSpecs } from "./WalletPopup/pages/Options/ChainSpecs"

type MenuItemTypes = "item" | "title" | "icon"

Expand Down Expand Up @@ -206,7 +205,7 @@ export const Options: FunctionComponent = () => {
) : menu === 1 ? (
<Bootnodes />
) : menu === 2 ? (
<ChainSpecs2 />
<ChainSpecs />
) : null}
</MenuContent>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Button, ButtonProps } from "@/components/ui/button"
import { CheckIcon, CopyIcon } from "lucide-react"
import { useState } from "react"
import { useDebounceCallback } from "usehooks-ts"

export namespace CopyButton {
export interface Props extends ButtonProps {
text: string
copyResetDelayMs?: number
}
}

const COPY_RESET_DELAY_MS = 2000

export const CopyButton: React.FC<CopyButton.Props> = ({

Check warning on line 15 in projects/wallet-template/src/containers/WalletPopup/components/CopyButton.tsx

View workflow job for this annotation

GitHub Actions / build (20.x)

'CopyButton' is already defined

Check warning on line 15 in projects/wallet-template/src/containers/WalletPopup/components/CopyButton.tsx

View workflow job for this annotation

GitHub Actions / build (18.x)

'CopyButton' is already defined

Check warning on line 15 in projects/wallet-template/src/containers/WalletPopup/components/CopyButton.tsx

View workflow job for this annotation

GitHub Actions / playwright-test-examples

'CopyButton' is already defined

Check warning on line 15 in projects/wallet-template/src/containers/WalletPopup/components/CopyButton.tsx

View workflow job for this annotation

GitHub Actions / playwright-test-wallet-template

'CopyButton' is already defined

Check warning on line 15 in projects/wallet-template/src/containers/WalletPopup/components/CopyButton.tsx

View workflow job for this annotation

GitHub Actions / connect-flaky-tests

'CopyButton' is already defined

Check warning on line 15 in projects/wallet-template/src/containers/WalletPopup/components/CopyButton.tsx

View workflow job for this annotation

GitHub Actions / playwright-test-extension

'CopyButton' is already defined

Check warning on line 15 in projects/wallet-template/src/containers/WalletPopup/components/CopyButton.tsx

View workflow job for this annotation

GitHub Actions / zombienet-tests

'CopyButton' is already defined
text,
onClick,
copyResetDelayMs,
...props
}) => {
const [isCopied, setIsCopied] = useState(false)
const setIsCopiedDebounced = useDebounceCallback(
setIsCopied,
copyResetDelayMs ?? COPY_RESET_DELAY_MS,
)

const copy = () => {
copyToClipboard(text)
setIsCopied(true)
setIsCopiedDebounced(false)
}

return (
<Button
variant={isCopied ? "ghost" : "outline"}
size="sm"
onClick={(e) => {
copy()
onClick?.(e)
}}
{...props}
>
{isCopied ? (
<>
<CheckIcon className="w-4 h-4 mr-2" />
Copied
</>
) : (
<>
<CopyIcon className="w-4 h-4 mr-2" />
Copy JSON
</>
)}
</Button>
)
}

function copyToClipboard(text: string) {
navigator.clipboard.writeText(text)
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ export * from "./UserSignedExtensions"
export * from "./ProtectedRoute"
export * from "./Header"
export * from "./BottomNavBar"
export * from "./CopyButton"
export { default as NetworkTab } from "./NetworkTab"
Original file line number Diff line number Diff line change
@@ -1,76 +1,154 @@
import React from "react"
import React, { useState } from "react"
import { useForm, SubmitHandler } from "react-hook-form"
import { CheckCircle, Loader } from "lucide-react"
import { useSWRConfig } from "swr"
import { CheckCircle, UploadIcon } from "lucide-react"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"

import { rpc } from "../../api"
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
import { Label } from "@/components/ui/label"
import { Textarea } from "@/components/ui/textarea"
import { Input } from "@/components/ui/input"
import { Button } from "@/components/ui/button"
import { z } from "zod"
import { zodResolver } from "@hookform/resolvers/zod"
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form"

type FormFields = {
chainSpec: string
rawChainSpec: string
}

export const AddChainSpec: React.FC = () => {
const formSchema = z.object({
rawChainSpec: z
.string({ required_error: "Raw Chain Spec is required" })
.min(1, "Chain Spec is empty")
.trim(),
})

export namespace AddChainSpec {
export type Props = {
addChainSpec: (rawChainSpec: string) => Promise<void>
}
}

type InputMethod = "upload" | "paste" | (string & {})

export const AddChainSpec: React.FC<AddChainSpec.Props> = ({
addChainSpec,
}) => {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
rawChainSpec: "",
},
})
const {
register,
handleSubmit,
formState: { isSubmitting, errors, isSubmitted, isSubmitSuccessful },
} = useForm<FormFields>()
const { mutate } = useSWRConfig()
} = form
const [inputMethod, setInputMethod] = useState<InputMethod>("paste")

const onSubmit: SubmitHandler<FormFields> = async ({ chainSpec }) => {
await rpc.client.addChainSpec(chainSpec)
await mutate("rpc.getChainSpecs")
const onSubmit: SubmitHandler<FormFields> = async ({
rawChainSpec: chainSpec,
}) => {
await addChainSpec(chainSpec)
}

return (
<section aria-labelledby="manual-entry-heading">
<h2 id="manual-entry-heading" className="font-semibold">
Enter Chain Specification
</h2>
<form onSubmit={handleSubmit(onSubmit)}>
<textarea
{...register("chainSpec", {
required: "You must specify a chain specification",
})}
className="w-full border border-gray-200 rounded-md p-2 mt-2"
aria-label="Manual chainspec input"
placeholder="Paste your chain specification here..."
rows={8}
></textarea>
{errors.chainSpec && (
<p className="text-red-500 text-sm mt-1">
{errors.chainSpec.message}
</p>
)}

<div className="mt-4 flex justify-center items-center">
<button
type="submit"
className="border border-gray-300 text-gray-600 py-2 px-4 rounded hover:bg-gray-100 flex items-center disabled:opacity-50"
disabled={isSubmitting}
>
{isSubmitting ? (
<>
<Loader className="animate-spin h-5 w-5 mr-3" />
Submitting...
</>
) : (
"Submit Chain Specification"
)}
</button>
</div>
<Card>
<CardHeader>
<CardTitle>Allow a Chain Spec</CardTitle>
</CardHeader>
<CardContent>
<Form {...form}>
<form onSubmit={handleSubmit(onSubmit)}>
<div className="grid gap-4 mb-4">
<RadioGroup
value={inputMethod}
onValueChange={setInputMethod}
className="mb-4"
>
<div className="flex items-center mb-2">
<RadioGroupItem value="paste" />
<Label className="ml-2 text-foreground">
Paste Chain Spec JSON
</Label>
</div>
<div className="flex items-center">
<RadioGroupItem value="upload" />
<Label className="ml-2 text-foreground">
Upload Chain Spec File
</Label>
</div>
</RadioGroup>
{inputMethod === "paste" && (
<FormField
control={form.control}
name="rawChainSpec"
render={({ field }) => (
<FormItem>
<FormLabel>Paste Chain Spec JSON</FormLabel>
<FormControl>
<Textarea
placeholder="Paste your chainspec JSON here..."
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
)}
{inputMethod === "upload" && (
<FormField
control={form.control}
name="rawChainSpec"
render={({ field: { value, onChange, ...fieldProps } }) => (
<FormItem>
<FormLabel>Upload Chain Spec File</FormLabel>
<FormControl>
<Input
{...fieldProps}
type="file"
onChange={async (event) =>
onChange(
event.target.files &&
(await event.target.files[0].text()),
)
}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
)}
</div>
<div className="flex justify-end">
<Button type="submit" disabled={isSubmitting}>
<UploadIcon className="w-4 h-4 mr-2" />
Submit
</Button>
</div>
</form>
</Form>
{isSubmitted && isSubmitSuccessful && (
<p className="text-green-500 text-center mt-2">
<p className="mt-2 text-center text-primary">
<CheckCircle className="inline-block mr-2" />
Chain specification submitted successfully.
</p>
)}
{isSubmitted && !isSubmitSuccessful && (
<p className="text-red-500 text-center mt-2">
{isSubmitted && !isSubmitSuccessful && errors && (
<p className="mt-2 text-center text-destructive">
Error submitting chain specification.
</p>
)}
</form>
</section>
</CardContent>
</Card>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { useState } from "react"
import { ListChainSpecs } from "./ListChainSpecs"
import useSWR from "swr"
import { rpc } from "../../api"
import { ChainSpec } from "@/background/types"
import { AddChainSpec } from "./AddChainSpec"

export const ChainSpecs = () => {
const { data: chainSpecs, mutate } = useSWR(
"rpc.getChainSpecs",
() => rpc.client.getChainSpecs(),
{ revalidateOnFocus: true },
)

const [view, setView] = useState<"list" | "allow" | (string & {})>("list")

const addChainSpec = async (rawChainSpec: string) => {
await rpc.client.addChainSpec(rawChainSpec)
await mutate()
}

const removeChainSpec = async (chainSpec: ChainSpec) => {
await rpc.client.removeChainSpec(chainSpec.genesisHash)
await mutate()
}

return (
<div className="container">
<h2 className="mb-6 text-3xl font-semibold">
Manage Chain Specifications
</h2>

<Tabs defaultValue={view} onValueChange={setView}>
<TabsList className="mb-6">
<TabsTrigger value="list">Allowlist</TabsTrigger>
<TabsTrigger value="allow">Add ChainSpec</TabsTrigger>
</TabsList>

<TabsContent value="list">
<ListChainSpecs
chainSpecs={chainSpecs ?? []}
removeChainSpec={removeChainSpec}
/>
</TabsContent>

<TabsContent value="allow">
<AddChainSpec addChainSpec={addChainSpec} />
</TabsContent>
</Tabs>
</div>
)
}
Loading

0 comments on commit 59398fa

Please sign in to comment.