diff --git a/api/src/Kurs.Platform.Application.Contracts/ListForms/GridOptionsDto/GridOptionsDto.cs b/api/src/Kurs.Platform.Application.Contracts/ListForms/GridOptionsDto/GridOptionsDto.cs index 09e2b9fe..6371112f 100644 --- a/api/src/Kurs.Platform.Application.Contracts/ListForms/GridOptionsDto/GridOptionsDto.cs +++ b/api/src/Kurs.Platform.Application.Contracts/ListForms/GridOptionsDto/GridOptionsDto.cs @@ -149,6 +149,19 @@ public class GridOptionsDto : AuditedEntityDto set { PivotOptionJson = JsonSerializer.Serialize(value); } } + [JsonIgnore] + public string TreeOptionJson { get; set; } + public TreeOptionDto TreeOptionDto + { + get + { + if (!string.IsNullOrEmpty(TreeOptionJson)) + return JsonSerializer.Deserialize(TreeOptionJson); + return new TreeOptionDto(); + } + set { TreeOptionJson = JsonSerializer.Serialize(value); } + } + [JsonIgnore] public string PagerOptionJson { get; set; } public GridPagerOptionDto PagerOptionDto diff --git a/api/src/Kurs.Platform.Application.Contracts/ListForms/GridOptionsDto/LayoutDto.cs b/api/src/Kurs.Platform.Application.Contracts/ListForms/GridOptionsDto/LayoutDto.cs index eddbe7bc..7b118506 100644 --- a/api/src/Kurs.Platform.Application.Contracts/ListForms/GridOptionsDto/LayoutDto.cs +++ b/api/src/Kurs.Platform.Application.Contracts/ListForms/GridOptionsDto/LayoutDto.cs @@ -5,6 +5,7 @@ public class LayoutDto public bool Grid { get; set; } = true; public bool Card { get; set; } = true; public bool Pivot { get; set; } = true; + public bool Tree { get; set; } = true; public bool Chart { get; set; } = true; public string DefaultLayout { get; set; } = "grid"; public int CardLayoutColumn { get; set; } = 4; diff --git a/api/src/Kurs.Platform.Application.Contracts/ListForms/GridOptionsDto/TreeOptionDto.cs b/api/src/Kurs.Platform.Application.Contracts/ListForms/GridOptionsDto/TreeOptionDto.cs new file mode 100644 index 00000000..45b14b7a --- /dev/null +++ b/api/src/Kurs.Platform.Application.Contracts/ListForms/GridOptionsDto/TreeOptionDto.cs @@ -0,0 +1,37 @@ +namespace Kurs.Platform.ListForms; + +/// +/// TreeList için özel ayarları içerir +/// +public class TreeOptionDto +{ + /// + /// Parent kaydı belirten field adı (örn: "parentId") + /// + public string ParentIdExpr { get; set; } + + /// + /// Alt kayıtların olup olmadığını belirten field adı (opsiyonel) + /// + public string HasItemsExpr { get; set; } + + /// + /// Root (en üst) seviyedeki kayıtların parent değeri (genelde null veya 0) + /// + public object RootValue { get; set; } = null; + + /// + /// Başlangıçta açık olacak node'ların ID'leri + /// + public object[] ExpandedRowKeys { get; set; } = []; + + /// + /// Tüm node'ları başlangıçta açık göster + /// + public bool AutoExpandAll { get; set; } = false; + + /// + /// Alt kayıtlar seçildiğinde parent kayıtları da seç (recursive selection) + /// + public bool RecursiveSelection { get; set; } = false; +} diff --git a/api/src/Kurs.Platform.Application.Contracts/ListForms/ListFormEditTabs.cs b/api/src/Kurs.Platform.Application.Contracts/ListForms/ListFormEditTabs.cs index 68520a44..76515c93 100644 --- a/api/src/Kurs.Platform.Application.Contracts/ListForms/ListFormEditTabs.cs +++ b/api/src/Kurs.Platform.Application.Contracts/ListForms/ListFormEditTabs.cs @@ -46,6 +46,7 @@ public class ListFormEditTabs public const string SelectForm = "select"; public const string ColumnForm = "column"; public const string PivotForm = "pivot"; + public const string TreeForm = "tree"; public const string PagerForm = "pager"; public const string StateForm = "state"; public const string SubFormJsonRow = "subForm"; diff --git a/api/src/Kurs.Platform.Application/ListForms/Administration/ListFormsAppService.cs b/api/src/Kurs.Platform.Application/ListForms/Administration/ListFormsAppService.cs index 951f5519..c8811f43 100644 --- a/api/src/Kurs.Platform.Application/ListForms/Administration/ListFormsAppService.cs +++ b/api/src/Kurs.Platform.Application/ListForms/Administration/ListFormsAppService.cs @@ -146,6 +146,10 @@ public class ListFormsAppService : CrudAppService< { item.PivotOptionJson = JsonSerializer.Serialize(input.PivotOptionDto); } + else if (input.EditType == ListFormEditTabs.TreeForm) + { + item.TreeOptionJson = JsonSerializer.Serialize(input.TreeOptionDto); + } else if (input.EditType == ListFormEditTabs.PagerForm) { item.PagerOptionJson = JsonSerializer.Serialize(input.PagerOptionDto); diff --git a/api/src/Kurs.Platform.DbMigrator/Seeds/LanguagesData.json b/api/src/Kurs.Platform.DbMigrator/Seeds/LanguagesData.json index e6f207a5..f2bcae6b 100644 --- a/api/src/Kurs.Platform.DbMigrator/Seeds/LanguagesData.json +++ b/api/src/Kurs.Platform.DbMigrator/Seeds/LanguagesData.json @@ -3943,6 +3943,12 @@ "en": "Pivot Settings", "tr": "Pivot Settings" }, + { + "resourceName": "Platform", + "key": "ListForms.ListFormEdit.TabTree", + "en": "Tree", + "tr": "Ağaç" + }, { "resourceName": "Platform", "key": "ListForms.ListFormEdit.TabDetails", @@ -4189,6 +4195,12 @@ "en": "Pivot Layout", "tr": "Pivot Düzeni" }, + { + "resourceName": "Platform", + "key": "ListForms.ListFormEdit.DetailsLayoutDto.TreeLayout", + "en": "Tree Layout", + "tr": "Ağaç Düzeni" + }, { "resourceName": "Platform", "key": "ListForms.ListFormEdit.DetailsLayoutDto.ChartLayout", @@ -5167,6 +5179,36 @@ "en": "Visible", "tr": "Görünür" }, + { + "resourceName": "Platform", + "key": "ListForms.ListFormEdit.ParentIdExpr", + "en": "Parent ID Expression", + "tr": "Üst Kimlik İfadesi" + }, + { + "resourceName": "Platform", + "key": "ListForms.ListFormEdit.RootValue", + "en": "Root Value", + "tr": "Kök Değer" + }, + { + "resourceName": "Platform", + "key": "ListForms.ListFormEdit.HasItemsExpr", + "en": "Has Items Expression", + "tr": "Öğeler Var İfadesi" + }, + { + "resourceName": "Platform", + "key": "ListForms.ListFormEdit.RecursiveSelection", + "en": "Recursive Selection", + "tr": "Özyinelemeli Seçim" + }, + { + "resourceName": "Platform", + "key": "ListForms.ListFormEdit.AutoExpandAll", + "en": "Auto Expand All", + "tr": "Otomatik Tümünü Genişlet" + }, { "resourceName": "Platform", "key": "ListForms.ListFormEdit.GroupingAutoExpandAll", diff --git a/api/src/Kurs.Platform.Domain.Shared/Enums/ListFormTypeEnum.cs b/api/src/Kurs.Platform.Domain.Shared/Enums/ListFormTypeEnum.cs index df2517c5..6b2e6be0 100644 --- a/api/src/Kurs.Platform.Domain.Shared/Enums/ListFormTypeEnum.cs +++ b/api/src/Kurs.Platform.Domain.Shared/Enums/ListFormTypeEnum.cs @@ -5,4 +5,6 @@ public static class ListFormTypeEnum public const string List = "List"; public const string Form = "Form"; public const string Chart = "Chart"; + public const string Pivot = "Pivot"; + public const string Tree = "Tree"; } diff --git a/api/src/Kurs.Platform.Domain/Entities/Host/ListForm.cs b/api/src/Kurs.Platform.Domain/Entities/Host/ListForm.cs index c8469584..5730c74d 100644 --- a/api/src/Kurs.Platform.Domain/Entities/Host/ListForm.cs +++ b/api/src/Kurs.Platform.Domain/Entities/Host/ListForm.cs @@ -32,6 +32,7 @@ public class ListForm : FullAuditedEntity public string DefaultFilter { get; set; } // Her sorgunun sonuna eklenecek default WHERE condition public string ColumnOptionJson { get; set; } public string PivotOptionJson { get; set; } + public string TreeOptionJson { get; set; } public string FilterRowJson { get; set; } // Filtre ayarlari, Json olarak tutulur, donus sinifi FilterRowDto public string RowJson { get; set; } // Row ayarları, Json olarak tutulur, donus sinifi FilterRowDto public string HeaderFilterJson { get; set; } // Header filtreleme ayarlari, Json olarak tutulur diff --git a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251107194939_Initial.Designer.cs b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251107212125_Initial.Designer.cs similarity index 99% rename from api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251107194939_Initial.Designer.cs rename to api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251107212125_Initial.Designer.cs index 9a9ded03..da0cbb3a 100644 --- a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251107194939_Initial.Designer.cs +++ b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251107212125_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace Kurs.Platform.Migrations { [DbContext(typeof(PlatformDbContext))] - [Migration("20251107194939_Initial")] + [Migration("20251107212125_Initial")] partial class Initial { /// @@ -5210,6 +5210,9 @@ namespace Kurs.Platform.Migrations b.Property("TooltipJson") .HasColumnType("text"); + b.Property("TreeOptionJson") + .HasColumnType("nvarchar(max)"); + b.Property("UpdateCommand") .HasColumnType("text"); diff --git a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251107194939_Initial.cs b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251107212125_Initial.cs similarity index 99% rename from api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251107194939_Initial.cs rename to api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251107212125_Initial.cs index b0e24566..b2155ae8 100644 --- a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251107194939_Initial.cs +++ b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251107212125_Initial.cs @@ -1885,6 +1885,7 @@ namespace Kurs.Platform.Migrations DefaultFilter = table.Column(type: "text", nullable: true), ColumnOptionJson = table.Column(type: "text", nullable: true), PivotOptionJson = table.Column(type: "text", nullable: true), + TreeOptionJson = table.Column(type: "nvarchar(max)", nullable: true), FilterRowJson = table.Column(type: "text", nullable: true), RowJson = table.Column(type: "nvarchar(max)", nullable: true), HeaderFilterJson = table.Column(type: "text", nullable: true), diff --git a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs index 56e0ed0c..28d20d18 100644 --- a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs +++ b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs @@ -5207,6 +5207,9 @@ namespace Kurs.Platform.Migrations b.Property("TooltipJson") .HasColumnType("text"); + b.Property("TreeOptionJson") + .HasColumnType("nvarchar(max)"); + b.Property("UpdateCommand") .HasColumnType("text"); diff --git a/ui/src/proxy/admin/list-form/options.ts b/ui/src/proxy/admin/list-form/options.ts index 60db0529..f35b8b72 100644 --- a/ui/src/proxy/admin/list-form/options.ts +++ b/ui/src/proxy/admin/list-form/options.ts @@ -39,6 +39,7 @@ export const ListFormEditTabs = { SelectForm: 'select', ColumnForm: 'column', PivotForm: 'pivot', + TreeForm: 'tree', PagerForm: 'pager', StateForm: 'state', SubForm: 'subForm', @@ -86,6 +87,7 @@ export const tabVisibilityConfig: Record = { 'select', 'columns', 'pivots', + 'tree', 'pager', 'state', 'extrafilter', diff --git a/ui/src/proxy/form/models.ts b/ui/src/proxy/form/models.ts index 814ddffd..f5a6a6c5 100644 --- a/ui/src/proxy/form/models.ts +++ b/ui/src/proxy/form/models.ts @@ -377,6 +377,15 @@ export interface GridPivotOptionDto { chartCommonSeriesType: SeriesType } +export interface TreeOptionDto { + parentIdExpr?: string + hasItemsExpr?: string + rootValue?: any + expandedRowKeys?: any[] + autoExpandAll?: boolean + recursiveSelection?: boolean +} + export interface GridEditingDto { mode?: GridsEditMode refreshMode?: GridsEditRefreshMode @@ -472,6 +481,8 @@ export interface GridOptionsDto extends AuditedEntityDto { columnOptionDto: GridColumnOptionDto pivotOptionJson?: string pivotOptionDto: GridPivotOptionDto + treeOptionJson?: string + treeOptionDto: TreeOptionDto pagerOptionJson?: string pagerOptionDto: GridPagerOptionDto editingOptionJson?: string @@ -800,6 +811,7 @@ export interface LayoutDto { grid: boolean card: boolean pivot: boolean + tree: boolean chart: boolean defaultLayout: ListViewLayoutType cardLayoutColumn: number diff --git a/ui/src/shared/useListFormColumns.ts b/ui/src/shared/useListFormColumns.ts index 7a0d1172..6068a116 100644 --- a/ui/src/shared/useListFormColumns.ts +++ b/ui/src/shared/useListFormColumns.ts @@ -125,7 +125,7 @@ const useListFormColumns = ({ gridDto, listFormCode, isSubForm, - gridRef, + gridRef }: { gridDto?: GridDto listFormCode: string diff --git a/ui/src/shared/useListFormCustomDataSource.ts b/ui/src/shared/useListFormCustomDataSource.ts index a234df14..d16e6511 100644 --- a/ui/src/shared/useListFormCustomDataSource.ts +++ b/ui/src/shared/useListFormCustomDataSource.ts @@ -7,15 +7,17 @@ import { GridOptionsDto } from '../proxy/form/models' import { GridColumnData } from '../views/list/GridColumnData' import { dynamicFetch } from '../services/form.service' import { MULTIVALUE_DELIMITER } from '../constants/app.constant' +import { TreeList } from 'devextreme-react' const filteredGridPanelColor = 'rgba(10, 200, 10, 0.5)' // kullanici tanimli filtre ile filtrelenmis gridin paneline ait renk const useListFormCustomDataSource = ({ gridRef, - pivotRef, }: { - gridRef?: MutableRefObject | undefined> - pivotRef?: MutableRefObject + gridRef: + | MutableRefObject | undefined> + | MutableRefObject + | MutableRefObject | undefined> }) => { const createSelectDataSource = useCallback( ( @@ -58,8 +60,15 @@ const useListFormCustomDataSource = ({ if (gridRef?.current) { //TODO: } - const columns = - (gridRef?.current?.instance.option('columns') as GridColumnData[]) ?? cols + // Type guard to handle union type for gridRef + let columns = cols + if (gridRef?.current?.instance) { + const instance = gridRef.current.instance as any + const instanceColumns = instance.option('columns') + if (instanceColumns) { + columns = instanceColumns as GridColumnData[] + } + } // URL'deki filtreyi grid'in mevcut filtrelerinin üzerine uygula if (columns?.length && searchParams) { const filters: (string[] | string)[] = [] diff --git a/ui/src/views/admin/listForm/edit/FormEdit.tsx b/ui/src/views/admin/listForm/edit/FormEdit.tsx index 3a754b1c..a72d0bc0 100644 --- a/ui/src/views/admin/listForm/edit/FormEdit.tsx +++ b/ui/src/views/admin/listForm/edit/FormEdit.tsx @@ -36,6 +36,7 @@ import FormTabWidgets from './FormTabWidgets' import FormTabExtraFilters from './FormTabExtraFilters' import FormTabEditForm from './FormTabEditForm' import FormTabPivots from './FormTabPivots' +import FormTabTree from './FormTabTree' import ChartTabAnimation from './ChartTabAnimation' import ChartTabAnnotations from './ChartTabAnnotations' import ChartTabZoomAndPan from './ChartTabZoomAndPan' @@ -232,6 +233,9 @@ const FormEdit = () => { {visibleTabs.includes('pivots') && ( {translate('::ListForms.ListFormEdit.TabPivots')} )} + {visibleTabs.includes('tree') && ( + {translate('::ListForms.ListFormEdit.TabTree')} + )} {visibleTabs.includes('pager') && ( {translate('::ListForms.ListFormEdit.TabPaging')} )} @@ -355,6 +359,9 @@ const FormEdit = () => { + + + diff --git a/ui/src/views/admin/listForm/edit/FormTabDetails.tsx b/ui/src/views/admin/listForm/edit/FormTabDetails.tsx index 644cb869..90b94360 100644 --- a/ui/src/views/admin/listForm/edit/FormTabDetails.tsx +++ b/ui/src/views/admin/listForm/edit/FormTabDetails.tsx @@ -26,6 +26,8 @@ const schema = Yup.object().shape({ grid: Yup.boolean(), card: Yup.boolean(), pivot: Yup.boolean(), + chart: Yup.boolean(), + tree: Yup.boolean(), defaultLayout: Yup.string(), cardLayoutColumn: Yup.number(), }), @@ -123,57 +125,6 @@ function FormTabDetails( - {values.listFormType === 'List' && ( - <> - - - {({ field, form }: FieldProps) => ( - option.value === values.layoutDto.defaultLayout, + )} + onChange={(option) => form.setFieldValue(field.name, option?.value)} + /> + )} + + + + + + + + )} +
+ + + +
([]) + + const getFields = async () => { + if (!listFormCode) { + return + } + + try { + const resp = await getListFormFields({ + listFormCode, + sorting: 'ListOrderNo', + maxResultCount: 1000, + }) + if (resp.data?.items) { + const fieldNames = groupBy(resp?.data?.items, 'fieldName') + setFieldList( + Object.keys(fieldNames).map((a) => ({ + value: a, + label: a, + })), + ) + } + } catch (error: any) { + toast.push( + + Alanlar getirilemedi + {error.toString()} + , + { + placement: 'top-end', + }, + ) + } + } + + useEffect(() => { + getFields() + }, [listFormCode]) + + const listFormValues = useStoreState((s) => s.admin.lists.values) + if (!listFormValues) { + return null + } + + return ( + + { + await props.onSubmit(ListFormEditTabs.TreeForm, values, formikHelpers) + }} + > + {({ touched, errors, isSubmitting, values }) => ( +
+ + + + {({ field, form }: FieldProps) => ( +