diff --git a/api/src/Kurs.Platform.DbMigrator/Seeds/ListFormSeeder_Saas.cs b/api/src/Kurs.Platform.DbMigrator/Seeds/ListFormSeeder_Saas.cs
index 56b4879e..bded9251 100644
--- a/api/src/Kurs.Platform.DbMigrator/Seeds/ListFormSeeder_Saas.cs
+++ b/api/src/Kurs.Platform.DbMigrator/Seeds/ListFormSeeder_Saas.cs
@@ -2702,7 +2702,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
}),
InsertFieldsDefaultValueJson = DefaultInsertFieldsDefaultValueJson,
FormFieldsDefaultValueJson = JsonSerializer.Serialize(new FieldsDefaultValue[] {
- new FieldsDefaultValue() { FieldName = "IsDisabled", FieldDbType = DbType.Boolean, Value = "false", CustomValueType = FieldCustomValueTypeEnum.Value }
+ new() { FieldName = "IsDisabled", FieldDbType = DbType.Boolean, Value = "false", CustomValueType = FieldCustomValueTypeEnum.Value }
})
}
);
diff --git a/ui/src/views/list/Grid.tsx b/ui/src/views/list/Grid.tsx
index 2c48d60f..33659f28 100644
--- a/ui/src/views/list/Grid.tsx
+++ b/ui/src/views/list/Grid.tsx
@@ -979,16 +979,14 @@ const Grid = (props: GridProps) => {
sortedFormDto.forEach((e: any) => {
if (e.itemType !== 'tabbed') {
- // colCount: max(endpoint.colCount, max(item.colSpan))
- const maxItemColSpan = Math.max(
- ...(e.items?.map((i: any) => i.colSpan || 1) || [1]),
- )
- const effectiveColCount = Math.max(maxItemColSpan, e.colCount || 1)
+ // Backend'den gelen colCount ve colSpan değerlerini kullan
+ const effectiveColCount = e.colCount || 1
+ const effectiveColSpan = e.colSpan || 1
result.push({
itemType: e.itemType,
colCount: effectiveColCount,
- colSpan: e.colSpan,
+ colSpan: effectiveColSpan,
caption: e.caption, // Group'larda caption olmalı
items: e.items
?.sort((a: any, b: any) => (a.order >= b.order ? 1 : -1))
@@ -1013,14 +1011,8 @@ const Grid = (props: GridProps) => {
colSpan: 1,
// caption kullanma! Tabs içindeki title'lar yeterli
tabs: tabbedItems.map((tabbedItem: any) => {
- // Tab için colCount: max(endpoint.colCount, max(item.colSpan))
- const maxItemColSpan = Math.max(
- ...(tabbedItem.items?.map((i: any) => i.colSpan || 1) || [1]),
- )
- const effectiveColCount = Math.max(
- maxItemColSpan,
- tabbedItem.colCount || 1,
- )
+ // Backend'den gelen colCount ve colSpan değerlerini kullan
+ const effectiveColCount = tabbedItem.colCount || 1
return {
title: tabbedItem.caption, // Her tab'ın title'ı
@@ -1094,7 +1086,6 @@ const Grid = (props: GridProps) => {
>
{
const [isPopupFullScreen, setIsPopupFullScreen] = useState(false)
const [expandedRowKeys, setExpandedRowKeys] = useState([])
+ const preloadExportLibs = () => {
+ import('exceljs')
+ import('file-saver')
+ import('devextreme/excel_exporter')
+ import('jspdf')
+ import('devextreme/pdf_exporter')
+ }
+
+ type EditorOptionsWithButtons = {
+ buttons?: any[]
+ } & Record
+
const defaultSearchParams = useRef(null)
useEffect(() => {
@@ -112,6 +125,7 @@ const Tree = (props: TreeProps) => {
expandAll,
collapseAll,
getFilter,
+ isTree: true
})
const { filterToolbarData, ...filterData } = useFilters({
@@ -630,6 +644,9 @@ const Tree = (props: TreeProps) => {
allowUpdating={gridDto.gridOptions.editingOptionDto?.allowUpdating}
allowAdding={gridDto.gridOptions.editingOptionDto?.allowAdding}
useIcons={gridDto.gridOptions.editingOptionDto?.useIcons}
+ confirmDelete={gridDto.gridOptions.editingOptionDto?.confirmDelete}
+ selectTextOnEditStart={gridDto.gridOptions.editingOptionDto?.selectTextOnEditStart}
+ startEditAction={gridDto.gridOptions.editingOptionDto?.startEditAction}
popup={{
title:
(mode === 'new' ? '✚ ' : '🖊️ ') +
@@ -657,7 +674,205 @@ const Tree = (props: TreeProps) => {
},
],
}}
- />
+ form={{
+ colCount: 1,
+ onFieldDataChanged: (e) => {
+ if (e.dataField) {
+ const formItem = gridDto.gridOptions.editingFormDto
+ .flatMap((group) => group.items || [])
+ .find((i) => i.dataField === e.dataField)
+ if (formItem?.editorScript) {
+ try {
+ eval(formItem.editorScript)
+ } catch (err) {
+ console.error('Script exec error', err)
+ }
+ }
+ }
+ },
+ items:
+ gridDto.gridOptions.editingFormDto?.length > 0
+ ? (() => {
+ const sortedFormDto = gridDto.gridOptions.editingFormDto
+ .slice()
+ .sort((a: any, b: any) => (a.order >= b.order ? 1 : -1))
+
+ // Tabbed item'ları grupla
+ const tabbedItems = sortedFormDto.filter(
+ (e: any) => e.itemType === 'tabbed',
+ )
+ const result: any[] = []
+
+ // Helper function: item mapper
+ const mapFormItem = (i: EditingFormItemDto) => {
+ let editorOptions: EditorOptionsWithButtons = {}
+ try {
+ editorOptions = i.editorOptions && JSON.parse(i.editorOptions)
+
+ if (editorOptions?.buttons) {
+ editorOptions.buttons = (editorOptions?.buttons || []).map(
+ (btn: any) => {
+ if (
+ btn?.options?.onClick &&
+ typeof btn.options.onClick === 'string'
+ ) {
+ btn.options.onClick = eval(`(${btn.options.onClick})`)
+ }
+ return btn
+ },
+ )
+ }
+
+ const rawFilter = searchParams?.get('filter')
+ if (rawFilter) {
+ const parsed = JSON.parse(rawFilter)
+ const filters = extractSearchParamsFields(parsed)
+
+ const hasFilter = filters.some(
+ ([field, op, val]) => field === i.dataField,
+ )
+
+ if (hasFilter) {
+ const existsInExtra = extraFilters.some(
+ (f) => f.fieldName === i.dataField && !!f.value,
+ )
+
+ if (!existsInExtra) {
+ editorOptions = {
+ ...editorOptions,
+ readOnly: true,
+ }
+ }
+ }
+ }
+ } catch {}
+
+ const fieldName = i.dataField.split(':')[0]
+ const listFormField = gridDto.columnFormats.find(
+ (x: any) => x.fieldName === fieldName,
+ )
+
+ if (listFormField?.sourceDbType === DbTypeEnum.Date) {
+ editorOptions = {
+ ...{
+ type: 'date',
+ dateSerializationFormat: 'yyyy-MM-dd',
+ displayFormat: 'shortDate',
+ },
+ ...editorOptions,
+ }
+ } else if (
+ listFormField?.sourceDbType === DbTypeEnum.DateTime ||
+ listFormField?.sourceDbType === DbTypeEnum.DateTime2 ||
+ listFormField?.sourceDbType === DbTypeEnum.DateTimeOffset
+ ) {
+ editorOptions = {
+ ...{
+ type: 'datetime',
+ dateSerializationFormat: 'yyyy-MM-ddTHH:mm:ssxxx',
+ displayFormat: 'shortDateShortTime',
+ },
+ ...editorOptions,
+ }
+ }
+
+ const item: SimpleItemWithColData = {
+ canRead: listFormField?.canRead ?? false,
+ canUpdate: listFormField?.canUpdate ?? false,
+ canCreate: listFormField?.canCreate ?? false,
+ canExport: listFormField?.canExport ?? false,
+ dataField: i.dataField,
+ name: i.dataField,
+ editorType2: i.editorType2,
+ editorType:
+ i.editorType2 == PlatformEditorTypes.dxGridBox
+ ? 'dxDropDownBox'
+ : i.editorType2,
+ colSpan: i.colSpan,
+ isRequired: i.isRequired,
+ editorOptions,
+ editorScript: i.editorScript,
+ }
+
+ if (i.dataField.indexOf(':') >= 0) {
+ item.label = { text: captionize(i.dataField.split(':')[1]) }
+ }
+
+ if (
+ (mode == 'edit' && !item.canUpdate) ||
+ (mode == 'new' && !item.canCreate)
+ ) {
+ item.editorOptions = {
+ ...item.editorOptions,
+ readOnly: true,
+ }
+ }
+
+ return item
+ }
+
+ sortedFormDto.forEach((e: any) => {
+ if (e.itemType !== 'tabbed') {
+
+ result.push({
+ itemType: e.itemType,
+ colCount: e.colCount,
+ colSpan: e.colSpan,
+ caption: e.caption, // Group'larda caption olmalı
+ items: e.items
+ ?.sort((a: any, b: any) => (a.order >= b.order ? 1 : -1))
+ .map(mapFormItem)
+ .filter((a: any) => {
+ if (mode === 'view') {
+ return a.canRead
+ } else if (mode === 'new') {
+ return a.canCreate || a.canRead
+ } else if (mode === 'edit') {
+ return a.canUpdate || a.canRead
+ } else {
+ return false
+ }
+ }),
+ })
+ } else if (tabbedItems.length > 0 && e === tabbedItems[0]) {
+ // Tabbed için caption OLMAMALI - sadece tabs array içinde title kullan
+ result.push({
+ itemType: 'tabbed',
+ colCount: 1,
+ colSpan: 1,
+ // caption kullanma! Tabs içindeki title'lar yeterli
+ tabs: tabbedItems.map((tabbedItem: any) => {
+ // Backend'den gelen colCount ve colSpan değerlerini kullan
+ const effectiveColCount = tabbedItem.colCount || 1
+
+ return {
+ title: tabbedItem.caption, // Her tab'ın title'ı
+ colCount: effectiveColCount,
+ items: tabbedItem.items
+ ?.sort((a: any, b: any) => (a.order >= b.order ? 1 : -1))
+ .map(mapFormItem)
+ .filter((a: any) => {
+ if (mode === 'view') {
+ return a.canRead
+ } else if (mode === 'new') {
+ return a.canCreate || a.canRead
+ } else if (mode === 'edit') {
+ return a.canUpdate || a.canRead
+ } else {
+ return false
+ }
+ }),
+ }
+ }),
+ })
+ }
+ })
+
+ return result
+ })()
+ : undefined,
+ }}
+ >
diff --git a/ui/src/views/list/useToolbar.tsx b/ui/src/views/list/useToolbar.tsx
index ca64d0b0..6018eb18 100644
--- a/ui/src/views/list/useToolbar.tsx
+++ b/ui/src/views/list/useToolbar.tsx
@@ -8,7 +8,6 @@ import { ToolbarItem } from 'devextreme/ui/data_grid_types'
import { useEffect, useState } from 'react'
import { useDialogContext } from '../shared/DialogContext'
import { usePWA } from '@/utils/hooks/usePWA'
-import { text } from 'stream/consumers'
type ToolbarModalData = {
open: boolean
@@ -26,6 +25,7 @@ const useToolbar = ({
getFilter,
expandAll,
collapseAll,
+ isTree = false,
}: {
gridDto?: GridDto
listFormCode: string
@@ -35,6 +35,7 @@ const useToolbar = ({
getFilter: () => void
expandAll?: () => void
collapseAll?: () => void
+ isTree?: boolean
}): {
toolbarData: ToolbarItem[]
toolbarModalData: ToolbarModalData | undefined
@@ -79,7 +80,7 @@ const useToolbar = ({
})
// Add Expand All button for TreeList
- if (gridDto?.gridOptions.layoutDto.defaultLayout === 'tree') {
+ if (isTree) {
items.push({
widget: 'dxButton',
name: 'expandAllButton',