From 18cd6b6f0176e61c3cac2fd042c5da63fedbd77c Mon Sep 17 00:00:00 2001 From: Bogdan Fazakas Date: Tue, 16 Feb 2021 11:27:02 +0200 Subject: [PATCH 01/30] WIP publish algorithm --- content/pages/publishAlgo.json | 62 +++++++++++++ src/@types/MetaData.d.ts | 12 +++ src/components/molecules/MetadataPreview.tsx | 36 +++++++- .../organisms/AssetActions/Edit/index.tsx | 2 +- .../pages/Publish/FormAlgoPublish.tsx | 86 ++++++++++++++++++ src/components/pages/Publish/index.tsx | 91 ++++++++++++++++--- src/models/FormAlgoPublish.ts | 32 +++++++ src/pages/publish.tsx | 31 ++++++- src/utils/metadata.ts | 59 +++++++++++- tests/unit/pages/publish.test.tsx | 5 +- 10 files changed, 395 insertions(+), 21 deletions(-) create mode 100644 content/pages/publishAlgo.json create mode 100644 src/components/pages/Publish/FormAlgoPublish.tsx create mode 100644 src/models/FormAlgoPublish.ts diff --git a/content/pages/publishAlgo.json b/content/pages/publishAlgo.json new file mode 100644 index 000000000..4132cd889 --- /dev/null +++ b/content/pages/publishAlgo.json @@ -0,0 +1,62 @@ +{ + "title": "Publish", + "description": "Highlight the important features of your algorith to make it more discoverable and catch the interest of data consumers.", + "warning": "Given the beta status, publishing on Ropsten or Rinkeby first is strongly recommended. Please familiarize yourself with [the market](https://oceanprotocol.com/technology/marketplaces), [the risks](https://blog.oceanprotocol.com/on-staking-on-data-in-ocean-market-3d8e09eb0a13), and the [Terms of Use](/terms).", + "form": { + "title": "Publish", + "data": [ + { + "name": "name", + "label": "Title", + "placeholder": "e.g. Shapes of Desert Plants", + "help": "Enter a concise title.", + "required": true + }, + { + "name": "description", + "label": "Description", + "help": "Add a thorough description with as much detail as possible. You can use [Markdown](https://daringfireball.net/projects/markdown/basics).", + "type": "textarea", + "required": true + }, + { + "name": "files", + "label": "File", + "placeholder": "e.g. https://file.com/file.json", + "help": "Please provide a URL to your algorith file. This URL will be stored encrypted after publishing.", + "type": "files", + "required": true + }, + { + "name": "dockerImage", + "label": "Docker Image", + "placeholder": "e.g. python3.7", + "help": "Please select a predefined image to run your algorithm.", + "type": "select", + "options": ["NodeJS", "Python 3.7"], + "required": true + }, + { + "name": "author", + "label": "Author", + "placeholder": "e.g. Jelly McJellyfish", + "help": "Give proper attribution for your algorith.", + "required": true + }, + { + "name": "tags", + "label": "Tags", + "placeholder": "e.g. logistics, ai", + "help": "Separate tags with comma." + }, + { + "name": "termsAndConditions", + "label": "Terms & Conditions", + "type": "terms", + "options": ["I agree to these Terms and Conditions"], + "required": true + } + ], + "success": "Algorithm Published!" + } +} diff --git a/src/@types/MetaData.d.ts b/src/@types/MetaData.d.ts index 6e3a48dea..80a585a28 100644 --- a/src/@types/MetaData.d.ts +++ b/src/@types/MetaData.d.ts @@ -39,6 +39,18 @@ export interface MetadataPublishForm { links?: string | File[] } +export interface AlgorithmPublishForm { + // ---- required fields ---- + name: string + description: string + files: string | File[] + author: string + dockerImage: string + termsAndConditions: boolean + // ---- optional fields ---- + tags?: string +} + export interface ServiceMetadataMarket extends ServiceMetadata { attributes: MetadataMarket } diff --git a/src/components/molecules/MetadataPreview.tsx b/src/components/molecules/MetadataPreview.tsx index cf448987e..6b72f338f 100644 --- a/src/components/molecules/MetadataPreview.tsx +++ b/src/components/molecules/MetadataPreview.tsx @@ -5,7 +5,10 @@ import Tags from '../atoms/Tags' import MetaItem from '../organisms/AssetContent/MetaItem' import styles from './MetadataPreview.module.css' import File from '../atoms/File' -import { MetadataPublishForm } from '../../@types/MetaData' +import { + MetadataPublishForm, + AlgorithmPublishForm +} from '../../@types/MetaData' import Button from '../atoms/Button' import { transformTags } from '../../utils/metadata' @@ -82,7 +85,7 @@ function Sample({ url }: { url: string }) { ) } -export default function MetadataPreview({ +export function MetadataPreview({ values }: { values: Partial @@ -119,3 +122,32 @@ export default function MetadataPreview({ ) } + +export function MetadataAlgorithmPreview({ + values +}: { + values: Partial +}): ReactElement { + return ( +
+

Preview

+
+ {values.name &&

{values.name}

} + {values.description && } + +
+ {values.files?.length > 0 && typeof values.files !== 'string' && ( + + )} +
+ {values.tags && } +
+ + +
+ ) +} diff --git a/src/components/organisms/AssetActions/Edit/index.tsx b/src/components/organisms/AssetActions/Edit/index.tsx index feb609469..d70a1343b 100644 --- a/src/components/organisms/AssetActions/Edit/index.tsx +++ b/src/components/organisms/AssetActions/Edit/index.tsx @@ -8,7 +8,7 @@ import { } from '../../../../models/FormEditMetadata' import { useAsset } from '../../../../providers/Asset' import { useUserPreferences } from '../../../../providers/UserPreferences' -import MetadataPreview from '../../../molecules/MetadataPreview' +import { MetadataPreview } from '../../../molecules/MetadataPreview' import Debug from './Debug' import Web3Feedback from '../../../molecules/Wallet/Feedback' import FormEditMetadata from './FormEditMetadata' diff --git a/src/components/pages/Publish/FormAlgoPublish.tsx b/src/components/pages/Publish/FormAlgoPublish.tsx new file mode 100644 index 000000000..5307c6ff9 --- /dev/null +++ b/src/components/pages/Publish/FormAlgoPublish.tsx @@ -0,0 +1,86 @@ +import React, { ReactElement, useEffect, FormEvent, ChangeEvent } from 'react' +import styles from './FormPublish.module.css' +import { useOcean } from '@oceanprotocol/react' +import { useFormikContext, Field, Form, FormikContextType } from 'formik' +import Input from '../../atoms/Input' +import Button from '../../atoms/Button' +import { FormContent, FormFieldProps } from '../../../@types/Form' +import { AlgorithmPublishForm } from '../../../@types/MetaData' + +export default function FormPublish({ + content +}: { + content: FormContent +}): ReactElement { + const { ocean, account } = useOcean() + const { + status, + setStatus, + isValid, + setErrors, + setTouched, + resetForm, + initialValues, + validateField, + setFieldValue + }: FormikContextType = useFormikContext() + + // reset form validation on every mount + useEffect(() => { + setErrors({}) + setTouched({}) + resetForm({ values: initialValues, status: 'empty' }) + // setSubmitting(false) + }, [setErrors, setTouched]) + + // Manually handle change events instead of using `handleChange` from Formik. + // Workaround for default `validateOnChange` not kicking in + function handleFieldChange( + e: ChangeEvent, + field: FormFieldProps + ) { + validateField(field.name) + setFieldValue(field.name, e.target.value) + } + + const resetFormAndClearStorage = (e: FormEvent) => { + e.preventDefault() + resetForm({ values: initialValues, status: 'empty' }) + setStatus('empty') + } + + return ( +
status === 'empty' && setStatus(null)} + > + {content.data.map((field: FormFieldProps) => ( + ) => + handleFieldChange(e, field) + } + /> + ))} + +
+ + + {status !== 'empty' && ( + + )} +
+ + ) +} diff --git a/src/components/pages/Publish/index.tsx b/src/components/pages/Publish/index.tsx index 5995acd9b..b78f9fc84 100644 --- a/src/components/pages/Publish/index.tsx +++ b/src/components/pages/Publish/index.tsx @@ -1,18 +1,31 @@ -import React, { ReactElement, useState } from 'react' +import React, { ReactElement, useState, useEffect } from 'react' import { Formik } from 'formik' import { usePublish, useOcean } from '@oceanprotocol/react' import styles from './index.module.css' import FormPublish from './FormPublish' +import FormAlgoPublish from './FormAlgoPublish' import PublishType from './PublishType' import Web3Feedback from '../../molecules/Wallet/Feedback' import { FormContent } from '../../../@types/Form' import { initialValues, validationSchema } from '../../../models/FormPublish' +import { + initialValues as initialValuesAlgorithm, + validationSchema as validationSchemaAlgorithm +} from '../../../models/FormAlgoPublish' + import { transformPublishFormToMetadata, + transformPublishAlgorithmFormToMetadata, mapTimeoutStringToSeconds } from '../../../utils/metadata' -import MetadataPreview from '../../molecules/MetadataPreview' -import { MetadataPublishForm } from '../../../@types/MetaData' +import { + MetadataPreview, + MetadataAlgorithmPreview +} from '../../molecules/MetadataPreview' +import { + MetadataPublishForm, + AlgorithmPublishForm +} from '../../../@types/MetaData' import { useUserPreferences } from '../../../providers/UserPreferences' import { Logger, Metadata } from '@oceanprotocol/lib' import { Persist } from '../../atoms/FormikPersist' @@ -24,20 +37,29 @@ import Button from '../../atoms/Button' const formName = 'ocean-publish-form' export default function PublishPage({ - content + content, + contentAlgoPublish }: { content: { warning: string; form: FormContent } + contentAlgoPublish: { warning: string; form: FormContent } }): ReactElement { const { debug } = useUserPreferences() const { publish, publishError, isLoading, publishStepText } = usePublish() const { isInPurgatory, purgatoryData } = useOcean() const [success, setSuccess] = useState() const [error, setError] = useState() + const [title, setTitle] = useState() const [did, setDid] = useState() const [publishType, setPublishType] = useState() const hasFeedback = isLoading || error || success + useEffect(() => { + publishType === 'data' + ? setTitle('Publishing Data Set') + : setTitle('Publishing Algorithm') + }, [publishType]) + async function handleSubmit( values: Partial, resetForm: () => void @@ -81,16 +103,52 @@ export default function PublishPage({ } } + async function handleAlgorithmSubmit( + values: Partial, + resetForm: () => void + ): Promise { + const metadata = transformPublishAlgorithmFormToMetadata(values) + + try { + Logger.log('Publish Algorithm with ', metadata) + + const ddo = await publish((metadata as unknown) as Metadata, 'access') + + // Publish failed + if (!ddo || publishError) { + setError(publishError || 'Publishing DDO failed.') + Logger.error(publishError || 'Publishing DDO failed.') + return + } + + // Publish succeeded + setDid(ddo.id) + setSuccess( + '🎉 Successfully published. 🎉 Now create a price for your algorithm.' + ) + resetForm() + } catch (error) { + setError(error.message) + Logger.error(error.message) + } + } + return isInPurgatory && purgatoryData ? null : ( { // move user's focus to top of screen window.scrollTo({ top: 0, left: 0, behavior: 'smooth' }) // kick off publishing - await handleSubmit(values, resetForm) + publishType === 'data' + ? await handleSubmit(values, resetForm) + : await handleAlgorithmSubmit(values, resetForm) }} > {({ values }) => ( @@ -99,7 +157,7 @@ export default function PublishPage({ {hasFeedback ? ( ) : ( <> - +
- + {publishType === 'data' ? ( + + ) : ( + + )} diff --git a/src/models/FormAlgoPublish.ts b/src/models/FormAlgoPublish.ts new file mode 100644 index 000000000..04c31d53b --- /dev/null +++ b/src/models/FormAlgoPublish.ts @@ -0,0 +1,32 @@ +import { AlgorithmPublishForm } from '../@types/MetaData' +import { File as FileMetadata } from '@oceanprotocol/lib' +import * as Yup from 'yup' + +export const validationSchema: Yup.SchemaOf = Yup.object() + .shape({ + // ---- required fields ---- + name: Yup.string() + .min(4, (param) => `Title must be at least ${param.min} characters`) + .required('Required'), + description: Yup.string().min(10).required('Required'), + files: Yup.array().required('Required').nullable(), + dockerImage: Yup.string() + .matches(/NodeJS|Python 3.7/g, { excludeEmptyString: true }) + .required('Required'), + author: Yup.string().required('Required'), + termsAndConditions: Yup.boolean().required('Required'), + // ---- optional fields ---- + tags: Yup.string().nullable(), + links: Yup.array().nullable() + }) + .defined() + +export const initialValues: Partial = { + name: '', + author: '', + dockerImage: '', + files: '', + description: '', + termsAndConditions: false, + tags: '' +} diff --git a/src/pages/publish.tsx b/src/pages/publish.tsx index 97a4c358e..365cf0ea5 100644 --- a/src/pages/publish.tsx +++ b/src/pages/publish.tsx @@ -5,11 +5,13 @@ import { graphql, PageProps } from 'gatsby' export default function PageGatsbyPublish(props: PageProps): ReactElement { const content = (props.data as any).content.edges[0].node.childPagesJson + const contentAlgoPublish = (props.data as any).contentAlgoPublish.edges[0] + .node.childPagesJson const { title, description } = content return ( - + ) } @@ -41,5 +43,32 @@ export const contentQuery = graphql` } } } + contentAlgoPublish: allFile( + filter: { relativePath: { eq: "pages/publishAlgo.json" } } + ) { + edges { + node { + childPagesJson { + title + description + warning + form { + title + data { + name + placeholder + label + help + type + required + sortOptions + options + } + success + } + } + } + } + } } ` diff --git a/src/utils/metadata.ts b/src/utils/metadata.ts index 23bf00406..58251e8a3 100644 --- a/src/utils/metadata.ts +++ b/src/utils/metadata.ts @@ -1,8 +1,12 @@ -import { MetadataMarket, MetadataPublishForm } from '../@types/MetaData' +import { + MetadataMarket, + MetadataPublishForm, + AlgorithmPublishForm +} from '../@types/MetaData' import { toStringNoMS } from '.' import AssetModel from '../models/Asset' import slugify from '@sindresorhus/slugify' -import { DDO } from '@oceanprotocol/lib' +import { DDO, MetadataAlgorithm } from '@oceanprotocol/lib' export function transformTags(value: string): string[] { const originalTags = value?.split(',') @@ -66,6 +70,21 @@ export function checkIfTimeoutInPredefinedValues( return false } +function getAlgoithComponent(selectedAlgorithm: string): MetadataAlgorithm { + return { + language: selectedAlgorithm === 'NodeJS' ? 'js' : 'py', + format: 'docker-image', + version: '0.1', + container: { + entrypoint: + selectedAlgorithm === 'NodeJS' ? 'node $ALGO' : 'python $ALGO', + image: + selectedAlgorithm === 'NodeJS' ? 'node' : 'oceanprotocol/algo_dockers', + tag: selectedAlgorithm === 'NodeJS' ? '10' : 'python-panda' + } + } +} + export function transformPublishFormToMetadata( { name, @@ -100,3 +119,39 @@ export function transformPublishFormToMetadata( return metadata } + +export function transformPublishAlgorithmFormToMetadata( + { + name, + author, + description, + tags, + dockerImage, + termsAndConditions, + files + }: Partial, + ddo?: DDO +): MetadataMarket { + const currentTime = toStringNoMS(new Date()) + const algorithm = getAlgoithComponent(dockerImage) + const metadata: MetadataMarket = { + main: { + ...AssetModel.main, + name, + type: 'algorithm', + author, + dateCreated: ddo ? ddo.created : currentTime, + files: typeof files !== 'string' && files, + license: 'https://market.oceanprotocol.com/terms', + algorithm: algorithm + }, + additionalInformation: { + ...AssetModel.additionalInformation, + description, + tags: transformTags(tags), + termsAndConditions + } + } + + return metadata +} diff --git a/tests/unit/pages/publish.test.tsx b/tests/unit/pages/publish.test.tsx index b2fcd1ee2..9accdb737 100644 --- a/tests/unit/pages/publish.test.tsx +++ b/tests/unit/pages/publish.test.tsx @@ -2,10 +2,13 @@ import React from 'react' import { render } from '@testing-library/react' import Publish from '../../../src/components/pages/Publish' import content from '../../../content/pages/publish.json' +import contentAlgo from '../../../content/pages/publishAlgo.json' describe('Home', () => { it('renders without crashing', () => { - const { container } = render() + const { container } = render( + + ) expect(container.firstChild).toBeInTheDocument() }) }) From 4088a790fb5a6789c301cd9b06b3effaee89ee24 Mon Sep 17 00:00:00 2001 From: Bogdan Fazakas Date: Tue, 16 Feb 2021 16:47:07 +0200 Subject: [PATCH 02/30] change publish type from data to dataset --- src/components/pages/Publish/PublishType.tsx | 21 ++++++++++---------- src/components/pages/Publish/index.tsx | 18 ++++++++++------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/components/pages/Publish/PublishType.tsx b/src/components/pages/Publish/PublishType.tsx index 884c99c5f..0bb8370d8 100644 --- a/src/components/pages/Publish/PublishType.tsx +++ b/src/components/pages/Publish/PublishType.tsx @@ -5,12 +5,13 @@ import Button from '../../atoms/Button' const cx = classNames.bind(styles) -const publishTypes = [ - { display: 'data', value: 'data' }, - { display: 'algorithms', value: 'algorithms' } -] +export const TypeOfPublish = { + dataset: 'dataset', + algorithm: 'algorithm' +} as const +type TypeOfPublish = typeof TypeOfPublish[keyof typeof TypeOfPublish] -export default function PublishType({ +export function PublishType({ type, setType }: { @@ -18,14 +19,14 @@ export default function PublishType({ setType: React.Dispatch> }): ReactElement { useEffect(() => { - setType(publishTypes[0].value) + setType(TypeOfPublish.dataset) }, []) return (
- {publishTypes.map((e, index) => { + {Object.keys(TypeOfPublish).map((key, index) => { const tabElement = cx({ - [styles.selected]: e.value === type, + [styles.selected]: key === type, [styles.tabElement]: true }) return ( @@ -35,10 +36,10 @@ export default function PublishType({ key={index} className={tabElement} onClick={async () => { - setType(e.value) + setType(key) }} > - {e.display} + {key} ) })} diff --git a/src/components/pages/Publish/index.tsx b/src/components/pages/Publish/index.tsx index b78f9fc84..dd65b1531 100644 --- a/src/components/pages/Publish/index.tsx +++ b/src/components/pages/Publish/index.tsx @@ -4,7 +4,7 @@ import { usePublish, useOcean } from '@oceanprotocol/react' import styles from './index.module.css' import FormPublish from './FormPublish' import FormAlgoPublish from './FormAlgoPublish' -import PublishType from './PublishType' +import { PublishType, TypeOfPublish } from './PublishType' import Web3Feedback from '../../molecules/Wallet/Feedback' import { FormContent } from '../../../@types/Form' import { initialValues, validationSchema } from '../../../models/FormPublish' @@ -55,7 +55,7 @@ export default function PublishPage({ const hasFeedback = isLoading || error || success useEffect(() => { - publishType === 'data' + publishType === TypeOfPublish.dataset ? setTitle('Publishing Data Set') : setTitle('Publishing Algorithm') }, [publishType]) @@ -136,17 +136,21 @@ export default function PublishPage({ return isInPurgatory && purgatoryData ? null : ( { // move user's focus to top of screen window.scrollTo({ top: 0, left: 0, behavior: 'smooth' }) // kick off publishing - publishType === 'data' + publishType === TypeOfPublish.dataset ? await handleSubmit(values, resetForm) : await handleAlgorithmSubmit(values, resetForm) }} @@ -176,7 +180,7 @@ export default function PublishPage({ className={styles.alert} />
- {publishType === 'data' ? ( + {publishType === TypeOfPublish.dataset ? ( ) : ( @@ -184,7 +188,7 @@ export default function PublishPage({
) diff --git a/src/components/pages/Publish/FormAlgoPublish.tsx b/src/components/pages/Publish/FormAlgoPublish.tsx index 5307c6ff9..f8686db94 100644 --- a/src/components/pages/Publish/FormAlgoPublish.tsx +++ b/src/components/pages/Publish/FormAlgoPublish.tsx @@ -39,8 +39,12 @@ export default function FormPublish({ e: ChangeEvent, field: FormFieldProps ) { + const value = + field.type === 'checkbox' + ? !Boolean(JSON.parse(e.target.value)) + : e.target.value validateField(field.name) - setFieldValue(field.name, e.target.value) + setFieldValue(field.name, value) } const resetFormAndClearStorage = (e: FormEvent) => { diff --git a/src/components/pages/Publish/index.tsx b/src/components/pages/Publish/index.tsx index dd65b1531..33b8cb3ea 100644 --- a/src/components/pages/Publish/index.tsx +++ b/src/components/pages/Publish/index.tsx @@ -112,7 +112,10 @@ export default function PublishPage({ try { Logger.log('Publish Algorithm with ', metadata) - const ddo = await publish((metadata as unknown) as Metadata, 'access') + const ddo = await publish( + (metadata as unknown) as Metadata, + values.algorithmPrivacy === true ? 'compute' : 'access' + ) // Publish failed if (!ddo || publishError) { diff --git a/src/models/FormAlgoPublish.ts b/src/models/FormAlgoPublish.ts index 04c31d53b..9d9acf368 100644 --- a/src/models/FormAlgoPublish.ts +++ b/src/models/FormAlgoPublish.ts @@ -16,6 +16,7 @@ export const validationSchema: Yup.SchemaOf = Yup.object() author: Yup.string().required('Required'), termsAndConditions: Yup.boolean().required('Required'), // ---- optional fields ---- + algorithmPrivacy: Yup.boolean().nullable(), tags: Yup.string().nullable(), links: Yup.array().nullable() }) @@ -27,6 +28,7 @@ export const initialValues: Partial = { dockerImage: '', files: '', description: '', + algorithmPrivacy: false, termsAndConditions: false, tags: '' } From ee25e29de0038ba348ebd1765267de1696821990 Mon Sep 17 00:00:00 2001 From: Bogdan Fazakas Date: Wed, 17 Feb 2021 15:42:22 +0200 Subject: [PATCH 04/30] Redundant Boolean call --- src/components/pages/Publish/FormAlgoPublish.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/pages/Publish/FormAlgoPublish.tsx b/src/components/pages/Publish/FormAlgoPublish.tsx index f8686db94..b7fb4c940 100644 --- a/src/components/pages/Publish/FormAlgoPublish.tsx +++ b/src/components/pages/Publish/FormAlgoPublish.tsx @@ -40,9 +40,7 @@ export default function FormPublish({ field: FormFieldProps ) { const value = - field.type === 'checkbox' - ? !Boolean(JSON.parse(e.target.value)) - : e.target.value + field.type === 'checkbox' ? !JSON.parse(e.target.value) : e.target.value validateField(field.name) setFieldValue(field.name, value) } From 707045071ad7987e740038646cd5a6592f4a0b7d Mon Sep 17 00:00:00 2001 From: Bogdan Fazakas Date: Thu, 18 Feb 2021 14:53:32 +0200 Subject: [PATCH 05/30] added support for custom docker images --- content/pages/publishAlgo.json | 23 +++++++++++- src/@types/MetaData.d.ts | 3 ++ .../molecules/MetadataPreview.module.css | 2 +- .../pages/Publish/FormAlgoPublish.tsx | 36 +++++++++++++++++-- src/models/FormAlgoPublish.ts | 10 +++++- src/utils/metadata.ts | 34 +++++++++++++----- 6 files changed, 95 insertions(+), 13 deletions(-) diff --git a/content/pages/publishAlgo.json b/content/pages/publishAlgo.json index 28cb46dce..544182b9a 100644 --- a/content/pages/publishAlgo.json +++ b/content/pages/publishAlgo.json @@ -33,9 +33,30 @@ "placeholder": "e.g. python3.7", "help": "Please select a predefined image to run your algorithm.", "type": "select", - "options": ["NodeJS", "Python 3.7"], + "options": ["node:pre-defined", "python:pre-defined", "custom image"], "required": true }, + { + "name": "image", + "label": "Image URL", + "placeholder": "e.g. node or https://hub.docker.com/_/node ", + "help": "Provide the name of a docker image or the full url if you have it hosted in a 3rd party repo", + "required": false + }, + { + "name": "version", + "label": "Version", + "placeholder": "e.g. 10", + "help": "Provide the version for your image.", + "required": false + }, + { + "name": "entrypoint", + "label": "Entrypoint", + "placeholder": "e.g. python $ALGO", + "help": "Provide the entrypoint for your algorithm.", + "required": false + }, { "name": "algorithmPrivacy", "label": "Algorithm Privacy", diff --git a/src/@types/MetaData.d.ts b/src/@types/MetaData.d.ts index 9ae93bfca..76c3ca8fb 100644 --- a/src/@types/MetaData.d.ts +++ b/src/@types/MetaData.d.ts @@ -49,6 +49,9 @@ export interface AlgorithmPublishForm { algorithmPrivacy: boolean termsAndConditions: boolean // ---- optional fields ---- + image: string + version: string + entrypoint: string tags?: string } diff --git a/src/components/molecules/MetadataPreview.module.css b/src/components/molecules/MetadataPreview.module.css index 70cf4f43a..e1a14e9b6 100644 --- a/src/components/molecules/MetadataPreview.module.css +++ b/src/components/molecules/MetadataPreview.module.css @@ -17,7 +17,7 @@ display: grid; gap: var(--spacer); grid-template-columns: 1fr 1fr; - margin-bottom: var(--spacer/2); + margin-bottom: var(--spacer); } .previewTitle { diff --git a/src/components/pages/Publish/FormAlgoPublish.tsx b/src/components/pages/Publish/FormAlgoPublish.tsx index b7fb4c940..6ad2c240d 100644 --- a/src/components/pages/Publish/FormAlgoPublish.tsx +++ b/src/components/pages/Publish/FormAlgoPublish.tsx @@ -33,16 +33,48 @@ export default function FormPublish({ // setSubmitting(false) }, [setErrors, setTouched]) + function handleImageSelectChange(imageSelected: string) { + switch (imageSelected) { + case 'node:pre-defined': { + setFieldValue('dockerImage', imageSelected) + setFieldValue('image', 'node') + setFieldValue('version', '10') + setFieldValue('entrypoint', 'node $ALGO') + break + } + case 'python:pre-defined': { + setFieldValue('dockerImage', imageSelected) + setFieldValue('image', 'oceanprotocol/algo_dockers') + setFieldValue('version', 'python-panda') + setFieldValue('entrypoint', 'python $ALGO') + break + } + default: { + setFieldValue('dockerImage', imageSelected) + setFieldValue('image', '') + setFieldValue('version', '') + setFieldValue('entrypoint', '') + break + } + } + } + // Manually handle change events instead of using `handleChange` from Formik. // Workaround for default `validateOnChange` not kicking in function handleFieldChange( e: ChangeEvent, field: FormFieldProps ) { + console.log(field) const value = field.type === 'checkbox' ? !JSON.parse(e.target.value) : e.target.value - validateField(field.name) - setFieldValue(field.name, value) + if (field.name === 'dockerImage') { + validateField(field.name) + handleImageSelectChange(e.target.value) + } else { + validateField(field.name) + setFieldValue(field.name, value) + } } const resetFormAndClearStorage = (e: FormEvent) => { diff --git a/src/models/FormAlgoPublish.ts b/src/models/FormAlgoPublish.ts index 9d9acf368..826721026 100644 --- a/src/models/FormAlgoPublish.ts +++ b/src/models/FormAlgoPublish.ts @@ -11,8 +11,13 @@ export const validationSchema: Yup.SchemaOf = Yup.object() description: Yup.string().min(10).required('Required'), files: Yup.array().required('Required').nullable(), dockerImage: Yup.string() - .matches(/NodeJS|Python 3.7/g, { excludeEmptyString: true }) + .matches(/node:pre-defined|python:pre-defined|custom image/g, { + excludeEmptyString: true + }) .required('Required'), + image: Yup.string().required('Required'), + version: Yup.string().required('Required'), + entrypoint: Yup.string().required('Required'), author: Yup.string().required('Required'), termsAndConditions: Yup.boolean().required('Required'), // ---- optional fields ---- @@ -26,6 +31,9 @@ export const initialValues: Partial = { name: '', author: '', dockerImage: '', + image: '', + version: '', + entrypoint: '', files: '', description: '', algorithmPrivacy: false, diff --git a/src/utils/metadata.ts b/src/utils/metadata.ts index 58251e8a3..a1fa323ab 100644 --- a/src/utils/metadata.ts +++ b/src/utils/metadata.ts @@ -70,21 +70,29 @@ export function checkIfTimeoutInPredefinedValues( return false } -function getAlgoithComponent(selectedAlgorithm: string): MetadataAlgorithm { +function getAlgoithComponent( + image: string, + version: string, + entrypoint: string, + algorithmLanguace: string +): MetadataAlgorithm { return { - language: selectedAlgorithm === 'NodeJS' ? 'js' : 'py', + language: algorithmLanguace, format: 'docker-image', version: '0.1', container: { - entrypoint: - selectedAlgorithm === 'NodeJS' ? 'node $ALGO' : 'python $ALGO', - image: - selectedAlgorithm === 'NodeJS' ? 'node' : 'oceanprotocol/algo_dockers', - tag: selectedAlgorithm === 'NodeJS' ? '10' : 'python-panda' + entrypoint: entrypoint, + image: image, + tag: version } } } +function getAlgoithFileExtension(fileUrl: string): string { + const splitedFileUrl = fileUrl.split('.') + return splitedFileUrl[splitedFileUrl.length - 1] +} + export function transformPublishFormToMetadata( { name, @@ -127,13 +135,23 @@ export function transformPublishAlgorithmFormToMetadata( description, tags, dockerImage, + image, + version, + entrypoint, termsAndConditions, files }: Partial, ddo?: DDO ): MetadataMarket { const currentTime = toStringNoMS(new Date()) - const algorithm = getAlgoithComponent(dockerImage) + const fileUrl = typeof files !== 'string' && files[0].url + const algorithmLanguace = getAlgoithFileExtension(fileUrl) + const algorithm = getAlgoithComponent( + image, + version, + entrypoint, + algorithmLanguace + ) const metadata: MetadataMarket = { main: { ...AssetModel.main, From 243283e434db270873b42f9862d3d2d23be1d1e7 Mon Sep 17 00:00:00 2001 From: Bogdan Fazakas Date: Fri, 19 Feb 2021 13:44:04 +0200 Subject: [PATCH 06/30] disable aditional docker image fields for pre-defined containers --- content/pages/publishAlgo.json | 5 ++++- src/@types/Form.d.ts | 1 + src/components/pages/Publish/FormAlgoPublish.tsx | 11 ++++++++++- src/pages/publish.tsx | 2 ++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/content/pages/publishAlgo.json b/content/pages/publishAlgo.json index 544182b9a..6cd0b2754 100644 --- a/content/pages/publishAlgo.json +++ b/content/pages/publishAlgo.json @@ -39,7 +39,8 @@ { "name": "image", "label": "Image URL", - "placeholder": "e.g. node or https://hub.docker.com/_/node ", + "placeholder": "e.g. node or https://hub.docker.com/_/node", + "disabled": true, "help": "Provide the name of a docker image or the full url if you have it hosted in a 3rd party repo", "required": false }, @@ -48,6 +49,7 @@ "label": "Version", "placeholder": "e.g. 10", "help": "Provide the version for your image.", + "disabled": true, "required": false }, { @@ -55,6 +57,7 @@ "label": "Entrypoint", "placeholder": "e.g. python $ALGO", "help": "Provide the entrypoint for your algorithm.", + "disabled": true, "required": false }, { diff --git a/src/@types/Form.d.ts b/src/@types/Form.d.ts index 107289ca0..5e757c86c 100644 --- a/src/@types/Form.d.ts +++ b/src/@types/Form.d.ts @@ -5,6 +5,7 @@ export interface FormFieldProps { options?: string[] sortOptions?: boolean required?: boolean + disabled?: boolean help?: string placeholder?: string pattern?: string diff --git a/src/components/pages/Publish/FormAlgoPublish.tsx b/src/components/pages/Publish/FormAlgoPublish.tsx index 6ad2c240d..051d73423 100644 --- a/src/components/pages/Publish/FormAlgoPublish.tsx +++ b/src/components/pages/Publish/FormAlgoPublish.tsx @@ -33,10 +33,17 @@ export default function FormPublish({ // setSubmitting(false) }, [setErrors, setTouched]) + function setDisableFlag(flag: boolean) { + content.data.forEach((field) => { + if (field.disabled !== null) field.disabled = flag + }) + } + function handleImageSelectChange(imageSelected: string) { switch (imageSelected) { case 'node:pre-defined': { setFieldValue('dockerImage', imageSelected) + setDisableFlag(true) setFieldValue('image', 'node') setFieldValue('version', '10') setFieldValue('entrypoint', 'node $ALGO') @@ -44,6 +51,7 @@ export default function FormPublish({ } case 'python:pre-defined': { setFieldValue('dockerImage', imageSelected) + setDisableFlag(true) setFieldValue('image', 'oceanprotocol/algo_dockers') setFieldValue('version', 'python-panda') setFieldValue('entrypoint', 'python $ALGO') @@ -51,6 +59,7 @@ export default function FormPublish({ } default: { setFieldValue('dockerImage', imageSelected) + setDisableFlag(false) setFieldValue('image', '') setFieldValue('version', '') setFieldValue('entrypoint', '') @@ -65,7 +74,6 @@ export default function FormPublish({ e: ChangeEvent, field: FormFieldProps ) { - console.log(field) const value = field.type === 'checkbox' ? !JSON.parse(e.target.value) : e.target.value if (field.name === 'dockerImage') { @@ -93,6 +101,7 @@ export default function FormPublish({ ) => handleFieldChange(e, field) diff --git a/src/pages/publish.tsx b/src/pages/publish.tsx index 365cf0ea5..ffe539d00 100644 --- a/src/pages/publish.tsx +++ b/src/pages/publish.tsx @@ -34,6 +34,7 @@ export const contentQuery = graphql` help type required + disabled sortOptions options } @@ -61,6 +62,7 @@ export const contentQuery = graphql` help type required + disabled sortOptions options } From 92547533a5315f9164d16377c1ab0a95eb2450a4 Mon Sep 17 00:00:00 2001 From: Bogdan Fazakas Date: Fri, 19 Feb 2021 16:08:47 +0200 Subject: [PATCH 07/30] refactor publish page content --- content/pages/form-algorithm.json | 88 ++++++++++++++++++ content/pages/form-dataset.json | 79 ++++++++++++++++ content/pages/index.json | 5 + content/pages/publish.json | 84 ----------------- content/pages/publishAlgo.json | 93 ------------------- .../pages/Publish/FormAlgoPublish.tsx | 37 +++++++- src/components/pages/Publish/FormPublish.tsx | 37 +++++++- src/components/pages/Publish/index.tsx | 10 +- src/pages/publish.tsx | 49 +--------- 9 files changed, 242 insertions(+), 240 deletions(-) create mode 100644 content/pages/form-algorithm.json create mode 100644 content/pages/form-dataset.json create mode 100644 content/pages/index.json delete mode 100644 content/pages/publish.json delete mode 100644 content/pages/publishAlgo.json diff --git a/content/pages/form-algorithm.json b/content/pages/form-algorithm.json new file mode 100644 index 000000000..b4cf7bac0 --- /dev/null +++ b/content/pages/form-algorithm.json @@ -0,0 +1,88 @@ +{ + "title": "Publish", + "data": [ + { + "name": "name", + "label": "Title", + "placeholder": "e.g. Shapes of Desert Plants", + "help": "Enter a concise title.", + "required": true + }, + { + "name": "description", + "label": "Description", + "help": "Add a thorough description with as much detail as possible. You can use [Markdown](https://daringfireball.net/projects/markdown/basics).", + "type": "textarea", + "required": true + }, + { + "name": "files", + "label": "File", + "placeholder": "e.g. https://file.com/file.json", + "help": "Please provide a URL to your algorith file. This URL will be stored encrypted after publishing.", + "type": "files", + "required": true + }, + { + "name": "dockerImage", + "label": "Docker Image", + "placeholder": "e.g. python3.7", + "help": "Please select a predefined image to run your algorithm.", + "type": "select", + "options": ["node:pre-defined", "python:pre-defined", "custom image"], + "required": true + }, + { + "name": "image", + "label": "Image URL", + "placeholder": "e.g. node or https://hub.docker.com/_/node", + "disabled": true, + "help": "Provide the name of a docker image or the full url if you have it hosted in a 3rd party repo", + "required": false + }, + { + "name": "version", + "label": "Version", + "placeholder": "e.g. 10", + "help": "Provide the version for your image.", + "disabled": true, + "required": false + }, + { + "name": "entrypoint", + "label": "Entrypoint", + "placeholder": "e.g. python $ALGO", + "help": "Provide the entrypoint for your algorithm.", + "disabled": true, + "required": false + }, + { + "name": "algorithmPrivacy", + "label": "Algorithm Privacy", + "type": "checkbox", + "options": ["Keep my algorithm private"], + "required": false + }, + { + "name": "author", + "label": "Author", + "placeholder": "e.g. Jelly McJellyfish", + "help": "Give proper attribution for your algorith.", + "required": true + }, + { + "name": "tags", + "label": "Tags", + "placeholder": "e.g. logistics, ai", + "help": "Separate tags with comma." + }, + { + "name": "termsAndConditions", + "label": "Terms & Conditions", + "type": "terms", + "options": ["I agree to these Terms and Conditions"], + "required": true + } + ], + "success": "Algorithm Published!" +} diff --git a/content/pages/form-dataset.json b/content/pages/form-dataset.json new file mode 100644 index 000000000..6f85d26e4 --- /dev/null +++ b/content/pages/form-dataset.json @@ -0,0 +1,79 @@ +{ + "title": "Publish", + "data": [ + { + "name": "name", + "label": "Title", + "placeholder": "e.g. Shapes of Desert Plants", + "help": "Enter a concise title.", + "required": true + }, + { + "name": "description", + "label": "Description", + "help": "Add a thorough description with as much detail as possible. You can use [Markdown](https://daringfireball.net/projects/markdown/basics).", + "type": "textarea", + "required": true + }, + { + "name": "files", + "label": "File", + "placeholder": "e.g. https://file.com/file.json", + "help": "Please provide a URL to your data set file. This URL will be stored encrypted after publishing.", + "type": "files", + "required": true + }, + { + "name": "links", + "label": "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.", + "type": "files" + }, + { + "name": "access", + "label": "Access Type", + "help": "Choose how you want your files to be accessible for the specified price.", + "type": "select", + "options": ["Download"], + "required": true + }, + { + "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": "dataTokenOptions", + "label": "Datatoken Name & Symbol", + "type": "datatoken", + "help": "The datatoken for this data set will be created with this name & symbol.", + "required": true + }, + { + "name": "author", + "label": "Author", + "placeholder": "e.g. Jelly McJellyfish", + "help": "Give proper attribution for your data set.", + "required": true + }, + { + "name": "tags", + "label": "Tags", + "placeholder": "e.g. logistics, ai", + "help": "Separate tags with comma." + }, + { + "name": "termsAndConditions", + "label": "Terms & Conditions", + "type": "terms", + "options": ["I agree to these Terms and Conditions"], + "required": true + } + ], + "success": "Asset Created!" +} diff --git a/content/pages/index.json b/content/pages/index.json new file mode 100644 index 000000000..36b3947f0 --- /dev/null +++ b/content/pages/index.json @@ -0,0 +1,5 @@ +{ + "title": "Publish", + "description": "Highlight the important features of your data set to make it more discoverable and catch the interest of data consumers.", + "warning": "Given the beta status, publishing on Ropsten or Rinkeby first is strongly recommended. Please familiarize yourself with [the market](https://oceanprotocol.com/technology/marketplaces), [the risks](https://blog.oceanprotocol.com/on-staking-on-data-in-ocean-market-3d8e09eb0a13), and the [Terms of Use](/terms)." +} diff --git a/content/pages/publish.json b/content/pages/publish.json deleted file mode 100644 index 8da56c3a0..000000000 --- a/content/pages/publish.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "title": "Publish", - "description": "Highlight the important features of your data set to make it more discoverable and catch the interest of data consumers.", - "warning": "Given the beta status, publishing on Ropsten or Rinkeby first is strongly recommended. Please familiarize yourself with [the market](https://oceanprotocol.com/technology/marketplaces), [the risks](https://blog.oceanprotocol.com/on-staking-on-data-in-ocean-market-3d8e09eb0a13), and the [Terms of Use](/terms).", - "form": { - "title": "Publish", - "data": [ - { - "name": "name", - "label": "Title", - "placeholder": "e.g. Shapes of Desert Plants", - "help": "Enter a concise title.", - "required": true - }, - { - "name": "description", - "label": "Description", - "help": "Add a thorough description with as much detail as possible. You can use [Markdown](https://daringfireball.net/projects/markdown/basics).", - "type": "textarea", - "required": true - }, - { - "name": "files", - "label": "File", - "placeholder": "e.g. https://file.com/file.json", - "help": "Please provide a URL to your data set file. This URL will be stored encrypted after publishing.", - "type": "files", - "required": true - }, - { - "name": "links", - "label": "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.", - "type": "files" - }, - { - "name": "access", - "label": "Access Type", - "help": "Choose how you want your files to be accessible for the specified price.", - "type": "select", - "options": ["Download"], - "required": true - }, - { - "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": "dataTokenOptions", - "label": "Datatoken Name & Symbol", - "type": "datatoken", - "help": "The datatoken for this data set will be created with this name & symbol.", - "required": true - }, - { - "name": "author", - "label": "Author", - "placeholder": "e.g. Jelly McJellyfish", - "help": "Give proper attribution for your data set.", - "required": true - }, - { - "name": "tags", - "label": "Tags", - "placeholder": "e.g. logistics, ai", - "help": "Separate tags with comma." - }, - { - "name": "termsAndConditions", - "label": "Terms & Conditions", - "type": "terms", - "options": ["I agree to these Terms and Conditions"], - "required": true - } - ], - "success": "Asset Created!" - } -} diff --git a/content/pages/publishAlgo.json b/content/pages/publishAlgo.json deleted file mode 100644 index 6cd0b2754..000000000 --- a/content/pages/publishAlgo.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "title": "Publish", - "description": "Highlight the important features of your algorith to make it more discoverable and catch the interest of data consumers.", - "warning": "Given the beta status, publishing on Ropsten or Rinkeby first is strongly recommended. Please familiarize yourself with [the market](https://oceanprotocol.com/technology/marketplaces), [the risks](https://blog.oceanprotocol.com/on-staking-on-data-in-ocean-market-3d8e09eb0a13), and the [Terms of Use](/terms).", - "form": { - "title": "Publish", - "data": [ - { - "name": "name", - "label": "Title", - "placeholder": "e.g. Shapes of Desert Plants", - "help": "Enter a concise title.", - "required": true - }, - { - "name": "description", - "label": "Description", - "help": "Add a thorough description with as much detail as possible. You can use [Markdown](https://daringfireball.net/projects/markdown/basics).", - "type": "textarea", - "required": true - }, - { - "name": "files", - "label": "File", - "placeholder": "e.g. https://file.com/file.json", - "help": "Please provide a URL to your algorith file. This URL will be stored encrypted after publishing.", - "type": "files", - "required": true - }, - { - "name": "dockerImage", - "label": "Docker Image", - "placeholder": "e.g. python3.7", - "help": "Please select a predefined image to run your algorithm.", - "type": "select", - "options": ["node:pre-defined", "python:pre-defined", "custom image"], - "required": true - }, - { - "name": "image", - "label": "Image URL", - "placeholder": "e.g. node or https://hub.docker.com/_/node", - "disabled": true, - "help": "Provide the name of a docker image or the full url if you have it hosted in a 3rd party repo", - "required": false - }, - { - "name": "version", - "label": "Version", - "placeholder": "e.g. 10", - "help": "Provide the version for your image.", - "disabled": true, - "required": false - }, - { - "name": "entrypoint", - "label": "Entrypoint", - "placeholder": "e.g. python $ALGO", - "help": "Provide the entrypoint for your algorithm.", - "disabled": true, - "required": false - }, - { - "name": "algorithmPrivacy", - "label": "Algorithm Privacy", - "type": "checkbox", - "options": ["Keep my algorithm private"], - "required": false - }, - { - "name": "author", - "label": "Author", - "placeholder": "e.g. Jelly McJellyfish", - "help": "Give proper attribution for your algorith.", - "required": true - }, - { - "name": "tags", - "label": "Tags", - "placeholder": "e.g. logistics, ai", - "help": "Separate tags with comma." - }, - { - "name": "termsAndConditions", - "label": "Terms & Conditions", - "type": "terms", - "options": ["I agree to these Terms and Conditions"], - "required": true - } - ], - "success": "Algorithm Published!" - } -} diff --git a/src/components/pages/Publish/FormAlgoPublish.tsx b/src/components/pages/Publish/FormAlgoPublish.tsx index 051d73423..61b56fbad 100644 --- a/src/components/pages/Publish/FormAlgoPublish.tsx +++ b/src/components/pages/Publish/FormAlgoPublish.tsx @@ -1,4 +1,5 @@ import React, { ReactElement, useEffect, FormEvent, ChangeEvent } from 'react' +import { useStaticQuery, graphql } from 'gatsby' import styles from './FormPublish.module.css' import { useOcean } from '@oceanprotocol/react' import { useFormikContext, Field, Form, FormikContextType } from 'formik' @@ -7,11 +8,37 @@ import Button from '../../atoms/Button' import { FormContent, FormFieldProps } from '../../../@types/Form' import { AlgorithmPublishForm } from '../../../@types/MetaData' -export default function FormPublish({ - content -}: { - content: FormContent -}): ReactElement { +const query = graphql` + query { + content: allFile( + filter: { relativePath: { eq: "pages/form-algorithm.json" } } + ) { + edges { + node { + childPagesJson { + title + data { + name + placeholder + label + help + type + required + disabled + sortOptions + options + } + warning + } + } + } + } + } +` + +export default function FormPublish({}: {}): ReactElement { + const data = useStaticQuery(query) + const content: FormContent = data.content.edges[0].node.childPagesJson const { ocean, account } = useOcean() const { status, diff --git a/src/components/pages/Publish/FormPublish.tsx b/src/components/pages/Publish/FormPublish.tsx index 80fe85c81..5ba4864a8 100644 --- a/src/components/pages/Publish/FormPublish.tsx +++ b/src/components/pages/Publish/FormPublish.tsx @@ -1,4 +1,5 @@ import React, { ReactElement, useEffect, FormEvent, ChangeEvent } from 'react' +import { useStaticQuery, graphql } from 'gatsby' import styles from './FormPublish.module.css' import { useOcean } from '@oceanprotocol/react' import { useFormikContext, Field, Form, FormikContextType } from 'formik' @@ -7,11 +8,37 @@ import Button from '../../atoms/Button' import { FormContent, FormFieldProps } from '../../../@types/Form' import { MetadataPublishForm } from '../../../@types/MetaData' -export default function FormPublish({ - content -}: { - content: FormContent -}): ReactElement { +const query = graphql` + query { + content: allFile( + filter: { relativePath: { eq: "pages/form-dataset.json" } } + ) { + edges { + node { + childPagesJson { + title + data { + name + placeholder + label + help + type + required + disabled + sortOptions + options + } + warning + } + } + } + } + } +` + +export default function FormPublish({}: {}): ReactElement { + const data = useStaticQuery(query) + const content: FormContent = data.content.edges[0].node.childPagesJson const { ocean, account } = useOcean() const { status, diff --git a/src/components/pages/Publish/index.tsx b/src/components/pages/Publish/index.tsx index 33b8cb3ea..42418ecb7 100644 --- a/src/components/pages/Publish/index.tsx +++ b/src/components/pages/Publish/index.tsx @@ -37,11 +37,9 @@ import Button from '../../atoms/Button' const formName = 'ocean-publish-form' export default function PublishPage({ - content, - contentAlgoPublish + content }: { - content: { warning: string; form: FormContent } - contentAlgoPublish: { warning: string; form: FormContent } + content: { warning: string } }): ReactElement { const { debug } = useUserPreferences() const { publish, publishError, isLoading, publishStepText } = usePublish() @@ -184,9 +182,9 @@ export default function PublishPage({ />
{publishType === TypeOfPublish.dataset ? ( - + ) : ( - + )}