Agenda ve SchedulerView düzenlemesi

This commit is contained in:
Sedat Öztürk 2026-07-30 22:38:27 +03:00
parent c0033be6f6
commit 6dfe8d22a8
23 changed files with 1078 additions and 644 deletions

View file

@ -10,6 +10,14 @@ public class SchedulerOptionDto
/// </summary> /// </summary>
public string TextExpr { get; set; } public string TextExpr { get; set; }
/// <summary> /// <summary>
/// Kullanıcı adı olarak gösterilecek field adı (örn: "userName")
/// </summary>
public string UserNameExpr { get; set; }
/// <summary>
/// Açıklama olarak gösterilecek field adı (örn: "description")
/// </summary>
public string DescriptionExpr { get; set; }
/// <summary>
/// Başlangıç tarihinin tutulduğu field adı (örn: "startDate") /// Başlangıç tarihinin tutulduğu field adı (örn: "startDate")
/// </summary> /// </summary>
public string StartDateExpr { get; set; } public string StartDateExpr { get; set; }

View file

@ -1530,6 +1530,12 @@
"en": "Development Requests", "en": "Development Requests",
"tr": "Geliştirme Talepleri" "tr": "Geliştirme Talepleri"
}, },
{
"resourceName": "Platform",
"key": "App.Agenda",
"en": "Agenda",
"tr": "Ajanda"
},
{ {
"resourceName": "Platform", "resourceName": "Platform",
"key": "App.Settings", "key": "App.Settings",
@ -4212,6 +4218,24 @@
"en": "Camera Off", "en": "Camera Off",
"tr": "Kamera Kapalı" "tr": "Kamera Kapalı"
}, },
{
"resourceName": "Platform",
"key": "App.Listform.ListformField.AllDay",
"en": "All Day",
"tr": "Tüm Gün"
},
{
"resourceName": "Platform",
"key": "App.Listform.ListformField.RecurrenceRule",
"en": "Recurrence Rule",
"tr": "Tekrarlama Kuralı"
},
{
"resourceName": "Platform",
"key": "App.Listform.ListformField.RecurrenceException",
"en": "Recurrence Exception",
"tr": "Tekrarlama İstisnası"
},
{ {
"resourceName": "Platform", "resourceName": "Platform",
"key": "App.Listform.ListformField.Avatar", "key": "App.Listform.ListformField.Avatar",
@ -19485,8 +19509,8 @@
{ {
"resourceName": "Platform", "resourceName": "Platform",
"key": "ListForms.ListFormFieldEdit.TodoStatusExpr", "key": "ListForms.ListFormFieldEdit.TodoStatusExpr",
"en": "Column / Status Field", "en": "Status Field",
"tr": "Kolon / durum alanı" "tr": "Durum alanı"
}, },
{ {
"resourceName": "Platform", "resourceName": "Platform",

View file

@ -6222,5 +6222,229 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
#endregion #endregion
} }
#endregion #endregion
#region Agenda
listFormName = AppCodes.Agenda;
if (!await _listFormRepository.AnyAsync(a => a.ListFormCode == listFormName))
{
var listForm = await _listFormRepository.InsertAsync(
new ListForm()
{
ListFormType = ListFormTypeEnum.List,
PageSize = 10,
ExportJson = DefaultExportJson,
IsSubForm = false,
ShowNote = false,
LayoutJson = DefaultLayoutJson("scheduler"),
CultureName = LanguageCodes.En,
ListFormCode = listFormName,
Name = listFormName,
Title = listFormName,
DataSourceCode = SeedConsts.DataSources.DefaultCode,
IsTenant = true,
IsBranch = false,
IsOrganizationUnit = false,
Description = listFormName,
SelectCommandType = SelectCommandTypeEnum.Table,
SelectCommand = TableNameResolver.GetFullTableName(nameof(TableNameEnum.Agenda)),
KeyFieldName = "Id",
KeyFieldDbSourceType = DbType.Guid,
DefaultFilter = DefaultFilterJson,
SortMode = GridOptions.SortModeSingle,
FilterRowJson = DefaultFilterRowJson(),
HeaderFilterJson = DefaultHeaderFilterJson(),
SearchPanelJson = DefaultSearchPanelJson(),
GroupPanelJson = DefaultGroupPanelJson(),
SelectionJson = DefaultSelectionSingleJson,
ColumnOptionJson = DefaultColumnOptionJson(),
PermissionJson = DefaultPermissionJson(listFormName),
DeleteCommand = DefaultDeleteCommand(nameof(TableNameEnum.Agenda)),
DeleteFieldsDefaultValueJson = DefaultDeleteFieldsDefaultValueJson(),
PagerOptionJson = DefaultPagerOptionJson,
InsertFieldsDefaultValueJson = DefaultInsertFieldsDefaultValueJson(),
EditingOptionJson = DefaultEditingOptionJson(listFormName, 800, 600, true, true, true, true, false),
EditingFormJson = JsonSerializer.Serialize(new List<EditingFormDto>
{
new() { Order = 1, ColCount = 1, ColSpan = 1, ItemType = "group" },
}),
FormFieldsDefaultValueJson = JsonSerializer.Serialize(new FieldsDefaultValue[] {
new() { FieldName = "UserName", FieldDbType = DbType.String, Value = "@USERNAME", CustomValueType = FieldCustomValueTypeEnum.CustomKey },
new() { FieldName = "AllDay", FieldDbType = DbType.Boolean, Value = "false", CustomValueType = FieldCustomValueTypeEnum.Value },
}),
SchedulerOptionJson = DefaultSchedulerOptionJson()
});
#region Agenda Fields
await _listFormFieldRepository.InsertManyAsync([
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.Guid,
FieldName = "Id",
CaptionName = "App.Listform.ListformField.Id",
Width = 0,
ListOrderNo = 0,
Visible = false,
IsActive = true,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "UserName",
EditGroupOrderNo = 1,
EditOrderNo = 1,
EditorType2 = EditorTypes.dxTextBox,
ColSpan = 1,
CaptionName = "App.Listform.ListformField.UserName",
Width = 0,
ListOrderNo = 1,
Visible = true,
IsActive = true,
AllowSearch = true,
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson,
EditorOptions = EditorOptionValues.Disabled
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "Text",
EditGroupOrderNo = 1,
EditOrderNo = 2,
EditorType2 = EditorTypes.dxTextBox,
ColSpan = 1,
CaptionName = "App.Listform.ListformField.Text",
Width = 0,
ListOrderNo = 2,
Visible = true,
IsActive = true,
AllowSearch = true,
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson,
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "Description",
EditGroupOrderNo = 1,
EditOrderNo = 3,
EditorType2 = EditorTypes.dxTextArea,
ColSpan = 1,
CaptionName = "App.Listform.ListformField.Description",
Width = 0,
ListOrderNo = 3,
Visible = true,
IsActive = true,
AllowSearch = true,
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson,
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.DateTime,
FieldName = "StartDate",
EditGroupOrderNo = 1,
EditOrderNo = 4,
EditorType2 = EditorTypes.dxDateBox,
ColSpan = 1,
CaptionName = "App.Listform.ListformField.StartDate",
Width = 0,
ListOrderNo = 4,
Visible = true,
IsActive = true,
AllowSearch = true,
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.DateTime,
FieldName = "EndDate",
EditGroupOrderNo = 1,
EditOrderNo = 5,
EditorType2 = EditorTypes.dxDateBox,
ColSpan = 1,
CaptionName = "App.Listform.ListformField.EndDate",
Width = 0,
ListOrderNo = 5,
Visible = true,
IsActive = true,
AllowSearch = true,
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "AllDay",
EditGroupOrderNo = 1,
EditOrderNo = 6,
EditorType2 = EditorTypes.dxCheckBox,
ColSpan = 1,
CaptionName = "App.Listform.ListformField.AllDay",
Width = 0,
ListOrderNo = 6,
Visible = true,
IsActive = true,
AllowSearch = true,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "RecurrenceRule",
ColSpan = 1,
CaptionName = "App.Listform.ListformField.RecurrenceRule",
Width = 0,
ListOrderNo = 7,
Visible = true,
IsActive = true,
AllowSearch = true,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "RecurrenceException",
ColSpan = 1,
CaptionName = "App.Listform.ListformField.RecurrenceException",
Width = 0,
ListOrderNo = 8,
Visible = true,
IsActive = true,
AllowSearch = true,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
}
]);
#endregion
}
#endregion
} }
} }

View file

