diff --git a/api/modules/Sozsoft.MailQueue/Domain.Shared/MailQueueWorkerOptions.cs b/api/modules/Sozsoft.MailQueue/Domain.Shared/MailQueueWorkerOptions.cs index f6d9790..53f948c 100644 --- a/api/modules/Sozsoft.MailQueue/Domain.Shared/MailQueueWorkerOptions.cs +++ b/api/modules/Sozsoft.MailQueue/Domain.Shared/MailQueueWorkerOptions.cs @@ -5,6 +5,6 @@ public class MailQueueWorkerOptions public string MailType { get; set; } // Template Tipi public string MailSubject { get; set; } // Mail konusu public string MailTemplate { get; set; } // Render edilecek html template - public string Tablo { get; set; } // Bu maildeki tablolar örn. {0:MT3_GECIKEN_SIPARIS:IN:Order Delay Notification:0:} + public string TableName { get; set; } // Bu maildeki tablolar örn. {0:MT3_GECIKEN_SIPARIS:IN:Order Delay Notification:0:} } diff --git a/api/src/Sozsoft.Platform.Application/ListForms/ListFormWizardAppService.cs b/api/src/Sozsoft.Platform.Application/ListForms/ListFormWizardAppService.cs index 41a4f49..ca891a7 100644 --- a/api/src/Sozsoft.Platform.Application/ListForms/ListFormWizardAppService.cs +++ b/api/src/Sozsoft.Platform.Application/ListForms/ListFormWizardAppService.cs @@ -296,10 +296,10 @@ public class ListFormWizardAppService( KeyFieldDbSourceType = input.KeyFieldDbSourceType, DefaultFilter = isDeleted ? WizardConsts.DefaultFilterJson : null, SortMode = PlatformConsts.GridOptions.SortModeSingle, - FilterRowJson = WizardConsts.DefaultFilterRowJson, - HeaderFilterJson = WizardConsts.DefaultHeaderFilterJson, - SearchPanelJson = WizardConsts.DefaultSearchPanelJson, - GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }), + FilterRowJson = WizardConsts.DefaultFilterRowJson(), + HeaderFilterJson = WizardConsts.DefaultHeaderFilterJson(), + SearchPanelJson = WizardConsts.DefaultSearchPanelJson(), + GroupPanelJson = WizardConsts.DefaultGroupPanelJson(), SelectionJson = WizardConsts.DefaultSelectionSingleJson(input.WorkflowCriteria.Count > 0 ? PlatformConsts.GridOptions.SelectionModeSingle : PlatformConsts.GridOptions.SelectionModeNone), ColumnOptionJson = WizardConsts.DefaultColumnOptionJson(), PermissionJson = WizardConsts.DefaultPermissionJson(code), diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/HostData.json b/api/src/Sozsoft.Platform.DbMigrator/Seeds/HostData.json index e165163..5daded9 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/HostData.json +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/HostData.json @@ -1146,7 +1146,7 @@ { "name": "AI Save DbTableColumns", "cron": "0 3 * * *", - "workerType": "BackupWorker", + "workerType": "SqlWorker", "isActive": true, "dataSourceCode": "Default", "beforeSp": "Sas_H_ListFormFieldsDictionaryJson_SaveDbTableColumns" diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Administration.cs b/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Administration.cs index ce1598e..7aac54b 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Administration.cs +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Administration.cs @@ -1426,7 +1426,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep FilterRowJson = DefaultFilterRowJson(), HeaderFilterJson = DefaultHeaderFilterJson(), SearchPanelJson = DefaultSearchPanelJson(), - GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }), + GroupPanelJson = DefaultGroupPanelJson(), SelectionJson = DefaultSelectionSingleJson, ColumnOptionJson = DefaultColumnOptionJson(), PermissionJson = DefaultPermissionJson(listFormName), diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Saas.cs b/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Saas.cs index 97a738e..0837227 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Saas.cs +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Saas.cs @@ -1395,8 +1395,8 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency SortMode = GridOptions.SortModeSingle, FilterRowJson = DefaultFilterRowJson(), HeaderFilterJson = DefaultHeaderFilterJson(), - SearchPanelJson = JsonSerializer.Serialize(new { Visible = false }), - GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }), + SearchPanelJson = DefaultSearchPanelJson(), + GroupPanelJson = DefaultGroupPanelJson(), SelectionJson = DefaultSelectionSingleJson, ColumnOptionJson = DefaultColumnOptionJson(), PermissionJson = DefaultPermissionJson(listFormName), @@ -1509,7 +1509,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency FilterRowJson = DefaultFilterRowJson(), HeaderFilterJson = DefaultHeaderFilterJson(), SearchPanelJson = DefaultSearchPanelJson(), - GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }), + GroupPanelJson = DefaultGroupPanelJson(), SelectionJson = DefaultSelectionSingleJson, ColumnOptionJson = DefaultColumnOptionJson(), PermissionJson = DefaultPermissionJson(listFormName), @@ -1658,7 +1658,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency FilterRowJson = DefaultFilterRowJson(), HeaderFilterJson = DefaultHeaderFilterJson(), SearchPanelJson = DefaultSearchPanelJson(), - GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }), + GroupPanelJson = DefaultGroupPanelJson(), SelectionJson = DefaultSelectionSingleJson, ColumnOptionJson = DefaultColumnOptionJson(), PermissionJson = DefaultPermissionJson(listFormName), @@ -1748,7 +1748,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency FilterRowJson = DefaultFilterRowJson(), HeaderFilterJson = DefaultHeaderFilterJson(), SearchPanelJson = DefaultSearchPanelJson(), - GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }), + GroupPanelJson = DefaultGroupPanelJson(), SelectionJson = DefaultSelectionSingleJson, ColumnOptionJson = DefaultColumnOptionJson(), PermissionJson = DefaultPermissionJson(listFormName), @@ -1948,7 +1948,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency FilterRowJson = DefaultFilterRowJson(), HeaderFilterJson = DefaultHeaderFilterJson(), SearchPanelJson = DefaultSearchPanelJson(), - GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }), + GroupPanelJson = DefaultGroupPanelJson(), SelectionJson = DefaultSelectionSingleJson, ColumnOptionJson = DefaultColumnOptionJson(), PermissionJson = DefaultPermissionJson(listFormName), @@ -2084,7 +2084,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency FilterRowJson = DefaultFilterRowJson(), HeaderFilterJson = DefaultHeaderFilterJson(), SearchPanelJson = DefaultSearchPanelJson(), - GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }), + GroupPanelJson = DefaultGroupPanelJson(), SelectionJson = DefaultSelectionSingleJson, ColumnOptionJson = DefaultColumnOptionJson(), PermissionJson = DefaultPermissionJson(listFormName), @@ -2249,7 +2249,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency FilterRowJson = DefaultFilterRowJson(), HeaderFilterJson = DefaultHeaderFilterJson(), SearchPanelJson = DefaultSearchPanelJson(), - GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }), + GroupPanelJson = DefaultGroupPanelJson(), SelectionJson = DefaultSelectionSingleJson, ColumnOptionJson = DefaultColumnOptionJson(), PermissionJson = DefaultPermissionJson(listFormName), @@ -2556,8 +2556,8 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency SortMode = GridOptions.SortModeSingle, FilterRowJson = DefaultFilterRowJson(), HeaderFilterJson = DefaultHeaderFilterJson(), - SearchPanelJson = JsonSerializer.Serialize(new { Visible = false }), - GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }), + SearchPanelJson = DefaultSearchPanelJson(), + GroupPanelJson = DefaultGroupPanelJson(), SelectionJson = DefaultSelectionSingleJson, ColumnOptionJson = DefaultColumnOptionJson(), PermissionJson = DefaultPermissionJson(listFormName), @@ -2854,7 +2854,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency FilterRowJson = DefaultFilterRowJson(), HeaderFilterJson = DefaultHeaderFilterJson(), SearchPanelJson = DefaultSearchPanelJson(), - GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }), + GroupPanelJson = DefaultGroupPanelJson(), SelectionJson = DefaultSelectionSingleJson, ColumnOptionJson = DefaultColumnOptionJson(), PermissionJson = DefaultPermissionJson(listFormName), @@ -4577,7 +4577,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency FilterRowJson = DefaultFilterRowJson(), HeaderFilterJson = DefaultHeaderFilterJson(), SearchPanelJson = DefaultSearchPanelJson(), - GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }), + GroupPanelJson = DefaultGroupPanelJson(), SelectionJson = DefaultSelectionSingleJson, ColumnOptionJson = DefaultColumnOptionJson(), PermissionJson = DefaultPermissionJson(listFormName), @@ -5155,8 +5155,8 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency new() { Order=2,ColCount=2,ColSpan=1,ItemType="group",Items= [ new EditingFormItemDto { Order = 1, DataField = "Options:MailType", ColSpan = 1, EditorType2=EditorTypes.dxTextBox }, new EditingFormItemDto { Order = 2, DataField = "Options:MailSubject", ColSpan = 1, EditorType2=EditorTypes.dxTextBox }, - new EditingFormItemDto { Order = 3, DataField = "Options:MailTemplate", ColSpan = 2, EditorType2=EditorTypes.dxTextArea, EditorOptions="{\"height\":200}" }, - new EditingFormItemDto { Order = 4, DataField = "Options:Tablo", ColSpan = 2, EditorType2=EditorTypes.dxTextBox }, + new EditingFormItemDto { Order = 3, DataField = "Options:MailTemplate", ColSpan = 2, EditorType2=EditorTypes.dxHtmlEditor, EditorOptions=EditorOptionValues.HtmlEditorOptions }, + new EditingFormItemDto { Order = 4, DataField = "Options:TableName", ColSpan = 2, EditorType2=EditorTypes.dxTextBox }, ]} }), InsertFieldsDefaultValueJson = DefaultInsertFieldsDefaultValueJson(), @@ -5521,7 +5521,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency FilterRowJson = DefaultFilterRowJson(), HeaderFilterJson = DefaultHeaderFilterJson(), SearchPanelJson = DefaultSearchPanelJson(), - GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }), + GroupPanelJson = DefaultGroupPanelJson(), SelectionJson = DefaultSelectionSingleJson, ColumnOptionJson = DefaultColumnOptionJson(), PermissionJson = DefaultPermissionJson(listFormName), @@ -5730,7 +5730,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency FilterRowJson = DefaultFilterRowJson(), HeaderFilterJson = DefaultHeaderFilterJson(), SearchPanelJson = DefaultSearchPanelJson(), - GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }), + GroupPanelJson = DefaultGroupPanelJson(), SelectionJson = DefaultSelectionSingleJson, ColumnOptionJson = DefaultColumnOptionJson(), PermissionJson = DefaultPermissionJson(listFormName), @@ -6370,7 +6370,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency FilterRowJson = DefaultFilterRowJson(), HeaderFilterJson = DefaultHeaderFilterJson(), SearchPanelJson = DefaultSearchPanelJson(), - GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }), + GroupPanelJson = DefaultGroupPanelJson(), SelectionJson = DefaultSelectionSingleJson, ColumnOptionJson = DefaultColumnOptionJson(), PermissionJson = DefaultPermissionJson(listFormName), @@ -6625,7 +6625,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency FilterRowJson = DefaultFilterRowJson(), HeaderFilterJson = DefaultHeaderFilterJson(), SearchPanelJson = DefaultSearchPanelJson(), - GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }), + GroupPanelJson = DefaultGroupPanelJson(), SelectionJson = DefaultSelectionSingleJson, ColumnOptionJson = DefaultColumnOptionJson(), PermissionJson = DefaultPermissionJson(listFormName), @@ -6760,7 +6760,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency FilterRowJson = DefaultFilterRowJson(), HeaderFilterJson = DefaultHeaderFilterJson(), SearchPanelJson = DefaultSearchPanelJson(), - GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }), + GroupPanelJson = DefaultGroupPanelJson(), SelectionJson = DefaultSelectionSingleJson, ColumnOptionJson = DefaultColumnOptionJson(), PermissionJson = DefaultPermissionJson(listFormName), @@ -6895,7 +6895,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency FilterRowJson = DefaultFilterRowJson(), HeaderFilterJson = DefaultHeaderFilterJson(), SearchPanelJson = DefaultSearchPanelJson(), - GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }), + GroupPanelJson = DefaultGroupPanelJson(), SelectionJson = DefaultSelectionSingleJson, ColumnOptionJson = DefaultColumnOptionJson(), PermissionJson = DefaultPermissionJson(listFormName), @@ -8151,7 +8151,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency FilterRowJson = DefaultFilterRowJson(), HeaderFilterJson = DefaultHeaderFilterJson(), SearchPanelJson = DefaultSearchPanelJson(), - GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }), + GroupPanelJson = DefaultGroupPanelJson(), SelectionJson = DefaultSelectionSingleJson, ColumnOptionJson = DefaultColumnOptionJson(), PermissionJson = DefaultPermissionJson(listFormName), diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/WizardDataSeeder.cs b/api/src/Sozsoft.Platform.DbMigrator/Seeds/WizardDataSeeder.cs index a5d3b51..fb4fb49 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/WizardDataSeeder.cs +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/WizardDataSeeder.cs @@ -408,10 +408,10 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency KeyFieldDbSourceType = input.KeyFieldDbSourceType, DefaultFilter = isDeleted ? WizardConsts.DefaultFilterJson : null, SortMode = GridOptions.SortModeSingle, - FilterRowJson = WizardConsts.DefaultFilterRowJson, - HeaderFilterJson = WizardConsts.DefaultHeaderFilterJson, - SearchPanelJson = WizardConsts.DefaultSearchPanelJson, - GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }), + FilterRowJson = WizardConsts.DefaultFilterRowJson(), + HeaderFilterJson = WizardConsts.DefaultHeaderFilterJson(), + SearchPanelJson = WizardConsts.DefaultSearchPanelJson(), + GroupPanelJson = WizardConsts.DefaultGroupPanelJson(), SelectionJson = WizardConsts.DefaultSelectionSingleJson(input.WorkflowCriteria.Count > 0 ? GridOptions.SelectionModeSingle : GridOptions.SelectionModeNone), ColumnOptionJson = WizardConsts.DefaultColumnOptionJson(), PermissionJson = WizardConsts.DefaultPermissionJson(code), diff --git a/api/src/Sozsoft.Platform.Domain.Shared/WizardConsts.cs b/api/src/Sozsoft.Platform.Domain.Shared/WizardConsts.cs index 1d83bc4..19b9f37 100644 --- a/api/src/Sozsoft.Platform.Domain.Shared/WizardConsts.cs +++ b/api/src/Sozsoft.Platform.Domain.Shared/WizardConsts.cs @@ -96,10 +96,10 @@ public static class WizardConsts }); public static readonly string DefaultFilterJson = "\"IsDeleted\" = 'false'"; - public static readonly string DefaultFilterRowJson = JsonSerializer.Serialize(new { Visible = true }); - public static readonly string DefaultHeaderFilterJson = JsonSerializer.Serialize(new { Visible = true }); - public static readonly string DefaultSearchPanelJson = JsonSerializer.Serialize(new { Visible = true }); - public static readonly string DefaultGroupPanelJson = JsonSerializer.Serialize(new { Visible = true }); + public static string DefaultFilterRowJson(bool visible = true) => JsonSerializer.Serialize(new { Visible = visible }); + public static string DefaultHeaderFilterJson(bool visible = true) => JsonSerializer.Serialize(new { Visible = visible }); + public static string DefaultSearchPanelJson(bool visible = true) => JsonSerializer.Serialize(new { Visible = visible }); + public static string DefaultGroupPanelJson(bool visible = true) => JsonSerializer.Serialize(new { Visible = visible }); public static string DefaultSelectionSingleJson(string Mode = "none") => JsonSerializer.Serialize(new { @@ -212,7 +212,7 @@ public static class WizardConsts new { FieldName = "Id", FieldDbType = dbType, Value = "@NEWID", CustomValueType = FieldCustomValueTypeEnum.CustomKey } }); } - + public static readonly string DefaultPagerOptionJson = JsonSerializer.Serialize(new { Visible = true, diff --git a/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicGridReport.cs b/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicGridReport.cs index 00b5a18..429194b 100644 --- a/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicGridReport.cs +++ b/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicGridReport.cs @@ -301,7 +301,8 @@ public class DynamicGridReport : XtraReport var headerTable = CreateTable(pageWidth, 28); var headerRow = new XRTableRow { HeightF = 28 }; var detailTable = CreateTable(pageWidth, detailHeight); - var detailRow = new XRTableRow { HeightF = detailHeight }; + detailTable.CanGrow = true; + var detailRow = new XRTableRow { HeightF = detailHeight, CanGrow = true }; var footerTable = CreateTable(pageWidth, 24); var footerRow = new XRTableRow { HeightF = 24 }; @@ -355,7 +356,11 @@ public class DynamicGridReport : XtraReport }; } - private static XRTableCell CreateDetailCell(ReportColumn column, float width, string imageBaseUrl, float height) + private static XRTableCell CreateDetailCell( + ReportColumn column, + float width, + string imageBaseUrl, + float height) { var field = column.Field; if (column.IsImage) @@ -380,8 +385,8 @@ public class DynamicGridReport : XtraReport Font = new DXFont("Segoe UI Emoji", 8F), Padding = new PaddingInfo(4, 4, 2, 2), TextAlignment = DynamicReportImageHelper.ToTextAlignment(field.Alignment, field.SourceDbType), - Multiline = false, - CanGrow = false + Multiline = true, + CanGrow = true }; cell.ExpressionBindings.Add(new ExpressionBinding( "BeforePrint", @@ -391,14 +396,17 @@ public class DynamicGridReport : XtraReport return cell; } - private static XRTableCell CreateHtmlDetailCell(ReportColumn column, float width, float height) + private static XRTableCell CreateHtmlDetailCell( + ReportColumn column, + float width, + float height) { var cell = new XRTableCell { WidthF = width, Weight = width, Padding = new PaddingInfo(0, 0, 0, 0), - CanGrow = false + CanGrow = true }; var richText = new XRRichText @@ -406,7 +414,7 @@ public class DynamicGridReport : XtraReport BoundsF = new System.Drawing.RectangleF(0, 0, width, height), Font = new DXFont("Arial", 8F), Padding = new PaddingInfo(4, 4, 2, 2), - CanGrow = false + CanGrow = true }; richText.ExpressionBindings.Add(new ExpressionBinding("BeforePrint", "Html", $"[{column.BindingName}]")); cell.Controls.Add(richText); diff --git a/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicReportImageHelper.cs b/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicReportImageHelper.cs index df0f563..abd82be 100644 --- a/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicReportImageHelper.cs +++ b/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicReportImageHelper.cs @@ -618,7 +618,9 @@ internal static class DynamicReportImageHelper return true; } - return TryFormatDateValue(dbType, format, value, out text) || + var formatOptions = ReportFormatOptions.Parse(format); + return TryFormatNamedTextValue(formatOptions, value, out text) || + TryFormatDateValue(dbType, formatOptions, value, out text) || TryFormatNumericValue(dbType, format, value, out text); } @@ -638,7 +640,11 @@ internal static class DynamicReportImageHelper return false; } - private static bool TryFormatDateValue(DbType dbType, string format, object value, out string text) + private static bool TryFormatDateValue( + DbType dbType, + ReportFormatOptions formatOptions, + object value, + out string text) { text = null; if (!IsDateField(dbType) || !TryConvertToDateTime(value, out var date)) @@ -647,7 +653,12 @@ internal static class DynamicReportImageHelper } var culture = CultureInfo.CurrentCulture; - var customFormat = GetCustomFormat(format); + if (TryFormatDevExtremeDateValue(date, formatOptions.Type, culture, out text)) + { + return true; + } + + var customFormat = NormalizeDateTimeFormat(formatOptions.CustomFormat); if (!string.IsNullOrWhiteSpace(customFormat)) { try @@ -675,7 +686,13 @@ internal static class DynamicReportImageHelper } var culture = CultureInfo.CurrentCulture; - var customFormat = GetCustomFormat(format); + var formatOptions = ReportFormatOptions.Parse(format); + if (TryFormatDevExtremeNumericValue(number, formatOptions, culture, out text)) + { + return true; + } + + var customFormat = formatOptions.CustomFormat; if (!string.IsNullOrWhiteSpace(customFormat)) { try @@ -692,6 +709,185 @@ internal static class DynamicReportImageHelper return true; } + private static bool TryFormatNamedTextValue( + ReportFormatOptions formatOptions, + object value, + out string text) + { + text = null; + if (!string.Equals(formatOptions.Type, "phoneGlobal", StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + var digits = Regex.Replace( + Convert.ToString(value, CultureInfo.InvariantCulture) ?? string.Empty, + @"\D", + string.Empty); + + if (digits.StartsWith("90", StringComparison.Ordinal) && digits.Length > 10) + { + digits = digits[^10..]; + } + if (digits.StartsWith("0", StringComparison.Ordinal) && digits.Length > 10) + { + digits = digits[^10..]; + } + if (digits.Length > 10) + { + digits = digits[^10..]; + } + + text = digits.Length == 10 + ? $"({digits[..3]}) {digits.Substring(3, 3)}-{digits[6..]}" + : Convert.ToString(value, CultureInfo.CurrentCulture) ?? string.Empty; + return true; + } + + private static bool TryFormatDevExtremeDateValue( + DateTime date, + string formatType, + CultureInfo culture, + out string text) + { + text = null; + switch (formatType) + { + case PlatformConsts.GridColumnOptions.ColumnValueFormatShortDate: + text = date.ToString(culture.DateTimeFormat.ShortDatePattern, culture); + return true; + case PlatformConsts.GridColumnOptions.ColumnValueFormatLongDate: + text = date.ToString(culture.DateTimeFormat.LongDatePattern, culture); + return true; + case PlatformConsts.GridColumnOptions.ColumnValueFormatShortTime: + text = date.ToString(culture.DateTimeFormat.ShortTimePattern, culture); + return true; + case PlatformConsts.GridColumnOptions.ColumnValueFormatLongTime: + text = date.ToString(culture.DateTimeFormat.LongTimePattern, culture); + return true; + case PlatformConsts.GridColumnOptions.ColumnValueFormatShortDateShortTime: + text = date.ToString("g", culture); + return true; + case PlatformConsts.GridColumnOptions.ColumnValueFormatLongDateLongTime: + text = date.ToString("G", culture); + return true; + case PlatformConsts.GridColumnOptions.ColumnValueFormatMonthAndDay: + text = date.ToString("M", culture); + return true; + case PlatformConsts.GridColumnOptions.ColumnValueFormatMonthAndYear: + text = date.ToString("Y", culture); + return true; + case PlatformConsts.GridColumnOptions.ColumnValueFormatYear: + text = date.ToString("yyyy", culture); + return true; + case PlatformConsts.GridColumnOptions.ColumnValueFormatMonth: + text = date.ToString("MMMM", culture); + return true; + case PlatformConsts.GridColumnOptions.ColumnValueFormatDay: + text = date.ToString("dd", culture); + return true; + case PlatformConsts.GridColumnOptions.ColumnValueFormatDayOfWeek: + text = date.ToString("dddd", culture); + return true; + case PlatformConsts.GridColumnOptions.ColumnValueFormatQuarter: + text = GetQuarter(date).ToString(culture); + return true; + case PlatformConsts.GridColumnOptions.ColumnValueFormatQuarterAndYear: + text = $"Q{GetQuarter(date)} {date:yyyy}"; + return true; + case PlatformConsts.GridColumnOptions.ColumnValueFormatHour: + text = date.ToString("%H", culture); + return true; + case PlatformConsts.GridColumnOptions.ColumnValueFormatMinute: + text = date.ToString("%m", culture); + return true; + case PlatformConsts.GridColumnOptions.ColumnValueFormatSecond: + text = date.ToString("%s", culture); + return true; + case PlatformConsts.GridColumnOptions.ColumnValueFormatMillisecond: + text = date.Millisecond.ToString(culture); + return true; + default: + return false; + } + } + + private static bool TryFormatDevExtremeNumericValue( + decimal number, + ReportFormatOptions formatOptions, + CultureInfo culture, + out string text) + { + text = null; + var precision = formatOptions.Precision; + switch (formatOptions.Type) + { + case PlatformConsts.GridColumnOptions.ColumnValueFormatFixedPoint: + case PlatformConsts.GridColumnOptions.ColumnValueFormatDecimal: + text = number.ToString(precision.HasValue ? $"N{precision.Value}" : "N", culture); + return true; + case PlatformConsts.GridColumnOptions.ColumnValueFormatCurrency: + text = number.ToString(precision.HasValue ? $"C{precision.Value}" : "C", culture); + return true; + case PlatformConsts.GridColumnOptions.ColumnValueFormatPercent: + text = number.ToString(precision.HasValue ? $"P{precision.Value}" : "P", culture); + return true; + case PlatformConsts.GridColumnOptions.ColumnValueFormatExponential: + text = number.ToString(precision.HasValue ? $"E{precision.Value}" : "E", culture); + return true; + case PlatformConsts.GridColumnOptions.ColumnValueFormatThousands: + text = FormatScaledNumber(number, 1_000M, "K", precision, culture); + return true; + case PlatformConsts.GridColumnOptions.ColumnValueFormatMillions: + text = FormatScaledNumber(number, 1_000_000M, "M", precision, culture); + return true; + case PlatformConsts.GridColumnOptions.ColumnValueFormatBillions: + text = FormatScaledNumber(number, 1_000_000_000M, "B", precision, culture); + return true; + case PlatformConsts.GridColumnOptions.ColumnValueFormatTrillions: + text = FormatScaledNumber(number, 1_000_000_000_000M, "T", precision, culture); + return true; + case PlatformConsts.GridColumnOptions.ColumnValueFormatLargeNumber: + text = FormatLargeNumber(number, precision, culture); + return true; + default: + return false; + } + } + + private static string FormatLargeNumber(decimal number, int? precision, CultureInfo culture) + { + var absolute = Math.Abs(number); + if (absolute >= 1_000_000_000_000M) + { + return FormatScaledNumber(number, 1_000_000_000_000M, "T", precision, culture); + } + if (absolute >= 1_000_000_000M) + { + return FormatScaledNumber(number, 1_000_000_000M, "B", precision, culture); + } + if (absolute >= 1_000_000M) + { + return FormatScaledNumber(number, 1_000_000M, "M", precision, culture); + } + if (absolute >= 1_000M) + { + return FormatScaledNumber(number, 1_000M, "K", precision, culture); + } + + return number.ToString(precision.HasValue ? $"N{precision.Value}" : "N", culture); + } + + private static string FormatScaledNumber( + decimal number, + decimal scale, + string suffix, + int? precision, + CultureInfo culture) + { + return (number / scale).ToString(precision.HasValue ? $"N{precision.Value}" : "N", culture) + suffix; + } + private static bool TryFormatBoolean(string value, out string text) { if (bool.TryParse(value, out var boolean)) @@ -716,6 +912,8 @@ internal static class DynamicReportImageHelper return false; } + private static int GetQuarter(DateTime date) => ((date.Month - 1) / 3) + 1; + private static string FormatBoolean(bool value) { return CultureInfo.CurrentCulture.TwoLetterISOLanguageName.Equals("tr", StringComparison.OrdinalIgnoreCase) @@ -950,7 +1148,12 @@ internal static class DynamicReportImageHelper return null; } - return value.ValueKind == JsonValueKind.String ? value.GetString() : null; + return value.ValueKind switch + { + JsonValueKind.String => value.GetString(), + JsonValueKind.Object => value.GetRawText(), + _ => null + }; } catch (JsonException) { @@ -976,6 +1179,110 @@ internal static class DynamicReportImageHelper }; } + private sealed class ReportFormatOptions + { + public string Type { get; private init; } + public string CustomFormat { get; private init; } + public int? Precision { get; private init; } + + public static ReportFormatOptions Parse(string format) + { + if (string.IsNullOrWhiteSpace(format)) + { + return new ReportFormatOptions(); + } + + var trimmed = format.Trim(); + if (!trimmed.StartsWith("{", StringComparison.Ordinal)) + { + var normalized = NormalizeDateTimeFormat(trimmed); + return new ReportFormatOptions + { + Type = trimmed, + CustomFormat = normalized == trimmed && IsKnownDevExtremeFormat(trimmed) ? null : normalized + }; + } + + try + { + using var document = JsonDocument.Parse(trimmed); + if (document.RootElement.ValueKind != JsonValueKind.Object) + { + return new ReportFormatOptions(); + } + + var type = GetJsonString(document.RootElement, "type"); + var formatter = GetJsonString(document.RootElement, "formatter"); + var customFormat = + GetJsonString(document.RootElement, "displayFormat") ?? + GetJsonString(document.RootElement, "format") ?? + GetJsonString(document.RootElement, "formatString"); + + return new ReportFormatOptions + { + Type = type ?? customFormat, + CustomFormat = NormalizeDateTimeFormat(formatter ?? customFormat), + Precision = GetJsonInt(document.RootElement, "precision") + }; + } + catch (JsonException) + { + return new ReportFormatOptions(); + } + } + + private static string GetJsonString(JsonElement element, string propertyName) + { + return TryGetLookupProperty(element, propertyName, out var value) && + value.ValueKind == JsonValueKind.String + ? value.GetString() + : null; + } + + private static int? GetJsonInt(JsonElement element, string propertyName) + { + return TryGetLookupProperty(element, propertyName, out var value) && + value.ValueKind == JsonValueKind.Number && + value.TryGetInt32(out var number) + ? Math.Clamp(number, 0, 15) + : null; + } + } + + private static bool IsKnownDevExtremeFormat(string format) + { + return format is + PlatformConsts.GridColumnOptions.ColumnValueFormatBillions or + PlatformConsts.GridColumnOptions.ColumnValueFormatCurrency or + PlatformConsts.GridColumnOptions.ColumnValueFormatDay or + PlatformConsts.GridColumnOptions.ColumnValueFormatDecimal or + PlatformConsts.GridColumnOptions.ColumnValueFormatExponential or + PlatformConsts.GridColumnOptions.ColumnValueFormatFixedPoint or + PlatformConsts.GridColumnOptions.ColumnValueFormatLargeNumber or + PlatformConsts.GridColumnOptions.ColumnValueFormatLongDate or + PlatformConsts.GridColumnOptions.ColumnValueFormatLongTime or + PlatformConsts.GridColumnOptions.ColumnValueFormatMillions or + PlatformConsts.GridColumnOptions.ColumnValueFormatMillisecond or + PlatformConsts.GridColumnOptions.ColumnValueFormatMonth or + PlatformConsts.GridColumnOptions.ColumnValueFormatMonthAndDay or + PlatformConsts.GridColumnOptions.ColumnValueFormatMonthAndYear or + PlatformConsts.GridColumnOptions.ColumnValueFormatPercent or + PlatformConsts.GridColumnOptions.ColumnValueFormatQuarter or + PlatformConsts.GridColumnOptions.ColumnValueFormatQuarterAndYear or + PlatformConsts.GridColumnOptions.ColumnValueFormatShortDate or + PlatformConsts.GridColumnOptions.ColumnValueFormatShortTime or + PlatformConsts.GridColumnOptions.ColumnValueFormatThousands or + PlatformConsts.GridColumnOptions.ColumnValueFormatTrillions or + PlatformConsts.GridColumnOptions.ColumnValueFormatYear or + PlatformConsts.GridColumnOptions.ColumnValueFormatDayOfWeek or + PlatformConsts.GridColumnOptions.ColumnValueFormatHour or + PlatformConsts.GridColumnOptions.ColumnValueFormatLongDateLongTime or + PlatformConsts.GridColumnOptions.ColumnValueFormatMinute or + PlatformConsts.GridColumnOptions.ColumnValueFormatSecond or + PlatformConsts.GridColumnOptions.ColumnValueFormatShortDateShortTime or + "phoneGlobal"; + } + private static bool IsDateField(DbType dbType) { return dbType is DbType.Date or DbType.DateTime or DbType.DateTime2 or DbType.DateTimeOffset or DbType.Time; diff --git a/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicTreeReport.cs b/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicTreeReport.cs index 7be7aa3..f030fc5 100644 --- a/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicTreeReport.cs +++ b/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicTreeReport.cs @@ -466,7 +466,8 @@ public class DynamicTreeReport : XtraReport var headerTable = CreateTable(pageWidth, 28); var headerRow = new XRTableRow { HeightF = 28 }; var detailTable = CreateTable(pageWidth, detailHeight); - var detailRow = new XRTableRow { HeightF = detailHeight }; + detailTable.CanGrow = true; + var detailRow = new XRTableRow { HeightF = detailHeight, CanGrow = true }; var footerTable = CreateTable(pageWidth, 24); var footerRow = new XRTableRow { HeightF = 24 }; @@ -550,8 +551,8 @@ public class DynamicTreeReport : XtraReport TextAlignment = isTreeColumn ? TextAlignment.MiddleLeft : DynamicReportImageHelper.ToTextAlignment(column.Field.Alignment, column.Field.SourceDbType), - Multiline = false, - CanGrow = false + Multiline = true, + CanGrow = true }; var valueExpression = DynamicReportImageHelper.CreateFormatValueExpression($"[{column.BindingName}]", column.Field, column.EditorType); @@ -573,14 +574,17 @@ public class DynamicTreeReport : XtraReport return cell; } - private static XRTableCell CreateHtmlDetailCell(ReportColumn column, float width, float height) + private static XRTableCell CreateHtmlDetailCell( + ReportColumn column, + float width, + float height) { var cell = new XRTableCell { WidthF = width, Weight = width, Padding = new PaddingInfo(0, 0, 0, 0), - CanGrow = false + CanGrow = true }; var richText = new XRRichText @@ -588,7 +592,7 @@ public class DynamicTreeReport : XtraReport BoundsF = new System.Drawing.RectangleF(0, 0, width, height), Font = new DXFont("Arial", 8F), Padding = new PaddingInfo(4, 4, 2, 2), - CanGrow = false + CanGrow = true }; richText.ExpressionBindings.Add(new ExpressionBinding("BeforePrint", "Html", $"[{column.BindingName}]")); cell.Controls.Add(richText); diff --git a/ui/src/views/report/DevexpressReportViewer.tsx b/ui/src/views/report/DevexpressReportViewer.tsx index 8945078..01e3dbf 100644 --- a/ui/src/views/report/DevexpressReportViewer.tsx +++ b/ui/src/views/report/DevexpressReportViewer.tsx @@ -99,21 +99,22 @@ const DevexpressReportViewer: React.FC = () => { return candidates.find( (candidate) => candidate && - ('zoom' in candidate || - 'originalZoom' in candidate || - 'autoFitBy' in candidate), + ('zoom' in candidate || 'originalZoom' in candidate || 'autoFitBy' in candidate), ) }, []) - const setDefaultZoom = useCallback((eventOrModel?: any) => { - const preview = getReportPreview(eventOrModel) - if (!preview) return + const setDefaultZoom = useCallback( + (eventOrModel?: any) => { + const preview = getReportPreview(eventOrModel) + if (!preview) return - previewModelRef.current = preview - preview.autoFitBy = ZoomAutoBy.None - preview.originalZoom = DEFAULT_REPORT_ZOOM - preview.zoom = DEFAULT_REPORT_ZOOM - }, [getReportPreview]) + previewModelRef.current = preview + preview.autoFitBy = ZoomAutoBy.None + preview.originalZoom = DEFAULT_REPORT_ZOOM + preview.zoom = DEFAULT_REPORT_ZOOM + }, + [getReportPreview], + ) useEffect(() => { loadViewerCss(isDarkMode) @@ -168,15 +169,12 @@ const DevexpressReportViewer: React.FC = () => { /> {isRequestAuthReady && ( - + - + )}