Grid performans çalışması
This commit is contained in:
parent
4eb43bd6de
commit
c366b6499c
6 changed files with 157 additions and 70 deletions
|
|
@ -394,5 +394,92 @@ public class ListFormSelectAppService : PlatformAppService, IListFormSelectAppSe
|
||||||
|
|
||||||
return new List<LookupDataDto>();
|
return new List<LookupDataDto>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string WrapLookupQueryWithInFilter(
|
||||||
|
string lookupQuery,
|
||||||
|
string listFormSelectCommand,
|
||||||
|
string listFormFieldName)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(lookupQuery))
|
||||||
|
throw new ArgumentException("LookupQuery boş olamaz.");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(listFormSelectCommand))
|
||||||
|
throw new ArgumentException("SelectCommand boş olamaz.");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(listFormFieldName))
|
||||||
|
throw new ArgumentException("ListFormFieldName boş olamaz.");
|
||||||
|
|
||||||
|
return $@"
|
||||||
|
SELECT *
|
||||||
|
FROM (
|
||||||
|
{lookupQuery}
|
||||||
|
) t
|
||||||
|
WHERE ""Key"" IN (
|
||||||
|
SELECT ""{listFormFieldName}""
|
||||||
|
FROM ""{listFormSelectCommand}""
|
||||||
|
GROUP BY ""{listFormFieldName}""
|
||||||
|
)";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string AddCascadeWhereCondition(
|
||||||
|
string sql,
|
||||||
|
string cascadeParentFields,
|
||||||
|
int paramStartIndex = 0)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(sql))
|
||||||
|
throw new ArgumentException("SQL boş olamaz.");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(cascadeParentFields))
|
||||||
|
return sql;
|
||||||
|
|
||||||
|
var fields = cascadeParentFields
|
||||||
|
.Split(',', StringSplitOptions.RemoveEmptyEntries)
|
||||||
|
.Select(f => f.Trim())
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
if (!fields.Any())
|
||||||
|
return sql;
|
||||||
|
|
||||||
|
var conditions = new List<string>();
|
||||||
|
for (int i = 0; i < fields.Length; i++)
|
||||||
|
{
|
||||||
|
var field = fields[i];
|
||||||
|
|
||||||
|
// Zaten " ile başlıyorsa dokunma
|
||||||
|
if (!field.StartsWith("\""))
|
||||||
|
field = $"\"{field}\"";
|
||||||
|
|
||||||
|
conditions.Add($"{field} = @param{paramStartIndex + i}");
|
||||||
|
}
|
||||||
|
|
||||||
|
string whereClause = string.Join(" AND ", conditions);
|
||||||
|
var upperSql = sql.ToUpperInvariant();
|
||||||
|
|
||||||
|
if (upperSql.Contains(" WHERE "))
|
||||||
|
{
|
||||||
|
return InsertBeforeClause(sql, "AND " + whereClause);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return InsertBeforeClause(sql, "WHERE " + whereClause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string InsertBeforeClause(string sql, string insertText)
|
||||||
|
{
|
||||||
|
var upperSql = sql.ToUpperInvariant();
|
||||||
|
string[] clauses = { " GROUP BY ", " ORDER BY ", " HAVING " };
|
||||||
|
|
||||||
|
foreach (var clause in clauses)
|
||||||
|
{
|
||||||
|
int index = upperSql.IndexOf(clause);
|
||||||
|
if (index > -1)
|
||||||
|
{
|
||||||
|
return sql.Insert(index, " " + insertText + " ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sql + " " + insertText;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1826,7 +1826,7 @@ public class ListFormSeeder_Hr : IDataSeedContributor, ITransientDependency
|
||||||
new() {
|
new() {
|
||||||
ListFormCode = listForm.ListFormCode,
|
ListFormCode = listForm.ListFormCode,
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
SourceDbType = DbType.Guid,
|
SourceDbType = DbType.String,
|
||||||
FieldName = "JobPositionId",
|
FieldName = "JobPositionId",
|
||||||
CaptionName = "App.Listform.ListformField.JobPositionId",
|
CaptionName = "App.Listform.ListformField.JobPositionId",
|
||||||
Width = 200,
|
Width = 200,
|
||||||
|
|
@ -1948,9 +1948,9 @@ public class ListFormSeeder_Hr : IDataSeedContributor, ITransientDependency
|
||||||
DisplayExpr = "name",
|
DisplayExpr = "name",
|
||||||
ValueExpr = "key",
|
ValueExpr = "key",
|
||||||
LookupQuery = JsonSerializer.Serialize(new LookupDataDto[] {
|
LookupQuery = JsonSerializer.Serialize(new LookupDataDto[] {
|
||||||
new () { Key= "Hours", Name= "Hours" },
|
new () { Key= "Hourly", Name= "Hourly" },
|
||||||
new () { Key= "Weeks", Name= "Weeks" },
|
new () { Key= "Weekly", Name= "Weekly" },
|
||||||
new () { Key= "Months", Name= "Months" }
|
new () { Key= "Monthly", Name= "Monthly" }
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
ValidationRuleJson = DefaultValidationRuleRequiredJson,
|
ValidationRuleJson = DefaultValidationRuleRequiredJson,
|
||||||
|
|
|
||||||
|
|
@ -2527,7 +2527,7 @@
|
||||||
"Url": null,
|
"Url": null,
|
||||||
"Icon": "FcServices",
|
"Icon": "FcServices",
|
||||||
"RequiredPermissionName": null,
|
"RequiredPermissionName": null,
|
||||||
"IsDisabled": false,
|
"IsDisabled": true,
|
||||||
"ShortName": "Mrp"
|
"ShortName": "Mrp"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -113,18 +113,25 @@ const FormButtons = (props: {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const toolbarExcludedNames = ['deleteAllRecords', 'deleteSelectedRecords', 'refreshButton']
|
||||||
|
const hasVisibleToolbarButtons = toolbarData?.some(
|
||||||
|
(item) => item.widget == 'dxButton' && !toolbarExcludedNames.includes(item.name!),
|
||||||
|
)
|
||||||
|
|
||||||
|
const commandExcludedNames = ['edit', 'delete']
|
||||||
|
const hasVisibleCommandButtons = commandColumnData?.buttons?.some(
|
||||||
|
(item) => typeof item !== 'string' && !commandExcludedNames.includes(item.name!),
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="flex flex-row items-center gap-1">
|
<div className="flex flex-row items-center gap-1">
|
||||||
{toolbarData
|
{toolbarData
|
||||||
?.filter(
|
?.filter(
|
||||||
(item) =>
|
(item) => item.widget == 'dxButton' && !toolbarExcludedNames.includes(item.name!),
|
||||||
item.widget == 'dxButton' &&
|
|
||||||
item.name != 'deleteAllRecords' &&
|
|
||||||
item.name != 'deleteSelectedRecords',
|
|
||||||
)
|
)
|
||||||
.map((item, i) => {
|
.map((item, i) => {
|
||||||
const IconComp = navigationIcon[item.options?.icon] // React bileşeni olabilir ya da undefined
|
const IconComp = navigationIcon[item.options?.icon]
|
||||||
const hasValidIcon =
|
const hasValidIcon =
|
||||||
IconComp &&
|
IconComp &&
|
||||||
(typeof IconComp === 'function' ||
|
(typeof IconComp === 'function' ||
|
||||||
|
|
@ -135,24 +142,21 @@ const FormButtons = (props: {
|
||||||
key={'toolbarButton-' + i}
|
key={'toolbarButton-' + i}
|
||||||
variant="default"
|
variant="default"
|
||||||
size="xs"
|
size="xs"
|
||||||
icon={
|
icon={hasValidIcon ? <IconComp className="text-gray-400" /> : null}
|
||||||
hasValidIcon ? <IconComp className="text-gray-400" /> : null // 🔒 güvenli render
|
|
||||||
}
|
|
||||||
onClick={item.options?.onClick}
|
onClick={item.options?.onClick}
|
||||||
>
|
>
|
||||||
{item.options?.text}
|
{item.options?.text}
|
||||||
</Button>
|
</Button>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
{!!toolbarData?.filter(
|
|
||||||
(item) =>
|
{hasVisibleToolbarButtons && <Badge innerClass="bg-blue-500" />}
|
||||||
item.widget == 'dxButton' &&
|
|
||||||
item.name != 'deleteAllRecords' &&
|
|
||||||
item.name != 'deleteSelectedRecords',
|
|
||||||
).length && <Badge innerClass="bg-blue-500" />}
|
|
||||||
{commandColumnData?.buttons
|
{commandColumnData?.buttons
|
||||||
?.filter((item) => typeof item !== 'string')
|
?.filter((item) => typeof item !== 'string' && !commandExcludedNames.includes(item.name!))
|
||||||
.map((item, i) => {
|
.map((item: any, i) => {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
key={'commandColumnButton-' + i}
|
key={'commandColumnButton-' + i}
|
||||||
|
|
@ -171,9 +175,8 @@ const FormButtons = (props: {
|
||||||
</Button>
|
</Button>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
{!!commandColumnData?.buttons?.filter((item) => typeof item !== 'string').length && (
|
|
||||||
<Badge innerClass="bg-blue-500" />
|
{hasVisibleCommandButtons && <Badge innerClass="bg-blue-500" />}
|
||||||
)}
|
|
||||||
|
|
||||||
{!isSubForm && (
|
{!isSubForm && (
|
||||||
<Button
|
<Button
|
||||||
|
|
|
||||||
|
|
@ -426,31 +426,29 @@ const Grid = (props: GridProps) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tüm cascade fieldlerin disabled durumlarını güncelle
|
// Tüm cascade fieldlerin disabled durumlarını güncelle
|
||||||
setTimeout(() => {
|
const popup = grid.option('editing.popup')
|
||||||
const popup = grid.option('editing.popup')
|
if (popup) {
|
||||||
if (popup) {
|
const formInstance = grid.option('editing.form') as any
|
||||||
const formInstance = grid.option('editing.form') as any
|
if (formInstance && formInstance.getEditor) {
|
||||||
if (formInstance && formInstance.getEditor) {
|
gridDto.columnFormats.forEach((col) => {
|
||||||
gridDto.columnFormats.forEach((col) => {
|
if (col.lookupDto?.cascadeParentFields) {
|
||||||
if (col.lookupDto?.cascadeParentFields) {
|
const colParentFields = col.lookupDto.cascadeParentFields
|
||||||
const colParentFields = col.lookupDto.cascadeParentFields
|
.split(',')
|
||||||
.split(',')
|
.map((f: string) => f.trim())
|
||||||
.map((f: string) => f.trim())
|
const shouldDisable = colParentFields.some((pf: string) => !rowData[pf])
|
||||||
const shouldDisable = colParentFields.some((pf: string) => !rowData[pf])
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const editorInstance = formInstance.getEditor(col.fieldName!)
|
const editorInstance = formInstance.getEditor(col.fieldName!)
|
||||||
if (editorInstance) {
|
if (editorInstance) {
|
||||||
editorInstance.option('disabled', shouldDisable)
|
editorInstance.option('disabled', shouldDisable)
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.debug('Cascade disabled update skipped for', col.fieldName, err)
|
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.debug('Cascade disabled update skipped for', col.fieldName, err)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}, 50)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// İlk açılışta disabled durumunu kontrol et
|
// İlk açılışta disabled durumunu kontrol et
|
||||||
|
|
@ -931,6 +929,9 @@ const Grid = (props: GridProps) => {
|
||||||
onEditingStart={onEditingStart}
|
onEditingStart={onEditingStart}
|
||||||
onDataErrorOccurred={onDataErrorOccurred}
|
onDataErrorOccurred={onDataErrorOccurred}
|
||||||
onExporting={onExporting}
|
onExporting={onExporting}
|
||||||
|
onEditCanceling={() => {
|
||||||
|
setMode('view')
|
||||||
|
}}
|
||||||
onEditCanceled={() => {
|
onEditCanceled={() => {
|
||||||
isEditingRef.current = false
|
isEditingRef.current = false
|
||||||
setMode('view')
|
setMode('view')
|
||||||
|
|
|
||||||
|
|
@ -445,31 +445,29 @@ const Tree = (props: TreeProps) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tüm cascade fieldlerin disabled durumlarını güncelle
|
// Tüm cascade fieldlerin disabled durumlarını güncelle
|
||||||
setTimeout(() => {
|
const popup = grid.option('editing.popup')
|
||||||
const popup = grid.option('editing.popup')
|
if (popup) {
|
||||||
if (popup) {
|
const formInstance = grid.option('editing.form') as any
|
||||||
const formInstance = grid.option('editing.form') as any
|
if (formInstance && formInstance.getEditor) {
|
||||||
if (formInstance && formInstance.getEditor) {
|
gridDto.columnFormats.forEach((col) => {
|
||||||
gridDto.columnFormats.forEach((col) => {
|
if (col.lookupDto?.cascadeParentFields) {
|
||||||
if (col.lookupDto?.cascadeParentFields) {
|
const colParentFields = col.lookupDto.cascadeParentFields
|
||||||
const colParentFields = col.lookupDto.cascadeParentFields
|
.split(',')
|
||||||
.split(',')
|
.map((f: string) => f.trim())
|
||||||
.map((f: string) => f.trim())
|
const shouldDisable = colParentFields.some((pf: string) => !rowData[pf])
|
||||||
const shouldDisable = colParentFields.some((pf: string) => !rowData[pf])
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const editorInstance = formInstance.getEditor(col.fieldName!)
|
const editorInstance = formInstance.getEditor(col.fieldName!)
|
||||||
if (editorInstance) {
|
if (editorInstance) {
|
||||||
editorInstance.option('disabled', shouldDisable)
|
editorInstance.option('disabled', shouldDisable)
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.debug('Cascade disabled update skipped for', col.fieldName, err)
|
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.debug('Cascade disabled update skipped for', col.fieldName, err)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}, 50)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// İlk açılışta disabled durumunu kontrol et
|
// İlk açılışta disabled durumunu kontrol et
|
||||||
|
|
@ -1163,9 +1161,7 @@ const Tree = (props: TreeProps) => {
|
||||||
<ColumnFixing
|
<ColumnFixing
|
||||||
enabled={gridDto.gridOptions.columnOptionDto?.columnFixingEnabled}
|
enabled={gridDto.gridOptions.columnOptionDto?.columnFixingEnabled}
|
||||||
></ColumnFixing>
|
></ColumnFixing>
|
||||||
<Scrolling
|
<Scrolling mode={gridDto.gridOptions.pagerOptionDto?.scrollingMode}></Scrolling>
|
||||||
mode={gridDto.gridOptions.pagerOptionDto?.scrollingMode}
|
|
||||||
></Scrolling>
|
|
||||||
<LoadPanel
|
<LoadPanel
|
||||||
enabled={gridDto.gridOptions.pagerOptionDto?.loadPanelEnabled}
|
enabled={gridDto.gridOptions.pagerOptionDto?.loadPanelEnabled}
|
||||||
text={gridDto.gridOptions.pagerOptionDto?.loadPanelText}
|
text={gridDto.gridOptions.pagerOptionDto?.loadPanelText}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue