diff --git a/packages/secretnote/package.json b/packages/secretnote/package.json index df97eca1..e249c62b 100644 --- a/packages/secretnote/package.json +++ b/packages/secretnote/package.json @@ -28,10 +28,10 @@ "@antv/s2": "^1.52.0", "@codemirror/lang-python": "^6.1.2", "@difizen/libro-jupyter": "^0.1.14", - "@difizen/mana-app": "^0.1.8", - "@difizen/mana-common": "^0.1.8", - "@difizen/mana-l10n": "^0.1.8", - "@difizen/mana-react": "^0.1.8", + "@difizen/mana-app": "^0.1.9", + "@difizen/mana-common": "^0.1.9", + "@difizen/mana-l10n": "^0.1.9", + "@difizen/mana-react": "^0.1.9", "@kanaries/web-data-loader": "^0.1.7", "@lumino/polling": "^1.11.4", "@rjsf/antd": "^5.7.3", diff --git a/packages/secretnote/src/components/component-form/table-config/index.tsx b/packages/secretnote/src/components/component-form/table-config/index.tsx index 21ad0fb2..16006a78 100644 --- a/packages/secretnote/src/components/component-form/table-config/index.tsx +++ b/packages/secretnote/src/components/component-form/table-config/index.tsx @@ -1,3 +1,4 @@ +import type { FormInstance } from 'antd'; import { Input, Form, Select } from 'antd'; import type { SchemaItem } from '../type'; @@ -9,11 +10,18 @@ const labelCol = { span: 8 }; const wrapperCol = { offset: 4, span: 12 }; const TableConfig = { - tableConfig: (props: { root: SchemaItem }) => { + tableConfig: (props: { root: SchemaItem; form: FormInstance }) => { const { root } = props; const types = getByPath(root, '$inputTableConfig/types'); const attrs = getByPath(root, '$inputTableConfig/attrs'); + const getInputType = () => { + const type = props.form.getFieldValue(['input', root.id, 'type']); + if (type) { + return type.split('.')[1]; + } + }; + return ( ))} - - - + {getInputType() === 'table' && ( + + + + )} ); }, diff --git a/packages/secretnote/src/components/component-form/table-config/table-selector.tsx b/packages/secretnote/src/components/component-form/table-config/table-selector.tsx index f66a7385..5ffcdc71 100644 --- a/packages/secretnote/src/components/component-form/table-config/table-selector.tsx +++ b/packages/secretnote/src/components/component-form/table-config/table-selector.tsx @@ -16,7 +16,8 @@ type Table = { type TableValue = { data_ref: Table[]; - schema: SchemaValue; + schema?: SchemaValue; + schemas?: SchemaValue[]; }; type TableOption = { @@ -64,9 +65,13 @@ const TableSelector = (props: TableSelectorProps) => { return []; }; - const getDefaultSchema = () => { - const schema = props.value?.schema || {}; - return schema; + const getDefaultSchema = (index: number) => { + const dataRef = props.value?.data_ref || []; + if (dataRef.length > 1) { + return props.value?.schemas?.[index]; + } else if (dataRef.length === 1) { + return props.value?.schema; + } }; const onTableChange = (index: number, value: string[]) => { @@ -76,26 +81,38 @@ const TableSelector = (props: TableSelectorProps) => { const dataRef = props.value?.data_ref || []; dataRef[index] = { uri, party }; props.onChange({ + ...props.value, data_ref: dataRef, - schema: props.value?.schema, }); } else { const dataRef = props.value?.data_ref || []; dataRef.splice(index, 1); props.onChange({ + ...props.value, data_ref: dataRef, - schema: props.value?.schema, }); } } }; - const onTableSchemaChange = (value: SchemaValue) => { + const onTableSchemaChange = (index: number, value: SchemaValue) => { if (props.onChange) { - props.onChange({ - data_ref: props.value?.data_ref, - schema: { ...props.value?.schema, ...value }, - }); + const dataRef = props.value?.data_ref || []; + if (dataRef.length > 1) { + const schemas = props.value?.schemas || []; + schemas[index] = { ...schemas[index], ...value }; + props.onChange({ + ...props.value, + schemas: schemas, + schema: undefined, + }); + } else if (dataRef.length === 1) { + props.onChange({ + ...props.value, + schema: { ...props.value?.schema, ...value }, + schemas: undefined, + }); + } } }; @@ -111,23 +128,21 @@ const TableSelector = (props: TableSelectorProps) => { options={table} onChange={(val) => onTableChange(index, val as string[])} /> - {index === 0 && ( - - } - placement="right" - title="" - overlayClassName="secretnote-table-selector-popover" - trigger="click" - arrow={false} - > - - - )} + onTableSchemaChange(index, val)} + /> + } + placement="right" + title="" + overlayClassName="secretnote-table-selector-popover" + trigger="click" + arrow={false} + > + + ) : ( diff --git a/packages/secretnote/src/components/component-form/type.ts b/packages/secretnote/src/components/component-form/type.ts index df2a5e4f..5412f72c 100644 --- a/packages/secretnote/src/components/component-form/type.ts +++ b/packages/secretnote/src/components/component-form/type.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -export type AttrType = 'AT_STRING' | 'AT_BOOL' | 'AT_INT'; +export type AttrType = 'AT_STRING' | 'AT_BOOL' | 'AT_INT' | 'AT_FLOAT'; export type ValueKey = 's' | 'ss' | 'i64' | 'f' | 'b'; @@ -27,6 +27,9 @@ export type Atomic = { lowerBoundEnabled?: boolean; lowerBound?: AtomicValue; lowerBoundInclusive?: boolean; + upperBoundEnabled?: boolean; + upperBound?: AtomicValue; + upperBoundInclusive?: boolean; }; export interface Attr { diff --git a/packages/secretnote/src/components/component-form/util.ts b/packages/secretnote/src/components/component-form/util.ts index 4d7dc554..84ad867c 100644 --- a/packages/secretnote/src/components/component-form/util.ts +++ b/packages/secretnote/src/components/component-form/util.ts @@ -17,17 +17,22 @@ const getRenderType = (attr: Attr): string => { return 'number'; case 'AT_STRING': return 'string'; + case 'AT_FLOAT': + return 'number'; } + return 'string'; }; -const getDefaultValue = (attr: Attr) => { +const getValue = (attr: Attr, key: 'defaultValue' | 'lowerBound' | 'upperBound') => { switch (attr.type) { case 'AT_BOOL': - return attr.atomic?.defaultValue?.b; + return attr.atomic?.[key]?.b; case 'AT_INT': - return attr.atomic?.defaultValue?.i64; + return attr.atomic?.[key]?.i64; case 'AT_STRING': - return attr.atomic?.defaultValue?.s; + return attr.atomic?.[key]?.s; + case 'AT_FLOAT': + return attr.atomic?.[key]?.f; } }; @@ -35,6 +40,18 @@ const isFieldRequired = (attr: Attr) => { return !attr.atomic.isOptional; }; +const getMinimum = (attr: Attr) => { + if (attr.atomic.lowerBoundEnabled) { + return Number(getValue(attr, 'lowerBound')); + } +}; + +const getMaximum = (attr: Attr) => { + if (attr.atomic.upperBoundEnabled) { + return Number(getValue(attr, 'upperBound')); + } +}; + export const setByPath = ( obj: any, path: string | string[], @@ -126,8 +143,10 @@ const transformSpecToJsonSchema: (spec: ComponentSpec) => SchemaItem = ( label: v, value: v, })), - $defaultValue: getDefaultValue(attr), + $defaultValue: getValue(attr, 'defaultValue'), $required: isFieldRequired(attr), + minimum: getMinimum(attr), + maximum: getMaximum(attr), }; setByPath(json, `properties/attrs/properties/${name}`, attrItem); diff --git a/packages/secretnote/src/modules/component-cell/cell-component/cell-code.ts b/packages/secretnote/src/modules/component-cell/cell-component/cell-code.ts index 3141a441..261772fd 100644 --- a/packages/secretnote/src/modules/component-cell/cell-component/cell-code.ts +++ b/packages/secretnote/src/modules/component-cell/cell-component/cell-code.ts @@ -1,6 +1,18 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import type { ComponentSpec, Value, IOType } from '@/components/component-form'; +const deviceConfig = { + runtime_config: { protocol: 'REF2K', field: 'FM64' }, + link_desc: { + connect_retry_times: 60, + connect_retry_interval_ms: 1000, + brpc_channel_protocol: 'http', + brpc_channel_connection_type: 'pooled', + recv_timeout_ms: 1200000, + http_timeout_ms: 1200000, + }, +}; + const clusterConfig = { public_config: { ray_fed_config: { @@ -23,8 +35,17 @@ const clusterConfig = { name: 'spu', type: 'spu', parties: ['alice', 'bob'], - config: - '{"runtime_config":{"protocol":"REF2K","field":"FM64"},"link_desc":{"connect_retry_times":60,"connect_retry_interval_ms":1000,"brpc_channel_protocol":"http","brpc_channel_connection_type":"pooled","recv_timeout_ms":1200000,"http_timeout_ms":1200000}}', + config: JSON.stringify(deviceConfig), + }, + { + name: 'heu', + type: 'heu', + parties: [], + config: JSON.stringify({ + mode: 'PHEU', + schema: 'paillier', + key_size: 2048, + }), }, ], }, @@ -41,12 +62,14 @@ const getAttrValue = (component: ComponentSpec, key: string, value: any) => { return { b: value }; case 'AT_STRING': return { s: value }; + case 'AT_FLOAT': + return { f: value }; default: return { s: value }; } } else { // input has no marked data type in the attr, so it can only be fixed - return { ss: [value] }; + return { ss: (value || '').split(',') }; } }; @@ -77,39 +100,45 @@ const generateComponentCellCode = (component: ComponentSpec, config: Value) => { const { input, output, ...others } = config; // attr - Object.entries(others).forEach(([key, value]) => { - componentConfig.attr_paths.push(key); - const attrValue = getAttrValue(component, key, value); - componentConfig.attrs.push(attrValue); - }); + if (others) { + Object.entries(others).forEach(([key, value]) => { + componentConfig.attr_paths.push(key); + const attrValue = getAttrValue(component, key, value); + componentConfig.attrs.push(attrValue); + }); + } // input // eslint-disable-next-line @typescript-eslint/no-explicit-any - Object.entries(input).forEach(([key, value]: [string, any]) => { - const { type, tables } = value; - - if (type && tables) { - componentConfig.inputs.push({ - name: key, - type: type, - data_refs: tables.data_ref.map((ref: any) => ({ - uri: ref.uri, - party: ref.party, - format: 'csv', - })), - meta: { - '@type': getIOMetaType(type), - schema: tables.schema, - line_count: -1, - }, - }); - } - }); + if (input) { + Object.entries(input).forEach(([key, value]: [string, any]) => { + const { type, tables } = value; + const schemaKey = type === 'sf.table.individual' ? 'schema' : 'schemas'; + if (type && tables) { + componentConfig.inputs.push({ + name: key, + type: type, + data_refs: tables.data_ref.map((ref: any) => ({ + uri: ref.uri, + party: ref.party, + format: 'csv', + })), + meta: { + '@type': getIOMetaType(type), + [schemaKey]: tables[schemaKey], + line_count: -1, + }, + }); + } + }); + } // output - Object.entries(output).forEach(([, value]) => { - componentConfig.output_uris.push(value); - }); + if (output) { + Object.entries(output).forEach(([, value]) => { + componentConfig.output_uris.push(value); + }); + } return ` from secretflow.spec.v1.evaluation_pb2 import NodeEvalParam diff --git a/packages/secretnote/src/modules/component-cell/generate-code.ts b/packages/secretnote/src/modules/component-cell/generate-code.ts deleted file mode 100644 index 0328553c..00000000 --- a/packages/secretnote/src/modules/component-cell/generate-code.ts +++ /dev/null @@ -1,144 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import type { ComponentSpec, Value, IOType } from '@/components/component-form'; - -const clusterConfig = { - public_config: { - ray_fed_config: { - parties: ['alice', 'bob'], - addresses: ['alice:8000', 'bob:8000'], - }, - spu_configs: [ - { - name: 'spu', - parties: ['alice', 'bob'], - addresses: ['alice:8001', 'bob:8001'], - }, - ], - }, - private_config: { self_party: '{self_party}', ray_head_addr: '127.0.0.1:6379' }, - desc: { - parties: ['alice', 'bob'], - devices: [ - { - name: 'spu', - type: 'spu', - parties: ['alice', 'bob'], - config: - '{"runtime_config":{"protocol":"REF2K","field":"FM64"},"link_desc":{"connect_retry_times":60,"connect_retry_interval_ms":1000,"brpc_channel_protocol":"http","brpc_channel_connection_type":"pooled","recv_timeout_ms":1200000,"http_timeout_ms":1200000}}', - }, - ], - }, -}; - -const getAttrValue = (key: string, value: any) => { - const type = typeof value; - - if (key.startsWith('input/')) { - return { ss: [value] }; - } - - if (type === 'string') { - return { s: value }; - } else if (type === 'number') { - return { i64: value }; - } else if (type === 'boolean') { - return { b: value }; - } - - return { s: value }; -}; - -const getInputMetaType = (type: IOType) => { - if (type === 'sf.table.individual') { - return 'type.googleapis.com/secretflow.spec.v1.IndividualTable'; - } - return ''; -}; - -const generateComponentCode = (component?: ComponentSpec, config?: Value) => { - if (!(component && config)) { - return ''; - } - - const componentConfig: any = { - domain: component.domain, - name: component.name, - version: component.version, - attr_paths: [], - attrs: [], - inputs: [], - output_uris: [], - }; - - const { input, output, ...others } = config; - - // attr - Object.entries(others).forEach(([key, value]) => { - componentConfig.attr_paths.push(key); - const attrValue = getAttrValue(key, value); - componentConfig.attrs.push(attrValue); - }); - - // input - // eslint-disable-next-line @typescript-eslint/no-explicit-any - Object.entries(input).forEach(([key, value]: [string, any]) => { - const { type, tables } = value; - - if (type && tables) { - componentConfig.inputs.push({ - name: key, - type: type, - data_refs: tables.data_ref.map((ref: any) => ({ - uri: ref.uri, - party: ref.party, - format: 'csv', - })), - meta: { - '@type': getInputMetaType(type), - schema: tables.schema, - line_count: -1, - }, - }); - } - }); - - // output - Object.entries(output).forEach(([, value]) => { - componentConfig.output_uris.push(value); - }); - - return ` - from secretflow.spec.v1.evaluation_pb2 import NodeEvalParam - from secretflow.spec.extend.cluster_pb2 import SFClusterConfig - from secretflow.component.entry import comp_eval - from google.protobuf.json_format import Parse - from secretflow.spec.v1.data_pb2 import StorageConfig - import os - - cluster_config_str = r""" - ${JSON.stringify(clusterConfig)} - """ - - - component_config_str = r""" - ${JSON.stringify(componentConfig)} - """ - - self_party = os.getenv("SELF_PARTY", "alice") - cluster_config = SFClusterConfig() - Parse(cluster_config_str.replace('{self_party}', self_party), cluster_config) - - node_eval_config = NodeEvalParam() - Parse(component_config_str, node_eval_config) - - storage_config = StorageConfig( - type="local_fs", - local_fs=StorageConfig.LocalFSConfig(wd="/home/vscode/examples"), - ) - - res = comp_eval(node_eval_config, storage_config, cluster_config) - - print(f"The execution is complete and the result is: \\n{res}") - `; -}; -export { generateComponentCode }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 978e3b2e..76b9d6a1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -91,10 +91,10 @@ importers: '@antv/s2': ^1.52.0 '@codemirror/lang-python': ^6.1.2 '@difizen/libro-jupyter': ^0.1.14 - '@difizen/mana-app': ^0.1.8 - '@difizen/mana-common': ^0.1.8 - '@difizen/mana-l10n': ^0.1.8 - '@difizen/mana-react': ^0.1.8 + '@difizen/mana-app': ^0.1.9 + '@difizen/mana-common': ^0.1.9 + '@difizen/mana-l10n': ^0.1.9 + '@difizen/mana-react': ^0.1.9 '@kanaries/web-data-loader': ^0.1.7 '@lumino/polling': ^1.11.4 '@rjsf/antd': ^5.7.3 @@ -132,7 +132,6 @@ importers: d3-dsv: ^3.0.1 endent: ^2.1.0 highlight.js: ^11.9.0 - highlightjs-line-numbers.js: ^2.8.0 lodash-es: ^4.17.21 lucide-react: ^0.284.0 monaco-editor: ^0.45.0 @@ -186,7 +185,6 @@ importers: d3-dsv: 3.0.1 endent: 2.1.0 highlight.js: 11.9.0 - highlightjs-line-numbers.js: 2.8.0 lodash-es: 4.17.21 lucide-react: 0.284.0 monaco-editor: 0.45.0 @@ -6066,7 +6064,7 @@ packages: prop-types: 15.8.1 react: 16.14.0 react-dom: 16.14.0_react@16.14.0 - react-is: 16.13.1 + react-is: 17.0.2 dev: false /@mdx-js/loader/1.5.1_react@16.14.0: @@ -17660,19 +17658,6 @@ packages: peerDependenciesMeta: debug: optional: true - dev: true - - /follow-redirects/1.15.5_debug@4.3.4: - resolution: {integrity: sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - dependencies: - debug: 4.3.4_supports-color@6.1.0 - dev: false /font-atlas/2.1.0: resolution: {integrity: sha512-kP3AmvX+HJpW4w3d+PiPR2X6E1yvsBXt2yhuCw+yReO9F1WYhvZwx3c95DGZGwg9xYzDGrgJYa885xmVA+28Cg==} @@ -19067,10 +19052,6 @@ packages: deprecated: Version no longer supported. Upgrade to @latest dev: false - /highlightjs-line-numbers.js/2.8.0: - resolution: {integrity: sha512-TEf1gw0c8mb8nan0QwliqS7obT4cpUd9hzsGzsZLweteNnWea/VIqy5/aQqsa5wnz9lnvmtAkS1ZtDTjB/goYQ==} - dev: false - /history/4.10.1: resolution: {integrity: sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==} dependencies: @@ -19345,7 +19326,7 @@ packages: engines: {node: '>=8.0.0'} dependencies: eventemitter3: 4.0.7 - follow-redirects: 1.15.5_debug@4.3.4 + follow-redirects: 1.15.5 requires-port: 1.0.0 transitivePeerDependencies: - debug @@ -19356,7 +19337,7 @@ packages: engines: {node: '>=8.0.0'} dependencies: eventemitter3: 4.0.7 - follow-redirects: 1.15.5_debug@4.3.4 + follow-redirects: 1.15.5 requires-port: 1.0.0 transitivePeerDependencies: - debug @@ -28081,7 +28062,6 @@ packages: /react-is/17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} - dev: true /react-is/18.1.0: resolution: {integrity: sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==}