@ -129,6 +129,29 @@ public static class ListFormSeeder_DefaultJsons
StatusOrder = StatusOrder, StatusOrder = StatusOrder,
AllowDragging = AllowDragging AllowDragging = AllowDragging
}); });
public static string DefaultSchedulerOptionJson(
string TextExpr = "Text",
string StartDateExpr = "StartDate",
string EndDateExpr = "EndDate",
string AllDayExpr = "AllDay",
string RecurrenceRuleExpr = "RecurrenceRule",
string RecurrenceExceptionExpr = "RecurrenceException"
) => JsonSerializer.Serialize(new SchedulerOptionDto
{
TextExpr = TextExpr,
StartDateExpr = StartDateExpr,
EndDateExpr = EndDateExpr,
AllDayExpr = AllDayExpr,
RecurrenceRuleExpr = RecurrenceRuleExpr,
RecurrenceExceptionExpr = RecurrenceExceptionExpr,
ShowAllDayPanel = true,
CrossScrollingEnabled = true,
AllowResizing = true,
AllowDragging = true,
AllowDeleting = true,
AllowEditing = true,
AllowAdding = true
});
public static readonly string DefaultPagerOptionJson = JsonSerializer.Serialize(new GridPagerOptionDto public static readonly string DefaultPagerOptionJson = JsonSerializer.Serialize(new GridPagerOptionDto
{ {
Visible = true, Visible = true,

View file

@ -1113,11 +1113,21 @@
"RequiredPermissionName": "App.DevRequest", "RequiredPermissionName": "App.DevRequest",
"IsDisabled": false "IsDisabled": false
}, },
{
"ParentCode": "App.Administration",
"Code": "App.Agenda",
"DisplayName": "App.Agenda",
"Order": 4,
"Url": "/admin/list/App.Agenda",
"Icon": "FcPlanner",
"RequiredPermissionName": "App.Agenda",
"IsDisabled": false
},
{ {
"ParentCode": "App.Administration", "ParentCode": "App.Administration",
"Code": "App.Setting", "Code": "App.Setting",
"DisplayName": "App.Setting", "DisplayName": "App.Setting",
"Order": 4, "Order": 5,
"Url": "/admin/settings", "Url": "/admin/settings",
"Icon": "FcSettings", "Icon": "FcSettings",
"RequiredPermissionName": "App.Setting", "RequiredPermissionName": "App.Setting",
@ -1127,7 +1137,7 @@
"ParentCode": "App.Administration", "ParentCode": "App.Administration",
"Code": "App.Administration.Intranet", "Code": "App.Administration.Intranet",
"DisplayName": "App.Intranet", "DisplayName": "App.Intranet",
"Order": 5, "Order": 6,
"Url": null, "Url": null,
"Icon": "FcConferenceCall", "Icon": "FcConferenceCall",
"RequiredPermissionName": null, "RequiredPermissionName": null,
@ -1177,7 +1187,7 @@
"ParentCode": "App.Administration.Intranet", "ParentCode": "App.Administration.Intranet",
"Code": "App.Intranet.Events.EventCategory", "Code": "App.Intranet.Events.EventCategory",
"DisplayName": "App.Intranet.Events.EventCategory", "DisplayName": "App.Intranet.Events.EventCategory",
"Order": 6, "Order": 5,
"Url": "/admin/list/App.Intranet.Events.EventCategory", "Url": "/admin/list/App.Intranet.Events.EventCategory",
"Icon": "FcTreeStructure", "Icon": "FcTreeStructure",
"RequiredPermissionName": "App.Intranet.Events.EventCategory", "RequiredPermissionName": "App.Intranet.Events.EventCategory",

View file

@ -4734,6 +4734,60 @@
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp|Kurs" "MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Administration",
"Name": "App.Agenda",
"ParentName": null,
"DisplayName": "App.Agenda",
"IsEnabled": true,
"MultiTenancySide": 3,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Administration",
"Name": "App.Agenda.Create",
"ParentName": "App.Agenda",
"DisplayName": "Create",
"IsEnabled": true,
"MultiTenancySide": 3,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Administration",
"Name": "App.Agenda.Update",
"ParentName": "App.Agenda",
"DisplayName": "Update",
"IsEnabled": true,
"MultiTenancySide": 3,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Administration",
"Name": "App.Agenda.Delete",
"ParentName": "App.Agenda",
"DisplayName": "Delete",
"IsEnabled": true,
"MultiTenancySide": 3,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Administration",
"Name": "App.Agenda.Export",
"ParentName": "App.Agenda",
"DisplayName": "Export",
"IsEnabled": true,
"MultiTenancySide": 3,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Administration",
"Name": "App.Agenda.Import",
"ParentName": "App.Agenda",
"DisplayName": "Import",
"IsEnabled": true,
"MultiTenancySide": 3,
"MenuGroup": "Erp|Kurs"
} }
] ]
} }

View file

@ -1,17 +0,0 @@
IF OBJECT_ID(N'[dbo].[Pro_D_Gantt]', 'U') IS NULL
BEGIN
CREATE TABLE [dbo].[Pro_D_Gantt]
(
[Id] uniqueidentifier NOT NULL DEFAULT NEWID(),
[ParentId] uniqueidentifier NULL,
[Title] nvarchar(300) NOT NULL,
[StartDate] datetime2 NOT NULL,
[EndDate] datetime2 NOT NULL,
[Progress] int NOT NULL DEFAULT 0,
CONSTRAINT [PK_Pro_D_Gantt] 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

View file

@ -1,18 +0,0 @@
IF OBJECT_ID(N'[dbo].[Pro_D_Scheduler]', 'U') IS NULL
BEGIN
CREATE TABLE [dbo].[Pro_D_Scheduler]
(
[Id] uniqueidentifier NOT NULL DEFAULT NEWID(),
[Text] nvarchar(300) NOT NULL,
[StartDate] datetime2 NOT NULL,
[EndDate] datetime2 NOT NULL,
[AllDay] bit NOT NULL DEFAULT 0,
[RecurrenceRule] nvarchar(500) NULL,
[RecurrenceException] nvarchar(MAX) NULL,
CONSTRAINT [PK_Pro_D_Scheduler] 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

View file

@ -1,214 +0,0 @@
{
"Wizard": {
"WizardName": "Gantt",
"ListFormCode": "App.Wizard.Gantt",
"MenuCode": "App.Wizard.Gantt",
"MenuOrder": 3,
"IsTenant": false,
"IsBranch": false,
"IsOrganizationUnit": false,
"AllowAdding": true,
"AllowUpdating": true,
"AllowDeleting": true,
"AllowDetail": false,
"ConfirmDelete": true,
"DefaultLayout": "gantt",
"Grid": true,
"Card": true,
"Pivot": true,
"Tree": false,
"Chart": true,
"Gantt": true,
"Scheduler": false,
"Todo": false,
"LanguageTextMenuEn": "Gantt",
"LanguageTextMenuTr": "Gantt",
"LanguageTextTitleEn": "Gantt",
"LanguageTextTitleTr": "Gantt",
"LanguageTextDescEn": "Gantt",
"LanguageTextDescTr": "Gantt",
"LanguageTextMenuParentEn": "Project",
"LanguageTextMenuParentTr": "Project",
"PermissionGroupName": "App.Wizard.Project",
"MenuParentCode": "App.Wizard.Project",
"MenuParentShortName": "Pro",
"MenuParentIcon": "FcVideoProjector",
"MenuIcon": "FcBullish",
"DataSourceCode": "Default",
"DataSourceConnectionString": "",
"SelectCommandType": 1,
"SelectCommand": "Pro_D_Gantt",
"KeyFieldName": "Id",
"KeyFieldDbSourceType": 9,
"TreeOptionDto": {},
"GanttOptionDto": {
"KeyExpr": "Id",
"ParentIdExpr": "ParentId",
"HasItemsExpr": null,
"RootValue": null,
"ExpandedRowKeys": [],
"AutoExpandAll": true,
"RecursiveSelection": false,
"TitleExpr": "Title",
"ScaleType": "weeks",
"StartExpr": "StartDate",
"EndExpr": "EndDate",
"ProgressExpr": "Progress",
"AllowEditing": true,
"AllowTaskAdding": true,
"AllowTaskUpdating": true,
"AllowTaskResourceUpdating": true,
"AllowTaskDeleting": true,
"AllowDependencyAdding": true,
"AllowDependencyDeleting": true,
"AllowResourceAdding": true,
"AllowResourceUpdating": true,
"AllowResourceDeleting": true
},
"SchedulerOptionDto": {},
"TodoOptionDto": {},
"WorkflowDto": {
"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": "ParentId",
"CaptionName": "App.Listform.ListformField.ParentId",
"EditorType": "dxSelectBox",
"EditorOptions": "",
"EditorScript": "",
"ColSpan": 1,
"IsRequired": false,
"IncludeInEditingForm": true,
"DbSourceType": 9,
"TurkishCaption": "Parent Id",
"EnglishCaption": "Parent Id",
"LookupDataSourceType": 2,
"ValueExpr": "Key",
"DisplayExpr": "Name",
"LookupQuery": "SELECT \u0022Id\u0022 AS \u0022Key\u0022, \u0022Title\u0022 AS \u0022Name\u0022 FROM \u0022Pro_D_Gantt\u0022 ORDER BY \u0022Title\u0022;"
},
{
"FieldName": "StartDate",
"CaptionName": "App.Listform.ListformField.StartDate",
"EditorType": "dxDateBox",
"EditorOptions": "",
"EditorScript": "",
"ColSpan": 1,
"IsRequired": true,
"IncludeInEditingForm": true,
"DbSourceType": 6,
"TurkishCaption": "Start Date",
"EnglishCaption": "Start Date",
"LookupDataSourceType": 1,
"ValueExpr": "Key",
"DisplayExpr": "Name",
"LookupQuery": ""
},
{
"FieldName": "EndDate",
"CaptionName": "App.Listform.ListformField.EndDate",
"EditorType": "dxDateBox",
"EditorOptions": "",
"EditorScript": "",
"ColSpan": 1,
"IsRequired": true,
"IncludeInEditingForm": true,
"DbSourceType": 6,
"TurkishCaption": "End Date",
"EnglishCaption": "End Date",
"LookupDataSourceType": 1,
"ValueExpr": "Key",
"DisplayExpr": "Name",
"LookupQuery": ""
},
{
"FieldName": "Progress",
"CaptionName": "App.Listform.ListformField.Progress",
"EditorType": "dxNumberBox",
"EditorOptions": "",
"EditorScript": "",
"ColSpan": 1,
"IsRequired": true,
"IncludeInEditingForm": true,
"DbSourceType": 11,
"TurkishCaption": "Progress",
"EnglishCaption": "Progress",
"LookupDataSourceType": 1,
"ValueExpr": "Key",
"DisplayExpr": "Name",
"LookupQuery": ""
}
]
}
],
"SubForms": [],
"Widgets": []
},
"IsDeletedField": false,
"IsCreatedField": false,
"InsertedRecords": {
"LanguageKeys": [
"App.Wizard.Gantt",
"App.Wizard.Gantt.Title",
"App.Wizard.Gantt.Desc"
],
"PermissionGroupNames": [],
"PermissionNames": [
"App.Wizard.Gantt",
"App.Wizard.Gantt.Create",
"App.Wizard.Gantt.Update",
"App.Wizard.Gantt.Delete",
"App.Wizard.Gantt.Export",
"App.Wizard.Gantt.Import",
"App.Wizard.Gantt.Note"
],
"MenuCodes": [
"App.Wizard.Gantt"
],
"DataSourceCodes": []
}
}

