771 lines
27 KiB
TypeScript
771 lines
27 KiB
TypeScript
import Container from '@/components/shared/Container'
|
||
import '@/utils/registerDevExtremeEditors'
|
||
import { Dialog, Notification, toast } from '@/components/ui'
|
||
import { DX_CLASSNAMES } from '@/constants/app.constant'
|
||
import { GridDto, SubFormTabTypeEnum } from '@/proxy/form/models'
|
||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||
import { Template } from 'devextreme-react/core/template'
|
||
import TreeListDx, {
|
||
ColumnChooser,
|
||
ColumnFixing,
|
||
Editing,
|
||
FilterPanel,
|
||
FilterRow,
|
||
HeaderFilter,
|
||
LoadPanel,
|
||
Pager,
|
||
Paging,
|
||
RemoteOperations,
|
||
Scrolling,
|
||
SearchPanel,
|
||
Selection,
|
||
Sorting,
|
||
Toolbar,
|
||
type TreeListRef,
|
||
type TreeListTypes,
|
||
} from 'devextreme-react/tree-list'
|
||
import { Item } from 'devextreme-react/toolbar'
|
||
import CustomStore from 'devextreme/data/custom_store'
|
||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||
import PageTitle from '@/components/shared/PageTitle'
|
||
import { RowMode } from '../form/types'
|
||
import { GridColumnData } from './GridColumnData'
|
||
import GridFilterDialogs from './GridFilterDialogs'
|
||
import { GridBoxEditorComponent } from './editors/GridBoxEditorComponent'
|
||
import { ImageUploadEditorComponent } from './editors/ImageUploadEditorComponent'
|
||
import { ImageViewerEditorComponent } from './editors/ImageViewerEditorComponent'
|
||
import { TagBoxEditorComponent } from './editors/TagBoxEditorComponent'
|
||
import { useFilters } from './useFilters'
|
||
import { updateWorkflowApprovalToolbarItems, useToolbar } from './useToolbar'
|
||
import WidgetGroup from '@/components/ui/Widget/WidgetGroup'
|
||
import { GridExtraFilterToolbar } from './GridExtraFilterToolbar'
|
||
import { layoutTypes } from '../admin/listForm/edit/types'
|
||
import {
|
||
resolveStoreKeyFieldName,
|
||
useListFormCustomDataSource,
|
||
} from './useListFormCustomDataSource'
|
||
import { useListFormColumns } from './useListFormColumns'
|
||
import { orderListToolbarItems } from './toolbarOrder'
|
||
import { useStoreState } from '@/store/store'
|
||
import SubForms from '../form/SubForms'
|
||
import { ImportDashboard } from '@/components/importManager/ImportDashboard'
|
||
import { NotePanel } from '../form/notes/NotePanel'
|
||
import { useListFormStateStoring } from './useListFormStateStoring'
|
||
import { buildEditPopupOptions, shouldUseMobileEditPopup } from './shared/editPopup'
|
||
import {
|
||
applyNewRowDefaults,
|
||
buildEditingFormItems,
|
||
buildInsertPayload,
|
||
buildUpdatePayload,
|
||
createFormItemMapper,
|
||
expandJsonFormFields,
|
||
getActiveEditingForm,
|
||
getValueByField,
|
||
} from './shared/editingForm'
|
||
import {
|
||
attachEditorButtonContext,
|
||
attachEditorValueChangedScript,
|
||
createEditingFormHandlers,
|
||
} from './shared/editingFormScripts'
|
||
import { attachFieldValueBroadcast } from '@/utils/phoneFormat'
|
||
import { attachCascadeBehavior, createCascadeMaps } from './shared/cascade'
|
||
import { createConditionalCellStyleHandler } from './shared/cellStyles'
|
||
import {
|
||
useExtraFilters,
|
||
useListFormCustomSources,
|
||
useListFormGridDto,
|
||
useListFormWidgets,
|
||
useWidgetGroupHeight,
|
||
} from './shared/hooks'
|
||
import { startWorkflowForInsertedRow } from './shared/workflowRows'
|
||
|
||
interface TreeProps {
|
||
listFormCode: string
|
||
searchParams?: URLSearchParams
|
||
isSubForm?: boolean
|
||
level?: number
|
||
refreshData?: () => Promise<void>
|
||
gridDto?: GridDto
|
||
}
|
||
|
||
const defaultPageSizes = [10, 20, 50, 100]
|
||
|
||
const Tree = (props: TreeProps) => {
|
||
const { listFormCode, searchParams, isSubForm, level, gridDto: extGridDto } = props
|
||
const { translate } = useLocalization()
|
||
const currentUser = useStoreState((state) => state.auth.user)
|
||
const currentCulture = useStoreState(
|
||
(state) => state.abpConfig.config?.localization.currentCulture.cultureName,
|
||
)
|
||
const localizationTexts = useStoreState((state) => state.abpConfig.texts)
|
||
const useMobileEditPopup = shouldUseMobileEditPopup()
|
||
|
||
const gridRef = useRef<TreeListRef | undefined>(undefined)
|
||
const widgetGroupRef = useRef<HTMLDivElement>(null)
|
||
const editingFormDataRef = useRef<Record<string, any>>({})
|
||
const editingFormInstanceRef = useRef<any | undefined>(undefined)
|
||
// Edit popup açıkken grid state'inin kaydedilmesini engeller.
|
||
const isEditingRef = useRef(false)
|
||
|
||
const [treeListDataSource, setTreeListDataSource] = useState<CustomStore<any, any>>()
|
||
const [columnData, setColumnData] = useState<GridColumnData[]>()
|
||
const [formData, setFormData] = useState<any>()
|
||
const [mode, setMode] = useState<RowMode>('view')
|
||
const gridDto = useListFormGridDto(listFormCode, extGridDto)
|
||
const [isPopupFullScreen, setIsPopupFullScreen] = useState(false)
|
||
const [expandedRowKeys, setExpandedRowKeys] = useState<any[]>([])
|
||
const [notePanelTarget, setNotePanelTarget] = useState<{
|
||
entityName: string
|
||
entityId: string
|
||
} | null>(null)
|
||
|
||
const { widgets, refreshWidgets } = useListFormWidgets(listFormCode, gridDto, isSubForm)
|
||
const widgetGroupHeight = useWidgetGroupHeight(widgetGroupRef, widgets)
|
||
useListFormCustomSources(gridDto)
|
||
|
||
const getTreeInstance = useCallback(() => gridRef.current?.instance(), [])
|
||
|
||
const { customSaveState, customLoadState } = useListFormStateStoring({
|
||
listFormCode,
|
||
storageKey: gridDto?.gridOptions.stateStoringDto?.storageKey,
|
||
filterPrefix: 'tree',
|
||
skipSaveRef: isEditingRef,
|
||
})
|
||
|
||
const { filterToolbarData, ...filterData } = useFilters({
|
||
gridDto,
|
||
gridRef,
|
||
listFormCode,
|
||
saveGridState: customSaveState,
|
||
searchParams,
|
||
})
|
||
|
||
const { createSelectDataSource } = useListFormCustomDataSource({ gridRef })
|
||
|
||
const refreshTree = useCallback(() => {
|
||
getTreeInstance()?.refresh()
|
||
}, [getTreeInstance])
|
||
|
||
const { extraFilters, setExtraFilters } = useExtraFilters({
|
||
gridDto,
|
||
listFormCode,
|
||
searchParams,
|
||
onFilterChanged: refreshTree,
|
||
})
|
||
|
||
const openNotePanel = useCallback(
|
||
(rowData: Record<string, any>) => {
|
||
const entityId = getValueByField(rowData, gridDto?.gridOptions.keyFieldName)
|
||
if (entityId === undefined || entityId === null || entityId === '') {
|
||
return
|
||
}
|
||
|
||
setNotePanelTarget({
|
||
entityName: gridDto?.gridOptions.listFormCode ?? listFormCode,
|
||
entityId: String(entityId),
|
||
})
|
||
},
|
||
[gridDto, listFormCode],
|
||
)
|
||
|
||
const { getBandedColumns, refreshLookupsForRow } = useListFormColumns({
|
||
gridDto,
|
||
listFormCode,
|
||
isSubForm,
|
||
gridRef,
|
||
onShowNote: openNotePanel,
|
||
})
|
||
|
||
/* =======================
|
||
TOOLBAR
|
||
======================= */
|
||
|
||
const updateWorkflowApprovalButtons = useCallback(
|
||
(component?: any, selectedRowsData?: Record<string, unknown>[]) => {
|
||
const tree = component ?? getTreeInstance()
|
||
if (!tree) return
|
||
|
||
updateWorkflowApprovalToolbarItems(
|
||
tree,
|
||
gridDto?.gridOptions.workflowDto,
|
||
selectedRowsData ?? tree.getSelectedRowsData(),
|
||
currentUser,
|
||
)
|
||
},
|
||
[currentUser, getTreeInstance, gridDto],
|
||
)
|
||
|
||
const refreshData = useCallback(() => {
|
||
const tree = getTreeInstance()
|
||
Promise.resolve(tree?.refresh()).finally(() => updateWorkflowApprovalButtons(tree))
|
||
void refreshWidgets()
|
||
}, [getTreeInstance, updateWorkflowApprovalButtons, refreshWidgets])
|
||
|
||
const getSelectedRowKeys = useCallback(
|
||
async () => (await getTreeInstance()?.getSelectedRowKeys()) ?? [],
|
||
[getTreeInstance],
|
||
)
|
||
const getSelectedRowsData = useCallback(
|
||
() => getTreeInstance()?.getSelectedRowsData() ?? [],
|
||
[getTreeInstance],
|
||
)
|
||
const getFilter = useCallback(() => getTreeInstance()?.getCombinedFilter(), [getTreeInstance])
|
||
|
||
const toggleAllNodes = useCallback(
|
||
(expand: boolean) => {
|
||
const tree = getTreeInstance()
|
||
if (!tree) return
|
||
|
||
tree.forEachNode((node: any) => {
|
||
if (!node.hasChildren) return
|
||
if (expand) {
|
||
tree.expandRow(node.key)
|
||
} else {
|
||
tree.collapseRow(node.key)
|
||
}
|
||
})
|
||
},
|
||
[getTreeInstance],
|
||
)
|
||
|
||
const expandAll = useCallback(() => toggleAllNodes(true), [toggleAllNodes])
|
||
const collapseAll = useCallback(() => toggleAllNodes(false), [toggleAllNodes])
|
||
|
||
const { toolbarData, toolbarModalData, setToolbarModalData } = useToolbar({
|
||
gridDto,
|
||
listFormCode,
|
||
getSelectedRowKeys,
|
||
getSelectedRowsData,
|
||
refreshData,
|
||
expandAll,
|
||
collapseAll,
|
||
getFilter,
|
||
layout: layoutTypes.tree,
|
||
})
|
||
|
||
const orderedToolbarData = useMemo(
|
||
() => orderListToolbarItems([...toolbarData, ...filterToolbarData]),
|
||
[toolbarData, filterToolbarData],
|
||
)
|
||
|
||
/* =======================
|
||
TREE EVENTS
|
||
======================= */
|
||
|
||
const onSelectionChanged = useCallback(
|
||
(data: any) => {
|
||
const tree = getTreeInstance()
|
||
if (!gridDto?.gridOptions || !tree) return
|
||
|
||
if (gridDto.gridOptions.editingOptionDto?.allowDeleting) {
|
||
const items = tree.option('toolbar')?.items ?? []
|
||
const deleteSelectedIndex = items.findIndex(
|
||
(item: any) => item.name === 'deleteSelectedRecords',
|
||
)
|
||
|
||
if (deleteSelectedIndex >= 0) {
|
||
tree.option(
|
||
`toolbar.items[${deleteSelectedIndex}].options.visible`,
|
||
data.selectedRowsData.length > 1,
|
||
)
|
||
}
|
||
}
|
||
|
||
updateWorkflowApprovalButtons(tree, data.selectedRowsData)
|
||
|
||
if (data.selectedRowsData.length) {
|
||
setFormData(data.selectedRowsData[0])
|
||
}
|
||
},
|
||
[getTreeInstance, gridDto, updateWorkflowApprovalButtons],
|
||
)
|
||
|
||
const onCellPrepared = useMemo(() => createConditionalCellStyleHandler(gridDto), [gridDto])
|
||
|
||
const onInitNewRow = useCallback(
|
||
(e: TreeListTypes.InitNewRowEvent) => {
|
||
if (!gridDto?.columnFormats) {
|
||
editingFormDataRef.current = { ...(e.data || {}) }
|
||
return
|
||
}
|
||
|
||
setMode('new')
|
||
setIsPopupFullScreen(
|
||
useMobileEditPopup || (gridDto.gridOptions.editingOptionDto?.popup?.fullScreen ?? false),
|
||
)
|
||
|
||
e.promise = applyNewRowDefaults(
|
||
gridDto,
|
||
e.data,
|
||
searchParams?.get('filter'),
|
||
extraFilters,
|
||
).then((data) => {
|
||
editingFormDataRef.current = { ...data }
|
||
})
|
||
},
|
||
[gridDto, searchParams, extraFilters, useMobileEditPopup],
|
||
)
|
||
|
||
const onRowInserting = useCallback(
|
||
(e: TreeListTypes.RowInsertingEvent) => {
|
||
e.data = buildInsertPayload(gridDto, e.data)
|
||
},
|
||
[gridDto],
|
||
)
|
||
|
||
const onRowUpdating = useCallback(
|
||
(e: TreeListTypes.RowUpdatingEvent) => {
|
||
if (!gridDto?.columnFormats) return
|
||
e.newData = buildUpdatePayload(gridDto, e.oldData, e.newData)
|
||
},
|
||
[gridDto],
|
||
)
|
||
|
||
const onEditingStart = useCallback(
|
||
(e: TreeListTypes.EditingStartEvent) => {
|
||
isEditingRef.current = true
|
||
editingFormDataRef.current = { ...(e.data || {}) }
|
||
setMode('edit')
|
||
setIsPopupFullScreen(
|
||
useMobileEditPopup || (gridDto?.gridOptions.editingOptionDto?.popup?.fullScreen ?? false),
|
||
)
|
||
|
||
expandJsonFormFields(e.component.option('columns') as GridColumnData[], e.data)
|
||
},
|
||
[gridDto, useMobileEditPopup],
|
||
)
|
||
|
||
const onEditFinished = useCallback(() => {
|
||
isEditingRef.current = false
|
||
setMode('view')
|
||
setIsPopupFullScreen(false)
|
||
}, [])
|
||
|
||
const onDataErrorOccurred = useCallback((e: TreeListTypes.DataErrorOccurredEvent) => {
|
||
toast.push(
|
||
<Notification type="danger" duration={2000}>
|
||
{e.error?.message}
|
||
</Notification>,
|
||
{ placement: 'bottom-end' },
|
||
)
|
||
}, [])
|
||
|
||
const cascadeMaps = useMemo(() => createCascadeMaps(gridDto), [gridDto])
|
||
|
||
const onEditorPreparing = useCallback(
|
||
(editor: TreeListTypes.EditorPreparingEvent) => {
|
||
if (editor.parentType !== 'dataRow' || !editor.dataField || !gridDto) return
|
||
|
||
const columnFormat = gridDto.columnFormats.find(
|
||
(column) => column.fieldName === editor.dataField,
|
||
)
|
||
const isNewRow = Boolean((editor as any).row?.isNewRow) || mode === 'new'
|
||
|
||
if (columnFormat?.editorOptions) {
|
||
try {
|
||
editor.editorOptions = {
|
||
...editor.editorOptions,
|
||
...JSON.parse(columnFormat.editorOptions),
|
||
}
|
||
} catch (err) {
|
||
console.error('EditorOptions parse error:', columnFormat.fieldName, err)
|
||
}
|
||
}
|
||
|
||
const hasReadOnlyEditorOption = editor.editorOptions?.readOnly === true
|
||
const hasDisabledEditorOption = editor.editorOptions?.disabled === true
|
||
|
||
if (
|
||
(isNewRow && columnFormat?.allowAdding === false) ||
|
||
(!isNewRow && columnFormat?.allowEditing === false)
|
||
) {
|
||
editor.editorOptions.readOnly = true
|
||
} else if (isNewRow && columnFormat?.allowAdding === true) {
|
||
if (!hasReadOnlyEditorOption) editor.editorOptions.readOnly = false
|
||
if (!hasDisabledEditorOption) editor.editorOptions.disabled = false
|
||
}
|
||
|
||
const cascadeInfo = cascadeMaps.cascadeFieldsMap.get(editor.dataField)
|
||
if (cascadeInfo) {
|
||
attachCascadeBehavior({ editor, gridDto, cascadeInfo, maps: cascadeMaps })
|
||
}
|
||
|
||
// phoneCountry maskesi ülke alanını bu olaydan izler; DataGrid formu fieldDataChanged yayınlamaz.
|
||
attachFieldValueBroadcast(editor)
|
||
|
||
if (columnFormat?.editOrderNo != null && columnFormat.editorScript) {
|
||
attachEditorValueChangedScript({
|
||
editor,
|
||
editorScript: columnFormat.editorScript,
|
||
fieldName: columnFormat.fieldName,
|
||
editingFormInstanceRef,
|
||
getActiveEditingForm,
|
||
})
|
||
}
|
||
|
||
attachEditorButtonContext(editor)
|
||
},
|
||
[gridDto, cascadeMaps, mode],
|
||
)
|
||
|
||
/* =======================
|
||
COLUMNS & DATASOURCE
|
||
======================= */
|
||
|
||
useEffect(() => {
|
||
setTreeListDataSource(undefined)
|
||
setColumnData(undefined)
|
||
|
||
const instance = getTreeInstance()
|
||
if (instance) {
|
||
instance.option('columns', undefined)
|
||
instance.option('dataSource', undefined)
|
||
instance.state(null)
|
||
}
|
||
}, [listFormCode, getTreeInstance])
|
||
|
||
useEffect(() => {
|
||
if (!gridDto) return
|
||
|
||
const columns = getBandedColumns()
|
||
setColumnData(columns)
|
||
setTreeListDataSource(
|
||
createSelectDataSource(
|
||
gridDto.gridOptions,
|
||
listFormCode,
|
||
searchParams,
|
||
layoutTypes.tree,
|
||
columns,
|
||
),
|
||
)
|
||
// getBandedColumns her render'da yeni referans üretebildiği için bağımlılığa alınmaz.
|
||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||
}, [gridDto, listFormCode, searchParams, currentCulture, localizationTexts])
|
||
|
||
// Başlangıçta açık olacak düğümler.
|
||
useEffect(() => {
|
||
setExpandedRowKeys(gridDto?.gridOptions.treeOptionDto?.expandedRowKeys ?? [])
|
||
}, [gridDto])
|
||
|
||
useEffect(() => {
|
||
const instance = getTreeInstance()
|
||
if (columnData && instance) {
|
||
instance.option('columns', columnData as any)
|
||
}
|
||
}, [columnData, getTreeInstance])
|
||
|
||
useEffect(() => {
|
||
const instance = getTreeInstance()
|
||
if (treeListDataSource && instance) {
|
||
instance.option('dataSource', treeListDataSource)
|
||
}
|
||
}, [treeListDataSource, getTreeInstance])
|
||
|
||
// Otomatik state kaydetme/yükleme kapalı; manuel akış kullanılır.
|
||
useEffect(() => {
|
||
if (!gridDto) return
|
||
getTreeInstance()?.option('stateStoring', { enabled: false })
|
||
}, [gridDto, getTreeInstance])
|
||
|
||
useEffect(() => {
|
||
const instance = getTreeInstance()
|
||
if (!gridDto || !instance || !treeListDataSource || !columnData) return
|
||
|
||
customLoadState()
|
||
.then((state) => {
|
||
if (state) instance.state(state)
|
||
})
|
||
.catch((err) => console.error('State load error:', err))
|
||
}, [gridDto, treeListDataSource, columnData, customLoadState, getTreeInstance])
|
||
|
||
/* =======================
|
||
EDITING FORM
|
||
======================= */
|
||
|
||
const mapFormItem = useMemo(
|
||
() =>
|
||
createFormItemMapper({
|
||
mode,
|
||
translate,
|
||
rawFilter: searchParams?.get('filter'),
|
||
extraFilters,
|
||
getEditingFormData: () => editingFormDataRef.current,
|
||
}),
|
||
[mode, translate, searchParams, extraFilters],
|
||
)
|
||
|
||
const editingFormItems = useMemo(
|
||
() => buildEditingFormItems(gridDto, mapFormItem, mode, translate),
|
||
[gridDto, mapFormItem, mode, translate],
|
||
)
|
||
|
||
const editingFormHandlers = useMemo(
|
||
() =>
|
||
createEditingFormHandlers({
|
||
getGridDto: () => gridDto,
|
||
getGridInstance: getTreeInstance,
|
||
editingFormDataRef,
|
||
editingFormInstanceRef,
|
||
}),
|
||
[gridDto, getTreeInstance],
|
||
)
|
||
|
||
const editPopupOptions = useMemo(
|
||
() =>
|
||
buildEditPopupOptions({
|
||
popupOptions: gridDto?.gridOptions.editingOptionDto?.popup,
|
||
mode,
|
||
isPopupFullScreen,
|
||
useMobileEditPopup,
|
||
baseWrapperClass: 'dx-treelist-edit-popup',
|
||
translate,
|
||
handlers: {
|
||
onSave: () => getTreeInstance()?.saveEditData(),
|
||
onCancel: () => getTreeInstance()?.cancelEditData(),
|
||
onToggleFullScreen: () => setIsPopupFullScreen((current) => !current),
|
||
},
|
||
}),
|
||
[gridDto, mode, isPopupFullScreen, useMobileEditPopup, translate, getTreeInstance],
|
||
)
|
||
|
||
/* =======================
|
||
RENDER
|
||
======================= */
|
||
|
||
const gridOptions = gridDto?.gridOptions
|
||
const treeOptions = gridOptions?.treeOptionDto
|
||
const autoExpandAll = treeOptions?.autoExpandAll ?? false
|
||
// Store'un anahtariyla ayni olmak zorunda; farkli olursa DevExtreme E1044 firlatir.
|
||
const treeKeyExpr = gridOptions
|
||
? resolveStoreKeyFieldName(gridOptions, layoutTypes.tree)
|
||
: undefined
|
||
|
||
return (
|
||
<>
|
||
<div ref={widgetGroupRef} className={widgets.length > 0 ? 'mt-2' : ''}>
|
||
<WidgetGroup widgetGroups={widgets} />
|
||
</div>
|
||
|
||
<Container className={DX_CLASSNAMES}>
|
||
{!isSubForm && <PageTitle title={translate('::' + gridOptions?.title)} />}
|
||
|
||
{gridDto && gridOptions && columnData && (
|
||
<div className="p-1 bg-white dark:bg-neutral-800 dark:border-neutral-700">
|
||
<TreeListDx
|
||
ref={gridRef as any}
|
||
id={'TreeList-' + listFormCode}
|
||
className="list-view-toolbar-host"
|
||
height={
|
||
gridOptions.height > 0
|
||
? gridOptions.height
|
||
: gridOptions.fullHeight
|
||
? `calc(100vh - ${170 + widgetGroupHeight}px)`
|
||
: undefined
|
||
}
|
||
width={gridOptions.width || '100%'}
|
||
dataStructure="plain"
|
||
keyExpr={treeKeyExpr}
|
||
parentIdExpr={treeOptions?.parentIdExpr}
|
||
hasItemsExpr={treeOptions?.hasItemsExpr}
|
||
rootValue={
|
||
treeOptions?.rootValue === '' || treeOptions?.rootValue === undefined
|
||
? null
|
||
: treeOptions.rootValue
|
||
}
|
||
{...(!autoExpandAll && {
|
||
expandedRowKeys,
|
||
onRowExpanding: (e: any) => setExpandedRowKeys((prev) => [...prev, e.key]),
|
||
onRowCollapsing: (e: any) =>
|
||
setExpandedRowKeys((prev) => prev.filter((key) => key !== e.key)),
|
||
})}
|
||
autoExpandAll={autoExpandAll}
|
||
allowColumnResizing={gridOptions.columnOptionDto?.allowColumnResizing}
|
||
allowColumnReordering={gridOptions.columnOptionDto?.allowColumnReordering}
|
||
showBorders={gridOptions.columnOptionDto?.showBorders}
|
||
showRowLines={gridOptions.columnOptionDto?.showRowLines}
|
||
showColumnLines={gridOptions.columnOptionDto?.showColumnLines}
|
||
columnResizingMode={gridOptions.columnOptionDto?.columnResizingMode}
|
||
columnAutoWidth={gridOptions.columnOptionDto?.columnAutoWidth}
|
||
rtlEnabled={gridOptions.columnOptionDto?.rtlEnabled}
|
||
rowAlternationEnabled={gridOptions.columnOptionDto?.rowAlternationEnabled}
|
||
hoverStateEnabled={gridOptions.columnOptionDto?.hoverStateEnabled}
|
||
columnHidingEnabled={gridOptions.columnOptionDto?.columnHidingEnabled}
|
||
focusedRowEnabled={gridOptions.columnOptionDto?.focusedRowEnabled}
|
||
showColumnHeaders={gridOptions.columnOptionDto?.showColumnHeaders}
|
||
filterSyncEnabled
|
||
onRowPrepared={(e) => {
|
||
if (e.rowType === 'data') {
|
||
e.rowElement.style.height = gridOptions.rowDto.rowHeight
|
||
e.rowElement.style.whiteSpace = gridOptions.rowDto.whiteSpace
|
||
e.rowElement.style.overflowWrap = gridOptions.rowDto.overflowWrap
|
||
}
|
||
}}
|
||
onSelectionChanged={onSelectionChanged}
|
||
onInitNewRow={onInitNewRow}
|
||
onCellPrepared={onCellPrepared}
|
||
onRowInserting={onRowInserting}
|
||
onRowUpdating={onRowUpdating}
|
||
onEditingStart={onEditingStart}
|
||
onDataErrorOccurred={onDataErrorOccurred}
|
||
onEditCanceled={onEditFinished}
|
||
onSaved={onEditFinished}
|
||
onRowInserted={(e) => {
|
||
startWorkflowForInsertedRow(e, gridDto, listFormCode, refreshTree)
|
||
props.refreshData?.()
|
||
void refreshWidgets()
|
||
void refreshLookupsForRow(e.component, e.data)
|
||
}}
|
||
onRowUpdated={(e) => {
|
||
props.refreshData?.()
|
||
void refreshWidgets()
|
||
void refreshLookupsForRow(e.component, e.data)
|
||
}}
|
||
onRowRemoved={() => {
|
||
props.refreshData?.()
|
||
void refreshWidgets()
|
||
}}
|
||
onEditorPreparing={onEditorPreparing}
|
||
onContentReady={(e) => {
|
||
updateWorkflowApprovalButtons(e.component)
|
||
|
||
// Veri yenilendikten sonra açık düğümleri geri yükle.
|
||
if (!autoExpandAll && expandedRowKeys.length > 0) {
|
||
e.component.option('expandedRowKeys', expandedRowKeys)
|
||
}
|
||
}}
|
||
>
|
||
<RemoteOperations filtering sorting grouping={false} />
|
||
<Editing
|
||
refreshMode={gridOptions.editingOptionDto?.refreshMode}
|
||
mode={gridOptions.editingOptionDto?.mode}
|
||
allowDeleting={gridOptions.editingOptionDto?.allowDeleting}
|
||
allowUpdating={gridOptions.editingOptionDto?.allowUpdating}
|
||
allowAdding={gridOptions.editingOptionDto?.allowAdding}
|
||
useIcons={gridOptions.editingOptionDto?.useIcons}
|
||
confirmDelete={gridOptions.editingOptionDto?.confirmDelete}
|
||
selectTextOnEditStart={gridOptions.editingOptionDto?.selectTextOnEditStart}
|
||
startEditAction={gridOptions.editingOptionDto?.startEditAction}
|
||
popup={editPopupOptions}
|
||
form={{
|
||
colCount: 1,
|
||
onContentReady: editingFormHandlers.onContentReady,
|
||
onFieldDataChanged: editingFormHandlers.onFieldDataChanged,
|
||
items: editingFormItems,
|
||
}}
|
||
/>
|
||
<Template name="cellEditTagBox" render={TagBoxEditorComponent} />
|
||
<Template name="cellEditGridBox" render={GridBoxEditorComponent} />
|
||
<Template name="cellEditImageUpload" render={ImageUploadEditorComponent} />
|
||
<Template
|
||
name="cellEditImageViewer"
|
||
render={(data: any) => (
|
||
<ImageViewerEditorComponent
|
||
{...data}
|
||
fallbackFormData={editingFormDataRef.current}
|
||
/>
|
||
)}
|
||
/>
|
||
<Template name="extraFilters">
|
||
<GridExtraFilterToolbar
|
||
filters={gridOptions.extraFilterDto ?? []}
|
||
extraFilters={extraFilters}
|
||
setExtraFilters={setExtraFilters}
|
||
/>
|
||
</Template>
|
||
<Toolbar visible={orderedToolbarData.length > 0}>
|
||
{orderedToolbarData.map((item) => (
|
||
<Item key={item.name} {...item} />
|
||
))}
|
||
{gridOptions.extraFilterDto?.length ? (
|
||
<Item location="before" template="extraFilters" cssClass="no-default" />
|
||
) : null}
|
||
</Toolbar>
|
||
<Sorting mode={gridOptions.sortMode} />
|
||
<FilterRow
|
||
visible={gridOptions.filterRowDto?.visible}
|
||
applyFilter={gridOptions.filterRowDto?.applyFilter}
|
||
/>
|
||
<FilterPanel visible={gridOptions.filterPanelDto.visible} />
|
||
<HeaderFilter visible={gridOptions.headerFilterDto.visible} />
|
||
<SearchPanel
|
||
visible={gridOptions.searchPanelDto.visible}
|
||
width={gridOptions.searchPanelDto.width}
|
||
placeholder={translate('::App.Platform.Search2')}
|
||
/>
|
||
<Selection
|
||
mode={gridOptions.selectionDto?.mode}
|
||
recursive={treeOptions?.recursiveSelection || false}
|
||
/>
|
||
<Paging enabled defaultPageSize={gridOptions.pageSize ?? 10} />
|
||
<Pager
|
||
visible={gridOptions.pagerOptionDto?.visible ?? true}
|
||
allowedPageSizes={
|
||
gridOptions.pagerOptionDto?.allowedPageSizes?.split(',').map(Number) ??
|
||
defaultPageSizes
|
||
}
|
||
showPageSizeSelector={gridOptions.pagerOptionDto?.showPageSizeSelector ?? true}
|
||
showInfo={gridOptions.pagerOptionDto?.showInfo ?? true}
|
||
showNavigationButtons={gridOptions.pagerOptionDto?.showNavigationButtons ?? true}
|
||
infoText={gridOptions.pagerOptionDto?.infoText}
|
||
displayMode={gridOptions.pagerOptionDto?.displayMode ?? 'full'}
|
||
/>
|
||
<ColumnChooser
|
||
enabled={gridOptions.columnOptionDto?.columnChooserEnabled}
|
||
mode={gridOptions.columnOptionDto?.columnChooserMode}
|
||
/>
|
||
<ColumnFixing enabled={gridOptions.columnOptionDto?.columnFixingEnabled} />
|
||
<Scrolling mode={gridOptions.pagerOptionDto?.scrollingMode} />
|
||
<LoadPanel
|
||
enabled={gridOptions.pagerOptionDto?.loadPanelEnabled}
|
||
text={gridOptions.pagerOptionDto?.loadPanelText}
|
||
/>
|
||
</TreeListDx>
|
||
|
||
{gridOptions.subFormsDto?.length > 0 &&
|
||
gridOptions.subFormsListFormType === SubFormTabTypeEnum.List && (
|
||
<>
|
||
<hr className="my-2" />
|
||
<SubForms gridDto={gridDto} formData={formData} level={level ?? 0} />
|
||
</>
|
||
)}
|
||
|
||
<Dialog
|
||
width={useMobileEditPopup ? '100%' : 1000}
|
||
isOpen={filterData.isImportModalOpen || false}
|
||
onClose={() => filterData.setIsImportModalOpen(false)}
|
||
onRequestClose={() => filterData.setIsImportModalOpen(false)}
|
||
>
|
||
<Dialog.Header className="-mx-6 -mt-6 flex h-11 items-center px-6 pr-20 border-b border-gray-200 dark:border-gray-700">
|
||
<h2 className="text-lg font-semibold text-gray-800 dark:text-gray-100">
|
||
{translate('::App.ListForm.ImportManager')}
|
||
</h2>
|
||
</Dialog.Header>
|
||
<Dialog.Body className="flex flex-col">
|
||
<ImportDashboard gridDto={gridDto} />
|
||
</Dialog.Body>
|
||
</Dialog>
|
||
</div>
|
||
)}
|
||
|
||
<Dialog
|
||
isOpen={toolbarModalData?.open || false}
|
||
onClose={() => setToolbarModalData(undefined)}
|
||
onRequestClose={() => setToolbarModalData(undefined)}
|
||
>
|
||
{toolbarModalData?.content}
|
||
</Dialog>
|
||
<GridFilterDialogs gridRef={gridRef as any} listFormCode={listFormCode} {...filterData} />
|
||
{notePanelTarget && (
|
||
<NotePanel
|
||
entityName={notePanelTarget.entityName}
|
||
entityId={notePanelTarget.entityId}
|
||
isVisible
|
||
onToggle={() => setNotePanelTarget(null)}
|
||
/>
|
||
)}
|
||
</Container>
|
||
</>
|
||
)
|
||
}
|
||
|
||
export default Tree
|