Grid üzerinden extra filter özelliği eklendi.

This commit is contained in:
Sedat ÖZTÜRK 2025-09-17 17:13:48 +03:00
parent ca28fe8b5c
commit defbf93165
19 changed files with 564 additions and 272 deletions

View file

@ -0,0 +1,16 @@
namespace Kurs.Platform.ListForms;
public class ExtraFilterDto
{
public string FieldName { get; set; }
public string Caption { get; set; }
public string Operator { get; set; }
public string DefaultValue { get; set; }
public ExtraFilterItemsDto[] Items { get; set; }
}
public class ExtraFilterItemsDto
{
public string Value { get; set; }
public string Text { get; set; }
}

View file

@ -0,0 +1,6 @@
namespace Kurs.Platform.ListForms;
public class ExtraFilterEditDto : ExtraFilterDto
{
public string SqlQuery { get; set; }
}

View file

@ -291,4 +291,18 @@ public class GridOptionsDto : AuditedEntityDto<Guid>
} }
set { SubFormsJson = JsonSerializer.Serialize(value); } set { SubFormsJson = JsonSerializer.Serialize(value); }
} }
[JsonIgnore]
public string ExtraFilterJson { get; set; } // Cagrilacak Extra Filters
public ExtraFilterDto[] ExtraFilterDto
{
get
{
if (!string.IsNullOrEmpty(ExtraFilterJson))
return JsonSerializer.Deserialize<ExtraFilterDto[]>(ExtraFilterJson);
return [];
}
set { ExtraFilterJson = JsonSerializer.Serialize(value); }
}
} }

View file

@ -91,6 +91,7 @@ public class GridOptionsEditDto : GridOptionsDto
set { FormFieldsDefaultValueJson = JsonSerializer.Serialize(value); } set { FormFieldsDefaultValueJson = JsonSerializer.Serialize(value); }
} }
//bu sadece ListFormSelectAppService/GetSelectAsync icerisinde kullanilir
[JsonIgnore] [JsonIgnore]
public string WidgetsJson { get; set; } // Cagrilacak Widgetlar public string WidgetsJson { get; set; } // Cagrilacak Widgetlar
public List<WidgetEditDto> WidgetsDto public List<WidgetEditDto> WidgetsDto
@ -104,4 +105,17 @@ public class GridOptionsEditDto : GridOptionsDto
} }
set { WidgetsJson = JsonSerializer.Serialize(value); } set { WidgetsJson = JsonSerializer.Serialize(value); }
} }
[JsonIgnore]
public List<ExtraFilterEditDto> ExtraFilterEditDto
{
get
{
if (!string.IsNullOrEmpty(ExtraFilterJson))
return JsonSerializer.Deserialize<List<ExtraFilterEditDto>>(ExtraFilterJson);
return [];
}
set { ExtraFilterJson = JsonSerializer.Serialize(value); }
}
} }

View file

@ -25,6 +25,9 @@ public class ListFormAutoMapperProfile : Profile
CreateMap<SubFormDto, SubForm>().ReverseMap(); CreateMap<SubFormDto, SubForm>().ReverseMap();
CreateMap<SubFormRelationDto, SubFormRelation>().ReverseMap(); CreateMap<SubFormRelationDto, SubFormRelation>().ReverseMap();
CreateMap<WidgetEditDto, Widget>().ReverseMap(); CreateMap<WidgetEditDto, Widget>().ReverseMap();
CreateMap<ExtraFilterDto, ExtraFilter>().ReverseMap();
CreateMap<ExtraFilterItemsDto, ExtraFilterItems>().ReverseMap();
CreateMap<ExtraFilterEditDto, ExtraFilterDto>().ReverseMap();
CreateMap<ListFormImport, ListFormsImportDto>(); CreateMap<ListFormImport, ListFormsImportDto>();
CreateMap<ListFormImportExecute, ListFormImportExecuteDto>(); CreateMap<ListFormImportExecute, ListFormImportExecuteDto>();

View file

@ -291,7 +291,6 @@ public class ListFormSelectAppService : PlatformAppService, IListFormSelectAppSe
}; };
var queryParameters = httpContextAccessor.HttpContext.Request.Query.ToDictionary(x => x.Key, x => x.Value); var queryParameters = httpContextAccessor.HttpContext.Request.Query.ToDictionary(x => x.Key, x => x.Value);
var defaultFields = await defaultValueManager.GenerateDefaultValuesAsync(listForm, Enums.OperationEnum.Select, queryParameters: queryParameters); var defaultFields = await defaultValueManager.GenerateDefaultValuesAsync(listForm, Enums.OperationEnum.Select, queryParameters: queryParameters);
foreach (var field in defaultFields) foreach (var field in defaultFields)

View file

@ -118,4 +118,7 @@ public class ListForm : FullAuditedEntity<Guid>
/// <summary>bu listform'un üstünde yer alan widgetların listesidir</summary> /// <summary>bu listform'un üstünde yer alan widgetların listesidir</summary>
public string WidgetsJson { get; set; } public string WidgetsJson { get; set; }
/// <summary>bu listform'un üstünde yer alan widgetların listesidir</summary>
public string ExtraFilterJson { get; set; }
} }

