Skip to content
Draft
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
2 changes: 1 addition & 1 deletion data/export-v3/admin/atoms/AntDesignSpace.json
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@
"allowedValues": [
{
"id": "7bb7803a-134e-4830-ae50-454ca9c534d0",
"key": "baseline",
"key": "Baseline",
"value": "baseline"
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,21 @@
import type { IFieldCreateData } from '@codelab/shared/abstract/core'

import { type IFormController, UiKey } from '@codelab/frontend/abstract/types'
import { SelectDefaultValue } from '@codelab/frontend/presentation/components/interface-form'
import { SelectFieldSibling } from '@codelab/frontend/presentation/components/interface-form'
import { useDomainStore } from '@codelab/frontend-infra-mobx/context'
import {
DisplayIfField,
Form,
FormController,
} from '@codelab/frontend-presentation-components-form'
import { DisplayIf } from '@codelab/frontend-presentation-view/components/conditionalView'
import { PrimitiveTypeKind } from '@codelab/shared/infra/gqlgen'
import { observer } from 'mobx-react-lite'
import { AutoFields } from 'uniforms-antd'
import { useState } from 'react'
import { AutoField, AutoFields } from 'uniforms-antd'
import { v4 } from 'uuid'

import { useFieldService } from '../../services'
import { useFieldSchema } from '../hooks'
import { useFieldFormSchema } from '../hooks'
import { TypeSelect } from '../select-types'
import { createFieldSchema } from './create-field.schema'
import {
canSetDefaultValue,
filterValidationRules,
Expand All @@ -35,10 +33,18 @@ interface CreateFieldFormProps extends IFormController {
}

export const CreateFieldForm = observer<CreateFieldFormProps>(
({ interfaceId, onSubmitSuccess, showFormControl = true, submitRef }) => {
({ interfaceId, onSubmitSuccess, submitRef }) => {
const fieldService = useFieldService()
const { typeDomainService } = useDomainStore()
const fieldSchema = useFieldSchema(createFieldSchema)

const [fieldModel, setFieldModel] = useState<IFieldCreateData>({
fieldType: '',
id: v4(),
interfaceTypeId: interfaceId,
key: '',
})

const schema = useFieldFormSchema(fieldModel)

const onSubmit = (input: IFieldCreateData) => {
const validationRules = filterValidationRules(
Expand All @@ -52,46 +58,23 @@ export const CreateFieldForm = observer<CreateFieldFormProps>(
return (
<Form<IFieldCreateData>
errorMessage="Error while creating field"
model={{
id: v4(),
interfaceTypeId: interfaceId,
}}
modelTransform={(mode, model) => {
// This automatically sets the `defaultValue` to be nullable for types
// where we dont set a default value like ReactNodeType, InterfaceType
if (
mode === 'form' &&
model.fieldType &&
!canSetDefaultValue(typeDomainService, model.fieldType)
) {
return {
...model,
validationRules: {
general: {
nullable: true,
},
},
}
}

return model
model={fieldModel}
onChangeModel={(model) => {
setFieldModel({ ...fieldModel, ...model })
}}
onSubmit={onSubmit}
onSubmitSuccess={onSubmitSuccess}
schema={fieldSchema}
schema={schema}
submitRef={submitRef}
successMessage="Field created successfully"
uiKey={UiKey.FieldFormCreate}
>
<AutoFields
omitFields={[
'fieldType',
'validationRules',
'interfaceTypeId',
'defaultValues',
]}
/>
<AutoFields fields={['id', 'key', 'name', 'description']} />
<TypeSelect label="Type" name="fieldType" />
<SelectFieldSibling
field={{ ...fieldModel, api: { id: fieldModel.interfaceTypeId } }}
name="prevSibling"
/>
<DisplayIfField<IFieldCreateData>
condition={({ model }) =>
!isBoolean(typeDomainService, model.fieldType) &&
Expand Down Expand Up @@ -138,12 +121,8 @@ export const CreateFieldForm = observer<CreateFieldFormProps>(
canSetDefaultValue(typeDomainService, model.fieldType)
}
>
<SelectDefaultValue />
<AutoField name="defaultValues" />
</DisplayIfField>

<DisplayIf condition={showFormControl}>
<FormController submitLabel="Create Field" />
</DisplayIf>
</Form>
)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ export const CreateFieldPopover = ({ context }: CreateFieldPopoverProps) => {
<CreateFieldForm
interfaceId={interfaceId}
onSubmitSuccess={closePopover}
showFormControl={false}
submitRef={submitRef}
/>
</CuiSidebarSecondary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,18 @@ import {
import { PrimitiveTypeKind } from '@codelab/shared/infra/gqlgen'

export const createFieldSchema: JSONSchemaType<IFieldCreateData> = {
if: {
properties: {
validationRules: {
properties: {
general: {
properties: {
// Using enum, we can check if it matches the current value in the form
[GeneralValidationRules.Nullable]: { const: false },
},
},
},
},
},
},
properties: {
...idSchema(),
defaultValues: {
// by using ref, this can support array or object type that
// has items or properties of any possible default value type
$ref: 'customTypes#/definitions/fieldDefaultValuesOrNullableFieldDefaultValues',
type: 'string',
nullable: true,
},
description: { nullable: true, type: 'string' },
/**
* TODO: Refactor to match interface
* Could somehow modify the form so we can accept an object of TypeRef, then the interface would match up better
*/
fieldType: { type: 'string' },
fieldType: { ...nonEmptyString },
interfaceTypeId: {
type: 'string',
uniforms: {
Expand All @@ -60,7 +45,6 @@ export const createFieldSchema: JSONSchemaType<IFieldCreateData> = {
disabled: false,
}),
},
label: '',
required: [],
type: 'object',
},
Expand All @@ -69,9 +53,10 @@ export const createFieldSchema: JSONSchemaType<IFieldCreateData> = {
properties: {
general: {
nullable: true,
label: '',
properties: {
[GeneralValidationRules.Nullable]: {
default: false,
default: true,
nullable: true,
type: 'boolean',
},
Expand All @@ -80,6 +65,7 @@ export const createFieldSchema: JSONSchemaType<IFieldCreateData> = {
},
[PrimitiveTypeKind.String]: {
nullable: true,
label: '',
properties: {
[StringValidationRules.MinLength]: {
nullable: true,
Expand All @@ -95,6 +81,7 @@ export const createFieldSchema: JSONSchemaType<IFieldCreateData> = {
},
[PrimitiveTypeKind.Number]: {
nullable: true,
label: '',
properties: {
[NumberValidationRules.Minimum]: {
nullable: true,
Expand All @@ -121,6 +108,7 @@ export const createFieldSchema: JSONSchemaType<IFieldCreateData> = {
},
[PrimitiveTypeKind.Integer]: {
nullable: true,
label: '',
properties: {
[NumberValidationRules.Minimum]: {
nullable: true,
Expand Down Expand Up @@ -149,16 +137,7 @@ export const createFieldSchema: JSONSchemaType<IFieldCreateData> = {
type: 'object',
},
},
// This is overridden if the field is not nullable, which will require a value for `defaultValues`
required: ['id', 'key', 'fieldType'],
then: {
required: ['id', 'key', 'fieldType'],
properties: {
defaultValues: {
$ref: 'customTypes#/definitions/fieldDefaultValues',
},
},
},
title: 'Create Field Input',
type: 'object',
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ export const canSetDefaultValue: FieldCondition = (
fieldType &&
typeDomainService.types.has(fieldType) &&
typeDomainService.type(fieldType).kind !== ITypeKind.InterfaceType &&
typeDomainService.type(fieldType).kind !== ITypeKind.ReactNodeType &&
typeDomainService.type(fieldType).kind !== ITypeKind.ActionType,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,16 @@ import type {
} from '@codelab/shared/abstract/core'
import type { JSONSchemaType } from 'ajv'

import { uniformSchemaFactory } from '@codelab/frontend/presentation/components/interface-form'
import {
useApplicationStore,
useDomainStore,
} from '@codelab/frontend-infra-mobx/context'
import { useMemo } from 'react'
import { useAsync } from 'react-use'

import { useTypeService } from '../../services/field.service'
import { createFieldSchema } from '../create-field'

/**
* @param schema
Expand Down Expand Up @@ -43,3 +48,45 @@ export const useFieldSchema = (
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [schema, updatedField, storeDomainService.storesList])
}

export const useFieldFormSchema = (
model: IFieldCreateData,
): JSONSchemaType<IFieldCreateData | IFieldUpdateData> => {
const { typeDomainService } = useDomainStore()
const typeService = useTypeService()
const fieldSchema = useFieldSchema(createFieldSchema)

const { value: fieldTypeModel } = useAsync(async () => {
if (!model.fieldType) {
return null
}

return typeDomainService.types.has(model.fieldType)
? typeDomainService.type(model.fieldType)
: await typeService.getOne(model.fieldType)
}, [model.fieldType])

const schema = useMemo(() => {
return {
...fieldSchema,
properties: {
...fieldSchema.properties,
...(fieldTypeModel
? {
defaultValues: fieldTypeModel.toJsonSchema({
fieldName: 'Default Value',
uniformSchema: uniformSchemaFactory,
validationRules: model.validationRules,
}),
}
: null),
},
required:
model.validationRules?.general?.nullable === false
? ['id', 'key', 'fieldType', 'defaultValues']
: ['id', 'key', 'fieldType'],
}
}, [fieldTypeModel, model.validationRules])

return schema as JSONSchemaType<IFieldCreateData | IFieldUpdateData>
}
Loading