Skip to content

Commit 6a1426c

Browse files
committedFeb 26, 2022
upload complete; also fix suggest chain
1 parent bef0bae commit 6a1426c

File tree

6 files changed

+334
-36
lines changed

6 files changed

+334
-36
lines changed
 

‎.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@
2121
npm-debug.log*
2222
yarn-debug.log*
2323
yarn-error.log*
24+
.log

‎src/features/accounts/AddContract.module.css

+85-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
.importGroup {
2626
display: flex;
2727
margin-bottom: 0.5rem;
28+
margin-top: -1em;
2829
}
2930

3031
.address {
@@ -50,6 +51,89 @@
5051
.file {
5152
border: 1px solid #ccc;
5253
padding: 0.6em;
54+
border-radius: 0 0.3em 0 0;
55+
margin-left: -1px;
56+
width: 14em;
57+
flex-grow: 1;
58+
}
59+
60+
.code {
61+
flex-grow: 1;
62+
margin-left: -1px;
63+
width: 4em;
64+
}
65+
66+
.code::part(:global(base)) {
67+
border-radius: 0 0.3em 0 0;
68+
}
69+
70+
.code input {
71+
-moz-appearance: textfield;
72+
}
73+
74+
input[type="number"]::-webkit-outer-spin-button,
75+
input[type="number"]::-webkit-inner-spin-button {
76+
-webkit-appearance: none;
77+
margin: 0;
78+
}
79+
80+
.label {
5381
flex-grow: 1;
54-
border-radius: 0.3em 0 0 0.3em;
82+
}
83+
84+
.label::part(:global(base)) {
85+
border-radius: 0.3em 0 0 0;
86+
}
87+
88+
.msgWrapper {
89+
min-height: 10em;
90+
max-height: 20em;
91+
overflow-y: auto;
92+
border: 1px solid #ccc;
93+
border-top: 0;
94+
}
95+
96+
.instantiateMsg {
97+
min-height: 10em;
98+
border: 0;
99+
}
100+
101+
.instantiateMsg textarea {
102+
min-height: 10em;
103+
outline: none;
104+
}
105+
106+
.uploadHeader {
107+
margin: 1em 0;
108+
display: flex;
109+
justify-content: space-between;
110+
}
111+
112+
.uploadTitle {
113+
font-size: 1.25rem;
114+
}
115+
116+
.choices {
117+
margin-top: -0.1em;
118+
margin-left: 1em;
119+
}
120+
121+
.choice {
122+
display: inline;
123+
}
124+
125+
.choice::part(:global(base)) {
126+
padding:0.4em;
127+
font-size: 0.9em;
128+
}
129+
130+
131+
.uploadGroup {
132+
display: flex;
133+
}
134+
135+
.uploadButton {
136+
margin-top: 1em;
137+
display: flex;
138+
flex-direction: row-reverse;
55139
}

‎src/features/accounts/AddContract.tsx

+143-20
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,93 @@ import {
22
SlButton,
33
SlCard,
44
SlDialog,
5+
SlDivider,
56
SlIcon,
67
SlInput,
8+
SlRadio,
9+
SlRadioGroup,
710
} from "@shoelace-style/shoelace/dist/react";
811
import type SlInputElement from "@shoelace-style/shoelace/dist/components/input/input";
9-
import React, { FC, useState } from "react";
10-
import { useAppDispatch } from "../../app/hooks";
12+
import React, { FC, useEffect, useRef, useState } from "react";
13+
import { useAppDispatch, useAppSelector } from "../../app/hooks";
1114
import styles from "./AddContract.module.css";
12-
import { importContract } from "./accountsSlice";
15+
import {
16+
importContract,
17+
instantiateContract,
18+
selectedAccount,
19+
setImportContractOpen,
20+
uploadContract,
21+
} from "./accountsSlice";
22+
import { useSelector } from "react-redux";
23+
import Editor from "react-simple-code-editor";
24+
import formatHighlight from "json-format-highlight";
25+
import { highlightColors } from "../console/consoleSlice";
1326

14-
interface ImportContractProps {
15-
open: boolean;
16-
setOpen: (open: boolean) => void;
27+
enum UploadType {
28+
File = "file",
29+
Code = "code",
1730
}
1831

19-
export const ImportContract: FC<ImportContractProps> = ({ open, setOpen }) => {
32+
export const ImportContract: FC = () => {
2033
const dispatch = useAppDispatch();
34+
const wasmInput = useRef<HTMLInputElement>(null);
2135
const [address, setAddress] = useState("");
36+
const [label, setLabel] = useState("");
37+
const [message, setMessage] = useState("");
38+
const [codeId, setCodeId] = useState("");
39+
const [uploadType, setUploadType] = useState(UploadType.File);
40+
const open = useAppSelector((state) => state.accounts.importContractOpen);
41+
const account = useSelector(selectedAccount);
42+
43+
useEffect(() => {
44+
if (!open) {
45+
setAddress("");
46+
setLabel("");
47+
setMessage("");
48+
setCodeId("");
49+
}
50+
}, [open]);
2251

2352
function doImport() {
2453
dispatch(importContract(address));
25-
setAddress("");
26-
setOpen(false);
54+
}
55+
56+
async function doUpload() {
57+
if (!account) throw new Error("No account selected");
58+
59+
const instantiateMsg = JSON.parse(message);
60+
61+
if (uploadType === UploadType.File) {
62+
const wasmFile = wasmInput.current?.files?.[0];
63+
if (wasmFile) {
64+
const wasmBuffer = await wasmFile.arrayBuffer();
65+
const wasm = new Uint8Array(wasmBuffer);
66+
dispatch(
67+
uploadContract({
68+
address: account.address,
69+
wasm,
70+
instantiateMsg,
71+
label,
72+
})
73+
);
74+
}
75+
} else {
76+
dispatch(
77+
instantiateContract({
78+
address: account.address,
79+
codeId: Number(codeId),
80+
instantiateMsg,
81+
label,
82+
})
83+
);
84+
}
2785
}
2886

2987
return (
3088
<SlDialog
31-
label="Add contract"
89+
label="Import contract"
3290
open={open}
33-
onSlAfterHide={() => setOpen(false)}
91+
onSlAfterHide={() => dispatch(setImportContractOpen(false))}
3492
>
3593
<div className={styles.importGroup}>
3694
<SlInput
@@ -42,28 +100,93 @@ export const ImportContract: FC<ImportContractProps> = ({ open, setOpen }) => {
42100
}
43101
/>
44102
<SlButton className={styles.importButton} onClick={() => doImport()}>
45-
Add
103+
Import
46104
</SlButton>
47105
</div>
48-
<div className={styles.importGroup}>
49-
<input className={styles.file} type="file" accept=".wasm" />
50-
<SlButton className={styles.importButton} onClick={() => doImport()}>
51-
Upload
52-
</SlButton>
106+
<SlDivider />
107+
<div className={styles.uploadHeader}>
108+
<div className={styles.uploadTitle}>Create contract</div>
109+
<div className={styles.instantiateFrom}>
110+
<SlRadioGroup className={styles.choices}>
111+
<SlRadio
112+
onSlFocus={() => setUploadType(UploadType.File)}
113+
className={styles.choice}
114+
checked={uploadType === UploadType.File}
115+
>
116+
From file
117+
</SlRadio>
118+
<SlRadio
119+
onSlFocus={() => setUploadType(UploadType.Code)}
120+
className={styles.choice}
121+
checked={uploadType === UploadType.Code}
122+
>
123+
From code
124+
</SlRadio>
125+
</SlRadioGroup>
126+
</div>
127+
</div>
128+
<div className={styles.upload}>
129+
<div className={styles.uploadGroup}>
130+
<SlInput
131+
placeholder="Label"
132+
value={label}
133+
className={styles.label}
134+
onSlChange={(e) =>
135+
setLabel((e.target as SlInputElement).value.trim())
136+
}
137+
/>
138+
{uploadType === UploadType.File ? (
139+
<input
140+
className={styles.file}
141+
type="file"
142+
accept=".wasm"
143+
ref={wasmInput}
144+
/>
145+
) : (
146+
<SlInput
147+
placeholder="Code ID"
148+
value={codeId}
149+
type="number"
150+
min="1"
151+
className={styles.code}
152+
onSlChange={(e) =>
153+
setCodeId((e.target as SlInputElement).value.trim())
154+
}
155+
/>
156+
)}
157+
</div>
158+
<div className={styles.msgWrapper}>
159+
<Editor
160+
className={styles.instantiateMsg}
161+
highlight={(code) => formatHighlight(code, highlightColors)}
162+
placeholder="Instantiate message"
163+
value={message}
164+
padding={10}
165+
onValueChange={(code) => setMessage(code)}
166+
/>
167+
</div>
168+
<div className={styles.uploadButton}>
169+
<SlButton onClick={() => doUpload()} disabled={!account}>
170+
{uploadType === UploadType.File ? "Upload and i" : "I"}nstantiate
171+
</SlButton>
172+
</div>
53173
</div>
54174
</SlDialog>
55175
);
56176
};
57177

58178
export const AddContract: FC = () => {
59-
const [importOpen, setImportOpen] = useState(false);
179+
const dispatch = useAppDispatch();
60180

61181
return (
62182
<>
63-
<SlCard className={styles.adder} onClick={() => setImportOpen(true)}>
183+
<SlCard
184+
className={styles.adder}
185+
onClick={() => dispatch(setImportContractOpen(true))}
186+
>
64187
<SlIcon name="plus-lg" className={styles.plus} /> Add contract
65188
</SlCard>
66-
<ImportContract open={importOpen} setOpen={setImportOpen} />
189+
<ImportContract />
67190
</>
68191
);
69192
};

0 commit comments

Comments
 (0)
Please sign in to comment.