mirror of
https://github.com/oceanprotocol/market.git
synced 2024-12-02 05:57:29 +01:00
Merge branch 'main' into fix/issue497-fetch-price-subgraph, fixed merge conflicts
This commit is contained in:
commit
ff1d987b5d
@ -1,5 +1,5 @@
|
|||||||
# Default network, possible values:
|
# Default network, possible values:
|
||||||
# "development", "ropsten", "rinkeby", "mainnet", "polygon"
|
# "development", "ropsten", "rinkeby", "mainnet", "polygon", "moonbeamalpha"
|
||||||
GATSBY_NETWORK="rinkeby"
|
GATSBY_NETWORK="rinkeby"
|
||||||
|
|
||||||
#GATSBY_INFURA_PROJECT_ID="xxx"
|
#GATSBY_INFURA_PROJECT_ID="xxx"
|
||||||
|
@ -20,6 +20,15 @@
|
|||||||
"rows": 10,
|
"rows": 10,
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "price",
|
||||||
|
"label": "New Price",
|
||||||
|
"type": "number",
|
||||||
|
"min": "1",
|
||||||
|
"placeholder": "0",
|
||||||
|
"help": "Enter a new price.",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "links",
|
"name": "links",
|
||||||
"label": "Sample file",
|
"label": "Sample file",
|
||||||
|
@ -6,13 +6,6 @@
|
|||||||
"successAction": "Close",
|
"successAction": "Close",
|
||||||
"error": "Updating DDO failed.",
|
"error": "Updating DDO failed.",
|
||||||
"data": [
|
"data": [
|
||||||
{
|
|
||||||
"name": "allowAllPublishedAlgorithms",
|
|
||||||
"label": "All Algorithms",
|
|
||||||
"help": "Allow any published algorithm to run on this data set.",
|
|
||||||
"type": "checkbox",
|
|
||||||
"options": ["Allow any published algorithm"]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "publisherTrustedAlgorithms",
|
"name": "publisherTrustedAlgorithms",
|
||||||
"label": "Selected Algorithms",
|
"label": "Selected Algorithms",
|
||||||
@ -21,6 +14,13 @@
|
|||||||
"multiple": true,
|
"multiple": true,
|
||||||
"options": [],
|
"options": [],
|
||||||
"sortOptions": false
|
"sortOptions": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "allowAllPublishedAlgorithms",
|
||||||
|
"label": "All Algorithms",
|
||||||
|
"help": "Allow any published algorithm to run on this data set.",
|
||||||
|
"type": "checkbox",
|
||||||
|
"options": ["Allow any published algorithm"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
{
|
{
|
||||||
"title": "History",
|
"title": "History",
|
||||||
"description": "Find the data sets and jobs that you previously accessed."
|
"description": "Find the data sets and jobs that you previously accessed.",
|
||||||
|
"compute": {
|
||||||
|
"storage": "Results are stored for 30 days."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
"name": "files",
|
"name": "files",
|
||||||
"label": "File",
|
"label": "File",
|
||||||
"placeholder": "e.g. https://file.com/file.json",
|
"placeholder": "e.g. https://file.com/file.json",
|
||||||
"help": "Please enter the URL to your algorithm file and click \"ADD FILE\" to validate the data. This URL will be stored encrypted after publishing.",
|
"help": "Please enter the URL to your algorithm file and click \"ADD FILE\" to validate the data. This URL will be stored encrypted after publishing. Some restrictions apply:\n\n- max. running time: 1 min.\n- [Writing Algorithms for Compute to Data](https://docs.oceanprotocol.com/tutorials/compute-to-data-algorithms/)",
|
||||||
"type": "files",
|
"type": "files",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
@ -56,6 +56,13 @@
|
|||||||
"sortOptions": false,
|
"sortOptions": false,
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "dataTokenOptions",
|
||||||
|
"label": "Datatoken Name & Symbol",
|
||||||
|
"type": "datatoken",
|
||||||
|
"help": "The datatoken for this algorithm will be created with this name & symbol.",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "entrypoint",
|
"name": "entrypoint",
|
||||||
"label": "Entrypoint",
|
"label": "Entrypoint",
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
"name": "files",
|
"name": "files",
|
||||||
"label": "File",
|
"label": "File",
|
||||||
"placeholder": "e.g. https://file.com/file.json",
|
"placeholder": "e.g. https://file.com/file.json",
|
||||||
"help": "Please enter the URL to your data set file and click \"ADD FILE\" to validate the data. This URL will be stored encrypted after publishing.",
|
"help": "Please enter the URL to your data set file and click \"ADD FILE\" to validate the data. This URL will be stored encrypted after publishing. For a compute data set, your file should match the file type required by the algorithm, and should not exceed 1 GB in file size.",
|
||||||
"type": "files",
|
"type": "files",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
|
36
package-lock.json
generated
36
package-lock.json
generated
@ -1573,16 +1573,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@ethereum-navigator/atlas": {
|
"@ethereum-navigator/atlas": {
|
||||||
"version": "0.7.1",
|
"version": "0.7.3",
|
||||||
"resolved": "https://registry.npmjs.org/@ethereum-navigator/atlas/-/atlas-0.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/@ethereum-navigator/atlas/-/atlas-0.7.3.tgz",
|
||||||
"integrity": "sha512-YV7tMVwpRcJbc+Kj/Rr0RzNV/2hHBEEM1/tMWDVLB15dGJfoQuRfPJpFt6uq+Ji6s3EkldIt9kZylEeG5ALKAA=="
|
"integrity": "sha512-kCyV/8wOqSU/gn+H7uSaR/Xc+ZogXrW2QmF5MfZL2+NUS4+y0emlfBphTGwP5bOB0Cg2goJTcI7Y6+0LNcJYzg=="
|
||||||
},
|
},
|
||||||
"@ethereum-navigator/navigator": {
|
"@ethereum-navigator/navigator": {
|
||||||
"version": "0.5.2",
|
"version": "0.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/@ethereum-navigator/navigator/-/navigator-0.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/@ethereum-navigator/navigator/-/navigator-0.5.3.tgz",
|
||||||
"integrity": "sha512-agSE2xzLxOKKid8QiS4v8jPhnFXW5uSXsICZ4JmS437aCZ8L3SUAy3cDQKikHb2PPZ3AazJO05k8m8i6u77peQ==",
|
"integrity": "sha512-AOhS1EXPrVeWbLvW3fVbw5AZ2mPYXDKOqMojgVz602U/tEjRXAsw/Gwa+oSOssAyU37SNKBaIorEhBiEY+RYdA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@ethereum-navigator/atlas": "^0.7.1",
|
"@ethereum-navigator/atlas": "^0.7.2",
|
||||||
"web3": "^1.2.7"
|
"web3": "^1.2.7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -3622,24 +3622,24 @@
|
|||||||
"integrity": "sha512-j4PEZSVtKSqxDYMVh/hd5vk088Bg6a6QkrUMTXN9Q6OIFAMfHM235f1AxaakNrEyK0FKMD908KuJEdfFLRn9Hw=="
|
"integrity": "sha512-j4PEZSVtKSqxDYMVh/hd5vk088Bg6a6QkrUMTXN9Q6OIFAMfHM235f1AxaakNrEyK0FKMD908KuJEdfFLRn9Hw=="
|
||||||
},
|
},
|
||||||
"@oceanprotocol/contracts": {
|
"@oceanprotocol/contracts": {
|
||||||
"version": "0.5.15",
|
"version": "0.5.16",
|
||||||
"resolved": "https://registry.npmjs.org/@oceanprotocol/contracts/-/contracts-0.5.15.tgz",
|
"resolved": "https://registry.npmjs.org/@oceanprotocol/contracts/-/contracts-0.5.16.tgz",
|
||||||
"integrity": "sha512-16edzNeO2v5WLW9ClsZ9VvMH1w24fZZutCmDhZWPirCAIdojGWRHraompfICjY1fovDljnZ5MpJpffuQ6kgxOA=="
|
"integrity": "sha512-p7aFIUT8RVoMzdPP7ML8G08BnQ09syywKjOT16hqJm0GmofunEuVffUXbryG4EkQ+qRbf/zeoxSmesi79kQXlA=="
|
||||||
},
|
},
|
||||||
"@oceanprotocol/lib": {
|
"@oceanprotocol/lib": {
|
||||||
"version": "0.14.4",
|
"version": "0.14.8",
|
||||||
"resolved": "https://registry.npmjs.org/@oceanprotocol/lib/-/lib-0.14.4.tgz",
|
"resolved": "https://registry.npmjs.org/@oceanprotocol/lib/-/lib-0.14.8.tgz",
|
||||||
"integrity": "sha512-f6Wj6FLpYmuFSGtnDw0lex0Vru1tGgvZqtwrdBYtMD+hW6Bn3B51+F/9ACVYAiSRDADrqPTDZiZetT2Ji3QY7Q==",
|
"integrity": "sha512-eqab5iEgowyIM/LcDDs6xhZo/KToOmVw0betjXLG0+g70zS8R6XL2RHzCpFyutSdf/cH0w/ltPUfR8ZBElIyhQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@ethereum-navigator/navigator": "^0.5.2",
|
"@ethereum-navigator/navigator": "^0.5.2",
|
||||||
"@oceanprotocol/contracts": "^0.5.10",
|
"@oceanprotocol/contracts": "0.5.16",
|
||||||
"@types/crypto-js": "^4.0.1",
|
"@types/crypto-js": "^4.0.1",
|
||||||
"cross-fetch": "^3.1.2",
|
"cross-fetch": "^3.1.2",
|
||||||
"crypto-js": "^4.0.0",
|
"crypto-js": "^4.0.0",
|
||||||
"decimal.js": "^10.2.1",
|
"decimal.js": "^10.2.1",
|
||||||
"fs": "0.0.1-security",
|
"fs": "0.0.1-security",
|
||||||
"lzma": "^2.3.2",
|
"lzma": "^2.3.2",
|
||||||
"node-abort-controller": "^1.2.0",
|
"node-abort-controller": "^2.0.0",
|
||||||
"save-file": "^2.3.1",
|
"save-file": "^2.3.1",
|
||||||
"uuid": "^8.3.2",
|
"uuid": "^8.3.2",
|
||||||
"web3": "^1.3.5",
|
"web3": "^1.3.5",
|
||||||
@ -28882,9 +28882,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node-abort-controller": {
|
"node-abort-controller": {
|
||||||
"version": "1.2.1",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-2.0.0.tgz",
|
||||||
"integrity": "sha512-79PYeJuj6S9+yOHirR0JBLFOgjB6sQCir10uN6xRx25iD+ZD4ULqgRn3MwWBRaQGB0vEgReJzWwJo42T1R6YbQ=="
|
"integrity": "sha512-L8RfEgjBTHAISTuagw51PprVAqNZoG6KSB6LQ6H1bskMVkFs5E71IyjauLBv3XbuomJlguWF/VnRHdJ1gqiAqA=="
|
||||||
},
|
},
|
||||||
"node-addon-api": {
|
"node-addon-api": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
"@coingecko/cryptoformat": "^0.4.2",
|
"@coingecko/cryptoformat": "^0.4.2",
|
||||||
"@loadable/component": "^5.14.1",
|
"@loadable/component": "^5.14.1",
|
||||||
"@oceanprotocol/art": "^3.0.0",
|
"@oceanprotocol/art": "^3.0.0",
|
||||||
"@oceanprotocol/lib": "^0.14.4",
|
"@oceanprotocol/lib": "^0.14.8",
|
||||||
"@oceanprotocol/typographies": "^0.1.0",
|
"@oceanprotocol/typographies": "^0.1.0",
|
||||||
"@portis/web3": "^3.0.3",
|
"@portis/web3": "^3.0.3",
|
||||||
"@sindresorhus/slugify": "^1.0.0",
|
"@sindresorhus/slugify": "^1.0.0",
|
||||||
|
2
src/@types/MetaData.d.ts
vendored
2
src/@types/MetaData.d.ts
vendored
@ -49,6 +49,7 @@ export interface MetadataPublishFormAlgorithm {
|
|||||||
dockerImage: string
|
dockerImage: string
|
||||||
algorithmPrivacy: boolean
|
algorithmPrivacy: boolean
|
||||||
timeout: string
|
timeout: string
|
||||||
|
dataTokenOptions: DataTokenOptions
|
||||||
termsAndConditions: boolean
|
termsAndConditions: boolean
|
||||||
// ---- optional fields ----
|
// ---- optional fields ----
|
||||||
image: string
|
image: string
|
||||||
@ -61,6 +62,7 @@ export interface MetadataEditForm {
|
|||||||
name: string
|
name: string
|
||||||
description: string
|
description: string
|
||||||
timeout: string
|
timeout: string
|
||||||
|
price?: number
|
||||||
links?: string | EditableMetadataLinks[]
|
links?: string | EditableMetadataLinks[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,6 +91,7 @@ export default function InputElement({
|
|||||||
id={slugify(option)}
|
id={slugify(option)}
|
||||||
type={type}
|
type={type}
|
||||||
name={name}
|
name={name}
|
||||||
|
checked={props.defaultChecked}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
<label className={styles.radioLabel} htmlFor={slugify(option)}>
|
<label className={styles.radioLabel} htmlFor={slugify(option)}>
|
||||||
|
@ -107,7 +107,9 @@
|
|||||||
|
|
||||||
.did {
|
.did {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
font-size: var(--font-size-mini);
|
/* font-size: var(--font-size-mini); */
|
||||||
|
/* hack to make DotDotDot clamp work in Safari*/
|
||||||
|
font-size: 0.63rem;
|
||||||
display: block;
|
display: block;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
color: var(--color-secondary);
|
color: var(--color-secondary);
|
||||||
|
@ -27,7 +27,7 @@ export default function FileInput({
|
|||||||
<Button
|
<Button
|
||||||
style="primary"
|
style="primary"
|
||||||
size="small"
|
size="small"
|
||||||
onClick={(e: React.SyntheticEvent) => handleButtonClick(e, field.value)}
|
onClick={(e: React.SyntheticEvent) => e.preventDefault()}
|
||||||
disabled={!field.value}
|
disabled={!field.value}
|
||||||
>
|
>
|
||||||
{isLoading ? <Loader /> : 'Add File'}
|
{isLoading ? <Loader /> : 'Add File'}
|
||||||
|
@ -14,7 +14,7 @@ export default function FilesInput(props: InputProps): ReactElement {
|
|||||||
const [fileUrl, setFileUrl] = useState<string>()
|
const [fileUrl, setFileUrl] = useState<string>()
|
||||||
const { config } = useOcean()
|
const { config } = useOcean()
|
||||||
|
|
||||||
useEffect(() => {
|
function loadFileInfo() {
|
||||||
const source = axios.CancelToken.source()
|
const source = axios.CancelToken.source()
|
||||||
|
|
||||||
async function validateUrl() {
|
async function validateUrl() {
|
||||||
@ -33,11 +33,16 @@ export default function FilesInput(props: InputProps): ReactElement {
|
|||||||
setIsLoading(false)
|
setIsLoading(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fileUrl && validateUrl()
|
fileUrl && validateUrl()
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
source.cancel()
|
source.cancel()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
loadFileInfo()
|
||||||
}, [fileUrl, config.providerUri])
|
}, [fileUrl, config.providerUri])
|
||||||
|
|
||||||
async function handleButtonClick(e: React.SyntheticEvent, url: string) {
|
async function handleButtonClick(e: React.SyntheticEvent, url: string) {
|
||||||
@ -48,6 +53,11 @@ export default function FilesInput(props: InputProps): ReactElement {
|
|||||||
// File example 'https://oceanprotocol.com/tech-whitepaper.pdf'
|
// File example 'https://oceanprotocol.com/tech-whitepaper.pdf'
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
|
// In the case when the user re-add the same URL after it was removed (by accident or intentionally)
|
||||||
|
if (fileUrl === url) {
|
||||||
|
loadFileInfo()
|
||||||
|
}
|
||||||
|
|
||||||
setFileUrl(url)
|
setFileUrl(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,10 @@ const query = graphql`
|
|||||||
|
|
||||||
export default function Terms(props: InputProps): ReactElement {
|
export default function Terms(props: InputProps): ReactElement {
|
||||||
const data = useStaticQuery(query)
|
const data = useStaticQuery(query)
|
||||||
|
const termsProps: InputProps = {
|
||||||
|
...props,
|
||||||
|
defaultChecked: props.value.toString() === 'true'
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -21,7 +25,7 @@ export default function Terms(props: InputProps): ReactElement {
|
|||||||
className={styles.terms}
|
className={styles.terms}
|
||||||
dangerouslySetInnerHTML={{ __html: data.terms.html }}
|
dangerouslySetInnerHTML={{ __html: data.terms.html }}
|
||||||
/>
|
/>
|
||||||
<InputElement {...props} type="checkbox" />
|
<InputElement {...termsProps} type="checkbox" />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -135,6 +135,11 @@ export function MetadataAlgorithmPreview({
|
|||||||
<h2 className={styles.previewTitle}>Preview</h2>
|
<h2 className={styles.previewTitle}>Preview</h2>
|
||||||
<header>
|
<header>
|
||||||
{values.name && <h3 className={styles.title}>{values.name}</h3>}
|
{values.name && <h3 className={styles.title}>{values.name}</h3>}
|
||||||
|
{values.dataTokenOptions?.name && (
|
||||||
|
<p
|
||||||
|
className={styles.datatoken}
|
||||||
|
>{`${values.dataTokenOptions.name} — ${values.dataTokenOptions.symbol}`}</p>
|
||||||
|
)}
|
||||||
{values.description && <Description description={values.description} />}
|
{values.description && <Description description={values.description} />}
|
||||||
|
|
||||||
<div className={styles.asset}>
|
<div className={styles.asset}>
|
||||||
|
@ -17,20 +17,30 @@ export default function SearchBar({
|
|||||||
filters?: boolean
|
filters?: boolean
|
||||||
size?: 'small' | 'large'
|
size?: 'small' | 'large'
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const [value, setValue] = useState(initialValue || '')
|
let [value, setValue] = useState(initialValue || '')
|
||||||
|
|
||||||
function handleChange(e: ChangeEvent<HTMLInputElement>) {
|
|
||||||
setValue(e.target.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function startSearch(e: FormEvent<HTMLButtonElement>) {
|
async function startSearch(e: FormEvent<HTMLButtonElement>) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
if (value === '') return
|
if (value === '') value = ' '
|
||||||
const urlEncodedValue = encodeURIComponent(value)
|
const urlEncodedValue = encodeURIComponent(value)
|
||||||
const url = await addExistingParamsToUrl(location, 'text')
|
const url = await addExistingParamsToUrl(location, 'text')
|
||||||
navigate(`${url}&text=${urlEncodedValue}`)
|
navigate(`${url}&text=${urlEncodedValue}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function emptySearch() {
|
||||||
|
const searchParams = new URLSearchParams(window.location.href)
|
||||||
|
const text = searchParams.get('text')
|
||||||
|
if (text !== ('' || undefined || null)) {
|
||||||
|
const url = await addExistingParamsToUrl(location, 'text')
|
||||||
|
navigate(`${url}&text=%20`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleChange(e: ChangeEvent<HTMLInputElement>) {
|
||||||
|
setValue(e.target.value)
|
||||||
|
e.target.value === '' && emptySearch()
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className={styles.form}>
|
<form className={styles.form}>
|
||||||
<InputGroup>
|
<InputGroup>
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
.buttons {
|
.buttons {
|
||||||
display: flex;
|
display: grid;
|
||||||
justify-content: space-between;
|
gap: calc(var(--spacer) / 4);
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(6rem, 1fr));
|
||||||
padding-bottom: calc(var(--spacer) / 8);
|
padding-bottom: calc(var(--spacer) / 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
display: block;
|
width: auto;
|
||||||
flex: 0 0 48%;
|
padding: calc(var(--spacer) / 3) calc(var(--spacer) / 4) !important;
|
||||||
padding: calc(var(--spacer) / 3) calc(var(--spacer) / 2)
|
|
||||||
calc(var(--spacer) / 4) calc(var(--spacer) / 2) !important;
|
|
||||||
border-radius: var(--border-radius);
|
border-radius: var(--border-radius);
|
||||||
text-transform: none;
|
text-transform: none;
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,9 @@ export default function Chain(): ReactElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const chains = [
|
const chains = [
|
||||||
{ name: 'ETH', oceanConfig: 'mainnet' },
|
{ name: 'ETH', oceanConfig: 'mainnet', label: 'Mainnet' },
|
||||||
{ name: 'Polygon/Matic', oceanConfig: 'polygon' }
|
{ name: 'Polygon/Matic', oceanConfig: 'polygon', label: 'Mainnet' },
|
||||||
|
{ name: 'Moonbase Alpha', oceanConfig: 'moonbeamalpha', label: 'Testnet' }
|
||||||
]
|
]
|
||||||
|
|
||||||
// TODO: to fully solve https://github.com/oceanprotocol/market/issues/432
|
// TODO: to fully solve https://github.com/oceanprotocol/market/issues/432
|
||||||
@ -42,7 +43,7 @@ export default function Chain(): ReactElement {
|
|||||||
onClick={() => connectOcean(button.oceanConfig)}
|
onClick={() => connectOcean(button.oceanConfig)}
|
||||||
>
|
>
|
||||||
{button.name}
|
{button.name}
|
||||||
<span>Mainnet</span>
|
<span>{button.label}</span>
|
||||||
</Button>
|
</Button>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
@ -25,7 +25,10 @@ import {
|
|||||||
getInitialValues,
|
getInitialValues,
|
||||||
validationSchema
|
validationSchema
|
||||||
} from '../../../../models/FormStartComputeDataset'
|
} from '../../../../models/FormStartComputeDataset'
|
||||||
import { ComputeAlgorithm } from '@oceanprotocol/lib/dist/node/ocean/interfaces/Compute'
|
import {
|
||||||
|
ComputeAlgorithm,
|
||||||
|
ComputeOutput
|
||||||
|
} from '@oceanprotocol/lib/dist/node/ocean/interfaces/Compute'
|
||||||
import { AssetSelectionAsset } from '../../../molecules/FormFields/AssetSelection'
|
import { AssetSelectionAsset } from '../../../molecules/FormFields/AssetSelection'
|
||||||
import { SearchQuery } from '@oceanprotocol/lib/dist/node/metadatacache/MetadataCache'
|
import { SearchQuery } from '@oceanprotocol/lib/dist/node/metadatacache/MetadataCache'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
@ -190,26 +193,30 @@ export default function Compute({
|
|||||||
}, [ocean, ddo, accountId])
|
}, [ocean, ddo, accountId])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!ocean || !accountId || !selectedAlgorithmAsset) return
|
if (!selectedAlgorithmAsset) return
|
||||||
|
|
||||||
if (selectedAlgorithmAsset.findServiceByType('access')) {
|
|
||||||
checkPreviousOrders(selectedAlgorithmAsset).then(() => {
|
|
||||||
if (
|
|
||||||
!hasPreviousAlgorithmOrder &&
|
|
||||||
selectedAlgorithmAsset.findServiceByType('compute')
|
|
||||||
) {
|
|
||||||
checkPreviousOrders(selectedAlgorithmAsset)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else if (selectedAlgorithmAsset.findServiceByType('compute')) {
|
|
||||||
checkPreviousOrders(selectedAlgorithmAsset)
|
|
||||||
}
|
|
||||||
checkAssetDTBalance(selectedAlgorithmAsset)
|
|
||||||
initMetadata(selectedAlgorithmAsset)
|
initMetadata(selectedAlgorithmAsset)
|
||||||
|
|
||||||
const { timeout } = (
|
const { timeout } = (
|
||||||
ddo.findServiceByType('access') || ddo.findServiceByType('compute')
|
ddo.findServiceByType('access') || ddo.findServiceByType('compute')
|
||||||
).attributes.main
|
).attributes.main
|
||||||
setAlgorithmTimeout(secondsToString(timeout))
|
setAlgorithmTimeout(secondsToString(timeout))
|
||||||
|
|
||||||
|
if (accountId) {
|
||||||
|
if (selectedAlgorithmAsset.findServiceByType('access')) {
|
||||||
|
checkPreviousOrders(selectedAlgorithmAsset).then(() => {
|
||||||
|
if (
|
||||||
|
!hasPreviousAlgorithmOrder &&
|
||||||
|
selectedAlgorithmAsset.findServiceByType('compute')
|
||||||
|
) {
|
||||||
|
checkPreviousOrders(selectedAlgorithmAsset)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if (selectedAlgorithmAsset.findServiceByType('compute')) {
|
||||||
|
checkPreviousOrders(selectedAlgorithmAsset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ocean && checkAssetDTBalance(selectedAlgorithmAsset)
|
||||||
}, [selectedAlgorithmAsset, ocean, accountId, hasPreviousAlgorithmOrder])
|
}, [selectedAlgorithmAsset, ocean, accountId, hasPreviousAlgorithmOrder])
|
||||||
|
|
||||||
// Output errors in toast UI
|
// Output errors in toast UI
|
||||||
@ -330,7 +337,10 @@ export default function Compute({
|
|||||||
computeAlgorithm.transferTxId = algorithmAssetOrderId
|
computeAlgorithm.transferTxId = algorithmAssetOrderId
|
||||||
Logger.log('[compute] Starting compute job.')
|
Logger.log('[compute] Starting compute job.')
|
||||||
|
|
||||||
const output = {}
|
const output: ComputeOutput = {
|
||||||
|
publishAlgorithmLog: true,
|
||||||
|
publishOutput: true
|
||||||
|
}
|
||||||
const response = await ocean.compute.start(
|
const response = await ocean.compute.start(
|
||||||
ddo.id,
|
ddo.id,
|
||||||
assetOrderId,
|
assetOrderId,
|
||||||
@ -410,7 +420,9 @@ export default function Compute({
|
|||||||
action={<SuccessAction />}
|
action={<SuccessAction />}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<Web3Feedback isBalanceSufficient={isBalanceSufficient} />
|
{type !== 'algorithm' && (
|
||||||
|
<Web3Feedback isBalanceSufficient={isBalanceSufficient} />
|
||||||
|
)}
|
||||||
</footer>
|
</footer>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -47,15 +47,17 @@ export default function FormEditMetadata({
|
|||||||
data,
|
data,
|
||||||
setShowEdit,
|
setShowEdit,
|
||||||
setTimeoutStringValue,
|
setTimeoutStringValue,
|
||||||
values
|
values,
|
||||||
|
showPrice
|
||||||
}: {
|
}: {
|
||||||
data: FormFieldProps[]
|
data: FormFieldProps[]
|
||||||
setShowEdit: (show: boolean) => void
|
setShowEdit: (show: boolean) => void
|
||||||
setTimeoutStringValue: (value: string) => void
|
setTimeoutStringValue: (value: string) => void
|
||||||
values: Partial<MetadataPublishFormDataset>
|
values: Partial<MetadataPublishFormDataset>
|
||||||
|
showPrice: boolean
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { accountId } = useWeb3()
|
const { accountId } = useWeb3()
|
||||||
const { ocean } = useOcean()
|
const { ocean, config } = useOcean()
|
||||||
const {
|
const {
|
||||||
isValid,
|
isValid,
|
||||||
validateField,
|
validateField,
|
||||||
@ -79,16 +81,20 @@ export default function FormEditMetadata({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Form className={styles.form}>
|
<Form className={styles.form}>
|
||||||
{data.map((field: FormFieldProps) => (
|
{data.map(
|
||||||
<Field
|
(field: FormFieldProps) =>
|
||||||
key={field.name}
|
(!showPrice && field.name === 'price') || (
|
||||||
{...field}
|
<Field
|
||||||
component={Input}
|
key={field.name}
|
||||||
onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
{...field}
|
||||||
handleFieldChange(e, field)
|
component={Input}
|
||||||
}
|
prefix={field.name === 'price' && config.oceanTokenSymbol}
|
||||||
/>
|
onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
||||||
))}
|
handleFieldChange(e, field)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
|
||||||
<footer className={styles.actions}>
|
<footer className={styles.actions}>
|
||||||
<Button
|
<Button
|
||||||
|
@ -36,6 +36,7 @@ const contentQuery = graphql`
|
|||||||
label
|
label
|
||||||
help
|
help
|
||||||
type
|
type
|
||||||
|
min
|
||||||
required
|
required
|
||||||
sortOptions
|
sortOptions
|
||||||
options
|
options
|
||||||
@ -60,7 +61,7 @@ export default function Edit({
|
|||||||
const { debug } = useUserPreferences()
|
const { debug } = useUserPreferences()
|
||||||
const { accountId } = useWeb3()
|
const { accountId } = useWeb3()
|
||||||
const { ocean } = useOcean()
|
const { ocean } = useOcean()
|
||||||
const { metadata, ddo, refreshDdo } = useAsset()
|
const { metadata, ddo, refreshDdo, price } = useAsset()
|
||||||
const [success, setSuccess] = useState<string>()
|
const [success, setSuccess] = useState<string>()
|
||||||
const [error, setError] = useState<string>()
|
const [error, setError] = useState<string>()
|
||||||
const [timeoutStringValue, setTimeoutStringValue] = useState<string>()
|
const [timeoutStringValue, setTimeoutStringValue] = useState<string>()
|
||||||
@ -70,6 +71,18 @@ export default function Edit({
|
|||||||
|
|
||||||
const hasFeedback = error || success
|
const hasFeedback = error || success
|
||||||
|
|
||||||
|
async function updateFixedPrice(newPrice: number) {
|
||||||
|
const setPriceResp = await ocean.fixedRateExchange.setRate(
|
||||||
|
price.address,
|
||||||
|
newPrice,
|
||||||
|
accountId
|
||||||
|
)
|
||||||
|
if (!setPriceResp) {
|
||||||
|
setError(content.form.error)
|
||||||
|
Logger.error(content.form.error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function handleSubmit(
|
async function handleSubmit(
|
||||||
values: Partial<MetadataEditForm>,
|
values: Partial<MetadataEditForm>,
|
||||||
resetForm: () => void
|
resetForm: () => void
|
||||||
@ -82,6 +95,10 @@ export default function Edit({
|
|||||||
links: typeof values.links !== 'string' ? values.links : []
|
links: typeof values.links !== 'string' ? values.links : []
|
||||||
})
|
})
|
||||||
|
|
||||||
|
price.type === 'exchange' &&
|
||||||
|
values.price !== price.value &&
|
||||||
|
(await updateFixedPrice(values.price))
|
||||||
|
|
||||||
if (!ddoEditedMetdata) {
|
if (!ddoEditedMetdata) {
|
||||||
setError(content.form.error)
|
setError(content.form.error)
|
||||||
Logger.error(content.form.error)
|
Logger.error(content.form.error)
|
||||||
@ -127,7 +144,7 @@ export default function Edit({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Formik
|
<Formik
|
||||||
initialValues={getInitialValues(metadata, timeout)}
|
initialValues={getInitialValues(metadata, timeout, price.value)}
|
||||||
validationSchema={validationSchema}
|
validationSchema={validationSchema}
|
||||||
onSubmit={async (values, { resetForm }) => {
|
onSubmit={async (values, { resetForm }) => {
|
||||||
// move user's focus to top of screen
|
// move user's focus to top of screen
|
||||||
@ -160,6 +177,7 @@ export default function Edit({
|
|||||||
setShowEdit={setShowEdit}
|
setShowEdit={setShowEdit}
|
||||||
setTimeoutStringValue={setTimeoutStringValue}
|
setTimeoutStringValue={setTimeoutStringValue}
|
||||||
values={initialValues}
|
values={initialValues}
|
||||||
|
showPrice={price.type === 'exchange'}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<aside>
|
<aside>
|
||||||
|
@ -174,7 +174,7 @@ export default function Add({
|
|||||||
) : (
|
) : (
|
||||||
<Alert
|
<Alert
|
||||||
className={styles.warning}
|
className={styles.warning}
|
||||||
text={content.warning.main}
|
text={content.warning}
|
||||||
state="info"
|
state="info"
|
||||||
action={{
|
action={{
|
||||||
name: 'I understand',
|
name: 'I understand',
|
||||||
|
@ -21,6 +21,7 @@ import UserLiquidity from '../../../atoms/UserLiquidity'
|
|||||||
import InputElement from '../../../atoms/Input/InputElement'
|
import InputElement from '../../../atoms/Input/InputElement'
|
||||||
import { useOcean } from '../../../../providers/Ocean'
|
import { useOcean } from '../../../../providers/Ocean'
|
||||||
import { useWeb3 } from '../../../../providers/Web3'
|
import { useWeb3 } from '../../../../providers/Web3'
|
||||||
|
import Decimal from 'decimal.js'
|
||||||
|
|
||||||
const contentQuery = graphql`
|
const contentQuery = graphql`
|
||||||
query PoolRemoveQuery {
|
query PoolRemoveQuery {
|
||||||
@ -155,14 +156,6 @@ export default function Remove({
|
|||||||
totalPoolTokens
|
totalPoolTokens
|
||||||
])
|
])
|
||||||
|
|
||||||
async function calculateAmountOfOceansRemoved(amountPoolShares: string) {
|
|
||||||
const oceanAmount = await ocean.pool.getOceanRemovedforPoolShares(
|
|
||||||
poolAddress,
|
|
||||||
amountPoolShares
|
|
||||||
)
|
|
||||||
setAmountOcean(oceanAmount)
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const minOceanAmount =
|
const minOceanAmount =
|
||||||
(Number(amountOcean) * (100 - Number(slippage))) / 100
|
(Number(amountOcean) * (100 - Number(slippage))) / 100
|
||||||
@ -177,19 +170,24 @@ export default function Remove({
|
|||||||
setAmountPercent(e.target.value)
|
setAmountPercent(e.target.value)
|
||||||
if (!poolTokens) return
|
if (!poolTokens) return
|
||||||
|
|
||||||
const amountPoolShares = (Number(e.target.value) / 100) * Number(poolTokens)
|
const amountPoolShares = new Decimal(e.target.value)
|
||||||
|
.dividedBy(100)
|
||||||
|
.mul(new Decimal(poolTokens))
|
||||||
|
.toPrecision(18) // in some cases the returned value contain more than 18 digits which break conversion to wei
|
||||||
|
|
||||||
setAmountPoolShares(`${amountPoolShares}`)
|
setAmountPoolShares(`${amountPoolShares}`)
|
||||||
calculateAmountOfOceansRemoved(`${amountPoolShares}`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleMaxButton(e: ChangeEvent<HTMLInputElement>) {
|
function handleMaxButton(e: ChangeEvent<HTMLInputElement>) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
setAmountPercent(amountMaxPercent)
|
setAmountPercent(amountMaxPercent)
|
||||||
|
|
||||||
const amountPoolShares =
|
const amountPoolShares = new Decimal(amountMaxPercent)
|
||||||
(Number(amountMaxPercent) / 100) * Number(poolTokens)
|
.dividedBy(100)
|
||||||
|
.mul(new Decimal(poolTokens))
|
||||||
|
.toPrecision(18)
|
||||||
|
|
||||||
setAmountPoolShares(`${amountPoolShares}`)
|
setAmountPoolShares(`${amountPoolShares}`)
|
||||||
calculateAmountOfOceansRemoved(`${amountPoolShares}`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleAdvancedButton(e: FormEvent<HTMLButtonElement>) {
|
function handleAdvancedButton(e: FormEvent<HTMLButtonElement>) {
|
||||||
|
@ -44,6 +44,7 @@ const poolLiquidityQuery = gql`
|
|||||||
id
|
id
|
||||||
totalShares
|
totalShares
|
||||||
swapFee
|
swapFee
|
||||||
|
spotPrice
|
||||||
tokens {
|
tokens {
|
||||||
tokenAddress
|
tokenAddress
|
||||||
balance
|
balance
|
||||||
@ -141,7 +142,8 @@ export default function Pool(): ReactElement {
|
|||||||
setCreatorLiquidity(creatorLiquidity)
|
setCreatorLiquidity(creatorLiquidity)
|
||||||
|
|
||||||
const totalCreatorLiquidityInOcean =
|
const totalCreatorLiquidityInOcean =
|
||||||
creatorLiquidity?.ocean + creatorLiquidity?.datatoken * price?.value
|
creatorLiquidity?.ocean +
|
||||||
|
creatorLiquidity?.datatoken * dataLiquidity.pool.spotPrice
|
||||||
setCreatorTotalLiquidityInOcean(totalCreatorLiquidityInOcean)
|
setCreatorTotalLiquidityInOcean(totalCreatorLiquidityInOcean)
|
||||||
const creatorPoolShare =
|
const creatorPoolShare =
|
||||||
price?.ocean &&
|
price?.ocean &&
|
||||||
@ -250,7 +252,7 @@ export default function Pool(): ReactElement {
|
|||||||
<ExplorerLink
|
<ExplorerLink
|
||||||
networkId={networkId}
|
networkId={networkId}
|
||||||
path={
|
path={
|
||||||
networkId === 137
|
networkId === 137 || networkId === 1287
|
||||||
? `tokens/${ddo.dataToken}`
|
? `tokens/${ddo.dataToken}`
|
||||||
: `token/${ddo.dataToken}`
|
: `token/${ddo.dataToken}`
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
.bookmark {
|
.bookmark {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -10px;
|
top: -10px;
|
||||||
right: calc(var(--spacer) / 4);
|
right: calc(var(--spacer) / 8);
|
||||||
appearance: none;
|
appearance: none;
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
|
@ -4,12 +4,30 @@
|
|||||||
font-size: var(--font-size-small);
|
font-size: var(--font-size-small);
|
||||||
}
|
}
|
||||||
|
|
||||||
.meta p {
|
.asset {
|
||||||
margin-bottom: 0;
|
margin-left: -2rem;
|
||||||
|
margin-right: -2rem;
|
||||||
|
padding-left: 2rem;
|
||||||
|
padding-right: 3rem;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
margin-bottom: calc(var(--spacer) / 1.5);
|
||||||
|
padding-bottom: calc(var(--spacer) / 1.75);
|
||||||
}
|
}
|
||||||
|
|
||||||
.published {
|
@media (min-width: 40rem) {
|
||||||
margin-top: calc(var(--spacer) / 2);
|
.asset {
|
||||||
|
margin-top: -0.65rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.assetType {
|
||||||
|
display: inline-block;
|
||||||
|
border-right: 1px solid var(--border-color);
|
||||||
|
padding-right: calc(var(--spacer) / 3.5);
|
||||||
|
margin-right: calc(var(--spacer) / 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.byline {
|
||||||
font-size: var(--font-size-small);
|
font-size: var(--font-size-small);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,21 +15,25 @@ export default function MetaMain(): ReactElement {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<aside className={styles.meta}>
|
<aside className={styles.meta}>
|
||||||
<AssetType type={type} accessType={accessType} />
|
<header className={styles.asset}>
|
||||||
<p>
|
<AssetType
|
||||||
|
type={type}
|
||||||
|
accessType={accessType}
|
||||||
|
className={styles.assetType}
|
||||||
|
/>
|
||||||
<ExplorerLink
|
<ExplorerLink
|
||||||
networkId={networkId}
|
networkId={networkId}
|
||||||
path={
|
path={
|
||||||
networkId === 137
|
networkId === 137 || networkId === 1287
|
||||||
? `tokens/${ddo?.dataToken}`
|
? `tokens/${ddo?.dataToken}`
|
||||||
: `token/${ddo?.dataToken}`
|
: `token/${ddo?.dataToken}`
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{`${ddo?.dataTokenInfo.name} — ${ddo?.dataTokenInfo.symbol}`}
|
{`${ddo?.dataTokenInfo.name} — ${ddo?.dataTokenInfo.symbol}`}
|
||||||
</ExplorerLink>
|
</ExplorerLink>
|
||||||
</p>
|
</header>
|
||||||
|
|
||||||
<div className={styles.published}>
|
<div className={styles.byline}>
|
||||||
Published By <Publisher account={owner} />
|
Published By <Publisher account={owner} />
|
||||||
<p>
|
<p>
|
||||||
<Time date={ddo?.created} relative />
|
<Time date={ddo?.created} relative />
|
||||||
|
@ -48,14 +48,16 @@ export default function AssetContent(props: AssetContentProps): ReactElement {
|
|||||||
const [showPricing, setShowPricing] = useState(false)
|
const [showPricing, setShowPricing] = useState(false)
|
||||||
const [showEdit, setShowEdit] = useState<boolean>()
|
const [showEdit, setShowEdit] = useState<boolean>()
|
||||||
const [showEditCompute, setShowEditCompute] = useState<boolean>()
|
const [showEditCompute, setShowEditCompute] = useState<boolean>()
|
||||||
const { ddo, price, metadata } = useAsset()
|
const [isOwner, setIsOwner] = useState(false)
|
||||||
|
const { ddo, price, metadata, type } = useAsset()
|
||||||
const isOwner = accountId === owner
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!price) return
|
if (!accountId || !owner) return
|
||||||
|
|
||||||
|
const isOwner = accountId.toLowerCase() === owner.toLowerCase()
|
||||||
|
setIsOwner(isOwner)
|
||||||
setShowPricing(isOwner && price.type === '')
|
setShowPricing(isOwner && price.type === '')
|
||||||
}, [isOwner, price])
|
}, [accountId, price, owner])
|
||||||
|
|
||||||
function handleEditButton() {
|
function handleEditButton() {
|
||||||
// move user's focus to top of screen
|
// move user's focus to top of screen
|
||||||
@ -101,7 +103,7 @@ export default function AssetContent(props: AssetContentProps): ReactElement {
|
|||||||
<Button style="text" size="small" onClick={handleEditButton}>
|
<Button style="text" size="small" onClick={handleEditButton}>
|
||||||
Edit Metadata
|
Edit Metadata
|
||||||
</Button>
|
</Button>
|
||||||
{ddo.findServiceByType('compute') && (
|
{ddo.findServiceByType('compute') && type === 'dataset' && (
|
||||||
<>
|
<>
|
||||||
<span className={styles.separator}>|</span>
|
<span className={styles.separator}>|</span>
|
||||||
<Button
|
<Button
|
||||||
|
@ -2,3 +2,7 @@
|
|||||||
composes: asset from './Details.module.css';
|
composes: asset from './Details.module.css';
|
||||||
border-bottom-left-radius: var(--border-radius) !important;
|
border-bottom-left-radius: var(--border-radius) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.help {
|
||||||
|
margin-top: calc(var(--spacer) / 3);
|
||||||
|
}
|
||||||
|
@ -6,12 +6,33 @@ import { ListItem } from '../../../atoms/Lists'
|
|||||||
import Button from '../../../atoms/Button'
|
import Button from '../../../atoms/Button'
|
||||||
import { useOcean } from '../../../../providers/Ocean'
|
import { useOcean } from '../../../../providers/Ocean'
|
||||||
import styles from './Results.module.css'
|
import styles from './Results.module.css'
|
||||||
|
import FormHelp from '../../../atoms/Input/Help'
|
||||||
|
import { graphql, useStaticQuery } from 'gatsby'
|
||||||
|
|
||||||
|
export const contentQuery = graphql`
|
||||||
|
query HistoryPageComputeResultsQuery {
|
||||||
|
content: allFile(filter: { relativePath: { eq: "pages/history.json" } }) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
childPagesJson {
|
||||||
|
compute {
|
||||||
|
storage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
export default function Results({
|
export default function Results({
|
||||||
job
|
job
|
||||||
}: {
|
}: {
|
||||||
job: ComputeJobMetaData
|
job: ComputeJobMetaData
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
|
const data = useStaticQuery(contentQuery)
|
||||||
|
const content = data.content.edges[0].node.childPagesJson
|
||||||
|
|
||||||
const { ocean, account } = useOcean()
|
const { ocean, account } = useOcean()
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
const [hasFetched, setHasFetched] = useState(false)
|
const [hasFetched, setHasFetched] = useState(false)
|
||||||
@ -85,6 +106,7 @@ export default function Results({
|
|||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
<FormHelp className={styles.help}>{content.compute.storage}</FormHelp>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -62,12 +62,11 @@ export default function FormPublish(): ReactElement {
|
|||||||
const [selectedDockerImage, setSelectedDockerImage] = useState<string>(
|
const [selectedDockerImage, setSelectedDockerImage] = useState<string>(
|
||||||
initialValues.dockerImage
|
initialValues.dockerImage
|
||||||
)
|
)
|
||||||
|
|
||||||
// reset form validation on every mount
|
// reset form validation on every mount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setErrors({})
|
setErrors({})
|
||||||
setTouched({})
|
setTouched({})
|
||||||
|
|
||||||
// setSubmitting(false)
|
|
||||||
}, [setErrors, setTouched])
|
}, [setErrors, setTouched])
|
||||||
|
|
||||||
function handleImageSelectChange(imageSelected: string) {
|
function handleImageSelectChange(imageSelected: string) {
|
||||||
|
@ -67,8 +67,11 @@ export default function FormPublish(): ReactElement {
|
|||||||
e: ChangeEvent<HTMLInputElement>,
|
e: ChangeEvent<HTMLInputElement>,
|
||||||
field: FormFieldProps
|
field: FormFieldProps
|
||||||
) {
|
) {
|
||||||
|
const value =
|
||||||
|
field.type === 'terms' ? !JSON.parse(e.target.value) : e.target.value
|
||||||
|
|
||||||
validateField(field.name)
|
validateField(field.name)
|
||||||
setFieldValue(field.name, e.target.value)
|
setFieldValue(field.name, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
const resetFormAndClearStorage = (e: FormEvent<Element>) => {
|
const resetFormAndClearStorage = (e: FormEvent<Element>) => {
|
||||||
|
@ -95,9 +95,22 @@ export default function PublishPage({
|
|||||||
const [publishType, setPublishType] = useState<MetadataMain['type']>(
|
const [publishType, setPublishType] = useState<MetadataMain['type']>(
|
||||||
'dataset'
|
'dataset'
|
||||||
)
|
)
|
||||||
|
|
||||||
const hasFeedback = isLoading || error || success
|
const hasFeedback = isLoading || error || success
|
||||||
|
|
||||||
|
const emptyAlgoDT = Object.values(algoInitialValues.dataTokenOptions).every(
|
||||||
|
(value) => value === ''
|
||||||
|
)
|
||||||
|
const emptyDatasetDT = Object.values(
|
||||||
|
datasetInitialValues.dataTokenOptions
|
||||||
|
).every((value) => value === '')
|
||||||
|
|
||||||
|
if (emptyAlgoDT) {
|
||||||
|
algoInitialValues.dataTokenOptions = datasetInitialValues.dataTokenOptions
|
||||||
|
} else {
|
||||||
|
if (emptyDatasetDT)
|
||||||
|
datasetInitialValues.dataTokenOptions = algoInitialValues.dataTokenOptions
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
publishType === 'dataset'
|
publishType === 'dataset'
|
||||||
? setTitle('Publishing Data Set')
|
? setTitle('Publishing Data Set')
|
||||||
@ -160,18 +173,22 @@ export default function PublishPage({
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const metadata = transformPublishAlgorithmFormToMetadata(values)
|
const metadata = transformPublishAlgorithmFormToMetadata(values)
|
||||||
const timeout = mapTimeoutStringToSeconds(values.timeout)
|
const timeout = mapTimeoutStringToSeconds(values.timeout)
|
||||||
const validDockerImage =
|
|
||||||
values.dockerImage === 'custom image'
|
// TODO: put back check once #572 is resolved
|
||||||
? await validateDockerImage(values.image, values.containerTag)
|
// https://github.com/oceanprotocol/market/issues/572
|
||||||
: true
|
const validDockerImage = true
|
||||||
|
// const validDockerImage =
|
||||||
|
// values.dockerImage === 'custom image'
|
||||||
|
// ? await validateDockerImage(values.image, values.containerTag)
|
||||||
|
// : true
|
||||||
try {
|
try {
|
||||||
if (validDockerImage) {
|
if (validDockerImage) {
|
||||||
Logger.log('Publish Algorithm with ', metadata)
|
Logger.log('Publish algorithm with ', metadata, values.dataTokenOptions)
|
||||||
|
|
||||||
const ddo = await publish(
|
const ddo = await publish(
|
||||||
(metadata as unknown) as Metadata,
|
(metadata as unknown) as Metadata,
|
||||||
values.algorithmPrivacy === true ? 'compute' : 'access',
|
values.algorithmPrivacy === true ? 'compute' : 'access',
|
||||||
undefined,
|
values.dataTokenOptions,
|
||||||
timeout
|
timeout
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -248,7 +265,9 @@ export default function PublishPage({
|
|||||||
loading={publishStepText}
|
loading={publishStepText}
|
||||||
setError={setError}
|
setError={setError}
|
||||||
successAction={{
|
successAction={{
|
||||||
name: 'Go to data set →',
|
name: `Go to ${
|
||||||
|
publishType === 'dataset' ? 'data set' : 'algorithm'
|
||||||
|
} →`,
|
||||||
to: `/asset/${did}`
|
to: `/asset/${did}`
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
@ -1,160 +0,0 @@
|
|||||||
import { useState } from 'react'
|
|
||||||
import { Logger, ServiceCompute } from '@oceanprotocol/lib'
|
|
||||||
import { MetadataAlgorithm } from '@oceanprotocol/lib/dist/node/ddo/interfaces/MetadataAlgorithm'
|
|
||||||
import {
|
|
||||||
ComputeJob,
|
|
||||||
ComputeAlgorithm
|
|
||||||
} from '@oceanprotocol/lib/dist/node/ocean/interfaces/Compute'
|
|
||||||
import { computeFeedback } from '../utils/feedback'
|
|
||||||
import { useOcean } from '../providers/Ocean'
|
|
||||||
import { useWeb3 } from '../providers/Web3'
|
|
||||||
|
|
||||||
interface ComputeValue {
|
|
||||||
entrypoint: string
|
|
||||||
image: string
|
|
||||||
tag: string
|
|
||||||
}
|
|
||||||
interface ComputeOption {
|
|
||||||
name: string
|
|
||||||
value: ComputeValue
|
|
||||||
}
|
|
||||||
|
|
||||||
const computeOptions: ComputeOption[] = [
|
|
||||||
{
|
|
||||||
name: 'nodejs',
|
|
||||||
value: {
|
|
||||||
entrypoint: 'node $ALGO',
|
|
||||||
image: 'node',
|
|
||||||
tag: '10'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'python3.7',
|
|
||||||
value: {
|
|
||||||
entrypoint: 'python $ALGO',
|
|
||||||
image: 'oceanprotocol/algo_dockers',
|
|
||||||
tag: 'python-panda'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
interface UseCompute {
|
|
||||||
compute: (
|
|
||||||
did: string,
|
|
||||||
computeService: ServiceCompute,
|
|
||||||
dataTokenAddress: string,
|
|
||||||
algorithmRawCode: string,
|
|
||||||
computeContainer: ComputeValue,
|
|
||||||
marketFeeAddress?: string,
|
|
||||||
orderId?: string
|
|
||||||
) => Promise<ComputeJob | void>
|
|
||||||
computeStep?: number
|
|
||||||
computeStepText?: string
|
|
||||||
computeError?: string
|
|
||||||
isLoading: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
const rawAlgorithmMeta: MetadataAlgorithm = {
|
|
||||||
rawcode: `console.log('Hello world'!)`,
|
|
||||||
format: 'docker-image',
|
|
||||||
version: '0.1',
|
|
||||||
container: {
|
|
||||||
entrypoint: '',
|
|
||||||
image: '',
|
|
||||||
tag: ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function useCompute(): UseCompute {
|
|
||||||
const { accountId } = useWeb3()
|
|
||||||
const { ocean, account } = useOcean()
|
|
||||||
const [computeStep, setComputeStep] = useState<number | undefined>()
|
|
||||||
const [computeStepText, setComputeStepText] = useState<string | undefined>()
|
|
||||||
const [computeError, setComputeError] = useState<string | undefined>()
|
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
|
||||||
|
|
||||||
function setStep(index?: number) {
|
|
||||||
if (!index) {
|
|
||||||
setComputeStep(undefined)
|
|
||||||
setComputeStepText(undefined)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
setComputeStep(index)
|
|
||||||
setComputeStepText(computeFeedback[index])
|
|
||||||
}
|
|
||||||
|
|
||||||
async function compute(
|
|
||||||
did: string,
|
|
||||||
computeService: ServiceCompute,
|
|
||||||
dataTokenAddress: string,
|
|
||||||
algorithmRawCode: string,
|
|
||||||
computeContainer: ComputeValue,
|
|
||||||
marketFeeAddress?: string,
|
|
||||||
orderId?: string
|
|
||||||
): Promise<ComputeJob | void> {
|
|
||||||
if (!ocean || !account) return
|
|
||||||
setComputeError(undefined)
|
|
||||||
try {
|
|
||||||
setIsLoading(true)
|
|
||||||
setStep(0)
|
|
||||||
rawAlgorithmMeta.container = computeContainer
|
|
||||||
rawAlgorithmMeta.rawcode = algorithmRawCode
|
|
||||||
const computeAlgorithm: ComputeAlgorithm = {
|
|
||||||
meta: rawAlgorithmMeta
|
|
||||||
}
|
|
||||||
const output = {}
|
|
||||||
if (!orderId) {
|
|
||||||
const userOwnedTokens = await ocean.accounts.getTokenBalance(
|
|
||||||
dataTokenAddress,
|
|
||||||
account
|
|
||||||
)
|
|
||||||
if (parseFloat(userOwnedTokens) < 1) {
|
|
||||||
setComputeError('Not enough datatokens')
|
|
||||||
} else {
|
|
||||||
Logger.log(
|
|
||||||
'compute order',
|
|
||||||
accountId,
|
|
||||||
did,
|
|
||||||
computeService,
|
|
||||||
rawAlgorithmMeta,
|
|
||||||
marketFeeAddress
|
|
||||||
)
|
|
||||||
orderId = await ocean.compute.orderAsset(
|
|
||||||
accountId,
|
|
||||||
did,
|
|
||||||
computeService.index,
|
|
||||||
computeAlgorithm,
|
|
||||||
marketFeeAddress
|
|
||||||
)
|
|
||||||
setStep(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setStep(2)
|
|
||||||
if (orderId) {
|
|
||||||
const response = await ocean.compute.start(
|
|
||||||
did,
|
|
||||||
orderId,
|
|
||||||
dataTokenAddress,
|
|
||||||
account,
|
|
||||||
computeAlgorithm,
|
|
||||||
output,
|
|
||||||
`${computeService.index}`,
|
|
||||||
computeService.type
|
|
||||||
)
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
Logger.error(error)
|
|
||||||
setComputeError(error.message)
|
|
||||||
} finally {
|
|
||||||
setStep(undefined)
|
|
||||||
setIsLoading(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return { compute, computeStep, computeStepText, computeError, isLoading }
|
|
||||||
}
|
|
||||||
|
|
||||||
export { useCompute, UseCompute, ComputeValue, ComputeOption, computeOptions }
|
|
||||||
export default UseCompute
|
|
@ -77,6 +77,7 @@ export function useGraphSyncStatus(): UseGraphSyncStatus {
|
|||||||
// Get and set subgraph block
|
// Get and set subgraph block
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!config || !config.subgraphUri) return
|
if (!config || !config.subgraphUri) return
|
||||||
|
|
||||||
async function initBlockSubgraph() {
|
async function initBlockSubgraph() {
|
||||||
setSubgraphLoading(true)
|
setSubgraphLoading(true)
|
||||||
const blockGraph = await getBlockSubgraph(config.subgraphUri)
|
const blockGraph = await getBlockSubgraph(config.subgraphUri)
|
||||||
@ -98,7 +99,7 @@ export function useGraphSyncStatus(): UseGraphSyncStatus {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
setIsGraphSynced(true)
|
setIsGraphSynced(true)
|
||||||
}, [blockGraph, blockHead])
|
}, [blockGraph, blockHead, web3Loading, subgraphLoading])
|
||||||
|
|
||||||
return { blockHead, blockGraph, isGraphSynced }
|
return { blockHead, blockGraph, isGraphSynced }
|
||||||
}
|
}
|
||||||
|
@ -82,36 +82,7 @@ function usePublish(): UsePublish {
|
|||||||
}
|
}
|
||||||
case 'compute': {
|
case 'compute': {
|
||||||
if (!timeout) timeout = 3600
|
if (!timeout) timeout = 3600
|
||||||
const cluster = ocean.compute.createClusterAttributes(
|
const provider = {}
|
||||||
'Kubernetes',
|
|
||||||
'http://10.0.0.17/xxx'
|
|
||||||
)
|
|
||||||
const servers = [
|
|
||||||
ocean.compute.createServerAttributes(
|
|
||||||
'1',
|
|
||||||
'xlsize',
|
|
||||||
'50',
|
|
||||||
'16',
|
|
||||||
'0',
|
|
||||||
'128gb',
|
|
||||||
'160gb',
|
|
||||||
timeout
|
|
||||||
)
|
|
||||||
]
|
|
||||||
const containers = [
|
|
||||||
ocean.compute.createContainerAttributes(
|
|
||||||
'tensorflow/tensorflow',
|
|
||||||
'latest',
|
|
||||||
'sha256:cb57ecfa6ebbefd8ffc7f75c0f00e57a7fa739578a429b6f72a0df19315deadc'
|
|
||||||
)
|
|
||||||
]
|
|
||||||
const provider = ocean.compute.createProviderAttributes(
|
|
||||||
'Azure',
|
|
||||||
'Compute service with 16gb ram for each node.',
|
|
||||||
cluster,
|
|
||||||
containers,
|
|
||||||
servers
|
|
||||||
)
|
|
||||||
const origComputePrivacy: ServiceComputePrivacy = {
|
const origComputePrivacy: ServiceComputePrivacy = {
|
||||||
allowRawAlgorithm: false,
|
allowRawAlgorithm: false,
|
||||||
allowNetworkAccess: false,
|
allowNetworkAccess: false,
|
||||||
|
@ -11,6 +11,12 @@ export const validationSchema: Yup.SchemaOf<MetadataPublishFormAlgorithm> = Yup.
|
|||||||
description: Yup.string().min(10).required('Required'),
|
description: Yup.string().min(10).required('Required'),
|
||||||
files: Yup.array<FileMetadata>().required('Required').nullable(),
|
files: Yup.array<FileMetadata>().required('Required').nullable(),
|
||||||
timeout: Yup.string().required('Required'),
|
timeout: Yup.string().required('Required'),
|
||||||
|
dataTokenOptions: Yup.object()
|
||||||
|
.shape({
|
||||||
|
name: Yup.string(),
|
||||||
|
symbol: Yup.string()
|
||||||
|
})
|
||||||
|
.required('Required'),
|
||||||
dockerImage: Yup.string()
|
dockerImage: Yup.string()
|
||||||
.matches(/node:latest|python:latest|custom image/g, {
|
.matches(/node:latest|python:latest|custom image/g, {
|
||||||
excludeEmptyString: true
|
excludeEmptyString: true
|
||||||
@ -31,6 +37,10 @@ export const validationSchema: Yup.SchemaOf<MetadataPublishFormAlgorithm> = Yup.
|
|||||||
export const initialValues: Partial<MetadataPublishFormAlgorithm> = {
|
export const initialValues: Partial<MetadataPublishFormAlgorithm> = {
|
||||||
name: '',
|
name: '',
|
||||||
author: '',
|
author: '',
|
||||||
|
dataTokenOptions: {
|
||||||
|
name: '',
|
||||||
|
symbol: ''
|
||||||
|
},
|
||||||
dockerImage: 'node:latest',
|
dockerImage: 'node:latest',
|
||||||
image: 'node',
|
image: 'node',
|
||||||
containerTag: 'latest',
|
containerTag: 'latest',
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { MetadataMarket, MetadataPublishFormDataset } from '../@types/MetaData'
|
import { MetadataMarket, MetadataEditForm } from '../@types/MetaData'
|
||||||
import { secondsToString } from '../utils/metadata'
|
import { secondsToString } from '../utils/metadata'
|
||||||
import { EditableMetadataLinks } from '@oceanprotocol/lib'
|
import { EditableMetadataLinks } from '@oceanprotocol/lib'
|
||||||
import * as Yup from 'yup'
|
import * as Yup from 'yup'
|
||||||
@ -8,17 +8,20 @@ export const validationSchema = Yup.object().shape({
|
|||||||
.min(4, (param) => `Title must be at least ${param.min} characters`)
|
.min(4, (param) => `Title must be at least ${param.min} characters`)
|
||||||
.required('Required'),
|
.required('Required'),
|
||||||
description: Yup.string().required('Required').min(10),
|
description: Yup.string().required('Required').min(10),
|
||||||
|
price: Yup.number().required('Required'),
|
||||||
links: Yup.array<EditableMetadataLinks[]>().nullable(),
|
links: Yup.array<EditableMetadataLinks[]>().nullable(),
|
||||||
timeout: Yup.string().required('Required')
|
timeout: Yup.string().required('Required')
|
||||||
})
|
})
|
||||||
|
|
||||||
export function getInitialValues(
|
export function getInitialValues(
|
||||||
metadata: MetadataMarket,
|
metadata: MetadataMarket,
|
||||||
timeout: number
|
timeout: number,
|
||||||
): Partial<MetadataPublishFormDataset> {
|
price: number
|
||||||
|
): Partial<MetadataEditForm> {
|
||||||
return {
|
return {
|
||||||
name: metadata.main.name,
|
name: metadata.main.name,
|
||||||
description: metadata.additionalInformation.description,
|
description: metadata.additionalInformation.description,
|
||||||
|
price,
|
||||||
links: metadata.additionalInformation.links,
|
links: metadata.additionalInformation.links,
|
||||||
timeout: secondsToString(timeout)
|
timeout: secondsToString(timeout)
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ export default function PageGatsbySearch(props: PageProps): ReactElement {
|
|||||||
? `Published by ${accountTruncate(owner as string)}`
|
? `Published by ${accountTruncate(owner as string)}`
|
||||||
: `${
|
: `${
|
||||||
totalResults !== undefined
|
totalResults !== undefined
|
||||||
? searchValue
|
? searchValue && searchValue !== ' '
|
||||||
? totalResults === 0
|
? totalResults === 0
|
||||||
? 'No results'
|
? 'No results'
|
||||||
: totalResults +
|
: totalResults +
|
||||||
|
@ -16,7 +16,10 @@ export function getOceanConfig(
|
|||||||
): ConfigHelperConfig {
|
): ConfigHelperConfig {
|
||||||
return new ConfigHelper().getConfig(
|
return new ConfigHelper().getConfig(
|
||||||
network,
|
network,
|
||||||
network === 'polygon' || network === 137
|
network === 'polygon' ||
|
||||||
|
network === 137 ||
|
||||||
|
network === 'moonbeamalpha' ||
|
||||||
|
network === 1287
|
||||||
? undefined
|
? undefined
|
||||||
: process.env.GATSBY_INFURA_PROJECT_ID
|
: process.env.GATSBY_INFURA_PROJECT_ID
|
||||||
) as ConfigHelperConfig
|
) as ConfigHelperConfig
|
||||||
|
@ -35,7 +35,7 @@ export async function fileinfo(
|
|||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
toast.dismiss() // Remove any existing error message
|
toast.dismiss() // Remove any existing error message
|
||||||
toast.success('Great! That dataset looks good 🐳', {
|
toast.success('Great! That file looks good. 🐳', {
|
||||||
position: 'bottom-right',
|
position: 'bottom-right',
|
||||||
autoClose: 5000,
|
autoClose: 5000,
|
||||||
hideProgressBar: false,
|
hideProgressBar: false,
|
||||||
|
Loading…
Reference in New Issue
Block a user