Devexpress 25.1.7 versiyonuna convert edildi.

This commit is contained in:
Sedat ÖZTÜRK 2025-11-28 16:31:53 +03:00
parent 6b4e64c3ca
commit d176565887
19 changed files with 695 additions and 615 deletions

View file

@ -20,7 +20,7 @@ public class GridColumnOptionDto
/// <summary> ilk kolon(lar) sabitlesitirlmesi ayari aktif mi
/// </summary>
public bool ColumnFixingEnabled { get; set; }
public bool ColumnFixingEnabled { get; set; } = false;
/// <summary> kolon secme butonu gosterilsin mi
/// </summary>
/// <summary> alabilecegi degerler: 'dragAndDrop', 'select'
@ -30,7 +30,7 @@ public class GridColumnOptionDto
/// </summary>
public bool HoverStateEnabled { get; set; } = false;
public bool ColumnHidingEnabled { get; set; } = true;
public bool FocusedRowEnabled { get; set; } = false;
public bool FocusedRowEnabled { get; set; } = true;
public bool ShowColumnHeaders { get; set; } = true;
}

View file

@ -9589,12 +9589,6 @@
"tr": "Tanımlamalar",
"en": "Definitions"
},
{
"resourceName": "Platform",
"key": "App.Store.Definitions",
"tr": "Tanımlamalar",
"en": "Definitions"
},
{
"resourceName": "Platform",
"key": "App.Project.Type",

View file

@ -54,12 +54,13 @@ public static class SeederDefaults
public static readonly string DefaultGroupPanelJson = JsonSerializer.Serialize(new { Visible = true });
public static readonly string DefaultColumnOptionJson = JsonSerializer.Serialize(new
{
ColumnFixingEnabled = true,
ColumnFixingEnabled = false,
ColumnAutoWidth = true,
ColumnChooserEnabled = true,
AllowColumnResizing = true,
AllowColumnReordering = true,
ColumnResizingMode = "widget",
FocusRowEnabled = true,
});
public static readonly string DefaultLayoutJson = JsonSerializer.Serialize(new LayoutDto()
{
@ -72,7 +73,7 @@ public static class SeederDefaults
});
public static readonly string DefaultSelectionSingleJson = JsonSerializer.Serialize(new SelectionDto
{
Mode = GridOptions.SelectionModeSingle,
Mode = GridOptions.SelectionModeNone,
AllowSelectAll = false
});
public static readonly string DefaultSelectionMultipleJson = JsonSerializer.Serialize(new SelectionDto

View file

@ -90,3 +90,48 @@ div.dialog-after-open > div.dialog-content.maximized {
min-width: fit-content !important;
}
/* React Pivot Vert Headers cok uzun olmaması icin */
/* Grid accessibility status mesajını gizle */
[e2e-a11y-general-status-container='true'] {
display: none !important;
visibility: hidden !important;
position: absolute !important;
left: -9999px !important;
}
/* Grid accessibility status mesajını gizle */
/* Grid Focused Row - Light Mode */
.dx-datagrid .dx-row-focused.dx-data-row > td:not(.dx-focused),
.dx-datagrid .dx-row-focused.dx-data-row > tr > td:not(.dx-focused) {
background-color: rgba(59, 130, 246, 0.15) !important;
color: inherit !important;
}
.dx-datagrid .dx-row-focused.dx-data-row .dx-link {
background-color: rgba(255, 255, 255, 0.5) !important;
border-radius: 4px !important;
color: #1e40af !important;
}
.dx-datagrid .dx-row-focused.dx-data-row .dx-link:hover {
background-color: rgba(255, 255, 255, 0.8) !important;
color: #1e3a8a !important;
}
/* Grid Focused Row - Dark Mode */
.dark .dx-datagrid .dx-row-focused.dx-data-row > td:not(.dx-focused),
.dark .dx-datagrid .dx-row-focused.dx-data-row > tr > td:not(.dx-focused) {
background-color: rgba(59, 130, 246, 0.25) !important;
color: #e5e7eb !important;
}
.dark .dx-datagrid .dx-row-focused.dx-data-row .dx-link {
background-color: rgba(0, 0, 0, 0.3) !important;
color: #93c5fd !important;
}
.dark .dx-datagrid .dx-row-focused.dx-data-row .dx-link:hover {
background-color: rgba(0, 0, 0, 0.5) !important;
color: #dbeafe !important;
}
/* Grid Focused Row */

View file

@ -217,8 +217,7 @@ const FormButtons = (props: {
if (onActionNew) {
onActionNew()
} else {
navigate(ROUTES_ENUM.protected.admin.formNew
.replace(':listFormCode', listFormCode))
navigate(ROUTES_ENUM.protected.admin.formNew.replace(':listFormCode', listFormCode))
}
}}
{...(permissions.c ? {} : { disabled: true })}

View file

@ -1,6 +1,7 @@
import { DX_CLASSNAMES } from '@/constants/app.constant'
import {
Form as FormDx,
FormRef,
GroupItem as GroupItemDx,
Label as LabelDx,
SimpleItem as SimpleItemDx,
@ -16,7 +17,7 @@ const FormDevExpress = (props: {
listFormCode: string
isSubForm?: boolean
mode: RowMode
refForm: RefObject<FormDx>
refForm: RefObject<FormRef>
formData: any
formItems: GroupItem[]
setFormData: Dispatch<any>
@ -36,14 +37,14 @@ const FormDevExpress = (props: {
// formItems değiştiğinde (özellikle cascading alanlar için) editörlerin dataSource'larını güncelle
useEffect(() => {
if (!refForm.current?.instance) return
if (!refForm.current?.instance()) return
const allItems = formItems.flatMap((group) => (group.items as SimpleItemWithColData[]) || [])
allItems.forEach((item) => {
if (item.colData?.lookupDto?.dataSourceType && item.editorOptions?.dataSource) {
try {
const editor = refForm.current?.instance.getEditor(item.dataField!)
const editor = refForm.current?.instance().getEditor(item.dataField!)
if (editor) {
editor.option('dataSource', item.editorOptions.dataSource)
}
@ -57,7 +58,7 @@ const FormDevExpress = (props: {
// Cascade fieldlerin disabled durumunu güncelle
const updateCascadeDisabledStates = () => {
if (!refForm.current?.instance) return
if (!refForm.current?.instance()) return
const allItems = formItemsRef.current.flatMap((group) => (group.items as SimpleItemWithColData[]) || [])
@ -67,7 +68,7 @@ const FormDevExpress = (props: {
const parentFields = cascadeParentFields.split(',').map((f: string) => f.trim())
try {
const editor = refForm.current?.instance.getEditor(item.dataField!)
const editor = refForm.current?.instance().getEditor(item.dataField!)
if (editor && mode !== 'view') {
// Parent fieldlerden en az biri boşsa disabled olmalı
const shouldDisable = parentFields.some((parentField: string) => {

View file

@ -1,6 +1,6 @@
import { ColumnFormatDto, GridBoxOptionsDto } from '@/proxy/form/models'
import { Button } from 'devextreme-react/button'
import DataGrid from 'devextreme-react/data-grid'
import DataGrid, { DataGridRef } from 'devextreme-react/data-grid'
import DropDownBox from 'devextreme-react/drop-down-box'
import { ReactElement, useRef } from 'react'
@ -19,7 +19,7 @@ const GridBoxEditorComponent = ({
col?: ColumnFormatDto
editorOptions: any
}): ReactElement => {
const gridRef = useRef<DataGrid>(null)
const gridRef = useRef<DataGridRef>(null)
const val = Array.isArray(value) ? value : [value]
const lookupDto = col?.lookupDto
@ -43,7 +43,7 @@ const GridBoxEditorComponent = ({
//Eğer clear button kullanılırsa altında grid bilgileride otomatik deselect olmalı ve dropbox kapanmalı
if (e.value === null) {
e.component.close()
gridRef.current?.instance.deselectAll()
gridRef.current?.instance().deselectAll()
}
}}
contentRender={(e) => (
@ -100,7 +100,7 @@ const GridBoxEditorComponent = ({
onClick={() => {
e.component.option(
'value',
gridRef.current?.instance.getSelectedRowKeys().map((a: any) => a.key),
gridRef.current?.instance().getSelectedRowKeys().map((a: any) => a.key),
)
e.component.close()
}}

View file

@ -2,7 +2,7 @@ import { Notification, toast } from '@/components/ui'
import { getList } from '@/services/form.service'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { usePermission } from '@/utils/hooks/usePermission'
import { Form as FormDx } from 'devextreme-react/form'
import { FormRef } from 'devextreme-react/form'
import { captionize } from 'devextreme/core/utils/inflector'
import CustomStore from 'devextreme/data/custom_store'
import { GroupItem } from 'devextreme/ui/form'
@ -40,7 +40,7 @@ const useGridData = (props: {
const [formItems, setFormItems] = useState<GroupItem[]>([])
const [permissionResults, setPermissionResults] = useState<PermissionResults>()
const refForm = useRef<FormDx>(null)
const refForm = useRef<FormRef>(null)
const [searchParams] = useSearchParams()
const navigate = useNavigate()
const { translate } = useLocalization()
@ -84,7 +84,7 @@ const useGridData = (props: {
return
}
const validationResult = refForm.current?.instance.validate()
const validationResult = refForm.current?.instance().validate()
if (!validationResult?.isValid) {
return
}

View file

@ -1,13 +1,8 @@
// src/.../useLookupDataSource.ts
import { dynamicFetch } from '@/services/form.service'
import { UiLookupDataSourceTypeEnum } from '@/proxy/form/models'
import CustomStore from 'devextreme/data/custom_store'
import { useCallback } from 'react'
/** Module-scope cache: key -> Promise<array>
* - Aynı anda ılan editörler tek çağrısı üzerinden paylaşır
* - Hata olursa cache temizlenir (yeniden denenebilir)
*/
const __lookupCache = new Map<string, Promise<any[]>>()
const cachedLoader = (key: string, loader: () => Promise<any[]>) => {

View file

@ -5,13 +5,13 @@ import { usePWA } from "@/utils/hooks/usePWA"
import CustomStore from "devextreme/data/custom_store"
import { useMemo, useRef, useState } from "react"
import { useNavigate } from "react-router-dom"
import { Form as FormDx } from 'devextreme-react/form'
import { GroupItem } from 'devextreme/ui/form'
import { PermissionResults, SimpleItemWithColData } from "../form/types"
import { captionize } from 'devextreme/core/utils/inflector'
import { ROUTES_ENUM } from "@/routes/route.constant"
import FormButtons from "../form/FormButtons"
import FormDevExpress from "../form/FormDevExpress"
import { FormRef } from "devextreme-react/cjs/form"
const CardItem = ({
isSubForm,
@ -31,7 +31,7 @@ const CardItem = ({
getCachedLookupDataSource: (editorOptions: any, colData: any, row?: any) => any
}) => {
const [formData, setFormData] = useState(row)
const refForm = useRef<FormDx>(null)
const refForm = useRef<FormRef>(null)
const navigate = useNavigate()
const { translate } = useLocalization()
const { checkPermission } = usePermission()

View file

@ -12,7 +12,7 @@ import { usePermission } from '@/utils/hooks/usePermission'
import { Button, toast, Notification } from '@/components/ui'
import { ROUTES_ENUM } from '@/routes/route.constant'
import { usePWA } from '@/utils/hooks/usePWA'
import { FaCog, FaCrosshairs, FaMinus, FaPlus, FaSearch, FaSyncAlt } from 'react-icons/fa'
import { FaCog, FaCrosshairs, FaSearch, FaSyncAlt } from 'react-icons/fa'
import { buildSeriesDto } from './Utils'
import { ChartSeriesDto } from '@/proxy/admin/charts/models'
import { SelectBoxOption } from '@/types/shared'

View file

@ -18,6 +18,7 @@ import { Template } from 'devextreme-react/core/template'
import DataGrid, {
ColumnChooser,
ColumnFixing,
DataGridRef,
DataGridTypes,
Editing,
Export,
@ -27,7 +28,6 @@ import DataGrid, {
GroupItem as GroupItemDx,
GroupPanel,
HeaderFilter,
IStateStoringProps,
LoadPanel,
Pager,
Paging,
@ -35,6 +35,7 @@ import DataGrid, {
SearchPanel,
Selection,
Sorting,
StateStoring,
Summary,
Toolbar,
TotalItem,
@ -86,7 +87,7 @@ const Grid = (props: GridProps) => {
const { translate } = useLocalization()
const { smaller } = useResponsive()
const gridRef = useRef<DataGrid>()
const gridRef = useRef<DataGridRef>()
const refListFormCode = useRef('')
const widgetGroupRef = useRef<HTMLDivElement>(null)
@ -170,7 +171,7 @@ const Grid = (props: GridProps) => {
}
async function getSelectedRowKeys() {
const grd = gridRef.current?.instance
const grd = gridRef.current?.instance()
if (!grd) {
return []
}
@ -179,7 +180,7 @@ const Grid = (props: GridProps) => {
}
function getSelectedRowsData() {
const grd = gridRef.current?.instance
const grd = gridRef.current?.instance()
if (!grd) {
return []
}
@ -188,11 +189,11 @@ const Grid = (props: GridProps) => {
}
function refreshData() {
gridRef.current?.instance.refresh()
gridRef.current?.instance()?.refresh()
}
function getFilter() {
const grd = gridRef.current?.instance
const grd = gridRef.current?.instance()
if (!grd) {
return
}
@ -202,7 +203,7 @@ const Grid = (props: GridProps) => {
function onSelectionChanged(data: any) {
const grdOpt = gridDto?.gridOptions
const grd = gridRef.current?.instance
const grd = gridRef.current?.instance()
if (!grdOpt || !grd) {
return
}
@ -521,39 +522,41 @@ const Grid = (props: GridProps) => {
}
const customSaveState = useCallback(
(state: any) =>
postListFormCustomization({
(state: any) => {
return postListFormCustomization({
listFormCode: listFormCode,
customizationType: ListFormCustomizationTypeEnum.GridState,
filterName: `list-${gridRef.current?.instance.option('stateStoring')?.storageKey ?? ''}`,
filterName: `list-${gridRef.current?.instance()?.option('stateStoring')?.storageKey ?? ''}`,
customizationData: JSON.stringify(state),
}).then(() => {
setGridPanelColor(statedGridPanelColor)
}),
})
},
[listFormCode],
)
const customLoadState = useCallback(
() =>
getListFormCustomization(
const customLoadState = useCallback(() => {
return getListFormCustomization(
listFormCode,
ListFormCustomizationTypeEnum.GridState,
`list-${gridRef.current?.instance.option('stateStoring')?.storageKey ?? ''}`,
`list-${gridRef.current?.instance()?.option('stateStoring')?.storageKey ?? ''}`,
).then((response: any) => {
setGridPanelColor(statedGridPanelColor)
if (response.data?.length > 0) {
return JSON.parse(response.data[0].customizationData)
}
}),
[listFormCode],
)
})
}, [listFormCode])
useEffect(() => {
if (gridRef?.current) {
gridRef.current.instance.option('columns', undefined)
gridRef.current.instance.option('remoteOperations', false)
gridRef.current.instance.option('dataSource', undefined)
gridRef.current.instance.state(null)
const instance = gridRef?.current?.instance()
if (instance) {
instance.option('columns', undefined)
instance.option('remoteOperations', false)
instance.option('dataSource', undefined)
instance.state(null)
}
}
if (refListFormCode.current !== listFormCode) {
@ -644,6 +647,7 @@ const Grid = (props: GridProps) => {
layoutTypes.grid,
cols,
)
setGridDataSource(dataSource)
}, [gridDto, searchParams])
@ -695,34 +699,12 @@ const Grid = (props: GridProps) => {
searchParams?.delete('filter')
}
gridRef.current?.instance.refresh()
gridRef.current?.instance()?.refresh()
}, [extraFilters])
useEffect(() => {
refListFormCode.current = listFormCode
if (!gridRef?.current) {
return
}
gridRef.current.instance.option('remoteOperations', { groupPaging: true })
gridRef.current.instance.option('columns', columnData)
gridRef.current.instance.option('dataSource', gridDataSource)
const stateStoring: IStateStoringProps = {
enabled: gridDto?.gridOptions.stateStoringDto?.enabled,
type: gridDto?.gridOptions.stateStoringDto?.type,
savingTimeout: gridDto?.gridOptions.stateStoringDto?.savingTimeout,
storageKey: gridDto?.gridOptions.stateStoringDto?.storageKey,
}
if (
gridDto?.gridOptions.stateStoringDto?.enabled &&
gridDto?.gridOptions.stateStoringDto?.type === 'custom'
) {
stateStoring.customSave = customSaveState
stateStoring.customLoad = customLoadState
}
gridRef.current.instance.option('stateStoring', stateStoring)
}, [columnData])
}, [listFormCode])
// WidgetGroup yüksekliğini hesapla
useEffect(() => {
@ -751,7 +733,7 @@ const Grid = (props: GridProps) => {
// DevExtremein varsayılan export davranışını iptal ediyoruz; kendi akışımızı çalıştıracağız
e.cancel = true
const grid = gridRef?.current?.instance
const grid = gridRef?.current?.instance()
if (!grid) return
try {
@ -767,7 +749,7 @@ const Grid = (props: GridProps) => {
const worksheet = workbook.addWorksheet(`${listFormCode}_sheet`)
await exportDataExcel({
component: grid,
component: grid as any,
worksheet,
autoFilterEnabled: true,
})
@ -798,7 +780,7 @@ const Grid = (props: GridProps) => {
await exportDataPdf({
jsPDFDocument: doc,
component: grid,
component: grid as any,
indent: 5,
})
@ -829,15 +811,26 @@ const Grid = (props: GridProps) => {
defaultTitle="Erp Platform"
></Helmet>
)}
{gridDto && columnData && (
{!gridDto && <div className="p-4">Loading grid configuration...</div>}
{gridDto && !columnData && <div className="p-4">Loading columns...</div>}
{gridDto && columnData && !gridDataSource && (
<div className="p-4">Loading data source...</div>
)}
{gridDto &&
columnData &&
gridDataSource &&
(() => {
return true
})() && (
<>
<div className="p-1">
<DataGrid
ref={gridRef as any}
key={`Grid-${listFormCode}-${gridDataSource ? 'loaded' : 'loading'}`}
id={'Grid-' + listFormCode}
//dataSource={gridDataSource}
//remoteOperations={{ groupPaging: true }}
//remoteOperations={false}
dataSource={gridDataSource}
columns={columnData}
remoteOperations={{ groupPaging: true }}
height={
gridDto.gridOptions.height > 0
? gridDto.gridOptions.height
@ -895,6 +888,24 @@ const Grid = (props: GridProps) => {
}}
onEditorPreparing={onEditorPreparing}
>
<StateStoring
enabled={gridDto.gridOptions.stateStoringDto?.enabled}
type={gridDto.gridOptions.stateStoringDto?.type}
savingTimeout={gridDto.gridOptions.stateStoringDto?.savingTimeout}
storageKey={gridDto.gridOptions.stateStoringDto?.storageKey}
customSave={
gridDto?.gridOptions.stateStoringDto?.enabled &&
gridDto?.gridOptions.stateStoringDto?.type === 'custom'
? customSaveState
: undefined
}
customLoad={
gridDto?.gridOptions.stateStoringDto?.enabled &&
gridDto?.gridOptions.stateStoringDto?.type === 'custom'
? customLoadState
: undefined
}
/>
<Export
enabled={gridDto.gridOptions.exportDto?.enabled}
allowExportSelectedData={gridDto.gridOptions.exportDto?.allowExportSelectedData}
@ -933,7 +944,7 @@ const Grid = (props: GridProps) => {
text: translate('::Save'),
type: 'default',
onClick: () => {
const grid = gridRef.current?.instance
const grid = gridRef.current?.instance()
grid?.saveEditData()
},
},
@ -945,7 +956,7 @@ const Grid = (props: GridProps) => {
options: {
text: translate('::Cancel'),
onClick: () => {
const grid = gridRef.current?.instance
const grid = gridRef.current?.instance()
grid?.cancelEditData()
},
},
@ -1206,7 +1217,9 @@ const Grid = (props: GridProps) => {
applyFilter={gridDto.gridOptions.filterRowDto?.applyFilter}
></FilterRow>
<FilterPanel visible={gridDto.gridOptions.filterPanelDto.visible}></FilterPanel>
<HeaderFilter visible={gridDto.gridOptions.headerFilterDto.visible}></HeaderFilter>
<HeaderFilter
visible={gridDto.gridOptions.headerFilterDto.visible}
></HeaderFilter>
<SearchPanel
visible={gridDto.gridOptions.searchPanelDto.visible}
width={gridDto.gridOptions.searchPanelDto.width}
@ -1228,9 +1241,10 @@ const Grid = (props: GridProps) => {
?.split(',')
.map((a: any) => +a)}
showPageSizeSelector={gridDto.gridOptions.pagerOptionDto?.showPageSizeSelector}
showInfo={gridDto.gridOptions.pagerOptionDto?.showInfo}
showNavigationButtons={gridDto.gridOptions.pagerOptionDto?.showNavigationButtons}
infoText={gridDto.gridOptions.pagerOptionDto?.infoText}
showInfo={false}
showNavigationButtons={
gridDto.gridOptions.pagerOptionDto?.showNavigationButtons
}
displayMode={gridDto.gridOptions.pagerOptionDto?.displayMode}
></Pager>
<ColumnChooser

View file

@ -3,7 +3,7 @@ import {
deleteListFormCustomization,
postListFormCustomization,
} from '@/services/list-form-customization.service'
import DataGrid from 'devextreme-react/data-grid'
import { DataGridRef } from 'devextreme-react/data-grid'
import { Dispatch, MutableRefObject, SetStateAction, useState } from 'react'
import CreatableSelect from 'react-select/creatable'
import { ISelectBoxData } from './useFilters'
@ -11,7 +11,7 @@ import { ListFormCustomizationTypeEnum } from '@/proxy/form/models'
const GridFilterDialogs = (props: {
listFormCode: string
gridRef: MutableRefObject<DataGrid | undefined>
gridRef: MutableRefObject<DataGridRef | undefined>
filtersForSelectBox: ISelectBoxData[]
isCreateUpdateModalOpen: boolean
setIsCreateUpdateModalOpen: Dispatch<SetStateAction<boolean>>
@ -68,7 +68,7 @@ const GridFilterDialogs = (props: {
variant="solid"
disabled={!newFilterName || newFilterName === ''}
onClick={async () => {
const grid = gridRef.current?.instance // gridi al
const grid = gridRef.current?.instance() // gridi al
if (!grid) {
return
}
@ -141,7 +141,7 @@ const GridFilterDialogs = (props: {
variant="solid"
disabled={!newFilterId || newFilterId === ''}
onClick={async () => {
const grid = gridRef.current?.instance
const grid = gridRef.current?.instance()
if (!grid || !newFilterId) {
return
}

View file

@ -1,4 +1,4 @@
import { useLocation, useParams, useSearchParams } from 'react-router-dom'
import { useParams, useSearchParams } from 'react-router-dom'
import { useEffect, useState } from 'react'
import Container from '@/components/shared/Container'
import Grid from './Grid'

View file

@ -6,15 +6,21 @@ import {
postListFormCustomization,
} from '@/services/list-form-customization.service'
import { useLocalization } from '@/utils/hooks/useLocalization'
import Chart, { CommonSeriesSettings, Size, Tooltip } from 'devextreme-react/chart'
import Chart, {
ChartRef,
CommonSeriesSettings,
Size,
Tooltip,
} from 'devextreme-react/chart'
import PivotGrid, {
FieldChooser,
FieldPanel,
HeaderFilter,
IStateStoringProps,
PivotGridRef,
PivotGridTypes,
Scrolling,
Search,
StateStoring,
} from 'devextreme-react/pivot-grid'
import CustomStore from 'devextreme/data/custom_store'
import PivotGridDataSource, { Field } from 'devextreme/ui/pivot_grid/data_source'
@ -57,8 +63,8 @@ const Pivot = (props: PivotProps) => {
const { checkPermission } = usePermission()
const isPwaMode = usePWA()
const gridRef = useRef<PivotGrid>()
const chartRef = useRef<Chart>(null)
const gridRef = useRef<PivotGridRef>()
const chartRef = useRef<ChartRef>(null)
const refListFormCode = useRef('')
const [gridDataSource, setGridDataSource] = useState<CustomStore<any, any>>()
@ -113,7 +119,7 @@ const Pivot = (props: PivotProps) => {
}
const clearPivotFilters = () => {
const grid = gridRef.current?.instance
const grid = gridRef.current?.instance()
if (!grid) return
const ds = grid.getDataSource()
@ -128,7 +134,7 @@ const Pivot = (props: PivotProps) => {
}
const moveAllFieldsToFilterArea = () => {
const grid = gridRef.current?.instance
const grid = gridRef.current?.instance()
if (!grid) return
const ds = grid.getDataSource()
@ -136,7 +142,7 @@ const Pivot = (props: PivotProps) => {
const fields = ds.fields()
fields.forEach((field) => {
fields.forEach((field: any) => {
field.area = 'filter' // tüm alanları filtre alanına taşı
field.areaIndex = undefined
})
@ -147,13 +153,13 @@ const Pivot = (props: PivotProps) => {
}
const resetPivotGridState = async () => {
const grid = gridRef.current?.instance
const grid = gridRef.current?.instance()
if (grid) {
// kullaniciya ait kayitli grid state i sil customizationData boşalt silinsin.
await postListFormCustomization({
listFormCode: listFormCode,
customizationType: ListFormCustomizationTypeEnum.GridState,
filterName: `pivot-${gridRef.current?.instance.option('stateStoring')?.storageKey ?? ''}`,
filterName: `pivot-${gridRef.current?.instance()?.option('stateStoring')?.storageKey ?? ''}`,
customizationData: '',
})
@ -164,38 +170,43 @@ const Pivot = (props: PivotProps) => {
}
const customSaveState = useCallback(
(state: any) =>
postListFormCustomization({
(state: any) => {
return postListFormCustomization({
listFormCode: listFormCode,
customizationType: ListFormCustomizationTypeEnum.GridState,
filterName: `pivot-${gridRef.current?.instance.option('stateStoring')?.storageKey ?? ''}`,
filterName: `pivot-${gridRef.current?.instance()?.option('stateStoring')?.storageKey ?? ''}`,
customizationData: JSON.stringify(state),
}).then(() => {
setGridPanelColor(statedGridPanelColor)
}),
})
},
[listFormCode],
)
const customLoadState = useCallback(
() =>
getListFormCustomization(
() => {
return getListFormCustomization(
listFormCode,
ListFormCustomizationTypeEnum.GridState,
`pivot-${gridRef.current?.instance.option('stateStoring')?.storageKey ?? ''}`,
`pivot-${gridRef.current?.instance()?.option('stateStoring')?.storageKey ?? ''}`,
).then((response: any) => {
setGridPanelColor(statedGridPanelColor)
if (response.data?.length > 0) {
return JSON.parse(response.data[0].customizationData)
}
}),
})
},
[listFormCode],
)
useEffect(() => {
if (gridRef?.current) {
gridRef.current.instance.option('remoteOperations', false)
gridRef.current.instance.option('dataSource', undefined)
gridRef.current.instance.option('stateStoring', undefined)
const instance = gridRef?.current?.instance()
if (instance) {
instance.option('remoteOperations', false)
instance.option('dataSource', undefined)
instance.option('stateStoring', undefined)
}
}
}, [listFormCode])
@ -269,31 +280,23 @@ const Pivot = (props: PivotProps) => {
fields,
}
gridRef.current.instance.option('dataSource', dataSource)
gridRef.current.instance.option('state', null)
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) {
instance.option('dataSource', dataSource)
instance.option('state', null)
}
if (
gridDto?.gridOptions.stateStoringDto?.enabled &&
gridDto?.gridOptions.stateStoringDto?.type === 'custom'
) {
stateStoring.customSave = customSaveState
stateStoring.customLoad = customLoadState
}
gridRef.current.instance.option('stateStoring', stateStoring)
//chart Integration
if (gridRef && chartRef) {
gridRef?.current?.instance.bindChart(chartRef?.current?.instance, {
if (gridRef?.current && chartRef?.current) {
const pivotInstance = gridRef?.current?.instance()
const chartInstance = chartRef?.current?.instance()
if (pivotInstance && chartInstance) {
pivotInstance.bindChart(chartInstance, {
dataFieldsDisplayMode: 'splitPanes',
alternateDataFields: false,
})
}
}
}, [columnData])
return (
@ -400,6 +403,24 @@ const Pivot = (props: PivotProps) => {
enabled={gridDto.gridOptions.pivotOptionDto.columnChooserEnabled}
height={500}
/>
<StateStoring
enabled={gridDto?.gridOptions.stateStoringDto?.enabled}
type={gridDto?.gridOptions.stateStoringDto?.type}
savingTimeout={gridDto?.gridOptions.stateStoringDto?.savingTimeout}
storageKey={gridDto?.gridOptions.stateStoringDto?.storageKey}
customSave={
gridDto?.gridOptions.stateStoringDto?.enabled &&
gridDto?.gridOptions.stateStoringDto?.type === 'custom'
? customSaveState
: undefined
}
customLoad={
gridDto?.gridOptions.stateStoringDto?.enabled &&
gridDto?.gridOptions.stateStoringDto?.type === 'custom'
? customLoadState
: undefined
}
/>
<Scrolling mode={gridDto.gridOptions.pagerOptionDto.scrollingMode} />
</PivotGrid>
</div>

View file

@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import Container from '@/components/shared/Container'
import { Dialog, Notification, toast } from '@/components/ui'
import { DX_CLASSNAMES } from '@/constants/app.constant'
@ -34,6 +33,7 @@ import TreeListDx, {
Selection,
Sorting,
Toolbar,
TreeListRef,
TreeListTypes,
} from 'devextreme-react/tree-list'
import { Item } from 'devextreme-react/toolbar'
@ -80,7 +80,7 @@ const Tree = (props: TreeProps) => {
const { translate } = useLocalization()
const { smaller } = useResponsive()
const gridRef = useRef<TreeListDx>()
const gridRef = useRef<TreeListRef>()
const refListFormCode = useRef('')
const widgetGroupRef = useRef<HTMLDivElement>(null)
@ -166,7 +166,7 @@ const Tree = (props: TreeProps) => {
}
async function getSelectedRowKeys() {
const tree = gridRef.current?.instance
const tree = gridRef.current?.instance()
if (!tree) {
return []
}
@ -175,7 +175,7 @@ const Tree = (props: TreeProps) => {
}
function getSelectedRowsData() {
const tree = gridRef.current?.instance
const tree = gridRef.current?.instance()
if (!tree) {
return []
}
@ -184,7 +184,7 @@ const Tree = (props: TreeProps) => {
}
function expandAll() {
const tree = gridRef.current?.instance
const tree = gridRef.current?.instance()
if (!tree) return
tree.forEachNode((node: any) => {
if (node.hasChildren) {
@ -194,7 +194,7 @@ const Tree = (props: TreeProps) => {
}
function collapseAll() {
const tree = gridRef.current?.instance
const tree = gridRef.current?.instance()
if (!tree) return
tree.forEachNode((node: any) => {
if (node.hasChildren) {
@ -204,11 +204,11 @@ const Tree = (props: TreeProps) => {
}
function refreshData() {
gridRef.current?.instance.refresh()
gridRef.current?.instance().refresh()
}
function getFilter() {
const tree = gridRef.current?.instance
const tree = gridRef.current?.instance()
if (!tree) {
return
}
@ -218,7 +218,7 @@ const Tree = (props: TreeProps) => {
function onSelectionChanged(data: any) {
const treeOpt = gridDto?.gridOptions
const tree = gridRef.current?.instance
const tree = gridRef.current?.instance()
if (!treeOpt || !tree) {
return
}
@ -536,7 +536,7 @@ const Tree = (props: TreeProps) => {
postListFormCustomization({
listFormCode: listFormCode,
customizationType: ListFormCustomizationTypeEnum.GridState,
filterName: `tree-${gridRef.current?.instance.option('stateStoring')?.storageKey ?? ''}`,
filterName: `tree-${gridRef.current?.instance().option('stateStoring')?.storageKey ?? ''}`,
customizationData: JSON.stringify(state),
}).then(() => {
setGridPanelColor(statedGridPanelColor)
@ -549,7 +549,7 @@ const Tree = (props: TreeProps) => {
getListFormCustomization(
listFormCode,
ListFormCustomizationTypeEnum.GridState,
`tree-${gridRef.current?.instance.option('stateStoring')?.storageKey ?? ''}`,
`tree-${gridRef.current?.instance().option('stateStoring')?.storageKey ?? ''}`,
).then((response: any) => {
setGridPanelColor(statedGridPanelColor)
if (response.data?.length > 0) {
@ -561,9 +561,9 @@ const Tree = (props: TreeProps) => {
useEffect(() => {
if (gridRef?.current) {
gridRef.current.instance.option('columns', undefined)
gridRef.current.instance.option('dataSource', undefined)
gridRef.current.instance.state(null)
gridRef?.current?.instance().option('columns', undefined)
gridRef?.current?.instance().option('dataSource', undefined)
gridRef?.current?.instance().state(null)
}
if (refListFormCode.current !== listFormCode) {
@ -694,7 +694,7 @@ const Tree = (props: TreeProps) => {
searchParams?.delete('filter')
}
gridRef.current?.instance.refresh()
gridRef.current?.instance().refresh()
}, [extraFilters])
useEffect(() => {
@ -703,8 +703,8 @@ const Tree = (props: TreeProps) => {
return
}
gridRef.current.instance.option('columns', columnData as any)
gridRef.current.instance.option('dataSource', treeListDataSource)
gridRef?.current?.instance().option('columns', columnData as any)
gridRef?.current?.instance().option('dataSource', treeListDataSource)
const stateStoring: IStateStoringProps = {
enabled: gridDto?.gridOptions.stateStoringDto?.enabled,
@ -719,7 +719,7 @@ const Tree = (props: TreeProps) => {
stateStoring.customSave = customSaveState
stateStoring.customLoad = customLoadState
}
gridRef.current.instance.option('stateStoring', stateStoring)
gridRef?.current?.instance().option('stateStoring', stateStoring)
}, [columnData])
return (
@ -857,7 +857,7 @@ const Tree = (props: TreeProps) => {
text: translate('::Save'),
type: 'default',
onClick: () => {
const tree = gridRef.current?.instance
const tree = gridRef.current?.instance()
tree?.saveEditData()
},
},
@ -869,7 +869,7 @@ const Tree = (props: TreeProps) => {
options: {
text: translate('::Cancel'),
onClick: () => {
const tree = gridRef.current?.instance
const tree = gridRef.current?.instance()
tree?.cancelEditData()
},
},

View file

@ -6,9 +6,9 @@ import {
} from '@/proxy/form/models'
import { getListFormCustomization } from '@/services/list-form-customization.service'
import { useLocalization } from '@/utils/hooks/useLocalization'
import DataGrid from 'devextreme-react/data-grid'
import PivotGrid from 'devextreme-react/pivot-grid'
import TreeList from 'devextreme-react/tree-list'
import { DataGridRef } from 'devextreme-react/data-grid'
import { PivotGridRef } from 'devextreme-react/pivot-grid'
import { TreeListRef } from 'devextreme-react/tree-list'
import { ToolbarItem } from 'devextreme/ui/data_grid_types'
import dxDataGrid from 'devextreme/ui/data_grid'
import dxPivotGrid from 'devextreme/ui/pivot_grid'
@ -141,9 +141,9 @@ const useFilters = ({
}: {
gridDto?: GridDto
gridRef:
| MutableRefObject<DataGrid<any, any> | undefined>
| MutableRefObject<PivotGrid | undefined>
| MutableRefObject<TreeList<any, any> | undefined>
| MutableRefObject<DataGridRef<any, any> | undefined>
| MutableRefObject<PivotGridRef | undefined>
| MutableRefObject<TreeListRef<any, any> | undefined>
listFormCode: string
}): {
filterToolbarData: ToolbarItem[]
@ -186,7 +186,7 @@ const useFilters = ({
}) ?? []
setFiltersForSelectBox(mappedFilters)
const grid = gridRef?.current?.instance
const grid = gridRef?.current?.instance()
if (grid) {
setToolbarItemValue(grid, 'selectCustomFilters', '')
setToolbarItemItems(grid, 'selectCustomFilters', mappedFilters)
@ -296,7 +296,7 @@ const useFilters = ({
)
} else if (itemData.id === 'clearFilter') {
// gridin bütün filtrelerini temizle
const grid = gridRef.current?.instance
const grid = gridRef.current?.instance()
if (!grid) {
return
}
@ -308,7 +308,7 @@ const useFilters = ({
setToolbarItemValue(grid, 'selectCustomFilters', '')
} else if (itemData.id === 'resetGridState') {
// state ye kaydedilen grid ayarlarini siler ve gridi resetler
const grid = gridRef.current?.instance
const grid = gridRef.current?.instance()
if (!grid) {
return
}
@ -353,7 +353,7 @@ const useFilters = ({
onValueChanged(e: any) {
// gride seçili filtreyi uygula
let value: string | undefined
const grid = gridRef.current?.instance
const grid = gridRef.current?.instance()
if (!grid) {
return
}

View file

@ -305,18 +305,14 @@ const useListFormColumns = ({
return
}
const column = {
type: 'buttons',
width: 'auto',
buttons: [] as any,
}
const buttons: any[] = []
if (hasUpdate) {
column.buttons.push('edit')
buttons.push('edit')
}
if (hasDelete) {
column.buttons.push('delete')
buttons.push('delete')
}
gridDto.gridOptions.commandColumnDto.forEach((action) => {
@ -365,8 +361,8 @@ const useListFormColumns = ({
props: dynamicMap,
onClose: () => {
// Dialog kapandığında grid'i yenile
if (gridRef?.current?.instance) {
gridRef.current.instance.refresh()
if (gridRef?.current?.instance()) {
gridRef?.current?.instance().refresh()
}
},
})
@ -377,9 +373,22 @@ const useListFormColumns = ({
},
}
column.buttons.push(item)
buttons.push(item)
})
// Buton sayısına göre dinamik genişlik hesapla
// Her buton için ~35-40px + padding
const calculatedWidth = Math.min(buttons.length * 40 + 30, 200)
const column = {
type: 'buttons',
width: calculatedWidth,
minWidth: calculatedWidth,
buttons,
cssClass: '[&_.dx-link]:mx-1',
allowResizing: true,
}
return column as GridColumnData
}

View file

@ -1,14 +1,14 @@
import DataGrid from 'devextreme-react/data-grid'
import PivotGrid from 'devextreme-react/pivot-grid'
import { DataGridRef } from 'devextreme-react/data-grid'
import { PivotGridRef } from 'devextreme-react/pivot-grid'
import CustomStore from 'devextreme/data/custom_store'
import { MutableRefObject, useCallback } from 'react'
import { TreeList } from 'devextreme-react'
import { layoutTypes, ListViewLayoutType } from '@/views/admin/listForm/edit/types'
import { getLoadOptions, getServiceAddress, setGridPanelColor } from './Utils'
import { GridOptionsDto } from '@/proxy/form/models'
import { GridColumnData } from './GridColumnData'
import { dynamicFetch } from '@/services/form.service'
import { MULTIVALUE_DELIMITER } from '@/constants/app.constant'
import { TreeListRef } from 'devextreme-react/cjs/tree-list'
const filteredGridPanelColor = 'rgba(10, 200, 10, 0.5)' // kullanici tanimli filtre ile filtrelenmis gridin paneline ait renk
@ -16,9 +16,9 @@ const useListFormCustomDataSource = ({
gridRef,
}: {
gridRef:
| MutableRefObject<DataGrid<any, any> | undefined>
| MutableRefObject<PivotGrid | undefined>
| MutableRefObject<TreeList<any, any> | undefined>
| MutableRefObject<DataGridRef<any, any> | undefined>
| MutableRefObject<PivotGridRef | undefined>
| MutableRefObject<TreeListRef<any, any> | undefined>
}) => {
const createSelectDataSource = useCallback(
(
@ -66,8 +66,8 @@ const useListFormCustomDataSource = ({
}
// Type guard to handle union type for gridRef
let columns = cols
if (gridRef?.current?.instance) {
const instance = gridRef.current.instance as any
if (gridRef?.current?.instance()) {
const instance = gridRef?.current?.instance() as any
const instanceColumns = instance.option('columns')
if (instanceColumns) {
columns = instanceColumns as GridColumnData[]
@ -157,6 +157,7 @@ const useListFormCustomDataSource = ({
summary: response.data.summary,
groupCount: response.data.groupCount,
}
return retValue
} catch (error: any) {
// toast.push(