diff --git a/content/pages/edit.json b/content/pages/edit.json index 2d526f630..0755221bf 100644 --- a/content/pages/edit.json +++ b/content/pages/edit.json @@ -1,67 +1,3 @@ { - "description": "Update selected metadata of this data set. Updating metadata will create an on-chain transaction you have to approve in your wallet.", - "form": { - "success": "🎉 Successfully updated. 🎉", - "successAction": "Close", - "error": "Updating DDO failed.", - "data": [ - { - "name": "name", - "label": "New Title", - "placeholder": "e.g. Shapes of Desert Plants", - "help": "Enter a concise title.", - "required": true - }, - { - "name": "description", - "label": "New Description", - "help": "Add a thorough description with as much detail as possible. You can use [Markdown](https://daringfireball.net/projects/markdown/basics).", - "type": "textarea", - "rows": 10, - "required": true - }, - { - "name": "price", - "label": "New Price", - "type": "number", - "min": "1", - "placeholder": "0", - "help": "Enter a new price.", - "required": true - }, - { - "name": "files", - "label": "New file", - "placeholder": "e.g. https://file.com/file.json", - "help": "This URL will be stored encrypted after publishing. **Please make sure that the endpoint is accessible over the internet and is not protected by a firewall or by credentials.** 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. Leaving this field empty will not remove the current value.", - "prominentHelp": true, - "type": "files" - }, - { - "name": "links", - "label": "New sample file", - "placeholder": "e.g. https://file.com/samplefile.json", - "help": "Please provide a URL to a sample of your data set file. This file should reveal the data structure of your data set, e.g. by including the header and one line of a CSV file. This file URL will be publicly available after publishing. **Please make sure that the endpoint is accessible over the internet and is not protected by a firewall or by credentials.** Leaving this field empty will not remove the current value.", - "prominentHelp": true, - "type": "files" - }, - - { - "name": "timeout", - "label": "Timeout", - "help": "Define how long buyers should be able to download the data set again after the initial purchase.", - "type": "select", - "options": ["Forever", "1 day", "1 week", "1 month", "1 year"], - "sortOptions": false, - "required": true - }, - { - "name": "author", - "label": "New Author", - "placeholder": "e.g. Mrs McJellyfish", - "help": "Give proper attribution for your data set.", - "required": false - } - ] - } + "description": "Updating metadata or updating compute settings will create an on-chain transaction you have to approve in your wallet." } diff --git a/content/pages/editComputeDataset.json b/content/pages/editComputeDataset.json index 2a9e4df9c..3d49b37de 100644 --- a/content/pages/editComputeDataset.json +++ b/content/pages/editComputeDataset.json @@ -1,9 +1,8 @@ { - "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", + "description": "Only the algorithms selected here will be allowed to run on your data set. Uncheck all to remove any access to your data set.", + "success": "🎉 Successfully updated. 🎉\n\nUpdates might not show up right away on your asset. In this case, wait some seconds and reload your asset details page in your browser.", "error": "Updating DDO failed.", "data": [ { diff --git a/content/pages/editMetadata.json b/content/pages/editMetadata.json new file mode 100644 index 000000000..2b164d6a8 --- /dev/null +++ b/content/pages/editMetadata.json @@ -0,0 +1,65 @@ +{ + "form": { + "success": "🎉 Successfully updated. 🎉\n\nUpdates might not show up right away on your asset. In this case, wait some seconds and reload your asset details page in your browser.", + "error": "Updating DDO failed.", + "data": [ + { + "name": "name", + "label": "New Title", + "placeholder": "e.g. Shapes of Desert Plants", + "help": "Enter a concise title.", + "required": true + }, + { + "name": "description", + "label": "New Description", + "help": "Add a thorough description with as much detail as possible. You can use [Markdown](https://daringfireball.net/projects/markdown/basics).", + "type": "textarea", + "rows": 10, + "required": true + }, + { + "name": "price", + "label": "New Price", + "type": "number", + "min": "1", + "placeholder": "0", + "help": "Enter a new price.", + "required": true + }, + { + "name": "files", + "label": "New file", + "placeholder": "e.g. https://file.com/file.json", + "help": "This URL will be stored encrypted after publishing. **Please make sure that the endpoint is accessible over the internet and is not protected by a firewall or by credentials.** 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. Leaving this field empty will not remove the current value.", + "prominentHelp": true, + "type": "files" + }, + { + "name": "links", + "label": "New sample file", + "placeholder": "e.g. https://file.com/samplefile.json", + "help": "Please provide a URL to a sample of your data set file. This file should reveal the data structure of your data set, e.g. by including the header and one line of a CSV file. This file URL will be publicly available after publishing. **Please make sure that the endpoint is accessible over the internet and is not protected by a firewall or by credentials.** Leaving this field empty will not remove the current value.", + "prominentHelp": true, + "type": "files" + }, + + { + "name": "timeout", + "label": "Timeout", + "help": "Define how long buyers should be able to download the data set again after the initial purchase.", + "type": "select", + "options": ["Forever", "1 day", "1 week", "1 month", "1 year"], + "sortOptions": false, + "required": true + }, + { + "name": "author", + "label": "New Author", + "placeholder": "e.g. Mrs McJellyfish", + "help": "Give proper attribution for your data set.", + "required": false + } + ] + } +} diff --git a/src/@types/Compute.d.ts b/src/@types/Compute.d.ts index c318cf398..5be008ed1 100644 --- a/src/@types/Compute.d.ts +++ b/src/@types/Compute.d.ts @@ -15,11 +15,6 @@ declare global { name: string } - interface ComputePrivacyForm { - allowAllPublishedAlgorithms: boolean - publisherTrustedAlgorithms: string[] - } - interface TokenOrder { id: string serviceIndex: number diff --git a/src/@utils/compute.ts b/src/@utils/compute.ts index 7f7cfd350..9a3184ab8 100644 --- a/src/@utils/compute.ts +++ b/src/@utils/compute.ts @@ -25,6 +25,7 @@ import { SortTermOptions } from 'src/@types/aquarius/SearchQuery' import { AssetSelectionAsset } from '@shared/FormFields/AssetSelection' import { transformAssetToAssetSelection } from './assetConvertor' import { AssetExtended } from 'src/@types/AssetExtended' +import { ComputeEditForm } from 'src/components/Asset/Edit/_types' const getComputeOrders = gql` query ComputeOrders($user: String!) { @@ -329,6 +330,7 @@ export async function createTrustedAlgorithmList( assetChainId: number, cancelToken: CancelToken ): Promise { + if (!selectedAlgorithms || selectedAlgorithms.length === 0) return [] const trustedAlgorithms: PublisherTrustedAlgorithm[] = [] const selectedAssets = await retrieveDDOListByDIDs( @@ -337,6 +339,8 @@ export async function createTrustedAlgorithmList( cancelToken ) + if (!selectedAssets || selectedAssets.length === 0) return [] + for (const selectedAlgorithm of selectedAssets) { const sanitizedAlgorithmContainer = { entrypoint: selectedAlgorithm.metadata.algorithm.container.entrypoint, @@ -357,22 +361,28 @@ export async function createTrustedAlgorithmList( } export async function transformComputeFormToServiceComputeOptions( - values: ComputePrivacyForm, + values: ComputeEditForm, currentOptions: ServiceComputeOptions, assetChainId: number, cancelToken: CancelToken ): Promise { const publisherTrustedAlgorithms = values.allowAllPublishedAlgorithms - ? [] + ? null : await createTrustedAlgorithmList( values.publisherTrustedAlgorithms, assetChainId, cancelToken ) + // TODO: add support for selecting trusted publishers and transforming here. + // This only deals with basics so we don't accidentially allow all accounts + // to be trusted. + const publisherTrustedAlgorithmPublishers: string[] = [] + const privacy: ServiceComputeOptions = { ...currentOptions, - publisherTrustedAlgorithms + publisherTrustedAlgorithms, + publisherTrustedAlgorithmPublishers } return privacy diff --git a/src/@utils/form.ts b/src/@utils/form.ts new file mode 100644 index 000000000..cfde7c36a --- /dev/null +++ b/src/@utils/form.ts @@ -0,0 +1,6 @@ +export function getFieldContent( + fieldName: string, + fields: FormFieldContent[] +): FormFieldContent { + return fields.filter((field: FormFieldContent) => field.name === fieldName)[0] +} diff --git a/src/components/Asset/Edit/DebugEditCompute.tsx b/src/components/Asset/Edit/DebugEditCompute.tsx index 20aa121dd..14e1e13ed 100644 --- a/src/components/Asset/Edit/DebugEditCompute.tsx +++ b/src/components/Asset/Edit/DebugEditCompute.tsx @@ -1,15 +1,15 @@ import { Asset, ServiceComputeOptions } from '@oceanprotocol/lib' import React, { ReactElement, useEffect, useState } from 'react' -// import { transformComputeFormToServiceComputePrivacy } from '@utils/compute' import DebugOutput from '@shared/DebugOutput' import { useCancelToken } from '@hooks/useCancelToken' import { transformComputeFormToServiceComputeOptions } from '@utils/compute' +import { ComputeEditForm } from './_types' export default function DebugEditCompute({ values, asset }: { - values: ComputePrivacyForm + values: ComputeEditForm asset: Asset }): ReactElement { const [formTransformed, setFormTransformed] = diff --git a/src/components/Asset/Edit/EditComputeDataset.tsx b/src/components/Asset/Edit/EditComputeDataset.tsx index 02e8aad07..9b9618252 100644 --- a/src/components/Asset/Edit/EditComputeDataset.tsx +++ b/src/components/Asset/Edit/EditComputeDataset.tsx @@ -6,9 +6,6 @@ import { LoggerInstance, ServiceComputeOptions, Service, - ProviderInstance, - getHash, - Nft, Asset } from '@oceanprotocol/lib' import { useUserPreferences } from '@context/UserPreferences' @@ -29,6 +26,7 @@ import DebugEditCompute from './DebugEditCompute' import { useAsset } from '@context/Asset' import EditFeedback from './EditFeedback' import { setNftMetadata } from '@utils/nft' +import { ComputeEditForm } from './_types' export default function EditComputeDataset({ asset @@ -44,10 +42,7 @@ export default function EditComputeDataset({ const newCancelToken = useCancelToken() const hasFeedback = error || success - async function handleSubmit( - values: ComputePrivacyForm, - resetForm: () => void - ) { + async function handleSubmit(values: ComputeEditForm, resetForm: () => void) { try { if (asset?.accessDetails?.type === 'free') { const tx = await setMinterToPublisher( @@ -130,18 +125,19 @@ export default function EditComputeDataset({ // move user's focus to top of screen window.scrollTo({ top: 0, left: 0, behavior: 'smooth' }) // kick off editing - await handleSubmit(values as any, resetForm) + await handleSubmit(values, resetForm) }} + enableReinitialize > {({ values, isSubmitting }) => isSubmitting || hasFeedback ? ( { await fetchAsset() }, @@ -150,13 +146,7 @@ export default function EditComputeDataset({ /> ) : ( <> -

{content.description}

-
- -
+ void }) { } export default function EditFeedback({ - title, error, success, loading, successAction, setError }: { - title: string error: string success: string - loading?: string + loading: string successAction: Action setError: (error: string) => void }): ReactElement { @@ -64,31 +62,28 @@ export default function EditFeedback({ return (
-
-

{title}

- {error ? ( - <> -

Sorry, something went wrong. Please try again.

- {moreInfo && } - - - - ) : success ? ( - } - /> - ) : ( - - )} -
+ {error ? ( + <> +

Sorry, something went wrong. Please try again.

+ {moreInfo && } + + + + ) : success ? ( + } + /> + ) : ( + + )}
) } diff --git a/src/components/Asset/Edit/EditMetadata.tsx b/src/components/Asset/Edit/EditMetadata.tsx index c34abfd01..4e7c1bf75 100644 --- a/src/components/Asset/Edit/EditMetadata.tsx +++ b/src/components/Asset/Edit/EditMetadata.tsx @@ -15,7 +15,7 @@ import Web3Feedback from '@shared/Web3Feedback' import FormEditMetadata from './FormEditMetadata' import { mapTimeoutStringToSeconds } from '@utils/ddo' import styles from './index.module.css' -import content from '../../../../content/pages/edit.json' +import content from '../../../../content/pages/editMetadata.json' import { AssetExtended } from 'src/@types/AssetExtended' import { useAbortController } from '@hooks/useAbortController' import DebugEditMetadata from './DebugEditMetadata' @@ -159,12 +159,12 @@ export default function Edit({ {({ isSubmitting, values }) => isSubmitting || hasFeedback ? ( { await fetchAsset() }, @@ -173,27 +173,22 @@ export default function Edit({ /> ) : ( <> -

{content.description}

-
- + - + - {debug === true && ( -
- -
- )} -
+ {debug === true && ( +
+ +
+ )} ) } diff --git a/src/components/Asset/Edit/FormActions.tsx b/src/components/Asset/Edit/FormActions.tsx index 312f0ab2c..7b119f472 100644 --- a/src/components/Asset/Edit/FormActions.tsx +++ b/src/components/Asset/Edit/FormActions.tsx @@ -4,6 +4,7 @@ import { useAsset } from '@context/Asset' import Button from '@shared/atoms/Button' import styles from './FormActions.module.css' import Link from 'next/link' +import { ComputeEditForm, MetadataEditForm } from './_types' export default function FormActions({ handleClick @@ -11,15 +12,17 @@ export default function FormActions({ handleClick?: () => void }): ReactElement { const { isAssetNetwork, asset } = useAsset() - const { isValid }: FormikContextType> = useFormikContext() + const { + isValid, + touched + }: FormikContextType = useFormikContext() + + const isSubmitDisabled = + !isValid || !isAssetNetwork || Object.keys(touched).length === 0 return (