Wizard Problemleri Giderildi
This commit is contained in:
parent
319afbcb13
commit
ab6a33c340
23 changed files with 1320 additions and 343 deletions
|
|
@ -41,6 +41,7 @@ public class ListFormWizardDto
|
|||
|
||||
public string PermissionGroupName { get; set; }
|
||||
public string MenuParentCode { get; set; }
|
||||
public string MenuParentShortName { get; set; }
|
||||
public string MenuParentIcon { get; set; }
|
||||
public string MenuIcon { get; set; }
|
||||
public string DataSourceCode { get; set; }
|
||||
|
|
|
|||
|
|
@ -180,11 +180,18 @@ public class ListFormWizardAppService(
|
|||
Code = input.MenuParentCode,
|
||||
DisplayName = input.MenuParentCode,
|
||||
IsDisabled = false,
|
||||
ShortName = input.MenuParentShortName?.Trim(),
|
||||
Icon = menuParentIcon,
|
||||
Order = maxRootOrder + 1,
|
||||
}, autoSave: false);
|
||||
inserted.MenuCodes.Add(input.MenuParentCode);
|
||||
}
|
||||
else if (string.IsNullOrWhiteSpace(menuParent.ShortName) &&
|
||||
!string.IsNullOrWhiteSpace(input.MenuParentShortName))
|
||||
{
|
||||
menuParent.ShortName = input.MenuParentShortName.Trim();
|
||||
await repoMenu.UpdateAsync(menuParent, autoSave: false);
|
||||
}
|
||||
|
||||
//Menu
|
||||
var maxChildOrder = menuQueryable.Where(a => a.ParentCode == menuParent.Code).Select(a => (int?)a.Order).Max() ?? 0;
|
||||
|
|
@ -301,8 +308,8 @@ public class ListFormWizardAppService(
|
|||
ColumnOptionJson = WizardConsts.DefaultColumnOptionJson(),
|
||||
PermissionJson = WizardConsts.DefaultPermissionJson(code),
|
||||
DeleteCommand = isDeleted ? WizardConsts.DefaultDeleteCommand(input.SelectCommand) : null,
|
||||
DeleteFieldsDefaultValueJson = isDeleted ? WizardConsts.DefaultDeleteFieldsDefaultValueJson(input.KeyFieldDbSourceType) : WizardConsts.DefaultFieldsJsonOnlyId(input.KeyFieldDbSourceType),
|
||||
InsertFieldsDefaultValueJson = isCreated ? WizardConsts.DefaultInsertFieldsDefaultValueJson(input.KeyFieldDbSourceType) : WizardConsts.DefaultFieldsJsonOnlyId(input.KeyFieldDbSourceType),
|
||||
DeleteFieldsDefaultValueJson = isDeleted ? WizardConsts.DefaultDeleteFieldsDefaultValueJson(input.KeyFieldDbSourceType) : WizardConsts.DefaultDeleteFieldsJsonOnlyId(input.KeyFieldDbSourceType),
|
||||
InsertFieldsDefaultValueJson = isCreated ? WizardConsts.DefaultInsertFieldsDefaultValueJson(input.KeyFieldDbSourceType) : WizardConsts.DefaultInsertFieldsJsonOnlyId(input.KeyFieldDbSourceType),
|
||||
PagerOptionJson = WizardConsts.DefaultPagerOptionJson,
|
||||
EditingOptionJson = WizardConsts.DefaultEditingOptionJson(titleLangKey, 600, 500, input.AllowDeleting, input.AllowAdding, input.AllowUpdating, input.ConfirmDelete, false, input.AllowDetail),
|
||||
EditingFormJson = editingFormDtos.Count > 0 ? JsonSerializer.Serialize(editingFormDtos) : null,
|
||||
|
|
@ -382,9 +389,11 @@ public class ListFormWizardAppService(
|
|||
Width = 0,
|
||||
ListOrderNo = fieldOrder,
|
||||
EditGroupOrderNo = item.IncludeInEditingForm ? editGroupOrder : null,
|
||||
EditOrderNo = item.IncludeInEditingForm && item.FieldName != input.KeyFieldName ? editOrder : null,
|
||||
EditorType2 = item.IncludeInEditingForm ? item.EditorType : null,
|
||||
ColSpan = item.IncludeInEditingForm ? item.ColSpan : null,
|
||||
EditOrderNo = item.IncludeInEditingForm && item.FieldName != input.KeyFieldName
|
||||
? editOrder
|
||||
: null,
|
||||
EditorType2 = item.EditorType,
|
||||
ColSpan = item.ColSpan,
|
||||
EditorOptions = string.IsNullOrWhiteSpace(item.EditorOptions) ? null : item.EditorOptions,
|
||||
EditorScript = string.IsNullOrWhiteSpace(item.EditorScript) ? null : item.EditorScript,
|
||||
SourceDbType = item.DbSourceType,
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ using Volo.Abp.PermissionManagement;
|
|||
using Volo.Abp.TenantManagement;
|
||||
using static Sozsoft.Platform.Data.Seeds.SeedConsts;
|
||||
using Sozsoft.Languages;
|
||||
using Sozsoft.Languages.Languages;
|
||||
using Sozsoft.Platform.ListForms;
|
||||
|
||||
namespace Sozsoft.Platform.Menus;
|
||||
|
|
@ -131,6 +132,30 @@ public class MenuAppService : CrudAppService<
|
|||
.ToList();
|
||||
|
||||
entityDtos = await base.MapToGetListOutputDtosAsync(entities);
|
||||
|
||||
var languageKeys = entityDtos
|
||||
.Select(item => string.IsNullOrWhiteSpace(item.DisplayName) ? item.Code : item.DisplayName)
|
||||
.Where(key => !string.IsNullOrWhiteSpace(key))
|
||||
.Distinct()
|
||||
.ToList();
|
||||
var languageTexts = await _repositoryText.GetListAsync(text =>
|
||||
text.ResourceName == PlatformConsts.AppName &&
|
||||
languageKeys.Contains(text.Key) &&
|
||||
(text.CultureName == PlatformConsts.DefaultLanguage ||
|
||||
text.CultureName == LanguageCodes.Tr));
|
||||
|
||||
foreach (var menu in entityDtos)
|
||||
{
|
||||
var languageKey = string.IsNullOrWhiteSpace(menu.DisplayName)
|
||||
? menu.Code
|
||||
: menu.DisplayName;
|
||||
menu.MenuTextEn = languageTexts.FirstOrDefault(text =>
|
||||
text.Key == languageKey &&
|
||||
text.CultureName == PlatformConsts.DefaultLanguage)?.Value;
|
||||
menu.MenuTextTr = languageTexts.FirstOrDefault(text =>
|
||||
text.Key == languageKey &&
|
||||
text.CultureName == LanguageCodes.Tr)?.Value;
|
||||
}
|
||||
}
|
||||
|
||||
return new PagedResultDto<MenuDto>(
|
||||
|
|
|
|||
|
|
@ -19467,7 +19467,7 @@
|
|||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormFieldEdit.TodoStatusOrderPlaceholder",
|
||||
"en": "Inbox, Today, This Week, This Month, Later, Done",
|
||||
"en": "Backlog, Ready to Start, In Progress, Code Review, Testing, Staging",
|
||||
"tr": "Gelen Kutusu, Bugün, Bu Hafta, Bu Ay, Daha Sonra, Tamamlandı"
|
||||
},
|
||||
{
|
||||
|
|
@ -19476,6 +19476,18 @@
|
|||
"en": "Allow cards to be dragged between columns",
|
||||
"tr": "Kartları kolonlar arasında sürüklemeye izin ver"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormFieldEdit.TodoRequiredFields",
|
||||
"en": "Title field and column / status field are required.",
|
||||
"tr": "Başlık alanı ve kolon / durum alanı zorunludur."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormFieldEdit.TodoDisabledInListSettings",
|
||||
"en": "Todo view is disabled in the list settings. You can skip this step or enable the Todo view in the previous steps.",
|
||||
"tr": "Todo görünümü liste ayarlarında kapalı. Bu adımı atlayabilir veya önceki adımlardan Todo görünümünü etkinleştirebilirsiniz."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.Uncategorized",
|
||||
|
|
@ -19743,13 +19755,13 @@
|
|||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.NewColumn",
|
||||
"en": "New Kanban column",
|
||||
"en": "New Kanban",
|
||||
"tr": "Yeni kanban"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.AddNewColumn",
|
||||
"en": "Add a new Kanban column",
|
||||
"en": "Add a new Kanban",
|
||||
"tr": "Yeni kanban ekle"
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
IF OBJECT_ID(N'[dbo].[Pro_T_Approval]', 'U') IS NULL
|
||||
BEGIN
|
||||
CREATE TABLE [dbo].[Pro_T_Approval]
|
||||
(
|
||||
[Id] uniqueidentifier NOT NULL DEFAULT NEWID(),
|
||||
[ApprovalUserName] nvarchar(256) NULL,
|
||||
[ApprovalStatus] nvarchar(50) NULL,
|
||||
[ApprovalDate] datetime NULL,
|
||||
[ApprovalDescription] nvarchar(200) NULL,
|
||||
[TenantId] uniqueidentifier NULL,
|
||||
[Title] nvarchar(100) NULL,
|
||||
CONSTRAINT [PK_Pro_T_Approval] PRIMARY KEY NONCLUSTERED
|
||||
(
|
||||
[Id] ASC
|
||||
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
|
||||
) ON [PRIMARY]
|
||||
END
|
||||
GO
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
IF OBJECT_ID(N'[dbo].[Pro_T_Todo]', 'U') IS NULL
|
||||
BEGIN
|
||||
CREATE TABLE [dbo].[Pro_T_Todo]
|
||||
(
|
||||
[Id] uniqueidentifier NOT NULL DEFAULT NEWID(),
|
||||
[Title] nvarchar(300) NOT NULL,
|
||||
[Status] nvarchar(50) NOT NULL DEFAULT N'Inbox',
|
||||
[Description] nvarchar(MAX) NULL,
|
||||
[DueDate] datetime2 NULL,
|
||||
[Tags] nvarchar(500) NULL,
|
||||
[Assignees] nvarchar(500) NULL,
|
||||
[Priority] nvarchar(50) NULL,
|
||||
[Completed] bit NOT NULL DEFAULT 0,
|
||||
[SortOrder] int NOT NULL DEFAULT 0,
|
||||
[TenantId] uniqueidentifier NULL,
|
||||
CONSTRAINT [PK_Table] PRIMARY KEY NONCLUSTERED
|
||||
(
|
||||
[Id] ASC
|
||||
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
|
||||
) ON [PRIMARY]
|
||||
END
|
||||
GO
|
||||
|
|
@ -0,0 +1,281 @@
|
|||
{
|
||||
"Wizard": {
|
||||
"WizardName": "Approval",
|
||||
"ListFormCode": "App.Wizard.Approval",
|
||||
"MenuCode": "App.Wizard.Approval",
|
||||
"IsTenant": true,
|
||||
"IsBranch": false,
|
||||
"IsOrganizationUnit": false,
|
||||
"AllowAdding": true,
|
||||
"AllowUpdating": true,
|
||||
"AllowDeleting": true,
|
||||
"AllowDetail": false,
|
||||
"ConfirmDelete": true,
|
||||
"DefaultLayout": "grid",
|
||||
"Grid": true,
|
||||
"Card": true,
|
||||
"Pivot": true,
|
||||
"Tree": true,
|
||||
"Chart": true,
|
||||
"Gantt": true,
|
||||
"Scheduler": true,
|
||||
"Todo": false,
|
||||
"LanguageTextMenuEn": "Approval",
|
||||
"LanguageTextMenuTr": "Onaylama",
|
||||
"LanguageTextTitleEn": "Approval",
|
||||
"LanguageTextTitleTr": "Onaylama",
|
||||
"LanguageTextDescEn": "Approval",
|
||||
"LanguageTextDescTr": "Onaylama",
|
||||
"LanguageTextMenuParentEn": "Project",
|
||||
"LanguageTextMenuParentTr": "Project",
|
||||
"PermissionGroupName": "App.Wizard.Project",
|
||||
"MenuParentCode": "App.Wizard.Project",
|
||||
"MenuParentShortName": "Pro",
|
||||
"MenuParentIcon": "FcVideoProjector",
|
||||
"MenuIcon": "FcApproval",
|
||||
"DataSourceCode": "Default",
|
||||
"DataSourceConnectionString": "",
|
||||
"SelectCommandType": 1,
|
||||
"SelectCommand": "Pro_T_Approval",
|
||||
"KeyFieldName": "Id",
|
||||
"KeyFieldDbSourceType": 9,
|
||||
"TreeKeyExpr": "",
|
||||
"TreeParentIdExpr": "",
|
||||
"TreeAutoExpandAll": false,
|
||||
"GanttKeyExpr": "",
|
||||
"GanttParentIdExpr": "",
|
||||
"GanttAutoExpandAll": false,
|
||||
"GanttTitleExpr": "",
|
||||
"GanttStartExpr": "",
|
||||
"GanttEndExpr": "",
|
||||
"GanttProgressExpr": "",
|
||||
"SchedulerTextExpr": "",
|
||||
"SchedulerStartDateExpr": "",
|
||||
"SchedulerEndDateExpr": "",
|
||||
"TodoTitleExpr": "",
|
||||
"TodoStatusExpr": "",
|
||||
"TodoDescriptionExpr": "",
|
||||
"TodoDueDateExpr": "",
|
||||
"TodoTagExpr": "",
|
||||
"TodoAssigneeExpr": "",
|
||||
"TodoPriorityExpr": "",
|
||||
"TodoCompletedExpr": "",
|
||||
"TodoOrderExpr": "",
|
||||
"TodoStatusOrder": "Backlog, Ready to Start, In Progress, Code Review, Testing, Staging",
|
||||
"TodoAllowDragging": true,
|
||||
"ApprovalUserFieldName": "ApprovalUserName",
|
||||
"ApprovalDateFieldName": "ApprovalDate",
|
||||
"ApprovalStatusFieldName": "ApprovalStatus",
|
||||
"ApprovalDescriptionFieldName": "ApprovalDescription",
|
||||
"ApprovalIsFilterUserName": false,
|
||||
"Criteria": [
|
||||
{
|
||||
"ListFormCode": "App.Wizard.Approval",
|
||||
"Kind": "Start",
|
||||
"Title": "\u0130\u015F Ak\u0131\u015F\u0131 Ba\u015Flat1",
|
||||
"CompareColumn": "Price",
|
||||
"CompareOperator": "\u003E",
|
||||
"CompareValue": 5000,
|
||||
"Approver": "",
|
||||
"NextOnStart": "App.Wizard.Approval-N002",
|
||||
"NextOnTrue": "",
|
||||
"NextOnFalse": "",
|
||||
"NextOnApprove": "",
|
||||
"NextOnReject": "",
|
||||
"PositionX": 46,
|
||||
"PositionY": 46,
|
||||
"CompareOutcomes": [],
|
||||
"Id": "App.Wizard.Approval-N001"
|
||||
},
|
||||
{
|
||||
"ListFormCode": "App.Wizard.Approval",
|
||||
"Kind": "Approval",
|
||||
"Title": "Onay1",
|
||||
"CompareColumn": "Price",
|
||||
"CompareOperator": "\u003E",
|
||||
"CompareValue": 5000,
|
||||
"Approver": "system@sozsoft.com",
|
||||
"NextOnStart": "",
|
||||
"NextOnTrue": "",
|
||||
"NextOnFalse": "",
|
||||
"NextOnApprove": "App.Wizard.Approval-N003",
|
||||
"NextOnReject": "App.Wizard.Approval-N004",
|
||||
"PositionX": 337,
|
||||
"PositionY": 39,
|
||||
"CompareOutcomes": [],
|
||||
"Id": "App.Wizard.Approval-N002"
|
||||
},
|
||||
{
|
||||
"ListFormCode": "App.Wizard.Approval",
|
||||
"Kind": "Inform",
|
||||
"Title": "Bilgilendirme1",
|
||||
"CompareColumn": "Price",
|
||||
"CompareOperator": "\u003E",
|
||||
"CompareValue": 5000,
|
||||
"Approver": "system@sozsoft.com",
|
||||
"NextOnStart": "App.Wizard.Approval-N004",
|
||||
"NextOnTrue": "",
|
||||
"NextOnFalse": "",
|
||||
"NextOnApprove": "",
|
||||
"NextOnReject": "",
|
||||
"PositionX": 538,
|
||||
"PositionY": 324,
|
||||
"CompareOutcomes": [],
|
||||
"Id": "App.Wizard.Approval-N003"
|
||||
},
|
||||
{
|
||||
"ListFormCode": "App.Wizard.Approval",
|
||||
"Kind": "End",
|
||||
"Title": "\u0130\u015F Ak\u0131\u015F\u0131 Bitir1",
|
||||
"CompareColumn": "Price",
|
||||
"CompareOperator": "\u003E",
|
||||
"CompareValue": 5000,
|
||||
"Approver": "",
|
||||
"NextOnStart": "",
|
||||
"NextOnTrue": "",
|
||||
"NextOnFalse": "",
|
||||
"NextOnApprove": "",
|
||||
"NextOnReject": "",
|
||||
"PositionX": 852,
|
||||
"PositionY": 26,
|
||||
"CompareOutcomes": [],
|
||||
"Id": "App.Wizard.Approval-N004"
|
||||
}
|
||||
],
|
||||
"Groups": [
|
||||
{
|
||||
"Caption": "",
|
||||
"ColCount": 1,
|
||||
"Items": [
|
||||
{
|
||||
"FieldName": "Id",
|
||||
"CaptionName": "App.Listform.ListformField.Id",
|
||||
"EditorType": "dxTextBox",
|
||||
"EditorOptions": "",
|
||||
"EditorScript": "",
|
||||
"ColSpan": 1,
|
||||
"IsRequired": true,
|
||||
"IncludeInEditingForm": true,
|
||||
"DbSourceType": 9,
|
||||
"TurkishCaption": "Id",
|
||||
"EnglishCaption": "Id",
|
||||
"LookupDataSourceType": 1,
|
||||
"ValueExpr": "Key",
|
||||
"DisplayExpr": "Name",
|
||||
"LookupQuery": ""
|
||||
},
|
||||
{
|
||||
"FieldName": "ApprovalUserName",
|
||||
"CaptionName": "App.Listform.ListformField.ApprovalUserName",
|
||||
"EditorType": "dxTextBox",
|
||||
"EditorOptions": "",
|
||||
"EditorScript": "",
|
||||
"ColSpan": 1,
|
||||
"IsRequired": false,
|
||||
"IncludeInEditingForm": false,
|
||||
"DbSourceType": 16,
|
||||
"TurkishCaption": "Approval User Name",
|
||||
"EnglishCaption": "Approval User Name",
|
||||
"LookupDataSourceType": 1,
|
||||
"ValueExpr": "Key",
|
||||
"DisplayExpr": "Name",
|
||||
"LookupQuery": ""
|
||||
},
|
||||
{
|
||||
"FieldName": "ApprovalStatus",
|
||||
"CaptionName": "App.Listform.ListformField.ApprovalStatus",
|
||||
"EditorType": "dxTextBox",
|
||||
"EditorOptions": "",
|
||||
"EditorScript": "",
|
||||
"ColSpan": 1,
|
||||
"IsRequired": false,
|
||||
"IncludeInEditingForm": false,
|
||||
"DbSourceType": 16,
|
||||
"TurkishCaption": "Approval Status",
|
||||
"EnglishCaption": "Approval Status",
|
||||
"LookupDataSourceType": 1,
|
||||
"ValueExpr": "Key",
|
||||
"DisplayExpr": "Name",
|
||||
"LookupQuery": ""
|
||||
},
|
||||
{
|
||||
"FieldName": "ApprovalDate",
|
||||
"CaptionName": "App.Listform.ListformField.ApprovalDate",
|
||||
"EditorType": "dxDateBox",
|
||||
"EditorOptions": "",
|
||||
"EditorScript": "",
|
||||
"ColSpan": 1,
|
||||
"IsRequired": false,
|
||||
"IncludeInEditingForm": false,
|
||||
"DbSourceType": 6,
|
||||
"TurkishCaption": "Approval Date",
|
||||
"EnglishCaption": "Approval Date",
|
||||
"LookupDataSourceType": 1,
|
||||
"ValueExpr": "Key",
|
||||
"DisplayExpr": "Name",
|
||||
"LookupQuery": ""
|
||||
},
|
||||
{
|
||||
"FieldName": "ApprovalDescription",
|
||||
"CaptionName": "App.Listform.ListformField.ApprovalDescription",
|
||||
"EditorType": "dxTextBox",
|
||||
"EditorOptions": "",
|
||||
"EditorScript": "",
|
||||
"ColSpan": 1,
|
||||
"IsRequired": false,
|
||||
"IncludeInEditingForm": false,
|
||||
"DbSourceType": 16,
|
||||
"TurkishCaption": "Approval Description",
|
||||
"EnglishCaption": "Approval Description",
|
||||
"LookupDataSourceType": 1,
|
||||
"ValueExpr": "Key",
|
||||
"DisplayExpr": "Name",
|
||||
"LookupQuery": ""
|
||||
},
|
||||
{
|
||||
"FieldName": "Title",
|
||||
"CaptionName": "App.Listform.ListformField.Title",
|
||||
"EditorType": "dxTextBox",
|
||||
"EditorOptions": "",
|
||||
"EditorScript": "",
|
||||
"ColSpan": 1,
|
||||
"IsRequired": false,
|
||||
"IncludeInEditingForm": true,
|
||||
"DbSourceType": 16,
|
||||
"TurkishCaption": "Title",
|
||||
"EnglishCaption": "Title",
|
||||
"LookupDataSourceType": 1,
|
||||
"ValueExpr": "Key",
|
||||
"DisplayExpr": "Name",
|
||||
"LookupQuery": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"SubForms": [],
|
||||
"Widgets": []
|
||||
},
|
||||
"IsDeletedField": false,
|
||||
"IsCreatedField": false,
|
||||
"InsertedRecords": {
|
||||
"LanguageKeys": [
|
||||
"App.Wizard.Approval",
|
||||
"App.Wizard.Approval.Title",
|
||||
"App.Wizard.Approval.Desc"
|
||||
],
|
||||
"PermissionGroupNames": [],
|
||||
"PermissionNames": [
|
||||
"App.Wizard.Approval",
|
||||
"App.Wizard.Approval.Create",
|
||||
"App.Wizard.Approval.Update",
|
||||
"App.Wizard.Approval.Delete",
|
||||
"App.Wizard.Approval.Export",
|
||||
"App.Wizard.Approval.Import",
|
||||
"App.Wizard.Approval.Note"
|
||||
],
|
||||
"MenuCodes": [
|
||||
"App.Wizard.Approval"
|
||||
],
|
||||
"DataSourceCodes": []
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,281 @@
|
|||
{
|
||||
"Wizard": {
|
||||
"WizardName": "Todo",
|
||||
"ListFormCode": "App.Wizard.Todo",
|
||||
"MenuCode": "App.Wizard.Todo",
|
||||
"IsTenant": true,
|
||||
"IsBranch": false,
|
||||
"IsOrganizationUnit": false,
|
||||
"AllowAdding": true,
|
||||
"AllowUpdating": true,
|
||||
"AllowDeleting": true,
|
||||
"AllowDetail": false,
|
||||
"ConfirmDelete": true,
|
||||
"DefaultLayout": "todo",
|
||||
"Grid": true,
|
||||
"Card": true,
|
||||
"Pivot": true,
|
||||
"Tree": true,
|
||||
"Chart": true,
|
||||
"Gantt": true,
|
||||
"Scheduler": true,
|
||||
"Todo": true,
|
||||
"LanguageTextMenuEn": "Todo",
|
||||
"LanguageTextMenuTr": "\u0130\u015Fler",
|
||||
"LanguageTextTitleEn": "Todo",
|
||||
"LanguageTextTitleTr": "\u0130\u015Fler",
|
||||
"LanguageTextDescEn": "Todo",
|
||||
"LanguageTextDescTr": "\u0130\u015Fler",
|
||||
"LanguageTextMenuParentEn": "Project",
|
||||
"LanguageTextMenuParentTr": "Project",
|
||||
"PermissionGroupName": "App.Wizard.Project",
|
||||
"MenuParentCode": "App.Wizard.Project",
|
||||
"MenuParentShortName": "Pro",
|
||||
"MenuParentIcon": "FcVideoProjector",
|
||||
"MenuIcon": "FcTodoList",
|
||||
"DataSourceCode": "Default",
|
||||
"DataSourceConnectionString": "",
|
||||
"SelectCommandType": 1,
|
||||
"SelectCommand": "Pro_T_Todo",
|
||||
"KeyFieldName": "Id",
|
||||
"KeyFieldDbSourceType": 9,
|
||||
"TreeKeyExpr": "",
|
||||
"TreeParentIdExpr": "",
|
||||
"TreeAutoExpandAll": false,
|
||||
"GanttKeyExpr": "",
|
||||
"GanttParentIdExpr": "",
|
||||
"GanttAutoExpandAll": false,
|
||||
"GanttTitleExpr": "",
|
||||
"GanttStartExpr": "",
|
||||
"GanttEndExpr": "",
|
||||
"GanttProgressExpr": "",
|
||||
"SchedulerTextExpr": "",
|
||||
"SchedulerStartDateExpr": "",
|
||||
"SchedulerEndDateExpr": "",
|
||||
"TodoTitleExpr": "Title",
|
||||
"TodoStatusExpr": "Status",
|
||||
"TodoDescriptionExpr": "Description",
|
||||
"TodoDueDateExpr": "DueDate",
|
||||
"TodoTagExpr": "Tags",
|
||||
"TodoAssigneeExpr": "Assignees",
|
||||
"TodoPriorityExpr": "Priority",
|
||||
"TodoCompletedExpr": "Completed",
|
||||
"TodoOrderExpr": "SortOrder",
|
||||
"TodoStatusOrder": "Backlog, Ready to Start, In Progress, Code Review, Testing, Staging",
|
||||
"TodoAllowDragging": true,
|
||||
"ApprovalUserFieldName": "",
|
||||
"ApprovalDateFieldName": "",
|
||||
"ApprovalStatusFieldName": "",
|
||||
"ApprovalDescriptionFieldName": "",
|
||||
"ApprovalIsFilterUserName": false,
|
||||
"Criteria": [],
|
||||
"Groups": [
|
||||
{
|
||||
"Caption": "",
|
||||
"ColCount": 1,
|
||||
"Items": [
|
||||
{
|
||||
"FieldName": "Id",
|
||||
"CaptionName": "App.Listform.ListformField.Id",
|
||||
"EditorType": "dxTextBox",
|
||||
"EditorOptions": "",
|
||||
"EditorScript": "",
|
||||
"ColSpan": 1,
|
||||
"IsRequired": true,
|
||||
"IncludeInEditingForm": true,
|
||||
"DbSourceType": 9,
|
||||
"TurkishCaption": "Id",
|
||||
"EnglishCaption": "Id",
|
||||
"LookupDataSourceType": 1,
|
||||
"ValueExpr": "Key",
|
||||
"DisplayExpr": "Name",
|
||||
"LookupQuery": ""
|
||||
},
|
||||
{
|
||||
"FieldName": "Title",
|
||||
"CaptionName": "App.Listform.ListformField.Title",
|
||||
"EditorType": "dxTextBox",
|
||||
"EditorOptions": "",
|
||||
"EditorScript": "",
|
||||
"ColSpan": 1,
|
||||
"IsRequired": true,
|
||||
"IncludeInEditingForm": true,
|
||||
"DbSourceType": 16,
|
||||
"TurkishCaption": "Title",
|
||||
"EnglishCaption": "Title",
|
||||
"LookupDataSourceType": 1,
|
||||
"ValueExpr": "Key",
|
||||
"DisplayExpr": "Name",
|
||||
"LookupQuery": ""
|
||||
},
|
||||
{
|
||||
"FieldName": "Status",
|
||||
"CaptionName": "App.Listform.ListformField.Status",
|
||||
"EditorType": "dxTextBox",
|
||||
"EditorOptions": "",
|
||||
"EditorScript": "",
|
||||
"ColSpan": 1,
|
||||
"IsRequired": true,
|
||||
"IncludeInEditingForm": false,
|
||||
"DbSourceType": 16,
|
||||
"TurkishCaption": "Status",
|
||||
"EnglishCaption": "Status",
|
||||
"LookupDataSourceType": 1,
|
||||
"ValueExpr": "Key",
|
||||
"DisplayExpr": "Name",
|
||||
"LookupQuery": ""
|
||||
},
|
||||
{
|
||||
"FieldName": "Description",
|
||||
"CaptionName": "App.Listform.ListformField.Description",
|
||||
"EditorType": "dxHtmlEditor",
|
||||
"EditorOptions": "{\u0022mediaResizing\u0022:{\u0022enabled\u0022:true},\u0022imageUpload\u0022:{\u0022tabs\u0022:[\u0022file\u0022,\u0022url\u0022],\u0022fileUploadMode\u0022:\u0022base64\u0022},\u0022toolbar\u0022:{\u0022multiline\u0022:true,\u0022items\u0022:[{\u0022name\u0022:\u0022undo\u0022},{\u0022name\u0022:\u0022redo\u0022},{\u0022name\u0022:\u0022separator\u0022},{\u0022name\u0022:\u0022size\u0022,\u0022acceptedValues\u0022:[\u00228pt\u0022,\u002210pt\u0022,\u002212pt\u0022,\u002214pt\u0022,\u002218pt\u0022,\u002224pt\u0022,\u002236pt\u0022],\u0022options\u0022:{\u0022inputAttr\u0022:{\u0022aria-label\u0022:\u0022Font size\u0022}}},{\u0022name\u0022:\u0022font\u0022,\u0022acceptedValues\u0022:[\u0022Arial\u0022,\u0022Courier New\u0022,\u0022Georgia\u0022,\u0022Impact\u0022,\u0022Lucida Console\u0022,\u0022Tahoma\u0022,\u0022Times New Roman\u0022,\u0022Verdana\u0022],\u0022options\u0022:{\u0022inputAttr\u0022:{\u0022aria-label\u0022:\u0022Font family\u0022}}},{\u0022name\u0022:\u0022separator\u0022},{\u0022name\u0022:\u0022bold\u0022},{\u0022name\u0022:\u0022italic\u0022},{\u0022name\u0022:\u0022strike\u0022},{\u0022name\u0022:\u0022underline\u0022},{\u0022name\u0022:\u0022separator\u0022},{\u0022name\u0022:\u0022alignLeft\u0022},{\u0022name\u0022:\u0022alignCenter\u0022},{\u0022name\u0022:\u0022alignRight\u0022},{\u0022name\u0022:\u0022alignJustify\u0022},{\u0022name\u0022:\u0022separator\u0022},{\u0022name\u0022:\u0022orderedList\u0022},{\u0022name\u0022:\u0022bulletList\u0022},{\u0022name\u0022:\u0022separator\u0022},{\u0022name\u0022:\u0022header\u0022,\u0022acceptedValues\u0022:[false,1,2,3,4,5]},{\u0022name\u0022:\u0022separator\u0022},{\u0022name\u0022:\u0022color\u0022},{\u0022name\u0022:\u0022background\u0022},{\u0022name\u0022:\u0022separator\u0022},{\u0022name\u0022:\u0022link\u0022},{\u0022name\u0022:\u0022image\u0022},{\u0022name\u0022:\u0022separator\u0022},{\u0022name\u0022:\u0022clear\u0022},{\u0022name\u0022:\u0022codeBlock\u0022},{\u0022name\u0022:\u0022blockquote\u0022},{\u0022name\u0022:\u0022separator\u0022},{\u0022name\u0022:\u0022insertTable\u0022},{\u0022name\u0022:\u0022deleteTable\u0022},{\u0022name\u0022:\u0022insertRowAbove\u0022},{\u0022name\u0022:\u0022insertRowBelow\u0022},{\u0022name\u0022:\u0022deleteRow\u0022},{\u0022name\u0022:\u0022insertColumnLeft\u0022},{\u0022name\u0022:\u0022insertColumnRight\u0022},{\u0022name\u0022:\u0022deleteColumn\u0022},{\u0022name\u0022:\u0022cellProperties\u0022},{\u0022name\u0022:\u0022tableProperties\u0022}]}}",
|
||||
"EditorScript": "",
|
||||
"ColSpan": 1,
|
||||
"IsRequired": false,
|
||||
"IncludeInEditingForm": false,
|
||||
"DbSourceType": 16,
|
||||
"TurkishCaption": "Description",
|
||||
"EnglishCaption": "Description",
|
||||
"LookupDataSourceType": 1,
|
||||
"ValueExpr": "Key",
|
||||
"DisplayExpr": "Name",
|
||||
"LookupQuery": ""
|
||||
},
|
||||
{
|
||||
"FieldName": "DueDate",
|
||||
"CaptionName": "App.Listform.ListformField.DueDate",
|
||||
"EditorType": "dxDateBox",
|
||||
"EditorOptions": "",
|
||||
"EditorScript": "",
|
||||
"ColSpan": 1,
|
||||
"IsRequired": false,
|
||||
"IncludeInEditingForm": false,
|
||||
"DbSourceType": 6,
|
||||
"TurkishCaption": "Due Date",
|
||||
"EnglishCaption": "Due Date",
|
||||
"LookupDataSourceType": 1,
|
||||
"ValueExpr": "Key",
|
||||
"DisplayExpr": "Name",
|
||||
"LookupQuery": ""
|
||||
},
|
||||
{
|
||||
"FieldName": "Tags",
|
||||
"CaptionName": "App.Listform.ListformField.Tags",
|
||||
"EditorType": "dxTextBox",
|
||||
"EditorOptions": "",
|
||||
"EditorScript": "",
|
||||
"ColSpan": 1,
|
||||
"IsRequired": false,
|
||||
"IncludeInEditingForm": false,
|
||||
"DbSourceType": 16,
|
||||
"TurkishCaption": "Tags",
|
||||
"EnglishCaption": "Tags",
|
||||
"LookupDataSourceType": 1,
|
||||
"ValueExpr": "Key",
|
||||
"DisplayExpr": "Name",
|
||||
"LookupQuery": ""
|
||||
},
|
||||
{
|
||||
"FieldName": "Assignees",
|
||||
"CaptionName": "App.Listform.ListformField.Assignees",
|
||||
"EditorType": "dxTextBox",
|
||||
"EditorOptions": "",
|
||||
"EditorScript": "",
|
||||
"ColSpan": 1,
|
||||
"IsRequired": false,
|
||||
"IncludeInEditingForm": false,
|
||||
"DbSourceType": 16,
|
||||
"TurkishCaption": "Assignees",
|
||||
"EnglishCaption": "Assignees",
|
||||
"LookupDataSourceType": 1,
|
||||
"ValueExpr": "Key",
|
||||
"DisplayExpr": "Name",
|
||||
"LookupQuery": ""
|
||||
},
|
||||
{
|
||||
"FieldName": "Priority",
|
||||
"CaptionName": "App.Listform.ListformField.Priority",
|
||||
"EditorType": "dxTextBox",
|
||||
"EditorOptions": "",
|
||||
"EditorScript": "",
|
||||
"ColSpan": 1,
|
||||
"IsRequired": false,
|
||||
"IncludeInEditingForm": false,
|
||||
"DbSourceType": 16,
|
||||
"TurkishCaption": "Priority",
|
||||
"EnglishCaption": "Priority",
|
||||
"LookupDataSourceType": 1,
|
||||
"ValueExpr": "Key",
|
||||
"DisplayExpr": "Name",
|
||||
"LookupQuery": ""
|
||||
},
|
||||
{
|
||||
"FieldName": "Completed",
|
||||
"CaptionName": "App.Listform.ListformField.Completed",
|
||||
"EditorType": "dxCheckBox",
|
||||
"EditorOptions": "",
|
||||
"EditorScript": "",
|
||||
"ColSpan": 1,
|
||||
"IsRequired": true,
|
||||
"IncludeInEditingForm": false,
|
||||
"DbSourceType": 3,
|
||||
"TurkishCaption": "Completed",
|
||||
"EnglishCaption": "Completed",
|
||||
"LookupDataSourceType": 1,
|
||||
"ValueExpr": "Key",
|
||||
"DisplayExpr": "Name",
|
||||
"LookupQuery": ""
|
||||
},
|
||||
{
|
||||
"FieldName": "SortOrder",
|
||||
"CaptionName": "App.Listform.ListformField.SortOrder",
|
||||
"EditorType": "dxNumberBox",
|
||||
"EditorOptions": "",
|
||||
"EditorScript": "",
|
||||
"ColSpan": 1,
|
||||
"IsRequired": true,
|
||||
"IncludeInEditingForm": false,
|
||||
"DbSourceType": 11,
|
||||
"TurkishCaption": "Sort Order",
|
||||
"EnglishCaption": "Sort Order",
|
||||
"LookupDataSourceType": 1,
|
||||
"ValueExpr": "Key",
|
||||
"DisplayExpr": "Name",
|
||||
"LookupQuery": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"SubForms": [],
|
||||
"Widgets": []
|
||||
},
|
||||
"IsDeletedField": false,
|
||||
"IsCreatedField": false,
|
||||
"InsertedRecords": {
|
||||
"LanguageKeys": [
|
||||
"App.Wizard.Todo",
|
||||
"App.Wizard.Todo.Title",
|
||||
"App.Wizard.Todo.Desc",
|
||||
"App.Listform.ListformField.Assignees",
|
||||
"App.Listform.ListformField.Completed",
|
||||
"App.Listform.ListformField.SortOrder"
|
||||
],
|
||||
"PermissionGroupNames": [
|
||||
"App.Wizard.Project"
|
||||
],
|
||||
"PermissionNames": [
|
||||
"App.Wizard.Todo",
|
||||
"App.Wizard.Todo.Create",
|
||||
"App.Wizard.Todo.Update",
|
||||
"App.Wizard.Todo.Delete",
|
||||
"App.Wizard.Todo.Export",
|
||||
"App.Wizard.Todo.Import",
|
||||
"App.Wizard.Todo.Note"
|
||||
],
|
||||
"MenuCodes": [
|
||||
"App.Wizard.Todo"
|
||||
],
|
||||
"DataSourceCodes": []
|
||||
}
|
||||
}
|
||||
|
|
@ -107,6 +107,8 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
|
||||
var fileName = Path.GetFileName(filePath);
|
||||
|
||||
await BackfillMenuParentShortNameAsync(seedFile.Wizard);
|
||||
|
||||
// Zaten seeded mi kontrol et (ListForm var mı?)
|
||||
if (await _repoListForm.AnyAsync(a => a.ListFormCode == seedFile.Wizard.ListFormCode))
|
||||
{
|
||||
|
|
@ -253,6 +255,7 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
Code = input.MenuParentCode,
|
||||
DisplayName = input.MenuParentCode,
|
||||
IsDisabled = false,
|
||||
ShortName = input.MenuParentShortName,
|
||||
Icon = menuParentIcon,
|
||||
Order = maxRootOrder + 1,
|
||||
}, autoSave: true);
|
||||
|
|
@ -410,10 +413,10 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
DeleteCommand = isDeleted ? WizardConsts.DefaultDeleteCommand(input.SelectCommand) : null,
|
||||
DeleteFieldsDefaultValueJson = isDeleted
|
||||
? WizardConsts.DefaultDeleteFieldsDefaultValueJson(input.KeyFieldDbSourceType)
|
||||
: WizardConsts.DefaultFieldsJsonOnlyId(input.KeyFieldDbSourceType),
|
||||
: WizardConsts.DefaultDeleteFieldsJsonOnlyId(input.KeyFieldDbSourceType),
|
||||
InsertFieldsDefaultValueJson = isCreated
|
||||
? WizardConsts.DefaultInsertFieldsDefaultValueJson(input.KeyFieldDbSourceType)
|
||||
: WizardConsts.DefaultFieldsJsonOnlyId(input.KeyFieldDbSourceType),
|
||||
: WizardConsts.DefaultInsertFieldsJsonOnlyId(input.KeyFieldDbSourceType),
|
||||
PagerOptionJson = WizardConsts.DefaultPagerOptionJson,
|
||||
EditingOptionJson = WizardConsts.DefaultEditingOptionJson(titleLangKey, formWidth, formHeight, input.AllowDeleting, input.AllowAdding, input.AllowUpdating, input.ConfirmDelete, false, input.AllowDetail),
|
||||
EditingFormJson = editingFormDtos.Count > 0 ? JsonSerializer.Serialize(editingFormDtos) : null,
|
||||
|
|
@ -465,9 +468,11 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
AllowSearch = true,
|
||||
ListOrderNo = fieldOrder,
|
||||
EditGroupOrderNo = item.IncludeInEditingForm ? editGroupOrder : null,
|
||||
EditOrderNo = item.IncludeInEditingForm && item.FieldName != input.KeyFieldName ? editOrder : null,
|
||||
EditorType2 = item.IncludeInEditingForm ? item.EditorType : null,
|
||||
ColSpan = item.IncludeInEditingForm ? item.ColSpan : null,
|
||||
EditOrderNo = item.IncludeInEditingForm && item.FieldName != input.KeyFieldName
|
||||
? editOrder
|
||||
: null,
|
||||
EditorType2 = item.EditorType,
|
||||
ColSpan = item.ColSpan,
|
||||
EditorOptions = string.IsNullOrWhiteSpace(item.EditorOptions) ? null : item.EditorOptions,
|
||||
EditorScript = string.IsNullOrWhiteSpace(item.EditorScript) ? null : item.EditorScript,
|
||||
SourceDbType = item.DbSourceType,
|
||||
|
|
@ -517,6 +522,24 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
}
|
||||
}
|
||||
|
||||
private async Task BackfillMenuParentShortNameAsync(ListFormWizardDto input)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(input.MenuParentCode) ||
|
||||
string.IsNullOrWhiteSpace(input.MenuParentShortName))
|
||||
return;
|
||||
|
||||
var menuParent = await _repoMenu.FirstOrDefaultAsync(a => a.Code == input.MenuParentCode);
|
||||
if (menuParent == null || !string.IsNullOrWhiteSpace(menuParent.ShortName))
|
||||
return;
|
||||
|
||||
menuParent.ShortName = input.MenuParentShortName.Trim();
|
||||
await _repoMenu.UpdateAsync(menuParent, autoSave: true);
|
||||
_logger.LogInformation(
|
||||
"Menu parent '{MenuParentCode}' ShortName backfilled as '{ShortName}'.",
|
||||
input.MenuParentCode,
|
||||
menuParent.ShortName);
|
||||
}
|
||||
|
||||
private static bool HasWorkflow(WorkflowDto workflow, List<ListFormWorkflowCriteriaDto> criteria)
|
||||
{
|
||||
return workflow != null && (
|
||||
|
|
|
|||
|
|
@ -198,6 +198,14 @@ public static class WizardConsts
|
|||
});
|
||||
}
|
||||
|
||||
public static string DefaultInsertFieldsJsonOnlyId(DbType dbType = DbType.Guid)
|
||||
{
|
||||
return JsonSerializer.Serialize(new[]
|
||||
{
|
||||
new { FieldName = "Id", FieldDbType = dbType, Value = "@NEWID", CustomValueType = FieldCustomValueTypeEnum.CustomKey }
|
||||
});
|
||||
}
|
||||
|
||||
public static string DefaultDeleteFieldsDefaultValueJson(DbType dbType = DbType.Guid)
|
||||
{
|
||||
return JsonSerializer.Serialize(new[]
|
||||
|
|
@ -207,11 +215,11 @@ public static class WizardConsts
|
|||
});
|
||||
}
|
||||
|
||||
public static string DefaultFieldsJsonOnlyId(DbType dbType = DbType.Guid)
|
||||
public static string DefaultDeleteFieldsJsonOnlyId(DbType dbType = DbType.Guid)
|
||||
{
|
||||
return JsonSerializer.Serialize(new[]
|
||||
{
|
||||
new { FieldName = "Id", FieldDbType = dbType, Value = "@NEWID", CustomValueType = FieldCustomValueTypeEnum.CustomKey }
|
||||
new { FieldName = "Id", FieldDbType = dbType, Value = "@ID", CustomValueType = FieldCustomValueTypeEnum.CustomKey }
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -170,7 +170,8 @@ public class QueryManager : PlatformDomainService, IQueryManager
|
|||
// oncelik Command alanindadir, dolu ise silme islemi buradaki sorguya yonlendirilir
|
||||
if (!string.IsNullOrEmpty(command))
|
||||
{
|
||||
sql = NormalizeCollectionParameterCommand(command, parameters, dataSourceType);
|
||||
// sql = NormalizeCollectionParameterCommand(command, parameters, dataSourceType);
|
||||
sql = command;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -188,12 +189,6 @@ public class QueryManager : PlatformDomainService, IQueryManager
|
|||
}
|
||||
else if (op == OperationEnum.Update)
|
||||
{
|
||||
var where = dataSourceType switch
|
||||
{
|
||||
DataSourceTypeEnum.Mssql => $"\"{listForm.KeyFieldName}\" IN @{listForm.KeyFieldName}",
|
||||
DataSourceTypeEnum.Postgresql => $"\"{listForm.KeyFieldName}\" = ANY(@{listForm.KeyFieldName})",
|
||||
_ => string.Empty,
|
||||
};
|
||||
var updateFields = parameters.Select(a => $"\"{a.Key}\" = @{a.Key}").ToList();
|
||||
var val = QueryHelper.GetFormattedValue(listForm.KeyFieldDbSourceType, keys);
|
||||
if (!parameters.ContainsKey(listForm.KeyFieldName))
|
||||
|
|
@ -202,6 +197,18 @@ public class QueryManager : PlatformDomainService, IQueryManager
|
|||
listForm.KeyFieldName,
|
||||
val.GetType().IsArray ? val : new object[] { val });
|
||||
}
|
||||
|
||||
var where = BuildWhereCondition(
|
||||
listForm.KeyFieldName,
|
||||
parameters[listForm.KeyFieldName],
|
||||
dataSourceType);
|
||||
|
||||
if (parameters.TryGetValue("TenantId", out var tenantId)
|
||||
&& !string.Equals(listForm.KeyFieldName, "TenantId", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
where += $" AND {BuildWhereCondition("TenantId", tenantId, dataSourceType)}";
|
||||
}
|
||||
|
||||
sql = $"UPDATE \"{listForm.SelectCommand}\" SET {string.Join(',', updateFields)} WHERE {where}";
|
||||
}
|
||||
else if (op == OperationEnum.Delete)
|
||||
|
|
@ -212,12 +219,7 @@ public class QueryManager : PlatformDomainService, IQueryManager
|
|||
{
|
||||
where = string.Join(
|
||||
" AND ",
|
||||
parameters.Select(a => dataSourceType switch
|
||||
{
|
||||
DataSourceTypeEnum.Mssql => $"\"{a.Key}\" IN @{a.Key}",
|
||||
DataSourceTypeEnum.Postgresql => $"\"{a.Key}\" = ANY(@{a.Key})",
|
||||
_ => "1 = 0",
|
||||
}).ToList());
|
||||
parameters.Select(a => BuildWhereCondition(a.Key, a.Value, dataSourceType)).ToList());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -240,77 +242,101 @@ public class QueryManager : PlatformDomainService, IQueryManager
|
|||
return sql;
|
||||
}
|
||||
|
||||
private static string NormalizeCollectionParameterCommand(
|
||||
string command,
|
||||
Dictionary<string, object> parameters,
|
||||
DataSourceTypeEnum dataSourceType)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(command) || parameters == null || parameters.Count == 0)
|
||||
{
|
||||
return command;
|
||||
}
|
||||
|
||||
var sql = command;
|
||||
foreach (var parameter in parameters)
|
||||
{
|
||||
if (!IsCollectionParameter(parameter.Value))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var escapedParameterName = Regex.Escape(parameter.Key);
|
||||
sql = dataSourceType switch
|
||||
{
|
||||
DataSourceTypeEnum.Mssql => NormalizeMssqlCollectionParameter(sql, escapedParameterName, parameter.Key),
|
||||
DataSourceTypeEnum.Postgresql => NormalizePostgresqlCollectionParameter(sql, escapedParameterName, parameter.Key),
|
||||
_ => sql
|
||||
};
|
||||
}
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
private static bool IsCollectionParameter(object value)
|
||||
private static bool IsCollectionValue(object value)
|
||||
{
|
||||
return value is System.Collections.IEnumerable
|
||||
&& value is not string
|
||||
&& value is not byte[];
|
||||
}
|
||||
|
||||
private static string NormalizeMssqlCollectionParameter(
|
||||
string sql,
|
||||
string escapedParameterName,
|
||||
string parameterName)
|
||||
private static string BuildWhereCondition(
|
||||
string fieldName,
|
||||
object value,
|
||||
DataSourceTypeEnum dataSourceType)
|
||||
{
|
||||
sql = Regex.Replace(
|
||||
sql,
|
||||
$@"IN\s*\(\s*@{escapedParameterName}\s*\)",
|
||||
$"IN @{parameterName}",
|
||||
RegexOptions.IgnoreCase);
|
||||
|
||||
return Regex.Replace(
|
||||
sql,
|
||||
$@"(?<column>(""[^""]+""|\[[^\]]+\]|`[^`]+`|\w+))\s*=\s*@{escapedParameterName}\b",
|
||||
match => $"{match.Groups["column"].Value} IN @{parameterName}",
|
||||
RegexOptions.IgnoreCase);
|
||||
return dataSourceType switch
|
||||
{
|
||||
DataSourceTypeEnum.Mssql when value is null or DBNull => $"\"{fieldName}\" IS NULL",
|
||||
DataSourceTypeEnum.Postgresql when value is null or DBNull => $"\"{fieldName}\" IS NULL",
|
||||
DataSourceTypeEnum.Mssql when IsCollectionValue(value) => $"\"{fieldName}\" IN @{fieldName}",
|
||||
DataSourceTypeEnum.Postgresql when IsCollectionValue(value) => $"\"{fieldName}\" = ANY(@{fieldName})",
|
||||
DataSourceTypeEnum.Mssql => $"\"{fieldName}\" = @{fieldName}",
|
||||
DataSourceTypeEnum.Postgresql => $"\"{fieldName}\" = @{fieldName}",
|
||||
_ => "1 = 0",
|
||||
};
|
||||
}
|
||||
|
||||
private static string NormalizePostgresqlCollectionParameter(
|
||||
string sql,
|
||||
string escapedParameterName,
|
||||
string parameterName)
|
||||
{
|
||||
sql = Regex.Replace(
|
||||
sql,
|
||||
$@"IN\s*\(\s*@{escapedParameterName}\s*\)",
|
||||
$"= ANY(@{parameterName})",
|
||||
RegexOptions.IgnoreCase);
|
||||
// private static string NormalizeCollectionParameterCommand(
|
||||
// string command,
|
||||
// Dictionary<string, object> parameters,
|
||||
// DataSourceTypeEnum dataSourceType)
|
||||
// {
|
||||
// if (string.IsNullOrWhiteSpace(command) || parameters == null || parameters.Count == 0)
|
||||
// {
|
||||
// return command;
|
||||
// }
|
||||
|
||||
return Regex.Replace(
|
||||
sql,
|
||||
$@"(?<column>(""[^""]+""|\[[^\]]+\]|`[^`]+`|\w+))\s*=\s*@{escapedParameterName}\b",
|
||||
match => $"{match.Groups["column"].Value} = ANY(@{parameterName})",
|
||||
RegexOptions.IgnoreCase);
|
||||
}
|
||||
// var sql = command;
|
||||
// foreach (var parameter in parameters)
|
||||
// {
|
||||
// if (!IsCollectionParameter(parameter.Value))
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// var escapedParameterName = Regex.Escape(parameter.Key);
|
||||
// sql = dataSourceType switch
|
||||
// {
|
||||
// DataSourceTypeEnum.Mssql => NormalizeMssqlCollectionParameter(sql, escapedParameterName, parameter.Key),
|
||||
// DataSourceTypeEnum.Postgresql => NormalizePostgresqlCollectionParameter(sql, escapedParameterName, parameter.Key),
|
||||
// _ => sql
|
||||
// };
|
||||
// }
|
||||
|
||||
// return sql;
|
||||
// }
|
||||
|
||||
// private static bool IsCollectionParameter(object value)
|
||||
// {
|
||||
// return value is System.Collections.IEnumerable
|
||||
// && value is not string
|
||||
// && value is not byte[];
|
||||
// }
|
||||
|
||||
// private static string NormalizeMssqlCollectionParameter(
|
||||
// string sql,
|
||||
// string escapedParameterName,
|
||||
// string parameterName)
|
||||
// {
|
||||
// sql = Regex.Replace(
|
||||
// sql,
|
||||
// $@"IN\s*\(\s*@{escapedParameterName}\s*\)",
|
||||
// $"IN @{parameterName}",
|
||||
// RegexOptions.IgnoreCase);
|
||||
|
||||
// return Regex.Replace(
|
||||
// sql,
|
||||
// $@"(?<column>(""[^""]+""|\[[^\]]+\]|`[^`]+`|\w+))\s*=\s*@{escapedParameterName}\b",
|
||||
// match => $"{match.Groups["column"].Value} IN @{parameterName}",
|
||||
// RegexOptions.IgnoreCase);
|
||||
// }
|
||||
|
||||
// private static string NormalizePostgresqlCollectionParameter(
|
||||
// string sql,
|
||||
// string escapedParameterName,
|
||||
// string parameterName)
|
||||
// {
|
||||
// sql = Regex.Replace(
|
||||
// sql,
|
||||
// $@"IN\s*\(\s*@{escapedParameterName}\s*\)",
|
||||
// $"= ANY(@{parameterName})",
|
||||
// RegexOptions.IgnoreCase);
|
||||
|
||||
// return Regex.Replace(
|
||||
// sql,
|
||||
// $@"(?<column>(""[^""]+""|\[[^\]]+\]|`[^`]+`|\w+))\s*=\s*@{escapedParameterName}\b",
|
||||
// match => $"{match.Groups["column"].Value} = ANY(@{parameterName})",
|
||||
// RegexOptions.IgnoreCase);
|
||||
// }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,17 @@
|
|||
{
|
||||
"commit": "1d05d24",
|
||||
"commit": "8146adf",
|
||||
"releases": [
|
||||
{
|
||||
"version": "1.1.08",
|
||||
"buildDate": "2026-07-16",
|
||||
"commit": "24e92fcb82eef0ee26ca5d65e08c5404f132a09e",
|
||||
"changeLog": [
|
||||
"- CardView komponenti geliştirildi.",
|
||||
"- Todo / Kanban komponenti geliştirildi.",
|
||||
"- Licence information",
|
||||
"- Check New Versiyon komponenti."
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.1.07",
|
||||
"buildDate": "2026-07-13",
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {
|
|||
import { ListViewLayoutType } from '@/views/admin/listForm/edit/types'
|
||||
|
||||
export interface ListFormWizardColumnItemDto {
|
||||
dataField: string
|
||||
fieldName: string
|
||||
editorType: string
|
||||
editorOptions: string
|
||||
editorScript: string
|
||||
|
|
@ -56,6 +56,7 @@ export interface ListFormWizardDto {
|
|||
languageTextMenuParentTr: string
|
||||
permissionGroupName: string
|
||||
menuParentCode: string
|
||||
menuParentShortName?: string
|
||||
menuParentIcon?: string
|
||||
menuIcon: string
|
||||
dataSourceCode: string
|
||||
|
|
@ -129,7 +130,7 @@ export interface WizardInsertedRecordsDto {
|
|||
}
|
||||
|
||||
export interface WizardSeedFileItemDto {
|
||||
dataField: string
|
||||
fieldName: string
|
||||
editorType: string
|
||||
editorOptions: string
|
||||
editorScript: string
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ const initialValues: ListFormWizardDto = {
|
|||
chart: true,
|
||||
gantt: true,
|
||||
scheduler: true,
|
||||
todo: true,
|
||||
todo: false,
|
||||
todoTitleExpr: '',
|
||||
todoStatusExpr: '',
|
||||
todoDescriptionExpr: '',
|
||||
|
|
@ -74,7 +74,7 @@ const initialValues: ListFormWizardDto = {
|
|||
todoPriorityExpr: '',
|
||||
todoCompletedExpr: '',
|
||||
todoOrderExpr: '',
|
||||
todoStatusOrder: 'Inbox, Today, This Week, This Month, Later, Done',
|
||||
todoStatusOrder: 'Backlog, Ready to Start, In Progress, Code Review, Testing, Staging',
|
||||
todoAllowDragging: true,
|
||||
languageTextMenuEn: '',
|
||||
languageTextMenuTr: '',
|
||||
|
|
@ -86,6 +86,7 @@ const initialValues: ListFormWizardDto = {
|
|||
languageTextMenuParentTr: '',
|
||||
permissionGroupName: '',
|
||||
menuParentCode: '',
|
||||
menuParentShortName: '',
|
||||
menuParentIcon: '',
|
||||
menuIcon: '',
|
||||
dataSourceCode: '',
|
||||
|
|
@ -146,7 +147,26 @@ const step2ValidationSchema = Yup.object().shape({
|
|||
confirmDelete: Yup.boolean(),
|
||||
})
|
||||
|
||||
const listFormValidationSchema = step1ValidationSchema.concat(step2ValidationSchema)
|
||||
const todoValidationSchema = Yup.object().shape({
|
||||
todoTitleExpr: Yup.string()
|
||||
.trim()
|
||||
.when('todo', {
|
||||
is: true,
|
||||
then: (schema) => schema.required(),
|
||||
otherwise: (schema) => schema.notRequired(),
|
||||
}),
|
||||
todoStatusExpr: Yup.string()
|
||||
.trim()
|
||||
.when('todo', {
|
||||
is: true,
|
||||
then: (schema) => schema.required(),
|
||||
otherwise: (schema) => schema.notRequired(),
|
||||
}),
|
||||
})
|
||||
|
||||
const listFormValidationSchema = step1ValidationSchema
|
||||
.concat(step2ValidationSchema)
|
||||
.concat(todoValidationSchema)
|
||||
|
||||
// ─── Wizard ───────────────────────────────────────────────────────────────────
|
||||
|
||||
|
|
@ -266,7 +286,7 @@ const Wizard = () => {
|
|||
const removeTenantGroupItems = (groups: WizardGroup[]) =>
|
||||
groups.map((group) => ({
|
||||
...group,
|
||||
items: group.items.filter((item) => !isTenantColumn(item.dataField)),
|
||||
items: group.items.filter((item) => !isTenantColumn(item.fieldName)),
|
||||
}))
|
||||
|
||||
const loadColumns = async (dsCode: string, schema: string, name: string) => {
|
||||
|
|
@ -433,7 +453,9 @@ const Wizard = () => {
|
|||
todoPriorityExpr: w.todoPriorityExpr ?? '',
|
||||
todoCompletedExpr: w.todoCompletedExpr ?? '',
|
||||
todoOrderExpr: w.todoOrderExpr ?? '',
|
||||
todoStatusOrder: w.todoStatusOrder ?? 'Inbox, Today, This Week, This Month, Later, Done',
|
||||
todoStatusOrder:
|
||||
w.todoStatusOrder ??
|
||||
'Backlog, Ready to Start, In Progress, Code Review, Testing, Staging',
|
||||
todoAllowDragging: w.todoAllowDragging ?? true,
|
||||
languageTextMenuEn: w.languageTextMenuEn ?? '',
|
||||
languageTextMenuTr: w.languageTextMenuTr ?? '',
|
||||
|
|
@ -445,6 +467,7 @@ const Wizard = () => {
|
|||
languageTextMenuParentTr: w.languageTextMenuParentTr ?? '',
|
||||
permissionGroupName: w.permissionGroupName ?? '',
|
||||
menuParentCode: w.menuParentCode ?? '',
|
||||
menuParentShortName: w.menuParentShortName ?? '',
|
||||
menuParentIcon: w.menuParentIcon ?? '',
|
||||
menuIcon: w.menuIcon ?? '',
|
||||
dataSourceCode: w.dataSourceCode ?? '',
|
||||
|
|
@ -497,19 +520,19 @@ const Wizard = () => {
|
|||
caption: g.caption ?? '',
|
||||
colCount: g.colCount ?? 2,
|
||||
items: (g.items ?? []).map(
|
||||
(it: any, ii: number) =>
|
||||
(it: WizardGroupItem, ii: number) =>
|
||||
({
|
||||
id: `${it.dataField}_edit_${ii}_${Date.now()}`,
|
||||
dataField: it.dataField ?? '',
|
||||
id: `${it.fieldName}_edit_${ii}_${Date.now()}`,
|
||||
fieldName: it.fieldName ?? '',
|
||||
editorType: it.editorType ?? 'dxTextBox',
|
||||
editorOptions: it.editorOptions ?? '',
|
||||
editorScript: it.editorScript ?? '',
|
||||
colSpan: it.colSpan ?? 1,
|
||||
isRequired: it.isRequired ?? false,
|
||||
includeInEditingForm: it.includeInEditingForm ?? true,
|
||||
turkishCaption: it.turkishCaption ?? it.dataField,
|
||||
englishCaption: it.englishCaption ?? it.dataField,
|
||||
captionName: it.captionName ?? `App.Listform.ListformField.${it.dataField}`,
|
||||
turkishCaption: it.turkishCaption ?? it.fieldName,
|
||||
englishCaption: it.englishCaption ?? it.fieldName,
|
||||
captionName: it.captionName ?? `App.Listform.ListformField.${it.fieldName}`,
|
||||
lookupDataSourceType:
|
||||
(it.lookupDataSourceType as UiLookupDataSourceTypeEnum) ??
|
||||
UiLookupDataSourceTypeEnum.StaticData,
|
||||
|
|
@ -522,7 +545,7 @@ const Wizard = () => {
|
|||
setEditingGroups(restoredGroups)
|
||||
|
||||
// Restore selectedColumns from all group items
|
||||
const allFields = new Set(restoredGroups.flatMap((g) => g.items.map((i) => i.dataField)))
|
||||
const allFields = new Set(restoredGroups.flatMap((g) => g.items.map((i) => i.fieldName)))
|
||||
setSelectedColumns(allFields)
|
||||
}
|
||||
|
||||
|
|
@ -638,8 +661,16 @@ const Wizard = () => {
|
|||
formikRef.current?.setFieldValue('menuParentCode', code)
|
||||
const selectedMenu = rawMenuItems.find((item) => item.code === code)
|
||||
formikRef.current?.setFieldValue('menuParentIcon', selectedMenu?.icon ?? '')
|
||||
if (!code) return
|
||||
applyPermissionGroupFromRoot(findRootCode(rawMenuItems, code))
|
||||
formikRef.current?.setFieldValue('languageTextMenuParentEn', selectedMenu?.menuTextEn ?? '')
|
||||
formikRef.current?.setFieldValue('languageTextMenuParentTr', selectedMenu?.menuTextTr ?? '')
|
||||
if (!code) {
|
||||
formikRef.current?.setFieldValue('menuParentShortName', '')
|
||||
return
|
||||
}
|
||||
const rootCode = findRootCode(rawMenuItems, code)
|
||||
const rootMenu = rawMenuItems.find((item) => item.code === rootCode)
|
||||
formikRef.current?.setFieldValue('menuParentShortName', rootMenu?.shortName ?? '')
|
||||
applyPermissionGroupFromRoot(rootCode)
|
||||
}
|
||||
|
||||
const handleMenuCreated = async (menu: {
|
||||
|
|
@ -648,6 +679,7 @@ const Wizard = () => {
|
|||
menuTextEn: string
|
||||
menuTextTr: string
|
||||
icon?: string
|
||||
shortName?: string
|
||||
}) => {
|
||||
formikRef.current?.setFieldValue('menuParentCode', menu.code)
|
||||
formikRef.current?.setFieldValue('menuParentIcon', menu.icon ?? '')
|
||||
|
|
@ -655,6 +687,11 @@ const Wizard = () => {
|
|||
formikRef.current?.setFieldValue('languageTextMenuParentTr', menu.menuTextTr)
|
||||
|
||||
const rootCode = menu.parentCode ? findRootCode(rawMenuItems, menu.parentCode) : menu.code
|
||||
const existingRoot = rawMenuItems.find((item) => item.code === rootCode)
|
||||
formikRef.current?.setFieldValue(
|
||||
'menuParentShortName',
|
||||
menu.parentCode ? (existingRoot?.shortName ?? '') : (menu.shortName ?? ''),
|
||||
)
|
||||
applyPermissionGroupFromRoot(rootCode)
|
||||
|
||||
await getMenuList()
|
||||
|
|
@ -726,10 +763,10 @@ const Wizard = () => {
|
|||
caption: g.caption,
|
||||
colCount: g.colCount,
|
||||
items: g.items.map((item) => {
|
||||
const col = selectCommandColumns.find((c) => c.columnName === item.dataField)
|
||||
const col = selectCommandColumns.find((c) => c.columnName === item.fieldName)
|
||||
|
||||
return {
|
||||
dataField: item.dataField,
|
||||
fieldName: item.fieldName,
|
||||
editorType: item.editorType,
|
||||
editorOptions: item.editorOptions ?? '',
|
||||
editorScript: item.editorScript ?? '',
|
||||
|
|
@ -836,6 +873,7 @@ const Wizard = () => {
|
|||
onMenuParentChange={handleMenuParentChange}
|
||||
onClearMenuParent={() => {
|
||||
formikRef.current?.setFieldValue('menuParentCode', '')
|
||||
formikRef.current?.setFieldValue('menuParentShortName', '')
|
||||
formikRef.current?.setFieldValue('menuParentIcon', '')
|
||||
}}
|
||||
onMenuCreated={handleMenuCreated}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import { ListFormWizardDto } from '@/proxy/admin/wizard/models'
|
|||
export interface MenuTreeNode {
|
||||
code: string
|
||||
displayName: string
|
||||
shortName?: string
|
||||
icon?: string
|
||||
url?: string
|
||||
order?: number
|
||||
|
|
@ -41,6 +42,7 @@ export function buildMenuTree(items: MenuItem[]): MenuTreeNode[] {
|
|||
map.set(item.code!, {
|
||||
code: item.code!,
|
||||
displayName: item.displayName ?? item.code!,
|
||||
shortName: item.shortName ?? undefined,
|
||||
icon: item.icon ?? undefined,
|
||||
url: item.url ?? undefined,
|
||||
order: item.order ?? undefined,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { Button, Dialog } from '@/components/ui'
|
||||
import type { SelectBoxOption } from '@/types/shared'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import {
|
||||
columnEditorTypeListOptions,
|
||||
|
|
@ -28,14 +29,17 @@ import {
|
|||
FaTrash,
|
||||
FaArrowRight,
|
||||
FaCode,
|
||||
FaSlidersH,
|
||||
} from 'react-icons/fa'
|
||||
import { UiLookupDataSourceTypeEnum } from '@/proxy/form/models'
|
||||
import EditorOptionsBuilderDialog from '../edit/json-row-operations/EditorOptionsBuilderDialog'
|
||||
import EditorScriptBuilderDialog from '../edit/json-row-operations/EditorScriptBuilderDialog'
|
||||
import { buildLookupQuery } from '../lookupQuery'
|
||||
|
||||
// ─── Types ────────────────────────────────────────────────────────────────────
|
||||
export interface WizardGroupItem {
|
||||
id: string
|
||||
dataField: string
|
||||
fieldName: string
|
||||
editorType: string
|
||||
editorOptions: string
|
||||
editorScript: string
|
||||
|
|
@ -109,7 +113,7 @@ function newGroupItem(colName: string, meta?: DatabaseColumnDto): WizardGroupIte
|
|||
const sqlType = meta?.dataType ?? ''
|
||||
return {
|
||||
id: `${colName}_${Date.now()}`,
|
||||
dataField: colName,
|
||||
fieldName: colName,
|
||||
editorType: inferEditorType(sqlType),
|
||||
editorOptions: '',
|
||||
editorScript: '',
|
||||
|
|
@ -169,6 +173,7 @@ interface SortableItemProps {
|
|||
groupColCount: number
|
||||
dbObjects: SqlObjectExplorerDto | null
|
||||
dsCode: string
|
||||
editorScriptFields: SelectBoxOption[]
|
||||
onTurkishCaptionChange: (val: string) => void
|
||||
onEnglishCaptionChange: (val: string) => void
|
||||
onEditorTypeChange: (val: string) => void
|
||||
|
|
@ -190,6 +195,7 @@ function SortableItem({
|
|||
groupColCount,
|
||||
dbObjects,
|
||||
dsCode,
|
||||
editorScriptFields,
|
||||
onTurkishCaptionChange,
|
||||
onEnglishCaptionChange,
|
||||
onEditorTypeChange,
|
||||
|
|
@ -207,6 +213,8 @@ function SortableItem({
|
|||
}: SortableItemProps) {
|
||||
const { translate } = useLocalization()
|
||||
const [isTablePickerOpen, setIsTablePickerOpen] = useState(false)
|
||||
const [isEditorOptionsDialogOpen, setIsEditorOptionsDialogOpen] = useState(false)
|
||||
const [isEditorScriptDialogOpen, setIsEditorScriptDialogOpen] = useState(false)
|
||||
const [tableSearch, setTableSearch] = useState('')
|
||||
const [pickerStep, setPickerStep] = useState<'table' | 'columns'>('table')
|
||||
const [pickerTable, setPickerTable] = useState<{ schemaName: string; tableName: string } | null>(
|
||||
|
|
@ -248,7 +256,7 @@ function SortableItem({
|
|||
tabIndex={-1}
|
||||
/>
|
||||
<span className="flex-1 text-xs font-semibold text-indigo-600 dark:text-indigo-400 truncate">
|
||||
{item.dataField}
|
||||
{item.fieldName}
|
||||
</span>
|
||||
<Button
|
||||
type="button"
|
||||
|
|
@ -564,12 +572,23 @@ function SortableItem({
|
|||
<span className="text-[10px] text-gray-400 font-medium">
|
||||
{translate('::ListForms.Wizard.Step3.EditorOptions')}
|
||||
</span>
|
||||
<input
|
||||
value={item.editorOptions}
|
||||
onChange={(e) => onEditorOptionsChange(e.target.value)}
|
||||
placeholder='{"readOnly": false}'
|
||||
className="w-full text-xs px-1.5 py-1 rounded border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-700 text-gray-700 dark:text-gray-200 focus:outline-none focus:border-indigo-400 resize-none font-mono"
|
||||
/>
|
||||
<div className="flex items-center gap-1">
|
||||
<input
|
||||
value={item.editorOptions}
|
||||
onChange={(e) => onEditorOptionsChange(e.target.value)}
|
||||
placeholder='{"readOnly": false}'
|
||||
className="min-w-0 flex-1 text-xs px-1.5 py-1 rounded border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-700 text-gray-700 dark:text-gray-200 focus:outline-none focus:border-indigo-400 resize-none font-mono"
|
||||
/>
|
||||
<Button
|
||||
shape="circle"
|
||||
variant="plain"
|
||||
type="button"
|
||||
size="sm"
|
||||
title="Build editor options"
|
||||
icon={<FaSlidersH />}
|
||||
onClick={() => setIsEditorOptionsDialogOpen(true)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Editor Script */}
|
||||
|
|
@ -577,14 +596,41 @@ function SortableItem({
|
|||
<span className="text-[10px] text-gray-400 font-medium">
|
||||
{translate('::ListForms.Wizard.Step3.EditorScript')}
|
||||
</span>
|
||||
<input
|
||||
value={item.editorScript}
|
||||
onChange={(e) => onEditorScriptChange(e.target.value)}
|
||||
placeholder="(e) => { /* e.component */ }"
|
||||
className="w-full text-xs px-1.5 py-1 rounded border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-700 text-gray-700 dark:text-gray-200 focus:outline-none focus:border-indigo-400 resize-none font-mono"
|
||||
/>
|
||||
<div className="flex items-center gap-1">
|
||||
<input
|
||||
value={item.editorScript}
|
||||
onChange={(e) => onEditorScriptChange(e.target.value)}
|
||||
placeholder="(e) => { /* e.component */ }"
|
||||
className="min-w-0 flex-1 text-xs px-1.5 py-1 rounded border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-700 text-gray-700 dark:text-gray-200 focus:outline-none focus:border-indigo-400 resize-none font-mono"
|
||||
/>
|
||||
<Button
|
||||
shape="circle"
|
||||
variant="plain"
|
||||
type="button"
|
||||
size="sm"
|
||||
title="Build editor script"
|
||||
icon={<FaCode />}
|
||||
onClick={() => setIsEditorScriptDialogOpen(true)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<EditorOptionsBuilderDialog
|
||||
isOpen={isEditorOptionsDialogOpen}
|
||||
value={item.editorOptions}
|
||||
editorType={item.editorType}
|
||||
onClose={() => setIsEditorOptionsDialogOpen(false)}
|
||||
onApply={onEditorOptionsChange}
|
||||
/>
|
||||
<EditorScriptBuilderDialog
|
||||
isOpen={isEditorScriptDialogOpen}
|
||||
value={item.editorScript}
|
||||
currentField={item.fieldName}
|
||||
fields={editorScriptFields}
|
||||
onClose={() => setIsEditorScriptDialogOpen(false)}
|
||||
onApply={onEditorScriptChange}
|
||||
/>
|
||||
|
||||
{/* Bottom row: ColSpan + Editing Form + Required */}
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex items-center gap-1">
|
||||
|
|
@ -639,6 +685,7 @@ interface GroupCardProps {
|
|||
hasAvailable: boolean
|
||||
dbObjects: SqlObjectExplorerDto | null
|
||||
dsCode: string
|
||||
editorScriptFields: SelectBoxOption[]
|
||||
onCaptionChange: (val: string) => void
|
||||
onColCountChange: (val: number) => void
|
||||
onItemChange: (itemId: string, patch: Partial<WizardGroupItem>) => void
|
||||
|
|
@ -653,6 +700,7 @@ function GroupCard({
|
|||
hasAvailable,
|
||||
dbObjects,
|
||||
dsCode,
|
||||
editorScriptFields,
|
||||
onCaptionChange,
|
||||
onColCountChange,
|
||||
onItemChange,
|
||||
|
|
@ -759,6 +807,7 @@ function GroupCard({
|
|||
groupColCount={group.colCount}
|
||||
dbObjects={dbObjects}
|
||||
dsCode={dsCode}
|
||||
editorScriptFields={editorScriptFields}
|
||||
onCaptionNameChange={(val) => onItemChange(item.id, { captionName: val })}
|
||||
onTurkishCaptionChange={(val) => onItemChange(item.id, { turkishCaption: val })}
|
||||
onEnglishCaptionChange={(val) => onItemChange(item.id, { englishCaption: val })}
|
||||
|
|
@ -809,7 +858,7 @@ const WizardStep3 = ({
|
|||
// 1. Remove items that are no longer in selectedColumns
|
||||
const cleaned = groups.map((g) => ({
|
||||
...g,
|
||||
items: g.items.filter((i) => selectedColumns.has(i.dataField)),
|
||||
items: g.items.filter((i) => selectedColumns.has(i.fieldName)),
|
||||
}))
|
||||
|
||||
// 2. Ensure at least one empty group exists for the user to drag into
|
||||
|
|
@ -835,8 +884,14 @@ const WizardStep3 = ({
|
|||
}, [selectedColumns])
|
||||
|
||||
// ── Available columns = selected but NOT yet placed ───────────────────────
|
||||
const placedColumns = new Set(groups.flatMap((g) => g.items.map((i) => i.dataField)))
|
||||
const placedColumns = new Set(groups.flatMap((g) => g.items.map((i) => i.fieldName)))
|
||||
const availableColumns = [...selectedColumns].filter((c) => !placedColumns.has(c))
|
||||
const editorScriptFields: SelectBoxOption[] = groups.flatMap((group) =>
|
||||
group.items.map((item) => ({
|
||||
value: item.fieldName,
|
||||
label: item.captionName || item.fieldName,
|
||||
})),
|
||||
)
|
||||
|
||||
// ── Helpers ───────────────────────────────────────────────────────────────
|
||||
const colMeta = (name: string) => selectCommandColumns.find((c) => c.columnName === name)
|
||||
|
|
@ -878,7 +933,7 @@ const WizardStep3 = ({
|
|||
}
|
||||
|
||||
const addAllToGroup = (groupId: string) => {
|
||||
const placed = new Set(groups.flatMap((g) => g.items.map((i) => i.dataField)))
|
||||
const placed = new Set(groups.flatMap((g) => g.items.map((i) => i.fieldName)))
|
||||
const toAdd = [...selectedColumns].filter((c) => !placed.has(c))
|
||||
if (toAdd.length === 0) return
|
||||
onGroupsChange(
|
||||
|
|
@ -1018,7 +1073,7 @@ const WizardStep3 = ({
|
|||
<div className="flex items-center gap-2 px-3 py-2 rounded-lg border border-indigo-400 bg-indigo-50 text-sm shadow-lg cursor-grabbing">
|
||||
<FaGripVertical className="text-indigo-300 text-xs" />
|
||||
<span className="text-xs font-semibold text-indigo-600 bg-indigo-100 px-2 py-0.5 rounded">
|
||||
{item.dataField}
|
||||
{item.fieldName}
|
||||
</span>
|
||||
<span className="text-xs text-gray-500">{item.editorType}</span>
|
||||
</div>
|
||||
|
|
@ -1087,6 +1142,7 @@ const WizardStep3 = ({
|
|||
hasAvailable={availableColumns.length > 0}
|
||||
dbObjects={dbObjects}
|
||||
dsCode={dsCode}
|
||||
editorScriptFields={editorScriptFields}
|
||||
onCaptionChange={(val) => updateGroup(group.id, { caption: val })}
|
||||
onColCountChange={(val) => updateGroup(group.id, { colCount: val })}
|
||||
onItemChange={(itemId, patch) => updateItem(group.id, itemId, patch)}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ type PendingLink = {
|
|||
outcome: string
|
||||
} | null
|
||||
|
||||
type RequiredWorkflowField = 'approvalUserFieldName' | 'approvalStatusFieldName'
|
||||
|
||||
const toDesignerCriteria = (items: ListFormWorkflowCriteriaDto[]): WorkflowCriteriaDto[] =>
|
||||
items.map((item) => ({
|
||||
...item,
|
||||
|
|
@ -67,6 +69,9 @@ function WizardStep6({
|
|||
const [dragPreview, setDragPreview] = useState<any>(null)
|
||||
const [canvasZoom, setCanvasZoom] = useState(1)
|
||||
const [designerTab, setDesignerTab] = useState('flow')
|
||||
const [workflowErrors, setWorkflowErrors] = useState<
|
||||
Partial<Record<RequiredWorkflowField, string>>
|
||||
>({})
|
||||
const canvasRef = useRef<HTMLDivElement | null>(null)
|
||||
|
||||
const currentCriteria = useMemo(() => toDesignerCriteria(criteria), [criteria])
|
||||
|
|
@ -91,6 +96,10 @@ function WizardStep6({
|
|||
setCriteriaForm(selected ? toCriteriaForm(selected) : emptyCriteria('Start', listFormCode))
|
||||
}, [currentCriteria, listFormCode, selectedId])
|
||||
|
||||
useEffect(() => {
|
||||
if (criteria.length === 0) setWorkflowErrors({})
|
||||
}, [criteria.length])
|
||||
|
||||
const updateCriteria = (next: WorkflowCriteriaDto[]) => onCriteriaChange(toWizardCriteria(next))
|
||||
|
||||
const saveCriteria = (event: FormEvent<HTMLFormElement>) => {
|
||||
|
|
@ -250,6 +259,26 @@ function WizardStep6({
|
|||
])
|
||||
}
|
||||
|
||||
const continueToTodo = () => {
|
||||
if (criteria.length === 0) {
|
||||
setWorkflowErrors({})
|
||||
onNext()
|
||||
return
|
||||
}
|
||||
|
||||
const requiredMessage = translate('::ListForms.Wizard.Required')
|
||||
const nextErrors: Partial<Record<RequiredWorkflowField, string>> = {}
|
||||
if (!workflow.approvalUserFieldName?.trim()) {
|
||||
nextErrors.approvalUserFieldName = requiredMessage
|
||||
}
|
||||
if (!workflow.approvalStatusFieldName?.trim()) {
|
||||
nextErrors.approvalStatusFieldName = requiredMessage
|
||||
}
|
||||
|
||||
setWorkflowErrors(nextErrors)
|
||||
if (Object.keys(nextErrors).length === 0) onNext()
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex h-[calc(100vh-250px)] min-h-[500px] flex-col overflow-hidden">
|
||||
<div className="flex-1 overflow-y-auto pr-1">
|
||||
|
|
@ -280,33 +309,51 @@ function WizardStep6({
|
|||
'approvalDescriptionFieldName',
|
||||
'::ListForms.ListFormEdit.Workflow.ApprovalDescriptionFieldName',
|
||||
],
|
||||
].map(([name, label]) => (
|
||||
<FormItem key={name} label={translate(label)}>
|
||||
<Field name={name}>
|
||||
{({ field, form }: FieldProps) => (
|
||||
<Select
|
||||
field={field}
|
||||
form={form}
|
||||
isClearable
|
||||
options={columnOptions}
|
||||
value={columnOptions.find(
|
||||
(option) => option.value === (values as any)[name],
|
||||
)}
|
||||
onChange={(option: any) => {
|
||||
form.setFieldValue(field.name, option?.value ?? '')
|
||||
onWorkflowChange({
|
||||
...values,
|
||||
[field.name]: option?.value ?? '',
|
||||
criteria,
|
||||
})
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</FormItem>
|
||||
))}
|
||||
].map(([name, label]) => {
|
||||
const requiredForCriteria =
|
||||
criteria.length > 0 &&
|
||||
(name === 'approvalUserFieldName' || name === 'approvalStatusFieldName')
|
||||
const error = workflowErrors[name as RequiredWorkflowField]
|
||||
|
||||
return (
|
||||
<FormItem
|
||||
key={name}
|
||||
errorMessage={error}
|
||||
invalid={Boolean(error)}
|
||||
label={`${translate(label)}${requiredForCriteria ? ' *' : ''}`}
|
||||
>
|
||||
<Field name={name}>
|
||||
{({ field, form }: FieldProps) => (
|
||||
<Select
|
||||
field={field}
|
||||
form={form}
|
||||
isClearable
|
||||
options={columnOptions}
|
||||
value={columnOptions.find(
|
||||
(option) => option.value === (values as any)[name],
|
||||
)}
|
||||
onChange={(option: any) => {
|
||||
form.setFieldValue(field.name, option?.value ?? '')
|
||||
setWorkflowErrors((current) => ({
|
||||
...current,
|
||||
[field.name]: undefined,
|
||||
}))
|
||||
onWorkflowChange({
|
||||
...values,
|
||||
[field.name]: option?.value ?? '',
|
||||
criteria,
|
||||
})
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</FormItem>
|
||||
)
|
||||
})}
|
||||
<FormItem
|
||||
label={translate('::ListForms.ListFormEdit.Workflow.ApprovalIsFilterUserName')}
|
||||
label={translate(
|
||||
'::ListForms.ListFormEdit.Workflow.ApprovalIsFilterUserName',
|
||||
)}
|
||||
>
|
||||
<Field name="approvalIsFilterUserName">
|
||||
{({ field, form }: FieldProps<boolean>) => (
|
||||
|
|
@ -402,7 +449,7 @@ function WizardStep6({
|
|||
variant="solid"
|
||||
type="button"
|
||||
icon={<FaArrowRight />}
|
||||
onClick={onNext}
|
||||
onClick={continueToTodo}
|
||||
>
|
||||
{translate('::Next') || 'Next'}
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import type { DatabaseColumnDto } from '@/proxy/sql-query-manager/models'
|
|||
import type { SelectBoxOption } from '@/types/shared'
|
||||
import { Field, type FieldProps, useFormikContext } from 'formik'
|
||||
import { useMemo, useState } from 'react'
|
||||
import { FaArrowLeft, FaArrowRight, FaColumns } from 'react-icons/fa'
|
||||
import { FaArrowLeft, FaArrowRight } from 'react-icons/fa'
|
||||
|
||||
interface WizardStep7Props {
|
||||
selectedColumns: Set<string>
|
||||
|
|
@ -25,18 +25,41 @@ const mappings: Array<{
|
|||
| 'todoPriorityExpr'
|
||||
| 'todoCompletedExpr'
|
||||
| 'todoOrderExpr'
|
||||
label: string
|
||||
translationKey: string
|
||||
required?: boolean
|
||||
}> = [
|
||||
{ name: 'todoTitleExpr', label: 'Başlık alanı', required: true },
|
||||
{ name: 'todoStatusExpr', label: 'Kanban / durum alanı', required: true },
|
||||
{ name: 'todoDescriptionExpr', label: 'Açıklama alanı' },
|
||||
{ name: 'todoDueDateExpr', label: 'Termin tarihi alanı' },
|
||||
{ name: 'todoTagExpr', label: 'Etiket alanı' },
|
||||
{ name: 'todoAssigneeExpr', label: 'Atanan kişi alanı' },
|
||||
{ name: 'todoPriorityExpr', label: 'Öncelik alanı' },
|
||||
{ name: 'todoCompletedExpr', label: 'Tamamlandı alanı' },
|
||||
{ name: 'todoOrderExpr', label: 'Kart sıra alanı' },
|
||||
{
|
||||
name: 'todoTitleExpr',
|
||||
translationKey: '::ListForms.ListFormFieldEdit.TodoTitleExpr',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'todoStatusExpr',
|
||||
translationKey: '::ListForms.ListFormFieldEdit.TodoStatusExpr',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'todoDescriptionExpr',
|
||||
translationKey: '::ListForms.ListFormFieldEdit.TodoDescriptionExpr',
|
||||
},
|
||||
{
|
||||
name: 'todoDueDateExpr',
|
||||
translationKey: '::ListForms.ListFormFieldEdit.TodoDueDateExpr',
|
||||
},
|
||||
{ name: 'todoTagExpr', translationKey: '::ListForms.ListFormFieldEdit.TodoTagExpr' },
|
||||
{
|
||||
name: 'todoAssigneeExpr',
|
||||
translationKey: '::ListForms.ListFormFieldEdit.TodoAssigneeExpr',
|
||||
},
|
||||
{
|
||||
name: 'todoPriorityExpr',
|
||||
translationKey: '::ListForms.ListFormFieldEdit.TodoPriorityExpr',
|
||||
},
|
||||
{
|
||||
name: 'todoCompletedExpr',
|
||||
translationKey: '::ListForms.ListFormFieldEdit.TodoCompletedExpr',
|
||||
},
|
||||
{ name: 'todoOrderExpr', translationKey: '::ListForms.ListFormFieldEdit.TodoOrderExpr' },
|
||||
]
|
||||
|
||||
const WizardStep7 = ({
|
||||
|
|
@ -46,7 +69,8 @@ const WizardStep7 = ({
|
|||
onBack,
|
||||
onNext,
|
||||
}: WizardStep7Props) => {
|
||||
const { values, setFieldValue } = useFormikContext<ListFormWizardDto>()
|
||||
const { errors, touched, values, setFieldTouched, setFieldValue, validateForm } =
|
||||
useFormikContext<ListFormWizardDto>()
|
||||
const [validationError, setValidationError] = useState('')
|
||||
const fieldOptions = useMemo<SelectBoxOption[]>(
|
||||
() =>
|
||||
|
|
@ -56,9 +80,15 @@ const WizardStep7 = ({
|
|||
[selectCommandColumns, selectedColumns],
|
||||
)
|
||||
|
||||
const continueToDeploy = () => {
|
||||
if (values.todo && (!values.todoTitleExpr || !values.todoStatusExpr)) {
|
||||
setValidationError('Başlık alanı ve Kanban / durum alanı zorunludur.')
|
||||
const continueToDeploy = async () => {
|
||||
await Promise.all([
|
||||
setFieldTouched('todoTitleExpr', true, false),
|
||||
setFieldTouched('todoStatusExpr', true, false),
|
||||
])
|
||||
const validationErrors = await validateForm()
|
||||
|
||||
if (validationErrors.todoTitleExpr || validationErrors.todoStatusExpr) {
|
||||
setValidationError(translate('::ListForms.ListFormFieldEdit.TodoRequiredFields'))
|
||||
return
|
||||
}
|
||||
setValidationError('')
|
||||
|
|
@ -67,75 +97,63 @@ const WizardStep7 = ({
|
|||
|
||||
return (
|
||||
<div className="pb-20">
|
||||
<div className="mb-5 rounded-xl border border-indigo-200 bg-indigo-50/60 p-4 dark:border-indigo-900 dark:bg-indigo-950/20">
|
||||
<div className="flex items-center gap-2 font-semibold text-indigo-700 dark:text-indigo-300">
|
||||
<FaColumns /> Todo / Kanban ayrıntıları
|
||||
</div>
|
||||
<p className="mt-1 text-sm text-gray-500 dark:text-gray-400">
|
||||
Liste alanlarını Todo kartının başlık, durum ve diğer özellikleriyle eşleştirin.
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3">
|
||||
{mappings.map((mapping) => {
|
||||
const isRequired = Boolean(mapping.required && values.todo)
|
||||
|
||||
{!values.todo ? (
|
||||
<div className="rounded-xl border border-amber-200 bg-amber-50 p-4 text-sm text-amber-700 dark:border-amber-900 dark:bg-amber-950/30 dark:text-amber-200">
|
||||
Todo görünümü liste ayarlarında kapalı. Bu adımı atlayabilir veya önceki adımlardan Todo
|
||||
görünümünü etkinleştirebilirsiniz.
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3">
|
||||
{mappings.map((mapping) => (
|
||||
<FormItem
|
||||
key={mapping.name}
|
||||
label={`${mapping.label}${mapping.required ? ' *' : ''}`}
|
||||
>
|
||||
<Field name={mapping.name}>
|
||||
{({ field, form }: FieldProps) => (
|
||||
<Select
|
||||
field={field}
|
||||
form={form}
|
||||
isClearable={!mapping.required}
|
||||
options={fieldOptions}
|
||||
value={fieldOptions.find((option) => option.value === values[mapping.name])}
|
||||
onChange={(option) => {
|
||||
form.setFieldValue(field.name, option?.value ?? '')
|
||||
setValidationError('')
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</FormItem>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="mt-5 grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<FormItem label="Durum sırası (virgülle ayırın)">
|
||||
<Field
|
||||
name="todoStatusOrder"
|
||||
component={Input}
|
||||
placeholder="Inbox, Today, This Week, This Month, Later, Done"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label="Kartları kolonlar arasında sürüklemeye izin ver">
|
||||
<Field name="todoAllowDragging">
|
||||
{({ field }: FieldProps<boolean>) => (
|
||||
<Checkbox
|
||||
checked={Boolean(field.value)}
|
||||
onChange={(checked) => setFieldValue(field.name, checked)}
|
||||
return (
|
||||
<FormItem
|
||||
key={mapping.name}
|
||||
label={`${translate(mapping.translationKey)}${isRequired ? ' *' : ''}`}
|
||||
invalid={Boolean(touched[mapping.name] && errors[mapping.name])}
|
||||
errorMessage={touched[mapping.name] ? errors[mapping.name] : undefined}
|
||||
>
|
||||
<Field name={mapping.name}>
|
||||
{({ field, form }: FieldProps) => (
|
||||
<Select
|
||||
field={field}
|
||||
form={form}
|
||||
isClearable={!isRequired}
|
||||
options={fieldOptions}
|
||||
value={fieldOptions.find((option) => option.value === values[mapping.name])}
|
||||
onChange={(option) => {
|
||||
form.setFieldValue(field.name, option?.value ?? '')
|
||||
setValidationError('')
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</FormItem>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div className="mt-5 grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<FormItem label={translate('::ListForms.ListFormFieldEdit.TodoStatusOrder')}>
|
||||
<Field
|
||||
name="todoStatusOrder"
|
||||
component={Input}
|
||||
placeholder={translate('::ListForms.ListFormFieldEdit.TodoStatusOrderPlaceholder')}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label={translate('::ListForms.ListFormFieldEdit.TodoAllowDragging')}>
|
||||
<Field name="todoAllowDragging">
|
||||
{({ field }: FieldProps<boolean>) => (
|
||||
<Checkbox
|
||||
checked={Boolean(field.value)}
|
||||
onChange={(checked) => setFieldValue(field.name, checked)}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</FormItem>
|
||||
</div>
|
||||
|
||||
{validationError && <p className="mt-4 text-sm text-red-500">{validationError}</p>}
|
||||
|
||||
<div className="fixed bottom-0 left-0 right-0 z-10 flex h-16 items-center border-t border-gray-200 bg-white px-6 dark:border-gray-700 dark:bg-gray-900">
|
||||
<div className="flex w-full items-center justify-between gap-3">
|
||||
<Button size="sm" variant="default" type="button" icon={<FaArrowLeft />} onClick={onBack}>
|
||||
{translate('::Back') || 'Geri'}
|
||||
{translate('::Back')}
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
|
|
@ -144,7 +162,7 @@ const WizardStep7 = ({
|
|||
icon={<FaArrowRight />}
|
||||
onClick={continueToDeploy}
|
||||
>
|
||||
{translate('::Next') || 'Deploy adımına geç'}
|
||||
{translate('::Next')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -218,7 +218,9 @@ const WizardStep8 = ({
|
|||
...prev,
|
||||
{
|
||||
id: 999,
|
||||
label: `Hata: ${err?.message ?? 'Bilinmeyen hata'}`,
|
||||
label: `${translate('::ListForms.Wizard.Step4.Error')}: ${
|
||||
err?.message ?? translate('::App.Platform.Unknown')
|
||||
}`,
|
||||
status: 'error',
|
||||
},
|
||||
])
|
||||
|
|
@ -231,10 +233,10 @@ const WizardStep8 = ({
|
|||
const totalFields = groups.reduce((acc, g) => acc + g.items.length, 0)
|
||||
const editingFormFields = groups.flatMap((g) =>
|
||||
g.items
|
||||
.filter((item) => item.includeInEditingForm && item.dataField !== values.keyFieldName)
|
||||
.filter((item) => item.includeInEditingForm && item.fieldName !== values.keyFieldName)
|
||||
.map((item) => ({ ...item, groupCaption: g.caption })),
|
||||
)
|
||||
const groupedFieldNames = new Set(groups.flatMap((g) => g.items.map((item) => item.dataField)))
|
||||
const groupedFieldNames = new Set(groups.flatMap((g) => g.items.map((item) => item.fieldName)))
|
||||
const ungroupedSelectedColumns = [...selectedColumns].filter((col) => !groupedFieldNames.has(col))
|
||||
const hasWorkflowFields = Boolean(
|
||||
workflow.approvalUserFieldName ||
|
||||
|
|
@ -387,8 +389,8 @@ const WizardStep8 = ({
|
|||
</span>
|
||||
) : (
|
||||
g.items.map((item) => {
|
||||
const meta = selectCommandColumns.find((c) => c.columnName === item.dataField)
|
||||
const isKeyField = item.dataField === values.keyFieldName
|
||||
const meta = selectCommandColumns.find((c) => c.columnName === item.fieldName)
|
||||
const isKeyField = item.fieldName === values.keyFieldName
|
||||
const isPopupField = item.includeInEditingForm && !isKeyField
|
||||
return (
|
||||
<div
|
||||
|
|
@ -397,7 +399,7 @@ const WizardStep8 = ({
|
|||
>
|
||||
<div className="flex min-w-0 items-center gap-2">
|
||||
<span className="text-xs font-medium text-indigo-600 dark:text-indigo-400 truncate">
|
||||
{item.dataField}
|
||||
{item.fieldName}
|
||||
</span>
|
||||
{meta?.dataType && (
|
||||
<span className="text-[10px] text-gray-400 truncate">
|
||||
|
|
@ -574,17 +576,52 @@ const WizardStep8 = ({
|
|||
{values.todo && (
|
||||
<Section title={translate('::ListForms.ListFormEdit.TabTodo') || 'Todo / Kanban'}>
|
||||
<div className="grid grid-cols-2 gap-x-4">
|
||||
<Row label="Başlık alanı" value={values.todoTitleExpr} />
|
||||
<Row label="Kanban / durum alanı" value={values.todoStatusExpr} />
|
||||
<Row label="Açıklama alanı" value={values.todoDescriptionExpr} />
|
||||
<Row label="Termin tarihi alanı" value={values.todoDueDateExpr} />
|
||||
<Row label="Etiket alanı" value={values.todoTagExpr} />
|
||||
<Row label="Atanan kişi alanı" value={values.todoAssigneeExpr} />
|
||||
<Row label="Öncelik alanı" value={values.todoPriorityExpr} />
|
||||
<Row label="Tamamlandı alanı" value={values.todoCompletedExpr} />
|
||||
<Row label="Kart sıra alanı" value={values.todoOrderExpr} />
|
||||
<Row label="Durum sırası" value={values.todoStatusOrder} />
|
||||
<Row label="Sürükle-bırak" value={values.todoAllowDragging ? 'Aktif' : 'Pasif'} />
|
||||
<Row
|
||||
label={translate('::ListForms.ListFormFieldEdit.TodoTitleExpr')}
|
||||
value={values.todoTitleExpr}
|
||||
/>
|
||||
<Row
|
||||
label={translate('::ListForms.ListFormFieldEdit.TodoStatusExpr')}
|
||||
value={values.todoStatusExpr}
|
||||
/>
|
||||
<Row
|
||||
label={translate('::ListForms.ListFormFieldEdit.TodoDescriptionExpr')}
|
||||
value={values.todoDescriptionExpr}
|
||||
/>
|
||||
<Row
|
||||
label={translate('::ListForms.ListFormFieldEdit.TodoDueDateExpr')}
|
||||
value={values.todoDueDateExpr}
|
||||
/>
|
||||
<Row
|
||||
label={translate('::ListForms.ListFormFieldEdit.TodoTagExpr')}
|
||||
value={values.todoTagExpr}
|
||||
/>
|
||||
<Row
|
||||
label={translate('::ListForms.ListFormFieldEdit.TodoAssigneeExpr')}
|
||||
value={values.todoAssigneeExpr}
|
||||
/>
|
||||
<Row
|
||||
label={translate('::ListForms.ListFormFieldEdit.TodoPriorityExpr')}
|
||||
value={values.todoPriorityExpr}
|
||||
/>
|
||||
<Row
|
||||
label={translate('::ListForms.ListFormFieldEdit.TodoCompletedExpr')}
|
||||
value={values.todoCompletedExpr}
|
||||
/>
|
||||
<Row
|
||||
label={translate('::ListForms.ListFormFieldEdit.TodoOrderExpr')}
|
||||
value={values.todoOrderExpr}
|
||||
/>
|
||||
<Row
|
||||
label={translate('::ListForms.ListFormFieldEdit.TodoStatusOrder')}
|
||||
value={values.todoStatusOrder}
|
||||
/>
|
||||
<Row
|
||||
label={translate('::ListForms.ListFormFieldEdit.TodoAllowDragging')}
|
||||
value={translate(
|
||||
values.todoAllowDragging ? '::App.Status.Active' : '::App.Status.Inactive',
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</Section>
|
||||
)}
|
||||
|
|
@ -643,12 +680,12 @@ const WizardStep8 = ({
|
|||
</span>
|
||||
{isDone && (
|
||||
<span className="text-xs text-emerald-500 font-semibold flex items-center gap-1">
|
||||
<FaCheckCircle /> {translate('::ListForms.Wizard.Step4.Success') || 'Başarılı'}
|
||||
<FaCheckCircle /> {translate('::ListForms.Wizard.Step4.Success')}
|
||||
</span>
|
||||
)}
|
||||
{hasError && (
|
||||
<span className="text-xs text-red-500 font-semibold flex items-center gap-1">
|
||||
<FaExclamationCircle /> {translate('::ListForms.Wizard.Step4.Error') || 'Hata'}
|
||||
<FaExclamationCircle /> {translate('::ListForms.Wizard.Step4.Error')}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -658,7 +695,7 @@ const WizardStep8 = ({
|
|||
<div className="flex flex-col items-center justify-center h-full gap-3 py-10 select-none">
|
||||
<FaRocket className="text-gray-700 text-3xl" />
|
||||
<span className="text-xs text-gray-600 italic text-center">
|
||||
{translate('::ListForms.Wizard.Step4.AllInfoReady') || 'Tüm bilgiler hazır.'}
|
||||
{translate('::ListForms.Wizard.Step4.AllInfoReady')}
|
||||
<br />
|
||||
{translate('::ListForms.Wizard.Step4.DeployStartHint')}
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -90,6 +90,47 @@ interface TableIndex {
|
|||
|
||||
// ─── Constants ────────────────────────────────────────────────────────────────
|
||||
|
||||
const REL_TYPES: { value: RelationshipType; label: string; desc: string }[] = [
|
||||
{ value: 'OneToMany', label: '1 → N', desc: 'Bire-çok' },
|
||||
{ value: 'OneToOne', label: '1 → 1', desc: 'Bire-bir' },
|
||||
]
|
||||
|
||||
const CASCADE_OPTIONS: { value: CascadeBehavior; label: string }[] = [
|
||||
{ value: 'NoAction', label: 'No Action' },
|
||||
{ value: 'Cascade', label: 'Cascade' },
|
||||
{ value: 'SetNull', label: 'Set Null' },
|
||||
{ value: 'Restrict', label: 'Restrict' },
|
||||
]
|
||||
|
||||
const EMPTY_FK: Omit<SqlTableRelation, 'id'> = {
|
||||
relationshipType: 'OneToMany',
|
||||
fkColumnName: '',
|
||||
referencedTable: '',
|
||||
referencedColumn: 'Id',
|
||||
cascadeDelete: 'NoAction',
|
||||
cascadeUpdate: 'Cascade',
|
||||
isRequired: false,
|
||||
description: '',
|
||||
}
|
||||
|
||||
const EMPTY_INDEX: Omit<TableIndex, 'id'> = {
|
||||
indexName: '',
|
||||
indexType: 'Index',
|
||||
isClustered: false,
|
||||
columns: [],
|
||||
description: '',
|
||||
}
|
||||
|
||||
const INDEX_TYPES: { value: IndexType; label: string; desc: string }[] = [
|
||||
{
|
||||
value: 'PrimaryKey',
|
||||
label: 'Primary Key',
|
||||
desc: 'App.SqlQueryManager.IndexType_PrimaryKey_Desc',
|
||||
},
|
||||
{ value: 'UniqueKey', label: 'Unique Key', desc: 'App.SqlQueryManager.IndexType_UniqueKey_Desc' },
|
||||
{ value: 'Index', label: 'Index', desc: 'App.SqlQueryManager.IndexType_Index_Desc' },
|
||||
]
|
||||
|
||||
const DATA_TYPES: { value: SqlDataType; label: string }[] = [
|
||||
{ value: 'nvarchar', label: 'String (nvarchar)' },
|
||||
{ value: 'nvarchar(MAX)', label: 'Text (nvarchar MAX)' },
|
||||
|
|
@ -180,47 +221,6 @@ const FULL_AUDIT_COLUMNS: ColumnDefinition[] = [
|
|||
},
|
||||
]
|
||||
|
||||
const REL_TYPES: { value: RelationshipType; label: string; desc: string }[] = [
|
||||
{ value: 'OneToMany', label: '1 → N', desc: 'Bire-çok' },
|
||||
{ value: 'OneToOne', label: '1 → 1', desc: 'Bire-bir' },
|
||||
]
|
||||
|
||||
const CASCADE_OPTIONS: { value: CascadeBehavior; label: string }[] = [
|
||||
{ value: 'NoAction', label: 'No Action' },
|
||||
{ value: 'Cascade', label: 'Cascade' },
|
||||
{ value: 'SetNull', label: 'Set Null' },
|
||||
{ value: 'Restrict', label: 'Restrict' },
|
||||
]
|
||||
|
||||
const EMPTY_FK: Omit<SqlTableRelation, 'id'> = {
|
||||
relationshipType: 'OneToMany',
|
||||
fkColumnName: '',
|
||||
referencedTable: '',
|
||||
referencedColumn: 'Id',
|
||||
cascadeDelete: 'NoAction',
|
||||
cascadeUpdate: 'Cascade',
|
||||
isRequired: false,
|
||||
description: '',
|
||||
}
|
||||
|
||||
const EMPTY_INDEX: Omit<TableIndex, 'id'> = {
|
||||
indexName: '',
|
||||
indexType: 'Index',
|
||||
isClustered: false,
|
||||
columns: [],
|
||||
description: '',
|
||||
}
|
||||
|
||||
const INDEX_TYPES: { value: IndexType; label: string; desc: string }[] = [
|
||||
{
|
||||
value: 'PrimaryKey',
|
||||
label: 'Primary Key',
|
||||
desc: 'App.SqlQueryManager.IndexType_PrimaryKey_Desc',
|
||||
},
|
||||
{ value: 'UniqueKey', label: 'Unique Key', desc: 'App.SqlQueryManager.IndexType_UniqueKey_Desc' },
|
||||
{ value: 'Index', label: 'Index', desc: 'App.SqlQueryManager.IndexType_Index_Desc' },
|
||||
]
|
||||
|
||||
const TENANT_COLUMN: ColumnDefinition = {
|
||||
id: '__TenantId',
|
||||
columnName: 'TenantId',
|
||||
|
|
@ -232,6 +232,15 @@ const TENANT_COLUMN: ColumnDefinition = {
|
|||
}
|
||||
|
||||
const WORKFLOW_COLUMNS: ColumnDefinition[] = [
|
||||
{
|
||||
id: '__WorkflowId',
|
||||
columnName: 'Id',
|
||||
dataType: 'uniqueidentifier',
|
||||
maxLength: '',
|
||||
isNullable: false,
|
||||
defaultValue: 'NEWID()',
|
||||
description: 'Workflow primary key',
|
||||
},
|
||||
{
|
||||
id: '__ApprovalUserId',
|
||||
columnName: 'ApprovalUserName',
|
||||
|
|
@ -1324,6 +1333,26 @@ const SqlTableDesignerDialog = ({
|
|||
|
||||
const clearAllColumns = () => setColumns([createEmptyColumn()])
|
||||
|
||||
const addAutomaticPrimaryKey = (preset: string, description: string) => {
|
||||
const tableName = settings.tableName || initialTableData?.tableName || 'Table'
|
||||
|
||||
setIndexes((prev) => {
|
||||
if (prev.some((index) => index.indexType === 'PrimaryKey')) return prev
|
||||
|
||||
return [
|
||||
...prev,
|
||||
{
|
||||
id: `auto-${preset}-${crypto.randomUUID()}`,
|
||||
indexName: `PK_${tableName}`,
|
||||
indexType: 'PrimaryKey',
|
||||
isClustered: false,
|
||||
columns: [{ columnName: 'Id', order: 'ASC' }],
|
||||
description,
|
||||
},
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
const addFullAuditedColumns = () => {
|
||||
const existingNames = new Set(columns.map((c) => c.columnName.trim().toLowerCase()))
|
||||
const toAdd = FULL_AUDIT_COLUMNS.filter((c) => !existingNames.has(c.columnName.toLowerCase()))
|
||||
|
|
@ -1332,24 +1361,7 @@ const SqlTableDesignerDialog = ({
|
|||
return [...nonEmpty, ...toAdd.map((c) => ({ ...c })), createEmptyColumn()]
|
||||
})
|
||||
|
||||
// FullAudited ile Id eklendiğinde PK tanımı Index/Key listesine otomatik düşsün.
|
||||
setIndexes((prev) => {
|
||||
const hasPk = prev.some((ix) => ix.indexType === 'PrimaryKey')
|
||||
if (hasPk) return prev
|
||||
|
||||
const tableName = settings.tableName || initialTableData?.tableName || 'Table'
|
||||
return [
|
||||
...prev,
|
||||
{
|
||||
id: `auto-pk-${crypto.randomUUID()}`,
|
||||
indexName: `PK_${tableName}`,
|
||||
indexType: 'PrimaryKey',
|
||||
isClustered: false,
|
||||
columns: [{ columnName: 'Id', order: 'ASC' }],
|
||||
description: 'Primary key (auto)',
|
||||
},
|
||||
]
|
||||
})
|
||||
addAutomaticPrimaryKey('full-audit', 'Full audited primary key (auto)')
|
||||
}
|
||||
|
||||
const addMultiTenantColumns = () => {
|
||||
|
|
@ -1372,6 +1384,8 @@ const SqlTableDesignerDialog = ({
|
|||
return [...nonEmpty, ...toAdd.map((c) => ({ ...c })), createEmptyColumn()]
|
||||
})
|
||||
}
|
||||
|
||||
addAutomaticPrimaryKey('workflow', 'Workflow primary key (auto)')
|
||||
}
|
||||
|
||||
const addTodoColumns = () => {
|
||||
|
|
@ -1385,22 +1399,7 @@ const SqlTableDesignerDialog = ({
|
|||
})
|
||||
}
|
||||
|
||||
setIndexes((prev) => {
|
||||
if (prev.some((index) => index.indexType === 'PrimaryKey')) return prev
|
||||
|
||||
const tableName = settings.tableName || initialTableData?.tableName || 'Table'
|
||||
return [
|
||||
...prev,
|
||||
{
|
||||
id: `auto-todo-pk-${crypto.randomUUID()}`,
|
||||
indexName: `PK_${tableName}`,
|
||||
indexType: 'PrimaryKey',
|
||||
isClustered: false,
|
||||
columns: [{ columnName: 'Id', order: 'ASC' }],
|
||||
description: 'Todo primary key (auto)',
|
||||
},
|
||||
]
|
||||
})
|
||||
addAutomaticPrimaryKey('todo', 'Todo primary key (auto)')
|
||||
}
|
||||
|
||||
const importColumnsFromRememberedCreateTable = async () => {
|
||||
|
|
@ -1511,11 +1510,10 @@ const SqlTableDesignerDialog = ({
|
|||
const syncAutoPkName = (newTableName: string) => {
|
||||
if (!newTableName) return
|
||||
setIndexes((prev) =>
|
||||
prev.map((ix) =>
|
||||
ix.indexType === 'PrimaryKey' && ix.id.startsWith('auto-pk')
|
||||
? { ...ix, indexName: `PK_${newTableName}` }
|
||||
: ix,
|
||||
),
|
||||
prev.map((ix) => {
|
||||
if (!ix.id.startsWith('auto-') || ix.indexType !== 'PrimaryKey') return ix
|
||||
return { ...ix, indexName: `PK_${newTableName}` }
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -1862,12 +1860,12 @@ const SqlTableDesignerDialog = ({
|
|||
<>
|
||||
<div className="flex items-center justify-between py-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<Button size="xs" variant="solid" color="blue-600" onClick={addFullAuditedColumns}>
|
||||
{translate('::App.SqlQueryManager.AddFullAuditedColumns')}
|
||||
</Button>
|
||||
<Button size="xs" variant="solid" color="green-600" onClick={addMultiTenantColumns}>
|
||||
{translate('::App.SqlQueryManager.AddMultiTenantColumns')}
|
||||
</Button>
|
||||
<Button size="xs" variant="solid" color="blue-600" onClick={addFullAuditedColumns}>
|
||||
{translate('::App.SqlQueryManager.AddFullAuditedColumns')}
|
||||
</Button>
|
||||
<Button size="xs" variant="solid" color="indigo-600" onClick={addWorkflowColumns}>
|
||||
{translate('::App.SqlQueryManager.AddWorkflowColumns')}
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ const toCardColumn = (
|
|||
const isImageColumn =
|
||||
typeof column.cellTemplate === 'function' &&
|
||||
Object.prototype.hasOwnProperty.call(column.extras ?? {}, 'imageUploadOptions')
|
||||
const isHtmlColumn = column.colData?.editorType2 === 'dxHtmlEditor'
|
||||
|
||||
return Object.fromEntries(
|
||||
Object.entries({
|
||||
|
|
@ -144,7 +145,14 @@ const toCardColumn = (
|
|||
})
|
||||
return container
|
||||
}
|
||||
: undefined,
|
||||
: isHtmlColumn
|
||||
? (templateOptions: any) => {
|
||||
const templateData = templateOptions?.model ?? templateOptions
|
||||
const container = document.createElement('div')
|
||||
container.innerHTML = String(templateData.field?.value ?? '')
|
||||
return container
|
||||
}
|
||||
: undefined,
|
||||
format: column.format,
|
||||
headerFilter: column.headerFilter,
|
||||
lookup: column.lookup,
|
||||
|
|
@ -1239,7 +1247,6 @@ const CardView = (props: CardViewProps) => {
|
|||
/>
|
||||
<FilterPanel
|
||||
visible={gridDto.gridOptions.filterPanelDto.visible}
|
||||
filterEnabled={gridDto.gridOptions.filterPanelDto.filterEnabled}
|
||||
texts={gridDto.gridOptions.filterPanelDto.texts}
|
||||
/>
|
||||
<HeaderFilter
|
||||
|
|
|
|||
|
|
@ -2,8 +2,17 @@ import type { GridDto, TodoOptionDto } from '@/proxy/form/models'
|
|||
import type { IdentityUserDto } from '@/proxy/admin/models'
|
||||
import type { DataGridRef } from 'devextreme-react/data-grid'
|
||||
import type CustomStore from 'devextreme/data/custom_store'
|
||||
import { HtmlEditor, ImageUpload, Item, MediaResizing, Toolbar } from 'devextreme-react/html-editor'
|
||||
import TagBox from 'devextreme-react/tag-box'
|
||||
import { AVATAR_URL } from '@/constants/app.constant'
|
||||
import {
|
||||
fontFamilyOptions,
|
||||
fontSizeOptions,
|
||||
fontValues,
|
||||
headerOptions,
|
||||
headerValues,
|
||||
sizeValues,
|
||||
} from '@/proxy/reports/data'
|
||||
import dayjs from 'dayjs'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
import { Fragment, useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
|
|
@ -60,6 +69,16 @@ interface UserOption {
|
|||
|
||||
const fieldValue = (row: TodoRow, field?: string) => (field ? row[field] : undefined)
|
||||
|
||||
const htmlToPlainText = (value: unknown) => {
|
||||
const html = String(value ?? '')
|
||||
if (!html) return ''
|
||||
if (typeof document === 'undefined') return html.replace(/<[^>]*>/g, ' ')
|
||||
|
||||
const container = document.createElement('div')
|
||||
container.innerHTML = html
|
||||
return (container.textContent ?? '').replace(/\s+/g, ' ').trim()
|
||||
}
|
||||
|
||||
const textList = (value: unknown) =>
|
||||
Array.isArray(value)
|
||||
? value.map(String)
|
||||
|
|
@ -682,18 +701,51 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
|
|||
<label className={labelClass}>
|
||||
{translate('::ListForms.TodoBoard.Description')}
|
||||
</label>
|
||||
<textarea
|
||||
className={`${inputClass} min-h-36 resize-y`}
|
||||
disabled={!canEdit}
|
||||
<HtmlEditor
|
||||
height={220}
|
||||
placeholder={translate('::ListForms.TodoBoard.DescriptionPlaceholder')}
|
||||
readOnly={!canEdit}
|
||||
value={String(draft[options.descriptionExpr] ?? '')}
|
||||
onChange={(event) =>
|
||||
onValueChanged={(event) =>
|
||||
setDraft((current) => ({
|
||||
...current,
|
||||
[options.descriptionExpr!]: event.target.value,
|
||||
[options.descriptionExpr!]: event.value,
|
||||
}))
|
||||
}
|
||||
/>
|
||||
>
|
||||
<MediaResizing enabled={true} />
|
||||
<ImageUpload fileUploadMode="base64" />
|
||||
<Toolbar multiline>
|
||||
<Item name="undo" />
|
||||
<Item name="redo" />
|
||||
<Item name="separator" />
|
||||
<Item name="size" acceptedValues={sizeValues} options={fontSizeOptions} />
|
||||
<Item name="font" acceptedValues={fontValues} options={fontFamilyOptions} />
|
||||
<Item name="separator" />
|
||||
<Item name="bold" />
|
||||
<Item name="italic" />
|
||||
<Item name="underline" />
|
||||
<Item name="strike" />
|
||||
<Item name="separator" />
|
||||
<Item name="orderedList" />
|
||||
<Item name="bulletList" />
|
||||
<Item name="separator" />
|
||||
<Item name="header" acceptedValues={headerValues} options={headerOptions} />
|
||||
<Item name="separator" />
|
||||
<Item name="color" />
|
||||
<Item name="background" />
|
||||
<Item name="separator" />
|
||||
<Item name="alignLeft" />
|
||||
<Item name="alignCenter" />
|
||||
<Item name="alignRight" />
|
||||
<Item name="alignJustify" />
|
||||
<Item name="separator" />
|
||||
<Item name="link" />
|
||||
<Item name="image" />
|
||||
<Item name="separator" />
|
||||
<Item name="clear" />
|
||||
</Toolbar>
|
||||
</HtmlEditor>
|
||||
</div>
|
||||
)}
|
||||
<div className="grid gap-4 sm:grid-cols-2">
|
||||
|
|
@ -972,9 +1024,9 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
|
|||
</form>
|
||||
) : (
|
||||
<>
|
||||
<h3 className="min-w-0 truncate font-semibold" title={status}>
|
||||
<h4 className="min-w-0 truncate font-sm" title={status}>
|
||||
{status}
|
||||
</h3>
|
||||
</h4>
|
||||
<button
|
||||
type="button"
|
||||
className="rounded p-1 text-gray-400 opacity-0 transition hover:bg-gray-200 hover:text-blue-600 group-hover:opacity-100 dark:hover:bg-gray-700"
|
||||
|
|
@ -1152,7 +1204,7 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
|
|||
</div>
|
||||
{fieldValue(row, options.descriptionExpr) && (
|
||||
<p className="mt-1 line-clamp-2 text-xs leading-5 text-gray-500 dark:text-gray-400">
|
||||
{String(fieldValue(row, options.descriptionExpr))}
|
||||
{htmlToPlainText(fieldValue(row, options.descriptionExpr))}
|
||||
</p>
|
||||
)}
|
||||
{due && (
|
||||
|
|
|
|||
|
|
@ -922,6 +922,10 @@ const useListFormColumns = ({
|
|||
|
||||
column.allowEditing = colData?.allowEditing || colData?.allowAdding
|
||||
|
||||
if (colData.editorType2 === 'dxHtmlEditor') {
|
||||
column.encodeHtml = false
|
||||
}
|
||||
|
||||
// #region lookup ayarlari
|
||||
if (colData.lookupDto?.dataSourceType) {
|
||||
// UiColumnEditorTemplateTypeEnum : None:0, Table:1, TagBox:2
|
||||
|
|
|
|||
Loading…
Reference in a new issue