View file

@ -0,0 +1,26 @@
using System.Collections.Generic;
using Volo.Abp.Domain.Values;
namespace Kurs.Platform.Queries;
public class ExtraFilter : ValueObject
{
public string FieldName { get; set; }
public string Caption { get; set; }
public string Operator { get; set; }
public ExtraFilterItems[] Items { get; set; }
protected override IEnumerable<object> GetAtomicValues()
{
yield return FieldName;
yield return Caption;
yield return Operator;
yield return Items;
}
}
public class ExtraFilterItems
{
public string Value { get; set; }
public string Text { get; set; }
}

View file

@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore;
namespace Kurs.Platform.Migrations namespace Kurs.Platform.Migrations
{ {
[DbContext(typeof(PlatformDbContext))] [DbContext(typeof(PlatformDbContext))]
[Migration("20250911192105_Initial")] [Migration("20250917121912_Initial")]
partial class Initial partial class Initial
{ {
/// <inheritdoc /> /// <inheritdoc />
@ -2806,6 +2806,9 @@ namespace Kurs.Platform.Migrations
b.Property<string>("EditingOptionJson") b.Property<string>("EditingOptionJson")
.HasColumnType("nvarchar(max)"); .HasColumnType("nvarchar(max)");
b.Property<string>("ExtraFilterJson")
.HasColumnType("nvarchar(max)");
b.Property<string>("FilterPanelJson") b.Property<string>("FilterPanelJson")
.HasColumnType("nvarchar(max)"); .HasColumnType("nvarchar(max)");

View file

@ -1240,6 +1240,7 @@ namespace Kurs.Platform.Migrations
IsSubForm = table.Column<bool>(type: "bit", nullable: false), IsSubForm = table.Column<bool>(type: "bit", nullable: false),
SubFormsJson = table.Column<string>(type: "nvarchar(max)", nullable: true), SubFormsJson = table.Column<string>(type: "nvarchar(max)", nullable: true),
WidgetsJson = table.Column<string>(type: "nvarchar(max)", nullable: true), WidgetsJson = table.Column<string>(type: "nvarchar(max)", nullable: true),
ExtraFilterJson = table.Column<string>(type: "nvarchar(max)", nullable: true),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false), CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true), LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),

View file

@ -2803,6 +2803,9 @@ namespace Kurs.Platform.Migrations
b.Property<string>("EditingOptionJson") b.Property<string>("EditingOptionJson")
.HasColumnType("nvarchar(max)"); .HasColumnType("nvarchar(max)");
b.Property<string>("ExtraFilterJson")
.HasColumnType("nvarchar(max)");
b.Property<string>("FilterPanelJson") b.Property<string>("FilterPanelJson")
.HasColumnType("nvarchar(max)"); .HasColumnType("nvarchar(max)");

View file

@ -82,7 +82,7 @@ define(['./workbox-a959eb95'], (function (workbox) { 'use strict';
"revision": "3ca0b8505b4bec776b69afdba2768812" "revision": "3ca0b8505b4bec776b69afdba2768812"
}, { }, {
"url": "/index.html", "url": "/index.html",
"revision": "0.h99odp2o5hg" "revision": "0.0c8gpen89r8"
}], {}); }], {});
workbox.cleanupOutdatedCaches(); workbox.cleanupOutdatedCaches();
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("/index.html"), { workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("/index.html"), {

View file

@ -478,6 +478,8 @@ export interface GridOptionsDto extends AuditedEntityDto<string> {
isSubForm: boolean isSubForm: boolean
subFormsJson?: string subFormsJson?: string
subFormsDto: SubFormDto[] subFormsDto: SubFormDto[]
extraFilterJson?: string
extraFilterDto: ExtraFilterDto[]
} }
export interface GridOptionsEditDto extends GridOptionsDto, Record<string, any> { export interface GridOptionsEditDto extends GridOptionsDto, Record<string, any> {
@ -722,3 +724,16 @@ export interface WidgetEditDto {
subTitle: string subTitle: string
onClick: string onClick: string
} }
export interface ExtraFilterDto {
fieldName: string
caption: string
operator: string
defaultValue?: string
items: ExtraFilterItemsDto[]
}
export interface ExtraFilterItemsDto {
value: string
text: string
}

View file

@ -31,11 +31,24 @@ const useListFormCustomDataSource = ({
load: async (loadOptions) => { load: async (loadOptions) => {
const parameters = getLoadOptions(loadOptions, { const parameters = getLoadOptions(loadOptions, {
listFormCode, listFormCode,
filter: searchParams?.get('filter'), filter: '',
createDeleteQuery: searchParams?.get('createDeleteQuery'), createDeleteQuery: searchParams?.get('createDeleteQuery'),
group: '', group: '',
}) })
// 1. Default filter'ı al
const defaultFilter = searchParams?.get('filter')
? JSON.parse(searchParams.get('filter')!)
: null
let combinedFilter: any = parameters.filter
// 2. Eğer hem default hem de grid filter varsa merge et
if (defaultFilter && combinedFilter) {
combinedFilter = [defaultFilter, 'and', combinedFilter]
} else if (defaultFilter) {
combinedFilter = defaultFilter
}
//editing asamasinda her bir field de yapilan degisiklik load istegi olarak buraya dusuyor. //editing asamasinda her bir field de yapilan degisiklik load istegi olarak buraya dusuyor.
//TODO: bu bug halen devam ediyor!! //TODO: bu bug halen devam ediyor!!
//Bunu engellemek icin eklendi. //Bunu engellemek icin eklendi.
@ -69,7 +82,8 @@ const useListFormCustomDataSource = ({
} }
} }
} }
parameters.filter = JSON.stringify(parameters.filter) parameters.filter = JSON.stringify(combinedFilter)
//parameters.filter = JSON.stringify(parameters.filter)
const response = await dynamicFetch('list-form-select/select', 'GET', parameters) const response = await dynamicFetch('list-form-select/select', 'GET', parameters)
if (setWidgetGroups) setWidgetGroups(response.data.widgets ?? []) if (setWidgetGroups) setWidgetGroups(response.data.widgets ?? [])
@ -145,11 +159,24 @@ const useListFormCustomDataSource = ({
totalCount: async (loadOptions) => { totalCount: async (loadOptions) => {
const parameters = getLoadOptions(loadOptions, { const parameters = getLoadOptions(loadOptions, {
listFormCode, listFormCode,
filter: searchParams?.get('filter'), filter: '',
createDeleteQuery: searchParams?.get('createDeleteQuery'), createDeleteQuery: searchParams?.get('createDeleteQuery'),
group: '', group: '',
}) })
parameters.filter = JSON.stringify(parameters.filter)
const defaultFilter = searchParams?.get('filter')
? JSON.parse(searchParams.get('filter')!)
: null
let combinedFilter: any = parameters.filter
if (defaultFilter && combinedFilter) {
combinedFilter = [defaultFilter, 'and', combinedFilter]
} else if (defaultFilter) {
combinedFilter = defaultFilter
}
parameters.filter = JSON.stringify(combinedFilter)
try { try {
const response = await dynamicFetch('list-form-select/select', 'GET', parameters) const response = await dynamicFetch('list-form-select/select', 'GET', parameters)
return response.data.totalCount return response.data.totalCount

View file

@ -10,7 +10,7 @@ import { useLocalization } from '@/utils/hooks/useLocalization'
export function Forum() { export function Forum() {
const { translate } = useLocalization() const { translate } = useLocalization()
const { user, tenant } = useStoreState((state) => state.auth) const { user } = useStoreState((state) => state.auth)
const { const {
categories, categories,
topics, topics,

View file

@ -51,7 +51,7 @@ import { useCallback, useEffect, useRef, useState } from 'react'
import { Helmet } from 'react-helmet' import { Helmet } from 'react-helmet'
import SubForms from '../form/SubForms' import SubForms from '../form/SubForms'
import { RowMode, SimpleItemWithColData } from '../form/types' import { RowMode, SimpleItemWithColData } from '../form/types'
import { GridColumnData } from './GridColumnData' import { GridColumnData, GridExtraFilterState } from './GridColumnData'
import GridFilterDialogs from './GridFilterDialogs' import GridFilterDialogs from './GridFilterDialogs'
import { import {
addCss, addCss,
@ -66,6 +66,7 @@ import { useFilters } from './useFilters'
import { useToolbar } from './useToolbar' import { useToolbar } from './useToolbar'
import { ImportDashboard } from '@/components/importManager/ImportDashboard' import { ImportDashboard } from '@/components/importManager/ImportDashboard'
import WidgetGroup from '@/components/ui/Widget/WidgetGroup' import WidgetGroup from '@/components/ui/Widget/WidgetGroup'
import { GridExtraFilterToolbar } from './GridExtraFilterToolbar'
interface GridProps { interface GridProps {
listFormCode: string listFormCode: string
@ -91,6 +92,7 @@ const Grid = (props: GridProps) => {
const [formData, setFormData] = useState<any>() const [formData, setFormData] = useState<any>()
const [mode, setMode] = useState<RowMode>('view') const [mode, setMode] = useState<RowMode>('view')
const [widgetGroups, setWidgetGroups] = useState<WidgetGroupDto[]>([]) const [widgetGroups, setWidgetGroups] = useState<WidgetGroupDto[]>([])
const [extraFilters, setExtraFilters] = useState<GridExtraFilterState[]>([])
const preloadExportLibs = () => { const preloadExportLibs = () => {
import('exceljs') import('exceljs')
@ -107,6 +109,8 @@ const Grid = (props: GridProps) => {
getSelectedRowsData, getSelectedRowsData,
refreshData, refreshData,
getFilter, getFilter,
extraFilters,
setExtraFilters,
}) })
const { filterToolbarData, ...filterData } = useFilters({ const { filterToolbarData, ...filterData } = useFilters({
@ -401,6 +405,22 @@ const Grid = (props: GridProps) => {
const cols = getBandedColumns() const cols = getBandedColumns()
setColumnData(cols) setColumnData(cols)
// Filters'i AND ile birleştir
let filterArray: any[] = []
extraFilters.forEach((f) => {
if (f.value) {
if (filterArray.length > 0) {
filterArray.push('and')
}
filterArray.push([f.fieldName, f.operator, f.value])
}
})
const params = new URLSearchParams()
if (filterArray.length > 0) {
params.set('filter', JSON.stringify(filterArray))
}
// Set data source // Set data source
const dataSource: CustomStore<any, any> = createSelectDataSource( const dataSource: CustomStore<any, any> = createSelectDataSource(
gridDto.gridOptions, gridDto.gridOptions,
@ -507,10 +527,81 @@ const Grid = (props: GridProps) => {
} }
} }
useEffect(() => {
if (gridDto?.gridOptions.extraFilterDto) {
setExtraFilters(
gridDto.gridOptions.extraFilterDto.map((f) => ({
fieldName: f.fieldName,
operator: f.operator,
value: f.defaultValue ?? '',
})),
)
}
}, [gridDto])
useEffect(() => {
if (!searchParams) return
// aktif filtreleri al
const activeFilters = extraFilters.filter((f) => f.value)
let filter: any = null
if (activeFilters.length === 1) {
// tek filtre -> düz array
const f = activeFilters[0]
filter = [f.fieldName, f.operator, f.value]
} else if (activeFilters.length > 1) {
// birden fazla filtre -> and ile bağla
filter = activeFilters.reduce((acc, f, idx) => {
if (idx === 0) return [f.fieldName, f.operator, f.value]
return [acc, 'and', [f.fieldName, f.operator, f.value]]
}, null as any)
}
if (filter) {
searchParams.set('filter', JSON.stringify(filter))
} else {
searchParams.delete('filter')
}
gridRef.current?.instance.refresh()
}, [extraFilters, searchParams])
return ( return (
<> <>
<WidgetGroup widgetGroups={widgetGroups} /> <WidgetGroup widgetGroups={widgetGroups} />
{/* {gridDto?.gridOptions.extraFilterDto && (
<div className="flex gap-4 pl-2 pb-1">
{gridDto?.gridOptions.extraFilterDto?.map((fs) => {
const current = extraFilters.find((f) => f.fieldName === fs.fieldName)
return (
<div key={fs.fieldName}>
<label className="mr-2">{fs.caption}</label>
<select
value={current?.value ?? ''}
onChange={(e) =>
setExtraFilters((prev) =>
prev.map((f) =>
f.fieldName === fs.fieldName ? { ...f, value: e.target.value } : f,
),
)
}
>
<option value="">Seçiniz</option>
{fs.items.map((item) => (
<option key={item.value} value={item.value}>
{item.text}
</option>
))}
</select>
</div>
)
})}
</div>
)} */}
<Container className={DX_CLASSNAMES}> <Container className={DX_CLASSNAMES}>
{!isSubForm && ( {!isSubForm && (
<Helmet <Helmet
@ -520,263 +611,279 @@ const Grid = (props: GridProps) => {
></Helmet> ></Helmet>
)} )}
{gridDto && columnData && ( {gridDto && columnData && (
<div className="p-1"> <>
<DataGrid <div className="p-1">
ref={gridRef as any} <DataGrid
id={'Grid-' + listFormCode} ref={gridRef as any}
//dataSource={gridDataSource} id={'Grid-' + listFormCode}
//remoteOperations={{ groupPaging: true }} //dataSource={gridDataSource}
//remoteOperations={false} //remoteOperations={{ groupPaging: true }}
height={gridDto.gridOptions.height || '100%'} //remoteOperations={false}
width={gridDto.gridOptions.width || '100%'} height={gridDto.gridOptions.height || '100%'}
allowColumnResizing={gridDto.gridOptions.columnOptionDto?.allowColumnResizing} width={gridDto.gridOptions.width || '100%'}
allowColumnReordering={gridDto.gridOptions.columnOptionDto?.allowColumnReordering} allowColumnResizing={gridDto.gridOptions.columnOptionDto?.allowColumnResizing}
showBorders={gridDto.gridOptions.columnOptionDto?.showBorders} allowColumnReordering={gridDto.gridOptions.columnOptionDto?.allowColumnReordering}
showRowLines={gridDto.gridOptions.columnOptionDto?.showRowLines} showBorders={gridDto.gridOptions.columnOptionDto?.showBorders}
showColumnLines={gridDto.gridOptions.columnOptionDto?.showColumnLines} showRowLines={gridDto.gridOptions.columnOptionDto?.showRowLines}
columnResizingMode={gridDto.gridOptions.columnOptionDto?.columnResizingMode} showColumnLines={gridDto.gridOptions.columnOptionDto?.showColumnLines}
columnAutoWidth={gridDto.gridOptions.columnOptionDto?.columnAutoWidth} columnResizingMode={gridDto.gridOptions.columnOptionDto?.columnResizingMode}
rtlEnabled={gridDto.gridOptions.columnOptionDto?.rtlEnabled} columnAutoWidth={gridDto.gridOptions.columnOptionDto?.columnAutoWidth}
rowAlternationEnabled={gridDto.gridOptions.columnOptionDto?.rowAlternationEnabled} rtlEnabled={gridDto.gridOptions.columnOptionDto?.rtlEnabled}
hoverStateEnabled={gridDto.gridOptions.columnOptionDto?.hoverStateEnabled} rowAlternationEnabled={gridDto.gridOptions.columnOptionDto?.rowAlternationEnabled}
columnHidingEnabled={gridDto.gridOptions.columnOptionDto?.columnHidingEnabled} hoverStateEnabled={gridDto.gridOptions.columnOptionDto?.hoverStateEnabled}
focusedRowEnabled={gridDto.gridOptions.columnOptionDto?.focusedRowEnabled} columnHidingEnabled={gridDto.gridOptions.columnOptionDto?.columnHidingEnabled}
showColumnHeaders={gridDto.gridOptions.columnOptionDto?.showColumnHeaders} focusedRowEnabled={gridDto.gridOptions.columnOptionDto?.focusedRowEnabled}
filterSyncEnabled={true} showColumnHeaders={gridDto.gridOptions.columnOptionDto?.showColumnHeaders}
onSelectionChanged={onSelectionChanged} filterSyncEnabled={true}
onInitNewRow={onInitNewRow} onSelectionChanged={onSelectionChanged}
onCellPrepared={onCellPrepared} onInitNewRow={onInitNewRow}
onRowInserting={onRowInserting} onCellPrepared={onCellPrepared}
onRowUpdating={onRowUpdating} onRowInserting={onRowInserting}
onEditingStart={onEditingStart} onRowUpdating={onRowUpdating}
onDataErrorOccurred={onDataErrorOccurred} onEditingStart={onEditingStart}
onExporting={onExporting} onDataErrorOccurred={onDataErrorOccurred}
onEditCanceled={() => { onExporting={onExporting}
setMode('view') onEditCanceled={() => {
}} setMode('view')
onSaved={() => {
setMode('view')
}}
onRowInserted={() => {
props.refreshData?.()
}}
onRowUpdated={() => {
props.refreshData?.()
}}
onRowRemoved={() => {
props.refreshData?.()
}}
>
<Export
enabled={true}
allowExportSelectedData={false}
formats={['pdf', 'xlsx', 'csv']}
/>
<Editing
refreshMode={gridDto.gridOptions.editingOptionDto?.refreshMode}
mode={smaller.md ? 'form' : gridDto.gridOptions.editingOptionDto?.mode}
allowDeleting={gridDto.gridOptions.editingOptionDto?.allowDeleting}
allowUpdating={gridDto.gridOptions.editingOptionDto?.allowUpdating}
allowAdding={gridDto.gridOptions.editingOptionDto?.allowAdding}
useIcons={gridDto.gridOptions.editingOptionDto?.useIcons}
confirmDelete={gridDto.gridOptions.editingOptionDto?.confirmDelete}
newRowPosition={gridDto.gridOptions.editingOptionDto?.newRowPosition}
selectTextOnEditStart={gridDto.gridOptions.editingOptionDto?.selectTextOnEditStart}
startEditAction={gridDto.gridOptions.editingOptionDto?.startEditAction}
popup={{
title: gridDto.gridOptions.editingOptionDto?.popup?.title,
showTitle: gridDto.gridOptions.editingOptionDto?.popup?.showTitle,
hideOnOutsideClick:
gridDto.gridOptions.editingOptionDto?.popup?.hideOnOutsideClick,
width: gridDto.gridOptions.editingOptionDto?.popup?.width,
height: gridDto.gridOptions.editingOptionDto?.popup?.height,
fullScreen: gridDto.gridOptions.editingOptionDto?.popup?.fullScreen,
}} }}
form={{ onSaved={() => {
items: setMode('view')
gridDto.gridOptions.editingFormDto?.length > 0 }}
? gridDto.gridOptions.editingFormDto onRowInserted={() => {
?.sort((a: any, b: any) => { props.refreshData?.()
return a.order >= b.order ? 1 : -1 }}
}) onRowUpdated={() => {
.map((e: any) => { props.refreshData?.()
return { }}
itemType: e.itemType, onRowRemoved={() => {
colCount: e.colCount, props.refreshData?.()
colSpan: e.colSpan, }}
caption: e.caption, >
items: e.items <Export
?.sort((a: any, b: any) => { enabled={true}
return a.order >= b.order ? 1 : -1 allowExportSelectedData={false}
}) formats={['pdf', 'xlsx', 'csv']}
.map((i: EditingFormItemDto) => { />
let editorOptions = {} <Editing
try { refreshMode={gridDto.gridOptions.editingOptionDto?.refreshMode}
editorOptions = i.editorOptions && JSON.parse(i.editorOptions) mode={smaller.md ? 'form' : gridDto.gridOptions.editingOptionDto?.mode}
allowDeleting={gridDto.gridOptions.editingOptionDto?.allowDeleting}
allowUpdating={gridDto.gridOptions.editingOptionDto?.allowUpdating}
allowAdding={gridDto.gridOptions.editingOptionDto?.allowAdding}
useIcons={gridDto.gridOptions.editingOptionDto?.useIcons}
confirmDelete={gridDto.gridOptions.editingOptionDto?.confirmDelete}
newRowPosition={gridDto.gridOptions.editingOptionDto?.newRowPosition}
selectTextOnEditStart={
gridDto.gridOptions.editingOptionDto?.selectTextOnEditStart
}
startEditAction={gridDto.gridOptions.editingOptionDto?.startEditAction}
popup={{
title: gridDto.gridOptions.editingOptionDto?.popup?.title,
showTitle: gridDto.gridOptions.editingOptionDto?.popup?.showTitle,
hideOnOutsideClick:
gridDto.gridOptions.editingOptionDto?.popup?.hideOnOutsideClick,
width: gridDto.gridOptions.editingOptionDto?.popup?.width,
height: gridDto.gridOptions.editingOptionDto?.popup?.height,
fullScreen: gridDto.gridOptions.editingOptionDto?.popup?.fullScreen,
}}
form={{
items:
gridDto.gridOptions.editingFormDto?.length > 0
? gridDto.gridOptions.editingFormDto
?.sort((a: any, b: any) => {
return a.order >= b.order ? 1 : -1
})
.map((e: any) => {
return {
itemType: e.itemType,
colCount: e.colCount,
colSpan: e.colSpan,
caption: e.caption,
items: e.items
?.sort((a: any, b: any) => {
return a.order >= b.order ? 1 : -1
})
.map((i: EditingFormItemDto) => {
let editorOptions = {}
try {
editorOptions = i.editorOptions && JSON.parse(i.editorOptions)
// Eğer default value varsa, bu editörü readonly yapıyoruz // Eğer default value varsa, bu editörü readonly yapıyoruz
if (searchParams?.has(i.dataField)) { if (searchParams?.has(i.dataField)) {
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 = { editorOptions = {
...{
type: 'date',
dateSerializationFormat: 'yyyy-MM-dd',
displayFormat: 'shortDate',
},
...editorOptions, ...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,
}
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, 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,
}
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 return item
}) })
.filter((a: any) => { .filter((a: any) => {
// return a.canRead // return a.canRead
if (mode === 'view') { if (mode === 'view') {
return a.canRead return a.canRead
} else if (mode === 'new') { } else if (mode === 'new') {
return a.canCreate || a.canRead return a.canCreate || a.canRead
} else if (mode === 'edit') { } else if (mode === 'edit') {
return a.canUpdate || a.canRead return a.canUpdate || a.canRead
} else { } else {
return false return false
} }
}), }),
} as GroupItem } as GroupItem
}) })
: undefined, : undefined,
}} }}
></Editing> ></Editing>
<Template name={'cellEditTagBox'} render={TagBoxEditorComponent} /> <Template name={'cellEditTagBox'} render={TagBoxEditorComponent} />
<Template name={'cellEditGridBox'} render={GridBoxEditorComponent} /> <Template name={'cellEditGridBox'} render={GridBoxEditorComponent} />
<Toolbar visible={toolbarData.length > 0 || filterToolbarData.length > 0}> <Template name="extraFilters">
{toolbarData.map((item) => ( <GridExtraFilterToolbar
<Item key={item.name} {...item}></Item> filters={gridDto?.gridOptions.extraFilterDto ?? []}
))} extraFilters={extraFilters}
{filterToolbarData.map((item) => ( setExtraFilters={setExtraFilters}
<Item key={item.name} {...item}></Item> />
))} </Template>
</Toolbar> <Toolbar visible={toolbarData.length > 0 || filterToolbarData.length > 0}>
<Sorting mode={gridDto.gridOptions?.sortMode}></Sorting> {toolbarData.map((item) => (
<FilterRow <Item key={item.name} {...item}></Item>
visible={gridDto.gridOptions.filterRowDto?.visible}
applyFilter={gridDto.gridOptions.filterRowDto?.applyFilter}
></FilterRow>
<FilterPanel visible={gridDto.gridOptions.filterPanelDto.visible}></FilterPanel>
<HeaderFilter visible={gridDto.gridOptions.headerFilterDto.visible}></HeaderFilter>
<SearchPanel
visible={gridDto.gridOptions.searchPanelDto.visible}
width={gridDto.gridOptions.searchPanelDto.width}
></SearchPanel>
<GroupPanel visible={gridDto.gridOptions.groupPanelDto?.visible}></GroupPanel>
<Grouping autoExpandAll={gridDto.gridOptions.groupPanelDto?.autoExpandAll}></Grouping>
<Selection
mode={gridDto.gridOptions.selectionDto?.mode}
allowSelectAll={gridDto.gridOptions.selectionDto?.allowSelectAll}
selectAllMode={gridDto.gridOptions.selectionDto?.selectAllMode}
showCheckBoxesMode={gridDto.gridOptions.selectionDto?.showCheckBoxesMode}
></Selection>
{/* <Paging pageSize={gridDto.gridOptions.pageSize ?? 0}></Paging> */}
<Pager
visible={gridDto.gridOptions.pagerOptionDto?.visible}
allowedPageSizes={gridDto.gridOptions.pagerOptionDto?.allowedPageSizes
?.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}
displayMode={gridDto.gridOptions.pagerOptionDto?.displayMode}
></Pager>
<ColumnChooser
enabled={gridDto.gridOptions.columnOptionDto?.columnChooserEnabled}
mode={gridDto.gridOptions.columnOptionDto?.columnChooserMode}
></ColumnChooser>
<ColumnFixing
enabled={gridDto.gridOptions.columnOptionDto?.columnFixingEnabled}
></ColumnFixing>
<Scrolling mode={gridDto.gridOptions.pagerOptionDto?.scrollingMode}></Scrolling>
<LoadPanel
enabled={gridDto.gridOptions.pagerOptionDto?.loadPanelEnabled}
text={gridDto.gridOptions.pagerOptionDto?.loadPanelText}
></LoadPanel>
<Summary>
{gridDto.columnFormats
.filter((x: any) => !!x.columnTotalSummaryDto?.summaryType)
.map((x: any) => (
<TotalItem
key={`Total_${x.fieldName}`}
column={x.fieldName}
summaryType={x.columnTotalSummaryDto.summaryType as any}
showInColumn={x.columnTotalSummaryDto.showInColumn}
valueFormat={x.columnTotalSummaryDto.valueFormat}
displayFormat={x.columnTotalSummaryDto.displayFormat}
/>
))} ))}
{gridDto.columnFormats {filterToolbarData.map((item) => (
.filter((x: any) => !!x.columnGroupSummaryDto?.summaryType) <Item key={item.name} {...item}></Item>
.map((x: any) => (
<GroupItemDx
key={`Group_${x.fieldName}`}
column={x.fieldName}
summaryType={x.columnGroupSummaryDto.summaryType as any}
showInColumn={x.columnGroupSummaryDto.showInColumn}
valueFormat={x.columnGroupSummaryDto.valueFormat}
displayFormat={x.columnGroupSummaryDto.displayFormat}
/>
))} ))}
</Summary> {/* burada özel filtre alanını Template ile bağla */}
{/* <Column {gridDto?.gridOptions.extraFilterDto?.length ? (
<Item location="before" template="extraFilters" />
) : null}
</Toolbar>
<Sorting mode={gridDto.gridOptions?.sortMode}></Sorting>
<FilterRow
visible={gridDto.gridOptions.filterRowDto?.visible}
applyFilter={gridDto.gridOptions.filterRowDto?.applyFilter}
></FilterRow>
<FilterPanel visible={gridDto.gridOptions.filterPanelDto.visible}></FilterPanel>
<HeaderFilter visible={gridDto.gridOptions.headerFilterDto.visible}></HeaderFilter>
<SearchPanel
visible={gridDto.gridOptions.searchPanelDto.visible}
width={gridDto.gridOptions.searchPanelDto.width}
></SearchPanel>
<GroupPanel visible={gridDto.gridOptions.groupPanelDto?.visible}></GroupPanel>
<Grouping
autoExpandAll={gridDto.gridOptions.groupPanelDto?.autoExpandAll}
></Grouping>
<Selection
mode={gridDto.gridOptions.selectionDto?.mode}
allowSelectAll={gridDto.gridOptions.selectionDto?.allowSelectAll}
selectAllMode={gridDto.gridOptions.selectionDto?.selectAllMode}
showCheckBoxesMode={gridDto.gridOptions.selectionDto?.showCheckBoxesMode}
></Selection>
{/* <Paging pageSize={gridDto.gridOptions.pageSize ?? 0}></Paging> */}
<Pager
visible={gridDto.gridOptions.pagerOptionDto?.visible}
allowedPageSizes={gridDto.gridOptions.pagerOptionDto?.allowedPageSizes
?.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}
displayMode={gridDto.gridOptions.pagerOptionDto?.displayMode}
></Pager>
<ColumnChooser
enabled={gridDto.gridOptions.columnOptionDto?.columnChooserEnabled}
mode={gridDto.gridOptions.columnOptionDto?.columnChooserMode}
></ColumnChooser>
<ColumnFixing
enabled={gridDto.gridOptions.columnOptionDto?.columnFixingEnabled}
></ColumnFixing>
<Scrolling mode={gridDto.gridOptions.pagerOptionDto?.scrollingMode}></Scrolling>
<LoadPanel
enabled={gridDto.gridOptions.pagerOptionDto?.loadPanelEnabled}
text={gridDto.gridOptions.pagerOptionDto?.loadPanelText}
></LoadPanel>
<Summary>
{gridDto.columnFormats
.filter((x: any) => !!x.columnTotalSummaryDto?.summaryType)
.map((x: any) => (
<TotalItem
key={`Total_${x.fieldName}`}
column={x.fieldName}
summaryType={x.columnTotalSummaryDto.summaryType as any}
showInColumn={x.columnTotalSummaryDto.showInColumn}
valueFormat={x.columnTotalSummaryDto.valueFormat}
displayFormat={x.columnTotalSummaryDto.displayFormat}
/>
))}
{gridDto.columnFormats
.filter((x: any) => !!x.columnGroupSummaryDto?.summaryType)
.map((x: any) => (
<GroupItemDx
key={`Group_${x.fieldName}`}
column={x.fieldName}
summaryType={x.columnGroupSummaryDto.summaryType as any}
showInColumn={x.columnGroupSummaryDto.showInColumn}
valueFormat={x.columnGroupSummaryDto.valueFormat}
displayFormat={x.columnGroupSummaryDto.displayFormat}
/>
))}
</Summary>
{/* <Column
dataField="Quantity" dataField="Quantity"
width={160} width={160}
alignment="right" alignment="right"
@ -786,23 +893,25 @@ const Grid = (props: GridProps) => {
> >
<Format type="fixedPoint" precision={2} /> <Format type="fixedPoint" precision={2} />
</Column> */} </Column> */}
</DataGrid> </DataGrid>
{gridDto?.gridOptions?.subFormsDto?.length > 0 && (
<>
<hr className="my-4" />
<SubForms gridDto={gridDto!} formData={formData} level={level ?? 0} />
</>
)}
<Dialog {gridDto?.gridOptions?.subFormsDto?.length > 0 && (
width={smaller.md ? '100%' : 1000} <>
isOpen={filterData.isImportModalOpen || false} <hr className="my-4" />
onClose={() => filterData.setIsImportModalOpen(false)} <SubForms gridDto={gridDto!} formData={formData} level={level ?? 0} />
onRequestClose={() => filterData.setIsImportModalOpen(false)} </>
> )}
<ImportDashboard gridDto={gridDto} />
</Dialog> <Dialog
</div> width={smaller.md ? '100%' : 1000}
isOpen={filterData.isImportModalOpen || false}
onClose={() => filterData.setIsImportModalOpen(false)}
onRequestClose={() => filterData.setIsImportModalOpen(false)}
>
<ImportDashboard gridDto={gridDto} />
</Dialog>
</div>
</>
)} )}
<Dialog <Dialog

View file

@ -1,6 +1,12 @@
import { DataGridTypes } from 'devextreme-react/data-grid' import { DataGridTypes } from 'devextreme-react/data-grid'
import { ColumnFormatDto, GridBoxOptionsDto, TagBoxOptionsDto } from '../../proxy/form/models' import { ColumnFormatDto, GridBoxOptionsDto, TagBoxOptionsDto } from '../../proxy/form/models'
export interface GridExtraFilterState {
fieldName: string
operator: string
value: string
}
interface IGridColumnData extends DataGridTypes.Column { interface IGridColumnData extends DataGridTypes.Column {
colData?: ColumnFormatDto colData?: ColumnFormatDto
extras?: { extras?: {

View file

@ -0,0 +1,42 @@
import { GridExtraFilterState } from './GridColumnData'
export function GridExtraFilterToolbar({
filters,
extraFilters,
setExtraFilters,
}: {
filters: any[]
extraFilters: GridExtraFilterState[]
setExtraFilters: React.Dispatch<React.SetStateAction<GridExtraFilterState[]>>
}) {
return (
<div className="flex gap-4">
{filters.map((fs) => {
const current = extraFilters.find((f) => f.fieldName === fs.fieldName)
return (
<div key={fs.fieldName} className="flex items-center gap-2">
<label>{fs.caption}</label>
<select
className="border rounded px-0.5 py-0.5"
value={current?.value ?? ''}
onChange={(e) =>
setExtraFilters((prev) =>
prev.map((f) =>
f.fieldName === fs.fieldName ? { ...f, value: e.target.value } : f,
),
)
}
>
<option value="">Seçiniz</option>
{fs.items.map((item: any) => (
<option key={item.value} value={item.value}>
{item.text}
</option>
))}
</select>
</div>
)
})}
</div>
)
}

View file

@ -8,6 +8,7 @@ import { ToolbarItem } from 'devextreme/ui/data_grid_types'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { useDialogContext } from '../shared/DialogContext' import { useDialogContext } from '../shared/DialogContext'
import { usePWA } from '@/utils/hooks/usePWA' import { usePWA } from '@/utils/hooks/usePWA'
import { GridExtraFilterState } from './GridColumnData'
type ToolbarModalData = { type ToolbarModalData = {
open: boolean open: boolean
@ -23,6 +24,8 @@ const useToolbar = ({
getSelectedRowsData, getSelectedRowsData,
refreshData, refreshData,
getFilter, getFilter,
extraFilters,
setExtraFilters,
}: { }: {
gridDto?: GridDto gridDto?: GridDto
listFormCode: string listFormCode: string
@ -30,6 +33,8 @@ const useToolbar = ({
getSelectedRowsData: () => any getSelectedRowsData: () => any
refreshData: () => void refreshData: () => void
getFilter: () => void getFilter: () => void
extraFilters: GridExtraFilterState[]
setExtraFilters: React.Dispatch<React.SetStateAction<GridExtraFilterState[]>>
}): { }): {
toolbarData: ToolbarItem[] toolbarData: ToolbarItem[]
toolbarModalData: ToolbarModalData | undefined toolbarModalData: ToolbarModalData | undefined