diff --git a/api/src/Erp.Platform.DbMigrator/Seeds/LanguagesData.json b/api/src/Erp.Platform.DbMigrator/Seeds/LanguagesData.json
index 4590e79d..f9997464 100644
--- a/api/src/Erp.Platform.DbMigrator/Seeds/LanguagesData.json
+++ b/api/src/Erp.Platform.DbMigrator/Seeds/LanguagesData.json
@@ -3210,6 +3210,12 @@
"en": "Reset Grid State",
"tr": "Tablo Yapısını Sıfırla"
},
+ {
+ "resourceName": "Platform",
+ "key": "ListForms.ListForm.GridStateReset",
+ "en": "Grid State Reset",
+ "tr": "Tablo Yapısı Sıfırlandı"
+ },
{
"resourceName": "Platform",
"key": "ListForms.ListForm.SaveFilter",
diff --git a/ui/src/views/list/Grid.tsx b/ui/src/views/list/Grid.tsx
index d9efddc1..866145ed 100644
--- a/ui/src/views/list/Grid.tsx
+++ b/ui/src/views/list/Grid.tsx
@@ -131,10 +131,53 @@ const Grid = (props: GridProps) => {
}
}, [searchParams])
+ // StateStoring için storageKey'i memoize et
+ const storageKey = useMemo(() => {
+ return gridDto?.gridOptions.stateStoringDto?.storageKey ?? ''
+ }, [gridDto?.gridOptions.stateStoringDto?.storageKey])
+
+ const customSaveState = useCallback(
+ (state: any) => {
+ if (isEditingRef.current) {
+ return Promise.resolve()
+ }
+ return postListFormCustomization({
+ listFormCode: listFormCode,
+ customizationType: ListFormCustomizationTypeEnum.GridState,
+ filterName: `list-${storageKey}`,
+ customizationData: JSON.stringify(state),
+ })
+ .then(() => {
+ setGridPanelColor(statedGridPanelColor)
+ toast.push(
+
+ {translate('::ListForms.ListForm.GridStateSaved')}
+ ,
+ {
+ placement: 'top-end',
+ },
+ )
+ })
+ .catch((err) => {
+ toast.push(
+
+ {translate('::ListForms.ListForm.GridStateSaveError')}
+ ,
+ {
+ placement: 'top-end',
+ },
+ )
+ throw err
+ })
+ },
+ [listFormCode, storageKey, translate],
+ )
+
const { filterToolbarData, ...filterData } = useFilters({
gridDto,
gridRef,
listFormCode,
+ saveGridState: customSaveState,
})
const { createSelectDataSource } = useListFormCustomDataSource({ gridRef })
@@ -415,9 +458,13 @@ const Grid = (props: GridProps) => {
gridDto.columnFormats.forEach((col) => {
if (col.lookupDto?.cascadeParentFields && col.fieldName) {
- const parentFields = col.lookupDto.cascadeParentFields.split(',').map((f: string) => f.trim())
- const childFields = col.lookupDto.cascadeEmptyFields?.split(',').map((f: string) => f.trim())
-
+ const parentFields = col.lookupDto.cascadeParentFields
+ .split(',')
+ .map((f: string) => f.trim())
+ const childFields = col.lookupDto.cascadeEmptyFields
+ ?.split(',')
+ .map((f: string) => f.trim())
+
cascadeMap.set(col.fieldName, {
parentFields,
childFields,
@@ -557,28 +604,6 @@ const Grid = (props: GridProps) => {
[gridDto, cascadeFieldsMap],
)
- // StateStoring için storageKey'i memoize et
- const storageKey = useMemo(() => {
- return gridDto?.gridOptions.stateStoringDto?.storageKey ?? ''
- }, [gridDto?.gridOptions.stateStoringDto?.storageKey])
-
- const customSaveState = useCallback(
- (state: any) => {
- if (isEditingRef.current) {
- return Promise.resolve()
- }
- return postListFormCustomization({
- listFormCode: listFormCode,
- customizationType: ListFormCustomizationTypeEnum.GridState,
- filterName: `list-${storageKey}`,
- customizationData: JSON.stringify(state),
- }).then(() => {
- setGridPanelColor(statedGridPanelColor)
- })
- },
- [listFormCode, storageKey],
- )
-
const customLoadState = useCallback(() => {
return getListFormCustomization(
listFormCode,
@@ -810,13 +835,15 @@ const Grid = (props: GridProps) => {
const instance = gridRef?.current?.instance()
if (instance) {
- customLoadState().then((state) => {
- if (state) {
- instance.state(state)
- }
- }).catch((err) => {
- console.error('State load error:', err)
- })
+ customLoadState()
+ .then((state) => {
+ if (state) {
+ instance.state(state)
+ }
+ })
+ .catch((err) => {
+ console.error('State load error:', err)
+ })
}
}, [gridDto, gridDataSource, columnData])
@@ -1014,17 +1041,14 @@ const Grid = (props: GridProps) => {
// Header ekle
worksheet.addRow(columns.map((c: any) => c.caption || c.dataField))
-
+
// Data ekle
items.forEach((item: any) => {
worksheet.addRow(columns.map((c: any) => item[c.dataField!]))
})
const buffer = await workbook.csv.writeBuffer()
- saveAs(
- new Blob([buffer], { type: 'text/csv' }),
- `${listFormCode}_export.csv`,
- )
+ saveAs(new Blob([buffer], { type: 'text/csv' }), `${listFormCode}_export.csv`)
} else if (e.format === 'pdf') {
// jspdf + devextreme pdf exporter => ihtiyaç anında yükle
const [jspdfMod, { exportDataGrid: exportDataPdf }] = await Promise.all([
diff --git a/ui/src/views/list/Tree.tsx b/ui/src/views/list/Tree.tsx
index 77695853..c8b8f8a9 100644
--- a/ui/src/views/list/Tree.tsx
+++ b/ui/src/views/list/Tree.tsx
@@ -24,7 +24,6 @@ import TreeListDx, {
FilterPanel,
FilterRow,
HeaderFilter,
- IStateStoringProps,
LoadPanel,
Pager,
Paging,
@@ -126,10 +125,68 @@ const Tree = (props: TreeProps) => {
}
}, [searchParams])
+ // StateStoring için storageKey'i memoize et
+ const storageKey = useMemo(() => {
+ return gridDto?.gridOptions.stateStoringDto?.storageKey ?? ''
+ }, [gridDto?.gridOptions.stateStoringDto?.storageKey])
+
+ const customSaveState = useCallback(
+ (state: any) => {
+ if (isEditingRef.current) {
+ return Promise.resolve()
+ }
+ return postListFormCustomization({
+ listFormCode: listFormCode,
+ customizationType: ListFormCustomizationTypeEnum.GridState,
+ filterName: `tree-${storageKey}`,
+ customizationData: JSON.stringify(state),
+ })
+ .then(() => {
+ setGridPanelColor(statedGridPanelColor)
+ toast.push(
+
+ {translate('::ListForms.ListForm.GridStateSaved')}
+ ,
+ {
+ placement: 'top-end',
+ },
+ )
+ })
+ .catch((err) => {
+ toast.push(
+
+ {translate('::ListForms.ListForm.GridStateSaveError')}
+ ,
+ {
+ placement: 'top-end',
+ },
+ )
+ throw err
+ })
+ },
+ [listFormCode, storageKey, translate],
+ )
+
+ const customLoadState = useCallback(() => {
+ return getListFormCustomization(
+ listFormCode,
+ ListFormCustomizationTypeEnum.GridState,
+ `tree-${storageKey}`,
+ ).then((response: any) => {
+ if (response.data?.length > 0) {
+ setGridPanelColor(statedGridPanelColor)
+ return JSON.parse(response.data[0].customizationData)
+ }
+ // Veri yoksa null dön (DevExtreme bunu default state olarak algılar)
+ return null
+ })
+ }, [listFormCode, storageKey])
+
const { filterToolbarData, ...filterData } = useFilters({
gridDto,
gridRef,
listFormCode,
+ saveGridState: customSaveState,
})
const { createSelectDataSource } = useListFormCustomDataSource({ gridRef })
@@ -543,52 +600,6 @@ const Tree = (props: TreeProps) => {
}
}
- // StateStoring için storageKey'i memoize et
- const storageKey = useMemo(() => {
- return gridDto?.gridOptions.stateStoringDto?.storageKey ?? ''
- }, [gridDto?.gridOptions.stateStoringDto?.storageKey])
-
- const customSaveState = useCallback(
- (state: any) => {
- if (isEditingRef.current) {
- return Promise.resolve()
- }
- return postListFormCustomization({
- listFormCode: listFormCode,
- customizationType: ListFormCustomizationTypeEnum.GridState,
- filterName: `tree-${storageKey}`,
- customizationData: JSON.stringify(state),
- }).then(() => {
- setGridPanelColor(statedGridPanelColor)
- })
- },
- [listFormCode, storageKey],
- )
-
- const customLoadState = useCallback(() => {
- return getListFormCustomization(
- listFormCode,
- ListFormCustomizationTypeEnum.GridState,
- `tree-${storageKey}`,
- ).then((response: any) => {
- if (response.data?.length > 0) {
- setGridPanelColor(statedGridPanelColor)
- return JSON.parse(response.data[0].customizationData)
- }
- // Veri yoksa null dön (DevExtreme bunu default state olarak algılar)
- return null
- })
- }, [listFormCode, storageKey])
-
- // StateStoring fonksiyonlarını ref'e kaydet - Grid'deki gibi
- const customSaveStateRef = useRef(customSaveState)
- const customLoadStateRef = useRef(customLoadState)
-
- useEffect(() => {
- customSaveStateRef.current = customSaveState
- customLoadStateRef.current = customLoadState
- }, [customSaveState, customLoadState])
-
useEffect(() => {
if (gridRef?.current) {
gridRef?.current?.instance().option('columns', undefined)
@@ -727,36 +738,58 @@ const Tree = (props: TreeProps) => {
gridRef.current?.instance().refresh()
}, [extraFilters])
+ useEffect(() => {
+ if (!columnData || !gridRef?.current) return
+
+ const instance = gridRef?.current?.instance()
+ if (instance) {
+ instance.option('columns', columnData as any)
+ }
+ }, [columnData])
+
+ useEffect(() => {
+ if (!treeListDataSource || !gridRef?.current) return
+
+ const instance = gridRef?.current?.instance()
+ if (instance) {
+ instance.option('dataSource', treeListDataSource)
+ }
+ }, [treeListDataSource])
+
useEffect(() => {
refListFormCode.current = listFormCode
- if (!gridRef?.current) {
- return
- }
+ }, [listFormCode])
- gridRef?.current?.instance().option('columns', columnData as any)
- gridRef?.current?.instance().option('dataSource', treeListDataSource)
+ // Component mount olduğunda state'i bir kez yükle
+ useEffect(() => {
+ if (!gridDto || !gridRef?.current || !treeListDataSource || !columnData) return
- const stateStoring: IStateStoringProps = {
- enabled: gridDto?.gridOptions.stateStoringDto?.enabled,
- type: gridDto?.gridOptions.stateStoringDto?.type,
- savingTimeout: gridDto?.gridOptions.stateStoringDto?.savingTimeout,
- storageKey: gridDto?.gridOptions.stateStoringDto?.storageKey,
+ const instance = gridRef?.current?.instance()
+ if (instance) {
+ customLoadState()
+ .then((state) => {
+ if (state) {
+ instance.state(state)
+ }
+ })
+ .catch((err) => {
+ console.error('State load error:', err)
+ })
}
- if (
- gridDto?.gridOptions.stateStoringDto?.enabled &&
- gridDto?.gridOptions.stateStoringDto?.type === 'custom'
- ) {
- // Ref pattern kullan - Grid'deki gibi
- stateStoring.customSave = (state: any) => customSaveStateRef.current(state)
- stateStoring.customLoad = () => customLoadStateRef.current()
+ }, [gridDto, treeListDataSource, columnData])
+
+ // StateStoring'i devre dışı bırak - manuel kaydetme kullanılacak
+ useEffect(() => {
+ if (!gridDto || !gridRef?.current) return
+
+ const instance = gridRef?.current?.instance()
+ if (instance) {
+ // Otomatik state kaydetme/yükleme kapalı
+ instance.option('stateStoring', {
+ enabled: false,
+ })
}
- gridRef?.current?.instance().option('stateStoring', stateStoring)
-
- // State'i yükle - dataSource ve columns hazır olduğunda
- if (treeListDataSource && columnData) {
- gridRef?.current?.instance().state(undefined) // undefined = reload from storage
- }
- }, [columnData, treeListDataSource, gridDto]) // dataSource ve columns hazır olduğunda state yükle
+ }, [gridDto])
return (
<>
diff --git a/ui/src/views/list/useFilters.tsx b/ui/src/views/list/useFilters.tsx
index 9cd5eeb5..ed58c659 100644
--- a/ui/src/views/list/useFilters.tsx
+++ b/ui/src/views/list/useFilters.tsx
@@ -4,7 +4,7 @@ import {
ListFormCustomizationForUserDto,
ListFormCustomizationTypeEnum,
} from '@/proxy/form/models'
-import { getListFormCustomization, postListFormCustomization } from '@/services/list-form-customization.service'
+import { getListFormCustomization } from '@/services/list-form-customization.service'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { DataGridRef } from 'devextreme-react/data-grid'
import { PivotGridRef } from 'devextreme-react/pivot-grid'
@@ -13,6 +13,7 @@ import { ToolbarItem } from 'devextreme/ui/data_grid_types'
import dxDataGrid from 'devextreme/ui/data_grid'
import dxPivotGrid from 'devextreme/ui/pivot_grid'
import dxTreeList from 'devextreme/ui/tree_list'
+import dxGantt from 'devextreme/ui/gantt'
import { Dispatch, MutableRefObject, SetStateAction, useEffect, useState } from 'react'
import { setGridPanelColor } from './Utils'
import { usePermission } from '@/utils/hooks/usePermission'
@@ -26,7 +27,7 @@ export interface ISelectBoxData {
label?: string
}
-type GridInstance = dxDataGrid | dxPivotGrid | dxTreeList
+type GridInstance = dxDataGrid | dxPivotGrid | dxTreeList | dxGantt
// Grid tipini kontrol eden yardımcı fonksiyonlar
const isDataGrid = (grid: GridInstance): grid is dxDataGrid => {
@@ -37,15 +38,12 @@ const isTreeList = (grid: GridInstance): grid is dxTreeList => {
return 'getRootNode' in grid
}
-const getToolbarItems = (grid: GridInstance): any[] => {
- if (isDataGrid(grid)) {
- const toolbarOptions = grid.option('toolbar')
- return toolbarOptions?.items || []
- } else if (isTreeList(grid)) {
- const toolbarOptions = grid.option('toolbar')
- return toolbarOptions?.items || []
- }
- return []
+const isGantt = (grid: GridInstance): grid is dxGantt => {
+ return 'getTaskData' in grid
+}
+
+const supportsState = (grid: GridInstance): grid is dxDataGrid | dxTreeList => {
+ return 'state' in grid && typeof (grid as any).state === 'function'
}
const setToolbarItemValue = (grid: GridInstance, itemName: string, value: any) => {
@@ -140,6 +138,7 @@ const useFilters = ({
gridDto,
gridRef,
listFormCode,
+ saveGridState,
}: {
gridDto?: GridDto
gridRef:
@@ -148,6 +147,7 @@ const useFilters = ({
| MutableRefObject | undefined>
| MutableRefObject
listFormCode: string
+ saveGridState?: (state: any) => Promise
}): {
filterToolbarData: ToolbarItem[]
isCreateUpdateModalOpen: boolean
@@ -261,7 +261,7 @@ const useFilters = ({
})
}
- if (checkPermission("App.Listforms.Listform.Update")) {
+ if (checkPermission('App.Listforms.Listform.Update')) {
menus.push({
text: translate('::ListForms.ListForm.Manage'),
id: 'openManage',
@@ -324,36 +324,12 @@ const useFilters = ({
return
}
- const currentState = grid.state()
- const storageKey = gridDto?.gridOptions.stateStoringDto?.storageKey ?? ''
-
- postListFormCustomization({
- listFormCode: listFormCode,
- customizationType: ListFormCustomizationTypeEnum.GridState,
- filterName: `list-${storageKey}`,
- customizationData: JSON.stringify(currentState),
- })
- .then(() => {
- setGridPanelColor(statedGridPanelColor)
- toast.push(
-
- {translate('::ListForms.ListForm.GridStateSaved')}
- ,
- {
- placement: 'top-end',
- },
- )
- })
- .catch((err) => {
- toast.push(
-
- {translate('::ListForms.ListForm.GridStateSaveError')}
- ,
- {
- placement: 'top-end',
- },
- )
+ if (saveGridState && supportsState(grid)) {
+ const currentState = grid.state()
+ saveGridState(currentState).catch(() => {
+ // Error handling already done in customSaveState
})
+ }
} else if (itemData.id === 'resetGridState') {
// state ye kaydedilen grid ayarlarini siler ve gridi resetler
const grid = gridRef.current?.instance()