Cascading sistem AI tarafından elde geçirildi.

This commit is contained in:
Sedat ÖZTÜRK 2026-10-01 16:58:07 +03:00
parent 81b2202df0
commit 021ddd03d1
7 changed files with 101 additions and 304 deletions

View file

@ -1352,8 +1352,8 @@ cascade eksik yetenek değildir ve analizde `Ready to Start`'ı engellemez. Tam
| `DataSourceType` | `1` StaticData · `2` Query · `3` WebService | | `DataSourceType` | `1` StaticData · `2` Query · `3` WebService |
| `ValueExpr` / `DisplayExpr` | Varsayılan `Key` / `Name` | | `ValueExpr` / `DisplayExpr` | Varsayılan `Key` / `Name` |
| `LookupQuery` | Kaynağın kendisi (tipe göre biçim değişir, aşağıda) | | `LookupQuery` | Kaynağın kendisi (tipe göre biçim değişir, aşağıda) |
| `CascadeParentFields` | **Çocuk alanda** doldurulur; değerleri sorguya taşınacak ebeveyn alan(lar), virgülle. Sırayla `@param0`, `@param1`… olur (`Query`/`WebService`); gelmeyen parametre `NULL` bağlanır | | `CascadeParentFields` | **Çocuk alanda** doldurulur; değerleri sorguya taşınacak ebeveyn alan(lar), virgülle. Sırayla `@param0`, `@param1`… olur (`Query`/`WebService`); boş ya da gelmeyen ebeveyn `NULL` bağlanır. Değer her zaman **metin** parametre olarak bağlanır (`ListFormSelectAppService.ToLookupParameter`), sayı anahtarlı ebeveyn de çalışır; dönüşümü kolon tipine göre veritabanı yapar. `WebService` gövdesine değer JSON kaçışlı yazılır |
| `CascadeRelationField` | **Çocuk alanda** doldurulur; `StaticData`'da ebeveynin değeriyle karşılaştırılan alan (öğedeki `group`) | | `CascadeRelationField` | **Çocuk alanda**, yalnızca `StaticData`'da anlamlıdır: öğede ilk ebeveynin değeriyle karşılaştırılan alan; boşsa `group`. Ebeveyn boşken liste süzülmez |
| `CascadeFilterOperator` | `StaticData` cascade filtresinin operatörü; varsayılan `=` | | `CascadeFilterOperator` | `StaticData` cascade filtresinin operatörü; varsayılan `=` |
| `CascadeEmptyFields` | **Ebeveyn alanda** doldurulur; bu alan değişince boşaltılacak çocuk alanlar, virgülle. Ara halka (İl) hem çocuk hem ebeveyn olduğu için iki tarafı birden taşır | | `CascadeEmptyFields` | **Ebeveyn alanda** doldurulur; bu alan değişince boşaltılacak çocuk alanlar, virgülle. Ara halka (İl) hem çocuk hem ebeveyn olduğu için iki tarafı birden taşır |
@ -1409,7 +1409,8 @@ ya da `EditorOptions`'ta `grouped: true` vardır ve öğeler `group` alanı taş
`[Key]` + `[Name]` takma adlarını döndürür ve `ValueExpr: "Key"`, `DisplayExpr: "Name"` yazılır. `[Key]` + `[Name]` takma adlarını döndürür ve `ValueExpr: "Key"`, `DisplayExpr: "Name"` yazılır.
Bağımlı liste `grouped` ile değil cascade ile kurulur. Bağımlı liste `grouped` ile değil cascade ile kurulur.
> Lookup verisi önbelleklenir; aynı sorgu aynı filtrelerle bir kez yüklenir. > Lookup verisi önbelleklenir; aynı sorgu aynı filtrelerle bir kez yüklenir. Grid, Tree, Card ve
> Form aynı veri kaynağını kullanır (`views/form/useLookupDataSource.ts`); cascade kuralı tek yerdedir.
### 4.3.5 Varsayılan değerler — `*FieldsDefaultValueJson` ### 4.3.5 Varsayılan değerler — `*FieldsDefaultValueJson`

View file

@ -4,6 +4,7 @@ public class LookupRequestDto
{ {
public string ListFormCode { get; set; } public string ListFormCode { get; set; }
public string ListFormFieldName { get; set; } public string ListFormFieldName { get; set; }
public string[] Filters { get; set; } /// <summary>Cascade ebeveyn degerleri, <c>CascadeParentFields</c> sirasiyla; sayi ya da metin olabilir.</summary>
public object[] Filters { get; set; }
} }