View file

@ -1,230 +0,0 @@
{
"Wizard": {
"WizardName": "Scheduler",
"ListFormCode": "App.Wizard.Scheduler",
"MenuCode": "App.Wizard.Scheduler",
"MenuOrder": 4,
"IsTenant": false,
"IsBranch": false,
"IsOrganizationUnit": false,
"AllowAdding": true,
"AllowUpdating": true,
"AllowDeleting": true,
"AllowDetail": false,
"ConfirmDelete": true,
"DefaultLayout": "scheduler",
"Grid": true,
"Card": true,
"Pivot": true,
"Tree": false,
"Chart": true,
"Gantt": false,
"Scheduler": true,
"Todo": false,
"LanguageTextMenuEn": "Scheduler",
"LanguageTextMenuTr": "Scheduler",
"LanguageTextTitleEn": "Scheduler",
"LanguageTextTitleTr": "Scheduler",
"LanguageTextDescEn": "Scheduler",
"LanguageTextDescTr": "Scheduler",
"LanguageTextMenuParentEn": "Project",
"LanguageTextMenuParentTr": "Project",
"PermissionGroupName": "App.Wizard.Project",
"MenuParentCode": "App.Wizard.Project",
"MenuParentShortName": "Pro",
"MenuParentIcon": "FcVideoProjector",
"MenuIcon": "FaGlassCheers",
"DataSourceCode": "Default",
"DataSourceConnectionString": "",
"SelectCommandType": 1,
"SelectCommand": "Pro_D_Scheduler",
"KeyFieldName": "Id",
"KeyFieldDbSourceType": 9,
"TreeOptionDto": {},
"GanttOptionDto": {},
"SchedulerOptionDto": {
"TextExpr": "Text",
"StartDateExpr": "StartDate",
"EndDateExpr": "EndDate",
"AllDayExpr": "AllDay",
"RecurrenceRuleExpr": "RecurrenceRule",
"RecurrenceExceptionExpr": "RecurrenceException",
"StartDayHour": 8,
"EndDayHour": 20,
"DefaultView": "week",
"ShowAllDayPanel": true,
"CellDuration": 30,
"FirstDayOfWeek": 1,
"CrossScrollingEnabled": true,
"AllowResizing": true,
"AllowDragging": true,
"AllowDeleting": true,
"AllowEditing": true,
"AllowAdding": true
},
"TodoOptionDto": {},
"WorkflowDto": {
"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": "Text",
"CaptionName": "App.Listform.ListformField.Text",
"EditorType": "dxTextBox",
"EditorOptions": "",
"EditorScript": "",
"ColSpan": 1,
"IsRequired": true,
"IncludeInEditingForm": true,
"DbSourceType": 16,
"TurkishCaption": "Text",
"EnglishCaption": "Text",
"LookupDataSourceType": 1,
"ValueExpr": "Key",
"DisplayExpr": "Name",
"LookupQuery": ""
},
{
"FieldName": "StartDate",
"CaptionName": "App.Listform.ListformField.StartDate",
"EditorType": "dxDateBox",
"EditorOptions": "",
"EditorScript": "",
"ColSpan": 1,
"IsRequired": true,
"IncludeInEditingForm": true,
"DbSourceType": 6,
"TurkishCaption": "Start Date",
"EnglishCaption": "Start Date",
"LookupDataSourceType": 1,
"ValueExpr": "Key",
"DisplayExpr": "Name",
"LookupQuery": ""
},
{
"FieldName": "EndDate",
"CaptionName": "App.Listform.ListformField.EndDate",
"EditorType": "dxDateBox",
"EditorOptions": "",
"EditorScript": "",
"ColSpan": 1,
"IsRequired": true,
"IncludeInEditingForm": true,
"DbSourceType": 6,
"TurkishCaption": "End Date",
"EnglishCaption": "End Date",
"LookupDataSourceType": 1,
"ValueExpr": "Key",
"DisplayExpr": "Name",
"LookupQuery": ""
},
{
"FieldName": "AllDay",
"CaptionName": "App.Listform.ListformField.AllDay",
"EditorType": "dxCheckBox",
"EditorOptions": "",
"EditorScript": "",
"ColSpan": 1,
"IsRequired": true,
"IncludeInEditingForm": true,
"DbSourceType": 3,
"TurkishCaption": "All Day",
"EnglishCaption": "All Day",
"LookupDataSourceType": 1,
"ValueExpr": "Key",
"DisplayExpr": "Name",
"LookupQuery": ""
},
{
"FieldName": "RecurrenceRule",
"CaptionName": "App.Listform.ListformField.RecurrenceRule",
"EditorType": "dxTextBox",
"EditorOptions": "",
"EditorScript": "",
"ColSpan": 1,
"IsRequired": false,
"IncludeInEditingForm": true,
"DbSourceType": 16,
"TurkishCaption": "Recurrence Rule",
"EnglishCaption": "Recurrence Rule",
"LookupDataSourceType": 1,
"ValueExpr": "Key",
"DisplayExpr": "Name",
"LookupQuery": ""
},
{
"FieldName": "RecurrenceException",
"CaptionName": "App.Listform.ListformField.RecurrenceException",
"EditorType": "dxTextBox",
"EditorOptions": "",
"EditorScript": "",
"ColSpan": 1,
"IsRequired": false,
"IncludeInEditingForm": true,
"DbSourceType": 16,
"TurkishCaption": "Recurrence Exception",
"EnglishCaption": "Recurrence Exception",
"LookupDataSourceType": 1,
"ValueExpr": "Key",
"DisplayExpr": "Name",
"LookupQuery": ""
}
]
}
],
"SubForms": [],
"Widgets": []
},
"IsDeletedField": false,
"IsCreatedField": false,
"InsertedRecords": {
"LanguageKeys": [
"App.Wizard.Scheduler",
"App.Wizard.Scheduler.Title",
"App.Wizard.Scheduler.Desc",
"App.Listform.ListformField.AllDay",
"App.Listform.ListformField.RecurrenceRule",
"App.Listform.ListformField.RecurrenceException"
],
"PermissionGroupNames": [],
"PermissionNames": [
"App.Wizard.Scheduler",
"App.Wizard.Scheduler.Create",
"App.Wizard.Scheduler.Update",
"App.Wizard.Scheduler.Delete",
"App.Wizard.Scheduler.Export",
"App.Wizard.Scheduler.Import",
"App.Wizard.Scheduler.Note"
],
"MenuCodes": [
"App.Wizard.Scheduler"
],
"DataSourceCodes": []
}
}

View file

@ -96,5 +96,6 @@ public enum TableNameEnum
VideoroomChat, VideoroomChat,
Sequence, Sequence,
DbTableColumn, DbTableColumn,
DevRequest DevRequest,
Agenda
} }

View file

@ -531,6 +531,7 @@ public static class PlatformConsts
} }
public const string DevRequest = Prefix.App + ".DevRequest"; public const string DevRequest = Prefix.App + ".DevRequest";
public const string DevRequests = Prefix.App + ".DevRequests"; public const string DevRequests = Prefix.App + ".DevRequests";
public const string Agenda = Prefix.App + ".Agenda";
} }
public static class AppErrorCodes public static class AppErrorCodes

View file

@ -87,6 +87,7 @@ public static class TableNameResolver
{ nameof(TableNameEnum.VideoroomAttandance), (TablePrefix.TenantByName, MenuPrefix.Administration) }, { nameof(TableNameEnum.VideoroomAttandance), (TablePrefix.TenantByName, MenuPrefix.Administration) },
{ nameof(TableNameEnum.VideoroomChat), (TablePrefix.TenantByName, MenuPrefix.Administration) }, { nameof(TableNameEnum.VideoroomChat), (TablePrefix.TenantByName, MenuPrefix.Administration) },
{ nameof(TableNameEnum.Sequence), (TablePrefix.TenantByName, MenuPrefix.Administration) }, { nameof(TableNameEnum.Sequence), (TablePrefix.TenantByName, MenuPrefix.Administration) },
{ nameof(TableNameEnum.Agenda), (TablePrefix.TenantByName, MenuPrefix.Administration) },
// 🔹 INTRANET TABLOLARI // 🔹 INTRANET TABLOLARI
{ nameof(TableNameEnum.Announcement), (TablePrefix.TenantByName, MenuPrefix.Administration) }, { nameof(TableNameEnum.Announcement), (TablePrefix.TenantByName, MenuPrefix.Administration) },

View file

@ -485,6 +485,7 @@ public static class SeedConsts
} }
public const string DevRequest = Prefix.App + ".DevRequest"; public const string DevRequest = Prefix.App + ".DevRequest";
public const string DevRequests = Prefix.App + ".DevRequests"; public const string DevRequests = Prefix.App + ".DevRequests";
public const string Agenda = Prefix.App + ".Agenda";
} }
public static class DataSources public static class DataSources

View file

