mirror of
https://github.com/oceanprotocol/market.git
synced 2024-12-02 05:57:29 +01:00
Edit compute dataset (#417)
* WIP * created form for editing compute privacy * used editComputePrivacy method * select and update trusted algorithm * display and select multiple trusted algorithms * fixed update when trusted algorithm list not changed * code refactoring * moved separator inside condition * moved functions and interface from EditComputeDataset component * moved algorithmOptions to parent component * used AssetSelection to display algorithms * use AssetSelection to select trusted algorithms * getAlgorithmsOptions function review * review fixes * removed unused imports * merge fixes * AssetSelection style & usability tweaks * use custom radio & checkbox styles * add simple search for name & DID * spacing adjustments * copy updates, remove raw algo input, hardcode allowRawAlgorithm * copy * AssetSelection usability tweaks * make rows clickable * tweak layout, style and markup * use formik set function to update values * sorted algorithm list, added checked field * sort assetSelection list on user select * fix getAlgorithmsForAssetSelection breaking on empty responses * form debug output * another empty publisherTrustedAlgorithms fix * created separate algorithms state for the form, sort list on edit * refactor * use Formik functionality wherever possible * unify transforming form data to final data * fix form debug transformation * fix form submit, fix defaultChecked * refactor * use Formik functionality wherever possible * unify transforming form data to final data * fix form debug transformation * fix form submit, fix defaultChecked * disable assetSelection when allowAllAlgorithms is true * added loader to AssetSelection * changed allowAllAlgorithms to allowAllPublishedAlgorithms * fixed lint error * updated transformComputeFormToServiceComputePrivacy * lint fix * modify publish defaults Co-authored-by: Matthias Kretschmann <m@kretschmann.io>
This commit is contained in:
parent
2e9db9d170
commit
977a38e118
27
content/pages/editComputeDataset.json
Normal file
27
content/pages/editComputeDataset.json
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"description": "Only selected algorithms are allowed to run on this data set. Updating these settings will create an on-chain transaction you have to approve in your wallet.",
|
||||||
|
"form": {
|
||||||
|
"title": "Set allowed algorithms",
|
||||||
|
"success": "🎉 Successfully updated. 🎉",
|
||||||
|
"successAction": "Close",
|
||||||
|
"error": "Updating DDO failed.",
|
||||||
|
"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",
|
||||||
|
"label": "Selected Algorithms",
|
||||||
|
"help": "Choose one or multiple algorithms you trust to allow them to run on this data set.",
|
||||||
|
"type": "assetSelectionMultiple",
|
||||||
|
"multiple": true,
|
||||||
|
"options": [],
|
||||||
|
"sortOptions": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
8
package-lock.json
generated
8
package-lock.json
generated
@ -3625,9 +3625,9 @@
|
|||||||
"integrity": "sha512-6GrBk1jy+zxjDjh2SPra06etrqdp8CB6RaZaTq2OQpK8dA2Dq91hqCbj+6eb21MlU8bDY3/atnxax9rgPgsxkA=="
|
"integrity": "sha512-6GrBk1jy+zxjDjh2SPra06etrqdp8CB6RaZaTq2OQpK8dA2Dq91hqCbj+6eb21MlU8bDY3/atnxax9rgPgsxkA=="
|
||||||
},
|
},
|
||||||
"@oceanprotocol/lib": {
|
"@oceanprotocol/lib": {
|
||||||
"version": "0.12.0",
|
"version": "0.12.1",
|
||||||
"resolved": "https://registry.npmjs.org/@oceanprotocol/lib/-/lib-0.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/@oceanprotocol/lib/-/lib-0.12.1.tgz",
|
||||||
"integrity": "sha512-bREJhiyQ1LlFdLY0WoZbelfH27R7PLi0pY+c3TiX3fYvDShfp5NCYkq0B8Wf4FjxUxd4BMJREwRNdOS416RYVA==",
|
"integrity": "sha512-Cw4d4Di6GnL1gfZcYqemnKh1Agpc66AemIJANfbJpO08KkgiLEZhhMYsYQZzha+zQD9Jr4ZuzE/ZlYDr6S0o6w==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@ethereum-navigator/navigator": "^0.5.2",
|
"@ethereum-navigator/navigator": "^0.5.2",
|
||||||
"@oceanprotocol/contracts": "^0.5.10",
|
"@oceanprotocol/contracts": "^0.5.10",
|
||||||
@ -16410,7 +16410,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ethereumjs-abi": {
|
"ethereumjs-abi": {
|
||||||
"version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#1ce6a1d64235fabe2aaf827fd606def55693508f",
|
"version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#1a27c59c15ab1e95ee8e5c4ed6ad814c49cc439e",
|
||||||
"from": "git+https://github.com/ethereumjs/ethereumjs-abi.git",
|
"from": "git+https://github.com/ethereumjs/ethereumjs-abi.git",
|
||||||
"requires": {
|
"requires": {
|
||||||
"bn.js": "^4.11.8",
|
"bn.js": "^4.11.8",
|
||||||
|
@ -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.12.0",
|
"@oceanprotocol/lib": "^0.12.1",
|
||||||
"@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",
|
||||||
|
4
src/@types/ComputeDataset.ts
Normal file
4
src/@types/ComputeDataset.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export interface AlgorithmOption {
|
||||||
|
did: string
|
||||||
|
name: string
|
||||||
|
}
|
5
src/@types/Form.d.ts
vendored
5
src/@types/Form.d.ts
vendored
@ -1,10 +1,13 @@
|
|||||||
|
import { AssetSelectionAsset } from '../../molecules/FormFields/AssetSelection'
|
||||||
|
|
||||||
export interface FormFieldProps {
|
export interface FormFieldProps {
|
||||||
label: string
|
label: string
|
||||||
name: string
|
name: string
|
||||||
type?: string
|
type?: string
|
||||||
options?: string[]
|
options?: string[] | AssetSelectionAsset[]
|
||||||
sortOptions?: boolean
|
sortOptions?: boolean
|
||||||
required?: boolean
|
required?: boolean
|
||||||
|
multiple?: boolean
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
help?: string
|
help?: string
|
||||||
placeholder?: string
|
placeholder?: string
|
||||||
|
@ -14,13 +14,14 @@ const cx = classNames.bind(styles)
|
|||||||
|
|
||||||
const DefaultInput = ({
|
const DefaultInput = ({
|
||||||
size,
|
size,
|
||||||
|
className,
|
||||||
prefix,
|
prefix,
|
||||||
postfix,
|
postfix,
|
||||||
additionalComponent,
|
additionalComponent,
|
||||||
...props
|
...props
|
||||||
}: InputProps) => (
|
}: InputProps) => (
|
||||||
<input
|
<input
|
||||||
className={cx({ input: true, [size]: size })}
|
className={cx({ input: true, [size]: size, [className]: className })}
|
||||||
id={props.name}
|
id={props.name}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
@ -36,13 +37,14 @@ export default function InputElement({
|
|||||||
size,
|
size,
|
||||||
field,
|
field,
|
||||||
label,
|
label,
|
||||||
|
multiple,
|
||||||
|
disabled,
|
||||||
help,
|
help,
|
||||||
form,
|
form,
|
||||||
additionalComponent,
|
additionalComponent,
|
||||||
...props
|
...props
|
||||||
}: InputProps): ReactElement {
|
}: InputProps): ReactElement {
|
||||||
const styleClasses = cx({ select: true, [size]: size })
|
const styleClasses = cx({ select: true, [size]: size })
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'select': {
|
case 'select': {
|
||||||
const sortedOptions =
|
const sortedOptions =
|
||||||
@ -50,7 +52,12 @@ export default function InputElement({
|
|||||||
? options
|
? options
|
||||||
: options.sort((a: string, b: string) => a.localeCompare(b))
|
: options.sort((a: string, b: string) => a.localeCompare(b))
|
||||||
return (
|
return (
|
||||||
<select id={name} className={styleClasses} {...props}>
|
<select
|
||||||
|
id={name}
|
||||||
|
className={styleClasses}
|
||||||
|
{...props}
|
||||||
|
multiple={multiple}
|
||||||
|
>
|
||||||
{field !== undefined && field.value === '' && (
|
{field !== undefined && field.value === '' && (
|
||||||
<option value="">---</option>
|
<option value="">---</option>
|
||||||
)}
|
)}
|
||||||
@ -106,6 +113,7 @@ export default function InputElement({
|
|||||||
<AssetSelection
|
<AssetSelection
|
||||||
assets={(options as unknown) as AssetSelectionAsset[]}
|
assets={(options as unknown) as AssetSelectionAsset[]}
|
||||||
multiple
|
multiple
|
||||||
|
disabled={disabled}
|
||||||
{...field}
|
{...field}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
@ -126,6 +134,7 @@ export default function InputElement({
|
|||||||
name={name}
|
name={name}
|
||||||
type={type || 'text'}
|
type={type || 'text'}
|
||||||
size={size}
|
size={size}
|
||||||
|
disabled={disabled}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
{postfix && (
|
{postfix && (
|
||||||
@ -137,6 +146,7 @@ export default function InputElement({
|
|||||||
name={name}
|
name={name}
|
||||||
type={type || 'text'}
|
type={type || 'text'}
|
||||||
size={size}
|
size={size}
|
||||||
|
disabled={disabled}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
@ -41,6 +41,7 @@ export interface InputProps {
|
|||||||
step?: string
|
step?: string
|
||||||
defaultChecked?: boolean
|
defaultChecked?: boolean
|
||||||
size?: 'mini' | 'small' | 'large' | 'default'
|
size?: 'mini' | 'small' | 'large' | 'default'
|
||||||
|
className?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Input(props: Partial<InputProps>): ReactElement {
|
export default function Input(props: Partial<InputProps>): ReactElement {
|
||||||
|
@ -1,12 +1,26 @@
|
|||||||
.selection {
|
.selection {
|
||||||
padding: calc(var(--spacer) / 4);
|
padding: 0;
|
||||||
border: 1px solid var(--border-color);
|
border: 1px solid var(--border-color);
|
||||||
background-color: var(--background-highlight);
|
background-color: var(--background-highlight);
|
||||||
border-radius: var(--border-radius);
|
border-radius: var(--border-radius);
|
||||||
margin-bottom: calc(var(--spacer) / 2);
|
margin-bottom: calc(var(--spacer) / 2);
|
||||||
font-size: var(--font-size-small);
|
font-size: var(--font-size-small);
|
||||||
|
}
|
||||||
|
|
||||||
|
.disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
div [class*='loaderWrap'] {
|
||||||
|
margin: calc(var(--spacer) / 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll {
|
||||||
|
border-top: 1px solid var(--border-color);
|
||||||
|
margin-top: calc(var(--spacer) / 4);
|
||||||
|
min-height: 200px;
|
||||||
max-height: 300px;
|
max-height: 300px;
|
||||||
|
position: relative;
|
||||||
/* smooth overflow scrolling for pre-iOS 13 */
|
/* smooth overflow scrolling for pre-iOS 13 */
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
-webkit-overflow-scrolling: touch;
|
-webkit-overflow-scrolling: touch;
|
||||||
@ -14,44 +28,78 @@
|
|||||||
|
|
||||||
.row {
|
.row {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: center;
|
||||||
border-bottom: 1px solid var(--border-color);
|
border-bottom: 1px solid var(--border-color);
|
||||||
padding-top: calc(var(--spacer) / 4);
|
padding: calc(var(--spacer) / 3) calc(var(--spacer) / 4);
|
||||||
padding-bottom: calc(var(--spacer) / 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.row > div {
|
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: baseline;
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: calc(var(--spacer) / 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input {
|
.input {
|
||||||
|
align-self: flex-start;
|
||||||
|
min-width: 1.2rem;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
margin-right: calc(var(--spacer) / 4);
|
margin-right: calc(var(--spacer) / 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.radio {
|
||||||
|
composes: radio from '../../atoms/Input/InputElement.module.css';
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox {
|
||||||
|
composes: checkbox from '../../atoms/Input/InputElement.module.css';
|
||||||
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
font-size: var(--font-size-small);
|
font-size: var(--font-size-small);
|
||||||
margin: 0;
|
margin-top: calc(var(--spacer) / 12);
|
||||||
|
margin-bottom: calc(var(--spacer) / 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
.link {
|
.link {
|
||||||
margin-left: calc(var(--spacer) / 4);
|
display: inline-block;
|
||||||
|
margin-left: calc(var(--spacer) / 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
.link svg {
|
.link svg {
|
||||||
|
margin: 0;
|
||||||
fill: var(--color-primary);
|
fill: var(--color-primary);
|
||||||
width: 0.7em;
|
width: 0.7em;
|
||||||
height: 0.7em;
|
height: 0.7em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--spacer);
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-top: calc(var(--spacer) / 12);
|
||||||
|
}
|
||||||
|
|
||||||
.price {
|
.price {
|
||||||
display: inline-block;
|
white-space: pre;
|
||||||
font-size: var(--font-size-small) !important;
|
font-size: var(--font-size-small) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search {
|
||||||
|
margin: calc(var(--spacer) / 4);
|
||||||
|
width: calc(100% - calc(var(--spacer) / 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
.did {
|
||||||
|
padding: 0;
|
||||||
|
font-size: var(--font-size-mini);
|
||||||
|
display: block;
|
||||||
|
text-align: left;
|
||||||
|
color: var(--color-secondary);
|
||||||
|
}
|
||||||
|
@ -1,58 +1,107 @@
|
|||||||
import React from 'react'
|
import React, { ChangeEvent, useState } from 'react'
|
||||||
import Dotdotdot from 'react-dotdotdot'
|
import Dotdotdot from 'react-dotdotdot'
|
||||||
import slugify from 'slugify'
|
import slugify from 'slugify'
|
||||||
|
import classNames from 'classnames/bind'
|
||||||
import PriceUnit from '../../atoms/Price/PriceUnit'
|
import PriceUnit from '../../atoms/Price/PriceUnit'
|
||||||
import { ReactComponent as External } from '../../../images/external.svg'
|
import { ReactComponent as External } from '../../../images/external.svg'
|
||||||
import styles from './AssetSelection.module.css'
|
import styles from './AssetSelection.module.css'
|
||||||
|
import InputElement from '../../atoms/Input/InputElement'
|
||||||
|
import Loader from '../../atoms/Loader'
|
||||||
|
|
||||||
|
const cx = classNames.bind(styles)
|
||||||
|
|
||||||
export interface AssetSelectionAsset {
|
export interface AssetSelectionAsset {
|
||||||
did: string
|
did: string
|
||||||
name: string
|
name: string
|
||||||
price: string
|
price: string
|
||||||
|
checked: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function AssetSelection({
|
export default function AssetSelection({
|
||||||
assets,
|
assets,
|
||||||
multiple,
|
multiple,
|
||||||
|
disabled,
|
||||||
...props
|
...props
|
||||||
}: {
|
}: {
|
||||||
assets: AssetSelectionAsset[]
|
assets: AssetSelectionAsset[]
|
||||||
multiple?: boolean
|
multiple?: boolean
|
||||||
|
disabled?: boolean
|
||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
return (
|
const [searchValue, setSearchValue] = useState('')
|
||||||
<div className={styles.selection}>
|
|
||||||
{assets.map((asset: AssetSelectionAsset) => (
|
|
||||||
<div className={styles.row} key={asset.did}>
|
|
||||||
<input
|
|
||||||
id={slugify(asset.name)}
|
|
||||||
type={multiple ? 'checkbox' : 'radio'}
|
|
||||||
value={asset.did}
|
|
||||||
className={styles.input}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
<div className={styles.content}>
|
|
||||||
<label
|
|
||||||
className={styles.label}
|
|
||||||
htmlFor={slugify(asset.name)}
|
|
||||||
title={asset.name}
|
|
||||||
>
|
|
||||||
<Dotdotdot clamp={1} tagName="h3" className={styles.title}>
|
|
||||||
{asset.name}
|
|
||||||
</Dotdotdot>
|
|
||||||
<PriceUnit price={asset.price} small className={styles.price} />
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<a
|
const styleClassesInput = cx({
|
||||||
className={styles.link}
|
input: true,
|
||||||
href={`/asset/${asset.did}`}
|
[styles.checkbox]: multiple,
|
||||||
target="_blank"
|
[styles.radio]: !multiple
|
||||||
rel="noreferrer"
|
})
|
||||||
>
|
|
||||||
<External />
|
function handleSearchInput(e: ChangeEvent<HTMLInputElement>) {
|
||||||
</a>
|
setSearchValue(e.target.value)
|
||||||
</div>
|
}
|
||||||
</div>
|
|
||||||
))}
|
return (
|
||||||
|
<div className={`${styles.selection} ${disabled ? styles.disabled : ''}`}>
|
||||||
|
<InputElement
|
||||||
|
type="search"
|
||||||
|
name="search"
|
||||||
|
size="small"
|
||||||
|
placeholder="Search by title or DID..."
|
||||||
|
value={searchValue}
|
||||||
|
onChange={handleSearchInput}
|
||||||
|
className={styles.search}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
<div className={styles.scroll}>
|
||||||
|
{assets ? (
|
||||||
|
assets
|
||||||
|
.filter((asset: AssetSelectionAsset) =>
|
||||||
|
searchValue !== ''
|
||||||
|
? asset.name.toLowerCase().includes(searchValue) ||
|
||||||
|
asset.did.includes(searchValue)
|
||||||
|
: asset
|
||||||
|
)
|
||||||
|
.map((asset: AssetSelectionAsset) => (
|
||||||
|
<div className={styles.row} key={asset.did}>
|
||||||
|
<input
|
||||||
|
id={slugify(asset.did)}
|
||||||
|
type={multiple ? 'checkbox' : 'radio'}
|
||||||
|
className={styleClassesInput}
|
||||||
|
defaultChecked={asset.checked}
|
||||||
|
{...props}
|
||||||
|
disabled={disabled}
|
||||||
|
value={asset.did}
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
className={styles.label}
|
||||||
|
htmlFor={slugify(asset.did)}
|
||||||
|
title={asset.name}
|
||||||
|
>
|
||||||
|
<h3 className={styles.title}>
|
||||||
|
<Dotdotdot clamp={1} tagName="span">
|
||||||
|
{asset.name}
|
||||||
|
</Dotdotdot>
|
||||||
|
<a
|
||||||
|
className={styles.link}
|
||||||
|
href={`/asset/${asset.did}`}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
<External />
|
||||||
|
</a>
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<Dotdotdot clamp={1} tagName="code" className={styles.did}>
|
||||||
|
{asset.did}
|
||||||
|
</Dotdotdot>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<PriceUnit price={asset.price} small className={styles.price} />
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<Loader />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
import { DDO, ServiceComputePrivacy } from '@oceanprotocol/lib'
|
||||||
|
import React, { ReactElement, useEffect, useState } from 'react'
|
||||||
|
import { ComputePrivacyForm } from '../../../../models/FormEditComputeDataset'
|
||||||
|
import { useOcean } from '../../../../providers/Ocean'
|
||||||
|
import { transformComputeFormToServiceComputePrivacy } from '../../../../utils/compute'
|
||||||
|
import DebugOutput from '../../../atoms/DebugOutput'
|
||||||
|
|
||||||
|
export default function DebugEditCompute({
|
||||||
|
values,
|
||||||
|
ddo
|
||||||
|
}: {
|
||||||
|
values: ComputePrivacyForm
|
||||||
|
ddo: DDO
|
||||||
|
}): ReactElement {
|
||||||
|
const { ocean } = useOcean()
|
||||||
|
const [
|
||||||
|
formTransformed,
|
||||||
|
setFormTransformed
|
||||||
|
] = useState<ServiceComputePrivacy>()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!ocean) return
|
||||||
|
|
||||||
|
async function transformValues() {
|
||||||
|
const privacy = await transformComputeFormToServiceComputePrivacy(
|
||||||
|
values,
|
||||||
|
ocean
|
||||||
|
)
|
||||||
|
setFormTransformed(privacy)
|
||||||
|
}
|
||||||
|
transformValues()
|
||||||
|
}, [values, ddo, ocean])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DebugOutput title="Collected Form Values" output={values} />
|
||||||
|
<DebugOutput title="Transformed Form Values" output={formTransformed} />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,161 @@
|
|||||||
|
import { useOcean } from '../../../../providers/Ocean'
|
||||||
|
import { useWeb3 } from '../../../../providers/Web3'
|
||||||
|
import { Formik } from 'formik'
|
||||||
|
import React, { ReactElement, useState } from 'react'
|
||||||
|
import {
|
||||||
|
validationSchema,
|
||||||
|
getInitialValues,
|
||||||
|
ComputePrivacyForm
|
||||||
|
} from '../../../../models/FormEditComputeDataset'
|
||||||
|
import { useAsset } from '../../../../providers/Asset'
|
||||||
|
import FormEditComputeDataset from './FormEditComputeDataset'
|
||||||
|
import { Logger, ServiceComputePrivacy } from '@oceanprotocol/lib'
|
||||||
|
import MetadataFeedback from '../../../molecules/MetadataFeedback'
|
||||||
|
import { graphql, useStaticQuery } from 'gatsby'
|
||||||
|
import { useUserPreferences } from '../../../../providers/UserPreferences'
|
||||||
|
import DebugEditCompute from './DebugEditCompute'
|
||||||
|
import styles from './index.module.css'
|
||||||
|
import { transformComputeFormToServiceComputePrivacy } from '../../../../utils/compute'
|
||||||
|
|
||||||
|
const contentQuery = graphql`
|
||||||
|
query EditComputeDataQuery {
|
||||||
|
content: allFile(
|
||||||
|
filter: { relativePath: { eq: "pages/editComputeDataset.json" } }
|
||||||
|
) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
childPagesJson {
|
||||||
|
description
|
||||||
|
form {
|
||||||
|
title
|
||||||
|
success
|
||||||
|
successAction
|
||||||
|
error
|
||||||
|
data {
|
||||||
|
name
|
||||||
|
placeholder
|
||||||
|
label
|
||||||
|
help
|
||||||
|
type
|
||||||
|
required
|
||||||
|
sortOptions
|
||||||
|
options
|
||||||
|
multiple
|
||||||
|
rows
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export default function EditComputeDataset({
|
||||||
|
setShowEdit
|
||||||
|
}: {
|
||||||
|
setShowEdit: (show: boolean) => void
|
||||||
|
}): ReactElement {
|
||||||
|
const data = useStaticQuery(contentQuery)
|
||||||
|
const content = data.content.edges[0].node.childPagesJson
|
||||||
|
|
||||||
|
const { debug } = useUserPreferences()
|
||||||
|
const { ocean } = useOcean()
|
||||||
|
const { accountId } = useWeb3()
|
||||||
|
const { ddo, refreshDdo } = useAsset()
|
||||||
|
const [success, setSuccess] = useState<string>()
|
||||||
|
const [error, setError] = useState<string>()
|
||||||
|
|
||||||
|
const hasFeedback = error || success
|
||||||
|
|
||||||
|
async function handleSubmit(
|
||||||
|
values: ComputePrivacyForm,
|
||||||
|
resetForm: () => void
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const privacy = await transformComputeFormToServiceComputePrivacy(
|
||||||
|
values,
|
||||||
|
ocean
|
||||||
|
)
|
||||||
|
|
||||||
|
const ddoEditedComputePrivacy = await ocean.compute.editComputePrivacy(
|
||||||
|
ddo,
|
||||||
|
1,
|
||||||
|
privacy as ServiceComputePrivacy
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!ddoEditedComputePrivacy) {
|
||||||
|
setError(content.form.error)
|
||||||
|
Logger.error(content.form.error)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const storedddo = await ocean.assets.updateMetadata(
|
||||||
|
ddoEditedComputePrivacy,
|
||||||
|
accountId
|
||||||
|
)
|
||||||
|
if (!storedddo) {
|
||||||
|
setError(content.form.error)
|
||||||
|
Logger.error(content.form.error)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
// Edit succeeded
|
||||||
|
setSuccess(content.form.success)
|
||||||
|
resetForm()
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
Logger.error(error.message)
|
||||||
|
setError(error.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Formik
|
||||||
|
initialValues={getInitialValues(
|
||||||
|
ddo.findServiceByType('compute').attributes.main.privacy
|
||||||
|
)}
|
||||||
|
validationSchema={validationSchema}
|
||||||
|
onSubmit={async (values, { resetForm }) => {
|
||||||
|
// move user's focus to top of screen
|
||||||
|
window.scrollTo({ top: 0, left: 0, behavior: 'smooth' })
|
||||||
|
// kick off editing
|
||||||
|
await handleSubmit(values, resetForm)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{({ values, isSubmitting }) =>
|
||||||
|
isSubmitting || hasFeedback ? (
|
||||||
|
<MetadataFeedback
|
||||||
|
title="Updating Data Set"
|
||||||
|
error={error}
|
||||||
|
success={success}
|
||||||
|
setError={setError}
|
||||||
|
successAction={{
|
||||||
|
name: content.form.successAction,
|
||||||
|
onClick: async () => {
|
||||||
|
await refreshDdo()
|
||||||
|
setShowEdit(false)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<p className={styles.description}>{content.description}</p>
|
||||||
|
<article className={styles.grid}>
|
||||||
|
<FormEditComputeDataset
|
||||||
|
title={content.form.title}
|
||||||
|
data={content.form.data}
|
||||||
|
setShowEdit={setShowEdit}
|
||||||
|
/>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
{debug === true && (
|
||||||
|
<div className={styles.grid}>
|
||||||
|
<DebugEditCompute values={values} ddo={ddo} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</Formik>
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,76 @@
|
|||||||
|
import React, { ReactElement, useEffect, useState } from 'react'
|
||||||
|
import { Field, Form, FormikContextType, useFormikContext } from 'formik'
|
||||||
|
import Button from '../../../atoms/Button'
|
||||||
|
import Input from '../../../atoms/Input'
|
||||||
|
import { useOcean } from '../../../../providers/Ocean'
|
||||||
|
import { useWeb3 } from '../../../../providers/Web3'
|
||||||
|
import { FormFieldProps } from '../../../../@types/Form'
|
||||||
|
import { AssetSelectionAsset } from '../../../molecules/FormFields/AssetSelection'
|
||||||
|
import stylesIndex from './index.module.css'
|
||||||
|
import styles from './FormEditMetadata.module.css'
|
||||||
|
import { getAlgorithmsForAssetSelection } from '../../../../utils/aquarius'
|
||||||
|
import { useAsset } from '../../../../providers/Asset'
|
||||||
|
import { ComputePrivacyForm } from '../../../../models/FormEditComputeDataset'
|
||||||
|
|
||||||
|
export default function FormEditComputeDataset({
|
||||||
|
data,
|
||||||
|
title,
|
||||||
|
setShowEdit
|
||||||
|
}: {
|
||||||
|
data: FormFieldProps[]
|
||||||
|
title: string
|
||||||
|
setShowEdit: (show: boolean) => void
|
||||||
|
}): ReactElement {
|
||||||
|
const { accountId } = useWeb3()
|
||||||
|
const { ocean, config } = useOcean()
|
||||||
|
const { ddo } = useAsset()
|
||||||
|
const {
|
||||||
|
isValid,
|
||||||
|
values
|
||||||
|
}: FormikContextType<ComputePrivacyForm> = useFormikContext()
|
||||||
|
const [allAlgorithms, setAllAlgorithms] = useState<AssetSelectionAsset[]>()
|
||||||
|
|
||||||
|
const { publisherTrustedAlgorithms } = ddo?.findServiceByType(
|
||||||
|
'compute'
|
||||||
|
).attributes.main.privacy
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getAlgorithmsForAssetSelection(
|
||||||
|
config.metadataCacheUri,
|
||||||
|
publisherTrustedAlgorithms
|
||||||
|
).then((algorithms) => {
|
||||||
|
setAllAlgorithms(algorithms)
|
||||||
|
})
|
||||||
|
}, [config.metadataCacheUri, publisherTrustedAlgorithms])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form className={styles.form}>
|
||||||
|
<h3 className={stylesIndex.title}>{title}</h3>
|
||||||
|
{data.map((field: FormFieldProps) => (
|
||||||
|
<Field
|
||||||
|
key={field.name}
|
||||||
|
{...field}
|
||||||
|
options={
|
||||||
|
field.name === 'publisherTrustedAlgorithms'
|
||||||
|
? allAlgorithms
|
||||||
|
: field.options
|
||||||
|
}
|
||||||
|
disabled={
|
||||||
|
field.name === 'publisherTrustedAlgorithms'
|
||||||
|
? values.allowAllPublishedAlgorithms
|
||||||
|
: false
|
||||||
|
}
|
||||||
|
component={Input}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
<footer className={styles.actions}>
|
||||||
|
<Button style="primary" disabled={!ocean || !accountId || !isValid}>
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
<Button style="text" onClick={() => setShowEdit(false)}>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
</footer>
|
||||||
|
</Form>
|
||||||
|
)
|
||||||
|
}
|
@ -22,3 +22,7 @@
|
|||||||
margin-left: calc(var(--spacer) / 2);
|
margin-left: calc(var(--spacer) / 2);
|
||||||
margin-right: calc(var(--spacer) / 2);
|
margin-right: calc(var(--spacer) / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
select[multiple] {
|
||||||
|
height: 130px;
|
||||||
|
}
|
||||||
|
@ -8,3 +8,14 @@
|
|||||||
margin-top: -1.5rem;
|
margin-top: -1.5rem;
|
||||||
max-width: 50rem;
|
max-width: 50rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: var(--font-size-large);
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
padding-bottom: calc(var(--spacer) / 2);
|
||||||
|
margin-top: -1rem;
|
||||||
|
margin-left: -2rem;
|
||||||
|
margin-right: -2rem;
|
||||||
|
padding-left: 2rem;
|
||||||
|
padding-right: 2rem;
|
||||||
|
}
|
||||||
|
@ -8,7 +8,7 @@ import {
|
|||||||
import { useAsset } from '../../../../providers/Asset'
|
import { useAsset } from '../../../../providers/Asset'
|
||||||
import { useUserPreferences } from '../../../../providers/UserPreferences'
|
import { useUserPreferences } from '../../../../providers/UserPreferences'
|
||||||
import { MetadataPreview } from '../../../molecules/MetadataPreview'
|
import { MetadataPreview } from '../../../molecules/MetadataPreview'
|
||||||
import Debug from './Debug'
|
import Debug from './DebugEditMetadata'
|
||||||
import Web3Feedback from '../../../molecules/Wallet/Feedback'
|
import Web3Feedback from '../../../molecules/Wallet/Feedback'
|
||||||
import FormEditMetadata from './FormEditMetadata'
|
import FormEditMetadata from './FormEditMetadata'
|
||||||
import { mapTimeoutStringToSeconds } from '../../../../utils/metadata'
|
import { mapTimeoutStringToSeconds } from '../../../../utils/metadata'
|
||||||
@ -64,6 +64,9 @@ export default function Edit({
|
|||||||
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>()
|
||||||
|
const timeout = ddo.findServiceByType('access')
|
||||||
|
? ddo.findServiceByType('access').attributes.main.timeout
|
||||||
|
: ddo.findServiceByType('compute').attributes.main.timeout
|
||||||
|
|
||||||
const hasFeedback = error || success
|
const hasFeedback = error || success
|
||||||
|
|
||||||
@ -122,10 +125,7 @@ export default function Edit({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Formik
|
<Formik
|
||||||
initialValues={getInitialValues(
|
initialValues={getInitialValues(metadata, timeout)}
|
||||||
metadata,
|
|
||||||
ddo.findServiceByType('access').attributes.main.timeout
|
|
||||||
)}
|
|
||||||
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
|
||||||
|
@ -42,3 +42,7 @@
|
|||||||
margin-left: calc(var(--spacer) / 4);
|
margin-left: calc(var(--spacer) / 4);
|
||||||
margin-right: calc(var(--spacer) / 4);
|
margin-right: calc(var(--spacer) / 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.separator {
|
||||||
|
color: var(--color-secondary);
|
||||||
|
}
|
||||||
|
@ -3,7 +3,6 @@ import { graphql, useStaticQuery } from 'gatsby'
|
|||||||
import Markdown from '../../atoms/Markdown'
|
import Markdown from '../../atoms/Markdown'
|
||||||
import MetaFull from './MetaFull'
|
import MetaFull from './MetaFull'
|
||||||
import MetaSecondary from './MetaSecondary'
|
import MetaSecondary from './MetaSecondary'
|
||||||
import styles from './index.module.css'
|
|
||||||
import AssetActions from '../AssetActions'
|
import AssetActions from '../AssetActions'
|
||||||
import { useUserPreferences } from '../../../providers/UserPreferences'
|
import { useUserPreferences } from '../../../providers/UserPreferences'
|
||||||
import Pricing from './Pricing'
|
import Pricing from './Pricing'
|
||||||
@ -12,10 +11,12 @@ import { useAsset } from '../../../providers/Asset'
|
|||||||
import Alert from '../../atoms/Alert'
|
import Alert from '../../atoms/Alert'
|
||||||
import Button from '../../atoms/Button'
|
import Button from '../../atoms/Button'
|
||||||
import Edit from '../AssetActions/Edit'
|
import Edit from '../AssetActions/Edit'
|
||||||
|
import EditComputeDataset from '../AssetActions/Edit/EditComputeDataset'
|
||||||
import DebugOutput from '../../atoms/DebugOutput'
|
import DebugOutput from '../../atoms/DebugOutput'
|
||||||
import MetaMain from './MetaMain'
|
import MetaMain from './MetaMain'
|
||||||
import EditHistory from './EditHistory'
|
import EditHistory from './EditHistory'
|
||||||
import { useWeb3 } from '../../../providers/Web3'
|
import { useWeb3 } from '../../../providers/Web3'
|
||||||
|
import styles from './index.module.css'
|
||||||
|
|
||||||
export interface AssetContentProps {
|
export interface AssetContentProps {
|
||||||
path?: string
|
path?: string
|
||||||
@ -46,7 +47,9 @@ export default function AssetContent(props: AssetContentProps): ReactElement {
|
|||||||
const { owner, isInPurgatory, purgatoryData } = useAsset()
|
const { owner, isInPurgatory, purgatoryData } = useAsset()
|
||||||
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 { ddo, price, metadata } = useAsset()
|
const { ddo, price, metadata } = useAsset()
|
||||||
|
|
||||||
const isOwner = accountId === owner
|
const isOwner = accountId === owner
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -60,8 +63,15 @@ export default function AssetContent(props: AssetContentProps): ReactElement {
|
|||||||
setShowEdit(true)
|
setShowEdit(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleEditComputeButton() {
|
||||||
|
window.scrollTo({ top: 0, left: 0, behavior: 'smooth' })
|
||||||
|
setShowEditCompute(true)
|
||||||
|
}
|
||||||
|
|
||||||
return showEdit ? (
|
return showEdit ? (
|
||||||
<Edit setShowEdit={setShowEdit} />
|
<Edit setShowEdit={setShowEdit} />
|
||||||
|
) : showEditCompute ? (
|
||||||
|
<EditComputeDataset setShowEdit={setShowEditCompute} />
|
||||||
) : (
|
) : (
|
||||||
<article className={styles.grid}>
|
<article className={styles.grid}>
|
||||||
<div>
|
<div>
|
||||||
@ -91,6 +101,18 @@ 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') && (
|
||||||
|
<>
|
||||||
|
<span className={styles.separator}>|</span>
|
||||||
|
<Button
|
||||||
|
style="text"
|
||||||
|
size="small"
|
||||||
|
onClick={handleEditComputeButton}
|
||||||
|
>
|
||||||
|
Edit Compute Settings
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
@ -113,8 +113,9 @@ function usePublish(): UsePublish {
|
|||||||
servers
|
servers
|
||||||
)
|
)
|
||||||
const origComputePrivacy: ServiceComputePrivacy = {
|
const origComputePrivacy: ServiceComputePrivacy = {
|
||||||
allowRawAlgorithm: true,
|
allowRawAlgorithm: false,
|
||||||
allowNetworkAccess: false,
|
allowNetworkAccess: false,
|
||||||
|
allowAllPublishedAlgorithms: false,
|
||||||
publisherTrustedAlgorithms: []
|
publisherTrustedAlgorithms: []
|
||||||
}
|
}
|
||||||
const computeService = ocean.compute.createComputeService(
|
const computeService = ocean.compute.createComputeService(
|
||||||
|
30
src/models/FormEditComputeDataset.ts
Normal file
30
src/models/FormEditComputeDataset.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { ServiceComputePrivacy } from '@oceanprotocol/lib'
|
||||||
|
import * as Yup from 'yup'
|
||||||
|
|
||||||
|
export interface ComputePrivacyForm {
|
||||||
|
allowAllPublishedAlgorithms: boolean
|
||||||
|
publisherTrustedAlgorithms: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const validationSchema: Yup.SchemaOf<ComputePrivacyForm> = Yup.object().shape(
|
||||||
|
{
|
||||||
|
allowAllPublishedAlgorithms: Yup.boolean().nullable(),
|
||||||
|
publisherTrustedAlgorithms: Yup.array().nullable()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export function getInitialValues(
|
||||||
|
compute: ServiceComputePrivacy
|
||||||
|
): ComputePrivacyForm {
|
||||||
|
// TODO: ocean.js needs allowAllAlgoritms setting
|
||||||
|
const { allowAllPublishedAlgorithms, publisherTrustedAlgorithms } = compute
|
||||||
|
|
||||||
|
const publisherTrustedAlgorithmsForForm = (
|
||||||
|
publisherTrustedAlgorithms || []
|
||||||
|
).map((algo) => algo.did)
|
||||||
|
|
||||||
|
return {
|
||||||
|
allowAllPublishedAlgorithms,
|
||||||
|
publisherTrustedAlgorithms: publisherTrustedAlgorithmsForForm
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,18 @@
|
|||||||
import { DDO, DID, Logger } from '@oceanprotocol/lib'
|
import {
|
||||||
|
Config,
|
||||||
|
DDO,
|
||||||
|
DID,
|
||||||
|
Logger,
|
||||||
|
publisherTrustedAlgorithm as PublisherTrustedAlgorithm
|
||||||
|
} from '@oceanprotocol/lib/'
|
||||||
import {
|
import {
|
||||||
QueryResult,
|
QueryResult,
|
||||||
SearchQuery
|
SearchQuery
|
||||||
} from '@oceanprotocol/lib/dist/node/metadatacache/MetadataCache'
|
} from '@oceanprotocol/lib/dist/node/metadatacache/MetadataCache'
|
||||||
|
import { AssetSelectionAsset } from '../components/molecules/FormFields/AssetSelection'
|
||||||
import axios, { CancelToken, AxiosResponse } from 'axios'
|
import axios, { CancelToken, AxiosResponse } from 'axios'
|
||||||
|
import web3 from 'web3'
|
||||||
|
import { ConfigHelperConfig } from '@oceanprotocol/lib/dist/node/utils/ConfigHelper'
|
||||||
|
|
||||||
// TODO: import directly from ocean.js somehow.
|
// TODO: import directly from ocean.js somehow.
|
||||||
// Transforming Aquarius' direct response is needed for getting actual DDOs
|
// Transforming Aquarius' direct response is needed for getting actual DDOs
|
||||||
@ -97,3 +106,57 @@ export async function getAssetsNames(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getAlgorithmsForAssetSelection(
|
||||||
|
metadataCacheUri: string,
|
||||||
|
selectedAlgorithms?: PublisherTrustedAlgorithm[]
|
||||||
|
): Promise<AssetSelectionAsset[]> {
|
||||||
|
const query = {
|
||||||
|
page: 1,
|
||||||
|
query: {
|
||||||
|
query_string: {
|
||||||
|
query: `(service.attributes.main.type:algorithm) -isInPurgatory:true`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sort: { created: -1 }
|
||||||
|
}
|
||||||
|
const source = axios.CancelToken.source()
|
||||||
|
const didList: string[] = []
|
||||||
|
const priceList: any = {}
|
||||||
|
const result = await queryMetadata(
|
||||||
|
query as any,
|
||||||
|
metadataCacheUri,
|
||||||
|
source.token
|
||||||
|
)
|
||||||
|
result?.results?.forEach((ddo: DDO) => {
|
||||||
|
const did: string = web3.utils
|
||||||
|
.toChecksumAddress(ddo.dataToken)
|
||||||
|
.replace('0x', 'did:op:')
|
||||||
|
didList.push(did)
|
||||||
|
priceList[did] = ddo.price.value
|
||||||
|
})
|
||||||
|
const ddoNames = await getAssetsNames(didList, metadataCacheUri, source.token)
|
||||||
|
const algorithmList: AssetSelectionAsset[] = []
|
||||||
|
didList?.forEach((did: string) => {
|
||||||
|
let selected = false
|
||||||
|
selectedAlgorithms?.forEach((algorithm: PublisherTrustedAlgorithm) => {
|
||||||
|
if (algorithm.did === did) {
|
||||||
|
selected = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
selected
|
||||||
|
? algorithmList.unshift({
|
||||||
|
did: did,
|
||||||
|
name: ddoNames[did],
|
||||||
|
price: priceList[did],
|
||||||
|
checked: selected
|
||||||
|
})
|
||||||
|
: algorithmList.push({
|
||||||
|
did: did,
|
||||||
|
name: ddoNames[did],
|
||||||
|
price: priceList[did],
|
||||||
|
checked: selected
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return algorithmList
|
||||||
|
}
|
||||||
|
41
src/utils/compute.ts
Normal file
41
src/utils/compute.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import {
|
||||||
|
DDO,
|
||||||
|
Ocean,
|
||||||
|
ServiceComputePrivacy,
|
||||||
|
publisherTrustedAlgorithm as PublisherTrustedAlgorithm
|
||||||
|
} from '@oceanprotocol/lib'
|
||||||
|
import { ComputePrivacyForm } from '../models/FormEditComputeDataset'
|
||||||
|
|
||||||
|
export async function createTrustedAlgorithmList(
|
||||||
|
selectedAlgorithms: string[], // list of DIDs
|
||||||
|
ocean: Ocean
|
||||||
|
): Promise<PublisherTrustedAlgorithm[]> {
|
||||||
|
const trustedAlgorithms = []
|
||||||
|
|
||||||
|
for (const selectedAlgorithm of selectedAlgorithms) {
|
||||||
|
const trustedAlgorithm = await ocean.compute.createPublisherTrustedAlgorithmfromDID(
|
||||||
|
selectedAlgorithm
|
||||||
|
)
|
||||||
|
trustedAlgorithms.push(trustedAlgorithm)
|
||||||
|
}
|
||||||
|
return trustedAlgorithms
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function transformComputeFormToServiceComputePrivacy(
|
||||||
|
values: ComputePrivacyForm,
|
||||||
|
ocean: Ocean
|
||||||
|
): Promise<ServiceComputePrivacy> {
|
||||||
|
const { allowAllPublishedAlgorithms } = values
|
||||||
|
const publisherTrustedAlgorithms = values.allowAllPublishedAlgorithms
|
||||||
|
? []
|
||||||
|
: await createTrustedAlgorithmList(values.publisherTrustedAlgorithms, ocean)
|
||||||
|
|
||||||
|
const privacy: ServiceComputePrivacy = {
|
||||||
|
allowNetworkAccess: false,
|
||||||
|
allowRawAlgorithm: false,
|
||||||
|
allowAllPublishedAlgorithms,
|
||||||
|
publisherTrustedAlgorithms
|
||||||
|
}
|
||||||
|
|
||||||
|
return privacy
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user