Compare commits
18 Commits
feat/long-
...
fix/tab-na
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb25986d72 | ||
|
|
309ad57173 | ||
|
|
25c5b9c015 | ||
|
|
407e3946ce | ||
|
|
dc5b0d71eb | ||
|
|
3fd6c3f50e | ||
|
|
ec8bfc5eee | ||
|
|
b4a0bcb90d | ||
|
|
2c729e2aa4 | ||
|
|
1cb2542170 | ||
|
|
00b309df34 | ||
|
|
a6fc730de6 | ||
|
|
2245c5a221 | ||
|
|
60c33661ad | ||
|
|
ea21c85038 | ||
|
|
5478f43609 | ||
|
|
a9b64abb85 | ||
|
|
c6ced424d8 |
@@ -116,9 +116,16 @@ export const AccountDialog = ({
|
||||
<Text
|
||||
css={{
|
||||
fontFamily: "$monospace",
|
||||
a: { "&:hover": { textDecoration: "underline" } },
|
||||
}}
|
||||
>
|
||||
{activeAccount?.address}
|
||||
<a
|
||||
href={`https://${process.env.NEXT_PUBLIC_EXPLORER_URL}/${activeAccount?.address}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{activeAccount?.address}
|
||||
</a>
|
||||
</Text>
|
||||
</Flex>
|
||||
<Flex css={{ marginLeft: "auto", color: "$mauve12" }}>
|
||||
@@ -215,7 +222,11 @@ export const AccountDialog = ({
|
||||
</Button>
|
||||
</Text>
|
||||
</Flex>
|
||||
<Flex css={{ marginLeft: "auto" }}>
|
||||
<Flex
|
||||
css={{
|
||||
marginLeft: "auto",
|
||||
}}
|
||||
>
|
||||
<a
|
||||
href={`https://${process.env.NEXT_PUBLIC_EXPLORER_URL}/${activeAccount?.address}`}
|
||||
target="_blank"
|
||||
@@ -237,10 +248,22 @@ export const AccountDialog = ({
|
||||
<Text
|
||||
css={{
|
||||
fontFamily: "$monospace",
|
||||
a: { "&:hover": { textDecoration: "underline" } },
|
||||
}}
|
||||
>
|
||||
{activeAccount && activeAccount.hooks.length > 0
|
||||
? activeAccount.hooks.map((i) => truncate(i, 12)).join(",")
|
||||
? activeAccount.hooks.map((i) => {
|
||||
return (
|
||||
<a
|
||||
key={i}
|
||||
href={`https://${process.env.NEXT_PUBLIC_EXPLORER_URL}/${i}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{truncate(i, 12)}
|
||||
</a>
|
||||
);
|
||||
})
|
||||
: "–"}
|
||||
</Text>
|
||||
</Flex>
|
||||
|
||||
@@ -57,7 +57,9 @@ export const SetHookDialog: React.FC<{ accountAddress: string }> = React.memo(
|
||||
({ accountAddress }) => {
|
||||
const snap = useSnapshot(state);
|
||||
const account = snap.accounts.find((acc) => acc.address === accountAddress);
|
||||
|
||||
const activeFile = snap.files[snap.active]?.compiledContent
|
||||
? snap.files[snap.active]
|
||||
: snap.files.filter((file) => file.compiledContent)[0];
|
||||
const [isSetHookDialogOpen, setIsSetHookDialogOpen] = useState(false);
|
||||
const {
|
||||
register,
|
||||
@@ -68,11 +70,13 @@ export const SetHookDialog: React.FC<{ accountAddress: string }> = React.memo(
|
||||
getValues,
|
||||
formState: { errors },
|
||||
} = useForm<SetHookData>({
|
||||
defaultValues: {
|
||||
HookNamespace:
|
||||
snap.files?.[snap.activeWat]?.name?.split(".")?.[0] || "",
|
||||
Invoke: transactionOptions.filter((to) => to.label === "ttPAYMENT"),
|
||||
},
|
||||
defaultValues: snap.deployValues?.[activeFile?.name]
|
||||
? snap.deployValues[activeFile?.name]
|
||||
: {
|
||||
HookNamespace:
|
||||
snap.files?.[snap.activeWat]?.name?.split(".")?.[0] || "",
|
||||
Invoke: transactionOptions.filter((to) => to.label === "ttPAYMENT"),
|
||||
},
|
||||
});
|
||||
const { fields, append, remove } = useFieldArray({
|
||||
control,
|
||||
@@ -81,14 +85,21 @@ export const SetHookDialog: React.FC<{ accountAddress: string }> = React.memo(
|
||||
const [formInitialized, setFormInitialized] = useState(false);
|
||||
const [estimateLoading, setEstimateLoading] = useState(false);
|
||||
const watchedFee = watch("Fee");
|
||||
|
||||
// Update value if activeWat changes
|
||||
useEffect(() => {
|
||||
setValue(
|
||||
"HookNamespace",
|
||||
snap.files?.[snap.activeWat]?.name?.split(".")?.[0] || ""
|
||||
);
|
||||
const defaultValue = snap.deployValues?.[activeFile?.name]
|
||||
? snap.deployValues?.[activeFile?.name].HookNamespace
|
||||
: snap.files?.[snap.activeWat]?.name?.split(".")?.[0] || "";
|
||||
setValue("HookNamespace", defaultValue);
|
||||
setFormInitialized(true);
|
||||
}, [snap.activeWat, snap.files, setValue]);
|
||||
}, [
|
||||
snap.activeWat,
|
||||
snap.files,
|
||||
setValue,
|
||||
activeFile?.name,
|
||||
snap.deployValues,
|
||||
]);
|
||||
useEffect(() => {
|
||||
if (
|
||||
watchedFee &&
|
||||
@@ -108,7 +119,9 @@ export const SetHookDialog: React.FC<{ accountAddress: string }> = React.memo(
|
||||
const [hashedNamespace, setHashedNamespace] = useState("");
|
||||
const namespace = watch(
|
||||
"HookNamespace",
|
||||
snap.files?.[snap.active]?.name?.split(".")?.[0] || ""
|
||||
snap.deployValues?.[activeFile?.name]
|
||||
? snap.deployValues?.[activeFile?.name].HookNamespace
|
||||
: snap.files?.[snap.activeWat]?.name?.split(".")?.[0] || ""
|
||||
);
|
||||
const calculateHashedValue = useCallback(async () => {
|
||||
const hashedVal = await sha256(namespace);
|
||||
@@ -191,9 +204,6 @@ export const SetHookDialog: React.FC<{ accountAddress: string }> = React.memo(
|
||||
<Controller
|
||||
name="Invoke"
|
||||
control={control}
|
||||
defaultValue={transactionOptions.filter(
|
||||
(to) => to.label === "ttPAYMENT"
|
||||
)}
|
||||
render={({ field }) => (
|
||||
<Select
|
||||
{...field}
|
||||
@@ -210,9 +220,6 @@ export const SetHookDialog: React.FC<{ accountAddress: string }> = React.memo(
|
||||
<Input
|
||||
{...register("HookNamespace", { required: true })}
|
||||
autoComplete={"off"}
|
||||
defaultValue={
|
||||
snap.files?.[snap.activeWat]?.name?.split(".")?.[0] || ""
|
||||
}
|
||||
/>
|
||||
{errors.HookNamespace?.type === "required" && (
|
||||
<Box css={{ display: "inline", color: "$red11" }}>
|
||||
|
||||
@@ -31,13 +31,15 @@ interface TabProps {
|
||||
|
||||
// TODO customise messages shown
|
||||
interface Props {
|
||||
label?: string;
|
||||
activeIndex?: number;
|
||||
activeHeader?: string;
|
||||
headless?: boolean;
|
||||
children: ReactElement<TabProps>[];
|
||||
keepAllAlive?: boolean;
|
||||
defaultExtension?: string;
|
||||
forceDefaultExtension?: boolean;
|
||||
appendDefaultExtension?: boolean;
|
||||
allowedExtensions?: string[];
|
||||
onCreateNewTab?: (name: string) => any;
|
||||
onCloseTab?: (index: number, header?: string) => any;
|
||||
onChangeActive?: (index: number, header?: string) => any;
|
||||
@@ -46,6 +48,7 @@ interface Props {
|
||||
export const Tab = (props: TabProps) => null;
|
||||
|
||||
export const Tabs = ({
|
||||
label = "Tab",
|
||||
children,
|
||||
activeIndex,
|
||||
activeHeader,
|
||||
@@ -55,7 +58,8 @@ export const Tabs = ({
|
||||
onCloseTab,
|
||||
onChangeActive,
|
||||
defaultExtension = "",
|
||||
forceDefaultExtension,
|
||||
appendDefaultExtension = false,
|
||||
allowedExtensions,
|
||||
}: Props) => {
|
||||
const [active, setActive] = useState(activeIndex || 0);
|
||||
const tabs: TabProps[] = children.map(elem => elem.props);
|
||||
@@ -86,9 +90,13 @@ export const Tabs = ({
|
||||
if (tabs.find(tab => tab.header === tabname)) {
|
||||
return { error: "Name already exists." };
|
||||
}
|
||||
const ext = tabname.split(".").pop() || "";
|
||||
if (allowedExtensions && !allowedExtensions.includes(ext)) {
|
||||
return { error: "This file extension is not allowed!" };
|
||||
}
|
||||
return { error: null };
|
||||
},
|
||||
[tabs]
|
||||
[allowedExtensions, tabs]
|
||||
);
|
||||
|
||||
const handleActiveChange = useCallback(
|
||||
@@ -101,9 +109,11 @@ export const Tabs = ({
|
||||
|
||||
const handleCreateTab = useCallback(() => {
|
||||
// add default extension in case omitted
|
||||
let _tabname = tabname.includes(".") ? tabname : tabname + defaultExtension;
|
||||
if (forceDefaultExtension && !_tabname.endsWith(defaultExtension)) {
|
||||
_tabname = _tabname + defaultExtension;
|
||||
let _tabname = tabname.includes(".")
|
||||
? tabname
|
||||
: `${tabname}.${defaultExtension}`;
|
||||
if (appendDefaultExtension && !_tabname.endsWith(defaultExtension)) {
|
||||
_tabname = `${_tabname}.${defaultExtension}`;
|
||||
}
|
||||
|
||||
const chk = validateTabname(_tabname);
|
||||
@@ -122,7 +132,7 @@ export const Tabs = ({
|
||||
}, [
|
||||
tabname,
|
||||
defaultExtension,
|
||||
forceDefaultExtension,
|
||||
appendDefaultExtension,
|
||||
validateTabname,
|
||||
onCreateNewTab,
|
||||
handleActiveChange,
|
||||
@@ -206,13 +216,13 @@ export const Tabs = ({
|
||||
size="sm"
|
||||
css={{ alignItems: "center", px: "$2", mr: "$3" }}
|
||||
>
|
||||
<Plus size="16px" /> {tabs.length === 0 && "Add new tab"}
|
||||
<Plus size="16px" /> {tabs.length === 0 && `Add new ${label.toLocaleLowerCase()}`}
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogTitle>Create new tab</DialogTitle>
|
||||
<DialogTitle>Create new {label.toLocaleLowerCase()}</DialogTitle>
|
||||
<DialogDescription>
|
||||
<Label>Tabname</Label>
|
||||
<Label>{label} name</Label>
|
||||
<Input
|
||||
value={tabname}
|
||||
onChange={e => setTabname(e.target.value)}
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
"monaco-editor": "^0.33.0",
|
||||
"next": "^12.0.4",
|
||||
"next-auth": "^4.0.0-beta.5",
|
||||
"next-plausible": "^3.2.0",
|
||||
"next-themes": "^0.1.1",
|
||||
"normalize-url": "^7.0.2",
|
||||
"octokit": "^1.7.0",
|
||||
|
||||
@@ -7,6 +7,7 @@ import { ThemeProvider } from "next-themes";
|
||||
import { Toaster } from "react-hot-toast";
|
||||
import { useRouter } from "next/router";
|
||||
import { IdProvider } from "@radix-ui/react-id";
|
||||
import PlausibleProvider from "next-plausible";
|
||||
|
||||
import { darkTheme, css } from "../stitches.config";
|
||||
import Navigation from "../components/Navigation";
|
||||
@@ -17,6 +18,8 @@ import TimeAgo from "javascript-time-ago";
|
||||
import en from "javascript-time-ago/locale/en.json";
|
||||
import { useSnapshot } from "valtio";
|
||||
import Alert from "../components/AlertDialog";
|
||||
import { Button, Flex } from "../components";
|
||||
import { ChatCircleText } from "phosphor-react";
|
||||
|
||||
TimeAgo.setDefaultLocale(en.locale);
|
||||
TimeAgo.addLocale(en);
|
||||
@@ -37,7 +40,7 @@ function MyApp({ Component, pageProps: { session, ...pageProps } }: AppProps) {
|
||||
if (
|
||||
!gistId &&
|
||||
router.isReady &&
|
||||
!router.pathname.includes("/sign-in") &&
|
||||
router.pathname.includes("/develop") &&
|
||||
!snap.files.length &&
|
||||
!snap.mainModalShowed
|
||||
) {
|
||||
@@ -114,6 +117,7 @@ function MyApp({ Component, pageProps: { session, ...pageProps } }: AppProps) {
|
||||
media="(prefers-color-scheme: light)"
|
||||
/>
|
||||
</Head>
|
||||
|
||||
<IdProvider>
|
||||
<SessionProvider session={session}>
|
||||
<ThemeProvider
|
||||
@@ -125,23 +129,40 @@ function MyApp({ Component, pageProps: { session, ...pageProps } }: AppProps) {
|
||||
dark: darkTheme.className,
|
||||
}}
|
||||
>
|
||||
<Navigation />
|
||||
<Component {...pageProps} />
|
||||
<Toaster
|
||||
toastOptions={{
|
||||
className: css({
|
||||
backgroundColor: "$mauve1",
|
||||
color: "$mauve10",
|
||||
fontSize: "$sm",
|
||||
zIndex: 9999,
|
||||
".dark &": {
|
||||
backgroundColor: "$mauve4",
|
||||
color: "$mauve12",
|
||||
},
|
||||
})(),
|
||||
}}
|
||||
/>
|
||||
<Alert />
|
||||
<PlausibleProvider
|
||||
domain="hooks-builder.xrpl.org"
|
||||
trackOutboundLinks
|
||||
>
|
||||
<Navigation />
|
||||
<Component {...pageProps} />
|
||||
<Toaster
|
||||
toastOptions={{
|
||||
className: css({
|
||||
backgroundColor: "$mauve1",
|
||||
color: "$mauve10",
|
||||
fontSize: "$sm",
|
||||
zIndex: 9999,
|
||||
".dark &": {
|
||||
backgroundColor: "$mauve4",
|
||||
color: "$mauve12",
|
||||
},
|
||||
})(),
|
||||
}}
|
||||
/>
|
||||
<Alert />
|
||||
<Flex
|
||||
as="a"
|
||||
href="https://github.com/XRPLF/Hooks/discussions"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
css={{ position: "fixed", right: "$4", bottom: "$4" }}
|
||||
>
|
||||
<Button size="sm" variant="primary" outline>
|
||||
<ChatCircleText size={14} style={{ marginRight: "0px" }} />
|
||||
Bugs & Discussions
|
||||
</Button>
|
||||
</Flex>
|
||||
</PlausibleProvider>
|
||||
</ThemeProvider>
|
||||
</SessionProvider>
|
||||
</IdProvider>
|
||||
|
||||
@@ -76,14 +76,15 @@ const Test = () => {
|
||||
>
|
||||
<Box css={{ width: "55%", px: "$2" }}>
|
||||
<Tabs
|
||||
label='Transaction'
|
||||
activeHeader={activeHeader}
|
||||
// TODO make header a required field
|
||||
onChangeActive={(idx, header) => {
|
||||
if (header) transactionsState.activeHeader = header;
|
||||
}}
|
||||
keepAllAlive
|
||||
forceDefaultExtension
|
||||
defaultExtension=".json"
|
||||
defaultExtension="json"
|
||||
allowedExtensions={['json']}
|
||||
onCreateNewTab={(header) => modifyTransaction(header, {})}
|
||||
onCloseTab={(idx, header) =>
|
||||
header && modifyTransaction(header, undefined)
|
||||
|
||||
@@ -126,6 +126,10 @@ export const deployHook = async (
|
||||
data: SetHookData
|
||||
) => {
|
||||
if (typeof window !== "undefined") {
|
||||
const activeFile = state.files[state.active]?.compiledContent
|
||||
? state.files[state.active]
|
||||
: state.files.filter((file) => file.compiledContent)[0];
|
||||
state.deployValues[activeFile.name] = data;
|
||||
const tx = await prepareDeployHookTx(account, data);
|
||||
if (!tx) {
|
||||
return;
|
||||
|
||||
@@ -52,6 +52,8 @@ export interface ILog {
|
||||
defaultCollapsed?: boolean
|
||||
}
|
||||
|
||||
export type DeployValue = Record<IFile['name'], any>;
|
||||
|
||||
export interface IState {
|
||||
files: IFile[];
|
||||
gistId?: string | null;
|
||||
@@ -82,7 +84,8 @@ export interface IState {
|
||||
compileOptions: {
|
||||
optimizationLevel: '-O0' | '-O1' | '-O2' | '-O3' | '-O4' | '-Os';
|
||||
strip: boolean
|
||||
}
|
||||
},
|
||||
deployValues: DeployValue
|
||||
}
|
||||
|
||||
// let localStorageState: null | string = null;
|
||||
@@ -116,7 +119,8 @@ let initialState: IState = {
|
||||
compileOptions: {
|
||||
optimizationLevel: '-O2',
|
||||
strip: true
|
||||
}
|
||||
},
|
||||
deployValues: {}
|
||||
};
|
||||
|
||||
let localStorageAccounts: string | null = null;
|
||||
|
||||
@@ -2981,6 +2981,11 @@ next-auth@^4.0.0-beta.5:
|
||||
preact-render-to-string "^5.1.19"
|
||||
uuid "^8.3.2"
|
||||
|
||||
next-plausible@^3.2.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/next-plausible/-/next-plausible-3.2.0.tgz#d801346253e0c1cf64a02b9fc3a42050455cbc47"
|
||||
integrity sha512-OlYcLXBG3kKd/fKMpm8SZ5IkUKSFm1/8t7cv6e5bewIqlpdZpdWuSrjbdJpbmutb2KPLXHzilKp09zmDGjy9KQ==
|
||||
|
||||
next-themes@^0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/next-themes/-/next-themes-0.1.1.tgz#122113a458bf1d1be5ffed66778ab924c106f82a"
|
||||
|
||||
Reference in New Issue
Block a user