Skip to content
This repository was archived by the owner on Feb 12, 2026. It is now read-only.

Commit 2b24cc1

Browse files
committed
feat: add descriptions
1 parent 60e71df commit 2b24cc1

17 files changed

Lines changed: 2139 additions & 384 deletions

README.md

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,6 @@
44
<p>
55
<h3>The Missing Solana Client</h3>
66
<p><i>For when you have had enough glass...</i></p>
7-
<p>
8-
<a href="https://github.com/labeleven-dev/bettercallsol/actions/workflows/deploy.yml">
9-
<img alt="Workflow Status" src="https://github.com/labeleven-dev/bettercallsol/actions/workflows/deploy.yml/badge.svg">
10-
</a>
11-
<a href="https://snyk.io/test/github/labeleven-dev/bettercallsol">
12-
<img alt="Known Vulnerabilities" src="https://snyk.io/test/github/labeleven-dev/bettercallsol/badge.svg">
13-
</a>
147
<p>
158
<a href="https://github.com/labeleven-dev/bettercallsol/discussions">
169
<img alt="Join the community on GitHub Discussions" src="https://img.shields.io/badge/Join%20the%20community-on%20GitHub%20Discussions-blue">

package-lock.json

Lines changed: 1536 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
"@solana/web3.js": "^1.44.2",
4444
"axios": "^0.27.2",
4545
"bignumber.js": "^9.0.2",
46+
"chakra-ui-markdown-renderer": "^4.1.0",
4647
"crypto-browserify": "^3.12.0",
4748
"framer-motion": "^6.3.15",
4849
"immer": "^9.0.15",
@@ -54,6 +55,7 @@
5455
"react-dom": "^18.2.0",
5556
"react-github-btn": "^1.3.0",
5657
"react-icons": "^3.11.0",
58+
"react-markdown": "^8.0.3",
5759
"react-router-dom": "^6.3.0",
5860
"react-stately": "^3.16.0",
5961
"snake-case": "^3.0.4",

