Compare commits

..

14 Commits

Author SHA1 Message Date
JaniAnttonen
810d3b2524 Add a todo 2022-02-25 16:34:09 +02:00
JaniAnttonen
a3393ded1e Fix build 2022-02-25 15:22:09 +02:00
JaniAnttonen
17ede265b1 Remove debug logging 2022-02-25 14:39:06 +02:00
JaniAnttonen
629070edad Save split state 2022-02-25 13:50:56 +02:00
Vaclav Barta
cc83924c27 Merge pull request #98 from eqlabs/bugfix/typos
fix for #97
2022-02-15 08:49:38 +01:00
Vaclav Barta
e3e964f72a fix for #97 2022-02-11 13:54:52 +01:00
Joni Juup
bdb2c0cf8f Merge pull request #93 from eqlabs/bugfix/monaco-popups
Fix monaco popup issues
2022-02-09 15:10:28 +02:00
muzamil
3e8dbc9793 Merge pull request #91 from eqlabs/fixes
Clearing some issues
2022-02-09 18:32:47 +05:30
muzam
d735cd3833 Merge branch 'main' into fixes 2022-02-09 18:31:35 +05:30
muzam
1a3f5d144c change accept template to starter 2022-02-09 14:26:19 +05:30
muzam
ce81c11c29 Update hooks installed info in card 2022-02-08 19:56:30 +05:30
muzam
3a98b95e3d fix firewall template link 2022-02-08 18:59:40 +05:30
muzam
8bc36655e2 disallow illegal characters in filename 2022-02-08 15:26:22 +05:30
muzam
b6ab536a60 Clear log on compile 2022-02-08 15:08:38 +05:30
11 changed files with 91 additions and 86 deletions

View File