@ -0,0 +1,26 @@
using System;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.MultiTenancy;
namespace Sozsoft.Platform.Entities;
public class Agenda : FullAuditedEntity<Guid>, IMultiTenant
{
public Guid? TenantId { get; set; }
public string UserName { get; set; }
public string Text { get; set; }
public string Description { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public bool? AllDay { get; set; }
public string RecurrenceRule { get; set; }
public string RecurrenceException { get; set; }
public Agenda(Guid id)
{
Id = id;
}
}

View file

@ -104,6 +104,7 @@ public class PlatformDbContext :
public DbSet<Sector> Sectors { get; set; } public DbSet<Sector> Sectors { get; set; }
public DbSet<SkillType> SkillTypes { get; set; } public DbSet<SkillType> SkillTypes { get; set; }
public DbSet<DevRequest> DevRequests { get; set; } public DbSet<DevRequest> DevRequests { get; set; }
public DbSet<Agenda> Agendas { get; set; }
// Dynamic Services // Dynamic Services
public DbSet<Skill> Skills { get; set; } public DbSet<Skill> Skills { get; set; }
@ -1581,7 +1582,7 @@ public class PlatformDbContext :
b.Property(x => x.IsActive).HasDefaultValue(true); b.Property(x => x.IsActive).HasDefaultValue(true);
b.Property(x => x.RefreshedAt).HasDefaultValueSql("SYSDATETIME()"); b.Property(x => x.RefreshedAt).HasDefaultValueSql("SYSDATETIME()");
b.Property(x => x.SourceProcedure).HasMaxLength(128); b.Property(x => x.SourceProcedure).HasMaxLength(128);
b.Property(x => x.Note).HasMaxLength(4000); b.Property(x => x.Note).HasMaxLength(4096);
}); });
builder.Entity<DevRequest>(b => builder.Entity<DevRequest>(b =>
@ -1589,18 +1590,32 @@ public class PlatformDbContext :
b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.DevRequest)), Prefix.DbSchema); b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.DevRequest)), Prefix.DbSchema);
b.ConfigureByConvention(); b.ConfigureByConvention();
b.Property(e => e.UserName).HasMaxLength(50).IsRequired(); b.Property(e => e.UserName).HasMaxLength(256).IsRequired();
b.Property(e => e.Title).HasMaxLength(300).IsRequired(); b.Property(e => e.Title).HasMaxLength(512).IsRequired();
b.Property(e => e.Status).HasMaxLength(50).IsRequired(); b.Property(e => e.Status).HasMaxLength(64).IsRequired();
b.Property(e => e.Description).HasColumnType("text"); b.Property(e => e.Description).HasColumnType("text");
b.Property(e => e.Tags).HasMaxLength(300); b.Property(e => e.Tags).HasMaxLength(256);
b.Property(e => e.Assignees).HasMaxLength(300); b.Property(e => e.Assignees).HasMaxLength(512);
b.Property(e => e.Priority).HasMaxLength(50); b.Property(e => e.Priority).HasMaxLength(64);
b.Property(e => e.Completed).HasDefaultValue(false); b.Property(e => e.Completed).HasDefaultValue(false);
b.Property(e => e.SortOrder).HasDefaultValue(0); b.Property(e => e.SortOrder).HasDefaultValue(0);
}); });
builder.Entity<Agenda>(b =>
{
b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.Agenda)), Prefix.DbSchema);
b.ConfigureByConvention();
b.Property(e => e.UserName).HasMaxLength(256).IsRequired();
b.Property(e => e.Text).HasMaxLength(512).IsRequired();
b.Property(e => e.Description).HasColumnType("text");
b.Property(e => e.AllDay).HasDefaultValue(false);
b.Property(e => e.RecurrenceRule).HasMaxLength(512);
b.Property(e => e.RecurrenceException).HasColumnType("text");
});
ConfigureProviderSpecificModel(builder); ConfigureProviderSpecificModel(builder);
} }

View file

@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore;
namespace Sozsoft.Platform.Migrations namespace Sozsoft.Platform.Migrations
{ {
[DbContext(typeof(PlatformDbContext))] [DbContext(typeof(PlatformDbContext))]
[Migration("20260730083424_Initial")] [Migration("20260730174943_Initial")]
partial class Initial partial class Initial
{ {
/// <inheritdoc /> /// <inheritdoc />
@ -679,6 +679,81 @@ namespace Sozsoft.Platform.Migrations
b.ToTable("Sas_H_About", (string)null); b.ToTable("Sas_H_About", (string)null);
}); });
modelBuilder.Entity("Sozsoft.Platform.Entities.Agenda", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<bool?>("AllDay")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false);
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime2")
.HasColumnName("DeletionTime");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<DateTime>("EndDate")
.HasColumnType("datetime2");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<string>("RecurrenceException")
.HasColumnType("text");
b.Property<string>("RecurrenceRule")
.HasMaxLength(512)
.HasColumnType("nvarchar(512)");
b.Property<DateTime>("StartDate")
.HasColumnType("datetime2");
b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier")
.HasColumnName("TenantId");
b.Property<string>("Text")
.IsRequired()
.HasMaxLength(512)
.HasColumnType("nvarchar(512)");
b.Property<string>("UserName")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.HasKey("Id");
b.ToTable("Adm_T_Agenda", (string)null);
});
modelBuilder.Entity("Sozsoft.Platform.Entities.AiBot", b => modelBuilder.Entity("Sozsoft.Platform.Entities.AiBot", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
@ -2045,8 +2120,8 @@ namespace Sozsoft.Platform.Migrations
.HasDefaultValue(500); .HasDefaultValue(500);
b.Property<string>("Note") b.Property<string>("Note")
.HasMaxLength(4000) .HasMaxLength(4096)
.HasColumnType("nvarchar(4000)"); .HasColumnType("nvarchar(max)");
b.Property<bool>("OnlyBaseDefinitions") b.Property<bool>("OnlyBaseDefinitions")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
@ -2223,8 +2298,8 @@ namespace Sozsoft.Platform.Migrations
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
b.Property<string>("Assignees") b.Property<string>("Assignees")
.HasMaxLength(300) .HasMaxLength(512)
.HasColumnType("nvarchar(300)"); .HasColumnType("nvarchar(512)");
b.Property<bool?>("Completed") b.Property<bool?>("Completed")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
@ -2268,8 +2343,8 @@ namespace Sozsoft.Platform.Migrations
.HasColumnName("LastModifierId"); .HasColumnName("LastModifierId");
b.Property<string>("Priority") b.Property<string>("Priority")
.HasMaxLength(50) .HasMaxLength(64)
.HasColumnType("nvarchar(50)"); .HasColumnType("nvarchar(64)");
b.Property<DateTime?>("RequestDate") b.Property<DateTime?>("RequestDate")
.HasColumnType("datetime2"); .HasColumnType("datetime2");
@ -2281,25 +2356,25 @@ namespace Sozsoft.Platform.Migrations
b.Property<string>("Status") b.Property<string>("Status")
.IsRequired() .IsRequired()
.HasMaxLength(50) .HasMaxLength(64)
.HasColumnType("nvarchar(50)"); .HasColumnType("nvarchar(64)");
b.Property<string>("Tags") b.Property<string>("Tags")
.HasMaxLength(300) .HasMaxLength(256)
.HasColumnType("nvarchar(300)"); .HasColumnType("nvarchar(256)");
b.Property<Guid?>("TenantId") b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
b.Property<string>("Title") b.Property<string>("Title")
.IsRequired() .IsRequired()
.HasMaxLength(300) .HasMaxLength(512)
.HasColumnType("nvarchar(300)"); .HasColumnType("nvarchar(512)");
b.Property<string>("UserName") b.Property<string>("UserName")
.IsRequired() .IsRequired()
.HasMaxLength(50) .HasMaxLength(256)
.HasColumnType("nvarchar(50)"); .HasColumnType("nvarchar(256)");
b.HasKey("Id"); b.HasKey("Id");

View file

@ -480,6 +480,33 @@ namespace Sozsoft.Platform.Migrations
table.PrimaryKey("PK_AbpUsers", x => x.Id); table.PrimaryKey("PK_AbpUsers", x => x.Id);
}); });
migrationBuilder.CreateTable(
name: "Adm_T_Agenda",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
UserName = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false),
Text = table.Column<string>(type: "nvarchar(512)", maxLength: 512, nullable: false),
Description = table.Column<string>(type: "text", nullable: true),
StartDate = table.Column<DateTime>(type: "datetime2", nullable: false),
EndDate = table.Column<DateTime>(type: "datetime2", nullable: false),
AllDay = table.Column<bool>(type: "bit", nullable: true, defaultValue: false),
RecurrenceRule = table.Column<string>(type: "nvarchar(512)", maxLength: 512, nullable: true),
RecurrenceException = table.Column<string>(type: "text", nullable: true),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Adm_T_Agenda", x => x.Id);
});
migrationBuilder.CreateTable( migrationBuilder.CreateTable(
name: "Adm_T_Announcement", name: "Adm_T_Announcement",
columns: table => new columns: table => new
@ -1216,7 +1243,7 @@ namespace Sozsoft.Platform.Migrations
IsActive = table.Column<bool>(type: "bit", nullable: false, defaultValue: true), IsActive = table.Column<bool>(type: "bit", nullable: false, defaultValue: true),
RefreshedAt = table.Column<DateTime>(type: "datetime2", nullable: false, defaultValueSql: "SYSDATETIME()"), RefreshedAt = table.Column<DateTime>(type: "datetime2", nullable: false, defaultValueSql: "SYSDATETIME()"),
SourceProcedure = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true), SourceProcedure = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
Note = table.Column<string>(type: "nvarchar(4000)", maxLength: 4000, nullable: true) Note = table.Column<string>(type: "nvarchar(max)", maxLength: 4096, nullable: true)
}, },
constraints: table => constraints: table =>
{ {
@ -1255,15 +1282,15 @@ namespace Sozsoft.Platform.Migrations
{ {
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false), Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
UserName = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false), UserName = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false),
RequestDate = table.Column<DateTime>(type: "datetime2", nullable: true), RequestDate = table.Column<DateTime>(type: "datetime2", nullable: true),
Title = table.Column<string>(type: "nvarchar(300)", maxLength: 300, nullable: false), Title = table.Column<string>(type: "nvarchar(512)", maxLength: 512, nullable: false),
Status = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false), Status = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false),
Description = table.Column<string>(type: "text", nullable: true), Description = table.Column<string>(type: "text", nullable: true),
DueDate = table.Column<DateTime>(type: "datetime2", nullable: true), DueDate = table.Column<DateTime>(type: "datetime2", nullable: true),
Tags = table.Column<string>(type: "nvarchar(300)", maxLength: 300, nullable: true), Tags = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
Assignees = table.Column<string>(type: "nvarchar(300)", maxLength: 300, nullable: true), Assignees = table.Column<string>(type: "nvarchar(512)", maxLength: 512, nullable: true),
Priority = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: true), Priority = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: true),
Completed = table.Column<bool>(type: "bit", nullable: true, defaultValue: false), Completed = table.Column<bool>(type: "bit", nullable: true, defaultValue: false),
SortOrder = table.Column<int>(type: "int", nullable: true, defaultValue: 0), SortOrder = table.Column<int>(type: "int", nullable: true, defaultValue: 0),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false), CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
@ -4381,6 +4408,9 @@ namespace Sozsoft.Platform.Migrations
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "AbpUserTokens"); name: "AbpUserTokens");
migrationBuilder.DropTable(
name: "Adm_T_Agenda");
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "Adm_T_AnnouncementComment"); name: "Adm_T_AnnouncementComment");