src/components/client/Instruction.tsx

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { useInstruction } from "../../hooks/useInstruction";
2121
import { useSessionStoreWithUndo } from "../../hooks/useSessionStore";
2222
import { useWeb3Account } from "../../hooks/useWeb3Account";
2323
import { AccountAutoComplete } from "../common/AccountAutoComplete";
24+
import { Description } from "../common/Description";
2425
import { ExplorerButton } from "../common/ExplorerButton";
2526
import { Accounts } from "./accounts/Accounts";
2627
import { Data } from "./data/Data";
@@ -29,14 +30,14 @@ import { InstructionHeader } from "./InstructionHeader";
2930
export const Instruction: React.FC<{ index: number }> = ({ index }) => {
3031
const rpcEndpoint = useSessionStoreWithUndo((state) => state.rpcEndpoint);
3132
const { useShallowGet, update } = useInstruction();
32-
const [programId, anchorMethod, disabled, expanded] = useShallowGet(
33-
(state) => [
33+
const [programId, description, anchorMethod, disabled, expanded] =
34+
useShallowGet((state) => [
3435
state.programId,
36+
state.description,
3537
state.anchorMethod,
3638
state.disabled,
3739
state.expanded,
38-
]
39-
);
40+
]);
4041
const programInfo = useWeb3Account(programId);
4142

4243
return (
@@ -57,6 +58,17 @@ export const Instruction: React.FC<{ index: number }> = ({ index }) => {
5758
<InstructionHeader index={index} />
5859

5960
<Collapse in={expanded}>
61+
<Description
62+
mb="2"
63+
fontSize="sm"
64+
description={description}
65+
setDescription={(description) => {
66+
update((state) => {
67+
state.description = description;
68+
});
69+
}}
70+
/>
71+
6072
<Flex alignItems="center" mb="1">
6173
<FormLabel mb="0" htmlFor="program-id">
6274
Program

src/components/client/TransactionHeader.tsx

Lines changed: 49 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
FaEraser,
2424
FaExpand,
2525
FaFileImport,
26+
FaInfo,
2627
FaPlay,
2728
FaShareAlt,
2829
} from "react-icons/fa";
@@ -36,19 +37,23 @@ import {
3637
useShallowSessionStoreWithUndo,
3738
} from "../../hooks/useSessionStore";
3839
import { DEFAULT_TRANSACTION_RUN, EMPTY_TRANSACTION } from "../../utils/state";
40+
import { Description } from "../common/Description";
3941
import { EditableName } from "../common/EditableName";
4042
import { RpcEndpointMenu } from "../common/RpcEndpointMenu";
43+
import { ToggleIconButton } from "../common/ToggleIconButton";
4144

4245
export const TransactionHeader: React.FC<{
4346
resultsRef: React.RefObject<HTMLDivElement>;
4447
}> = ({ resultsRef }) => {
4548
const scrollToResults = usePersistentStore(
4649
(state) => state.appOptions.scrollToResults
4750
);
48-
const [inProgress, setUI] = useShallowSessionStoreWithoutUndo((state) => [
49-
state.transactionRun.inProgress,
50-
state.set,
51-
]);
51+
const [inProgress, descriptionVisible, setUI] =
52+
useShallowSessionStoreWithoutUndo((state) => [
53+
state.transactionRun.inProgress,
54+
state.uiState.descriptionVisible,
55+
state.set,
56+
]);
5257
const [transaction, rpcEndpoint, setSession] = useShallowSessionStoreWithUndo(
5358
(state) => [state.transaction, state.rpcEndpoint, state.set]
5459
);
@@ -145,6 +150,20 @@ export const TransactionHeader: React.FC<{
145150

146151
<Spacer />
147152

153+
<ToggleIconButton
154+
ml="1"
155+
label={
156+
descriptionVisible ? "Hide annotations" : "Display annotations"
157+
}
158+
icon={<Icon as={FaInfo} />}
159+
toggled={descriptionVisible}
160+
onToggle={(toggled) => {
161+
setUI((state) => {
162+
state.uiState.descriptionVisible = toggled;
163+
});
164+
}}
165+
/>
166+
148167
<Tooltip label="Import">
149168
<IconButton
150169
aria-label="Import"
@@ -225,23 +244,32 @@ export const TransactionHeader: React.FC<{
225244
</Alert>
226245
</Collapse>
227246

228-
<Flex mt="5" mb="3" alignItems="center">
229-
<Heading flex="1" size="lg">
230-
<EditableName
231-
tooltip="Click to edit"
232-
tooltipProps={{ placement: "bottom-start" }}
233-
previewProps={{ p: "3px 10px 3px 10px" }}
234-
inputProps={{ p: "3px 10px 3px 10px" }}
235-
placeholder="Unnamed Transaction"
236-
value={transaction.name}
237-
onChange={(value) =>
238-
setSession((state) => {
239-
state.transaction.name = value;
240-
})
241-
}
242-
/>
243-
</Heading>
244-
</Flex>
247+
<Heading mt="5" mb="2" alignItems="center" flex="1" size="lg">
248+
<EditableName
249+
tooltip="Click to edit"
250+
tooltipProps={{ placement: "bottom-start" }}
251+
previewProps={{ p: "3px 10px 3px 10px" }}
252+
inputProps={{ p: "3px 10px 3px 10px" }}
253+
placeholder="Unnamed Transaction"
254+
value={transaction.name}
255+
onChange={(value) =>
256+
setSession((state) => {
257+
state.transaction.name = value;
258+
})
259+
}
260+
/>
261+
</Heading>
262+
263+
<Description
264+
ml="3"
265+
mb="3"
266+
description={transaction.description}
267+
setDescription={(description) => {
268+
setSession((state) => {
269+
state.transaction.description = description;
270+
});
271+
}}
272+
/>
245273
</>
246274
);
247275
};
Lines changed: 80 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { CloseIcon, EditIcon } from "@chakra-ui/icons";
1+
import { CloseIcon } from "@chakra-ui/icons";
22
import {
33
Flex,
44
Grid,
@@ -10,12 +10,13 @@ import {
1010
Wrap,
1111
} from "@chakra-ui/react";
1212
import React from "react";
13-
import { FaPenNib } from "react-icons/fa";
13+
import { FaFeather, FaICursor } from "react-icons/fa";
1414
import { useAccount } from "../../../hooks/useAccount";
1515
import { useAccountType } from "../../../hooks/useAccountType";
1616
import { useInstruction } from "../../../hooks/useInstruction";
1717
import { useShallowSessionStoreWithUndo } from "../../../hooks/useSessionStore";
1818
import { removeFrom } from "../../../utils/sortable";
19+
import { Description } from "../../common/Description";
1920
import { DragHandle } from "../../common/DragHandle";
2021
import { EditableName } from "../../common/EditableName";
2122
import { Numbering } from "../../common/Numbering";
@@ -39,12 +40,15 @@ export const Account: React.FC<{
3940
state.set,
4041
]);
4142

42-
const [name, pubkey, isWritable, isSigner] = useShallowGet((state) => [
43-
state.name,
44-
state.pubkey,
45-
state.isWritable,
46-
state.isSigner,
47-
]);
43+
const [name, description, pubkey, isWritable, isSigner] = useShallowGet(
44+
(state) => [
45+
state.name,
46+
state.description,
47+
state.pubkey,
48+
state.isWritable,
49+
state.isSigner,
50+
]
51+
);
4852

4953
const removeAccount = () => {
5054
updateInstruction((state) => {
@@ -65,7 +69,7 @@ export const Account: React.FC<{
6569
});
6670

6771
return (
68-
<Flex mb="2" alignItems="start">
72+
<Flex mb="1" alignItems="start">
6973
<DragHandle
7074
unlockedProps={{ mt: "2", h: "2.5", w: "2.5" }}
7175
lockedProps={{ mt: "2", h: "3" }}
@@ -94,68 +98,79 @@ export const Account: React.FC<{
9498
/>
9599

96100
<Grid flex="1">
97-
<AccountInput />
98-
99-
<Wrap
100-
// TODO ignores other future tags
101-
pt={isTypeConfigurable || metadata?.name ? "1" : undefined}
102-
>
103-
{/* TODO */}
104-
{/* {type === "ata" && (
101+
<Flex>
102+
<Grid flex="1">
103+
<AccountInput />
104+
105+
<Wrap
106+
// TODO ignores other future tags
107+
pt={isTypeConfigurable || metadata?.name ? "1" : undefined}
108+
>
109+
{/* TODO */}
110+
{/* {type === "ata" && (
105111
<AtaTypeConfig />
106112
)} */}
107113

108-
{type === "pda" && <PdaTypeConfig />}
109-
110-
{metadata?.name && <Tag size="sm">{metadata.name}</Tag>}
114+
{type === "pda" && <PdaTypeConfig />}
115+
116+
{metadata?.name && <Tag size="sm">{metadata.name}</Tag>}
117+
118+
{/* TODO account balance */}
119+
</Wrap>
120+
</Grid>
121+
122+
<ToggleIconButton
123+
ml="1"
124+
size="sm"
125+
label="Writable"
126+
icon={<Icon as={FaICursor} />}
127+
isDisabled={isAnchor}
128+
toggled={isWritable}
129+
onToggle={(toggled) => {
130+
update((state) => {
131+
state.isWritable = toggled;
132+
});
133+
}}
134+
/>
111135

112-
{/* TODO account balance */}
113-
</Wrap>
136+
<ToggleIconButton
137+
ml="1"
138+
size="sm"
139+
label="Signer"
140+
icon={<Icon as={FaFeather} />}
141+
isDisabled={isAnchor}
142+
toggled={isSigner}
143+
onToggle={(toggled) => {
144+
update((state) => {
145+
state.isSigner = toggled;
146+
});
147+
}}
148+
/>
114149

115-
{/* TODO description when not minimised */}
150+
{!isAnchor && (
151+
<Tooltip label="Remove">
152+
<IconButton
153+
mt="1"
154+
ml="3"
155+
size="xs"
156+
aria-label="Remove"
157+
icon={<CloseIcon />}
158+
variant="ghost"
159+
onClick={removeAccount}
160+
/>
161+
</Tooltip>
162+
)}
163+
</Flex>
164+
165+
<Description
166+
mt="1"
167+
fontSize="sm"
168+
description={description}
169+
setDescription={(description) => {
170+
update((state) => (state.description = description));
171+
}}
172+
/>
116173
</Grid>
117-
118-
<ToggleIconButton
119-
ml="1"
120-
size="sm"
121-
label="Writable"
122-
icon={<EditIcon />}
123-
isDisabled={isAnchor}
124-
toggled={isWritable}
125-
onToggle={(toggled) => {
126-
update((state) => {
127-
state.isWritable = toggled;
128-
});
129-
}}
130-
/>
131-
132-
<ToggleIconButton
133-
ml="1"
134-
size="sm"
135-
label="Signer"
136-
icon={<Icon as={FaPenNib} />}
137-
isDisabled={isAnchor}
138-
toggled={isSigner}
139-
onToggle={(toggled) => {
140-
update((state) => {
141-
state.isSigner = toggled;
142-
});
143-
}}
144-
/>
145-
146-
{!isAnchor && (
147-
<Tooltip label="Remove">
148-
<IconButton
149-
mt="1"
150-
ml="3"
151-
size="xs"
152-
aria-label="Remove"
153-
icon={<CloseIcon />}
154-
variant="ghost"
155-
onClick={removeAccount}
156-
/>
157-
</Tooltip>
158-
)}
159174
</Flex>
160175
);
161176
};

0 commit comments

Comments
 (0)