@@ -36,13 +36,11 @@ const AccountDialog = ({
}) => { }) => {
const snap = useSnapshot(state); const snap = useSnapshot(state);
const [showSecret, setShowSecret] = useState(false); const [showSecret, setShowSecret] = useState(false);
const activeAccount = snap.accounts.find( const activeAccount = snap.accounts.find(account => account.address === activeAccountAddress);
(account) => account.address === activeAccountAddress
);
return ( return (
<Dialog <Dialog
open={Boolean(activeAccountAddress)} open={Boolean(activeAccountAddress)}
onOpenChange={(open) => { onOpenChange={open => {
setShowSecret(false); setShowSecret(false);
!open && setActiveAccountAddress(null); !open && setActiveAccountAddress(null);
}} }}
@@ -137,7 +135,7 @@ const AccountDialog = ({
}} }}
ghost ghost
size="xs" size="xs"
onClick={() => setShowSecret((curr) => !curr)} onClick={() => setShowSecret(curr => !curr)}
> >
{showSecret ? "Hide" : "Show"} {showSecret ? "Hide" : "Show"}
</Button> </Button>
@@ -201,15 +199,7 @@ const AccountDialog = ({
fontFamily: "$monospace", fontFamily: "$monospace",
}} }}
> >
{activeAccount && activeAccount?.hooks?.length > 0 {activeAccount && activeAccount.hooks.length}
? activeAccount?.hooks
.map((i) => {
return `${i?.substring(0, 6)}...${i?.substring(
i.length - 4
)}`;
})
.join(", ")
: ""}
</Text> </Text>
</Flex> </Flex>
</Flex> </Flex>
@@ -231,15 +221,13 @@ interface AccountProps {
showHookStats?: boolean; showHookStats?: boolean;
} }
const Accounts: FC<AccountProps> = (props) => { const Accounts: FC<AccountProps> = props => {
const snap = useSnapshot(state); const snap = useSnapshot(state);
const [activeAccountAddress, setActiveAccountAddress] = useState< const [activeAccountAddress, setActiveAccountAddress] = useState<string | null>(null);
string | null
>(null);
useEffect(() => { useEffect(() => {
const fetchAccInfo = async () => { const fetchAccInfo = async () => {
if (snap.clientStatus === "online") { if (snap.clientStatus === "online") {
const requests = snap.accounts.map((acc) => const requests = snap.accounts.map(acc =>
snap.client?.send({ snap.client?.send({
id: acc.address, id: acc.address,
command: "account_info", command: "account_info",
@@ -251,15 +239,13 @@ const Accounts: FC<AccountProps> = (props) => {
const address = res?.account_data?.Account as string; const address = res?.account_data?.Account as string;
const balance = res?.account_data?.Balance as string; const balance = res?.account_data?.Balance as string;
const sequence = res?.account_data?.Sequence as number; const sequence = res?.account_data?.Sequence as number;
const accountToUpdate = state.accounts.find( const accountToUpdate = state.accounts.find(acc => acc.address === address);
(acc) => acc.address === address
);
if (accountToUpdate) { if (accountToUpdate) {
accountToUpdate.xrp = balance; accountToUpdate.xrp = balance;
accountToUpdate.sequence = sequence; accountToUpdate.sequence = sequence;
} }
}); });
const objectRequests = snap.accounts.map((acc) => { const objectRequests = snap.accounts.map(acc => {
return snap.client?.send({ return snap.client?.send({
id: `${acc.address}-hooks`, id: `${acc.address}-hooks`,
command: "account_objects", command: "account_objects",
@@ -269,9 +255,7 @@ const Accounts: FC<AccountProps> = (props) => {
const objectResponses = await Promise.all(objectRequests); const objectResponses = await Promise.all(objectRequests);
objectResponses.forEach((res: any) => { objectResponses.forEach((res: any) => {
const address = res?.account as string; const address = res?.account as string;
const accountToUpdate = state.accounts.find( const accountToUpdate = state.accounts.find(acc => acc.address === address);
(acc) => acc.address === address
);
if (accountToUpdate) { if (accountToUpdate) {
accountToUpdate.hooks = res.account_objects accountToUpdate.hooks = res.account_objects
.filter((ac: any) => ac?.LedgerEntryType === "Hook") .filter((ac: any) => ac?.LedgerEntryType === "Hook")
@@ -353,7 +337,7 @@ const Accounts: FC<AccountProps> = (props) => {
overflowY: "auto", overflowY: "auto",
}} }}
> >
{snap.accounts.map((account) => ( {snap.accounts.map(account => (
<Flex <Flex
column column
key={account.address + account.name} key={account.address + account.name}
@@ -406,11 +390,10 @@ const Accounts: FC<AccountProps> = (props) => {
isLoading={account.isLoading} isLoading={account.isLoading}
disabled={ disabled={
account.isLoading || account.isLoading ||
!snap.files.filter((file) => file.compiledWatContent) !snap.files.filter(file => file.compiledWatContent).length
.length
} }
variant="secondary" variant="secondary"
onClick={(e) => { onClick={e => {
e.stopPropagation(); e.stopPropagation();
deployHook(account); deployHook(account);
}} }}
@@ -421,7 +404,7 @@ const Accounts: FC<AccountProps> = (props) => {
</Flex> </Flex>
{props.showHookStats && ( {props.showHookStats && (
<Text muted small css={{ mt: "$2" }}> <Text muted small css={{ mt: "$2" }}>
X hooks installed {account.hooks.length} hook{account.hooks.length === 1 ? "" : "s"} installed
</Text> </Text>
)} )}
</Flex> </Flex>
@@ -453,7 +436,7 @@ const ImportAccountDialog = () => {
name="secret" name="secret"
type="password" type="password"
value={value} value={value}
onChange={(e) => setValue(e.target.value)} onChange={e => setValue(e.target.value)}
/> />
</DialogDescription> </DialogDescription>

View File

@@ -90,9 +90,16 @@ const EditorNavigation = ({ showWat }: { showWat?: boolean }) => {
const validateFilename = useCallback( const validateFilename = useCallback(
(filename: string): { error: string | null } => { (filename: string): { error: string | null } => {
if (snap.files.find((file) => file.name === filename)) { // check if filename already exists
if (snap.files.find(file => file.name === filename)) {
return { error: "Filename already exists." }; return { error: "Filename already exists." };
} }
// check for illegal characters
const ILLEGAL_REGEX = /[/]/gi;
if (filename.match(ILLEGAL_REGEX)) {
return { error: "Filename contains illegal characters" };
}
// More checks in future // More checks in future
return { error: null }; return { error: null };
}, },

View File

@@ -173,7 +173,7 @@ const HooksEditor = () => {
fontFamily: "$monospace", fontFamily: "$monospace",
}} }}
> >
Click the link above to create a your file Click the link above to create your file
</Text> </Text>
</Box> </Box>
</Box> </Box>

View File

@@ -279,28 +279,18 @@ const Navigation = () => {
> >
<Heading>Starter</Heading> <Heading>Starter</Heading>
<Text> <Text>
Just an empty starter with essential imports Just a basic starter with essential imports
</Text> </Text>
</PanelBox> </PanelBox>
<PanelBox <PanelBox
as="a" as="a"
href={`/develop/${templateFileIds.starter}`} href={`/develop/${templateFileIds.firewall}`}
> >
<Heading>Firewall</Heading> <Heading>Firewall</Heading>
<Text> <Text>
This Hook essentially checks a blacklist of accounts This Hook essentially checks a blacklist of accounts
</Text> </Text>
</PanelBox> </PanelBox>
<PanelBox
as="a"
href={`/develop/${templateFileIds.accept}`}
>
<Heading>Accept</Heading>
<Text>
This hook just accepts any transaction coming through
it
</Text>
</PanelBox>
<PanelBox <PanelBox
as="a" as="a"
href={`/develop/${templateFileIds.notary}`} href={`/develop/${templateFileIds.notary}`}
@@ -322,7 +312,7 @@ const Navigation = () => {
href={`/develop/${templateFileIds.peggy}`} href={`/develop/${templateFileIds.peggy}`}
> >
<Heading>Peggy</Heading> <Heading>Peggy</Heading>
<Text>An oracle based stabe coin hook</Text> <Text>An oracle based stable coin hook</Text>
</PanelBox> </PanelBox>
</Flex> </Flex>
</Flex> </Flex>

View File

@@ -1,8 +1,9 @@
import React from "react";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import React from "react";
import Split from "react-split";
import { useSnapshot } from "valtio"; import { useSnapshot } from "valtio";
import state from "../../state"; import state from "../../state";
import Split from "react-split"; import { getSplit, saveSplit } from "../../state/actions/persistSplits";
const DeployEditor = dynamic(() => import("../../components/DeployEditor"), { const DeployEditor = dynamic(() => import("../../components/DeployEditor"), {
ssr: false, ssr: false,
@@ -17,21 +18,22 @@ const LogBox = dynamic(() => import("../../components/LogBox"), {
}); });
const Deploy = () => { const Deploy = () => {
const snap = useSnapshot(state); const { deployLogs } = useSnapshot(state);
return ( return (
<Split <Split
direction="vertical" direction="vertical"
gutterSize={4} gutterSize={4}
gutterAlign="center" gutterAlign="center"
sizes={[40, 60]} sizes={getSplit("deployVertical") || [40, 60]}
style={{ height: "calc(100vh - 60px)" }} style={{ height: "calc(100vh - 60px)" }}
onDragEnd={(e) => saveSplit("deployVertical", e)}
> >
<main style={{ display: "flex", flex: 1, position: "relative" }}> <main style={{ display: "flex", flex: 1, position: "relative" }}>
<DeployEditor /> <DeployEditor />
</main> </main>
<Split <Split
direction="horizontal" direction="horizontal"
sizes={[50, 50]} sizes={getSplit("deployHorizontal") || [50, 50]}
minSize={[320, 160]} minSize={[320, 160]}
gutterSize={4} gutterSize={4}
gutterAlign="center" gutterAlign="center"
@@ -41,6 +43,7 @@ const Deploy = () => {
width: "100%", width: "100%",
height: "100%", height: "100%",
}} }}
onDragEnd={(e) => saveSplit("deployHorizontal", e)}
> >
<div style={{ alignItems: "stretch", display: "flex" }}> <div style={{ alignItems: "stretch", display: "flex" }}>
<Accounts /> <Accounts />
@@ -48,7 +51,7 @@ const Deploy = () => {
<div> <div>
<LogBox <LogBox
title="Deploy Log" title="Deploy Log"
logs={snap.deployLogs} logs={deployLogs}
clearLog={() => (state.deployLogs = [])} clearLog={() => (state.deployLogs = [])}
/> />
</div> </div>

View File

@@ -1,14 +1,15 @@
import dynamic from "next/dynamic";
import { useSnapshot } from "valtio";
import Hotkeys from "react-hot-keys";
import { Play } from "phosphor-react";
import Split from "react-split";
import type { NextPage } from "next"; import type { NextPage } from "next";
import { compileCode } from "../../state/actions"; import dynamic from "next/dynamic";
import state from "../../state"; import { Play } from "phosphor-react";
import Button from "../../components/Button"; import Hotkeys from "react-hot-keys";
import Split from "react-split";
import { useSnapshot } from "valtio";
import Box from "../../components/Box"; import Box from "../../components/Box";
import Button from "../../components/Button";
import state from "../../state";
import { compileCode } from "../../state/actions";
import { getSplit, saveSplit } from "../../state/actions/persistSplits";
const HooksEditor = dynamic(() => import("../../components/HooksEditor"), { const HooksEditor = dynamic(() => import("../../components/HooksEditor"), {
ssr: false, ssr: false,
@@ -24,11 +25,12 @@ const Home: NextPage = () => {
return ( return (
<Split <Split
direction="vertical" direction="vertical"
sizes={[70, 30]} sizes={getSplit("developVertical") || [70, 30]}
minSize={[100, 100]} minSize={[100, 100]}
gutterAlign="center" gutterAlign="center"
gutterSize={4} gutterSize={4}
style={{ height: "calc(100vh - 60px)" }} style={{ height: "calc(100vh - 60px)" }}
onDragEnd={(e) => saveSplit("developVertical", e)}
> >
<main style={{ display: "flex", flex: 1, position: "relative" }}> <main style={{ display: "flex", flex: 1, position: "relative" }}>
<HooksEditor /> <HooksEditor />

View File

@@ -1,22 +1,17 @@
import {
Container,
Flex,
Box,
Tabs,
Tab,
Input,
Select,
Text,
Button,
} from "../../components";
import { Play } from "phosphor-react";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import { useSnapshot } from "valtio"; import { Play } from "phosphor-react";
import { FC, useCallback, useEffect, useState } from "react";
import Split from "react-split"; import Split from "react-split";
import { useSnapshot } from "valtio";
import {
Box, Button, Container,
Flex, Input,
Select, Tab, Tabs, Text
} from "../../components";
import transactionsData from "../../content/transactions.json";
import state from "../../state"; import state from "../../state";
import { sendTransaction } from "../../state/actions"; import { sendTransaction } from "../../state/actions";
import { useCallback, useEffect, useState, FC } from "react"; import { getSplit, saveSplit } from "../../state/actions/persistSplits";
import transactionsData from "../../content/transactions.json";
const DebugStream = dynamic(() => import("../../components/DebugStream"), { const DebugStream = dynamic(() => import("../../components/DebugStream"), {
ssr: false, ssr: false,
@@ -349,16 +344,17 @@ const Transaction: FC<Props> = ({ header, ...props }) => {
}; };
const Test = () => { const Test = () => {
const snap = useSnapshot(state); const { transactionLogs } = useSnapshot(state);
const [tabHeaders, setTabHeaders] = useState<string[]>(["test1.json"]); const [tabHeaders, setTabHeaders] = useState<string[]>(["test1.json"]);
return ( return (
<Container css={{ px: 0 }}> <Container css={{ px: 0 }}>
<Split <Split
direction="vertical" direction="vertical"
sizes={[50, 50]} sizes={getSplit("testVertical") || [50, 50]}
gutterSize={4} gutterSize={4}
gutterAlign="center" gutterAlign="center"
style={{ height: "calc(100vh - 60px)" }} style={{ height: "calc(100vh - 60px)" }}
onDragEnd={(e) => saveSplit("testVertical", e)}
> >
<Flex <Flex
row row
@@ -370,7 +366,7 @@ const Test = () => {
> >
<Split <Split
direction="horizontal" direction="horizontal"
sizes={[50, 50]} sizes={getSplit("testHorizontal") || [50, 50]}
minSize={[180, 320]} minSize={[180, 320]}
gutterSize={4} gutterSize={4}
gutterAlign="center" gutterAlign="center"
@@ -380,6 +376,7 @@ const Test = () => {
width: "100%", width: "100%",
height: "100%", height: "100%",
}} }}
onDragEnd={(e) => saveSplit("testHorizontal", e)}
> >
<Box css={{ width: "55%", px: "$2" }}> <Box css={{ width: "55%", px: "$2" }}>
<Tabs <Tabs
@@ -428,7 +425,7 @@ const Test = () => {
> >
<LogBox <LogBox
title="Development Log" title="Development Log"
logs={snap.transactionLogs} logs={transactionLogs}
clearLog={() => (state.transactionLogs = [])} clearLog={() => (state.transactionLogs = [])}
/> />
</Box> </Box>

View File

@@ -25,6 +25,7 @@ export const compileCode = async (activeId: number) => {
} }
// Set loading state to true // Set loading state to true
state.compiling = true; state.compiling = true;
state.logs = []
try { try {
const res = await fetch(process.env.NEXT_PUBLIC_COMPILE_API_ENDPOINT, { const res = await fetch(process.env.NEXT_PUBLIC_COMPILE_API_ENDPOINT, {
method: "POST", method: "POST",

View File

@@ -0,0 +1,15 @@
import { snapshot } from "valtio"
import state from ".."
export type SplitSize = number[]
export const saveSplit = (splitId: string, event: SplitSize) => {
state.splits[splitId] = event
}
export const getSplit = (splitId: string): SplitSize | null => {
const { splits } = snapshot(state)
const split = splits[splitId]
return split ? split : null
}

View File

@@ -1,6 +1,5 @@
export const templateFileIds = { export const templateFileIds = {
'starter': '1d14e51e2e02dc0a508cb0733767a914', // TODO currently same as accept 'starter': '1d14e51e2e02dc0a508cb0733767a914', // TODO currently same as accept
'accept': '1d14e51e2e02dc0a508cb0733767a914',
'firewall': 'bcd6d0c0fcbe52545ddb802481ff9d26', 'firewall': 'bcd6d0c0fcbe52545ddb802481ff9d26',
'notary': 'a789c75f591eeab7932fd702ed8cf9ea', 'notary': 'a789c75f591eeab7932fd702ed8cf9ea',
'carbon': '43925143fa19735d8c6505c34d3a6a47', 'carbon': '43925143fa19735d8c6505c34d3a6a47',

View File

@@ -1,7 +1,8 @@
import { proxy, ref, subscribe } from "valtio";
import { devtools } from 'valtio/utils'
import type monaco from "monaco-editor"; import type monaco from "monaco-editor";
import { proxy, ref, subscribe } from "valtio";
import { devtools } from 'valtio/utils';
import { XrplClient } from "xrpl-client"; import { XrplClient } from "xrpl-client";
import { SplitSize } from "./actions/persistSplits";
export interface IFile { export interface IFile {
name: string; name: string;
@@ -55,6 +56,9 @@ export interface IState {
editorSettings: { editorSettings: {
tabSize: number; tabSize: number;
}; };
splits: {
[id: string]: SplitSize
};
client: XrplClient | null; client: XrplClient | null;
clientStatus: "offline" | "online"; clientStatus: "offline" | "online";
mainModalOpen: boolean; mainModalOpen: boolean;
@@ -83,6 +87,7 @@ let initialState: IState = {
editorSettings: { editorSettings: {
tabSize: 2, tabSize: 2,
}, },
splits: {},
client: null, client: null,
clientStatus: "offline" as "offline", clientStatus: "offline" as "offline",
mainModalOpen: false, mainModalOpen: false,
@@ -91,6 +96,9 @@ let initialState: IState = {
let localStorageAccounts: string | null = null; let localStorageAccounts: string | null = null;
let initialAccounts: IAccount[] = []; let initialAccounts: IAccount[] = [];
// TODO: What exactly should we store in localStorage? editorSettings, splits, accounts?
// Check if there's a persited accounts in localStorage // Check if there's a persited accounts in localStorage
if (typeof window !== "undefined") { if (typeof window !== "undefined") {
try { try {