Grid, Card, Pivot Layout
This commit is contained in:
parent
5dd6e0bcd4
commit
b2e489d705
19 changed files with 522 additions and 228 deletions
|
|
@ -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); }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)");
|
||||||
|
|
@ -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),
|
||||||
|
|
@ -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)");
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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' },
|
||||||
|
|
|
||||||
|
|
@ -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}
|
||||||
|
|
|
||||||
|
|
@ -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,10 +295,16 @@ const Card = ({ listFormCode, searchParams }: CardProps) => {
|
||||||
requireTotalCount: true,
|
requireTotalCount: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
gridDataSource.load(loadOptions).then((res: any) => {
|
gridDataSource
|
||||||
setData(res.data)
|
.load(loadOptions)
|
||||||
setTotalCount(res.totalCount || 0)
|
.then((res: any) => {
|
||||||
})
|
setData(res.data)
|
||||||
|
setTotalCount(res.totalCount || 0)
|
||||||
|
setLoading(false)
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setLoading(false)
|
||||||
|
})
|
||||||
}, [gridDataSource, currentPage, pageSize])
|
}, [gridDataSource, currentPage, pageSize])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -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,100 +342,131 @@ 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">
|
||||||
<input
|
<FaSearch className="absolute left-2 top-1/2 -translate-y-1/2 text-gray-400 text-sm" />
|
||||||
type="text"
|
<input
|
||||||
placeholder="Search..."
|
type="text"
|
||||||
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"
|
placeholder="Search..."
|
||||||
/>
|
value={searchText}
|
||||||
|
onChange={(e) => setSearchText(e.target.value)}
|
||||||
<Button
|
onKeyDown={(e) => {
|
||||||
size="xs"
|
if (e.key === 'Enter') {
|
||||||
variant={layoutCount === 3 ? 'solid' : 'default'}
|
filtrele(e.currentTarget.value)
|
||||||
className="text-sm"
|
}
|
||||||
onClick={() => setLayoutCount(3)}
|
}}
|
||||||
>
|
onBlur={(e) => {
|
||||||
3
|
filtrele(e.currentTarget.value)
|
||||||
</Button>
|
}}
|
||||||
<Button
|
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"
|
||||||
size="xs"
|
/>
|
||||||
variant={layoutCount === 4 ? 'solid' : 'default'}
|
<Button
|
||||||
className="text-sm"
|
|
||||||
onClick={() => setLayoutCount(4)}
|
|
||||||
>
|
|
||||||
4
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
size="xs"
|
|
||||||
variant={layoutCount === 5 ? 'solid' : 'default'}
|
|
||||||
className="text-sm"
|
|
||||||
onClick={() => setLayoutCount(5)}
|
|
||||||
>
|
|
||||||
5
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={`grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-${layoutCount} gap-4`}>
|
|
||||||
{gridDataSource &&
|
|
||||||
data.map((row, idx) => {
|
|
||||||
const keyField = gridDto.gridOptions.keyFieldName
|
|
||||||
const rowId = row[keyField!]
|
|
||||||
|
|
||||||
return (
|
|
||||||
<CardItem
|
|
||||||
isSubForm={true}
|
|
||||||
key={rowId || idx}
|
|
||||||
row={row}
|
|
||||||
gridDto={gridDto}
|
|
||||||
listFormCode={listFormCode}
|
|
||||||
dataSource={gridDataSource}
|
|
||||||
refreshData={loadData}
|
|
||||||
getCachedLookupDataSource={getCachedLookupDataSource}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{gridDto.gridOptions.pagerOptionDto?.visible && totalCount > pageSize && (
|
|
||||||
<div className={classNames('flex items-center justify-between border-t-1 gap-4 mt-4')}>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<span className="text-xs text-gray-600 dark:text-gray-300">
|
|
||||||
Toplam {totalCount} kayıt
|
|
||||||
</span>
|
|
||||||
<Select
|
|
||||||
size="xs"
|
size="xs"
|
||||||
menuPlacement="top"
|
variant={layoutCount === 1 ? 'solid' : 'default'}
|
||||||
value={pageSizeOptions.find((o) => o.value === pageSize)}
|
className="text-sm"
|
||||||
options={pageSizeOptions}
|
onClick={() => setLayoutCount(1)}
|
||||||
onChange={(selected) => onPageSizeSelect(selected as Option)}
|
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
|
||||||
|
size="xs"
|
||||||
|
variant={layoutCount === 3 ? 'solid' : 'default'}
|
||||||
|
className="text-sm"
|
||||||
|
onClick={() => setLayoutCount(3)}
|
||||||
|
title="3 Sütunda Göster"
|
||||||
|
>
|
||||||
|
3
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
size="xs"
|
||||||
|
variant={layoutCount === 4 ? 'solid' : 'default'}
|
||||||
|
className="text-sm"
|
||||||
|
onClick={() => setLayoutCount(4)}
|
||||||
|
title="4 Sütunda Göster"
|
||||||
|
>
|
||||||
|
4
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
size="xs"
|
||||||
|
variant={layoutCount === 5 ? 'solid' : 'default'}
|
||||||
|
className="text-sm"
|
||||||
|
onClick={() => setLayoutCount(5)}
|
||||||
|
title="5 Sütunda Göster"
|
||||||
|
>
|
||||||
|
5
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{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 &&
|
||||||
|
data.map((row, idx) => {
|
||||||
|
const keyField = gridDto.gridOptions.keyFieldName
|
||||||
|
const rowId = row[keyField!]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CardItem
|
||||||
|
isSubForm={true}
|
||||||
|
key={rowId || idx}
|
||||||
|
row={row}
|
||||||
|
gridDto={gridDto}
|
||||||
|
listFormCode={listFormCode}
|
||||||
|
dataSource={gridDataSource}
|
||||||
|
refreshData={loadData}
|
||||||
|
getCachedLookupDataSource={getCachedLookupDataSource}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{gridDto.gridOptions.pagerOptionDto?.visible && totalCount > pageSize && (
|
||||||
|
<div className={classNames('flex items-center justify-between border-t-1 gap-4 mt-2')}>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<span className="text-xs text-gray-600 dark:text-gray-300">
|
||||||
|
Toplam {totalCount} kayıt
|
||||||
|
</span>
|
||||||
|
<Select
|
||||||
|
size="xs"
|
||||||
|
menuPlacement="top"
|
||||||
|
value={pageSizeOptions.find((o) => o.value === pageSize)}
|
||||||
|
options={pageSizeOptions}
|
||||||
|
onChange={(selected) => onPageSizeSelect(selected as Option)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Pagination
|
||||||
|
currentPage={currentPage}
|
||||||
|
total={totalCount}
|
||||||
|
pageSize={pageSize}
|
||||||
|
onChange={onPageChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Pagination
|
)}
|
||||||
currentPage={currentPage}
|
</div>
|
||||||
total={totalCount}
|
|
||||||
pageSize={pageSize}
|
|
||||||
onChange={onPageChange}
|
|
||||||
/>
|
|
||||||
</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>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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,54 +60,89 @@ const List = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<div
|
{!gridDto ? (
|
||||||
className={classNames('flex items-center border-solid gap-1 pb-1', {
|
<Loading loading={true} />
|
||||||
'border-gray-100': mode === 'light',
|
|
||||||
'border-neutral-700': mode === 'dark',
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
{getCurrentMenuIcon('w-6 h-6')}
|
|
||||||
<h3>{translate('::' + gridDto?.gridOptions?.title)}</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{gridDto?.gridOptions?.description === gridDto?.gridOptions?.title ? (
|
|
||||||
<p className="text-gray-600 mr-auto pt-1 ml-2"></p>
|
|
||||||
) : (
|
|
||||||
<p className="text-gray-600 mr-auto pt-1 ml-2">
|
|
||||||
{translate('::' + gridDto?.gridOptions?.description)}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="flex gap-1">
|
|
||||||
<Button
|
|
||||||
size="xs"
|
|
||||||
variant={viewMode === 'grid' ? 'solid' : 'default'}
|
|
||||||
onClick={() => setViewMode('grid')}
|
|
||||||
title="Grid Görünümü"
|
|
||||||
>
|
|
||||||
<FaList className="w-4 h-4" />
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
size="xs"
|
|
||||||
variant={viewMode === 'card' ? 'solid' : 'default'}
|
|
||||||
onClick={() => setViewMode('card')}
|
|
||||||
title="Kart Görünümü"
|
|
||||||
>
|
|
||||||
<FaTh className="w-4 h-4" />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{viewMode === 'grid' ? (
|
|
||||||
<Grid
|
|
||||||
listFormCode={listFormCode}
|
|
||||||
searchParams={searchParams}
|
|
||||||
isSubForm={false}
|
|
||||||
onGridDtoLoad={setGridDto}
|
|
||||||
/>
|
|
||||||
) : (
|
) : (
|
||||||
<Card listFormCode={listFormCode} searchParams={searchParams} />
|
<>
|
||||||
|
<div
|
||||||
|
className={classNames('flex items-center border-solid gap-1 pb-1', {
|
||||||
|
'border-gray-100': mode === 'light',
|
||||||
|
'border-neutral-700': mode === 'dark',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
{getCurrentMenuIcon('w-5 h-5')} {/* ikon biraz küçüldü */}
|
||||||
|
<h4 className="text-slate-700 text-sm font-medium leading-none">
|
||||||
|
{translate('::' + gridDto?.gridOptions?.title)}
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{gridDto?.gridOptions?.description === gridDto?.gridOptions?.title ? (
|
||||||
|
<p className="mr-auto"></p>
|
||||||
|
) : (
|
||||||
|
<p className="text-slate-500 text-xs mr-auto ml-2 leading-none">
|
||||||
|
{translate('::' + gridDto?.gridOptions?.description)}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="flex gap-1">
|
||||||
|
{gridDto?.gridOptions?.layoutDto.grid && (
|
||||||
|
<Button
|
||||||
|
size="xs"
|
||||||
|
variant={viewMode === 'grid' ? 'solid' : 'default'}
|
||||||
|
onClick={() => setViewMode('grid')}
|
||||||
|
title="Grid Görünümü"
|
||||||
|
>
|
||||||
|
<FaList className="w-4 h-4" />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{gridDto?.gridOptions?.layoutDto.card && (
|
||||||
|
<Button
|
||||||
|
size="xs"
|
||||||
|
variant={viewMode === 'card' ? 'solid' : 'default'}
|
||||||
|
onClick={() => setViewMode('card')}
|
||||||
|
title="Kart Görünümü"
|
||||||
|
>
|
||||||
|
<FaTh className="w-4 h-4" />
|
||||||
|
</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>
|
||||||
|
|
||||||
|
{viewMode === 'pivot' ? (
|
||||||
|
<Pivot
|
||||||
|
listFormCode={listFormCode}
|
||||||
|
searchParams={searchParams}
|
||||||
|
isSubForm={false}
|
||||||
|
gridDto={gridDto}
|
||||||
|
/>
|
||||||
|
) : viewMode === 'card' ? (
|
||||||
|
<Card
|
||||||
|
listFormCode={listFormCode}
|
||||||
|
searchParams={searchParams}
|
||||||
|
isSubForm={false}
|
||||||
|
gridDto={gridDto}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Grid
|
||||||
|
listFormCode={listFormCode}
|
||||||
|
searchParams={searchParams}
|
||||||
|
isSubForm={false}
|
||||||
|
gridDto={gridDto}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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(() => {
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue