From e8451627bda8cad063eb2b085a00f1d62fc157a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sedat=20=C3=96ZT=C3=9CRK?= <76204082+iamsedatozturk@users.noreply.github.com> Date: Fri, 31 Oct 2025 11:30:04 +0300 Subject: [PATCH] Developer Kit Custom Entity --- .../DeveloperKit/CustomEntityDto.cs | 2 + .../DeveloperKit/CustomEntityAppService.cs | 30 +- .../Seeds/LanguagesData.json | 12 +- .../Seeds/ListFormSeeder.cs | 2 +- .../Tenant/Administration/CustomEntity.cs | 1 + ....cs => 20251031075637_Initial.Designer.cs} | 5 +- ...4_Initial.cs => 20251031075637_Initial.cs} | 1 + .../PlatformDbContextModelSnapshot.cs | 3 + .../developerKit/ComponentEditor.tsx | 357 +++++----- .../components/developerKit/EntityEditor.tsx | 642 +++++++++--------- .../components/developerKit/EntityManager.tsx | 126 ++-- ui/src/proxy/developerKit/models.ts | 2 + 12 files changed, 588 insertions(+), 595 deletions(-) rename api/src/Kurs.Platform.EntityFrameworkCore/Migrations/{20251030134034_Initial.Designer.cs => 20251031075637_Initial.Designer.cs} (99%) rename api/src/Kurs.Platform.EntityFrameworkCore/Migrations/{20251030134034_Initial.cs => 20251031075637_Initial.cs} (99%) diff --git a/api/src/Kurs.Platform.Application.Contracts/DeveloperKit/CustomEntityDto.cs b/api/src/Kurs.Platform.Application.Contracts/DeveloperKit/CustomEntityDto.cs index f1e5597e..586a08ac 100644 --- a/api/src/Kurs.Platform.Application.Contracts/DeveloperKit/CustomEntityDto.cs +++ b/api/src/Kurs.Platform.Application.Contracts/DeveloperKit/CustomEntityDto.cs @@ -43,6 +43,7 @@ public class EntityFieldDto : FullAuditedEntityDto public bool IsUnique { get; set; } public string? DefaultValue { get; set; } public string? Description { get; set; } + public int DisplayOrder { get; set; } = 0; } public class CreateUpdateCustomEntityFieldDto @@ -56,4 +57,5 @@ public class CreateUpdateCustomEntityFieldDto public bool IsUnique { get; set; } public string? DefaultValue { get; set; } public string? Description { get; set; } + public int DisplayOrder { get; set; } = 0; } diff --git a/api/src/Kurs.Platform.Application/DeveloperKit/CustomEntityAppService.cs b/api/src/Kurs.Platform.Application/DeveloperKit/CustomEntityAppService.cs index 8b762964..1149adb6 100644 --- a/api/src/Kurs.Platform.Application/DeveloperKit/CustomEntityAppService.cs +++ b/api/src/Kurs.Platform.Application/DeveloperKit/CustomEntityAppService.cs @@ -35,12 +35,13 @@ public class CustomEntityAppService : CrudAppService< _repository = repository; _migrationRepository = migrationRepository; _endpointRepository = endpointRepository; + _fieldRepository = fieldRepository; } public override async Task> GetListAsync(PagedAndSortedResultRequestDto input) { var query = await _repository.GetQueryableAsync(); - var fullQuery = query.Include(x => x.Fields); + var fullQuery = query.Include(x => x.Fields.OrderBy(f => f.DisplayOrder)); var totalCount = await fullQuery.CountAsync(); @@ -59,7 +60,7 @@ public class CustomEntityAppService : CrudAppService< { var query = await _repository.GetQueryableAsync(); var entity = await query - .Include(x => x.Fields) + .Include(x => x.Fields.OrderBy(f => f.DisplayOrder)) .FirstOrDefaultAsync(x => x.Id == id); if (entity == null) @@ -72,7 +73,7 @@ public class CustomEntityAppService : CrudAppService< { var query = await _repository.GetQueryableAsync(); var entities = await query - .Include(x => x.Fields) + .Include(x => x.Fields.OrderBy(f => f.DisplayOrder)) .Where(x => x.IsActive) .ToListAsync(); @@ -83,7 +84,7 @@ public class CustomEntityAppService : CrudAppService< { var query = await _repository.GetQueryableAsync(); var entity = await query - .Include(x => x.Fields) + .Include(x => x.Fields.OrderBy(f => f.DisplayOrder)) .FirstOrDefaultAsync(x => x.Id == id); if (entity == null) @@ -115,13 +116,14 @@ public class CustomEntityAppService : CrudAppService< var updatedFields = new List(); - foreach (var dtoField in input.Fields) + for (int i = 0; i < input.Fields.Count; i++) { + var dtoField = input.Fields[i]; CustomEntityField? existingField = null; if (dtoField.Id.HasValue) { - existingField = entity.Fields.FirstOrDefault(f => f.Id == dtoField.Id.Value); + existingField = entity.Fields?.FirstOrDefault(f => f.Id == dtoField.Id.Value); } if (existingField != null) @@ -133,6 +135,7 @@ public class CustomEntityAppService : CrudAppService< existingField.IsUnique = dtoField.IsUnique; existingField.DefaultValue = dtoField.DefaultValue; existingField.Description = dtoField.Description; + existingField.DisplayOrder = dtoField.DisplayOrder; updatedFields.Add(existingField); } @@ -147,7 +150,8 @@ public class CustomEntityAppService : CrudAppService< MaxLength = dtoField.MaxLength, IsUnique = dtoField.IsUnique, DefaultValue = dtoField.DefaultValue, - Description = dtoField.Description + Description = dtoField.Description, + DisplayOrder = dtoField.DisplayOrder }; await _fieldRepository.InsertAsync(newField); @@ -156,9 +160,9 @@ public class CustomEntityAppService : CrudAppService< } // Silinecek alanlar - var toRemove = entity.Fields + var toRemove = entity.Fields? .Where(existing => updatedFields.All(f => f.Id != existing.Id)) - .ToList(); + .ToList() ?? []; if (toRemove.Any()) { @@ -185,9 +189,10 @@ public class CustomEntityAppService : CrudAppService< MigrationStatus = "pending" }; - // Fields ekle - foreach (var fieldDto in input.Fields) + // Fields ekle - sıralama ile + for (int i = 0; i < input.Fields.Count; i++) { + var fieldDto = input.Fields[i]; var field = new CustomEntityField { EntityId = entity.Id, @@ -197,7 +202,8 @@ public class CustomEntityAppService : CrudAppService< MaxLength = fieldDto.MaxLength, IsUnique = fieldDto.IsUnique, DefaultValue = fieldDto.DefaultValue, - Description = fieldDto.Description + Description = fieldDto.Description, + DisplayOrder = fieldDto.DisplayOrder }; entity.Fields.Add(field); } diff --git a/api/src/Kurs.Platform.DbMigrator/Seeds/LanguagesData.json b/api/src/Kurs.Platform.DbMigrator/Seeds/LanguagesData.json index 5237cbf0..6a941305 100644 --- a/api/src/Kurs.Platform.DbMigrator/Seeds/LanguagesData.json +++ b/api/src/Kurs.Platform.DbMigrator/Seeds/LanguagesData.json @@ -10168,7 +10168,7 @@ { "resourceName": "Platform", "key": "App.DeveloperKit.Entity.EndpointStatus", - "en": "Endpoint Status:", + "en": "Crud Endpoint Status:", "tr": "Uç Nokta Durumu:" }, { @@ -10681,17 +10681,11 @@ "en": "Active", "tr": "Aktif" }, - { - "resourceName": "Platform", - "key": "App.DeveloperKit.ComponentEditor.Active", - "en": "Active", - "tr": "Aktif" - }, { "resourceName": "Platform", "key": "App.DeveloperKit.ComponentEditor.Save", - "en": "Save Component", - "tr": "Bileşeni Kaydet" + "en": "Save", + "tr": "Kaydet" }, { "resourceName": "Platform", diff --git a/api/src/Kurs.Platform.DbMigrator/Seeds/ListFormSeeder.cs b/api/src/Kurs.Platform.DbMigrator/Seeds/ListFormSeeder.cs index 179ee4c0..8ad476f0 100644 --- a/api/src/Kurs.Platform.DbMigrator/Seeds/ListFormSeeder.cs +++ b/api/src/Kurs.Platform.DbMigrator/Seeds/ListFormSeeder.cs @@ -44042,7 +44042,7 @@ public class ListFormSeeder : IDataSeedContributor, ITransientDependency R = AppCodes.SupplyChain.MaterialGroup, U = AppCodes.SupplyChain.MaterialGroup + ".Update", E = true, - I = true, + I = false, Deny = false }), PivotSettingsJson = JsonSerializer.Serialize(new ListFormFieldPivotSettingsDto diff --git a/api/src/Kurs.Platform.Domain/Entities/Tenant/Administration/CustomEntity.cs b/api/src/Kurs.Platform.Domain/Entities/Tenant/Administration/CustomEntity.cs index c52d32ff..2f2fd40a 100644 --- a/api/src/Kurs.Platform.Domain/Entities/Tenant/Administration/CustomEntity.cs +++ b/api/src/Kurs.Platform.Domain/Entities/Tenant/Administration/CustomEntity.cs @@ -38,6 +38,7 @@ public class CustomEntityField : FullAuditedEntity public bool IsUnique { get; set; } public string? DefaultValue { get; set; } public string? Description { get; set; } + public int DisplayOrder { get; set; } = 0; public virtual CustomEntity Entity { get; set; } = null!; diff --git a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251030134034_Initial.Designer.cs b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251031075637_Initial.Designer.cs similarity index 99% rename from api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251030134034_Initial.Designer.cs rename to api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251031075637_Initial.Designer.cs index 52409666..7619f7ea 100644 --- a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251030134034_Initial.Designer.cs +++ b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251031075637_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace Kurs.Platform.Migrations { [DbContext(typeof(PlatformDbContext))] - [Migration("20251030134034_Initial")] + [Migration("20251031075637_Initial")] partial class Initial { /// @@ -3001,6 +3001,9 @@ namespace Kurs.Platform.Migrations .HasMaxLength(500) .HasColumnType("nvarchar(500)"); + b.Property("DisplayOrder") + .HasColumnType("int"); + b.Property("EntityId") .HasColumnType("uniqueidentifier"); diff --git a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251030134034_Initial.cs b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251031075637_Initial.cs similarity index 99% rename from api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251030134034_Initial.cs rename to api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251031075637_Initial.cs index 5a190f0d..90966b70 100644 --- a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251030134034_Initial.cs +++ b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20251031075637_Initial.cs @@ -3459,6 +3459,7 @@ namespace Kurs.Platform.Migrations IsUnique = table.Column(type: "bit", nullable: false), DefaultValue = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), Description = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: true), + DisplayOrder = table.Column(type: "int", nullable: false), CreationTime = table.Column(type: "datetime2", nullable: false), CreatorId = table.Column(type: "uniqueidentifier", nullable: true), LastModificationTime = table.Column(type: "datetime2", nullable: true), diff --git a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs index c7cc445d..a547aab1 100644 --- a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs +++ b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs @@ -2998,6 +2998,9 @@ namespace Kurs.Platform.Migrations .HasMaxLength(500) .HasColumnType("nvarchar(500)"); + b.Property("DisplayOrder") + .HasColumnType("int"); + b.Property("EntityId") .HasColumnType("uniqueidentifier"); diff --git a/ui/src/components/developerKit/ComponentEditor.tsx b/ui/src/components/developerKit/ComponentEditor.tsx index 9fa365cf..59714746 100644 --- a/ui/src/components/developerKit/ComponentEditor.tsx +++ b/ui/src/components/developerKit/ComponentEditor.tsx @@ -17,7 +17,7 @@ import { ROUTES_ENUM } from '@/routes/route.constant' import { useLocalization } from '@/utils/hooks/useLocalization' import { Formik, Form, Field, FieldProps } from 'formik' import * as Yup from 'yup' -import { FormItem } from '@/components/ui' +import { Checkbox, FormContainer, FormItem, Input } from '@/components/ui' // Error tipini tanımla interface ValidationError { @@ -180,207 +180,188 @@ const ComponentEditor: React.FC = () => { } return ( -
-
- - {({ values, touched, errors, isSubmitting, setFieldValue, submitForm, isValid }) => ( - <> - {/* Enhanced Header */} -
-
-
-
- -
-
-
- -
-
-

- {isEditing - ? `${translate('::App.DeveloperKit.ComponentEditor.Title.Edit')} - ${values.name || initialValues.name || 'Component'}` - : translate('::App.DeveloperKit.ComponentEditor.Title.Create')} -

-

- {isEditing - ? 'Modify your React component' - : 'Create a new React component'} -

-
-
+ + {({ values, touched, errors, isSubmitting, setFieldValue, submitForm, isValid }) => ( + <> + {/* Enhanced Header */} +
+
+
+
+ +
+
+
+
- - {/* Save Button in Header */} -
- +
+

+ {isEditing + ? `${translate('::App.DeveloperKit.ComponentEditor.Title.Edit')} - ${values.name || initialValues.name || 'Component'}` + : translate('::App.DeveloperKit.ComponentEditor.Title.Create')} +

+

+ {isEditing ? 'Modify your React component' : 'Create a new React component'} +

+ + {/* Save Button in Header */} +
+ +
+
+
-
- {/* Left Side - Component Settings */} -
-
-
-
- -
-

Component Settings

-
- -
- - - - - - - - - - - {({ field }: FieldProps) => ( - - setFieldValue( - 'dependencies', - e.target.value - .split(',') - .map((s) => s.trim()) - .filter(Boolean), - ) - } - className="w-full px-2 py-1.5 border border-slate-300 rounded focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all duration-200 text-sm bg-slate-50 focus:bg-white" - placeholder="MyComponent, AnotherComponent, etc." - /> - )} - - - - -
- - -
-
-
+ + {/* Left Side - Component Settings */} +
+
+
+
+
+

Component Settings

- {/* Right Side - Preview and Validation */} -
- {/* Validation Errors */} - {validationErrors.length > 0 && ( -
-
-
- -
-
-

- Validation Issues -

-

- {validationErrors.length} issue - {validationErrors.length !== 1 ? 's' : ''} found in your code -

-
- {validationErrors.slice(0, 5).map((error, index) => ( -
-
- - Line {error.startLineNumber} - - {error.message} -
-
- ))} - {validationErrors.length > 5 && ( -
- ... and {validationErrors.length - 5} more issue - {validationErrors.length - 5 !== 1 ? 's' : ''} -
- )} + + + + + + + + + + + + {({ field }: FieldProps) => ( + + setFieldValue( + 'dependencies', + e.target.value + .split(',') + .map((s) => s.trim()) + .filter(Boolean), + ) + } + placeholder="MyComponent, AnotherComponent, etc." + /> + )} + + + + + + + +
+
+ + {/* Right Side - Preview and Validation */} +
+ {/* Validation Errors */} + {validationErrors.length > 0 && ( +
+
+
+ +
+
+

+ Validation Issues +

+

+ {validationErrors.length} issue + {validationErrors.length !== 1 ? 's' : ''} found in your code +

+
+ {validationErrors.slice(0, 5).map((error, index) => ( +
+
+ + Line {error.startLineNumber} + + {error.message} +
-
+ ))} + {validationErrors.length > 5 && ( +
+ ... and {validationErrors.length - 5} more issue + {validationErrors.length - 5 !== 1 ? 's' : ''} +
+ )}
- )} - - {/* Component Preview */} -
-
-
- -
-

Preview

-
-
- - - )} - -
-
+ )} + + {/* Component Preview */} +
+
+
+ +
+

Preview

+
+ +
+
+ + + )} + ) } diff --git a/ui/src/components/developerKit/EntityEditor.tsx b/ui/src/components/developerKit/EntityEditor.tsx index 87a29e3b..10428b1a 100644 --- a/ui/src/components/developerKit/EntityEditor.tsx +++ b/ui/src/components/developerKit/EntityEditor.tsx @@ -11,12 +11,12 @@ import { FaTable, FaColumns, } from 'react-icons/fa' -import { CreateUpdateCustomEntityFieldDto, CustomEntityField } from '@/proxy/developerKit/models' +import { CustomEntityField } from '@/proxy/developerKit/models' import { ROUTES_ENUM } from '@/routes/route.constant' import { useLocalization } from '@/utils/hooks/useLocalization' import { Formik, Form, Field, FieldProps, FieldArray } from 'formik' import * as Yup from 'yup' -import { FormItem, Input, Select, Checkbox } from '@/components/ui' +import { FormItem, Input, Select, Checkbox, FormContainer } from '@/components/ui' import { SelectBoxOption } from '@/shared/types' // Validation schema @@ -33,8 +33,9 @@ const validationSchema = Yup.object({ isRequired: Yup.boolean(), maxLength: Yup.number().nullable(), isUnique: Yup.boolean(), - defaultValue: Yup.string(), - description: Yup.string(), + defaultValue: Yup.string().notRequired(), + description: Yup.string().notRequired(), + displayOrder: Yup.number().required(), }), ) .min(1, 'At least one field is required'), @@ -67,6 +68,7 @@ const EntityEditor: React.FC = () => { isRequired: true, maxLength: 100, description: 'Entity name', + displayOrder: 1, }, ] as CustomEntityField[], isActive: true, @@ -83,12 +85,18 @@ const EntityEditor: React.FC = () => { if (isEditing && id) { const entity = getEntity(id) if (entity) { + // Ensure fields are sorted by displayOrder and normalized to sequential values + const sortedFields = (entity.fields || []) + .slice() + .sort((a, b) => (a.displayOrder ?? 0) - (b.displayOrder ?? 0)) + .map((f, idx) => ({ ...f, displayOrder: f.displayOrder ?? idx + 1 })) + setInitialValues({ name: entity.name, displayName: entity.displayName, tableName: entity.tableName, description: entity.description || '', - fields: entity.fields, + fields: sortedFields, isActive: entity.isActive, hasAuditFields: entity.hasAuditFields, hasSoftDelete: entity.hasSoftDelete, @@ -100,7 +108,8 @@ const EntityEditor: React.FC = () => { const handleSubmit = async (values: typeof initialValues, { setSubmitting }: any) => { try { const sanitizedFields = values.fields.map((f) => { - const sanitized: CreateUpdateCustomEntityFieldDto = { + // send both `displayOrder` (frontend proxy) and `order` (backend DTO) to be safe + const sanitized: any = { ...(f.id && isEditing ? { id: f.id } : {}), name: f.name.trim(), type: f.type, @@ -109,6 +118,8 @@ const EntityEditor: React.FC = () => { isUnique: f.isUnique || false, defaultValue: f.defaultValue, description: f.description, + displayOrder: f.displayOrder, + order: f.displayOrder, } return sanitized @@ -150,171 +161,164 @@ const EntityEditor: React.FC = () => { ] return ( -
-
- - {({ values, touched, errors, isSubmitting, setFieldValue, submitForm, isValid }) => ( - <> - {/* Enhanced Header */} -
-
-
-
- -
-
-
- -
-
-

- {isEditing - ? `${translate('::App.DeveloperKit.EntityEditor.Title.Edit')} - ${values.name || initialValues.name || 'Entity'}` - : translate('::App.DeveloperKit.EntityEditor.Title.Create')} -

-
-
+ + {({ values, touched, errors, isSubmitting, setFieldValue, submitForm, isValid }) => ( + <> + {/* Enhanced Header */} +
+
+
+
+ +
+
+
+
- - {/* Save Button in Header */} -
- +
+

+ {isEditing + ? `${translate('::App.DeveloperKit.EntityEditor.Title.Edit')} - ${values.name || initialValues.name || 'Entity'}` + : translate('::App.DeveloperKit.EntityEditor.Title.Create')} +

+

+ {isEditing ? 'Modify your entity' : 'Create a new entity'} +

+ + {/* Save Button in Header */} +
+ +
+
+
-
- {/* Basic Entity Information */} -
-
-
- -
-

Entity Settings

-
- -
- - - {({ field }: FieldProps) => ( - { - field.onBlur(e) - if (!values.tableName) { - setFieldValue('tableName', values.name + 's') - } - if (!values.displayName) { - setFieldValue('displayName', values.name) - } - }} - disabled={isMigrationApplied} - placeholder="e.g., Product, User, Order" - className="px-2 py-1.5 bg-slate-50 focus:bg-white transition-all duration-200 text-sm h-7" - /> - )} - - - - - - - - - - - - - - -
- -
-
- - -
- -
- - -
- -
- - -
+ + {/* Basic Entity Information */} +
+
+
+
+
+

Entity Settings

- {/* Fields Section */} -
+ + + + {({ field }: FieldProps) => ( + { + field.onBlur(e) + if (!values.tableName) { + setFieldValue('tableName', values.name + 's') + } + if (!values.displayName) { + setFieldValue('displayName', values.name) + } + }} + disabled={isMigrationApplied} + placeholder="e.g., Product, User, Order" + className="px-2 py-1.5 bg-slate-50 focus:bg-white transition-all duration-200 text-sm h-7" + /> + )} + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + {/* Fields Section */} +
+
+ {({ push, remove }) => ( <>
-
- +
+

{translate('::App.DeveloperKit.EntityEditor.Fields')} @@ -330,6 +334,8 @@ const EntityEditor: React.FC = () => { type: 'string', isRequired: false, description: '', + // Assign next sequential displayOrder + displayOrder: (values.fields?.length ?? 0) + 1, }) } className="flex items-center gap-1 bg-gradient-to-r from-blue-600 to-blue-700 text-white px-2 py-1.5 rounded hover:from-blue-700 hover:to-blue-800 transition-all duration-200 text-sm" @@ -339,197 +345,191 @@ const EntityEditor: React.FC = () => {

-
- {values.fields.map((field, index) => ( -
-
- - - + {values.fields.map((field, index) => ( +
+
+ + + - - - {({ field, form }: FieldProps) => ( - ({ + value: type.value, + label: type.label, + }))} + value={fieldTypes + .map((type) => ({ value: type.value, label: type.label })) + .filter((option) => option.value === field.value)} + onChange={(option) => + form.setFieldValue(field.name, option?.value) + } /> - - )} + )} + + + + + + + {field.type === 'string' && ( -
+ )} -
-
- - - -
+ + + -
-
- - -
+ + + -
- - -
+ + + - -
-
+
- ))} +
+ ))} - {values.fields.length === 0 && ( -
- -

- {translate('::App.DeveloperKit.EntityEditor.NoFields')} -

-

- {translate('::App.DeveloperKit.EntityEditor.NoFieldsDescription')} -

-
- )} -
+ {values.fields.length === 0 && ( +
+ +

+ {translate('::App.DeveloperKit.EntityEditor.NoFields')} +

+

+ {translate('::App.DeveloperKit.EntityEditor.NoFieldsDescription')} +

+
+ )} )} -
- - - )} - -
-
+
+
+
+ + + )} + ) } diff --git a/ui/src/components/developerKit/EntityManager.tsx b/ui/src/components/developerKit/EntityManager.tsx index b5ae088b..93004bea 100644 --- a/ui/src/components/developerKit/EntityManager.tsx +++ b/ui/src/components/developerKit/EntityManager.tsx @@ -103,7 +103,7 @@ const EntityManager: React.FC = () => {
{/* Stats Cards */} -
+
@@ -162,94 +162,94 @@ const EntityManager: React.FC = () => {
{/* Filters */} -
-
-
- - setSearchTerm(e.target.value)} - className="w-full pl-10 pr-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-emerald-500 focus:border-transparent transition-colors" - /> -
-
-
- - -
+
+
+ + setSearchTerm(e.target.value)} + className="w-full pl-10 pr-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-emerald-500 focus:border-transparent transition-colors" + /> +
+
+
+ +
{/* Entities List */} {filteredEntities.length > 0 ? ( -
+
{filteredEntities.map((entity) => { return (
-
+
-
-
- +
+ {/* Sol taraf */} +
+
+ +
+
+

+ {entity.displayName} +

+

+ {translate('::App.DeveloperKit.Entity.TableLabel')}:{' '} + {entity.tableName} +

+
-
-

- {entity.displayName} -

-

- {translate('::App.DeveloperKit.Entity.TableLabel')}: {entity.tableName} -

+ + {/* Sağ taraf */} +
+
+ + + {translate('::App.DeveloperKit.Entity.Updated')}:{' '} + {entity.lastModificationTime + ? new Date(entity.lastModificationTime).toLocaleDateString() + : 'Never'} + +
+
+ + + {entity.fields.length} {translate('::App.DeveloperKit.Entity.Fields')} + +
+ {entity.description && (

{entity.description}

)} -
-
- - - {translate('::App.DeveloperKit.Entity.Updated')}:{' '} - {entity.lastModificationTime - ? new Date(entity.lastModificationTime).toLocaleDateString() - : 'Never'} - -
-
- - - {entity.fields.length} {translate('::App.DeveloperKit.Entity.Fields')} - -
-
{/* Entity Fields Preview */}
-

- {translate('::App.DeveloperKit.Entity.FieldLabel')} -

-
+
{entity.fields.slice(0, 4).map((field) => (