View file

@ -676,6 +676,81 @@ namespace Sozsoft.Platform.Migrations
b.ToTable("Sas_H_About", (string)null); b.ToTable("Sas_H_About", (string)null);
}); });
modelBuilder.Entity("Sozsoft.Platform.Entities.Agenda", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<bool?>("AllDay")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false);
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime2")
.HasColumnName("DeletionTime");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<DateTime>("EndDate")
.HasColumnType("datetime2");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<string>("RecurrenceException")
.HasColumnType("text");
b.Property<string>("RecurrenceRule")
.HasMaxLength(512)
.HasColumnType("nvarchar(512)");
b.Property<DateTime>("StartDate")
.HasColumnType("datetime2");
b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier")
.HasColumnName("TenantId");
b.Property<string>("Text")
.IsRequired()
.HasMaxLength(512)
.HasColumnType("nvarchar(512)");
b.Property<string>("UserName")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.HasKey("Id");
b.ToTable("Adm_T_Agenda", (string)null);
});
modelBuilder.Entity("Sozsoft.Platform.Entities.AiBot", b => modelBuilder.Entity("Sozsoft.Platform.Entities.AiBot", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
@ -2042,8 +2117,8 @@ namespace Sozsoft.Platform.Migrations
.HasDefaultValue(500); .HasDefaultValue(500);
b.Property<string>("Note") b.Property<string>("Note")
.HasMaxLength(4000) .HasMaxLength(4096)
.HasColumnType("nvarchar(4000)"); .HasColumnType("nvarchar(max)");
b.Property<bool>("OnlyBaseDefinitions") b.Property<bool>("OnlyBaseDefinitions")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
@ -2220,8 +2295,8 @@ namespace Sozsoft.Platform.Migrations
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
b.Property<string>("Assignees") b.Property<string>("Assignees")
.HasMaxLength(300) .HasMaxLength(512)
.HasColumnType("nvarchar(300)"); .HasColumnType("nvarchar(512)");
b.Property<bool?>("Completed") b.Property<bool?>("Completed")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
@ -2265,8 +2340,8 @@ namespace Sozsoft.Platform.Migrations
.HasColumnName("LastModifierId"); .HasColumnName("LastModifierId");
b.Property<string>("Priority") b.Property<string>("Priority")
.HasMaxLength(50) .HasMaxLength(64)
.HasColumnType("nvarchar(50)"); .HasColumnType("nvarchar(64)");
b.Property<DateTime?>("RequestDate") b.Property<DateTime?>("RequestDate")
.HasColumnType("datetime2"); .HasColumnType("datetime2");
@ -2278,25 +2353,25 @@ namespace Sozsoft.Platform.Migrations
b.Property<string>("Status") b.Property<string>("Status")
.IsRequired() .IsRequired()
.HasMaxLength(50) .HasMaxLength(64)
.HasColumnType("nvarchar(50)"); .HasColumnType("nvarchar(64)");
b.Property<string>("Tags") b.Property<string>("Tags")
.HasMaxLength(300) .HasMaxLength(256)
.HasColumnType("nvarchar(300)"); .HasColumnType("nvarchar(256)");
b.Property<Guid?>("TenantId") b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
b.Property<string>("Title") b.Property<string>("Title")
.IsRequired() .IsRequired()
.HasMaxLength(300) .HasMaxLength(512)
.HasColumnType("nvarchar(300)"); .HasColumnType("nvarchar(512)");
b.Property<string>("UserName") b.Property<string>("UserName")
.IsRequired() .IsRequired()
.HasMaxLength(50) .HasMaxLength(256)
.HasColumnType("nvarchar(50)"); .HasColumnType("nvarchar(256)");
b.HasKey("Id"); b.HasKey("Id");

View file

@ -431,6 +431,8 @@ export interface GanttOptionDto {
export interface SchedulerOptionDto { export interface SchedulerOptionDto {
textExpr?: string textExpr?: string
userNameExpr?: string
descriptionExpr?: string
startDateExpr?: string startDateExpr?: string
endDateExpr?: string endDateExpr?: string
allDayExpr?: string allDayExpr?: string

View file

@ -71,12 +71,26 @@ function FormTabScheduler(props: FormEditProps) {
return null return null
} }
const userNameField = fieldList.find((field) => String(field.value).toLowerCase() === 'username')
const descriptionField = fieldList.find(
(field) => String(field.value).toLowerCase() === 'description',
)
return ( return (
<Formik <Formik
initialValues={listFormValues} initialValues={listFormValues}
validationSchema={validationSchema} validationSchema={validationSchema}
onSubmit={async (values, formikHelpers) => { onSubmit={async (values, formikHelpers) => {
await props.onSubmit(ListFormEditTabs.SchedulerForm, values, formikHelpers) const submittedValues = {
...values,
schedulerOptionDto: {
...values.schedulerOptionDto,
userNameExpr: values.schedulerOptionDto.userNameExpr ?? userNameField?.value,
descriptionExpr: values.schedulerOptionDto.descriptionExpr ?? descriptionField?.value,
},
}
await props.onSubmit(ListFormEditTabs.SchedulerForm, submittedValues, formikHelpers)
}} }}
> >
{({ touched, errors, isSubmitting, values }) => ( {({ touched, errors, isSubmitting, values }) => (
@ -110,6 +124,44 @@ function FormTabScheduler(props: FormEditProps) {
</Field> </Field>
</FormItem> </FormItem>
<FormItem label="User Name">
<Field type="text" name="schedulerOptionDto.userNameExpr">
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
isClearable={true}
options={fieldList}
value={fieldList.find(
(option) =>
option.value ===
(values.schedulerOptionDto.userNameExpr ?? userNameField?.value),
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>
)}
</Field>
</FormItem>
<FormItem label={translate('::ListForms.ListFormFieldEdit.TodoDescriptionExpr')}>
<Field type="text" name="schedulerOptionDto.descriptionExpr">
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
isClearable={true}
options={fieldList}
value={fieldList.find(
(option) =>
option.value ===
(values.schedulerOptionDto.descriptionExpr ?? descriptionField?.value),
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>
)}
</Field>
</FormItem>
<FormItem <FormItem
label={translate('::ListForms.SchedulerOptions.StartDateExpr')} label={translate('::ListForms.SchedulerOptions.StartDateExpr')}
invalid={ invalid={
@ -363,7 +415,14 @@ function FormTabScheduler(props: FormEditProps) {
</FormItem> </FormItem>
</Card> </Card>
</div> </div>
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit" className="my-2"> <Button
block
size="sm"
variant="solid"
loading={isSubmitting}
type="submit"
className="my-2"
>
{isSubmitting ? translate('::Saving') : translate('::Save')} {isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>{' '} </Button>{' '}
</FormContainer> </FormContainer>

View file

@ -439,15 +439,33 @@ const SCHEDULER_COLUMNS: ColumnDefinition[] = [
defaultValue: 'NEWID()', defaultValue: 'NEWID()',
description: 'Scheduler appointment primary key', description: 'Scheduler appointment primary key',
}, },
{
id: '__SchedulerUserName',
columnName: 'UserName',
dataType: 'nvarchar',
maxLength: '256',
isNullable: false,
defaultValue: '',
description: 'Scheduler appointment userName',
},
{ {
id: '__SchedulerText', id: '__SchedulerText',
columnName: 'Text', columnName: 'Text',
dataType: 'nvarchar', dataType: 'nvarchar',
maxLength: '300', maxLength: '512',
isNullable: false, isNullable: false,
defaultValue: '', defaultValue: '',
description: 'Scheduler appointment text', description: 'Scheduler appointment text',
}, },
{
id: '__SchedulerDescription',
columnName: 'Description',
dataType: 'nvarchar(MAX)',
maxLength: '',
isNullable: false,
defaultValue: '',
description: 'Scheduler appointment description',
},
{ {
id: '__SchedulerStartDate', id: '__SchedulerStartDate',
columnName: 'StartDate', columnName: 'StartDate',
@ -479,7 +497,7 @@ const SCHEDULER_COLUMNS: ColumnDefinition[] = [
id: '__SchedulerRecurrenceRule', id: '__SchedulerRecurrenceRule',
columnName: 'RecurrenceRule', columnName: 'RecurrenceRule',
dataType: 'nvarchar', dataType: 'nvarchar',
maxLength: '500', maxLength: '512',
isNullable: true, isNullable: true,
defaultValue: '', defaultValue: '',
description: 'Scheduler recurrence rule', description: 'Scheduler recurrence rule',

View file

@ -1,9 +1,10 @@
import Container from '@/components/shared/Container' import Container from '@/components/shared/Container'
import '@/utils/registerDevExtremeEditors' import '@/utils/registerDevExtremeEditors'
import { APP_NAME, DX_CLASSNAMES } from '@/constants/app.constant' import { APP_NAME, AVATAR_URL, DX_CLASSNAMES } from '@/constants/app.constant'
import { import {
ColumnFormatDto, ColumnFormatDto,
DbTypeEnum, DbTypeEnum,
FieldCustomValueTypeEnum,
GridDto, GridDto,
PlatformEditorTypes, PlatformEditorTypes,
UiLookupDataSourceTypeEnum, UiLookupDataSourceTypeEnum,
@ -17,9 +18,9 @@ import Scheduler, {
Toolbar, Toolbar,
View, View,
} from 'devextreme-react/scheduler' } from 'devextreme-react/scheduler'
import { useCallback, useEffect, useRef, useState } from 'react' import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { Helmet } from 'react-helmet' import { Helmet } from 'react-helmet'
import { getList } from '@/services/form.service' import { getList, getNextSequenceValue } from '@/services/form.service'
import { useListFormCustomDataSource } from './useListFormCustomDataSource' import { useListFormCustomDataSource } from './useListFormCustomDataSource'
import { addCss, addJs, autoNumber, getEditingFormGroups } from './Utils' import { addCss, addJs, autoNumber, getEditingFormGroups } from './Utils'
import { layoutTypes } from '../admin/listForm/edit/types' import { layoutTypes } from '../admin/listForm/edit/types'
@ -29,10 +30,14 @@ import { usePWA } from '@/utils/hooks/usePWA'
import CustomStore from 'devextreme/data/custom_store' import CustomStore from 'devextreme/data/custom_store'
import { Loading } from '@/components/shared' import { Loading } from '@/components/shared'
import { usePermission } from '@/utils/hooks/usePermission' import { usePermission } from '@/utils/hooks/usePermission'
import { RowMode, SimpleItemWithColData } from '../form/types' import { SimpleItemWithColData } from '../form/types'
import { captionize } from 'devextreme/core/utils/inflector' import { captionize } from 'devextreme/core/utils/inflector'
import { formatDate } from 'devextreme/localization' import { formatDate } from 'devextreme/localization'
import type { AppointmentFormOpeningEvent } from 'devextreme/ui/scheduler' import type { AppointmentFormOpeningEvent } from 'devextreme/ui/scheduler'
import type { ValidationRule } from 'devextreme/common'
import { FaAlignLeft, FaClock, FaHeading } from 'react-icons/fa'
import { Avatar } from '@/components/ui'
import { getUsers } from '@/services/identity.service'
interface SchedulerViewProps { interface SchedulerViewProps {
listFormCode: string listFormCode: string
@ -43,12 +48,45 @@ interface SchedulerViewProps {
gridDto?: GridDto gridDto?: GridDto
} }
const isTouchLikeDevice = () =>
typeof window !== 'undefined' &&
(window.matchMedia?.('(pointer: coarse)').matches || window.matchMedia?.('(hover: none)').matches)
const isMobileViewport = () =>
typeof window !== 'undefined' && window.matchMedia?.('(max-width: 767px)').matches
const getEditPopupHeight = (useMobileEditPopup: boolean, isPopupFullScreen: boolean) =>
useMobileEditPopup && isPopupFullScreen ? '100%' : 'auto'
const getEditPopupMaxHeight = (
useMobileEditPopup: boolean,
isPopupFullScreen: boolean,
configuredHeight?: number,
) => {
if (useMobileEditPopup && isPopupFullScreen) {
return '100%'
}
return configuredHeight && configuredHeight > 0 ? configuredHeight : '90vh'
}
const getValueByField = (data: Record<string, any>, field?: string) => {
if (!field) {
return undefined
}
const resolvedField = Object.keys(data).find(
(dataField) => dataField.toLowerCase() === field.toLowerCase(),
)
return resolvedField ? data[resolvedField] : undefined
}
const SchedulerView = (props: SchedulerViewProps) => { const SchedulerView = (props: SchedulerViewProps) => {
const { listFormCode, searchParams, isSubForm, level, gridDto: extGridDto } = props const { listFormCode, searchParams, isSubForm, level, gridDto: extGridDto } = props
const { translate } = useLocalization() const { translate } = useLocalization()
const isPwaMode = usePWA() const isPwaMode = usePWA()
const [mode, setMode] = useState<RowMode>('view') const useMobileEditPopup = isMobileViewport() || isTouchLikeDevice()
const schedulerRef = useRef<SchedulerRef>() const schedulerRef = useRef<SchedulerRef>()
const refListFormCode = useRef('') const refListFormCode = useRef('')
const widgetGroupRef = useRef<HTMLDivElement>(null) const widgetGroupRef = useRef<HTMLDivElement>(null)
@ -59,8 +97,38 @@ const SchedulerView = (props: SchedulerViewProps) => {
const [widgetGroupHeight, setWidgetGroupHeight] = useState(0) const [widgetGroupHeight, setWidgetGroupHeight] = useState(0)
const [currentView, setCurrentView] = useState<string>('week') const [currentView, setCurrentView] = useState<string>('week')
const [isPopupFullScreen, setIsPopupFullScreen] = useState(false) const [isPopupFullScreen, setIsPopupFullScreen] = useState(false)
const [userAvatarUrls, setUserAvatarUrls] = useState<Record<string, string>>({})
const layout = layoutTypes.scheduler || 'scheduler' const layout = layoutTypes.scheduler || 'scheduler'
useEffect(() => {
let cancelled = false
getUsers(0, 1000)
.then((response) => {
if (cancelled) {
return
}
const avatarUrls = (response.data?.items ?? []).reduce<Record<string, string>>(
(result, user) => {
if (user.userName) {
result[user.userName.toLowerCase()] = AVATAR_URL(user.id, user.tenantId)
}
return result
},
{},
)
setUserAvatarUrls(avatarUrls)
})
.catch((error) => console.error('Scheduler user avatars load error:', error))
return () => {
cancelled = true
}
}, [])
useEffect(() => { useEffect(() => {
const initializeScheduler = async () => { const initializeScheduler = async () => {
const response = await getList({ listFormCode }) const response = await getList({ listFormCode })
@ -196,37 +264,155 @@ const SchedulerView = (props: SchedulerViewProps) => {
[gridDto], [gridDto],
) )
const getAppointmentPreviewDetails = useCallback(
(appointmentData: Record<string, any>) => {
const schedulerOptions = gridDto?.gridOptions.schedulerOptionDto
const userNameField =
schedulerOptions?.userNameExpr ??
gridDto?.columnFormats?.find((column) => column.fieldName?.toLowerCase() === 'username')
?.fieldName
const descriptionField =
schedulerOptions?.descriptionExpr ??
gridDto?.columnFormats?.find((column) => column.fieldName?.toLowerCase() === 'description')
?.fieldName
const userName = getValueByField(appointmentData, userNameField)
const description = getValueByField(appointmentData, descriptionField)
if (
(userName === null || userName === undefined) &&
(description === null || description === undefined)
) {
return undefined
}
return {
userName: userName === null || userName === undefined ? undefined : String(userName),
avatarUrl:
userName === null || userName === undefined
? undefined
: userAvatarUrls[String(userName).toLowerCase()],
description:
description === null || description === undefined ? undefined : String(description),
}
},
[gridDto, userAvatarUrls],
)
const renderAppointment = useCallback( const renderAppointment = useCallback(
(data: any) => { (data: any) => {
const appointmentData = data.targetedAppointmentData || data.appointmentData || {} const appointmentData = data.targetedAppointmentData || data.appointmentData || {}
const previewDetails = getAppointmentPreviewDetails(appointmentData)
return ( return (
<> <div className="flex h-full min-w-0 flex-col gap-1 overflow-hidden p-1">
{previewDetails?.userName && (
<div <div
className="dx-scheduler-appointment-title scheduler-appointment-text" className="flex min-w-0 items-center gap-1 self-start rounded-full bg-black/20 px-2 py-0.5 text-[10px] font-semibold"
title={`User Name: ${previewDetails.userName}`}
>
<Avatar
alt={previewDetails.userName}
className="shrink-0"
shape="circle"
size={18}
src={previewDetails.avatarUrl ?? '/img/others/default-profile.png'}
/>
<span className="uppercase opacity-70">User:</span>
<span className="truncate">{previewDetails.userName}</span>
</div>
)}
<div className="min-w-0">
<div className="flex items-center gap-1 text-[9px] font-semibold uppercase opacity-70">
<FaHeading className="shrink-0" />
<span>Text</span>
</div>
<div
className="dx-scheduler-appointment-title scheduler-appointment-text line-clamp-2 whitespace-normal font-semibold leading-tight"
dangerouslySetInnerHTML={{ __html: getAppointmentHtml(appointmentData) }} dangerouslySetInnerHTML={{ __html: getAppointmentHtml(appointmentData) }}
/> />
<div className="dx-scheduler-appointment-content-date">
{getAppointmentTimeText(appointmentData)}
</div> </div>
</>
{previewDetails?.description && (
<div className="min-w-0">
<div className="flex items-center gap-1 text-[9px] font-semibold uppercase opacity-70">
<FaAlignLeft className="shrink-0" />
<span>Description</span>
</div>
<div
className="line-clamp-2 whitespace-normal text-[11px] leading-tight"
title={previewDetails.description}
>
{previewDetails.description}
</div>
</div>
)}
<div className="dx-scheduler-appointment-content-date mt-auto flex items-center gap-1 border-t border-black/10 pt-1 text-[10px] font-medium">
<FaClock className="shrink-0" />
<span>{getAppointmentTimeText(appointmentData)}</span>
</div>
</div>
) )
}, },
[getAppointmentHtml, getAppointmentTimeText], [getAppointmentHtml, getAppointmentPreviewDetails, getAppointmentTimeText],
) )
const renderAppointmentTooltip = useCallback( const renderAppointmentTooltip = useCallback(
(data: any) => { (data: any) => {
const appointmentData = data.targetedAppointmentData || data.appointmentData || {} const appointmentData = data.targetedAppointmentData || data.appointmentData || {}
const previewDetails = getAppointmentPreviewDetails(appointmentData)
return ( return (
<div className="scheduler-appointment-preview flex min-w-72 items-center gap-3 px-4 py-3"> <div className="scheduler-appointment-preview flex w-96 max-w-[calc(100vw-2rem)] items-start gap-3 p-4 text-gray-900 dark:text-gray-100">
<div className="min-w-0 flex-1 text-left"> <div className="min-w-0 flex-1 space-y-3 text-left">
{previewDetails?.userName && (
<div className="flex min-w-0 items-center gap-2">
<Avatar
alt={previewDetails.userName}
className="shrink-0 ring-2 ring-blue-100 dark:ring-blue-900/50"
shape="circle"
size={40}
src={previewDetails.avatarUrl ?? '/img/others/default-profile.png'}
/>
<div className="min-w-0">
<div className="text-[10px] font-semibold uppercase text-gray-500 dark:text-gray-400">
User Name
</div>
<div className="truncate text-sm font-semibold text-gray-900 dark:text-gray-100">
{previewDetails.userName}
</div>
</div>
</div>
)}
<div className="rounded-lg border border-gray-200 bg-gray-50 p-3 dark:border-gray-700 dark:bg-gray-800">
<div className="mb-1 flex items-center gap-1.5 text-[10px] font-semibold uppercase text-gray-500 dark:text-gray-400">
<FaHeading />
<span>Text</span>
</div>
<div <div
className="scheduler-appointment-preview-text font-semibold" className="scheduler-appointment-preview-text text-base font-semibold leading-snug text-gray-900 dark:text-gray-100"
dangerouslySetInnerHTML={{ __html: getAppointmentHtml(appointmentData) }} dangerouslySetInnerHTML={{ __html: getAppointmentHtml(appointmentData) }}
/> />
<div className="text-xs">{getAppointmentTimeText(appointmentData)}</div> </div>
{previewDetails?.description && (
<div className="rounded-lg border border-gray-200 bg-gray-50 p-3 dark:border-gray-700 dark:bg-gray-800">
<div className="mb-1 flex items-center gap-1.5 text-[10px] font-semibold uppercase text-gray-500 dark:text-gray-400">
<FaAlignLeft />
<span>Description</span>
</div>
<div className="max-h-32 overflow-y-auto whitespace-pre-wrap pr-1 text-sm leading-relaxed text-gray-700 dark:text-gray-300">
{previewDetails.description}
</div>
</div>
)}
<div className="flex items-center gap-2 border-t border-gray-200 pt-2 text-xs font-medium text-gray-600 dark:border-gray-700 dark:text-gray-300">
<FaClock className="text-blue-600 dark:text-blue-400" />
<span>{getAppointmentTimeText(appointmentData)}</span>
</div>
</div> </div>
{gridDto?.gridOptions.schedulerOptionDto?.allowDeleting && ( {gridDto?.gridOptions.schedulerOptionDto?.allowDeleting && (
<button <button
@ -245,7 +431,7 @@ const SchedulerView = (props: SchedulerViewProps) => {
</div> </div>
) )
}, },
[getAppointmentHtml, getAppointmentTimeText, gridDto], [getAppointmentHtml, getAppointmentPreviewDetails, getAppointmentTimeText, gridDto],
) )
const onAppointmentFormOpening = useCallback( const onAppointmentFormOpening = useCallback(
@ -258,23 +444,88 @@ const SchedulerView = (props: SchedulerViewProps) => {
(!e.appointmentData.id && !e.appointmentData[gridDto.gridOptions.keyFieldName || 'id']) (!e.appointmentData.id && !e.appointmentData[gridDto.gridOptions.keyFieldName || 'id'])
const currentMode = isNewAppointment ? 'new' : 'edit' const currentMode = isNewAppointment ? 'new' : 'edit'
setMode(currentMode)
// Popup ayarlarını her açılışta yeniden yapılandır if (isNewAppointment) {
e.popup.option( const appointmentData = (e.appointmentData ?? {}) as Record<string, any>
'title', const defaultValues: Record<string, any> = {}
(currentMode === 'new' ? '✚ ' : '🖊️ ') + const sequenceDefaults: Promise<void>[] = []
translate('::' + gridDto.gridOptions.editingOptionDto?.popup?.title),
for (const colFormat of gridDto.columnFormats ?? []) {
const fieldName = colFormat.fieldName
if (
!fieldName ||
colFormat.defaultValue === null ||
colFormat.defaultValue === undefined
) {
continue
}
if (
typeof colFormat.defaultValue === 'string' &&
colFormat.defaultValue === '@AUTONUMBER'
) {
defaultValues[fieldName] = autoNumber()
} else if (colFormat.defaultValueType === FieldCustomValueTypeEnum.Sequence) {
sequenceDefaults.push(
getNextSequenceValue(String(colFormat.defaultValue))
.then((response) => {
const value = response.data
appointmentData[fieldName] = value
e.form.updateData(fieldName, value)
})
.catch((error) => {
console.error('Sequence default value alınamadı:', {
fieldName,
defaultValue: colFormat.defaultValue,
error,
})
}),
) )
e.popup.option('showTitle', gridDto.gridOptions.editingOptionDto?.popup?.showTitle) } else {
e.popup.option('width', gridDto.gridOptions.editingOptionDto?.popup?.width) defaultValues[fieldName] = colFormat.defaultValue
e.popup.option('height', isPopupFullScreen ? '100%' : 'auto') }
e.popup.option( }
'maxHeight',
isPopupFullScreen ? '100%' : gridDto.gridOptions.editingOptionDto?.popup?.height || '90vh', Object.assign(appointmentData, defaultValues)
) e.form.option('formData', {
e.popup.option('resizeEnabled', gridDto.gridOptions.editingOptionDto?.popup?.resizeEnabled) ...(e.form.option('formData') ?? {}),
e.popup.option('fullScreen', isPopupFullScreen) ...appointmentData,
})
void Promise.all(sequenceDefaults)
}
const popupOptions = gridDto.gridOptions.editingOptionDto?.popup
const popupFullScreen =
useMobileEditPopup || isPopupFullScreen || (popupOptions?.fullScreen ?? false)
// Popup ayarlarını Grid ile aynı ölçü ve cihaz kurallarıyla yapılandır.
e.popup.option({
animation: {},
deferRendering: true,
dragEnabled: popupOptions?.dragEnabled,
fullScreen: popupFullScreen,
height: getEditPopupHeight(useMobileEditPopup, popupFullScreen),
hideOnOutsideClick: popupOptions?.hideOnOutsideClick,
maxHeight: getEditPopupMaxHeight(useMobileEditPopup, popupFullScreen, popupOptions?.height),
maxWidth: useMobileEditPopup ? '100%' : popupOptions?.width,
position: useMobileEditPopup
? {
my: 'top center',
at: 'top center',
of: typeof window !== 'undefined' ? window : undefined,
}
: popupOptions?.position,
resizeEnabled: popupOptions?.resizeEnabled,
restorePosition: popupOptions?.restorePosition,
showTitle: popupOptions?.showTitle,
title: (currentMode === 'new' ? '✚ ' : '🖊️ ') + translate('::' + popupOptions?.title),
width: useMobileEditPopup ? '100%' : popupOptions?.width,
wrapperAttr: useMobileEditPopup
? { class: 'dx-scheduler-appointment-popup mobile-edit-popup' }
: undefined,
})
// Toolbar butonlarını ekle // Toolbar butonlarını ekle
e.popup.option('toolbarItems', [ e.popup.option('toolbarItems', [
@ -342,8 +593,8 @@ const SchedulerView = (props: SchedulerViewProps) => {
toolbar: 'top', toolbar: 'top',
location: 'after', location: 'after',
options: { options: {
icon: 'fullscreen', icon: popupFullScreen ? 'collapse' : 'fullscreen',
hint: translate('::Tam Ekran'), hint: popupFullScreen ? translate('::Normal Boyut') : translate('::Tam Ekran'),
stylingMode: 'text', stylingMode: 'text',
onClick: () => { onClick: () => {
// Popup'tan mevcut fullScreen durumunu al // Popup'tan mevcut fullScreen durumunu al
@ -356,19 +607,16 @@ const SchedulerView = (props: SchedulerViewProps) => {
// Popup'ı güncelle // Popup'ı güncelle
e.popup.option('fullScreen', newFullScreenState) e.popup.option('fullScreen', newFullScreenState)
// Width ve height'i da güncelle e.popup.option({
if (newFullScreenState) { height: getEditPopupHeight(useMobileEditPopup, newFullScreenState),
e.popup.option('width', '100%') maxHeight: getEditPopupMaxHeight(
e.popup.option('height', '100%') useMobileEditPopup,
e.popup.option('maxHeight', '100%') newFullScreenState,
} else { popupOptions?.height,
e.popup.option('width', gridDto.gridOptions.editingOptionDto?.popup?.width || 600) ),
e.popup.option('height', 'auto') maxWidth: useMobileEditPopup ? '100%' : popupOptions?.width,
e.popup.option( width: useMobileEditPopup ? '100%' : popupOptions?.width,
'maxHeight', })
gridDto.gridOptions.editingOptionDto?.popup?.height || '90vh',
)
}
}, },
}, },
}, },
@ -423,18 +671,6 @@ const SchedulerView = (props: SchedulerViewProps) => {
} }
} }
// Set defaultValue for @AUTONUMBER fields
if (
typeof listFormField?.defaultValue === 'string' &&
listFormField?.defaultValue === '@AUTONUMBER' &&
currentMode === 'new'
) {
editorOptions = {
...editorOptions,
value: autoNumber(),
}
}
// EditorType belirleme // EditorType belirleme
let editorType: any = i.editorType2 let editorType: any = i.editorType2
if (i.editorType2 === PlatformEditorTypes.dxGridBox) { if (i.editorType2 === PlatformEditorTypes.dxGridBox) {
@ -507,6 +743,9 @@ const SchedulerView = (props: SchedulerViewProps) => {
colSpan: i.colSpan, colSpan: i.colSpan,
editorOptions, editorOptions,
editorScript: i.editorScript, editorScript: i.editorScript,
isRequired:
listFormField.validationRuleDto?.some((rule) => rule.type === 'required') ?? false,
validationRules: (listFormField.validationRuleDto ?? []) as ValidationRule[],
} }
if (i.captionName) { if (i.captionName) {
@ -549,21 +788,23 @@ const SchedulerView = (props: SchedulerViewProps) => {
const groupItems = sortedItems.map(mapFormItem).filter(isVisibleFormItem) const groupItems = sortedItems.map(mapFormItem).filter(isVisibleFormItem)
if (e.itemType !== 'tabbed') { if (e.itemType !== 'tabbed') {
// Grup kullanmadan direkt items'ları ekle - form'un colCount'u geçerli olsun result.push({
result.push(...groupItems) itemType: e.itemType,
colCount: e.colCount || 1,
colSpan: e.colSpan || 1,
caption: e.caption,
items: groupItems,
})
} else if (e.itemType === 'tabbed' && tabbedItems.length > 0 && e === tabbedItems[0]) { } else if (e.itemType === 'tabbed' && tabbedItems.length > 0 && e === tabbedItems[0]) {
// Tabbed için caption OLMAMALI - sadece tabs array içinde title kullan
result.push({ result.push({
itemType: 'tabbed', itemType: 'tabbed',
// colCount tabbed item için OLMAMALI - sadece colSpan colCount: 1,
colSpan: 1, colSpan: 1,
// caption kullanma! Tabs içindeki title'lar yeterli
tabs: tabbedItems.map((tabbedItem: any) => { tabs: tabbedItems.map((tabbedItem: any) => {
// Backend'den gelen colCount ve colSpan değerlerini kullan const effectiveColCount = tabbedItem.colCount || 1
const effectiveColCount = tabbedItem.colCount || 2
return { return {
title: tabbedItem.caption, // Her tab'ın title'ı title: tabbedItem.caption,
colCount: effectiveColCount, colCount: effectiveColCount,
items: tabbedItem.items items: tabbedItem.items
?.sort((a: any, b: any) => ?.sort((a: any, b: any) =>
@ -578,46 +819,68 @@ const SchedulerView = (props: SchedulerViewProps) => {
}) })
} }
// Form'u tamamen yeniden yapılandır e.form.option('colCount', 1)
const hasTabbedItems = result.some((item: any) => item.itemType === 'tabbed')
// Form'u tamamen yeniden baştan yapılandır
e.form.option(
'colCount',
hasTabbedItems ? 1 : getEditingFormGroups(gridDto)?.[0]?.colCount || 2,
)
e.form.option(
'colCount',
hasTabbedItems ? 1 : getEditingFormGroups(gridDto)?.[0]?.colCount || 2,
)
e.form.option('showValidationSummary', false) e.form.option('showValidationSummary', false)
e.form.option('items', result) e.form.option('items', result)
// Yeni versiyonlarda bu şekilde Style değiştirme işlemi yapmak zorunda olmayabiliriz.
// Yani geçici olarak eklenmiştir.
// Tabbed varsa belirli class'lara sahip elementi bul ve flex-direction'ı değiştir
if (hasTabbedItems) {
setTimeout(() => {
const targetElement = document.querySelector(
'.dx-item-content.dx-box-item-content.dx-box-flex.dx-box.dx-widget.dx-collection',
)
if (targetElement) {
const htmlElement = targetElement as HTMLElement
// Mevcut style'ı al ve flex-direction: row'u column'a çevir
const currentStyle = htmlElement.getAttribute('style') || ''
const updatedStyle = currentStyle.replace(
/flex-direction:\s*row/gi,
'flex-direction: column',
)
htmlElement.setAttribute('style', updatedStyle)
}
}, 100)
}
}, },
[gridDto, translate, isPopupFullScreen, listFormCode], [gridDto, translate, isPopupFullScreen, listFormCode, useMobileEditPopup],
) )
const configuredEditPopup = gridDto?.gridOptions.editingOptionDto?.popup
const schedulerPopupFullScreen =
useMobileEditPopup || isPopupFullScreen || (configuredEditPopup?.fullScreen ?? false)
const schedulerPopupWidth = useMobileEditPopup ? '100%' : configuredEditPopup?.width
const schedulerEditingPopup = useMemo(
() =>
configuredEditPopup
? {
animation: {},
deferRendering: true,
dragEnabled: configuredEditPopup.dragEnabled,
fullScreen: schedulerPopupFullScreen,
height: getEditPopupHeight(useMobileEditPopup, schedulerPopupFullScreen),
hideOnOutsideClick: configuredEditPopup.hideOnOutsideClick,
maxHeight: getEditPopupMaxHeight(
useMobileEditPopup,
schedulerPopupFullScreen,
configuredEditPopup.height,
),
maxWidth: schedulerPopupWidth,
position: useMobileEditPopup
? {
my: 'top center',
at: 'top center',
of: typeof window !== 'undefined' ? window : undefined,
}
: configuredEditPopup.position,
resizeEnabled: configuredEditPopup.resizeEnabled,
restorePosition: configuredEditPopup.restorePosition,
width: schedulerPopupWidth,
wrapperAttr: useMobileEditPopup
? { class: 'dx-scheduler-appointment-popup mobile-edit-popup' }
: undefined,
onShowing: (event: any) => {
event.component.option({
fullScreen: schedulerPopupFullScreen,
height: getEditPopupHeight(useMobileEditPopup, schedulerPopupFullScreen),
maxHeight: getEditPopupMaxHeight(
useMobileEditPopup,
schedulerPopupFullScreen,
configuredEditPopup.height,
),
maxWidth: schedulerPopupWidth,
width: schedulerPopupWidth,
})
},
}
: undefined,
[configuredEditPopup, schedulerPopupFullScreen, schedulerPopupWidth, useMobileEditPopup],
)
const schedulerDescriptionExpr =
gridDto?.gridOptions.schedulerOptionDto?.descriptionExpr ??
gridDto?.columnFormats?.find((column) => column.fieldName?.toLowerCase() === 'description')
?.fieldName
return ( return (
<> <>
<div ref={widgetGroupRef} className={(gridDto?.widgets?.length ?? 0) > 0 ? 'mt-2' : ''}> <div ref={widgetGroupRef} className={(gridDto?.widgets?.length ?? 0) > 0 ? 'mt-2' : ''}>
@ -652,6 +915,7 @@ const SchedulerView = (props: SchedulerViewProps) => {
className="list-view-toolbar-host" className="list-view-toolbar-host"
dataSource={schedulerDataSource} dataSource={schedulerDataSource}
dateSerializationFormat="yyyy-MM-ddTHH:mm:ss" dateSerializationFormat="yyyy-MM-ddTHH:mm:ss"
descriptionExpr={schedulerDescriptionExpr}
textExpr={gridDto.gridOptions.schedulerOptionDto?.textExpr || 'text'} textExpr={gridDto.gridOptions.schedulerOptionDto?.textExpr || 'text'}
startDateExpr={gridDto.gridOptions.schedulerOptionDto?.startDateExpr || 'startDate'} startDateExpr={gridDto.gridOptions.schedulerOptionDto?.startDateExpr || 'startDate'}
endDateExpr={gridDto.gridOptions.schedulerOptionDto?.endDateExpr || 'endDate'} endDateExpr={gridDto.gridOptions.schedulerOptionDto?.endDateExpr || 'endDate'}
@ -736,10 +1000,12 @@ const SchedulerView = (props: SchedulerViewProps) => {
<Editing <Editing
allowAdding={gridDto.gridOptions.schedulerOptionDto?.allowAdding ?? false} allowAdding={gridDto.gridOptions.schedulerOptionDto?.allowAdding ?? false}
allowUpdating={gridDto.gridOptions.schedulerOptionDto?.allowEditing ?? false}
allowDeleting={gridDto.gridOptions.schedulerOptionDto?.allowDeleting ?? false} allowDeleting={gridDto.gridOptions.schedulerOptionDto?.allowDeleting ?? false}
allowResizing={gridDto.gridOptions.schedulerOptionDto?.allowResizing ?? false}
allowDragging={gridDto.gridOptions.schedulerOptionDto?.allowDragging ?? false} allowDragging={gridDto.gridOptions.schedulerOptionDto?.allowDragging ?? false}
allowResizing={gridDto.gridOptions.schedulerOptionDto?.allowResizing ?? false}
allowUpdating={gridDto.gridOptions.schedulerOptionDto?.allowEditing ?? false}
form={{ colCount: 1 }}
popup={schedulerEditingPopup}
/> />
<View <View