Grid, Card, Pivot Layout

This commit is contained in:
Sedat ÖZTÜRK 2025-09-22 17:08:42 +03:00
parent 5dd6e0bcd4
commit b2e489d705
19 changed files with 522 additions and 228 deletions

View file

@ -305,4 +305,18 @@ public class GridOptionsDto : AuditedEntityDto<Guid>
} }
set { ExtraFilterJson = JsonSerializer.Serialize(value); } set { ExtraFilterJson = JsonSerializer.Serialize(value); }
} }
[JsonIgnore]
public string LayoutJson { get; set; }
public LayoutDto LayoutDto
{
get
{
if (!string.IsNullOrEmpty(LayoutJson))
return JsonSerializer.Deserialize<LayoutDto>(LayoutJson);
return new LayoutDto();
}
set { LayoutJson = JsonSerializer.Serialize(value); }
}
} }

View file

@ -0,0 +1,10 @@
namespace Kurs.Platform.ListForms;
public class LayoutDto
{
public bool Grid { get; set; } = true;
public bool Card { get; set; } = true;
public bool Pivot { get; set; } = true;
public string DefaultLayout { get; set; } = "grid";
public int CardLayoutColumn { get; set; } = 4;
}

View file

@ -65,6 +65,7 @@ public class ListFormsAppService : CrudAppService<
item.Description = input.Description; item.Description = input.Description;
item.IsSubForm = input.IsSubForm; item.IsSubForm = input.IsSubForm;
item.ListFormType = input.ListFormType; item.ListFormType = input.ListFormType;
item.LayoutJson = JsonSerializer.Serialize(input.LayoutDto);
} }
else if (input.EditType == ListFormEditTabs.Database.DataSourceForm) else if (input.EditType == ListFormEditTabs.Database.DataSourceForm)
{ {

View file

@ -2581,7 +2581,7 @@ public class ListFormsSeeder : IDataSeedContributor, ITransientDependency
Visible = true, Visible = true,
IsActive = true, IsActive = true,
IsDeleted = false, IsDeleted = false,
AllowSearch = true, AllowSearch = false,
LookupJson = JsonSerializer.Serialize(new LookupDto { LookupJson = JsonSerializer.Serialize(new LookupDto {
DataSourceType = UiLookupDataSourceTypeEnum.Query, DataSourceType = UiLookupDataSourceTypeEnum.Query,
@ -3821,7 +3821,7 @@ public class ListFormsSeeder : IDataSeedContributor, ITransientDependency
Visible = true, Visible = true,
IsActive = true, IsActive = true,
IsDeleted = false, IsDeleted = false,
AllowSearch = true, AllowSearch = false,
ValidationRuleJson = JsonSerializer.Serialize(new ValidationRuleDto[] { ValidationRuleJson = JsonSerializer.Serialize(new ValidationRuleDto[] {
new ValidationRuleDto() { Type = Enum.GetName(UiColumnValidationRuleTypeEnum.required)} new ValidationRuleDto() { Type = Enum.GetName(UiColumnValidationRuleTypeEnum.required)}
}), }),
@ -4097,7 +4097,7 @@ public class ListFormsSeeder : IDataSeedContributor, ITransientDependency
Visible = true, Visible = true,
IsActive = true, IsActive = true,
IsDeleted = false, IsDeleted = false,
AllowSearch = true, AllowSearch = false,
LookupJson = JsonSerializer.Serialize(new LookupDto { LookupJson = JsonSerializer.Serialize(new LookupDto {
DataSourceType = UiLookupDataSourceTypeEnum.Query, DataSourceType = UiLookupDataSourceTypeEnum.Query,
@ -5505,7 +5505,7 @@ public class ListFormsSeeder : IDataSeedContributor, ITransientDependency
Visible = true, Visible = true,
IsActive = true, IsActive = true,
IsDeleted = false, IsDeleted = false,
AllowSearch = true, AllowSearch = false,
LookupJson = JsonSerializer.Serialize(new LookupDto { LookupJson = JsonSerializer.Serialize(new LookupDto {
DataSourceType = UiLookupDataSourceTypeEnum.Query, DataSourceType = UiLookupDataSourceTypeEnum.Query,
@ -5543,7 +5543,7 @@ public class ListFormsSeeder : IDataSeedContributor, ITransientDependency
Visible = true, Visible = true,
IsActive = true, IsActive = true,
IsDeleted = false, IsDeleted = false,
AllowSearch = true, AllowSearch = false,
LookupJson = JsonSerializer.Serialize(new LookupDto { LookupJson = JsonSerializer.Serialize(new LookupDto {
DataSourceType = UiLookupDataSourceTypeEnum.Query, DataSourceType = UiLookupDataSourceTypeEnum.Query,
@ -5611,7 +5611,7 @@ public class ListFormsSeeder : IDataSeedContributor, ITransientDependency
Visible = true, Visible = true,
IsActive = true, IsActive = true,
IsDeleted = false, IsDeleted = false,
AllowSearch = true, AllowSearch = false,
LookupJson = JsonSerializer.Serialize(new LookupDto { LookupJson = JsonSerializer.Serialize(new LookupDto {
DataSourceType = UiLookupDataSourceTypeEnum.Query, DataSourceType = UiLookupDataSourceTypeEnum.Query,
@ -5649,7 +5649,7 @@ public class ListFormsSeeder : IDataSeedContributor, ITransientDependency
Visible = true, Visible = true,
IsActive = true, IsActive = true,
IsDeleted = false, IsDeleted = false,
AllowSearch = true, AllowSearch = false,
LookupJson = JsonSerializer.Serialize(new LookupDto { LookupJson = JsonSerializer.Serialize(new LookupDto {
DataSourceType = UiLookupDataSourceTypeEnum.Query, DataSourceType = UiLookupDataSourceTypeEnum.Query,
@ -12790,7 +12790,7 @@ public class ListFormsSeeder : IDataSeedContributor, ITransientDependency
Visible = true, Visible = true,
IsActive = true, IsActive = true,
IsDeleted = false, IsDeleted = false,
AllowSearch = true, AllowSearch = false,
ValidationRuleJson = JsonSerializer.Serialize(new[] ValidationRuleJson = JsonSerializer.Serialize(new[]
{ {
new ValidationRuleDto { Type = "required" } new ValidationRuleDto { Type = "required" }
@ -12849,7 +12849,7 @@ public class ListFormsSeeder : IDataSeedContributor, ITransientDependency
Visible = true, Visible = true,
IsActive = true, IsActive = true,
IsDeleted = false, IsDeleted = false,
AllowSearch = true, AllowSearch = false,
ValidationRuleJson = JsonSerializer.Serialize(new[] ValidationRuleJson = JsonSerializer.Serialize(new[]
{ {
new ValidationRuleDto { Type = "required" } new ValidationRuleDto { Type = "required" }
@ -13124,7 +13124,7 @@ public class ListFormsSeeder : IDataSeedContributor, ITransientDependency
Visible = true, Visible = true,
IsActive = true, IsActive = true,
IsDeleted = false, IsDeleted = false,
AllowSearch = true, AllowSearch = false,
ValidationRuleJson = JsonSerializer.Serialize(new[] ValidationRuleJson = JsonSerializer.Serialize(new[]
{ {
new ValidationRuleDto { Type = "required" } new ValidationRuleDto { Type = "required" }
@ -13183,7 +13183,7 @@ public class ListFormsSeeder : IDataSeedContributor, ITransientDependency
Visible = true, Visible = true,
IsActive = true, IsActive = true,
IsDeleted = false, IsDeleted = false,
AllowSearch = true, AllowSearch = false,
ValidationRuleJson = JsonSerializer.Serialize(new[] ValidationRuleJson = JsonSerializer.Serialize(new[]
{ {
new ValidationRuleDto { Type = "required" } new ValidationRuleDto { Type = "required" }
@ -13899,7 +13899,7 @@ public class ListFormsSeeder : IDataSeedContributor, ITransientDependency
Visible = true, Visible = true,
IsActive = true, IsActive = true,
IsDeleted = false, IsDeleted = false,
AllowSearch = true, AllowSearch = false,
ValidationRuleJson = JsonSerializer.Serialize(new[] ValidationRuleJson = JsonSerializer.Serialize(new[]
{ {
new ValidationRuleDto { Type = "required" } new ValidationRuleDto { Type = "required" }
@ -13932,7 +13932,7 @@ public class ListFormsSeeder : IDataSeedContributor, ITransientDependency
Visible = true, Visible = true,
IsActive = true, IsActive = true,
IsDeleted = false, IsDeleted = false,
AllowSearch = true, AllowSearch = false,
PermissionJson = JsonSerializer.Serialize(new ListFormFieldPermissionDto PermissionJson = JsonSerializer.Serialize(new ListFormFieldPermissionDto
{ {
C = AppCodes.Orders.Products + ".Create", C = AppCodes.Orders.Products + ".Create",
@ -15790,7 +15790,7 @@ public class ListFormsSeeder : IDataSeedContributor, ITransientDependency
Visible = true, Visible = true,
IsActive = true, IsActive = true,
IsDeleted = false, IsDeleted = false,
AllowSearch = true, AllowSearch = false,
LookupJson = JsonSerializer.Serialize(new LookupDto { LookupJson = JsonSerializer.Serialize(new LookupDto {
DataSourceType = UiLookupDataSourceTypeEnum.Query, DataSourceType = UiLookupDataSourceTypeEnum.Query,
DisplayExpr = "Name", DisplayExpr = "Name",
@ -15848,7 +15848,7 @@ public class ListFormsSeeder : IDataSeedContributor, ITransientDependency
Visible = true, Visible = true,
IsActive = true, IsActive = true,
IsDeleted = false, IsDeleted = false,
AllowSearch = true, AllowSearch = false,
LookupJson = JsonSerializer.Serialize(new LookupDto { LookupJson = JsonSerializer.Serialize(new LookupDto {
DataSourceType = UiLookupDataSourceTypeEnum.Query, DataSourceType = UiLookupDataSourceTypeEnum.Query,
DisplayExpr = "Name", DisplayExpr = "Name",
@ -16322,7 +16322,7 @@ public class ListFormsSeeder : IDataSeedContributor, ITransientDependency
Visible = true, Visible = true,
IsActive = true, IsActive = true,
IsDeleted = false, IsDeleted = false,
AllowSearch = true, AllowSearch = false,
LookupJson = JsonSerializer.Serialize(new LookupDto { LookupJson = JsonSerializer.Serialize(new LookupDto {
DataSourceType = UiLookupDataSourceTypeEnum.Query, DataSourceType = UiLookupDataSourceTypeEnum.Query,
DisplayExpr = "Name", DisplayExpr = "Name",

View file

@ -12510,6 +12510,36 @@
"en": "Height", "en": "Height",
"tr": "Yükseklik" "tr": "Yükseklik"
}, },
{
"resourceName": "Platform",
"key": "ListForms.ListFormEdit.DetailsLayoutDto.GridLayout",
"en": "Grid Layout",
"tr": "Liste Düzeni"
},
{
"resourceName": "Platform",
"key": "ListForms.ListFormEdit.DetailsLayoutDto.CardLayout",
"en": "Card Layout",
"tr": "Kart Düzeni"
},
{
"resourceName": "Platform",
"key": "ListForms.ListFormEdit.DetailsLayoutDto.PivotLayout",
"en": "Pivot Layout",
"tr": "Pivot Düzeni"
},
{
"resourceName": "Platform",
"key": "ListForms.ListFormEdit.DetailsLayoutDto.DefaultLayout",
"en": "Default Layout",
"tr": "Varsayılan Düzen"
},
{
"resourceName": "Platform",
"key": "ListForms.ListFormEdit.DetailsLayoutDto.CardLayoutColumn",
"en": "Card Layout Column",
"tr": "Kart Düzeni Sütunu"
},
{ {
"resourceName": "Platform", "resourceName": "Platform",
"key": "ListForms.ListFormEdit.DatabaseDataSource", "key": "ListForms.ListFormEdit.DatabaseDataSource",

View file

@ -121,4 +121,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 ExtraFilterJson { get; set; } public string ExtraFilterJson { get; set; }
/// <summary>bu listform'un üstünde yer alan widgetların listesidir</summary>
public string LayoutJson { 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("20250917121912_Initial")] [Migration("20250922114945_Initial")]
partial class Initial partial class Initial
{ {
/// <inheritdoc /> /// <inheritdoc />
@ -2869,6 +2869,9 @@ namespace Kurs.Platform.Migrations
.HasColumnType("uniqueidentifier") .HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId"); .HasColumnName("LastModifierId");
b.Property<string>("LayoutJson")
.HasColumnType("nvarchar(max)");
b.Property<string>("ListFormCode") b.Property<string>("ListFormCode")
.IsRequired() .IsRequired()
.HasColumnType("nvarchar(450)"); .HasColumnType("nvarchar(450)");

View file

@ -1241,6 +1241,7 @@ namespace Kurs.Platform.Migrations
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), ExtraFilterJson = table.Column<string>(type: "nvarchar(max)", nullable: true),
LayoutJson = 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

@ -2866,6 +2866,9 @@ namespace Kurs.Platform.Migrations
.HasColumnType("uniqueidentifier") .HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId"); .HasColumnName("LastModifierId");
b.Property<string>("LayoutJson")
.HasColumnType("nvarchar(max)");
b.Property<string>("ListFormCode") b.Property<string>("ListFormCode")
.IsRequired() .IsRequired()
.HasColumnType("nvarchar(450)"); .HasColumnType("nvarchar(450)");

View file

@ -19,6 +19,7 @@ import {
import { FormItemComponent } from 'devextreme/ui/form' import { FormItemComponent } from 'devextreme/ui/form'
import { AuditedEntityDto } from '../abp' import { AuditedEntityDto } from '../abp'
import { EditorType2, RowMode } from '../../views/form/types' import { EditorType2, RowMode } from '../../views/form/types'
import { bool } from 'yup'
//1 //1
export interface SelectListItem { export interface SelectListItem {
@ -481,6 +482,7 @@ export interface GridOptionsDto extends AuditedEntityDto<string> {
subFormsDto: SubFormDto[] subFormsDto: SubFormDto[]
extraFilterJson?: string extraFilterJson?: string
extraFilterDto: ExtraFilterDto[] extraFilterDto: ExtraFilterDto[]
layoutDto: LayoutDto
} }
export interface GridOptionsEditDto extends GridOptionsDto, Record<string, any> { export interface GridOptionsEditDto extends GridOptionsDto, Record<string, any> {
@ -727,6 +729,14 @@ export interface WidgetEditDto {
onClick: string onClick: string
} }
export interface LayoutDto {
grid: boolean
card: boolean
pivot: boolean
defaultLayout: 'grid' | 'card' | 'pivot'
cardLayoutColumn: number
}
export interface ExtraFilterDto { export interface ExtraFilterDto {
fieldName: string fieldName: string
caption: string caption: string

View file

@ -292,7 +292,7 @@ function ChartEdit() {
<div className="lg:flex items-center justify-between mb-4 gap-3"> <div className="lg:flex items-center justify-between mb-4 gap-3">
<div className="mb-4 lg:mb-0"> <div className="mb-4 lg:mb-0">
<h4> <h4>
<Link to={`/chart/${chartCode}`}>🔙 {chartCode}</Link> <Link to={`/admin/chart/${chartCode}`}>🔙 {chartCode}</Link>
</h4> </h4>
{chartValues.isTenant && ( {chartValues.isTenant && (
<Alert showIcon className="mb-4" type="warning"> <Alert showIcon className="mb-4" type="warning">
@ -3450,7 +3450,7 @@ function ChartEdit() {
id: chartValues.id, id: chartValues.id,
index: databaseOperationsModalData.index, index: databaseOperationsModalData.index,
fieldName: 'serie', fieldName: 'serie',
itemSerie: { ...values }, itemSerie: { ...values } as ChartSeriesDto,
}) })
toast.push( toast.push(

View file

@ -10,7 +10,7 @@ import { Field, FieldProps, Form, Formik } from 'formik'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import * as Yup from 'yup' import * as Yup from 'yup'
import { FormEditProps } from './FormEdit' import { FormEditProps } from './FormEdit'
import { listFormTypeOptions } from './options' import { listFormDefaultLayoutOptions, listFormTypeOptions } from './options'
const schema = Yup.object().shape({ const schema = Yup.object().shape({
cultureName: Yup.string().required('Culture Name Required'), cultureName: Yup.string().required('Culture Name Required'),
@ -18,6 +18,13 @@ const schema = Yup.object().shape({
name: Yup.string(), name: Yup.string(),
pageSize: Yup.number(), pageSize: Yup.number(),
description: Yup.string(), description: Yup.string(),
layoutDto: Yup.object().shape({
grid: Yup.boolean(),
card: Yup.boolean(),
pivot: Yup.boolean(),
defaultLayout: Yup.string(),
cardLayoutColumn: Yup.number(),
}),
}) })
function FormTabDetails(props: FormEditProps) { function FormTabDetails(props: FormEditProps) {
@ -181,6 +188,92 @@ function FormTabDetails(props: FormEditProps) {
component={Input} component={Input}
/> />
</FormItem> </FormItem>
<FormItem
label={translate('::ListForms.ListFormEdit.DetailsLayoutDto.GridLayout')}
invalid={errors.layoutDto?.grid && touched.layoutDto?.grid}
errorMessage={errors.layoutDto?.grid}
>
<Field
className="w-20"
autoComplete="off"
name="layoutDto.grid"
placeholder={translate('::ListForms.ListFormEdit.DetailsLayoutDto.GridLayout')}
component={Checkbox}
/>
</FormItem>
<FormItem
label={translate('::ListForms.ListFormEdit.DetailsLayoutDto.CardLayout')}
invalid={errors.layoutDto?.card && touched.layoutDto?.card}
errorMessage={errors.layoutDto?.card}
>
<Field
className="w-20"
autoComplete="off"
name="layoutDto.card"
placeholder={translate('::ListForms.ListFormEdit.DetailsLayoutDto.CardLayout')}
component={Checkbox}
/>
</FormItem>
<FormItem
label={translate('::ListForms.ListFormEdit.DetailsLayoutDto.PivotLayout')}
invalid={errors.layoutDto?.card && touched.layoutDto?.card}
errorMessage={errors.layoutDto?.card}
>
<Field
className="w-20"
autoComplete="off"
name="layoutDto.pivot"
placeholder={translate('::ListForms.ListFormEdit.DetailsLayoutDto.PivotLayout')}
component={Checkbox}
/>
</FormItem>
<FormItem
label={translate('::ListForms.ListFormEdit.DetailsLayoutDto.DefaultLayout')}
invalid={errors.layoutDto?.defaultLayout && touched.layoutDto?.defaultLayout}
errorMessage={errors.layoutDto?.defaultLayout}
>
<Field
type="text"
autoComplete="off"
name="layoutDto.defaultLayout"
placeholder={translate('::ListForms.ListFormEdit.DetailsLayoutDto.DefaultLayout')}
>
{({ field, form }: FieldProps<SelectBox>) => (
<Select
field={field}
form={form}
isClearable={true}
options={listFormDefaultLayoutOptions}
value={listFormDefaultLayoutOptions?.filter(
(option) => option.value === values.layoutDto.defaultLayout,
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>
)}
</Field>
</FormItem>
<FormItem
label={translate('::ListForms.ListFormEdit.DetailsLayoutDto.CardLayoutColumn')}
invalid={errors.layoutDto?.cardLayoutColumn && touched.layoutDto?.cardLayoutColumn}
errorMessage={errors.layoutDto?.cardLayoutColumn}
>
<Field
type="number"
className="w-20"
autoComplete="off"
name="layoutDto.cardLayoutColumn"
placeholder={translate(
'::ListForms.ListFormEdit.DetailsLayoutDto.CardLayoutColumn',
)}
component={Input}
/>
</FormItem>
<Button block variant="solid" loading={isSubmitting} type="submit"> <Button block variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::SavingWithThreeDot') : translate('::Save')} {isSubmitting ? translate('::SavingWithThreeDot') : translate('::Save')}
</Button> </Button>

View file

@ -189,6 +189,12 @@ export const listFormTypeOptions = [
{ value: 'List', label: 'List' }, { value: 'List', label: 'List' },
] ]
export const listFormDefaultLayoutOptions = [
{ value: 'grid', label: 'Grid' },
{ value: 'card', label: 'Card' },
{ value: 'pivot', label: 'Pivot' },
]
export const listFormAlignmentOptions = [ export const listFormAlignmentOptions = [
{ value: 'center', label: 'Center' }, { value: 'center', label: 'Center' },
{ value: 'left', label: 'Left' }, { value: 'left', label: 'Left' },

View file

@ -24,7 +24,7 @@ const FormDevExpress = (props: {
const { listFormCode, isSubForm, mode, refForm, formData, formItems, setFormData } = props const { listFormCode, isSubForm, mode, refForm, formData, formItems, setFormData } = props
return ( return (
<form className={`${DX_CLASSNAMES} p-2`}> <form className={`${DX_CLASSNAMES} py-2`}>
<FormDx <FormDx
ref={refForm} ref={refForm}
formData={formData} formData={formData}

View file

@ -4,13 +4,12 @@ import { captionize } from 'devextreme/core/utils/inflector'
import { useListFormCustomDataSource } from '@/shared/useListFormCustomDataSource' import { useListFormCustomDataSource } from '@/shared/useListFormCustomDataSource'
import { Button, Pagination, Select } from '@/components/ui' import { Button, Pagination, Select } from '@/components/ui'
import classNames from 'classnames' import classNames from 'classnames'
import { getList } from '@/services/form.service' import { FaSearch } from 'react-icons/fa'
import { FaInbox, FaSearch } from 'react-icons/fa'
import FormDevExpress from '../form/FormDevExpress' import FormDevExpress from '../form/FormDevExpress'
import { GroupItem } from 'devextreme/ui/form' import { GroupItem } from 'devextreme/ui/form'
import { Form as FormDx } from 'devextreme-react/form' import { Form as FormDx } from 'devextreme-react/form'
import FormButtons from '../form/FormButtons' import FormButtons from '../form/FormButtons'
import { useNavigate } from 'react-router-dom' import { Link, useNavigate } from 'react-router-dom'
import { ROUTES_ENUM } from '@/routes/route.constant' import { ROUTES_ENUM } from '@/routes/route.constant'
import CustomStore from 'devextreme/data/custom_store' import CustomStore from 'devextreme/data/custom_store'
import { PermissionResults, SimpleItemWithColData } from '../form/types' import { PermissionResults, SimpleItemWithColData } from '../form/types'
@ -24,6 +23,10 @@ import { GridExtraFilterState } from './Utils'
interface CardProps { interface CardProps {
listFormCode: string listFormCode: string
searchParams?: URLSearchParams searchParams?: URLSearchParams
isSubForm?: boolean
level?: number
refreshData?: () => Promise<void>
gridDto?: GridDto
} }
type Option = { type Option = {
@ -147,7 +150,7 @@ const CardItem = ({
return ( return (
<div className="bg-white dark:bg-neutral-800 border dark:border-neutral-700 flex flex-col groupp p-2"> <div className="bg-white dark:bg-neutral-800 border dark:border-neutral-700 flex flex-col groupp p-2">
<div className={`flex items-center mb-2 ${isSubForm ? 'justify-center' : 'justify-between'}`}> <div className={`flex items-center ${isSubForm ? 'justify-end' : 'justify-between'}`}>
{!isSubForm && <h3>{translate('::' + gridDto?.gridOptions.title)}</h3>} {!isSubForm && <h3>{translate('::' + gridDto?.gridOptions.title)}</h3>}
{permissionResults && ( {permissionResults && (
<FormButtons <FormButtons
@ -183,21 +186,22 @@ const CardItem = ({
) )
} }
const Card = ({ listFormCode, searchParams }: CardProps) => { const Card = (props: CardProps) => {
const { listFormCode, searchParams, gridDto } = props
const { createSelectDataSource } = useListFormCustomDataSource({}) const { createSelectDataSource } = useListFormCustomDataSource({})
const [gridDto, setGridDto] = useState<GridDto>()
const [data, setData] = useState<any[]>([]) const [data, setData] = useState<any[]>([])
const [totalCount, setTotalCount] = useState(0) const [totalCount, setTotalCount] = useState(0)
const [currentPage, setCurrentPage] = useState(1) const [currentPage, setCurrentPage] = useState(1)
const [pageSize, setPageSize] = useState(20) const [pageSize, setPageSize] = useState(20)
const [pageSizeOptions, setPageSizeOptions] = useState<Option[]>([]) const [pageSizeOptions, setPageSizeOptions] = useState<Option[]>([])
const [gridDataSource, setGridDataSource] = useState<CustomStore<any, any>>() const [gridDataSource, setGridDataSource] = useState<CustomStore<any, any>>()
const [extraFilters, setExtraFilters] = useState<GridExtraFilterState[]>([])
const [layoutCount, setLayoutCount] = useState(4)
const { getLookupDataSource } = useLookupDataSource({ listFormCode }) const { getLookupDataSource } = useLookupDataSource({ listFormCode })
const lookupCache = useRef<Map<string, any>>(new Map()) const [layoutCount, setLayoutCount] = useState(4)
const [searchText, setSearchText] = useState('')
const [loading, setLoading] = useState(false)
const [extraFilters, setExtraFilters] = useState<GridExtraFilterState[]>([])
const lookupCache = useRef<Map<string, any>>(new Map())
const getCachedLookupDataSource = useCallback( const getCachedLookupDataSource = useCallback(
(editorOptions: any, colData: any) => { (editorOptions: any, colData: any) => {
const key = colData?.fieldName const key = colData?.fieldName
@ -220,19 +224,70 @@ const Card = ({ listFormCode, searchParams }: CardProps) => {
setCurrentPage(page) setCurrentPage(page)
} }
useEffect(() => { // props.searchParams varsa onunla başlat
getList({ listFormCode }).then((res: any) => setGridDto(res.data)) const [urlSearchParams, setUrlSearchParams] = useState<URLSearchParams>(
}, [listFormCode]) searchParams ? new URLSearchParams(searchParams) : new URLSearchParams(),
)
const filtrele = useCallback(
(value?: string) => {
const text = value !== undefined ? value.trim() : searchText.trim()
if (!gridDto?.columnFormats) return
const newParams = new URLSearchParams(urlSearchParams.toString())
if (!text) {
newParams.delete('filter')
setUrlSearchParams(newParams)
return
}
const merged = gridDto.columnFormats
.filter(
(col) =>
col.dataType === 'string' &&
col.visible &&
col.width &&
col.allowSearch &&
col.width > 0,
)
.map((col) => [col.fieldName, 'contains', text])
let filter: any = null
if (merged.length === 1) {
filter = merged[0]
} else if (merged.length > 1) {
filter = merged.reduce((acc, f, idx) => {
if (idx === 0) return f
return [acc, 'or', f]
}, null as any)
}
if (filter) {
newParams.set('filter', JSON.stringify(filter))
} else {
newParams.delete('filter')
}
setUrlSearchParams(newParams) // ✅ state güncelleniyor
console.log('Applied filter:', filter)
},
[gridDto, urlSearchParams, searchText],
)
useEffect(() => { useEffect(() => {
if (gridDto) { if (gridDto) {
const dataSource = createSelectDataSource(gridDto.gridOptions, listFormCode, searchParams) const dataSource = createSelectDataSource(gridDto.gridOptions, listFormCode, urlSearchParams)
setGridDataSource(dataSource) setGridDataSource(dataSource)
setLayoutCount(gridDto.gridOptions.layoutDto.cardLayoutColumn || 4)
} }
}, [gridDto, listFormCode, searchParams, createSelectDataSource]) }, [gridDto, listFormCode, urlSearchParams, createSelectDataSource])
const loadData = useCallback(() => { const loadData = useCallback(() => {
if (!gridDataSource) return if (!gridDataSource) return
setLoading(true)
const loadOptions = { const loadOptions = {
skip: (currentPage - 1) * pageSize, skip: (currentPage - 1) * pageSize,
@ -240,9 +295,15 @@ const Card = ({ listFormCode, searchParams }: CardProps) => {
requireTotalCount: true, requireTotalCount: true,
} }
gridDataSource.load(loadOptions).then((res: any) => { gridDataSource
.load(loadOptions)
.then((res: any) => {
setData(res.data) setData(res.data)
setTotalCount(res.totalCount || 0) setTotalCount(res.totalCount || 0)
setLoading(false)
})
.catch(() => {
setLoading(false)
}) })
}, [gridDataSource, currentPage, pageSize]) }, [gridDataSource, currentPage, pageSize])
@ -264,10 +325,13 @@ const Card = ({ listFormCode, searchParams }: CardProps) => {
setPageSizeOptions(allowedSizes.map((size) => ({ value: size, label: `${size} page` }))) setPageSizeOptions(allowedSizes.map((size) => ({ value: size, label: `${size} page` })))
}, [gridDto, listFormCode, searchParams]) }, [gridDto, listFormCode, searchParams])
// Data güncellendiğinde sayfanın en üstüne kaydır
useEffect(() => { useEffect(() => {
if (data.length > 0) { if (data.length > 0) {
window.scrollTo({ top: 0, behavior: 'smooth' }) window.scrollTo({ top: 0, behavior: 'smooth' })
if (data.length < 3) {
setLayoutCount(data.length)
}
} }
}, [data]) }, [data])
@ -278,20 +342,49 @@ const Card = ({ listFormCode, searchParams }: CardProps) => {
<WidgetGroup widgetGroups={gridDto.widgets || []} /> <WidgetGroup widgetGroups={gridDto.widgets || []} />
<Container> <Container>
<div className="bg-white border border-solid border-1 dark:bg-neutral-800 dark:border-neutral-700 flex justify-end items-center"> <div className="p-1 bg-white dark:bg-neutral-800 dark:border-neutral-700 ">
<div className="relative py-1 px-2 flex gap-1"> <div className="flex justify-end items-center">
<FaSearch className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 text-sm" /> <div className="relative py-1 flex gap-1 border-b-1">
<FaSearch className="absolute left-2 top-1/2 -translate-y-1/2 text-gray-400 text-sm" />
<input <input
type="text" type="text"
placeholder="Search..." placeholder="Search..."
value={searchText}
onChange={(e) => setSearchText(e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
filtrele(e.currentTarget.value)
}
}}
onBlur={(e) => {
filtrele(e.currentTarget.value)
}}
className="p-1 pl-6 pr-2 border border-1 outline-none text-xs text-gray-700 dark:text-gray-200 placeholder-gray-400 rounded" className="p-1 pl-6 pr-2 border border-1 outline-none text-xs text-gray-700 dark:text-gray-200 placeholder-gray-400 rounded"
/> />
<Button
size="xs"
variant={layoutCount === 1 ? 'solid' : 'default'}
className="text-sm"
onClick={() => setLayoutCount(1)}
title="1 Sütunda Göster"
>
1
</Button>
<Button
size="xs"
variant={layoutCount === 2 ? 'solid' : 'default'}
className="text-sm"
onClick={() => setLayoutCount(2)}
title="2 Sütunda Göster"
>
2
</Button>
<Button <Button
size="xs" size="xs"
variant={layoutCount === 3 ? 'solid' : 'default'} variant={layoutCount === 3 ? 'solid' : 'default'}
className="text-sm" className="text-sm"
onClick={() => setLayoutCount(3)} onClick={() => setLayoutCount(3)}
title="3 Sütunda Göster"
> >
3 3
</Button> </Button>
@ -300,6 +393,7 @@ const Card = ({ listFormCode, searchParams }: CardProps) => {
variant={layoutCount === 4 ? 'solid' : 'default'} variant={layoutCount === 4 ? 'solid' : 'default'}
className="text-sm" className="text-sm"
onClick={() => setLayoutCount(4)} onClick={() => setLayoutCount(4)}
title="4 Sütunda Göster"
> >
4 4
</Button> </Button>
@ -308,13 +402,27 @@ const Card = ({ listFormCode, searchParams }: CardProps) => {
variant={layoutCount === 5 ? 'solid' : 'default'} variant={layoutCount === 5 ? 'solid' : 'default'}
className="text-sm" className="text-sm"
onClick={() => setLayoutCount(5)} onClick={() => setLayoutCount(5)}
title="5 Sütunda Göster"
> >
5 5
</Button> </Button>
</div> </div>
</div> </div>
<div className={`grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-${layoutCount} gap-4`}> {loading ? (
<Loading loading={true} />
) : data.length === 0 ? (
<div className="text-center py-12">
<FaSearch className="mx-auto h-10 w-10 text-gray-400" />
<h3 className="mt-2 text-sm font-medium text-gray-900 dark:text-gray-200">
Uygun kayıt bulunamadı
</h3>
<p className="mt-1 text-xs text-gray-500 dark:text-gray-400">
Farklı filtreler deneyin veya yeni bir kayıt ekleyin.
</p>
</div>
) : (
<div className={`bg-transparent grid grid-cols-1 lg:grid-cols-${layoutCount} gap-4`}>
{gridDataSource && {gridDataSource &&
data.map((row, idx) => { data.map((row, idx) => {
const keyField = gridDto.gridOptions.keyFieldName const keyField = gridDto.gridOptions.keyFieldName
@ -334,9 +442,10 @@ const Card = ({ listFormCode, searchParams }: CardProps) => {
) )
})} })}
</div> </div>
)}
{gridDto.gridOptions.pagerOptionDto?.visible && totalCount > pageSize && ( {gridDto.gridOptions.pagerOptionDto?.visible && totalCount > pageSize && (
<div className={classNames('flex items-center justify-between border-t-1 gap-4 mt-4')}> <div className={classNames('flex items-center justify-between border-t-1 gap-4 mt-2')}>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<span className="text-xs text-gray-600 dark:text-gray-300"> <span className="text-xs text-gray-600 dark:text-gray-300">
Toplam {totalCount} kayıt Toplam {totalCount} kayıt
@ -357,21 +466,7 @@ const Card = ({ listFormCode, searchParams }: CardProps) => {
/> />
</div> </div>
)} )}
</div>
{data.length === 0 && (
<Loading loading={!data.length} />
// <div className="flex flex-col items-center justify-center p-10 bg-gray-50 dark:bg-neutral-800/50 rounded-md border-2 border-dashed border-gray-200 dark:border-neutral-700">
// <div className="text-center">
// <FaInbox className="mx-auto h-12 w-12 text-gray-400 dark:text-gray-500" />
// <p className="mt-4 text-lg font-semibold text-gray-700 dark:text-gray-300">
// Kayıt Bulunamadı
// </p>
// <p className="text-sm text-gray-500 dark:text-gray-400 mt-1">
// Görüntülenecek herhangi bir veri yok.
// </p>
// </div>
// </div>
)}
</Container> </Container>
</> </>
) )

View file

@ -8,7 +8,6 @@ import {
ListFormCustomizationTypeEnum, ListFormCustomizationTypeEnum,
PlatformEditorTypes, PlatformEditorTypes,
} from '@/proxy/form/models' } from '@/proxy/form/models'
import { getList } from '@/services/form.service'
import { import {
getListFormCustomization, getListFormCustomization,
postListFormCustomization, postListFormCustomization,
@ -74,20 +73,19 @@ interface GridProps {
isSubForm?: boolean isSubForm?: boolean
level?: number level?: number
refreshData?: () => Promise<void> refreshData?: () => Promise<void>
onGridDtoLoad?: (gridDto: GridDto) => void gridDto?: GridDto
} }
const statedGridPanelColor = 'rgba(50, 200, 200, 0.5)' // kullanici tanimli gridState ile islem gormus gridin paneline ait renk const statedGridPanelColor = 'rgba(50, 200, 200, 0.5)' // kullanici tanimli gridState ile islem gormus gridin paneline ait renk
const Grid = (props: GridProps) => { const Grid = (props: GridProps) => {
const { listFormCode, searchParams, isSubForm, level } = props const { listFormCode, searchParams, isSubForm, level, gridDto } = props
const { translate } = useLocalization() const { translate } = useLocalization()
const { smaller } = useResponsive() const { smaller } = useResponsive()
const gridRef = useRef<DataGrid>() const gridRef = useRef<DataGrid>()
const refListFormCode = useRef('') const refListFormCode = useRef('')
const [gridDto, setGridDto] = useState<GridDto>()
const [gridDataSource, setGridDataSource] = useState<CustomStore<any, any>>() const [gridDataSource, setGridDataSource] = useState<CustomStore<any, any>>()
const [columnData, setColumnData] = useState<GridColumnData[]>() const [columnData, setColumnData] = useState<GridColumnData[]>()
const [formData, setFormData] = useState<any>() const [formData, setFormData] = useState<any>()
@ -102,12 +100,12 @@ const Grid = (props: GridProps) => {
import('devextreme/pdf_exporter') import('devextreme/pdf_exporter')
} }
const defaultSearchParamsFilter = useRef<string | null>(null) const defaultSearchParams = useRef<string | null>(null)
useEffect(() => { useEffect(() => {
// sadece 1 kere açılışta al // sadece 1 kere açılışta al
if (!defaultSearchParamsFilter.current) { if (!defaultSearchParams.current) {
defaultSearchParamsFilter.current = searchParams?.get('filter') ?? null defaultSearchParams.current = searchParams?.get('filter') ?? null
} }
}, [searchParams]) }, [searchParams])
@ -401,17 +399,9 @@ const Grid = (props: GridProps) => {
gridRef.current.instance.state(null) gridRef.current.instance.state(null)
} }
const initializeGrid = async () => { if (refListFormCode.current && refListFormCode.current !== listFormCode) {
const response = await getList({ listFormCode })
setGridDto(response.data)
}
if (refListFormCode.current !== listFormCode) {
initializeGrid()
//bir önceki gridin filtreleri kalmasın
setExtraFilters([]) setExtraFilters([])
defaultSearchParamsFilter.current = null defaultSearchParams.current = null
} }
}, [listFormCode]) }, [listFormCode])
@ -434,7 +424,6 @@ const Grid = (props: GridProps) => {
} }
if (gridDto?.gridOptions.extraFilterDto) { if (gridDto?.gridOptions.extraFilterDto) {
console.log('extraFilterDto:', gridDto.gridOptions.extraFilterDto)
setExtraFilters( setExtraFilters(
gridDto.gridOptions.extraFilterDto.map((f) => ({ gridDto.gridOptions.extraFilterDto.map((f) => ({
fieldName: f.fieldName, fieldName: f.fieldName,
@ -444,10 +433,6 @@ const Grid = (props: GridProps) => {
})), })),
) )
} }
if (gridDto) {
props.onGridDtoLoad?.(gridDto)
}
}, [gridDto]) }, [gridDto])
useEffect(() => { useEffect(() => {
@ -464,8 +449,8 @@ const Grid = (props: GridProps) => {
const activeFilters = extraFilters.filter((f) => f.value) const activeFilters = extraFilters.filter((f) => f.value)
let base: any = null let base: any = null
if (defaultSearchParamsFilter.current) { if (defaultSearchParams.current) {
base = JSON.parse(defaultSearchParamsFilter.current) base = JSON.parse(defaultSearchParams.current)
} }
// Default filter tripletlerini çıkar // Default filter tripletlerini çıkar

View file

@ -1,8 +1,8 @@
import { useLocation, useParams, useSearchParams } from 'react-router-dom' import { useLocation, useParams, useSearchParams } from 'react-router-dom'
import { useState } from 'react' import { useEffect, useState } from 'react'
import Container from '@/components/shared/Container' import Container from '@/components/shared/Container'
import Grid from './Grid' import Grid from './Grid'
import { FaList, FaTh, FaUser } from 'react-icons/fa' import { FaChartPie, FaList, FaTable, FaTh, FaUser } from 'react-icons/fa'
import { useStoreState } from '@/store/store' import { useStoreState } from '@/store/store'
import classNames from 'classnames' import classNames from 'classnames'
import { useLocalization } from '@/utils/hooks/useLocalization' import { useLocalization } from '@/utils/hooks/useLocalization'
@ -11,19 +11,41 @@ import Card from './Card'
import { Button } from '@/components/ui' import { Button } from '@/components/ui'
import navigationIcon from '@/configs/navigation-icon.config' import navigationIcon from '@/configs/navigation-icon.config'
import { navigationTreeToFlat } from '@/utils/navigation' import { navigationTreeToFlat } from '@/utils/navigation'
import Pivot from './Pivot'
import { getList } from '@/services/form.service'
import { Loading } from '@/components/shared'
const List = () => { const List = () => {
const params = useParams() const params = useParams()
const { translate } = useLocalization() const { translate } = useLocalization()
const [searchParams] = useSearchParams() const [searchParams] = useSearchParams()
const listFormCode = params?.listFormCode ?? '' const listFormCode = params?.listFormCode ?? ''
const [viewMode, setViewMode] = useState<'grid' | 'card'>('grid') const [viewMode, setViewMode] = useState<'grid' | 'card' | 'pivot'>()
const mode = useStoreState((state) => state.theme.mode) const mode = useStoreState((state) => state.theme.mode)
const [gridDto, setGridDto] = useState<GridDto>() const [gridDto, setGridDto] = useState<GridDto>()
const mainMenu = useStoreState((state) => state.abpConfig.menu.mainMenu) const mainMenu = useStoreState((state) => state.abpConfig.menu.mainMenu)
const location = useLocation() const location = useLocation()
if (!listFormCode) return null const initializeGridAsync = async () => {
const response = await getList({ listFormCode })
setGridDto(response.data)
}
useEffect(() => {
initializeGridAsync()
}, [listFormCode])
useEffect(() => {
if (!gridDto) {
return
}
setViewMode(gridDto?.gridOptions?.layoutDto.defaultLayout)
}, [gridDto])
if (!listFormCode) {
return null
}
const getCurrentMenuIcon = (className = 'w-6 h-6'): JSX.Element => { const getCurrentMenuIcon = (className = 'w-6 h-6'): JSX.Element => {
const menus = navigationTreeToFlat(mainMenu) const menus = navigationTreeToFlat(mainMenu)
@ -38,6 +60,10 @@ const List = () => {
return ( return (
<Container> <Container>
{!gridDto ? (
<Loading loading={true} />
) : (
<>
<div <div
className={classNames('flex items-center border-solid gap-1 pb-1', { className={classNames('flex items-center border-solid gap-1 pb-1', {
'border-gray-100': mode === 'light', 'border-gray-100': mode === 'light',
@ -45,19 +71,22 @@ const List = () => {
})} })}
> >
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
{getCurrentMenuIcon('w-6 h-6')} {getCurrentMenuIcon('w-5 h-5')} {/* ikon biraz küçüldü */}
<h3>{translate('::' + gridDto?.gridOptions?.title)}</h3> <h4 className="text-slate-700 text-sm font-medium leading-none">
{translate('::' + gridDto?.gridOptions?.title)}
</h4>
</div> </div>
{gridDto?.gridOptions?.description === gridDto?.gridOptions?.title ? ( {gridDto?.gridOptions?.description === gridDto?.gridOptions?.title ? (
<p className="text-gray-600 mr-auto pt-1 ml-2"></p> <p className="mr-auto"></p>
) : ( ) : (
<p className="text-gray-600 mr-auto pt-1 ml-2"> <p className="text-slate-500 text-xs mr-auto ml-2 leading-none">
{translate('::' + gridDto?.gridOptions?.description)} {translate('::' + gridDto?.gridOptions?.description)}
</p> </p>
)} )}
<div className="flex gap-1"> <div className="flex gap-1">
{gridDto?.gridOptions?.layoutDto.grid && (
<Button <Button
size="xs" size="xs"
variant={viewMode === 'grid' ? 'solid' : 'default'} variant={viewMode === 'grid' ? 'solid' : 'default'}
@ -66,6 +95,9 @@ const List = () => {
> >
<FaList className="w-4 h-4" /> <FaList className="w-4 h-4" />
</Button> </Button>
)}
{gridDto?.gridOptions?.layoutDto.card && (
<Button <Button
size="xs" size="xs"
variant={viewMode === 'card' ? 'solid' : 'default'} variant={viewMode === 'card' ? 'solid' : 'default'}
@ -74,18 +106,43 @@ const List = () => {
> >
<FaTh className="w-4 h-4" /> <FaTh className="w-4 h-4" />
</Button> </Button>
)}
{gridDto?.gridOptions?.layoutDto.pivot && (
<Button
size="xs"
variant={viewMode === 'pivot' ? 'solid' : 'default'}
onClick={() => setViewMode('pivot')}
title="Pivot Görünümü"
>
<FaTable className="w-4 h-4" />
</Button>
)}
</div> </div>
</div> </div>
{viewMode === 'grid' ? ( {viewMode === 'pivot' ? (
<Pivot
listFormCode={listFormCode}
searchParams={searchParams}
isSubForm={false}
gridDto={gridDto}
/>
) : viewMode === 'card' ? (
<Card
listFormCode={listFormCode}
searchParams={searchParams}
isSubForm={false}
gridDto={gridDto}
/>
) : (
<Grid <Grid
listFormCode={listFormCode} listFormCode={listFormCode}
searchParams={searchParams} searchParams={searchParams}
isSubForm={false} isSubForm={false}
onGridDtoLoad={setGridDto} gridDto={gridDto}
/> />
) : ( )}
<Card listFormCode={listFormCode} searchParams={searchParams} /> </>
)} )}
</Container> </Container>
) )

View file

@ -40,19 +40,19 @@ interface GridProps {
isSubForm?: boolean isSubForm?: boolean
level?: number level?: number
refreshData?: () => Promise<void> refreshData?: () => Promise<void>
gridDto?: GridDto
} }
const statedGridPanelColor = 'rgba(50, 200, 200, 0.5)' // kullanici tanimli gridState ile islem gormus gridin paneline ait renk const statedGridPanelColor = 'rgba(50, 200, 200, 0.5)' // kullanici tanimli gridState ile islem gormus gridin paneline ait renk
const Pivot = (props: GridProps) => { const Pivot = (props: GridProps) => {
const { listFormCode, searchParams, isSubForm, level } = props const { listFormCode, searchParams, isSubForm, level, gridDto } = props
const { translate } = useLocalization() const { translate } = useLocalization()
const gridRef = useRef<PivotGrid>() const gridRef = useRef<PivotGrid>()
const chartRef = useRef<Chart>(null) const chartRef = useRef<Chart>(null)
const refListFormCode = useRef('') const refListFormCode = useRef('')
const [gridDto, setGridDto] = useState<GridDto>()
const [gridDataSource, setGridDataSource] = useState<CustomStore<any, any>>() const [gridDataSource, setGridDataSource] = useState<CustomStore<any, any>>()
const [columnData, setColumnData] = useState<GridColumnData[]>() const [columnData, setColumnData] = useState<GridColumnData[]>()
@ -137,15 +137,6 @@ const Pivot = (props: GridProps) => {
gridRef.current.instance.option('dataSource', undefined) gridRef.current.instance.option('dataSource', undefined)
gridRef.current.instance.option('stateStoring', undefined) gridRef.current.instance.option('stateStoring', undefined)
} }
const initializeGrid = async () => {
const response = await getList({ listFormCode })
setGridDto(response.data)
}
if (refListFormCode.current !== listFormCode) {
initializeGrid()
}
}, [listFormCode]) }, [listFormCode])
useEffect(() => { useEffect(() => {

View file

@ -8,7 +8,6 @@ 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 './Utils'
type ToolbarModalData = { type ToolbarModalData = {
open: boolean open: boolean
@ -282,16 +281,9 @@ const useToolbar = ({
} }
useEffect(() => { useEffect(() => {
if (!gridDto) return () => null if (!gridDto && !listFormCode) return
if (!listFormCode) return () => null
const timeout = setTimeout(() => {
getToolbarData() getToolbarData()
}, 100)
return () => {
clearTimeout(timeout)
}
}, [gridDto, listFormCode]) }, [gridDto, listFormCode])
return { return {