View file

@ -418,22 +418,17 @@ public class ListFormSelectAppService : PlatformAppService, IListFormSelectAppSe
var lookup = JsonSerializer.Deserialize<LookupDto>(field.LookupJson); var lookup = JsonSerializer.Deserialize<LookupDto>(field.LookupJson);
if (!string.IsNullOrWhiteSpace(lookup?.LookupQuery)) if (!string.IsNullOrWhiteSpace(lookup?.LookupQuery))
{ {
var parameters = new Dictionary<string, object>(); // Cascade ebeveyn degerleri @param0… olarak baglanir; gelmeyen ebeveyn NULL olur ki
if (input.Filters != null) // sorgu "(Kolon = @param0 OR @param0 IS NULL)" kalibiyla tum listeyi donsun.
{
for (int i = 0; i < input.Filters.Length; i++)
{
parameters.Add("@param" + i, input.Filters[i]);
}
}
var cascadeParameterCount = lookup.CascadeParentFields? var cascadeParameterCount = lookup.CascadeParentFields?
.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) .Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
.Length ?? 0; .Length ?? 0;
var parameterCount = Math.Max(input.Filters?.Length ?? 0, cascadeParameterCount);
for (int i = input.Filters?.Length ?? 0; i < cascadeParameterCount; i++) var parameters = new Dictionary<string, object>();
for (var i = 0; i < parameterCount; i++)
{ {
parameters.Add("@param" + i, null!); parameters.Add("@param" + i, ToLookupParameter(input.Filters, i)!);
} }
var lookupQuery = defaultValueHelper.GetDefaultValue(lookup.LookupQuery); var lookupQuery = defaultValueHelper.GetDefaultValue(lookup.LookupQuery);
@ -444,6 +439,26 @@ public class ListFormSelectAppService : PlatformAppService, IListFormSelectAppSe
return new List<LookupDataDto>(); return new List<LookupDataDto>();
} }
/// <summary>
/// Ebeveyn degeri istemcide sayi, metin ya da bool olabilir; parametre her zaman metin olarak
/// baglanir ki sorgudaki kolon tipine gore veritabani donustursun (int kolona "5" de gider).
/// </summary>
private static string? ToLookupParameter(object[]? filters, int index)
{
var value = filters is not null && index < filters.Length ? filters[index] : null;
return value switch
{
null => null,
JsonElement { ValueKind: JsonValueKind.Null or JsonValueKind.Undefined } => null,
JsonElement { ValueKind: JsonValueKind.String } element => NullIfEmpty(element.GetString()),
JsonElement element => element.GetRawText(),
_ => NullIfEmpty(Convert.ToString(value, CultureInfo.InvariantCulture))
};
static string? NullIfEmpty(string? text) => string.IsNullOrEmpty(text) ? null : text;
}
public async Task<string> GetNextSequenceValueAsync(string SequenceName) public async Task<string> GetNextSequenceValueAsync(string SequenceName)
{ {
var sequenceManager = LazyServiceProvider.LazyGetRequiredService<SequenceManager>(); var sequenceManager = LazyServiceProvider.LazyGetRequiredService<SequenceManager>();
@ -451,93 +466,6 @@ public class ListFormSelectAppService : PlatformAppService, IListFormSelectAppSe
return await sequenceManager.GetNextSequenceAsync(SequenceName); return await sequenceManager.GetNextSequenceAsync(SequenceName);
} }
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;
}
//Workflow kriterlerini alma //Workflow kriterlerini alma
private async Task<List<ListFormWorkflowCriteriaDto>> GetWorkflowCriteriaAsync(string listFormCode) private async Task<List<ListFormWorkflowCriteriaDto>> GetWorkflowCriteriaAsync(string listFormCode)
{ {

View file

@ -39,7 +39,7 @@ type BuildFormItemsParams = {
mode: RowMode mode: RowMode
columns?: GridColumnData[] columns?: GridColumnData[]
/** Lookup alanları için DevExtreme dataSource üretici. */ /** Lookup alanları için DevExtreme dataSource üretici. */
getLookupDataSource: (options: any, colData: ColumnFormatDto, formData: any) => any getLookupDataSource: (colData: ColumnFormatDto, formData: any) => any
formData: any formData: any
} }
@ -57,7 +57,7 @@ const toFormItem = (
const lookupEditorOptions = colFormat.lookupDto?.dataSourceType const lookupEditorOptions = colFormat.lookupDto?.dataSourceType
? { ? {
dataSource: getLookupDataSource(colFormat.editorOptions, colFormat, formData), dataSource: getLookupDataSource(colFormat, formData),
valueExpr: colFormat.lookupDto?.valueExpr?.toLowerCase(), valueExpr: colFormat.lookupDto?.valueExpr?.toLowerCase(),
displayExpr: colFormat.lookupDto?.displayExpr?.toLowerCase(), displayExpr: colFormat.lookupDto?.displayExpr?.toLowerCase(),
} }

View file

@ -262,7 +262,7 @@ const useGridData = (props: {
...item.editorOptions, ...item.editorOptions,
dataSource: keepCustomDataSource dataSource: keepCustomDataSource
? currentDataSource ? currentDataSource
: getLookupDataSource(colData?.editorOptions, colData, formData || null), : getLookupDataSource(colData, formData || null),
valueExpr: valueExpr:
item.editorOptions?.valueExpr ?? colData?.lookupDto?.valueExpr?.toLowerCase(), item.editorOptions?.valueExpr ?? colData?.lookupDto?.valueExpr?.toLowerCase(),
displayExpr: displayExpr:

View file

@ -14,17 +14,48 @@ export { clearLookupCache } from '../shared/lookupCache'
const isLookupAllowed = (listFormCode?: string, isSubForm?: boolean) => const isLookupAllowed = (listFormCode?: string, isSubForm?: boolean) =>
isSubForm || !listFormCode || window.location.pathname.includes(listFormCode) isSubForm || !listFormCode || window.location.pathname.includes(listFormCode)
const createLookupStaticDataSource = ( const splitFields = (value?: string | null) =>
(value ?? '')
.split(',')
.map((field) => field.trim())
.filter(Boolean)
const isEmptyValue = (value: unknown) => value === undefined || value === null || value === ''
/**
* Cascade filtresi. Query/WebService için ebeveyn değerleri sırayla `@param0…` olur; boş ebeveyn
* `null` gider ve sorgu `(Kolon = @param0 OR @param0 IS NULL)` kalıbıyla tüm listeyi döner.
* StaticData için öğelerdeki `CascadeRelationField` alanı (varsayılan `group`) ilk ebeveynin
* değeriyle karşılaştırılır; ebeveyn boşsa süzülmez.
*/
export const buildCascadeFilters = (lookupDto: any, rowData: any): any[] | null => {
const parentFields = splitFields(lookupDto?.cascadeParentFields)
if (!parentFields.length) return null
if (lookupDto.dataSourceType == UiLookupDataSourceTypeEnum.StaticData) {
const parentValue = rowData?.[parentFields[0]]
if (isEmptyValue(parentValue)) return null
return [
lookupDto.cascadeRelationField || 'group',
lookupDto.cascadeFilterOperator || '=',
parentValue,
]
}
return parentFields.map((field) => (isEmptyValue(rowData?.[field]) ? null : rowData[field]))
}
export const createLookupStaticDataSource = (
load: () => any, load: () => any,
filter: any = null, filter: any[] | null,
key: any = 'static', cacheKey: string,
sort: any = 'name', sort = 'name',
) => ({ ) => ({
store: new CustomStore({ store: new CustomStore({
key,
loadMode: 'raw', loadMode: 'raw',
load: () => load: () =>
cachedLookupLoad(`static:${key}`, async () => { cachedLookupLoad(`static:${cacheKey}`, async () => {
const result = await Promise.resolve(load()) const result = await Promise.resolve(load())
if (result === undefined || result === null) return [] if (result === undefined || result === null) return []
return Array.isArray(result) ? result : [result] return Array.isArray(result) ? result : [result]
@ -34,10 +65,10 @@ const createLookupStaticDataSource = (
filter, filter,
}) })
const createLookupQueryDataSource = ( export const createLookupQueryDataSource = (
listFormCode?: string, listFormCode?: string,
listFormFieldName?: string, listFormFieldName?: string,
filters?: any[], filters?: any[] | null,
isSubForm?: boolean, isSubForm?: boolean,
) => ) =>
new CustomStore({ new CustomStore({
@ -72,10 +103,13 @@ const createLookupQueryDataSource = (
}, },
}) })
const createLookupApiDataSource = ( /** Gövde JSON şablonudur; değer tırnak içine yerleştiği için JSON kaçışlı yazılır. */
const toJsonText = (value: unknown) => (value === null ? 'null' : JSON.stringify(String(value)).slice(1, -1))
export const createLookupApiDataSource = (
listFormCode?: string, listFormCode?: string,
lookupQuery?: string, lookupQuery?: string,
filters?: any[], filters?: any[] | null,
keyName?: string, keyName?: string,
isSubForm?: boolean, isSubForm?: boolean,
) => ) =>
@ -99,7 +133,7 @@ const createLookupApiDataSource = (
// Gövdedeki @param0, @param1… yer tutucularını cascade filtreleriyle doldur. // Gövdedeki @param0, @param1… yer tutucularını cascade filtreleriyle doldur.
let resolvedBody = bodyTemplate ?? '' let resolvedBody = bodyTemplate ?? ''
filters?.forEach((filterValue, index) => { filters?.forEach((filterValue, index) => {
resolvedBody = resolvedBody.replace(new RegExp(`@param${index}`, 'g'), String(filterValue)) resolvedBody = resolvedBody.replace(new RegExp(`@param${index}\\b`, 'g'), toJsonText(filterValue))
}) })
try { try {
@ -129,6 +163,10 @@ const createLookupApiDataSource = (
}, },
}) })
/**
* Lookup kolonunun veri kaynağı. Grid/Tree/Card (`useListFormColumns`) ve Form aynı kuralı
* kullanır; `rowData` cascade ebeveynlerinin okunduğu kayıttır.
*/
export const useLookupDataSource = ({ export const useLookupDataSource = ({
listFormCode, listFormCode,
isSubForm, isSubForm,
@ -139,24 +177,9 @@ export const useLookupDataSource = ({
const { translate, cultureName } = useLocalization() const { translate, cultureName } = useLocalization()
const getLookupDataSource = useCallback( const getLookupDataSource = useCallback(
(options: any, colData: any, data: any) => { (colData: any, rowData: any) => {
const { lookupDto } = colData const { lookupDto } = colData
const filters: any[] = [] const filters = buildCascadeFilters(lookupDto, rowData)
// Cascading alanlar: parent değeri yoksa null gönderilir, istek yine de yapılır.
if (lookupDto.cascadeParentFields) {
if (lookupDto.dataSourceType == UiLookupDataSourceTypeEnum.StaticData) {
filters.push([
lookupDto?.cascadeRelationField,
lookupDto?.cascadeFilterOperator,
options?.data?.[lookupDto?.cascadeParentField] ?? null,
])
} else {
for (const cascadeParentField of lookupDto.cascadeParentFields.split(',')) {
filters.push(data?.[cascadeParentField.trim()] ?? null)
}
}
}
switch (lookupDto.dataSourceType) { switch (lookupDto.dataSourceType) {
case UiLookupDataSourceTypeEnum.StaticData: case UiLookupDataSourceTypeEnum.StaticData:
@ -166,8 +189,8 @@ export const useLookupDataSource = ({
...item, ...item,
name: typeof item.name === 'string' ? translate(`::${item.name}`) : item.name, name: typeof item.name === 'string' ? translate(`::${item.name}`) : item.name,
})), })),
filters.length ? filters : null, filters,
`static:${cultureName}:${listFormCode}:${colData.fieldName}`, `${cultureName}:${listFormCode}:${colData.fieldName}`,
) )
case UiLookupDataSourceTypeEnum.Query: case UiLookupDataSourceTypeEnum.Query:
return createLookupQueryDataSource(listFormCode, colData.fieldName, filters, isSubForm) return createLookupQueryDataSource(listFormCode, colData.fieldName, filters, isSubForm)

View file

@ -17,11 +17,8 @@ import {
UiLookupDataSourceTypeEnum, UiLookupDataSourceTypeEnum,
} from '@/proxy/form/models' } from '@/proxy/form/models'
import { addCss, getEditingFormFields } from './Utils' import { addCss, getEditingFormFields } from './Utils'
import { import { clearLookupCache, clearLookupCacheByPrefix } from '../shared/lookupCache'
cachedLookupLoad, import { useLookupDataSource } from '../form/useLookupDataSource'
clearLookupCache,
clearLookupCacheByPrefix,
} from '../shared/lookupCache'
import { import {
NO_IMAGE, NO_IMAGE,
normalizeImageSize, normalizeImageSize,
@ -169,7 +166,7 @@ const useListFormColumns = ({
onShowNote?: (rowData: Record<string, any>) => void onShowNote?: (rowData: Record<string, any>) => void
}) => { }) => {
const dialog: any = useDialogContext() const dialog: any = useDialogContext()
const { translate, cultureName } = useLocalization() const { translate } = useLocalization()
const { checkPermission } = usePermission() const { checkPermission } = usePermission()
const isPwaMode = usePWA() const isPwaMode = usePWA()
@ -178,55 +175,12 @@ const useListFormColumns = ({
clearLookupCache() clearLookupCache()
}, [listFormCode]) }, [listFormCode])
const { getLookupDataSource } = useLookupDataSource({ listFormCode, isSubForm })
// DataGrid lookup'ı satırı `options.data` ile verir; görünen metin yüklemesi satırsız çağırır.
const lookupDataSource = useCallback( const lookupDataSource = useCallback(
(options: any, colData: any, listFormCode: string) => { (options: any, colData: any) => getLookupDataSource(colData, options?.data ?? options),
const { lookupDto } = colData [getLookupDataSource],
const filters = []
if (lookupDto.cascadeParentFields) {
if (lookupDto.dataSourceType == UiLookupDataSourceTypeEnum.StaticData) {
filters.push([
lookupDto?.cascadeRelationField,
lookupDto?.cascadeFilterOperator,
options?.data[lookupDto?.cascadeParentField],
])
//TODO: Statik data test edilecek
} else {
const data = options?.data ?? options
for (const cascadeParentField of lookupDto.cascadeParentFields.split(',')) {
filters.push(data[cascadeParentField])
}
}
}
//UiLookupDataSourceTypeEnum :
// Data = 1 (Statik Data),
// Query = 2 (API'den geliyor fakat API query çalıştırıyor)
// WebService = 3 (API servisten geliyor)
if (lookupDto.dataSourceType == UiLookupDataSourceTypeEnum.StaticData) {
return createLookupStaticDataSource(
() =>
JSON.parse(lookupDto?.lookupQuery).map((item: any) => ({
...item,
name: typeof item.name === 'string' ? translate(`::${item.name}`) : item.name,
})),
filters.length ? filters : null,
`static:${cultureName}:${listFormCode}:${colData.fieldName}`, // cache key
)
} else if (lookupDto.dataSourceType == UiLookupDataSourceTypeEnum.Query) {
return createLookupQueryDataSource(listFormCode, colData.fieldName, filters)
} else if (lookupDto.dataSourceType == UiLookupDataSourceTypeEnum.WebService) {
return createLookupApiDataSource(
listFormCode,
lookupDto?.lookupQuery,
filters,
colData.lookupDto?.valueExpr?.toLowerCase(),
)
} else {
return {
store: [],
}
}
},
[listFormCode, translate, cultureName],
) )
const loadLookupDisplayValues = useCallback( const loadLookupDisplayValues = useCallback(
@ -241,7 +195,7 @@ const useListFormColumns = ({
) )
.map(async (column) => { .map(async (column) => {
const lookup = column.colData!.lookupDto const lookup = column.colData!.lookupDto
const source = lookupDataSource({}, column.colData, listFormCode) const source = lookupDataSource({}, column.colData)
const store = const store =
source instanceof CustomStore source instanceof CustomStore
? source ? source
@ -270,7 +224,7 @@ const useListFormColumns = ({
return Object.fromEntries(entries) as Record<string, Map<string, string>> return Object.fromEntries(entries) as Record<string, Map<string, string>>
}, },
[listFormCode, lookupDataSource], [lookupDataSource],
) )
/** /**
@ -311,7 +265,7 @@ const useListFormColumns = ({
const prefix = getCachePrefix(colData) const prefix = getCachePrefix(colData)
if (!prefix) return if (!prefix) return
const source = lookupDataSource({}, colData, listFormCode) const source = lookupDataSource({}, colData)
const store = const store =
source instanceof CustomStore source instanceof CustomStore
? source ? source
@ -347,115 +301,6 @@ const useListFormColumns = ({
[gridDto, listFormCode, lookupDataSource], [gridDto, listFormCode, lookupDataSource],
) )
const createLookupStaticDataSource = (
load: () => any,
filter: any = null,
key: any = 'static',
sort: any = 'name',
) => ({
store: new CustomStore({
key,
loadMode: 'raw',
load: async () => {
// load fonksiyonu sync sonuç döndürüyor olabilir, o yüzden Promise.resolve ile sar
return cachedLookupLoad(`static:${key}`, async () => {
const result = await Promise.resolve(load())
if (result === undefined || result === null) return []
return Array.isArray(result) ? result : [result]
})
},
}),
sort,
filter,
})
const createLookupQueryDataSource = (
listFormCode?: string,
listFormFieldName?: string,
filters?: any[],
) => {
return new CustomStore({
loadMode: 'raw',
load: async () => {
if (!isSubForm && listFormCode && !window.location.pathname.includes(listFormCode)) {
return []
}
try {
const cacheKey = `query:${listFormCode}:${listFormFieldName}:${JSON.stringify(filters ?? null)}`
return cachedLookupLoad(cacheKey, async () => {
const response = await dynamicFetch('list-form-select/lookup', 'POST', null, {
listFormCode,
listFormFieldName,
filters,
})
return (response.data ?? []).map((a: any) => ({
key: a.Key,
name: a.Name,
group: a.Group,
...a,
}))
})
} catch (error) {
console.error('Lookup query data could not be loaded:', error)
return []
}
},
})
}
const createLookupApiDataSource = (
listFormCode?: string,
lookupQuery?: string,
filters?: any[],
keyName?: string,
) => {
return new CustomStore({
key: keyName,
loadMode: 'raw',
load: async () => {
if (!isSubForm && listFormCode && !window.location.pathname.includes(listFormCode)) {
return []
}
if (!lookupQuery) {
return []
}
const [method, url, body, keySelector, nameSelector, groupSelector] = lookupQuery.split(';')
// body içindeki @paramN'leri filtrelerle değiştir
let resolvedBody = body
if (filters?.length) {
for (let i = 0; i < filters.length; i++) {
resolvedBody = resolvedBody.replace(new RegExp(`@param${i}`, 'g'), filters[i])
}
}
try {
const cacheKey = `api:${lookupQuery}:${JSON.stringify(filters ?? null)}`
return cachedLookupLoad(cacheKey, async () => {
const response = await dynamicFetch(url, method, null, resolvedBody)
let { data } = response
if (!data) return []
if (!Array.isArray(data)) data = [data]
return data.map((a: any) => ({
key: eval(keySelector),
name: eval(nameSelector),
group: eval(groupSelector),
...a,
}))
})
} catch (error) {
console.error('Lookup API data could not be loaded:', error)
return []
}
},
})
}
const getCommandColumn = useCallback((): GridColumnData | undefined => { const getCommandColumn = useCallback((): GridColumnData | undefined => {
if (!gridDto) { if (!gridDto) {
return return
@ -817,9 +662,8 @@ const useListFormColumns = ({
column.lookup = { column.lookup = {
valueExpr: colData.lookupDto?.valueExpr?.toLowerCase(), valueExpr: colData.lookupDto?.valueExpr?.toLowerCase(),
displayExpr: colData.lookupDto?.displayExpr?.toLowerCase(), displayExpr: colData.lookupDto?.displayExpr?.toLowerCase(),
dataSource: (o) => lookupDataSource(o, colData, listFormCode), dataSource: (o) => lookupDataSource(o, colData),
} }
//column.lookup.dataSource = lookupDataSource(null, colData)
//cascadeEmptyFields verisi dolu ise bu kolon/field bir parent field dir //cascadeEmptyFields verisi dolu ise bu kolon/field bir parent field dir
if (colData.lookupDto.cascadeEmptyFields) { if (colData.lookupDto.cascadeEmptyFields) {
@ -891,7 +735,7 @@ const useListFormColumns = ({
return columns return columns
}, },
[gridDto, lookupDataSource, translate, checkPermission, dialog, isPwaMode, listFormCode], [gridDto, lookupDataSource, translate],
) )
const getBandedColumns = useCallback(() => { const getBandedColumns = useCallback(() => {