Skip to content

Commit c35e3f0

Browse files
668 lab 627 fix add tool issues (#676)
Co-authored-by: Aakaash Meduri <aakaash.meduri@gmail.com>
1 parent 16d0986 commit c35e3f0

22 files changed

+1409
-385
lines changed

frontend/app/datafile/add/page.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export default function DataFileForm() {
4747
dispatch(setError("Please select a file"))
4848
return
4949
}
50-
50+
5151
dispatch(startLoading())
5252
dispatch(setError(null))
5353
const metadata = { walletAddress };

frontend/app/layout.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export default function RootLayout(props: React.PropsWithChildren) {
1515
<Box display="flex" flexDirection="column" height="100vh"> {/* Fill entire view height and set up for flex */}
1616
<TopNav />
1717

18-
<Container maxWidth="lg">
18+
<Container maxWidth="lg" style={{paddingBottom: "40px"}}>
1919
<Box mt={5} mb={5} flexGrow={1} display="flex" alignItems="center" justifyContent="center"> {/* Center content */}
2020
<Grid container direction="column" spacing={3}>
2121
<Grid item xs={12}>

frontend/app/tool/add/page.tsx

+70-241
Original file line numberDiff line numberDiff line change
@@ -1,268 +1,97 @@
11
'use client'
22

3-
import React, { useState } from 'react'
3+
import React, { useEffect } from 'react'
44
import { useDispatch, useSelector } from 'react-redux'
5-
import { addToolAsync, selectWalletAddress, setError, startFileUpload, endFileUpload } from '@/lib/redux'
5+
import { useRouter } from 'next/navigation'
66
import {
7-
selectToolError,
8-
selectToolIsLoading,
9-
selectToolIsUploaded
10-
} from '@/lib/redux/slices/toolAddSlice/selectors'
11-
import TextField from '@mui/material/TextField'
7+
AppDispatch,
8+
setAddToolError,
9+
setAddToolLoading,
10+
setAddToolJson,
11+
setAddToolSuccess,
12+
selectWalletAddress,
13+
selectAddToolLoading,
14+
selectAddToolError,
15+
selectAddToolJson,
16+
selectAddToolSuccess,
17+
createToolThunk,
18+
} from '@/lib/redux'
1219
import Button from '@mui/material/Button'
1320
import Box from '@mui/material/Box'
1421
import Grid from '@mui/material/Grid'
15-
// import { useRouter } from 'next/router'
22+
import Alert from '@mui/material/Alert'
23+
import Typography from '@mui/material/Typography'
24+
import { JsonInput } from '@mantine/core'
25+
import { MantineProvider } from '@mantine/core';
26+
1627

1728
export default function AddTool() {
18-
const dispatch = useDispatch()
19-
// const router = useRouter()
29+
const dispatch = useDispatch<AppDispatch>()
30+
const router = useRouter()
2031

21-
const isLoading = useSelector(selectToolIsLoading);
22-
const error = useSelector(selectToolError);
23-
const isUploaded = useSelector(selectToolIsUploaded);
2432
const walletAddress = useSelector(selectWalletAddress)
25-
26-
const sampleToolConfig = {
27-
"class": "CommandLineTool",
28-
"name": "equibind",
29-
"description": "Docking of small molecules to a protein",
30-
"author": "@misc{stärk2022equibind,\n title={EquiBind: Geometric Deep Learning for Drug Binding Structure Prediction}, \n author={Hannes Stärk and Octavian-Eugen Ganea and Lagnajit Pattanaik and Regina Barzilay and Tommi Jaakkola},\n year={2022},\n eprint={2202.05146},\n archivePrefix={arXiv},\n primaryClass={q-bio.BM}\n}",
31-
"baseCommand": ["/bin/bash", "-c"],
32-
"arguments": [
33-
"mkdir -p /tmp-inputs/tmp;",
34-
"mkdir -p /tmp-outputs/tmp;",
35-
"cp /inputs/* /tmp-inputs/tmp/;",
36-
"ls /tmp-inputs/tmp;",
37-
"cd /src && python /src/inference.py --config=/src/configs_clean/bacalhau.yml;",
38-
"mv /tmp-outputs/tmp/* /outputs/;",
39-
"mv /outputs/lig_equibind_corrected.sdf /outputs/$(inputs.protein.basename)_$(inputs.small_molecule.basename)_docked.$(inputs.small_molecule.ext);",
40-
"mv /tmp-inputs/tmp/*.pdb /outputs/;"],
41-
"dockerPull": "ghcr.io/labdao/equibind:main@sha256:21a381d9ab1ff047565685044569c8536a55e489c9531326498b28d6b3cc244f",
42-
"gpuBool": false,
43-
"networkBool": false,
44-
"inputs": {
45-
"protein": {
46-
"type": "File",
47-
"item": "",
48-
"glob": ["*.pdb"]
49-
},
50-
"small_molecule": {
51-
"type": "File",
52-
"item": "",
53-
"glob": ["*.sdf", "*.mol2"]
54-
}
55-
},
56-
"outputs": {
57-
"best_docked_small_molecule": {
58-
"type": "File",
59-
"item": "",
60-
"glob": ["*_docked.sdf", "*_docked.mol2"]
61-
},
62-
"protein": {
63-
"type": "File",
64-
"item": "",
65-
"glob": ["*.pdb"]
66-
}
33+
const loading = useSelector(selectAddToolLoading)
34+
const error = useSelector(selectAddToolError)
35+
const toolJson = useSelector(selectAddToolJson)
36+
const toolSuccess = useSelector(selectAddToolSuccess)
37+
38+
useEffect(() => {
39+
if (toolSuccess) {
40+
setAddToolSuccess(false)
41+
dispatch(setAddToolJson(""))
42+
router.push('/tool/list')
6743
}
68-
}
69-
70-
const [toolClass, setToolClass] = useState(sampleToolConfig.class)
71-
const [name, setName] = useState(sampleToolConfig.name);
72-
const [description, setDescription] = useState(sampleToolConfig.description);
73-
const [author, setAuthor] = useState(sampleToolConfig.author);
74-
const [baseCommand, setBaseCommand] = useState(sampleToolConfig.baseCommand);
75-
const [toolArguments, setToolArguments] = useState(sampleToolConfig.arguments);
76-
const [dockerPull, setDockerPull] = useState(sampleToolConfig.dockerPull);
77-
const [gpuBool, setGpuBool] = useState(sampleToolConfig.gpuBool);
78-
const [networkBool, setNetworkBool] = useState(sampleToolConfig.networkBool);
79-
const [inputs, setInputs] = useState(sampleToolConfig.inputs);
80-
const [outputs, setOutputs] = useState(sampleToolConfig.outputs);
81-
82-
const handleToolClassChange = (e: React.ChangeEvent<HTMLInputElement>) => {
83-
setToolClass(e.target.value);
84-
};
85-
86-
const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
87-
setName(e.target.value);
88-
};
89-
90-
const handleDescriptionChange = (e: React.ChangeEvent<HTMLInputElement>) => {
91-
setDescription(e.target.value);
92-
};
93-
94-
const handleAuthorChange = (e: React.ChangeEvent<HTMLInputElement>) => {
95-
setAuthor(e.target.value);
96-
};
97-
98-
const handleBaseCommandChange = (e: React.ChangeEvent<HTMLInputElement>) => {
99-
setBaseCommand(e.target.value.split(','));
100-
};
101-
102-
const handleToolArgumentsChange = (e: React.ChangeEvent<HTMLInputElement>) => {
103-
setToolArguments(e.target.value.split(','));
104-
};
44+
}, [toolSuccess, dispatch])
10545

106-
const handleDockerPullChange = (e: React.ChangeEvent<HTMLInputElement>) => {
107-
setDockerPull(e.target.value);
108-
};
109-
110-
const handleGpuBoolChange = (e: React.ChangeEvent<HTMLInputElement>) => {
111-
setGpuBool(e.target.checked);
112-
};
113-
114-
const handleNetworkBoolChange = (e: React.ChangeEvent<HTMLInputElement>) => {
115-
setNetworkBool(e.target.checked);
116-
};
117-
118-
const handleInputsChange = (e: React.ChangeEvent<HTMLInputElement>) => {
119-
try {
120-
const value = JSON.parse(e.target.value);
121-
setInputs(value);
122-
} catch (error) {
123-
console.error(error);
124-
}
125-
};
46+
const handleToolJsonChange = (toolJsonInput: string) => {
47+
dispatch(setAddToolJson(toolJsonInput))
48+
}
12649

127-
const handleOutputsChange = (e: React.ChangeEvent<HTMLInputElement>) => {
50+
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
51+
e.preventDefault();
52+
console.log("Submitting tool.json: ", toolJson);
53+
dispatch(setAddToolLoading(true))
54+
dispatch(setAddToolError(""))
12855
try {
129-
const value = JSON.parse(e.target.value);
130-
setOutputs(value);
56+
const toolJsonParsed = JSON.parse(toolJson)
57+
await dispatch(createToolThunk({ walletAddress, toolJson: toolJsonParsed }))
13158
} catch (error) {
132-
console.error(error);
59+
console.error("Error creating tool", error)
60+
dispatch(setAddToolError("Error creating tool"))
13361
}
134-
};
135-
136-
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
137-
e.preventDefault();
138-
139-
console.log("Submitting tool config")
140-
console.log("Wallet address: ", walletAddress)
141-
142-
const toolConfig = {
143-
"name": name,
144-
"description": description,
145-
"author": author,
146-
"baseCommand": baseCommand,
147-
"arguments": toolArguments,
148-
"dockerPull": dockerPull,
149-
"gpuBool": gpuBool,
150-
"networkBool": networkBool,
151-
"inputs": inputs,
152-
"outputs": outputs
153-
};
154-
155-
// @ts-ignore
156-
dispatch(addToolAsync({ toolData: toolConfig, walletAddress }));
157-
// router.push('/tool/list');
158-
};
62+
dispatch(setAddToolLoading(false))
63+
}
15964

