diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json b/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json
index 5c588db..ed9ff49 100644
--- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json
+++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json
@@ -1398,6 +1398,18 @@
"en": "Menu Management",
"tr": "Menü Yönetimi"
},
+ {
+ "resourceName": "Platform",
+ "key": "App.Reports.List",
+ "en": "List Report",
+ "tr": "Liste Raporu"
+ },
+ {
+ "resourceName": "Platform",
+ "key": "App.Reports.Form",
+ "en": "Form Report",
+ "tr": "Form Raporu"
+ },
{
"resourceName": "Platform",
"key": "App.Reports",
diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Administration.cs b/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Administration.cs
index fe694a5..0d0421d 100644
--- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Administration.cs
+++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Administration.cs
@@ -1584,7 +1584,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
Text ="App.Platform.View",
UrlTarget="_blank",
AuthName = listFormName,
- Url=$"/admin/reports/DynamicReport/view?id=@Id",
+ Url=$"/admin/reports/DynamicReport/view/@Id",
IsVisible = true,
VisibleExpression = "((e)=> e.row.data.CategoryId === 'Raporlar')"
},
@@ -1593,7 +1593,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
Text ="App.Platform.Design",
UrlTarget="_blank",
AuthName = listFormName + ".Update",
- Url=$"/admin/reports/DynamicReport/design?id=@Id",
+ Url=$"/admin/reports/DynamicReport/design/@Id",
IsVisible = true,
VisibleExpression = "((e)=> e.row.data.CategoryId === 'Raporlar')"
},
@@ -1602,7 +1602,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
Text ="App.Platform.View",
UrlTarget="_blank",
AuthName = listFormName,
- Url=$"/admin/reports/DynamicGrid/view?listFormCode=@Name",
+ Url=$"/admin/reports/DynamicGrid/view/@Name",
IsVisible = true,
VisibleExpression = "((e)=> e.row.data.CategoryId === 'Listeler')"
},
@@ -1611,7 +1611,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
Text ="App.Platform.View",
UrlTarget="_blank",
AuthName = listFormName,
- Url=$"/admin/reports/DynamicGrid/view?listFormCode=@Name&id=@Id",
+ Url=$"/admin/reports/DynamicGrid/view/@Id/@Name",
IsVisible = true,
VisibleExpression = "((e)=> e.row.data.CategoryId === 'Formlar')"
},
diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/MenusData.json b/api/src/Sozsoft.Platform.DbMigrator/Seeds/MenusData.json
index 0eda867..8b07c31 100644
--- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/MenusData.json
+++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/MenusData.json
@@ -418,7 +418,7 @@
},
{
"key": "admin.devexpressDynamicReportView",
- "path": "/admin/reports/:id/view",
+ "path": "/admin/reports/:report/view/:id?/:listFormCode?",
"componentType": "normal",
"componentPath": "@/views/report/DevexpressReportViewer",
"routeType": "protected",
@@ -426,7 +426,7 @@
},
{
"key": "admin.devexpressDynamicReportDesigner",
- "path": "/admin/reports/:id/design",
+ "path": "/admin/reports/:report/design/:id?/:listFormCode?",
"componentType": "normal",
"componentPath": "@/views/report/DevexpressReportDesigner",
"routeType": "protected",
diff --git a/api/src/Sozsoft.Platform.EntityFrameworkCore/Seeds/TenantData.json b/api/src/Sozsoft.Platform.EntityFrameworkCore/Seeds/TenantData.json
index 1b36603..2e224e1 100644
--- a/api/src/Sozsoft.Platform.EntityFrameworkCore/Seeds/TenantData.json
+++ b/api/src/Sozsoft.Platform.EntityFrameworkCore/Seeds/TenantData.json
@@ -1383,21 +1383,21 @@
"name": "Standard Taahhütname",
"description": "Standard Taahhütname",
"categoryName": "Raporlar",
- "htmlContent": "
Taahhütname
http://localhost:3000/admin/reports/DynamicReport/view?id=ede12de7-0e94-4b84-a953-6c359606478b
",
+ "htmlContent": "Taahhütname
http://localhost:3000/admin/reports/DynamicReport/view/ede12de7-0e94-4b84-a953-6c359606478b
",
"status": "active"
},
{
"name": "App.Languages.LanguageText",
"description": "Liste Raporları",
"categoryName": "Listeler",
- "htmlContent": "Liste Raporları.
http://localhost:3000/admin/reports/DynamicGridReport/view?listFormCode=App.Languages.LanguageText&filter=[%22CultureName%22,%22=%22,%22en%22]
",
+ "htmlContent": "Liste Raporları.
http://localhost:3000/admin/reports/DynamicGridReport/view/App.Languages.LanguageText?filter=[%22CultureName%22,%22=%22,%22en%22]
",
"status": "active"
},
{
"name": "App.Languages.Language",
"description": "Form Raporları",
"categoryName": "Formlar",
- "htmlContent": "Liste Raporları.
http://localhost:3000/admin/reports/DynamicFormReport/view?listFormCode=App.Languages.Language&id=e2c8a2e0-af22-f7bb-5d88-3a21e3079997
",
+ "htmlContent": "Liste Raporları.
http://localhost:3000/admin/reports/DynamicFormReport/view/e2c8a2e0-af22-f7bb-5d88-3a21e3079997/App.Languages.Language
",
"status": "active"
}
],
diff --git a/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicFormReport.cs b/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicFormReport.cs
index 60d194b..3adff87 100644
--- a/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicFormReport.cs
+++ b/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicFormReport.cs
@@ -28,6 +28,7 @@ public class DynamicFormReport : XtraReport
private const string QueryName = "DynamicForm";
private const int HorizontalMargin = 35;
private const float RowHeight = 24;
+ private static readonly System.Drawing.Color FieldBorderColor = System.Drawing.Color.FromArgb(226, 232, 240);
private static IServiceProvider _serviceProvider;
public static void SetServiceProvider(IServiceProvider serviceProvider)
@@ -107,6 +108,7 @@ public class DynamicFormReport : XtraReport
reportFields,
defaultValueHelper);
selectQuery = ApplyQueryParameters(selectQuery, selectQueryManager.SelectQueryParameters);
+ selectQuery = StripReportPaging(selectQuery);
var row = GetFirstRow(dynamicDataRepository.QueryAsync(selectQuery, connectionString).GetAwaiter().GetResult());
@@ -118,12 +120,23 @@ public class DynamicFormReport : XtraReport
private void ConfigurePage()
{
- Margins = new System.Drawing.Printing.Margins(HorizontalMargin, HorizontalMargin, 35, 35);
+ Margins = CreateReportMargins(HorizontalMargin, HorizontalMargin, 35, 35);
PaperKind = DevExpress.Drawing.Printing.DXPaperKind.A4;
Landscape = false;
Font = new DXFont("Arial", 8.25F);
}
+#pragma warning disable CA1416
+ private static System.Drawing.Printing.Margins CreateReportMargins(
+ int left,
+ int right,
+ int top,
+ int bottom)
+ {
+ return new System.Drawing.Printing.Margins(left, right, top, bottom);
+ }
+#pragma warning restore CA1416
+
private void ConfigureDataSource(string selectQuery, string connectionString, DataSourceTypeEnum dataSourceType)
{
var dataSource = new SqlDataSource(new CustomStringConnectionParameters(ToDevExpressConnectionString(connectionString, dataSourceType)));
@@ -195,7 +208,7 @@ public class DynamicFormReport : XtraReport
var rowHeight = GetFieldRowHeight(field);
var labelWidth = pageWidth * 0.28F;
detail.Controls.Add(CreateCaptionLabel(field, localizer, 0, y, labelWidth, rowHeight));
- detail.Controls.Add(CreateValueLabel(field, labelWidth, y, pageWidth - labelWidth, rowHeight));
+ detail.Controls.Add(CreateValueLabel(field, row, labelWidth, y, pageWidth - labelWidth, rowHeight));
y += rowHeight + 3;
}
@@ -230,48 +243,75 @@ public class DynamicFormReport : XtraReport
Font = new DXFont("Arial", 8F, DXFontStyle.Bold),
BackColor = System.Drawing.Color.FromArgb(248, 250, 252),
Borders = BorderSide.All,
- BorderWidth = 0.5F,
+ BorderColor = FieldBorderColor,
+ BorderWidth = 0.25F,
Padding = new PaddingInfo(5, 5, 2, 2),
TextAlignment = TextAlignment.MiddleLeft,
Multiline = true
};
}
- private static XRLabel CreateValueLabel(FormReportField field, float x, float y, float width, float height)
+ private static XRLabel CreateValueLabel(
+ FormReportField field,
+ IDictionary row,
+ float x,
+ float y,
+ float width,
+ float height)
{
var label = new XRLabel
{
BoundsF = new System.Drawing.RectangleF(x, y, width, height),
Font = new DXFont("Arial", 8F),
Borders = BorderSide.All,
- BorderWidth = 0.5F,
+ BorderColor = FieldBorderColor,
+ BorderWidth = 0.25F,
Padding = new PaddingInfo(5, 5, 2, 2),
TextAlignment = ToTextAlignment(field.Field.Alignment, field.Field.SourceDbType),
Multiline = true,
CanGrow = true
};
- label.ExpressionBindings.Add(new ExpressionBinding("BeforePrint", "Text", $"[{field.BindingName}]"));
-
- if (IsBooleanEditor(field) || field.StaticLookupValues?.Count > 0)
+ if (TryGetFormattedValue(field, row, out var text))
{
- label.BeforePrint += (_, _) =>
- {
- var value = Convert.ToString(label.Text, CultureInfo.InvariantCulture);
- if (IsBooleanEditor(field) && TryFormatBoolean(value, out var booleanText))
- {
- label.Text = booleanText;
- }
- else if (value != null && field.StaticLookupValues?.TryGetValue(value, out var displayText) == true)
- {
- label.Text = displayText;
- }
- };
+ label.Text = text;
+ }
+ else
+ {
+ label.ExpressionBindings.Add(new ExpressionBinding("BeforePrint", "Text", $"[{field.BindingName}]"));
}
return label;
}
+ private static bool TryGetFormattedValue(
+ FormReportField field,
+ IDictionary row,
+ out string text)
+ {
+ text = null;
+ if (row == null || !TryGetRowValue(row, field.BindingName, out var rawValue))
+ {
+ return false;
+ }
+
+ var value = Convert.ToString(rawValue, CultureInfo.InvariantCulture);
+ if (IsBooleanEditor(field) && TryFormatBoolean(value, out var booleanText))
+ {
+ text = booleanText;
+ return true;
+ }
+
+ if (value != null && field.StaticLookupValues?.TryGetValue(value, out var displayText) == true)
+ {
+ text = displayText;
+ return true;
+ }
+
+ text = value ?? string.Empty;
+ return true;
+ }
+
private static float CalculateDetailHeight(
IReadOnlyList fields,
ListForm listForm,
@@ -546,6 +586,20 @@ public class DynamicFormReport : XtraReport
return sql;
}
+ private static string StripReportPaging(string sql)
+ {
+ if (string.IsNullOrWhiteSpace(sql))
+ {
+ return sql;
+ }
+
+ return Regex.Replace(
+ sql,
+ @"\s+ORDER\s+BY[\s\S]*?(?:\s+OFFSET\s+\d+\s+ROWS(?:\s+FETCH\s+NEXT\s+\d+\s+ROWS\s+ONLY)?)?\s*$",
+ string.Empty,
+ RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
+ }
+
private static string ToSqlLiteral(object value)
{
if (value == null || value == DBNull.Value)
@@ -741,7 +795,7 @@ public class DynamicFormReport : XtraReport
var query = lookupQuery.Trim().TrimEnd(';');
return Regex.Replace(
query,
- @"\s+ORDER\s+BY\s+[\s\S]*$",
+ @"(? visibleFields)
{
- Margins = new System.Drawing.Printing.Margins(HorizontalMargin, HorizontalMargin, 35, 35);
+ Margins = CreateReportMargins(HorizontalMargin, HorizontalMargin, 35, 35);
PaperKind = DevExpress.Drawing.Printing.DXPaperKind.A4;
var portraitContentWidth = A4PortraitWidth - Margins.Left - Margins.Right;
var requestedContentWidth = visibleFields.Sum(x => Math.Max(x.Field.Width ?? 90, 60));
@@ -146,6 +149,16 @@ public class DynamicGridReport : XtraReport
Font = new DXFont("Arial", 8.25F);
}
+ private static System.Drawing.Printing.Margins CreateReportMargins(
+ int left,
+ int right,
+ int top,
+ int bottom)
+ {
+ return new System.Drawing.Printing.Margins(left, right, top, bottom);
+ }
+#pragma warning restore CA1416
+
private void ConfigureDataSource(string selectQuery, string connectionString, DataSourceTypeEnum dataSourceType)
{
var dataSource = new SqlDataSource(new CustomStringConnectionParameters(ToDevExpressConnectionString(connectionString, dataSourceType)));
@@ -195,6 +208,20 @@ public class DynamicGridReport : XtraReport
return sql;
}
+ private static string StripReportPaging(string sql)
+ {
+ if (string.IsNullOrWhiteSpace(sql))
+ {
+ return sql;
+ }
+
+ return Regex.Replace(
+ sql,
+ @"\s+ORDER\s+BY[\s\S]*?(?:\s+OFFSET\s+\d+\s+ROWS(?:\s+FETCH\s+NEXT\s+\d+\s+ROWS\s+ONLY)?)?\s*$",
+ string.Empty,
+ RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
+ }
+
private static string ToSqlLiteral(object value)
{
if (value == null || value == DBNull.Value)
@@ -293,7 +320,8 @@ public class DynamicGridReport : XtraReport
{
BoundsF = new System.Drawing.RectangleF(0, 0, width, height),
Borders = BorderSide.All,
- BorderWidth = 0.5F
+ BorderColor = TableBorderColor,
+ BorderWidth = 0.25F
};
}
@@ -353,17 +381,6 @@ public class DynamicGridReport : XtraReport
CanGrow = false
};
cell.ExpressionBindings.Add(new ExpressionBinding("BeforePrint", "Text", $"[{column.BindingName}]"));
- if (column.StaticLookupValues?.Count > 0)
- {
- cell.BeforePrint += (_, _) =>
- {
- var value = Convert.ToString(cell.Text, CultureInfo.InvariantCulture);
- if (value != null && column.StaticLookupValues.TryGetValue(value, out var displayText))
- {
- cell.Text = displayText;
- }
- };
- }
return cell;
}
@@ -455,11 +472,12 @@ public class DynamicGridReport : XtraReport
if (lookup.DataSourceType == UiLookupDataSourceTypeEnum.StaticData)
{
+ var staticLookupValues = GetStaticLookupValues(lookup, defaultValueHelper);
return new ReportColumn(
field,
- bindingName,
+ staticLookupValues?.Count > 0 ? GetLookupBindingName(field) : bindingName,
lookup,
- GetStaticLookupValues(lookup, defaultValueHelper));
+ staticLookupValues);
}
return new ReportColumn(field, bindingName, null, null);
@@ -570,11 +588,15 @@ public class DynamicGridReport : XtraReport
IReadOnlyList reportColumns,
DefaultValueHelper defaultValueHelper)
{
- var lookupColumns = reportColumns
+ var queryLookupColumns = reportColumns
.Where(x => x.Lookup != null && IsReportQueryableLookup(x.Lookup))
.ToList();
+ var staticLookupColumns = reportColumns
+ .Where(x => x.StaticLookupValues?.Count > 0)
+ .ToList();
- if (lookupColumns.Count == 0 || string.IsNullOrWhiteSpace(selectQuery))
+ if ((queryLookupColumns.Count == 0 && staticLookupColumns.Count == 0) ||
+ string.IsNullOrWhiteSpace(selectQuery))
{
return selectQuery;
}
@@ -585,7 +607,12 @@ public class DynamicGridReport : XtraReport
var selectParts = new List();
var joinParts = new List();
- foreach (var column in lookupColumns)
+ foreach (var column in staticLookupColumns)
+ {
+ selectParts.Add(CreateStaticLookupSelectPart(column, tableAlias));
+ }
+
+ foreach (var column in queryLookupColumns)
{
var lookup = column.Lookup;
var alias = GetLookupAlias(column.Field);
@@ -612,6 +639,10 @@ public class DynamicGridReport : XtraReport
{
joinInsertIndex = FindClauseIndex(selectQuery, " ORDER BY ");
}
+ if (joinParts.Count == 0)
+ {
+ return selectQuery;
+ }
if (joinInsertIndex < 0)
{
return selectQuery + " " + string.Join(' ', joinParts);
@@ -620,6 +651,15 @@ public class DynamicGridReport : XtraReport
return selectQuery.Insert(joinInsertIndex, " " + string.Join(' ', joinParts));
}
+ private static string CreateStaticLookupSelectPart(ReportColumn column, string tableAlias)
+ {
+ var sourceField = $"{QuoteSqlIdentifier(tableAlias)}.{QuoteSqlIdentifier(column.Field.FieldName)}";
+ var cases = column.StaticLookupValues
+ .Select(item => $"WHEN {ToSqlLiteral(item.Key)} THEN {ToSqlLiteral(item.Value)}");
+
+ return $"CASE {sourceField} {string.Join(" ", cases)} ELSE CAST({sourceField} AS VARCHAR(4000)) END AS {QuoteSqlIdentifier(column.BindingName)}";
+ }
+
private static int FindClauseIndex(string sql, string clause)
{
return sql.IndexOf(clause, StringComparison.OrdinalIgnoreCase);
@@ -630,7 +670,7 @@ public class DynamicGridReport : XtraReport
var query = lookupQuery.Trim().TrimEnd(';');
return Regex.Replace(
query,
- @"\s+ORDER\s+BY\s+[\s\S]*$",
+ @"(? Parameters) ParseReportUrl(string url)
{
var decodedUrl = DecodeRepeatedly(url);
- var reportName = decodedUrl;
var parameters = new Dictionary(StringComparer.OrdinalIgnoreCase);
var queryIndex = decodedUrl.IndexOf('?');
- if (queryIndex < 0)
+ var reportPath = queryIndex < 0 ? decodedUrl : decodedUrl[..queryIndex];
+ if (queryIndex >= 0)
{
- return (reportName, parameters);
- }
+ var queryString = decodedUrl[(queryIndex + 1)..];
+ var paramPairs = queryString.Split('&', StringSplitOptions.RemoveEmptyEntries);
- reportName = decodedUrl[..queryIndex];
- var queryString = decodedUrl[(queryIndex + 1)..];
- var paramPairs = queryString.Split('&', StringSplitOptions.RemoveEmptyEntries);
-
- foreach (var pair in paramPairs)
- {
- var keyValue = pair.Split('=', 2);
- if (keyValue.Length == 2 && !string.IsNullOrWhiteSpace(keyValue[0]))
+ foreach (var pair in paramPairs)
{
- parameters[keyValue[0]] = keyValue[1];
+ var keyValue = pair.Split('=', 2);
+ if (keyValue.Length == 2 && !string.IsNullOrWhiteSpace(keyValue[0]))
+ {
+ parameters[keyValue[0]] = keyValue[1];
+ }
}
}
+ var pathParts = reportPath
+ .Split('/', StringSplitOptions.RemoveEmptyEntries)
+ .Select(Uri.UnescapeDataString)
+ .ToArray();
+
+ if (pathParts.Length == 0)
+ {
+ return (reportPath, parameters);
+ }
+
+ var reportName = pathParts[0];
+ if (pathParts.Length >= 3 && IsReportActionSegment(pathParts[1]))
+ {
+ AddPathParameters(reportName, pathParts.Skip(2).ToArray(), parameters);
+ }
+
return (reportName, parameters);
}
+ private static void AddPathParameters(string reportName, string[] pathParameters, Dictionary parameters)
+ {
+ if (pathParameters.Length == 0)
+ {
+ return;
+ }
+
+ if (IsDynamicGridReport(reportName) || IsDynamicFormReport(reportName))
+ {
+ if (pathParameters.Length == 1)
+ {
+ parameters.TryAdd("listFormCode", pathParameters[0]);
+ return;
+ }
+
+ parameters.TryAdd("id", pathParameters[0]);
+ parameters.TryAdd("listFormCode", pathParameters[1]);
+ return;
+ }
+
+ parameters.TryAdd("id", pathParameters[0]);
+ }
+
private static bool IsDynamicGridReport(string reportName)
{
return string.Equals(reportName, "DynamicGrid", StringComparison.OrdinalIgnoreCase) ||
@@ -219,6 +256,12 @@ public class CustomReportStorageWebExtension : DevExpress.XtraReports.Web.Extens
string.Equals(reportName, Sozsoft.Reports.PredefinedReports.DynamicFormReport.ReportName, StringComparison.OrdinalIgnoreCase);
}
+ private static bool IsReportActionSegment(string value)
+ {
+ return string.Equals(value, "view", StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(value, "design", StringComparison.OrdinalIgnoreCase);
+ }
+
private static bool HasParameter(Dictionary parameters, string name)
{
return parameters.TryGetValue(name, out var value) && !string.IsNullOrWhiteSpace(value);
diff --git a/ui/src/routes/route.constant.ts b/ui/src/routes/route.constant.ts
index 739d754..847ccbd 100644
--- a/ui/src/routes/route.constant.ts
+++ b/ui/src/routes/route.constant.ts
@@ -50,8 +50,8 @@ export const ROUTES_ENUM = {
dynamicServicesEdit: '/admin/developerkit/dynamic-services/edit/:id',
},
reports: {
- view: '/admin/reports/:id/view',
- design: '/admin/reports/:id/design',
+ view: '/admin/reports/:report/view/:id?/:listFormCode?',
+ design: '/admin/reports/:report/design/:id?/:listFormCode?',
},
},
admin: {
diff --git a/ui/src/views/form/FormButtons.tsx b/ui/src/views/form/FormButtons.tsx
index eebbd3d..5903350 100644
--- a/ui/src/views/form/FormButtons.tsx
+++ b/ui/src/views/form/FormButtons.tsx
@@ -11,6 +11,7 @@ import {
FaEye,
FaSave,
FaCog,
+ FaFileAlt,
} from 'react-icons/fa'
import { useNavigate } from 'react-router-dom'
import { GridColumnData } from '../list/GridColumnData'
@@ -80,6 +81,13 @@ const FormButtons = (props: {
layout,
})
+ const openDynamicGridReport = () => {
+ if (!id) return
+
+ const reportUrl = `/admin/reports/DynamicGrid/view/${encodeURIComponent(id)}/${encodeURIComponent(listFormCode)}`
+ window.open(reportUrl, isPwaMode ? '_self' : '_blank')
+ }
+
const handleDelete = async (e: any) => {
//auth check
e.preventDefault()
@@ -279,7 +287,17 @@ const FormButtons = (props: {
{...(permissions.c || permissions.u ? {} : { disabled: true })}
>
)}
- {checkPermission(gridDto?.gridOptions.permissionDto.c) && !isSubForm && (
+ {id && !isSubForm && (
+ }
+ title={translate('::App.Reports.Form')}
+ onClick={openDynamicGridReport}
+ >
+ )}
+ {checkPermission(gridDto?.gridOptions.permissionDto.u) && !isSubForm && (