setReadOnly metodu eklendi.
This commit is contained in:
parent
57dbb0d308
commit
2df3e359c4
4 changed files with 713 additions and 29 deletions
|
|
@ -2,7 +2,7 @@ import { Button, Dialog } from '@/components/ui'
|
|||
import { SelectBoxOption } from '@/types/shared'
|
||||
import Editor from '@monaco-editor/react'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { FaBolt, FaCheck, FaCode, FaPlus, FaTimes, FaTrash } from 'react-icons/fa'
|
||||
import { FaBolt, FaCheck, FaCode, FaMagic, FaPlus, FaTimes, FaTrash } from 'react-icons/fa'
|
||||
|
||||
type CopyMapping = {
|
||||
id: string
|
||||
|
|
@ -30,8 +30,10 @@ type ConditionalAction = {
|
|||
| 'alert'
|
||||
| 'confirm'
|
||||
| 'calculate'
|
||||
| 'setReadOnly'
|
||||
targetField: string
|
||||
textValue: string
|
||||
booleanValue: 'true' | 'false'
|
||||
apiUrl: string
|
||||
apiMethod: 'GET' | 'POST'
|
||||
responsePath: string
|
||||
|
|
@ -60,6 +62,35 @@ const actionIconCellClass =
|
|||
|
||||
const makeId = () => `${Date.now()}_${Math.random().toString(36).slice(2)}`
|
||||
|
||||
const formatScriptFallback = (source: string) => {
|
||||
const trimmed = source.trim()
|
||||
if (!trimmed) return ''
|
||||
|
||||
let indent = 0
|
||||
return trimmed
|
||||
.replace(/\s*;\s*/g, ';\n')
|
||||
.replace(/\s*\{\s*/g, ' {\n')
|
||||
.replace(/\s*\}\s*/g, '\n}\n')
|
||||
.replace(/\n\s*\n/g, '\n')
|
||||
.split('\n')
|
||||
.map((line) => line.trim())
|
||||
.filter(Boolean)
|
||||
.map((line) => {
|
||||
if (line.startsWith('}')) {
|
||||
indent = Math.max(0, indent - 1)
|
||||
}
|
||||
|
||||
const formattedLine = `${' '.repeat(indent)}${line}`
|
||||
|
||||
if (line.endsWith('{')) {
|
||||
indent += 1
|
||||
}
|
||||
|
||||
return formattedLine
|
||||
})
|
||||
.join('\n')
|
||||
}
|
||||
|
||||
const createConditionalAction = (): ConditionalAction => ({
|
||||
id: makeId(),
|
||||
source: '',
|
||||
|
|
@ -68,6 +99,7 @@ const createConditionalAction = (): ConditionalAction => ({
|
|||
actionType: 'setField',
|
||||
targetField: '',
|
||||
textValue: '',
|
||||
booleanValue: 'true',
|
||||
apiUrl: '',
|
||||
apiMethod: 'GET',
|
||||
responsePath: '',
|
||||
|
|
@ -124,6 +156,7 @@ function isConditionalActionReady(action: ConditionalAction) {
|
|||
if (action.actionType === 'alert' || action.actionType === 'confirm')
|
||||
return Boolean(action.message.trim())
|
||||
if (action.actionType === 'calculate') return Boolean(action.targetField && action.formula.trim())
|
||||
if (action.actionType === 'setReadOnly') return Boolean(action.targetField)
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
@ -233,6 +266,9 @@ function buildScript({
|
|||
const needsRollbackCurrentValue = activeConditionalActions.some(
|
||||
(action) => action.actionType === 'confirm',
|
||||
)
|
||||
const needsSetEditorReadOnly = activeConditionalActions.some(
|
||||
(action) => action.actionType === 'setReadOnly',
|
||||
)
|
||||
|
||||
const lines: string[] = ['(async () => {']
|
||||
|
||||
|
|
@ -269,6 +305,12 @@ function buildScript({
|
|||
)
|
||||
}
|
||||
|
||||
if (needsSetEditorReadOnly) {
|
||||
lines.push(
|
||||
' const setEditorReadOnly = (field, readOnly) => { if (typeof runtimeSetEditorReadOnly === "function") runtimeSetEditorReadOnly(field, readOnly); };',
|
||||
)
|
||||
}
|
||||
|
||||
activeCopyMappings.forEach((mapping) => {
|
||||
const source = mapping.source.includes('.')
|
||||
? `getByPath(selectedItem, ${quote(mapping.source)})`
|
||||
|
|
@ -345,6 +387,16 @@ function buildScript({
|
|||
|
||||
activeConditionalActions.forEach((action) => {
|
||||
const condition = buildGenericCondition(action)
|
||||
|
||||
if (action.actionType === 'setReadOnly' && action.targetField) {
|
||||
const enabledValue = action.booleanValue === 'true'
|
||||
const readOnlyExpression = enabledValue ? condition : `!(${condition})`
|
||||
lines.push(
|
||||
` setEditorReadOnly(${quote(action.targetField)}, ${readOnlyExpression});`,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
lines.push(` if (${condition}) {`)
|
||||
|
||||
if (action.actionType === 'setField' && action.targetField) {
|
||||
|
|
@ -467,6 +519,10 @@ function EditorScriptBuilderDialog({
|
|||
const findField = (fieldName: string) =>
|
||||
availableFields.find((field) => field.toLowerCase() === fieldName.toLowerCase()) || ''
|
||||
|
||||
const formatScriptPreview = () => {
|
||||
setScriptEditorValue((current) => formatScriptFallback(current))
|
||||
}
|
||||
|
||||
const fillAmountDefaults = () => {
|
||||
setAmountQuantityField((current) => current || findField('Quantity'))
|
||||
setAmountUnitPriceField((current) => current || findField('UnitPrice'))
|
||||
|
|
@ -582,14 +638,19 @@ function EditorScriptBuilderDialog({
|
|||
],
|
||||
)
|
||||
|
||||
const formattedGeneratedScript = useMemo(
|
||||
() => formatScriptFallback(generatedScript),
|
||||
[generatedScript],
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (!isOpen) return
|
||||
setScriptEditorValue((current) => {
|
||||
if (current === lastGeneratedScript || !current.trim()) return generatedScript
|
||||
if (current === lastGeneratedScript || !current.trim()) return formattedGeneratedScript
|
||||
return current
|
||||
})
|
||||
setLastGeneratedScript(generatedScript)
|
||||
}, [generatedScript, isOpen, lastGeneratedScript])
|
||||
setLastGeneratedScript(formattedGeneratedScript)
|
||||
}, [formattedGeneratedScript, isOpen, lastGeneratedScript])
|
||||
|
||||
const renderFieldSelect = (value: string, onChange: (value: string) => void) => (
|
||||
<select
|
||||
|
|
@ -664,6 +725,9 @@ function EditorScriptBuilderDialog({
|
|||
if (action.actionType === 'calculate') {
|
||||
return `${condition}, formül sonucunu ${target} alanına yaz.`
|
||||
}
|
||||
if (action.actionType === 'setReadOnly') {
|
||||
return `${condition}, ${target} alanını readOnly ${action.booleanValue} yap.`
|
||||
}
|
||||
return condition
|
||||
}
|
||||
|
||||
|
|
@ -888,6 +952,7 @@ function EditorScriptBuilderDialog({
|
|||
<option value="alert">Uyarı göster</option>
|
||||
<option value="confirm">Onay iste</option>
|
||||
<option value="calculate">Formül hesapla</option>
|
||||
<option value="setReadOnly">ReadOnly ayarla</option>
|
||||
<option value="apiToField">API sonucunu field'a yaz</option>
|
||||
</select>
|
||||
</label>
|
||||
|
|
@ -896,6 +961,7 @@ function EditorScriptBuilderDialog({
|
|||
'setField',
|
||||
'apiToField',
|
||||
'calculate',
|
||||
'setReadOnly',
|
||||
].includes(action.actionType) && (
|
||||
<div className="col-span-12 md:col-span-4">
|
||||
{renderLabeledFieldSelect('Hedef field', action.targetField, (value) =>
|
||||
|
|
@ -919,6 +985,26 @@ function EditorScriptBuilderDialog({
|
|||
</label>
|
||||
)}
|
||||
|
||||
{action.actionType === 'setReadOnly' && (
|
||||
<label className={`${fieldLabelClass} col-span-12 md:col-span-4`}>
|
||||
ReadOnly
|
||||
<select
|
||||
className={baseInputClass}
|
||||
value={action.booleanValue}
|
||||
title="true seçilirse alan salt okunur olur, false seçilirse tekrar düzenlenebilir olur."
|
||||
onChange={(event) =>
|
||||
updateConditionalAction(action.id, {
|
||||
booleanValue: event.target
|
||||
.value as ConditionalAction['booleanValue'],
|
||||
})
|
||||
}
|
||||
>
|
||||
<option value="true">true</option>
|
||||
<option value="false">false</option>
|
||||
</select>
|
||||
</label>
|
||||
)}
|
||||
|
||||
{action.actionType === 'apiToField' && (
|
||||
<>
|
||||
<label className={`${fieldLabelClass} col-span-12 md:col-span-2`}>
|
||||
|
|
@ -1121,9 +1207,20 @@ function EditorScriptBuilderDialog({
|
|||
<FaCode />
|
||||
Script Önizleme
|
||||
</span>
|
||||
<span className="rounded bg-gray-100 px-2 py-1 text-[11px] font-medium text-gray-500 dark:bg-gray-800 dark:text-gray-300">
|
||||
TypeScript
|
||||
</span>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="rounded bg-gray-100 px-2 py-1 text-[11px] font-medium text-gray-500 dark:bg-gray-800 dark:text-gray-300">
|
||||
TypeScript
|
||||
</span>
|
||||
<Button
|
||||
size="xs"
|
||||
type="button"
|
||||
variant="plain"
|
||||
icon={<FaMagic />}
|
||||
onClick={formatScriptPreview}
|
||||
>
|
||||
Formatla
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-1 min-h-[350px] overflow-hidden rounded border border-gray-200 dark:border-gray-700">
|
||||
<Editor
|
||||
|
|
|
|||
|
|
@ -14,6 +14,133 @@ import { RowMode, SimpleItemWithColData } from './types'
|
|||
import { PlatformEditorTypes } from '@/proxy/form/models'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
|
||||
const flattenFormItems = (items: any[] = []): SimpleItemWithColData[] =>
|
||||
items.flatMap((item) => [
|
||||
...(item?.dataField ? [item] : []),
|
||||
...flattenFormItems(item?.items || []),
|
||||
...(item?.tabs || []).flatMap((tab: any) => flattenFormItems(tab?.items || [])),
|
||||
])
|
||||
|
||||
const updateReadOnlyInFormItems = (items: any[] = [], field: string, readOnly: boolean) => {
|
||||
let changed = false
|
||||
const expected = String(field || '').toLowerCase()
|
||||
|
||||
const nextItems = items.map((item) => {
|
||||
const key = item?.dataField || item?.name
|
||||
let nextItem = item
|
||||
|
||||
if (key && String(key).toLowerCase() === expected) {
|
||||
const editorOptions = nextItem.editorOptions || {}
|
||||
if (editorOptions.readOnly !== readOnly) {
|
||||
changed = true
|
||||
nextItem = {
|
||||
...nextItem,
|
||||
editorOptions: {
|
||||
...editorOptions,
|
||||
readOnly,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nextItem?.items?.length) {
|
||||
const childResult = updateReadOnlyInFormItems(nextItem.items, field, readOnly)
|
||||
if (childResult.changed) {
|
||||
changed = true
|
||||
nextItem = { ...nextItem, items: childResult.items }
|
||||
}
|
||||
}
|
||||
|
||||
if (nextItem?.tabs?.length) {
|
||||
const tabs = nextItem.tabs.map((tab: any) => {
|
||||
const tabResult = updateReadOnlyInFormItems(tab.items, field, readOnly)
|
||||
if (tabResult.changed) {
|
||||
changed = true
|
||||
return { ...tab, items: tabResult.items }
|
||||
}
|
||||
return tab
|
||||
})
|
||||
nextItem = tabs === nextItem.tabs ? nextItem : { ...nextItem, tabs }
|
||||
}
|
||||
|
||||
return nextItem
|
||||
})
|
||||
|
||||
return { items: nextItems, changed }
|
||||
}
|
||||
|
||||
const findFormFieldKey = (items: any[] = [], field: string): string => {
|
||||
const expected = String(field || '').toLowerCase()
|
||||
|
||||
for (const item of items || []) {
|
||||
const key = item?.dataField || item?.name
|
||||
if (key && String(key).toLowerCase() === expected) {
|
||||
return key
|
||||
}
|
||||
|
||||
const childKey = findFormFieldKey(item?.items || [], field)
|
||||
if (childKey) {
|
||||
return childKey
|
||||
}
|
||||
|
||||
for (const tab of item?.tabs || []) {
|
||||
const tabKey = findFormFieldKey(tab?.items || [], field)
|
||||
if (tabKey) {
|
||||
return tabKey
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
const setFormEditorReadOnly = (form: any, field: string, readOnly: boolean) => {
|
||||
if (!form?.option) return false
|
||||
|
||||
const apply = () => {
|
||||
const formItems = form.option('items') || []
|
||||
const resolvedField = findFormFieldKey(formItems, field)
|
||||
const editor = form.getEditor?.(resolvedField) ?? form.getEditor?.(field)
|
||||
const result = updateReadOnlyInFormItems(formItems, resolvedField, readOnly)
|
||||
|
||||
if (result.changed) {
|
||||
try {
|
||||
const item = form.itemOption?.(resolvedField) ?? form.itemOption?.(field)
|
||||
if (item) {
|
||||
form.itemOption?.(resolvedField, 'editorOptions', {
|
||||
...(item.editorOptions || {}),
|
||||
readOnly,
|
||||
})
|
||||
} else {
|
||||
form.option('items', result.items)
|
||||
}
|
||||
} catch {
|
||||
form.option('items', result.items)
|
||||
}
|
||||
}
|
||||
|
||||
const activeEditor = editor ?? form.getEditor?.(resolvedField) ?? form.getEditor?.(field)
|
||||
if (activeEditor?.option?.('readOnly') !== readOnly) {
|
||||
activeEditor?.option?.('readOnly', readOnly)
|
||||
}
|
||||
}
|
||||
|
||||
apply()
|
||||
return true
|
||||
}
|
||||
|
||||
const getValueByField = (data: Record<string, any> = {}, field?: string) => {
|
||||
if (!field) return undefined
|
||||
if (Object.prototype.hasOwnProperty.call(data, field)) return data[field]
|
||||
const key = Object.keys(data).find(
|
||||
(itemKey) => itemKey.toLowerCase() === String(field).toLowerCase(),
|
||||
)
|
||||
return key ? data[key] : undefined
|
||||
}
|
||||
|
||||
const shouldRunEditorScriptOnContentReady = (script?: string) =>
|
||||
Boolean(script && (script.includes('setEditorReadOnly') || script.includes('runtimeSetEditorReadOnly')))
|
||||
|
||||
const FormDevExpress = (props: {
|
||||
listFormCode: string
|
||||
isSubForm?: boolean
|
||||
|
|
@ -28,6 +155,7 @@ const FormDevExpress = (props: {
|
|||
|
||||
const formDataRef = useRef(formData)
|
||||
const formItemsRef = useRef(formItems)
|
||||
const formInstanceRef = useRef<any>()
|
||||
|
||||
useEffect(() => {
|
||||
formDataRef.current = formData
|
||||
|
|
@ -41,7 +169,7 @@ const FormDevExpress = (props: {
|
|||
useEffect(() => {
|
||||
if (!refForm.current?.instance()) return
|
||||
|
||||
const allItems = formItems.flatMap((group) => (group.items as SimpleItemWithColData[]) || [])
|
||||
const allItems = formItems.flatMap((group) => flattenFormItems([group]))
|
||||
|
||||
allItems.forEach((item) => {
|
||||
if (item.colData?.lookupDto?.dataSourceType && item.editorOptions?.dataSource) {
|
||||
|
|
@ -62,9 +190,7 @@ const FormDevExpress = (props: {
|
|||
const updateCascadeDisabledStates = () => {
|
||||
if (!refForm.current?.instance()) return
|
||||
|
||||
const allItems = formItemsRef.current.flatMap(
|
||||
(group) => (group.items as SimpleItemWithColData[]) || [],
|
||||
)
|
||||
const allItems = formItemsRef.current.flatMap((group) => flattenFormItems([group]))
|
||||
|
||||
allItems.forEach((item) => {
|
||||
const cascadeParentFields = item.colData?.lookupDto?.cascadeParentFields
|
||||
|
|
@ -107,9 +233,7 @@ const FormDevExpress = (props: {
|
|||
const newFormData = { ...formData, [e.dataField!]: e.value }
|
||||
|
||||
// Cascading child field'leri temizle (parent field değiştiğinde)
|
||||
const allItems = formItemsRef.current.flatMap(
|
||||
(group) => (group.items as SimpleItemWithColData[]) || [],
|
||||
)
|
||||
const allItems = formItemsRef.current.flatMap((group) => flattenFormItems([group]))
|
||||
const cascadingChildren = allItems.filter((item) => {
|
||||
const parentFields = item.colData?.lookupDto?.cascadeParentFields?.split(',') || []
|
||||
return parentFields.some((field) => field.trim() === e.dataField)
|
||||
|
|
@ -129,11 +253,24 @@ const FormDevExpress = (props: {
|
|||
|
||||
//Dinamik script
|
||||
const changeItem = formItemsRef.current
|
||||
.flatMap((group) => (group.items as SimpleItemWithColData[]) || [])
|
||||
.find((i: SimpleItemWithColData) => i.dataField === e.dataField)
|
||||
.flatMap((group) => flattenFormItems([group]))
|
||||
.find(
|
||||
(i: SimpleItemWithColData) =>
|
||||
String(i.dataField || '').toLowerCase() === String(e.dataField || '').toLowerCase(),
|
||||
)
|
||||
|
||||
if (changeItem?.editorScript) {
|
||||
try {
|
||||
const form = e.component
|
||||
const editor = {
|
||||
dataField: changeItem.dataField,
|
||||
component: form,
|
||||
}
|
||||
const formData = newFormData
|
||||
formDataRef.current = newFormData
|
||||
const runtimeSetEditorReadOnly = (field: string, readOnly: boolean) =>
|
||||
setFormEditorReadOnly(formInstanceRef.current ?? form, field, readOnly)
|
||||
|
||||
//setFormData({...formData, Path: e.value});
|
||||
//UiEvalService.ApiGenerateBackgroundWorkers();
|
||||
//setFormData({ ...formData, Path: (v => v === '1' ? '1-deneme' : v === '0' ? '0-deneme' : '')(e.value) })
|
||||
|
|
@ -142,8 +279,47 @@ const FormDevExpress = (props: {
|
|||
console.error('Script execution failed for', changeItem.name, err)
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
onContentReady={(e) => {
|
||||
formInstanceRef.current = e.component
|
||||
|
||||
const form = e.component
|
||||
const runtimeSetEditorReadOnly = (field: string, readOnly: boolean) =>
|
||||
setFormEditorReadOnly(form, field, readOnly)
|
||||
|
||||
const runReadOnlyScripts = () => {
|
||||
const currentFormData = {
|
||||
...(formDataRef.current || {}),
|
||||
...(form?.option?.('formData') || {}),
|
||||
}
|
||||
formDataRef.current = currentFormData
|
||||
|
||||
formItemsRef.current
|
||||
.flatMap((group) => flattenFormItems([group]))
|
||||
.filter((formItem) => shouldRunEditorScriptOnContentReady(formItem.editorScript))
|
||||
.forEach((formItem) => {
|
||||
try {
|
||||
const editor = {
|
||||
dataField: formItem.dataField,
|
||||
component: form,
|
||||
}
|
||||
const formData = currentFormData
|
||||
const e = {
|
||||
component: form,
|
||||
dataField: formItem.dataField,
|
||||
value: getValueByField(currentFormData, formItem.dataField),
|
||||
}
|
||||
|
||||
eval(formItem.editorScript!)
|
||||
} catch (err) {
|
||||
console.error('Script execution failed on contentReady for', formItem.name, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
runReadOnlyScripts()
|
||||
|
||||
const groupItems = e.component.option('items') as any[]
|
||||
const firstItem = groupItems?.[0]?.items?.[0]
|
||||
|
||||
|
|
|
|||
|
|
@ -106,6 +106,138 @@ const getPersistedInsertedKey = (
|
|||
return undefined
|
||||
}
|
||||
|
||||
const updateReadOnlyInFormItems = (items: any[] = [], field: string, readOnly: boolean) => {
|
||||
let changed = false
|
||||
const expected = String(field || '').toLowerCase()
|
||||
|
||||
const nextItems = items.map((item) => {
|
||||
const key = item?.dataField || item?.name
|
||||
let nextItem = item
|
||||
|
||||
if (key && String(key).toLowerCase() === expected) {
|
||||
const editorOptions = nextItem.editorOptions || {}
|
||||
if (editorOptions.readOnly !== readOnly) {
|
||||
changed = true
|
||||
nextItem = {
|
||||
...nextItem,
|
||||
editorOptions: {
|
||||
...editorOptions,
|
||||
readOnly,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nextItem?.items?.length) {
|
||||
const childResult = updateReadOnlyInFormItems(nextItem.items, field, readOnly)
|
||||
if (childResult.changed) {
|
||||
changed = true
|
||||
nextItem = { ...nextItem, items: childResult.items }
|
||||
}
|
||||
}
|
||||
|
||||
if (nextItem?.tabs?.length) {
|
||||
const tabs = nextItem.tabs.map((tab: any) => {
|
||||
const tabResult = updateReadOnlyInFormItems(tab.items, field, readOnly)
|
||||
if (tabResult.changed) {
|
||||
changed = true
|
||||
return { ...tab, items: tabResult.items }
|
||||
}
|
||||
return tab
|
||||
})
|
||||
nextItem = tabs === nextItem.tabs ? nextItem : { ...nextItem, tabs }
|
||||
}
|
||||
|
||||
return nextItem
|
||||
})
|
||||
|
||||
return { items: nextItems, changed }
|
||||
}
|
||||
|
||||
const findFormFieldKey = (items: any[] = [], field: string): string => {
|
||||
const expected = String(field || '').toLowerCase()
|
||||
|
||||
for (const item of items || []) {
|
||||
const key = item?.dataField || item?.name
|
||||
if (key && String(key).toLowerCase() === expected) {
|
||||
return key
|
||||
}
|
||||
|
||||
const childKey = findFormFieldKey(item?.items || [], field)
|
||||
if (childKey) {
|
||||
return childKey
|
||||
}
|
||||
|
||||
for (const tab of item?.tabs || []) {
|
||||
const tabKey = findFormFieldKey(tab?.items || [], field)
|
||||
if (tabKey) {
|
||||
return tabKey
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
const setFormEditorReadOnly = (form: any, field: string, readOnly: boolean) => {
|
||||
if (!form?.option) return false
|
||||
|
||||
const apply = () => {
|
||||
const formItems = form.option('items') || []
|
||||
const resolvedField = findFormFieldKey(formItems, field)
|
||||
const editor = form.getEditor?.(resolvedField) ?? form.getEditor?.(field)
|
||||
const result = updateReadOnlyInFormItems(formItems, resolvedField, readOnly)
|
||||
|
||||
if (result.changed) {
|
||||
try {
|
||||
const item = form.itemOption?.(resolvedField) ?? form.itemOption?.(field)
|
||||
if (item) {
|
||||
form.itemOption?.(resolvedField, 'editorOptions', {
|
||||
...(item.editorOptions || {}),
|
||||
readOnly,
|
||||
})
|
||||
} else {
|
||||
form.option('items', result.items)
|
||||
}
|
||||
} catch {
|
||||
form.option('items', result.items)
|
||||
}
|
||||
}
|
||||
|
||||
const activeEditor = editor ?? form.getEditor?.(resolvedField) ?? form.getEditor?.(field)
|
||||
if (activeEditor?.option?.('readOnly') !== readOnly) {
|
||||
activeEditor?.option?.('readOnly', readOnly)
|
||||
}
|
||||
}
|
||||
|
||||
apply()
|
||||
return true
|
||||
}
|
||||
|
||||
const getActiveEditingForm = (component: any) => {
|
||||
const editForm = component?.getView?.('editingView')?._editForm
|
||||
return editForm?.getEditor || editForm?.itemOption ? editForm : undefined
|
||||
}
|
||||
|
||||
const flattenEditingFormItems = (items: any[] = []): EditingFormItemDto[] =>
|
||||
items.flatMap((item) => [
|
||||
...(item?.dataField ? [item] : []),
|
||||
...flattenEditingFormItems(item?.items || []),
|
||||
...(item?.tabs || []).flatMap((tab: any) => flattenEditingFormItems(tab?.items || [])),
|
||||
])
|
||||
|
||||
const getValueByField = (data: Record<string, any> = {}, field?: string) => {
|
||||
if (!field) return undefined
|
||||
if (Object.prototype.hasOwnProperty.call(data, field)) return data[field]
|
||||
const key = Object.keys(data).find(
|
||||
(itemKey) => itemKey.toLowerCase() === String(field).toLowerCase(),
|
||||
)
|
||||
return key ? data[key] : undefined
|
||||
}
|
||||
|
||||
const shouldRunEditorScriptOnContentReady = (script?: string) =>
|
||||
Boolean(script && (script.includes('setEditorReadOnly') || script.includes('runtimeSetEditorReadOnly')))
|
||||
|
||||
const Grid = (props: GridProps) => {
|
||||
const { listFormCode, searchParams, isSubForm, level, gridDto: extGridDto } = props
|
||||
const { translate } = useLocalization()
|
||||
|
|
@ -116,6 +248,7 @@ const Grid = (props: GridProps) => {
|
|||
const refListFormCode = useRef('')
|
||||
const widgetGroupRef = useRef<HTMLDivElement>(null)
|
||||
const editingFormDataRef = useRef<Record<string, any>>({})
|
||||
const editingFormInstanceRef = useRef<any>()
|
||||
// Edit popup state kaydetmeyi engellemek için flag
|
||||
const isEditingRef = useRef(false)
|
||||
|
||||
|
|
@ -571,7 +704,7 @@ const Grid = (props: GridProps) => {
|
|||
(editor: DataGridTypes.EditorPreparingEvent<any, any>) => {
|
||||
if (editor.parentType === 'dataRow' && editor.dataField && gridDto) {
|
||||
const formItem = gridDto.gridOptions.editingFormDto
|
||||
.flatMap((group) => group.items || [])
|
||||
.flatMap((group) => flattenEditingFormItems([group]))
|
||||
.find((i) => i.dataField === editor.dataField)
|
||||
const fieldName = editor.dataField.split(':')[0]
|
||||
const columnFormat = gridDto.columnFormats.find((column) => column.fieldName === fieldName)
|
||||
|
|
@ -632,7 +765,7 @@ const Grid = (props: GridProps) => {
|
|||
)
|
||||
try {
|
||||
const childFormItem = gridDto.gridOptions.editingFormDto
|
||||
.flatMap((group) => group.items || [])
|
||||
.flatMap((group) => flattenEditingFormItems([group]))
|
||||
.find((i) => i.dataField === childFieldName)
|
||||
const childEditorOptions = childFormItem?.editorOptions
|
||||
? JSON.parse(childFormItem.editorOptions)
|
||||
|
|
@ -665,6 +798,7 @@ const Grid = (props: GridProps) => {
|
|||
|
||||
if (formItem?.editorScript) {
|
||||
const prevHandler = editor.editorOptions.onValueChanged
|
||||
const editorDataField = editor.dataField
|
||||
|
||||
editor.editorOptions.onValueChanged = (e: any) => {
|
||||
if (prevHandler) prevHandler(e)
|
||||
|
|
@ -674,8 +808,16 @@ const Grid = (props: GridProps) => {
|
|||
const rowKey = grid.option('editing.editRowKey')
|
||||
const rowIndex = grid.getRowIndexByKey(rowKey)
|
||||
|
||||
const formData = grid.getVisibleRows().find((r) => r.key === rowKey)?.data || {}
|
||||
|
||||
const formData = {
|
||||
...(grid.getVisibleRows().find((r) => r.key === rowKey)?.data || {}),
|
||||
[editorDataField]: e.value,
|
||||
}
|
||||
const runtimeSetEditorReadOnly = (field: string, readOnly: boolean) =>
|
||||
setFormEditorReadOnly(
|
||||
editingFormInstanceRef.current ?? getActiveEditingForm(grid),
|
||||
field,
|
||||
readOnly,
|
||||
)
|
||||
const setFormData = (newData: any) => {
|
||||
if (rowIndex >= 0) {
|
||||
Object.keys(newData).forEach((field) => {
|
||||
|
|
@ -1388,6 +1530,58 @@ const Grid = (props: GridProps) => {
|
|||
}}
|
||||
form={{
|
||||
colCount: 1,
|
||||
onContentReady: (e) => {
|
||||
editingFormInstanceRef.current = e.component
|
||||
|
||||
const form = e.component
|
||||
const grid = gridRef.current?.instance()
|
||||
const rowKey = grid?.option('editing.editRowKey')
|
||||
const rowIndex = rowKey !== undefined ? grid?.getRowIndexByKey(rowKey) : -1
|
||||
const runtimeSetEditorReadOnly = (field: string, readOnly: boolean) =>
|
||||
setFormEditorReadOnly(form, field, readOnly)
|
||||
const setFormData = (newData: any) => {
|
||||
form?.option?.('formData', newData)
|
||||
editingFormDataRef.current = { ...newData }
|
||||
if (grid && rowIndex !== undefined && rowIndex >= 0) {
|
||||
Object.keys(newData).forEach((field) => {
|
||||
grid.cellValue(rowIndex, field, newData[field])
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const runReadOnlyScripts = () => {
|
||||
const formData = {
|
||||
...editingFormDataRef.current,
|
||||
...(form?.option?.('formData') || {}),
|
||||
}
|
||||
editingFormDataRef.current = { ...formData }
|
||||
|
||||
gridDto.gridOptions.editingFormDto
|
||||
.flatMap((group) => flattenEditingFormItems([group]))
|
||||
.filter((formItem) =>
|
||||
shouldRunEditorScriptOnContentReady(formItem.editorScript),
|
||||
)
|
||||
.forEach((formItem) => {
|
||||
try {
|
||||
const editor = {
|
||||
dataField: formItem.dataField,
|
||||
component: grid,
|
||||
}
|
||||
const e = {
|
||||
component: form,
|
||||
dataField: formItem.dataField,
|
||||
value: getValueByField(formData, formItem.dataField),
|
||||
}
|
||||
|
||||
eval(formItem.editorScript!)
|
||||
} catch (err) {
|
||||
console.error('Script exec error on contentReady', formItem.dataField, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
runReadOnlyScripts()
|
||||
},
|
||||
onFieldDataChanged: (e) => {
|
||||
if (e.dataField) {
|
||||
const previousValue = editingFormDataRef.current?.[e.dataField]
|
||||
|
|
@ -1396,15 +1590,25 @@ const Grid = (props: GridProps) => {
|
|||
}
|
||||
|
||||
const formItem = gridDto.gridOptions.editingFormDto
|
||||
.flatMap((group) => group.items || [])
|
||||
.find((i) => i.dataField === e.dataField)
|
||||
.flatMap((group) => flattenEditingFormItems([group]))
|
||||
.find(
|
||||
(i) =>
|
||||
String(i.dataField || '').toLowerCase() ===
|
||||
String(e.dataField || '').toLowerCase(),
|
||||
)
|
||||
if (formItem?.editorScript) {
|
||||
try {
|
||||
const grid = gridRef.current?.instance()
|
||||
const rowKey = grid?.option('editing.editRowKey')
|
||||
const rowIndex =
|
||||
rowKey !== undefined ? grid?.getRowIndexByKey(rowKey) : -1
|
||||
const formData = e.component?.option?.('formData') || {}
|
||||
const formData = {
|
||||
...(e.component?.option?.('formData') || {}),
|
||||
[e.dataField]: e.value,
|
||||
}
|
||||
editingFormDataRef.current = { ...formData }
|
||||
const runtimeSetEditorReadOnly = (field: string, readOnly: boolean) =>
|
||||
setFormEditorReadOnly(e.component, field, readOnly)
|
||||
const setFormData = (newData: any) => {
|
||||
e.component?.option?.('formData', newData)
|
||||
editingFormDataRef.current = { ...newData }
|
||||
|
|
@ -1420,6 +1624,7 @@ const Grid = (props: GridProps) => {
|
|||
console.error('Script exec error', err)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
items:
|
||||
|
|
|
|||
|
|
@ -94,6 +94,138 @@ const getPersistedInsertedKey = (e: any, keyFieldName?: string) => {
|
|||
return undefined
|
||||
}
|
||||
|
||||
const updateReadOnlyInFormItems = (items: any[] = [], field: string, readOnly: boolean) => {
|
||||
let changed = false
|
||||
const expected = String(field || '').toLowerCase()
|
||||
|
||||
const nextItems = items.map((item) => {
|
||||
const key = item?.dataField || item?.name
|
||||
let nextItem = item
|
||||
|
||||
if (key && String(key).toLowerCase() === expected) {
|
||||
const editorOptions = nextItem.editorOptions || {}
|
||||
if (editorOptions.readOnly !== readOnly) {
|
||||
changed = true
|
||||
nextItem = {
|
||||
...nextItem,
|
||||
editorOptions: {
|
||||
...editorOptions,
|
||||
readOnly,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nextItem?.items?.length) {
|
||||
const childResult = updateReadOnlyInFormItems(nextItem.items, field, readOnly)
|
||||
if (childResult.changed) {
|
||||
changed = true
|
||||
nextItem = { ...nextItem, items: childResult.items }
|
||||
}
|
||||
}
|
||||
|
||||
if (nextItem?.tabs?.length) {
|
||||
const tabs = nextItem.tabs.map((tab: any) => {
|
||||
const tabResult = updateReadOnlyInFormItems(tab.items, field, readOnly)
|
||||
if (tabResult.changed) {
|
||||
changed = true
|
||||
return { ...tab, items: tabResult.items }
|
||||
}
|
||||
return tab
|
||||
})
|
||||
nextItem = tabs === nextItem.tabs ? nextItem : { ...nextItem, tabs }
|
||||
}
|
||||
|
||||
return nextItem
|
||||
})
|
||||
|
||||
return { items: nextItems, changed }
|
||||
}
|
||||
|
||||
const findFormFieldKey = (items: any[] = [], field: string): string => {
|
||||
const expected = String(field || '').toLowerCase()
|
||||
|
||||
for (const item of items || []) {
|
||||
const key = item?.dataField || item?.name
|
||||
if (key && String(key).toLowerCase() === expected) {
|
||||
return key
|
||||
}
|
||||
|
||||
const childKey = findFormFieldKey(item?.items || [], field)
|
||||
if (childKey) {
|
||||
return childKey
|
||||
}
|
||||
|
||||
for (const tab of item?.tabs || []) {
|
||||
const tabKey = findFormFieldKey(tab?.items || [], field)
|
||||
if (tabKey) {
|
||||
return tabKey
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return field
|
||||
}
|
||||
|
||||
const setFormEditorReadOnly = (form: any, field: string, readOnly: boolean) => {
|
||||
if (!form?.option) return false
|
||||
|
||||
const apply = () => {
|
||||
const formItems = form.option('items') || []
|
||||
const resolvedField = findFormFieldKey(formItems, field)
|
||||
const editor = form.getEditor?.(resolvedField) ?? form.getEditor?.(field)
|
||||
const result = updateReadOnlyInFormItems(formItems, resolvedField, readOnly)
|
||||
|
||||
if (result.changed) {
|
||||
try {
|
||||
const item = form.itemOption?.(resolvedField) ?? form.itemOption?.(field)
|
||||
if (item) {
|
||||
form.itemOption?.(resolvedField, 'editorOptions', {
|
||||
...(item.editorOptions || {}),
|
||||
readOnly,
|
||||
})
|
||||
} else {
|
||||
form.option('items', result.items)
|
||||
}
|
||||
} catch {
|
||||
form.option('items', result.items)
|
||||
}
|
||||
}
|
||||
|
||||
const activeEditor = editor ?? form.getEditor?.(resolvedField) ?? form.getEditor?.(field)
|
||||
if (activeEditor?.option?.('readOnly') !== readOnly) {
|
||||
activeEditor?.option?.('readOnly', readOnly)
|
||||
}
|
||||
}
|
||||
|
||||
apply()
|
||||
return true
|
||||
}
|
||||
|
||||
const getActiveEditingForm = (component: any) => {
|
||||
const editForm = component?.getView?.('editingView')?._editForm
|
||||
return editForm?.getEditor || editForm?.itemOption ? editForm : undefined
|
||||
}
|
||||
|
||||
const flattenEditingFormItems = (items: any[] = []): EditingFormItemDto[] =>
|
||||
items.flatMap((item) => [
|
||||
...(item?.dataField ? [item] : []),
|
||||
...flattenEditingFormItems(item?.items || []),
|
||||
...(item?.tabs || []).flatMap((tab: any) => flattenEditingFormItems(tab?.items || [])),
|
||||
])
|
||||
|
||||
const getValueByField = (data: Record<string, any> = {}, field?: string) => {
|
||||
if (!field) return undefined
|
||||
if (Object.prototype.hasOwnProperty.call(data, field)) return data[field]
|
||||
const key = Object.keys(data).find(
|
||||
(itemKey) => itemKey.toLowerCase() === String(field).toLowerCase(),
|
||||
)
|
||||
return key ? data[key] : undefined
|
||||
}
|
||||
|
||||
const shouldRunEditorScriptOnContentReady = (script?: string) =>
|
||||
Boolean(script && (script.includes('setEditorReadOnly') || script.includes('runtimeSetEditorReadOnly')))
|
||||
|
||||
const Tree = (props: TreeProps) => {
|
||||
const { listFormCode, searchParams, isSubForm, level, gridDto: extGridDto } = props
|
||||
const { translate } = useLocalization()
|
||||
|
|
@ -103,6 +235,7 @@ const Tree = (props: TreeProps) => {
|
|||
const refListFormCode = useRef('')
|
||||
const widgetGroupRef = useRef<HTMLDivElement>(null)
|
||||
const editingFormDataRef = useRef<Record<string, any>>({})
|
||||
const editingFormInstanceRef = useRef<any>()
|
||||
// Edit popup state kaydetmeyi engellemek için flag
|
||||
const isEditingRef = useRef(false)
|
||||
|
||||
|
|
@ -520,7 +653,7 @@ const Tree = (props: TreeProps) => {
|
|||
function onEditorPreparing(editor: TreeListTypes.EditorPreparingEvent) {
|
||||
if (editor.parentType === 'dataRow' && editor.dataField && gridDto) {
|
||||
const formItem = gridDto.gridOptions.editingFormDto
|
||||
.flatMap((group) => group.items || [])
|
||||
.flatMap((group) => flattenEditingFormItems([group]))
|
||||
.find((i) => i.dataField === editor.dataField)
|
||||
const fieldName = editor.dataField.split(':')[0]
|
||||
const columnFormat = gridDto.columnFormats.find((column) => column.fieldName === fieldName)
|
||||
|
|
@ -589,7 +722,7 @@ const Tree = (props: TreeProps) => {
|
|||
const editorInstance = formInstance.getEditor(col.fieldName!)
|
||||
if (editorInstance) {
|
||||
const formItem = gridDto.gridOptions.editingFormDto
|
||||
.flatMap((group) => group.items || [])
|
||||
.flatMap((group) => flattenEditingFormItems([group]))
|
||||
.find((i) => i.dataField === col.fieldName)
|
||||
const editorOptions = formItem?.editorOptions
|
||||
? JSON.parse(formItem.editorOptions)
|
||||
|
|
@ -622,6 +755,7 @@ const Tree = (props: TreeProps) => {
|
|||
|
||||
if (formItem?.editorScript) {
|
||||
const prevHandler = editor.editorOptions.onValueChanged
|
||||
const editorDataField = editor.dataField
|
||||
|
||||
editor.editorOptions.onValueChanged = (e: any) => {
|
||||
if (prevHandler) prevHandler(e)
|
||||
|
|
@ -631,7 +765,16 @@ const Tree = (props: TreeProps) => {
|
|||
const rowKey = grid.option('editing.editRowKey')
|
||||
const rowIndex = grid.getRowIndexByKey(rowKey)
|
||||
|
||||
const formData = grid.getVisibleRows().find((r) => r.key === rowKey)?.data || {}
|
||||
const formData = {
|
||||
...(grid.getVisibleRows().find((r) => r.key === rowKey)?.data || {}),
|
||||
[editorDataField]: e.value,
|
||||
}
|
||||
const runtimeSetEditorReadOnly = (field: string, readOnly: boolean) =>
|
||||
setFormEditorReadOnly(
|
||||
editingFormInstanceRef.current ?? getActiveEditingForm(grid),
|
||||
field,
|
||||
readOnly,
|
||||
)
|
||||
|
||||
const setFormData = (newData: any) => {
|
||||
if (rowIndex >= 0) {
|
||||
|
|
@ -1049,6 +1192,58 @@ const Tree = (props: TreeProps) => {
|
|||
}}
|
||||
form={{
|
||||
colCount: 1,
|
||||
onContentReady: (e) => {
|
||||
editingFormInstanceRef.current = e.component
|
||||
|
||||
const form = e.component
|
||||
const grid = gridRef.current?.instance()
|
||||
const rowKey = grid?.option('editing.editRowKey')
|
||||
const rowIndex = rowKey !== undefined ? grid?.getRowIndexByKey(rowKey) : -1
|
||||
const runtimeSetEditorReadOnly = (field: string, readOnly: boolean) =>
|
||||
setFormEditorReadOnly(form, field, readOnly)
|
||||
const setFormData = (newData: any) => {
|
||||
form?.option?.('formData', newData)
|
||||
editingFormDataRef.current = { ...newData }
|
||||
if (grid && rowIndex !== undefined && rowIndex >= 0) {
|
||||
Object.keys(newData).forEach((field) => {
|
||||
grid.cellValue(rowIndex, field, newData[field])
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const runReadOnlyScripts = () => {
|
||||
const formData = {
|
||||
...editingFormDataRef.current,
|
||||
...(form?.option?.('formData') || {}),
|
||||
}
|
||||
editingFormDataRef.current = { ...formData }
|
||||
|
||||
gridDto.gridOptions.editingFormDto
|
||||
.flatMap((group) => flattenEditingFormItems([group]))
|
||||
.filter((formItem) =>
|
||||
shouldRunEditorScriptOnContentReady(formItem.editorScript),
|
||||
)
|
||||
.forEach((formItem) => {
|
||||
try {
|
||||
const editor = {
|
||||
dataField: formItem.dataField,
|
||||
component: grid,
|
||||
}
|
||||
const e = {
|
||||
component: form,
|
||||
dataField: formItem.dataField,
|
||||
value: getValueByField(formData, formItem.dataField),
|
||||
}
|
||||
|
||||
eval(formItem.editorScript!)
|
||||
} catch (err) {
|
||||
console.error('Script exec error on contentReady', formItem.dataField, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
runReadOnlyScripts()
|
||||
},
|
||||
onFieldDataChanged: (e) => {
|
||||
if (e.dataField) {
|
||||
const previousValue = editingFormDataRef.current?.[e.dataField]
|
||||
|
|
@ -1057,15 +1252,25 @@ const Tree = (props: TreeProps) => {
|
|||
}
|
||||
|
||||
const formItem = gridDto.gridOptions.editingFormDto
|
||||
.flatMap((group) => group.items || [])
|
||||
.find((i) => i.dataField === e.dataField)
|
||||
.flatMap((group) => flattenEditingFormItems([group]))
|
||||
.find(
|
||||
(i) =>
|
||||
String(i.dataField || '').toLowerCase() ===
|
||||
String(e.dataField || '').toLowerCase(),
|
||||
)
|
||||
if (formItem?.editorScript) {
|
||||
try {
|
||||
const grid = gridRef.current?.instance()
|
||||
const rowKey = grid?.option('editing.editRowKey')
|
||||
const rowIndex =
|
||||
rowKey !== undefined ? grid?.getRowIndexByKey(rowKey) : -1
|
||||
const formData = e.component?.option?.('formData') || {}
|
||||
const formData = {
|
||||
...(e.component?.option?.('formData') || {}),
|
||||
[e.dataField]: e.value,
|
||||
}
|
||||
editingFormDataRef.current = { ...formData }
|
||||
const runtimeSetEditorReadOnly = (field: string, readOnly: boolean) =>
|
||||
setFormEditorReadOnly(e.component, field, readOnly)
|
||||
const setFormData = (newData: any) => {
|
||||
e.component?.option?.('formData', newData)
|
||||
editingFormDataRef.current = { ...newData }
|
||||
|
|
@ -1081,6 +1286,7 @@ const Tree = (props: TreeProps) => {
|
|||
console.error('Script exec error', err)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
items:
|
||||
|
|
|
|||
Loading…
Reference in a new issue