16065
return (
16166
<form onSubmit={handleSubmit}>
16267
<Box maxWidth={500} margin="auto">
163-
<Grid container direction="column" spacing={2}>
164-
<Grid item>
165-
<TextField
166-
fullWidth
167-
label="Tool Class"
168-
variant="outlined"
169-
value={toolClass}
170-
onChange={handleToolClassChange}
171-
/>
172-
</Grid>
173-
<Grid item>
174-
<TextField
175-
fullWidth
176-
label="Tool Name"
177-
variant="outlined"
178-
value={name}
179-
onChange={handleNameChange}
180-
/>
181-
</Grid>
182-
<Grid item>
183-
<TextField
184-
fullWidth
185-
label="Description"
186-
variant="outlined"
187-
value={description}
188-
onChange={handleDescriptionChange}
189-
/>
190-
</Grid>
191-
<Grid item>
192-
<TextField
193-
fullWidth
194-
label="Author"
195-
variant="outlined"
196-
value={author}
197-
onChange={handleAuthorChange}
198-
/>
199-
</Grid>
200-
<Grid item>
201-
<TextField
202-
fullWidth
203-
label="Base Command"
204-
variant="outlined"
205-
value={baseCommand}
206-
onChange={handleBaseCommandChange}
207-
/>
208-
</Grid>
209-
<Grid item>
210-
<TextField
211-
fullWidth
212-
label="Arguments"
213-
variant="outlined"
214-
value={toolArguments}
215-
onChange={handleToolArgumentsChange}
216-
/>
217-
</Grid>
218-
<Grid item>
219-
<TextField
220-
fullWidth
221-
label="Docker Pull"
222-
variant="outlined"
223-
value={dockerPull}
224-
onChange={handleDockerPullChange}
225-
/>
226-
</Grid>
227-
<Grid item>
228-
<TextField
229-
fullWidth
230-
label="GPU Bool"
231-
variant="outlined"
232-
value={gpuBool}
233-
onChange={handleGpuBoolChange}
234-
/>
235-
</Grid>
236-
<Grid item>
237-
<TextField
238-
fullWidth
239-
label="Network Bool"
240-
variant="outlined"
241-
value={networkBool}
242-
onChange={handleNetworkBoolChange}
243-
/>
244-
</Grid>
245-
<Grid item>
246-
<TextField
247-
fullWidth
248-
label="Inputs"
249-
variant="outlined"
250-
value={inputs}
251-
onChange={handleInputsChange}
252-
/>
253-
</Grid>
254-
<Grid item>
255-
<TextField
256-
fullWidth
257-
label="Outputs"
258-
variant="outlined"
259-
value={outputs}
260-
onChange={handleOutputsChange}
261-
/>
68+
<Grid container direction="column" spacing={2} justifyContent="center" alignItems="center">
69+
<Grid style={{ width: '100%' }} item>
70+
<MantineProvider>
71+
<JsonInput
72+
label="Tool Definition"
73+
placeholder="Paste your tool's JSON definition here."
74+
validationError="Invalid JSON"
75+
autosize
76+
minRows={10}
77+
value={toolJson}
78+
onChange={handleToolJsonChange}
79+
styles={{
80+
input: { 'width': '100%' },
81+
}}
82+
/>
83+
</MantineProvider>
26284
</Grid>
85+
{error && (
86+
<Box my={2}>
87+
<Alert severity="error" variant="filled">
88+
<Typography align="center">{error}</Typography>
89+
</Alert>
90+
</Box>
91+
)}
26392
<Grid item container justifyContent="center">
26493
<Button variant="contained" color="primary" type="submit">
265-
{isLoading ? "Submitting..." : "Submit"}
94+
{loading ? "Submitting..." : "Submit"}
26695
</Button>
26796
</Grid>
26897
</Grid>

frontend/app/tool/list/page.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import backendUrl from 'lib/backendUrl'
1313
export default function ListToolFiles() {
1414
interface Tool {
1515
CID: string;
16-
ToolJSON: string;
16+
Name: string;
1717
WalletAddress: string;
1818
}
1919

@@ -41,20 +41,20 @@ export default function ListToolFiles() {
4141
<Table>
4242
<TableHead>
4343
<TableRow>
44+
<TableCell>Name</TableCell>
4445
<TableCell>CID</TableCell>
45-
<TableCell>Serialized Tool Config</TableCell>
4646
<TableCell>Uploader Wallet Address</TableCell>
4747
</TableRow>
4848
</TableHead>
4949
<TableBody>
5050
{tools.map((tool, index) => (
5151
<TableRow key={index}>
52+
<TableCell>{tool.Name}</TableCell>
5253
<TableCell>
5354
<a href={`http://bacalhau.labdao.xyz:8080/ipfs/${tool.CID}/`}>
5455
{tool.CID}
5556
</a>
5657
</TableCell>
57-
<TableCell>{JSON.stringify(tool.ToolJSON)}</TableCell>
5858
<TableCell>{tool.WalletAddress}</TableCell>
5959
</TableRow>
6060
))}

0 commit comments

Comments
 (0)