Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(console): support dynamic vars & form columns field #1562

Merged
merged 4 commits into from
Nov 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion console/packages/starwhale-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"base64-js": "^1.5.1",
"eventemitter3": "^4.0.7",
"history": "4.10.1",
"klona": "^2.0.5",
"lodash": "4.17.21",
"rxjs": "^7.5.7",
"tsc": "^2.0.4",
Expand Down Expand Up @@ -79,4 +80,4 @@
"react": "17.0.2",
"react-dom": "17.0.2"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ import React, { Context, createContext, useContext } from 'react'
import { createCustomStore } from '../store/store'
import { EventBus } from '../events/types'

export type StoreType = ReturnType<typeof createCustomStore>

export type EditorContextType = {
store: ReturnType<typeof createCustomStore>
store: StoreType
eventBus: EventBus
dynamicVars: Record<string, any>
}
type EditorContextProviderProps = {
value: any
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,34 @@ import React, { useEffect, useMemo } from 'react'

export default function useDatastoreTables(projectName: string, jobUuid: string) {
const queryAllTables = useMemo(() => {
if (!projectName || !jobUuid) return ''
if (!projectName || !jobUuid) return
return {
prefix: tablesOfEvaluation(projectName, jobUuid),
}
}, [projectName, jobUuid])
const allTables = useListDatastoreTables(queryAllTables)

return useDatastoreTablesByPrefix(queryAllTables?.prefix as string)
}

export function useDatastoreTablesByPrefix(prefix: string) {
const allTables = useListDatastoreTables({ prefix })

useEffect(() => {
if (projectName && jobUuid) {
if (prefix) {
allTables.refetch()
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [projectName, jobUuid])
}, [prefix])

const tables = React.useMemo(() => {
// const names = []
// if (projectName) names.push(tableNameOfSummary(projectName))

return [
// ...names,
// @FIXME hard code remove results
...(allTables.data?.tables?.sort((a, b) => (a > b ? 1 : -1)).filter((v) => !v.includes('results')) ?? []),
]
}, [allTables, projectName])
return allTables.data?.tables?.sort((a, b) => (a > b ? 1 : -1)).filter((v) => !v.includes('results')) ?? []
}, [allTables])

return {
names: tables,
tables: tables.map((table) => {
// @FIXME hard code remove summary replace
const short = table.replace(`${tablesOfEvaluation(projectName, jobUuid)}/`, '')
// .replace('project/mnist-exp/eval/', '')
return {
short,
short: table.replace(`${prefix}`, ''),
name: table,
}
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export function useScanDatastore(query: any, enabled = false) {
export function useQueryDatastore(query: any, enabled = false) {
const info = useQuery(`queryDatastore:${qs.stringify(query)}`, () => queryTable(query), {
refetchOnWindowFocus: false,
enabled,
enabled: !!query?.tableName,
})
return info
}
Expand Down
2 changes: 1 addition & 1 deletion console/packages/starwhale-core/src/datastore/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export function tableNameOfSummary(projectName: string) {
return `project/${projectName}/eval/summary`
}

export function tablesOfEvaluation(projectName: string, evaluationUuid: string) {
export function tablesOfEvaluation(projectName: string, evaluationUuid: string = '') {
return `project/${projectName}/eval/${evaluationUuid.substring(0, VERSION_PREFIX_CNT)}/${evaluationUuid}`
}

Expand Down
79 changes: 2 additions & 77 deletions console/packages/starwhale-core/src/form/WidgetForm.tsx
Original file line number Diff line number Diff line change
@@ -1,85 +1,10 @@
import Widgets from '@starwhale/ui/form/widgets'
import Form from '@rjsf/core'
import { RegistryWidgetsType, RJSFSchema, UiSchema } from '@rjsf/utils'
import validator from '@rjsf/validator-ajv8'
import React from 'react'
import { useJob } from '@/domain/job/hooks/useJob'
import { useProject } from '@/domain/project/hooks/useProject'
import useDatastoreTables from '../datastore/hooks/useDatastoreTables'
import WidgetFactory from '../widget/WidgetFactory'

const uiSchema: UiSchema = {
'tableName': {
'ui:widget': 'SelectWidget',
},
// 'ui:order': ['bar', '*'],
// "ui:options": {
// expandable: false
// }
'ui:submitButtonOptions': {
norender: true,
},
}

// @ts-ignore
function WidgetForm({ formData, onChange, onSubmit }: any, ref: any) {
// 'starwhale', '90138e6fde2a480888531526b7b65dfe'
const { project } = useProject()
const { job } = useJob()
const { tables = [] } = useDatastoreTables(project?.name as string, job?.uuid as string)

const panels = WidgetFactory.getPanels()
if (panels.length === 0) return <></>

const tableName = {
type: 'string',
oneOf:
tables.map((v) => ({
const: v.name,
title: v.short,
})) ?? [],
}
const multiTableName = {
type: 'array',
uniqueItems: true,
items: {
type: 'object',
oneOf:
tables.map((v) => ({
const: v.name,
title: v.short,
})) ?? [],
},
}

const tableNameSchema = tableName // formData.chartType === 'ui:panel:table' ? tableName : multiTableName

// console.log('panels', WidgetFactory.getPanels(), tables, tableNameSchema)

const schema: RJSFSchema = {
// title: 'My title',
// description: 'My description',
type: 'object',
properties: {
chartType: {
type: 'string',
oneOf:
WidgetFactory.getPanels().map((v) => ({
const: v.type,
title: v.name,
})) ?? [],
},
// @ts-ignore
tableName: tables.length === 0 ? undefined : tableNameSchema,
chartTitle: {
type: 'string',
},
},
// "required": ["name"],
// "dependencies": {
// "credit_card": ["billing_address"]
// }
}
function WidgetForm({ formData, onChange, onSubmit, form }: any, ref: any) {
const { schema, uiSchema } = form.schemas
return (
<Form
schema={schema}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,53 +6,71 @@ import { Button } from '@/components/Button'
import { getWidget } from '../store/hooks/useSelector'
import { WidgetRenderer } from '../widget/WidgetRenderer'
import WidgetEditForm from './WidgetForm'
import useDatastoreTables from '../datastore/hooks/useDatastoreTables'
import { StoreType, useEditorContext } from '../context/EditorContextProvider'
import { useDatastoreTablesByPrefix } from '../datastore/hooks/useDatastoreTables'
import WidgetFormModel from './WidgetFormModel'
import useForceUpdate from '../utils/useForceUpdate'
import deepEqual from 'fast-deep-equal'
import { useDeepEffect } from '../../../../src/hooks/useDeepEffects'
import WidgetModel from '../widget/WidgetModel'

export default function WidgetFormModel({
const PAGE_TABLE_SIZE = 100

export default function WidgetFormModal({
store,
handleFormSubmit,
id: editWidgetId = '',
isShow: isPanelModalOpen = false,
setIsShow: setisPanelModalOpen,
}: any) {
setIsShow: setisPanelModalOpen = () => {},
form,
}: {
store: StoreType
form: WidgetFormModel
isShow?: boolean
setIsShow?: any
handleFormSubmit: (args: any) => void
id?: string
}) {
// @FIXME use event bus handle global state
const { dynamicVars } = useEditorContext()
const { prefix } = dynamicVars
const [t] = useTranslation()
const config = store(getWidget(editWidgetId)) ?? {}
const [formData, setFormData] = React.useState({})
const [formData, setFormData] = React.useState<Record<string, any>>({})
const formRef = React.useRef(null)

const handleFormChange = (formData: any) => setFormData(formData)
const handleFormChange = (formData: any) => {
setFormData(formData)
}

// @ts-ignore
const type = formData?.chartType
// @ts-ignore
const tableName = Array.isArray(formData?.tableName) ? formData?.tableName[0] : formData?.tableName
const filter = undefined
const PAGE_TABLE_SIZE = 100

const query = React.useMemo(
() => ({
const query = React.useMemo(() => {
// @ts-ignore
const tableName = Array.isArray(formData?.tableName) ? formData?.tableName[0] : formData?.tableName
return {
tableName,
start: 0,
limit: PAGE_TABLE_SIZE,
rawResult: true,
ignoreNonExistingTable: true,
// filter,
}),
[tableName]
)
}
}, [formData?.tableName])

const info = useQueryDatastore(query, false)
const { tables } = useDatastoreTablesByPrefix(prefix)
const info = useQueryDatastore(query)

useEffect(() => {
if (tableName) info.refetch()
}, [tableName, type])
if (formData?.chartType && form?.widget?.type !== formData?.chartType) {
form.setWidget(new WidgetModel({ type: formData.chartType }))
}
form.addDataTableNamesField(tables)
form.addDataTableColumnsField(info.data?.columnTypes)

useEffect(() => {
setFormData(config.fieldConfig?.data ?? {})
}, [editWidgetId])

// console.log('WidgetFormModel', query, info, editWidgetId)

const formRef = React.useRef(null)
console.log('WidgetFormModel', form, formData)

return (
<Modal
Expand Down Expand Up @@ -106,12 +124,19 @@ export default function WidgetFormModel({
}}
>
{/* @ts-ignore */}
<WidgetRenderer type={type} data={info.data} />
<WidgetRenderer
type={type}
data={info.data}
fieldConfig={{
data: formData,
}}
/>
</div>
)}
</div>
<WidgetEditForm
ref={formRef}
form={form}
formData={formData}
onChange={handleFormChange}
onSubmit={handleFormSubmit}
Expand Down
Loading