form-craft-package 1.3.0 → 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/components/form/1-list/header.tsx +85 -26
- package/src/components/form/1-list/index.tsx +2 -2
- package/src/components/form/1-list/table.tsx +8 -4
- package/src/components/form/2-details/index.tsx +10 -2
- package/src/components/form/layout-renderer/3-element/7-file-upload.tsx +3 -2
- package/src/components/form/layout-renderer/3-element/8-fields-with-options.tsx +30 -8
- package/src/components/form/layout-renderer/3-element/9-form-data-render.tsx +23 -10
- package/src/enums.ts +2 -0
- package/src/functions/index.ts +6 -1
- package/src/types/data-list/filter-config.ts +29 -0
- package/src/types/data-list/index.ts +2 -9
package/package.json
CHANGED
|
@@ -1,55 +1,78 @@
|
|
|
1
1
|
import { Form } from 'antd'
|
|
2
|
-
import { ReactNode, useEffect, useState } from 'react'
|
|
2
|
+
import { ReactNode, useCallback, useEffect, useState } from 'react'
|
|
3
3
|
import dayjs from 'dayjs'
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
IFilterByAuthUser,
|
|
6
|
+
IFilterByLinkedForm,
|
|
7
|
+
IFilterConfig,
|
|
8
|
+
IFilterCustom,
|
|
9
|
+
IFilterNested,
|
|
10
|
+
IFilterSimple,
|
|
11
|
+
IFormData,
|
|
12
|
+
IFormLayoutRow,
|
|
13
|
+
} from '../../../types'
|
|
5
14
|
import { extractFiltersFromLayout } from '../../../functions'
|
|
6
15
|
import { FilterConfigTypeEnum, FormPreservedItemKeys } from '../../../enums'
|
|
7
16
|
import { LayoutRendererRow } from '../layout-renderer/1-row'
|
|
8
17
|
import { VALUE_REPLACEMENT_PLACEHOLDER } from '../../../constants'
|
|
9
18
|
import { DynamicFormButtonRender, ICustomFunctionCall } from '../layout-renderer/3-element/1-dynamic-button'
|
|
10
19
|
import { DEFAULT_NO_FILTER, DEFAULT_NO_SORTER, DEFAULT_PAGINATION, IConstantValues, IReqDataConfig } from './table'
|
|
20
|
+
import client from '../../../functions/axios-handler'
|
|
11
21
|
|
|
12
22
|
export default function FormDataListHeaderComponent({
|
|
13
23
|
layout,
|
|
14
24
|
titleComponent,
|
|
15
25
|
defaultFilter,
|
|
26
|
+
startLoading,
|
|
16
27
|
updateReqData,
|
|
17
28
|
onCustomFunctionCall,
|
|
18
29
|
...constantValues
|
|
19
30
|
}: IFormDataListHeaderComponent) {
|
|
20
31
|
const [dataListHeaderFormRef] = Form.useForm()
|
|
21
32
|
const [filterConfigs, setFilterConfigs] = useState<IFilterNested>({})
|
|
22
|
-
const { userId, formId } = constantValues
|
|
33
|
+
const { userId, formId, formDataId } = constantValues
|
|
23
34
|
|
|
24
35
|
const filterValues = Form.useWatch([], dataListHeaderFormRef)
|
|
25
36
|
|
|
26
37
|
useEffect(() => {
|
|
27
|
-
if (dataListHeaderFormRef)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
if (dataListHeaderFormRef)
|
|
39
|
+
dataListHeaderFormRef.setFieldsValue({
|
|
40
|
+
[FormPreservedItemKeys.FormId]: formId,
|
|
41
|
+
[FormPreservedItemKeys.FormDataId]: formDataId,
|
|
42
|
+
[FormPreservedItemKeys.InPreviewMode]: false,
|
|
43
|
+
})
|
|
44
|
+
}, [dataListHeaderFormRef, formId, formDataId])
|
|
45
|
+
|
|
46
|
+
useEffect(() => setFilterConfigs(extractFiltersFromLayout(layout)), [layout])
|
|
47
|
+
|
|
48
|
+
const organizeFilterData = useCallback(
|
|
49
|
+
async (values: { [key: string]: any }) => {
|
|
50
|
+
const filtersWithConfig: [string, string][] = Object.entries(values).filter(
|
|
37
51
|
([field, value]) => !!value && !!filterConfigs[field],
|
|
38
52
|
)
|
|
39
53
|
|
|
40
54
|
if (filtersWithConfig.length > 0) {
|
|
41
|
-
const filtersToApply =
|
|
55
|
+
const filtersToApply = []
|
|
56
|
+
for (const filterConfig of filtersWithConfig) {
|
|
57
|
+
const [field, value] = filterConfig
|
|
42
58
|
const config = filterConfigs[field]
|
|
43
59
|
|
|
44
|
-
if ('type' in config)
|
|
45
|
-
|
|
60
|
+
if ('type' in config) {
|
|
61
|
+
if (config.type === FilterConfigTypeEnum.ByLinkedForm) startLoading()
|
|
62
|
+
|
|
63
|
+
const filterData = await handleFilterValues(config as IFilterConfig, value, userId)
|
|
64
|
+
filtersToApply.push(filterData)
|
|
65
|
+
} else {
|
|
46
66
|
// cases like radio buttons, where each has its own filter, but only 1 needs to apply
|
|
47
67
|
const nestedConfig = config as IFilterSimple
|
|
48
68
|
const eachConfig = nestedConfig[value as string]
|
|
49
69
|
|
|
50
|
-
|
|
70
|
+
if (eachConfig.type === FilterConfigTypeEnum.ByLinkedForm) startLoading()
|
|
71
|
+
|
|
72
|
+
const filterData = await handleFilterValues(eachConfig as IFilterConfig, value, userId)
|
|
73
|
+
filtersToApply.push(filterData)
|
|
51
74
|
}
|
|
52
|
-
}
|
|
75
|
+
}
|
|
53
76
|
|
|
54
77
|
const { customFilter, dynamicFilter } = filtersToApply.reduce(
|
|
55
78
|
(curr, next) => {
|
|
@@ -79,11 +102,14 @@ export default function FormDataListHeaderComponent({
|
|
|
79
102
|
dynamicFilter: JSON.stringify(dynamicFilter),
|
|
80
103
|
}
|
|
81
104
|
})
|
|
82
|
-
} else
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
105
|
+
} else updateReqData(defaultFilter)
|
|
106
|
+
},
|
|
107
|
+
[filterConfigs],
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
useEffect(() => {
|
|
111
|
+
if (filterValues) organizeFilterData(filterValues)
|
|
112
|
+
}, [filterValues])
|
|
87
113
|
|
|
88
114
|
return (
|
|
89
115
|
<Form layout="vertical" form={dataListHeaderFormRef}>
|
|
@@ -112,10 +138,31 @@ type IFormDataListHeaderComponent = {
|
|
|
112
138
|
updateReqData: React.Dispatch<React.SetStateAction<IReqDataConfig | undefined>>
|
|
113
139
|
titleComponent?: ReactNode
|
|
114
140
|
defaultFilter: IReqDataConfig
|
|
141
|
+
startLoading: () => void
|
|
115
142
|
} & ICustomFunctionCall &
|
|
116
143
|
IConstantValues
|
|
117
144
|
|
|
118
|
-
const
|
|
145
|
+
const getLinkedFormFilter = async (
|
|
146
|
+
config: IFilterByLinkedForm,
|
|
147
|
+
parentDataIds: string[],
|
|
148
|
+
lastRelIndex: number,
|
|
149
|
+
): Promise<{ dataIds: string[]; foreignKey: string }> => {
|
|
150
|
+
const lastRel = config.relationshipPath[lastRelIndex]
|
|
151
|
+
|
|
152
|
+
if (lastRelIndex - 1 >= 0) {
|
|
153
|
+
const childOfLastRel = config.relationshipPath[lastRelIndex - 1]
|
|
154
|
+
const childFormDataRes = await client.post(`/api/formdata/list/${childOfLastRel.formId}`, {
|
|
155
|
+
dynamicFilter: JSON.stringify({ [`Data.${lastRel.foreignKey}`]: { $in: parentDataIds } }),
|
|
156
|
+
})
|
|
157
|
+
if (childFormDataRes.status === 200) {
|
|
158
|
+
const childDataIds = childFormDataRes.data.data.map((d: IFormData) => d.id)
|
|
159
|
+
|
|
160
|
+
return getLinkedFormFilter(config, childDataIds, lastRelIndex - 1)
|
|
161
|
+
} else return { dataIds: parentDataIds, foreignKey: childOfLastRel.foreignKey }
|
|
162
|
+
} else return { dataIds: parentDataIds, foreignKey: lastRel.foreignKey }
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const handleFilterValues = async (config: IFilterConfig, value: any, userId?: string | number) => {
|
|
119
166
|
if (config.type === FilterConfigTypeEnum.NoFilter) return DEFAULT_NO_FILTER
|
|
120
167
|
|
|
121
168
|
const isDate = dayjs(value as Date).isValid()
|
|
@@ -124,12 +171,24 @@ const handleFilterValues = (config: IFilterConfig, value: any, userId?: string |
|
|
|
124
171
|
let customFilters = {}
|
|
125
172
|
if (config.type === FilterConfigTypeEnum.ByAuthUser) customFilters = { createdById: userId }
|
|
126
173
|
|
|
127
|
-
if (
|
|
128
|
-
|
|
174
|
+
if (
|
|
175
|
+
[FilterConfigTypeEnum.ByAuthUser, FilterConfigTypeEnum.Custom].includes(config.type) &&
|
|
176
|
+
(config as IFilterByAuthUser | IFilterCustom).config
|
|
177
|
+
) {
|
|
178
|
+
let stringifiedFilter = JSON.stringify((config as IFilterByAuthUser | IFilterCustom).config)
|
|
129
179
|
stringifiedFilter = stringifiedFilter
|
|
130
180
|
.replaceAll(VALUE_REPLACEMENT_PLACEHOLDER, (value as string).trim())
|
|
131
181
|
.replaceAll('@', '$')
|
|
132
182
|
|
|
133
183
|
return { customFilter: customFilters, dynamicFilter: stringifiedFilter }
|
|
134
184
|
}
|
|
185
|
+
|
|
186
|
+
if (config.type === FilterConfigTypeEnum.ByLinkedForm && value) {
|
|
187
|
+
const finalFilter = await getLinkedFormFilter(config, [value], config.relationshipPath.length - 1)
|
|
188
|
+
|
|
189
|
+
return {
|
|
190
|
+
customFilter: {},
|
|
191
|
+
dynamicFilter: JSON.stringify({ [`Data.${finalFilter.foreignKey}`]: { $in: finalFilter.dataIds } }),
|
|
192
|
+
}
|
|
193
|
+
}
|
|
135
194
|
}
|
|
@@ -17,7 +17,7 @@ function FormDataListComponent({
|
|
|
17
17
|
const [formData, setFormData] = useState<{ data: IFormData[]; total: number }>({ data: [], total: 0 })
|
|
18
18
|
const [dataListConfig, setDataListConfig] = useState<
|
|
19
19
|
| {
|
|
20
|
-
dataListConfig: IFormDataListConfig
|
|
20
|
+
dataListConfig: IFormDataListConfig & { configForFormId: number }
|
|
21
21
|
detailsLayout: IFormLayoutRow[]
|
|
22
22
|
}
|
|
23
23
|
| undefined
|
|
@@ -33,7 +33,7 @@ function FormDataListComponent({
|
|
|
33
33
|
const parsedData: IFormSchema | null = parseJSON(res.data.data)
|
|
34
34
|
if (parsedData) {
|
|
35
35
|
setDataListConfig({
|
|
36
|
-
dataListConfig: parsedData.dataListConfig,
|
|
36
|
+
dataListConfig: { ...parsedData.dataListConfig, configForFormId: formId },
|
|
37
37
|
detailsLayout: parsedData.detailsConfig.layout,
|
|
38
38
|
})
|
|
39
39
|
}
|
|
@@ -37,7 +37,7 @@ export default function FormDataListTableComponent({
|
|
|
37
37
|
pagination: DEFAULT_PAGINATION,
|
|
38
38
|
})
|
|
39
39
|
|
|
40
|
-
const { attachmentBaseUrl, userId } = constantValues
|
|
40
|
+
const { attachmentBaseUrl, userId, formId } = constantValues
|
|
41
41
|
|
|
42
42
|
useEffect(() => {
|
|
43
43
|
setIsHandlingSchema(true)
|
|
@@ -50,7 +50,9 @@ export default function FormDataListTableComponent({
|
|
|
50
50
|
}, [debouncedFilterReqData])
|
|
51
51
|
|
|
52
52
|
const handleDataListConfig = useCallback(
|
|
53
|
-
async (config: IFormDataListConfig, layout: IFormLayoutRow[] = []) => {
|
|
53
|
+
async (config: IFormDataListConfig & { configForFormId?: number }, layout: IFormLayoutRow[] = []) => {
|
|
54
|
+
if (config.configForFormId && config.configForFormId !== formId) return
|
|
55
|
+
|
|
54
56
|
const {
|
|
55
57
|
elements = [],
|
|
56
58
|
header = { layout: [] },
|
|
@@ -93,7 +95,7 @@ export default function FormDataListTableComponent({
|
|
|
93
95
|
setIsHandlingSchema(false)
|
|
94
96
|
isFinishedHandlingRef.current = true
|
|
95
97
|
},
|
|
96
|
-
[attachmentBaseUrl, userId],
|
|
98
|
+
[attachmentBaseUrl, userId, formId],
|
|
97
99
|
)
|
|
98
100
|
|
|
99
101
|
useEffect(() => {
|
|
@@ -112,6 +114,7 @@ export default function FormDataListTableComponent({
|
|
|
112
114
|
setParentLoading(true)
|
|
113
115
|
setFilterReqData(req)
|
|
114
116
|
}}
|
|
117
|
+
startLoading={() => setParentLoading(true)}
|
|
115
118
|
defaultFilter={defaultFilterRef.current}
|
|
116
119
|
titleComponent={
|
|
117
120
|
<>
|
|
@@ -162,7 +165,7 @@ export default function FormDataListTableComponent({
|
|
|
162
165
|
}
|
|
163
166
|
|
|
164
167
|
type IFormDataListTableComponent = {
|
|
165
|
-
dataListConfig?: IFormDataListConfig
|
|
168
|
+
dataListConfig?: IFormDataListConfig & { configForFormId?: number }
|
|
166
169
|
detailsLayout?: IFormLayoutRow[]
|
|
167
170
|
dataList: { data: IFormData[]; total: number }
|
|
168
171
|
parentLoading: boolean
|
|
@@ -201,4 +204,5 @@ export interface IConstantValues {
|
|
|
201
204
|
userId?: string | number
|
|
202
205
|
formId?: number
|
|
203
206
|
attachmentBaseUrl?: string
|
|
207
|
+
formDataId?: string
|
|
204
208
|
}
|
|
@@ -35,8 +35,16 @@ export default function FormDataDetailsComponent({
|
|
|
35
35
|
}, [isPublic, location, formDataRef])
|
|
36
36
|
|
|
37
37
|
useEffect(() => {
|
|
38
|
-
if (formDataRef)
|
|
39
|
-
|
|
38
|
+
if (formDataRef)
|
|
39
|
+
formDataRef.setFieldsValue({
|
|
40
|
+
[FormPreservedItemKeys.FormId]: formId,
|
|
41
|
+
[FormPreservedItemKeys.FormKey]: formKey,
|
|
42
|
+
[FormPreservedItemKeys.BaseServerUrl]: baseServerUrl,
|
|
43
|
+
[FormPreservedItemKeys.CompanyKey]: companyKey,
|
|
44
|
+
[FormPreservedItemKeys.IsPublic]: isPublic,
|
|
45
|
+
[FormPreservedItemKeys.InPreviewMode]: false,
|
|
46
|
+
})
|
|
47
|
+
}, [formDataRef, formId, formKey, baseServerUrl, companyKey, isPublic, formDataId])
|
|
40
48
|
|
|
41
49
|
const fetchFormData = useCallback(
|
|
42
50
|
(dFormId?: number, dateFields: string[] = []) => {
|
|
@@ -7,8 +7,8 @@ import { IFileUploadElementRules } from '../../../../types'
|
|
|
7
7
|
import { useNotification } from '../../../common/custom-hooks'
|
|
8
8
|
import { FaTrashAlt } from 'react-icons/fa'
|
|
9
9
|
import { saveFile } from '../../../../functions/form'
|
|
10
|
-
import { FormPreservedItemKeys } from '../../../../enums'
|
|
11
10
|
import { IFormItemPath } from '.'
|
|
11
|
+
import { useFormPreservedItemValues } from '../../../common/custom-hooks/use-preserved-form-items.hook'
|
|
12
12
|
|
|
13
13
|
export default function LayoutRenderer_FileUpload({
|
|
14
14
|
formRef,
|
|
@@ -21,7 +21,8 @@ export default function LayoutRenderer_FileUpload({
|
|
|
21
21
|
const { warningModal, confirmModal } = useNotification()
|
|
22
22
|
const [loading, setLoading] = useState(false)
|
|
23
23
|
const savedSignatureBlobName = Form.useWatch(fullPath, formRef)
|
|
24
|
-
|
|
24
|
+
|
|
25
|
+
const { companyKey } = useFormPreservedItemValues(formRef)
|
|
25
26
|
|
|
26
27
|
const deleteSavedFile = useCallback(
|
|
27
28
|
(blobName: string) => {
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { FormInstance } from 'antd'
|
|
2
2
|
import { useCallback, useEffect, useState } from 'react'
|
|
3
|
-
import { IFormLayoutFieldOption, IRadioElement, ISelectElement } from '../../../../types'
|
|
3
|
+
import { IFilterByLinkedFormRelPath, IFormLayoutFieldOption, IRadioElement, ISelectElement } from '../../../../types'
|
|
4
4
|
import { FieldElementOptionSourceEnum } from '../../../../enums'
|
|
5
5
|
import { IFormItemPath } from '.'
|
|
6
6
|
import { LayoutRenderer_FieldElement } from './2-field-element'
|
|
7
7
|
import { fetchFormDataAsLookup } from '../../../../functions'
|
|
8
8
|
import { getElementGeneralizedProps } from '../../../../functions/get-element-props'
|
|
9
|
+
import { useFormPreservedItemValues } from '../../../common/custom-hooks/use-preserved-form-items.hook'
|
|
10
|
+
import { IReqDataConfig } from '../../1-list/table'
|
|
9
11
|
|
|
10
12
|
export default function LayoutRenderer_FieldsWithOptions({
|
|
11
13
|
formRef,
|
|
@@ -16,24 +18,44 @@ export default function LayoutRenderer_FieldsWithOptions({
|
|
|
16
18
|
const [options, setOptions] = useState<{ value: string; label: string }[]>([])
|
|
17
19
|
const props = getElementGeneralizedProps(elementData.props)
|
|
18
20
|
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
+
const { inPreviewMode, formDataId } = useFormPreservedItemValues(formRef)
|
|
22
|
+
|
|
23
|
+
const fetchFormData = useCallback(async (formId: number, field: string, filter?: Partial<IReqDataConfig>) => {
|
|
24
|
+
const formDataResData = await fetchFormDataAsLookup(formId, filter)
|
|
21
25
|
setOptions(
|
|
22
26
|
formDataResData.map((formData) => ({
|
|
23
27
|
value: formData.id,
|
|
24
|
-
label: formData[
|
|
28
|
+
label: formData[field],
|
|
25
29
|
})),
|
|
26
30
|
)
|
|
27
31
|
}, [])
|
|
28
32
|
|
|
33
|
+
const fetchLinkedFormData = useCallback(
|
|
34
|
+
async (relationshipPath: IFilterByLinkedFormRelPath[] = []) => {
|
|
35
|
+
const lastPath = relationshipPath[relationshipPath.length - 1]
|
|
36
|
+
|
|
37
|
+
if (lastPath && lastPath.field)
|
|
38
|
+
fetchFormData(lastPath.formId, lastPath.field, {
|
|
39
|
+
dynamicFilter: JSON.stringify(
|
|
40
|
+
lastPath.parentForeignKey && formDataId
|
|
41
|
+
? { [`Data.${lastPath.parentForeignKey}`]: { $eq: formDataId } }
|
|
42
|
+
: {},
|
|
43
|
+
),
|
|
44
|
+
})
|
|
45
|
+
},
|
|
46
|
+
[formDataId],
|
|
47
|
+
)
|
|
48
|
+
|
|
29
49
|
useEffect(() => {
|
|
30
|
-
if (!props.optionSource) return
|
|
50
|
+
if (!props.optionSource || inPreviewMode === undefined) return
|
|
31
51
|
|
|
32
52
|
if (props.optionSource.type === FieldElementOptionSourceEnum.Static)
|
|
33
53
|
setOptions(props.optionSource.options.map((op: IFormLayoutFieldOption) => ({ value: op.id, label: op.value })))
|
|
34
|
-
else if (props.optionSource.type === FieldElementOptionSourceEnum.DynamicForm)
|
|
35
|
-
fetchFormData(props.optionSource.form.id)
|
|
36
|
-
|
|
54
|
+
else if (!inPreviewMode && props.optionSource.type === FieldElementOptionSourceEnum.DynamicForm)
|
|
55
|
+
fetchFormData(props.optionSource.form.id, props.optionSource.form.field)
|
|
56
|
+
else if (!inPreviewMode && props.optionSource.type === FieldElementOptionSourceEnum.LinkedForm)
|
|
57
|
+
fetchLinkedFormData(props.filter.relationshipPath)
|
|
58
|
+
}, [props.optionSource, inPreviewMode, formDataId])
|
|
37
59
|
|
|
38
60
|
return (
|
|
39
61
|
<LayoutRenderer_FieldElement
|
|
@@ -6,11 +6,13 @@ import client from '../../../../functions/axios-handler'
|
|
|
6
6
|
import { useFormPreservedItemValues } from '../../../common/custom-hooks/use-preserved-form-items.hook'
|
|
7
7
|
import FormDataListTableComponent from '../../1-list/table'
|
|
8
8
|
import FormDataListSkeleton_Table from '../../../common/loading-skeletons/table'
|
|
9
|
+
import { NEW_FORM_DATA_IDENTIFIER } from '../../../../constants'
|
|
9
10
|
|
|
10
11
|
export default function LayoutRenderer_FormDataRender({ formRef, elementProps }: ILayoutRenderer_FormDataRender) {
|
|
11
12
|
const { form } = elementProps
|
|
12
13
|
const { formDataId } = useFormPreservedItemValues(formRef)
|
|
13
14
|
const recursiveCallCount = useRef(0)
|
|
15
|
+
const hasInitialFetched = useRef(false)
|
|
14
16
|
const [loading, setLoading] = useState(true)
|
|
15
17
|
const [displayConfig, setDisplayConfig] = useState<
|
|
16
18
|
| {
|
|
@@ -59,7 +61,7 @@ export default function LayoutRenderer_FormDataRender({ formRef, elementProps }:
|
|
|
59
61
|
const childFormDataRes = await client.post(`/api/formdata/list/${childFormId}`, {
|
|
60
62
|
dynamicFilter: JSON.stringify({ [`Data.${relationship.foreignKey}`]: { $in: foreignKeyIds } }),
|
|
61
63
|
})
|
|
62
|
-
if (childFormDataRes.status
|
|
64
|
+
if ((childFormDataRes.status = 200)) {
|
|
63
65
|
const formData = {
|
|
64
66
|
...childFormDataRes.data,
|
|
65
67
|
data: childFormDataRes.data.data.map((d: IFormData) => {
|
|
@@ -70,6 +72,7 @@ export default function LayoutRenderer_FormDataRender({ formRef, elementProps }:
|
|
|
70
72
|
|
|
71
73
|
if (relationship.isRenderChildForm) {
|
|
72
74
|
if (!relationship.renderChildConfig) return
|
|
75
|
+
|
|
73
76
|
const formDataMap: { [id: string]: any } = {}
|
|
74
77
|
const parentDataIds: string[] = []
|
|
75
78
|
|
|
@@ -84,6 +87,7 @@ export default function LayoutRenderer_FormDataRender({ formRef, elementProps }:
|
|
|
84
87
|
parentDataIds,
|
|
85
88
|
formDataMap,
|
|
86
89
|
)
|
|
90
|
+
|
|
87
91
|
return childResData
|
|
88
92
|
} else {
|
|
89
93
|
return {
|
|
@@ -113,24 +117,33 @@ export default function LayoutRenderer_FormDataRender({ formRef, elementProps }:
|
|
|
113
117
|
)
|
|
114
118
|
|
|
115
119
|
useEffect(() => {
|
|
116
|
-
if (
|
|
120
|
+
if (
|
|
121
|
+
!form ||
|
|
122
|
+
!form.relationshipConfig?.formId ||
|
|
123
|
+
!formDataId ||
|
|
124
|
+
formDataId === NEW_FORM_DATA_IDENTIFIER ||
|
|
125
|
+
!formValues
|
|
126
|
+
) {
|
|
117
127
|
setLoading(false)
|
|
118
128
|
return
|
|
119
129
|
}
|
|
120
130
|
|
|
121
|
-
|
|
122
|
-
(
|
|
123
|
-
|
|
131
|
+
if (!hasInitialFetched.current) {
|
|
132
|
+
fetchFormDetails(form.id, form.relationshipConfig.formId, [formDataId], { [formDataId]: formValues }).then(
|
|
133
|
+
(resData) => {
|
|
134
|
+
const { config, data, layout = [] } = resData ?? {}
|
|
124
135
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
136
|
+
if (config) setDisplayConfig({ dataListConfig: config, detailsLayout: layout })
|
|
137
|
+
if (data) setDataList(data)
|
|
138
|
+
},
|
|
139
|
+
)
|
|
140
|
+
hasInitialFetched.current = true
|
|
141
|
+
}
|
|
129
142
|
}, [form, fetchFormDetails, formDataId, formValues])
|
|
130
143
|
|
|
131
144
|
if (!form || !form.relationshipConfig?.formId) return <></>
|
|
132
145
|
|
|
133
|
-
const constantValues = {}
|
|
146
|
+
const constantValues = { formDataId }
|
|
134
147
|
|
|
135
148
|
return (
|
|
136
149
|
<FormDataListTableComponent
|
package/src/enums.ts
CHANGED
|
@@ -126,6 +126,7 @@ export enum ButtonElementSizeEnum {
|
|
|
126
126
|
export enum FieldElementOptionSourceEnum {
|
|
127
127
|
Static = 'Static',
|
|
128
128
|
DynamicForm = 'DynamicForm',
|
|
129
|
+
LinkedForm = 'LinkedForm',
|
|
129
130
|
}
|
|
130
131
|
export enum FormDataListViewTypeEnum {
|
|
131
132
|
Table = 'table',
|
|
@@ -174,6 +175,7 @@ export enum FlexAlignItems {
|
|
|
174
175
|
export enum FilterConfigTypeEnum {
|
|
175
176
|
NoFilter = 'NoFilter',
|
|
176
177
|
ByAuthUser = 'ByAuthUser',
|
|
178
|
+
ByLinkedForm = 'ByLinkedForm',
|
|
177
179
|
Custom = 'Custom',
|
|
178
180
|
}
|
|
179
181
|
export enum TextElementTypeEnum {
|
package/src/functions/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { IReqDataConfig } from '../components/form/1-list/table'
|
|
1
2
|
import { DEFAULT_FLEX_CONFIG } from '../constants'
|
|
2
3
|
import { ElementTypeEnum, FieldElementOptionSourceEnum, FormLayoutNodeEnum, ResponsivenessDeviceEnum } from '../enums'
|
|
3
4
|
import {
|
|
@@ -206,13 +207,17 @@ export const kebabCaseToCamelCase = (cssObject: Record<string, string | number>)
|
|
|
206
207
|
|
|
207
208
|
/** --------------------------------------------------------------------------------------------------------- */
|
|
208
209
|
|
|
209
|
-
export async function fetchFormDataAsLookup(
|
|
210
|
+
export async function fetchFormDataAsLookup(
|
|
211
|
+
formId: number,
|
|
212
|
+
filter: Partial<IReqDataConfig> = {},
|
|
213
|
+
): Promise<(IFormData & { [key: string]: any })[]> {
|
|
210
214
|
try {
|
|
211
215
|
const response = await client.post(`/api/formdata/list/${formId}`, {
|
|
212
216
|
customFilter: {},
|
|
213
217
|
dynamicFilter: JSON.stringify({}),
|
|
214
218
|
pagination: {},
|
|
215
219
|
sorter: {},
|
|
220
|
+
...filter,
|
|
216
221
|
})
|
|
217
222
|
if (response.status === 200)
|
|
218
223
|
return response.data.data.map((formData: IFormData) => ({ ...formData, ...JSON.parse(formData.data) }))
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { FilterConfigTypeEnum } from '../../enums'
|
|
2
|
+
|
|
3
|
+
export type IFilterConfig = INoFilterConfig | IFilterByAuthUser | IFilterByLinkedForm | IFilterCustom
|
|
4
|
+
export interface INoFilterConfig {
|
|
5
|
+
type: FilterConfigTypeEnum.NoFilter
|
|
6
|
+
}
|
|
7
|
+
export interface IFilterByAuthUser {
|
|
8
|
+
type: FilterConfigTypeEnum.ByAuthUser
|
|
9
|
+
config?: { [key: string]: any }
|
|
10
|
+
}
|
|
11
|
+
export interface IFilterByLinkedForm {
|
|
12
|
+
type: FilterConfigTypeEnum.ByLinkedForm
|
|
13
|
+
relationshipPath: IFilterByLinkedFormRelPath[]
|
|
14
|
+
}
|
|
15
|
+
export interface IFilterByLinkedFormRelPath {
|
|
16
|
+
formId: number
|
|
17
|
+
foreignKey: string
|
|
18
|
+
parentForeignKey?: string
|
|
19
|
+
field?: string
|
|
20
|
+
}
|
|
21
|
+
export interface IFilterCustom {
|
|
22
|
+
type: FilterConfigTypeEnum.Custom
|
|
23
|
+
config: { [key: string]: any }
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface IFilterSimple {
|
|
27
|
+
[key: string]: IFilterConfig
|
|
28
|
+
}
|
|
29
|
+
export type IFilterNested = IFilterSimple | { [key: string]: IFilterSimple }
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
export * from './filter-config'
|
|
1
2
|
import { ReactNode } from 'react'
|
|
2
3
|
import { IFormLayoutRow } from '..'
|
|
3
|
-
import { AlignTypeEnum, DataListElementAddTypeEnum
|
|
4
|
+
import { AlignTypeEnum, DataListElementAddTypeEnum } from '../../enums'
|
|
4
5
|
import { IDataRenderConfig } from '../layout-elements'
|
|
5
6
|
|
|
6
7
|
export interface IFormDataListElement {
|
|
@@ -17,14 +18,6 @@ export interface IFormDataListElement {
|
|
|
17
18
|
export interface IFormDataListHeader {
|
|
18
19
|
layout: IFormLayoutRow[]
|
|
19
20
|
}
|
|
20
|
-
export interface IFilterConfig {
|
|
21
|
-
type: FilterConfigTypeEnum
|
|
22
|
-
config?: { [key: string]: any } | null
|
|
23
|
-
}
|
|
24
|
-
export interface IFilterSimple {
|
|
25
|
-
[key: string]: IFilterConfig
|
|
26
|
-
}
|
|
27
|
-
export type IFilterNested = IFilterSimple | { [key: string]: IFilterSimple }
|
|
28
21
|
export interface IFormDataListPagination {
|
|
29
22
|
hasNoPagination?: boolean
|
|
30
23
|
showSizeChanger: boolean
|