From 287979df8be57705b5d3906d9cba80d98b452d91 Mon Sep 17 00:00:00 2001 From: Moritz Kirstein Date: Thu, 16 Mar 2023 12:15:19 +0100 Subject: [PATCH 001/113] feat: add consumer parameters to publish --- content/publish/form.json | 69 ++++++++ .../InputElement/ConsumerParameters/index.tsx | 155 ++++++++++++++++++ .../@shared/FormInput/InputElement/index.tsx | 4 + .../Publish/Customization/index.tsx | 26 +++ .../Publish/Navigation/index.module.css | 2 +- src/components/Publish/_constants.tsx | 13 +- src/components/Publish/_types.ts | 28 +++- 7 files changed, 292 insertions(+), 5 deletions(-) create mode 100644 src/components/@shared/FormInput/InputElement/ConsumerParameters/index.tsx create mode 100644 src/components/Publish/Customization/index.tsx diff --git a/content/publish/form.json b/content/publish/form.json index 6738fc12b0..52a0154446 100644 --- a/content/publish/form.json +++ b/content/publish/form.json @@ -258,6 +258,75 @@ } ] }, + "customization": { + "title": "Customization", + "fields": [ + { + "name": "consumerParameters", + "label": "Consumer Parameters", + "help": "Define consumer parameters to be submitted to the algortihm before usage.", + "type": "consumerParameters", + "required": false, + "fields": [ + { + "name": "name", + "label": "Parameter Name", + "placeholder_value": "custom_parameter", + "help": "The name of the parameter to ask for. This will be the JSON key handed to the algorithm for this parameter.", + "type": "text", + "required": true + }, + + { + "name": "label", + "label": "Parameter Label", + "placeholder_value": "Custom Parameter", + "type": "text", + "required": true + }, + { + "name": "description", + "label": "Description", + "placeholder_value": "A custom parameter changing the behaviour of the algorithm.", + "type": "text", + "required": true + }, + { + "name": "required", + "label": "Parameter Required", + "type": "checkbox", + "options": ["is required"], + "required": true + }, + { + "name": "type", + "label": "Parameter Type", + "help": "The type of the parameter to ask for. This influences how the parameter is displayed for the consumer before the algorithm is used.", + "type": "select", + "options": ["number", "text", "boolean", "select", "multiselect"], + "required": true + }, + { + "name": "options", + "label": "Select Options", + "placeholder_value": "Define the options for the user to select from", + "type": "creatableSelect", + "required": false + }, + { + "name": "default", + "label": "Default Value", + "required": true, + "placeholder_value": "user input" + } + ] + }, + { + "name": "userdata", + "label": "User Data" + } + ] + }, "pricing": { "title": "Pricing", "fields": [ diff --git a/src/components/@shared/FormInput/InputElement/ConsumerParameters/index.tsx b/src/components/@shared/FormInput/InputElement/ConsumerParameters/index.tsx new file mode 100644 index 0000000000..aadf5c17b0 --- /dev/null +++ b/src/components/@shared/FormInput/InputElement/ConsumerParameters/index.tsx @@ -0,0 +1,155 @@ +import { Field, useField } from 'formik' +import React, { ReactElement, useEffect, useState } from 'react' +import CreatableSelect from 'react-select/creatable' +import Input, { InputProps } from '../..' +import { AlgorithmConsumerParameter } from '../../../../Publish/_types' +import Button from '../../../atoms/Button' +import Tabs from '../../../atoms/Tabs' +import creatableSelectStyles from '../TagsAutoComplete/index.module.css' + +const defaultParam: AlgorithmConsumerParameter = { + name: 'parameter', + label: 'Label', + type: 'text', + default: '', + required: false, + description: 'Description', + options: [] +} + +export const paramTypes: AlgorithmConsumerParameter['type'][] = [ + 'number', + 'text', + 'boolean', + 'multiselect', + 'select' +] + +export function ConsumerParameters(props: InputProps): ReactElement { + const [showOptions, setShowOptions] = useState([]) + + const [field, meta, helpers] = useField( + props.name + ) + + const addParameter = () => { + helpers.setValue([...field.value, defaultParam]) + setShowOptions([...showOptions, false]) + } + + const deleteParameter = (index: number) => { + helpers.setValue(field.value.filter((p, i) => i !== index)) + setShowOptions(showOptions.splice(index, 1)) + } + + return ( +
+ + { + return { + title: param.name, + content: ( +
+ {props.fields?.map((subField) => { + if (subField.name === 'options') { + return field.value[index]?.type?.includes('select') ? ( + null, + IndicatorSeparator: () => null + }} + className={creatableSelectStyles.select} + hideSelectedOptions + isMulti + isClearable={false} + noOptionsMessage={() => + 'Start typing to create options for the user to select.' + } + defaultValue={field.value[index]?.options?.map((o) => ({ + value: o, + label: o + }))} + onChange={(value) => + helpers.setValue([ + ...field.value.map((p, i) => { + if (i !== index) return p + + return { + ...p, + options: value.map((v) => v.value) + } + }) + ]) + } + theme={(theme) => ({ + ...theme, + colors: { + ...theme.colors, + primary25: 'var(--border-color)' + } + })} + /> + ) : ( + <> + ) + } + + if (subField.name === 'default') { + return ( + + ) + } + + return ( + + ) + })} + + +
+ ) + } + })} + /> +
+ ) +} diff --git a/src/components/@shared/FormInput/InputElement/index.tsx b/src/components/@shared/FormInput/InputElement/index.tsx index c21e29ba77..a803015e27 100644 --- a/src/components/@shared/FormInput/InputElement/index.tsx +++ b/src/components/@shared/FormInput/InputElement/index.tsx @@ -16,6 +16,7 @@ import TabsFile from '@shared/atoms/TabsFile' import useDarkMode from '@oceanprotocol/use-dark-mode' import appConfig from '../../../../../app.config' import { extensions, oceanTheme } from '@utils/codemirror' +import { ConsumerParameters } from './ConsumerParameters' const cx = classNames.bind(styles) @@ -130,6 +131,9 @@ export default function InputElement({ /> ) + case 'consumerParameters': + return + case 'textarea': return