editorScript ve Seeder
This commit is contained in:
parent
65af5fa231
commit
ea37ef0682
15 changed files with 324 additions and 296 deletions
|
|
@ -46,5 +46,6 @@ public class EditingFormItemDto
|
|||
public bool IsRequired { get; set; }
|
||||
public GridBoxOptionsDto GridBoxOptions { get; set; }
|
||||
public TagBoxOptionsDto TagBoxOptions { get; set; }
|
||||
public string Script { get; set; }
|
||||
[JsonPropertyName("editorScript")]
|
||||
public string EditorScript { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35399,9 +35399,9 @@ public class ListFormsSeeder : IDataSeedContributor, ITransientDependency
|
|||
new EditingFormItemDto { Order = 1, DataField = "AppliedDate", ColSpan = 2, IsRequired=true, EditorType2 = EditorTypes.dxDateBox},
|
||||
new EditingFormItemDto { Order = 2, DataField = "EmployeeId", ColSpan = 2, IsRequired = true, EditorType2 = EditorTypes.dxSelectBox },
|
||||
new EditingFormItemDto { Order = 3, DataField = "LeaveType", ColSpan = 2, IsRequired = true, EditorType2 = EditorTypes.dxSelectBox },
|
||||
new EditingFormItemDto { Order = 4, DataField = "StartDate", ColSpan = 2, IsRequired=true, EditorType2 = EditorTypes.dxDateBox},
|
||||
new EditingFormItemDto { Order = 5, DataField = "EndDate", ColSpan = 2, IsRequired=true, EditorType2 = EditorTypes.dxDateBox},
|
||||
new EditingFormItemDto { Order = 6, DataField = "TotalDays", ColSpan = 2, EditorType2 = EditorTypes.dxNumberBox},
|
||||
new EditingFormItemDto { Order = 4, DataField = "StartDate", ColSpan = 2, IsRequired=true, EditorType2 = EditorTypes.dxDateBox, EditorScript = EditorOptionValues.DateDiffStartDateEndDate},
|
||||
new EditingFormItemDto { Order = 5, DataField = "EndDate", ColSpan = 2, IsRequired=true, EditorType2 = EditorTypes.dxDateBox, EditorScript = EditorOptionValues.DateDiffStartDateEndDate},
|
||||
new EditingFormItemDto { Order = 6, DataField = "TotalDays", ColSpan = 2, EditorType2 = EditorTypes.dxNumberBox, EditorOptions = EditorOptionValues.Disabled},
|
||||
new EditingFormItemDto { Order = 7, DataField = "IsHalfDay", ColSpan = 2, EditorType2 = EditorTypes.dxCheckBox},
|
||||
new EditingFormItemDto { Order = 8, DataField = "Reason", ColSpan = 2, IsRequired = true, EditorType2 = EditorTypes.dxTextArea},
|
||||
new EditingFormItemDto { Order = 9, DataField = "Status", ColSpan = 2, IsRequired = true, EditorType2 = EditorTypes.dxSelectBox},
|
||||
|
|
|
|||
|
|
@ -19,9 +19,11 @@ public static class PlatformConsts
|
|||
|
||||
public static class EditorOptionValues
|
||||
{
|
||||
public static string Disabled = "{ \"disabled\" : true }";
|
||||
public static string ShowClearButton = "{ \"showClearButton\" : true }";
|
||||
public static string HtmlEditorOptions = "{\"toolbar\": {\"multiline\": true, \"items\": [{\"name\": \"undo\"},{\"name\": \"redo\"},{\"name\": \"separator\"},{\"name\": \"size\",\"acceptedValues\": [\"8pt\",\"10pt\",\"12pt\",\"14pt\",\"18pt\",\"24pt\",\"36pt\"],\"options\": {\"inputAttr\": {\"aria-label\": \"Font size\"}}},{\"name\": \"font\",\"acceptedValues\": [\"Arial\",\"Courier New\",\"Georgia\",\"Impact\",\"Lucida Console\",\"Tahoma\",\"Times New Roman\",\"Verdana\"],\"options\": {\"inputAttr\": {\"aria-label\": \"Font family\"}}},{\"name\": \"separator\"},{\"name\": \"bold\"},{\"name\": \"italic\"},{\"name\": \"strike\"},{\"name\": \"underline\"},{\"name\": \"separator\"},{\"name\": \"alignLeft\"},{\"name\": \"alignCenter\"},{\"name\": \"alignRight\"},{\"name\": \"alignJustify\"},{\"name\": \"separator\"},{\"name\": \"orderedList\"},{\"name\": \"bulletList\"},{\"name\": \"separator\"},{\"name\": \"header\",\"acceptedValues\": [false,1,2,3,4,5],\"options\": {\"inputAttr\": {\"aria-label\": \"Font family\"}}},{\"name\": \"separator\"},{\"name\": \"color\"},{\"name\": \"background\"},{\"name\": \"separator\"},{\"name\": \"link\"},{\"name\": \"image\"},{\"name\": \"separator\"},{\"name\": \"clear\"},{\"name\": \"codeBlock\"},{\"name\": \"blockquote\"},{\"name\": \"separator\"},{\"name\": \"insertTable\"},{\"name\": \"deleteTable\"},{\"name\": \"insertRowAbove\"},{\"name\": \"insertRowBelow\"},{\"name\": \"deleteRow\"},{\"name\": \"insertColumnLeft\"},{\"name\": \"insertColumnRight\"},{\"name\": \"deleteColumn\"}]}}";
|
||||
public static string PhoneEditorOptions = "{\"format\": \"phoneGlobal\", \"mask\":\"(000) 000-0000\", \"maskInvalidMessage\":\"Lütfen geçerli bir telefon numarası girin\", \"useMaskedValue\":false, \"maskRules\": { \"X\": \"[1-9]\" }, \"placeholder\": \"(555) 123-4567\" }";
|
||||
public static string DateDiffStartDateEndDate = "(() => {const d=v=>!v?null:(v instanceof Date?v:new Date(v));const nf={...formData,[editor.dataField]:e?.value};const s=d(nf.StartDate),t=d(nf.EndDate);setFormData({...formData,TotalDays: s&&t?Math.max(0,Math.floor((Date.UTC(t.getFullYear(),t.getMonth(),t.getDate())-Date.UTC(s.getFullYear(),s.getMonth(),s.getDate()))/(24*60*60*1000))+1):null});})();";
|
||||
}
|
||||
|
||||
public static class Prefix
|
||||
|
|
|
|||
|
|
@ -2719,14 +2719,14 @@
|
|||
"district": "Ankara",
|
||||
"street": "Kızılay Cd. No:12",
|
||||
"postalCode": "06050",
|
||||
"phone": "+90 212 555 0100",
|
||||
"personalPhone": "+90 532 555 0101",
|
||||
"phone": "2125550100",
|
||||
"personalPhone": "5325550101",
|
||||
"email": "ali.ozturk@company.com",
|
||||
"address1": "",
|
||||
"address2": "",
|
||||
"emergencyContactname": "Ayşe Öztürk",
|
||||
"emergencyContactrelationship": "Eşi",
|
||||
"emergencyContactphone": "+90 532 555 0100",
|
||||
"emergencyContactphone": "5325550100",
|
||||
"hireDate": "15-01-2020",
|
||||
"terminationDate": "15-01-2020",
|
||||
"employmentTypeName": "FullTime",
|
||||
|
|
@ -2759,14 +2759,14 @@
|
|||
"district": "Ankara",
|
||||
"street": "İnönü Bulvarı No:456",
|
||||
"postalCode": "06000",
|
||||
"phone": "+90 212 555 0102",
|
||||
"personalPhone": "+90 532 555 0103",
|
||||
"phone": "2125550102",
|
||||
"personalPhone": "5325550103",
|
||||
"email": "ayse.kaya@company.com",
|
||||
"address1": "",
|
||||
"address2": "",
|
||||
"emergencyContactname": "Fatma Kaya",
|
||||
"emergencyContactrelationship": "Anne",
|
||||
"emergencyContactphone": "+90 532 555 0104",
|
||||
"emergencyContactphone": "5325550104",
|
||||
"hireDate": "01-06-2021",
|
||||
"terminationDate": "",
|
||||
"employmentTypeName": "FullTime",
|
||||
|
|
|
|||
|
|
@ -416,7 +416,7 @@ export interface EditingFormItemDto {
|
|||
isRequired?: boolean
|
||||
gridBoxOptions?: GridBoxOptionsDto
|
||||
tagBoxOptions?: TagBoxOptionsDto
|
||||
script?: string
|
||||
editorScript?: string
|
||||
}
|
||||
|
||||
export interface GridEditingPopupDto {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import {
|
|||
UiCommandButtonPositionTypeEnum,
|
||||
UiLookupDataSourceTypeEnum,
|
||||
} from '../proxy/form/models'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
const cellTemplateMultiValue = (
|
||||
cellElement: HTMLElement,
|
||||
|
|
@ -82,6 +83,22 @@ function calculateFilterExpressionMultiValue(
|
|||
}
|
||||
}
|
||||
|
||||
// lookup cache (module scope)
|
||||
const __lookupCache = new Map<string, Promise<any[]>>()
|
||||
|
||||
const cachedLoader = (key: string, loader: () => Promise<any[]>) => {
|
||||
if (__lookupCache.has(key)) return __lookupCache.get(key)!
|
||||
const p = Promise.resolve()
|
||||
.then(() => loader())
|
||||
.then((res) => res ?? [])
|
||||
.catch((err) => {
|
||||
__lookupCache.delete(key) // hata olursa tekrar denenebilsin
|
||||
throw err
|
||||
})
|
||||
__lookupCache.set(key, p)
|
||||
return p
|
||||
}
|
||||
|
||||
const useListFormColumns = ({
|
||||
gridDto,
|
||||
listFormCode,
|
||||
|
|
@ -98,6 +115,11 @@ const useListFormColumns = ({
|
|||
const { checkPermission } = usePermission()
|
||||
const isPwaMode = usePWA()
|
||||
|
||||
useEffect(() => {
|
||||
// listFormCode değişince lookup cache temizlensin (farklı form farklı lookuplar)
|
||||
__lookupCache.clear()
|
||||
}, [listFormCode])
|
||||
|
||||
const lookupDataSource = (options: any, colData: any, listFormCode: string) => {
|
||||
const { lookupDto } = colData
|
||||
const filters = []
|
||||
|
|
@ -124,6 +146,7 @@ const useListFormColumns = ({
|
|||
return createLookupStaticDataSource(
|
||||
() => JSON.parse(lookupDto?.lookupQuery),
|
||||
filters.length ? filters : null,
|
||||
`static:${listFormCode}:${colData.fieldName}`, // cache key
|
||||
)
|
||||
} else if (lookupDto.dataSourceType == UiLookupDataSourceTypeEnum.Query) {
|
||||
return createLookupQueryDataSource(listFormCode, colData.fieldName, filters)
|
||||
|
|
@ -144,13 +167,16 @@ const useListFormColumns = ({
|
|||
const createLookupStaticDataSource = (
|
||||
load: () => any,
|
||||
filter: any = null,
|
||||
key: any = 'key',
|
||||
key: any = 'static',
|
||||
sort: any = 'name',
|
||||
) => ({
|
||||
store: new CustomStore({
|
||||
key,
|
||||
loadMode: 'raw',
|
||||
load,
|
||||
load: async (loadOptions) => {
|
||||
// load fonksiyonu sync sonuç döndürüyor olabilir, o yüzden Promise.resolve ile sar
|
||||
return cachedLoader(`static:${key}`, () => Promise.resolve(load()))
|
||||
},
|
||||
}),
|
||||
sort,
|
||||
filter,
|
||||
|
|
@ -169,27 +195,21 @@ const useListFormColumns = ({
|
|||
}
|
||||
|
||||
try {
|
||||
const cacheKey = `query:${listFormCode}:${listFormFieldName}:${JSON.stringify(filters ?? null)}`
|
||||
return cachedLoader(cacheKey, async () => {
|
||||
const response = await dynamicFetch('list-form-select/lookup', 'POST', null, {
|
||||
listFormCode,
|
||||
listFormFieldName,
|
||||
filters,
|
||||
})
|
||||
|
||||
return response.data.map((a: any) => ({
|
||||
return (response.data ?? []).map((a: any) => ({
|
||||
key: a.Key,
|
||||
name: a.Name,
|
||||
group: a.Group,
|
||||
}))
|
||||
})
|
||||
} catch (error: any) {
|
||||
// toast.push(
|
||||
// <Notification type="danger" duration={2000}>
|
||||
// Select error
|
||||
// {error.toString()}
|
||||
// </Notification>,
|
||||
// {
|
||||
// placement: 'top-end',
|
||||
// },
|
||||
// )
|
||||
return null
|
||||
}
|
||||
},
|
||||
|
|
@ -206,7 +226,6 @@ const useListFormColumns = ({
|
|||
key: keyName,
|
||||
loadMode: 'raw',
|
||||
load: async (loadOptions) => {
|
||||
//Sayfa degismisse istek yapma
|
||||
if (!isSubForm && listFormCode && !window.location.pathname.includes(listFormCode)) {
|
||||
return
|
||||
}
|
||||
|
|
@ -215,48 +234,29 @@ const useListFormColumns = ({
|
|||
}
|
||||
|
||||
const [method, url, body, keySelector, nameSelector, groupSelector] = lookupQuery.split(';')
|
||||
//POST;https://tcmb.gov.tr/api/doviz;{"dovizType":@param0};a=>a.DovizId;a=>a.DovizName;a=>a.Ulke
|
||||
|
||||
//TODO: Body dinamik params test edilecek
|
||||
// body içindeki @paramN'leri filtrelerle değiştir
|
||||
let resolvedBody = body
|
||||
if (filters?.length) {
|
||||
for (let i = 0; i < filters.length; i++) {
|
||||
body.replace(`@param${i}`, filters[i])
|
||||
resolvedBody = resolvedBody.replace(new RegExp(`@param${i}`, 'g'), filters[i])
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await dynamicFetch(url, method, null, body)
|
||||
const cacheKey = `api:${lookupQuery}:${JSON.stringify(filters ?? null)}`
|
||||
return cachedLoader(cacheKey, async () => {
|
||||
const response = await dynamicFetch(url, method, null, resolvedBody)
|
||||
let { data } = response
|
||||
if (!data) {
|
||||
// toast.push(
|
||||
// <Notification type="danger" duration={2000}>
|
||||
// {'Lookup Datası boş geldi.'}
|
||||
// </Notification>,
|
||||
// {
|
||||
// placement: 'top-end',
|
||||
// },
|
||||
// )
|
||||
return
|
||||
}
|
||||
|
||||
if (!Array.isArray(data)) {
|
||||
data = [data]
|
||||
}
|
||||
|
||||
if (!data) return []
|
||||
if (!Array.isArray(data)) data = [data]
|
||||
return data.map((a: any) => ({
|
||||
key: eval(keySelector),
|
||||
name: eval(nameSelector),
|
||||
group: eval(groupSelector),
|
||||
}))
|
||||
})
|
||||
} catch {
|
||||
// toast.push(
|
||||
// <Notification type="danger" duration={2000}>
|
||||
// {'Network error'}
|
||||
// </Notification>,
|
||||
// {
|
||||
// placement: 'top-end',
|
||||
// },
|
||||
// )
|
||||
return
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -740,9 +740,9 @@ function JsonRowOpDialogEditForm({
|
|||
<Field
|
||||
type="text"
|
||||
autoComplete="off"
|
||||
name={`items.${index}.script`}
|
||||
name={`items.${index}.editorScript`}
|
||||
component={Input}
|
||||
placeholder="Script"
|
||||
placeholder="Editor Script"
|
||||
/>
|
||||
</div>
|
||||
<div className="w-1/12 ml-2 align-middle text-center">
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ import { GridColumnData } from '../list/GridColumnData'
|
|||
import { useToolbar } from '../list/useToolbar'
|
||||
import { PermissionResults, RowMode } from './types'
|
||||
import { GridDto } from '@/proxy/form/models'
|
||||
import React from 'react'
|
||||
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||
import { usePermission } from '@/utils/hooks/usePermission'
|
||||
import { GridExtraFilterState } from '../list/Utils'
|
||||
|
|
@ -214,7 +213,8 @@ const FormButtons = (props: {
|
|||
if (onActionNew) {
|
||||
onActionNew()
|
||||
} else {
|
||||
navigate(ROUTES_ENUM.protected.admin.formNew.replace(':listFormCode', listFormCode))
|
||||
navigate(ROUTES_ENUM.protected.admin.formNew
|
||||
.replace(':listFormCode', listFormCode))
|
||||
}
|
||||
}}
|
||||
{...(permissions.c ? {} : { disabled: true })}
|
||||
|
|
|
|||
|
|
@ -41,12 +41,12 @@ const FormDevExpress = (props: {
|
|||
.flatMap((group) => (group.items as SimpleItemWithColData[]) || [])
|
||||
.find((i: SimpleItemWithColData) => i.dataField === e.dataField)
|
||||
|
||||
if (changeItem?.script) {
|
||||
if (changeItem?.editorScript) {
|
||||
try {
|
||||
//setFormData({...formData, Path: e.value});
|
||||
//UiEvalService.ApiGenerateBackgroundWorkers();
|
||||
//setFormData({ ...formData, Path: (v => v === '1' ? '1-deneme' : v === '0' ? '0-deneme' : '')(e.value) })
|
||||
eval(changeItem.script)
|
||||
eval(changeItem.editorScript)
|
||||
} catch (err) {
|
||||
console.error('Script execution failed for', changeItem.name, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ export type SimpleItemWithColData = Overwrite<
|
|||
canUpdate: boolean
|
||||
canExport: boolean
|
||||
editorType2: EditorType2
|
||||
script?: string
|
||||
editorScript?: string
|
||||
}
|
||||
>
|
||||
export type RowMode = 'view' | 'edit' | 'new'
|
||||
|
|
|
|||
|
|
@ -261,7 +261,7 @@ const useGridData = (props: {
|
|||
colData,
|
||||
tagBoxOptions: i.tagBoxOptions,
|
||||
gridBoxOptions: i.gridBoxOptions,
|
||||
script: i.script,
|
||||
editorScript: i.editorScript,
|
||||
}
|
||||
if (i.dataField.indexOf(':') >= 0) {
|
||||
item.label = { text: captionize(i.dataField.split(':')[1]) }
|
||||
|
|
|
|||
|
|
@ -1,18 +1,44 @@
|
|||
// src/.../useLookupDataSource.ts
|
||||
import { dynamicFetch } from '@/services/form.service'
|
||||
import { UiLookupDataSourceTypeEnum } from '@/proxy/form/models'
|
||||
import CustomStore from 'devextreme/data/custom_store'
|
||||
import { useCallback } from 'react'
|
||||
|
||||
/** Module-scope cache: key -> Promise<array>
|
||||
* - Aynı anda açılan editörler tek ağ çağrısı üzerinden paylaşır
|
||||
* - Hata olursa cache temizlenir (yeniden denenebilir)
|
||||
*/
|
||||
const __lookupCache = new Map<string, Promise<any[]>>()
|
||||
|
||||
const cachedLoader = (key: string, loader: () => Promise<any[]>) => {
|
||||
if (__lookupCache.has(key)) return __lookupCache.get(key)!
|
||||
const p = Promise.resolve()
|
||||
.then(() => loader())
|
||||
.then((res) => res ?? [])
|
||||
.catch((err) => {
|
||||
__lookupCache.delete(key)
|
||||
throw err
|
||||
})
|
||||
__lookupCache.set(key, p)
|
||||
return p
|
||||
}
|
||||
|
||||
const createLookupStaticDataSource = (
|
||||
load: () => any,
|
||||
filter: any = null,
|
||||
key: any = 'key',
|
||||
key: any = 'static',
|
||||
sort: any = 'name',
|
||||
) => ({
|
||||
store: new CustomStore({
|
||||
key,
|
||||
loadMode: 'raw',
|
||||
load,
|
||||
load: async () => {
|
||||
const cacheKey = `static:${key}`
|
||||
return cachedLoader(cacheKey, async () => {
|
||||
const res = await Promise.resolve(load())
|
||||
return Array.isArray(res) ? res : [res]
|
||||
})
|
||||
},
|
||||
}),
|
||||
sort,
|
||||
filter,
|
||||
|
|
@ -30,21 +56,21 @@ const createLookupQueryDataSource = (
|
|||
if (!isSubForm && listFormCode && !window.location.pathname.includes(listFormCode)) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
|
||||
const cacheKey = `query:${listFormCode}:${listFormFieldName}:${JSON.stringify(filters ?? null)}`
|
||||
return cachedLoader(cacheKey, async () => {
|
||||
const response = await dynamicFetch('list-form-select/lookup', 'POST', null, {
|
||||
listFormCode,
|
||||
listFormFieldName,
|
||||
filters,
|
||||
})
|
||||
|
||||
return response.data.map((a: any) => ({
|
||||
const data = response?.data ?? []
|
||||
return (Array.isArray(data) ? data : [data]).map((a: any) => ({
|
||||
key: a.Key,
|
||||
name: a.Name,
|
||||
group: a.Group,
|
||||
}))
|
||||
} catch (error: any) {
|
||||
return null
|
||||
}
|
||||
}).catch(() => null as any)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
@ -67,33 +93,35 @@ const createLookupApiDataSource = (
|
|||
return
|
||||
}
|
||||
|
||||
const [method, url, body, keySelector, nameSelector, groupSelector] = lookupQuery.split(';')
|
||||
const parts = lookupQuery.split(';')
|
||||
const [
|
||||
method = 'GET',
|
||||
url = '',
|
||||
bodyTemplate = '',
|
||||
keySelector = 'a=>a.id',
|
||||
nameSelector = 'a=>a.name',
|
||||
groupSelector = 'a=>a.group',
|
||||
] = parts
|
||||
|
||||
let resolvedBody = bodyTemplate ?? ''
|
||||
if (filters?.length) {
|
||||
for (let i = 0; i < filters.length; i++) {
|
||||
body.replace(`@param${i}`, filters[i])
|
||||
resolvedBody = resolvedBody.replace(new RegExp(`@param${i}`, 'g'), String(filters[i]))
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await dynamicFetch(url, method, null, body)
|
||||
const cacheKey = `api:${lookupQuery}:${JSON.stringify(filters ?? null)}`
|
||||
return cachedLoader(cacheKey, async () => {
|
||||
const response = await dynamicFetch(url, method, null, resolvedBody)
|
||||
let { data } = response
|
||||
if (!data) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!Array.isArray(data)) {
|
||||
data = [data]
|
||||
}
|
||||
|
||||
if (!data) return []
|
||||
if (!Array.isArray(data)) data = [data]
|
||||
return data.map((a: any) => ({
|
||||
key: eval(keySelector),
|
||||
name: eval(nameSelector),
|
||||
group: eval(groupSelector),
|
||||
}))
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
}).catch(() => [] as any)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
@ -108,13 +136,11 @@ export const useLookupDataSource = ({
|
|||
const getLookupDataSource = useCallback(
|
||||
(options: any, colData: any, data: any) => {
|
||||
const { lookupDto } = colData
|
||||
const filters = []
|
||||
const filters: any[] = []
|
||||
|
||||
//Eğer cascadeParentFields varsa ve data yoksa boş döneriz.
|
||||
// Eğer cascadeParentFields varsa ve row verisi (data) yoksa boş döneriz
|
||||
if (lookupDto.cascadeParentFields && !data) {
|
||||
return {
|
||||
store: [],
|
||||
}
|
||||
return { store: [] }
|
||||
}
|
||||
|
||||
if (lookupDto.cascadeParentFields) {
|
||||
|
|
@ -132,9 +158,11 @@ export const useLookupDataSource = ({
|
|||
}
|
||||
|
||||
if (lookupDto.dataSourceType == UiLookupDataSourceTypeEnum.StaticData) {
|
||||
const staticKey = `static:${listFormCode}:${colData.fieldName}`
|
||||
return createLookupStaticDataSource(
|
||||
() => JSON.parse(lookupDto?.lookupQuery),
|
||||
filters.length ? filters : null,
|
||||
staticKey,
|
||||
)
|
||||
} else if (lookupDto.dataSourceType == UiLookupDataSourceTypeEnum.Query) {
|
||||
return createLookupQueryDataSource(listFormCode, colData.fieldName, filters, isSubForm)
|
||||
|
|
@ -147,9 +175,7 @@ export const useLookupDataSource = ({
|
|||
isSubForm,
|
||||
)
|
||||
} else {
|
||||
return {
|
||||
store: [],
|
||||
}
|
||||
return { store: [] }
|
||||
}
|
||||
},
|
||||
[listFormCode, isSubForm],
|
||||
|
|
@ -157,3 +183,9 @@ export const useLookupDataSource = ({
|
|||
|
||||
return { getLookupDataSource }
|
||||
}
|
||||
|
||||
/** Opsiyonel: dışarıdan cache temizlemek istersen export et */
|
||||
export const clearLookupCache = (key?: string) => {
|
||||
if (!key) __lookupCache.clear()
|
||||
else __lookupCache.delete(key)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,182 +1,19 @@
|
|||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { EditingFormItemDto, GridDto, PlatformEditorTypes } from '@/proxy/form/models'
|
||||
import { captionize } from 'devextreme/core/utils/inflector'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { GridDto } from '@/proxy/form/models'
|
||||
import { useListFormCustomDataSource } from '@/shared/useListFormCustomDataSource'
|
||||
import { Button, Pagination, Select } from '@/components/ui'
|
||||
import classNames from 'classnames'
|
||||
import { FaCog, FaSearch } from 'react-icons/fa'
|
||||
import FormDevExpress from '../form/FormDevExpress'
|
||||
import { GroupItem } from 'devextreme/ui/form'
|
||||
import { Form as FormDx } from 'devextreme-react/form'
|
||||
import FormButtons from '../form/FormButtons'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||
import CustomStore from 'devextreme/data/custom_store'
|
||||
import { PermissionResults, SimpleItemWithColData } from '../form/types'
|
||||
import { usePermission } from '@/utils/hooks/usePermission'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import { useLookupDataSource } from '../form/useLookupDataSource'
|
||||
import { Container, Loading } from '@/components/shared'
|
||||
import WidgetGroup from '@/components/common/WidgetGroup'
|
||||
import { GridExtraFilterState } from './Utils'
|
||||
import { useStoreActions, useStoreState } from '@/store/store'
|
||||
import { usePWA } from '@/utils/hooks/usePWA'
|
||||
|
||||
const CardItem = ({
|
||||
isSubForm,
|
||||
row,
|
||||
gridDto,
|
||||
listFormCode,
|
||||
dataSource,
|
||||
refreshData,
|
||||
getCachedLookupDataSource,
|
||||
}: {
|
||||
isSubForm?: boolean
|
||||
row: any
|
||||
gridDto: GridDto
|
||||
listFormCode: string
|
||||
dataSource: CustomStore
|
||||
refreshData: () => void
|
||||
getCachedLookupDataSource: (editorOptions: any, colData: any, row?: any) => any
|
||||
}) => {
|
||||
const [formData, setFormData] = useState(row)
|
||||
const refForm = useRef<FormDx>(null)
|
||||
const navigate = useNavigate()
|
||||
const { translate } = useLocalization()
|
||||
const { checkPermission } = usePermission()
|
||||
const isPwaMode = usePWA()
|
||||
|
||||
const keyField = gridDto.gridOptions.keyFieldName
|
||||
const rowId = row[keyField!]
|
||||
|
||||
// Form Items
|
||||
const formItems: GroupItem[] = useMemo(() => {
|
||||
if (!gridDto) return []
|
||||
|
||||
return gridDto.gridOptions.editingFormDto
|
||||
?.sort((a, b) => (a.order >= b.order ? 1 : -1))
|
||||
.map((e) => {
|
||||
return {
|
||||
itemType: e.itemType,
|
||||
colCount: e.colCount,
|
||||
colSpan: e.colSpan,
|
||||
caption: e.caption,
|
||||
items: e.items
|
||||
?.sort((a, b) => (a.order >= b.order ? 1 : -1))
|
||||
.map((i: EditingFormItemDto) => {
|
||||
let editorOptions = {}
|
||||
const colData = gridDto.columnFormats.find((x) => x.fieldName === i.dataField)
|
||||
|
||||
try {
|
||||
editorOptions = i.editorOptions && JSON.parse(i.editorOptions)
|
||||
} catch {}
|
||||
|
||||
const item: SimpleItemWithColData = {
|
||||
canRead: colData?.canRead ?? false,
|
||||
canUpdate: colData?.canUpdate ?? false,
|
||||
canCreate: colData?.canCreate ?? false,
|
||||
canExport: colData?.canExport ?? false,
|
||||
dataField: i.dataField,
|
||||
name: i.dataField,
|
||||
editorType2: i.editorType2,
|
||||
editorType:
|
||||
i.editorType2 == PlatformEditorTypes.dxGridBox ? 'dxDropDownBox' : i.editorType2,
|
||||
colSpan: i.colSpan,
|
||||
isRequired: i.isRequired,
|
||||
editorOptions: {
|
||||
...editorOptions,
|
||||
...(colData?.lookupDto?.dataSourceType
|
||||
? {
|
||||
dataSource: getCachedLookupDataSource(colData?.editorOptions, colData),
|
||||
valueExpr: colData?.lookupDto?.valueExpr?.toLowerCase(),
|
||||
displayExpr: colData?.lookupDto?.displayExpr?.toLowerCase(),
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
colData,
|
||||
tagBoxOptions: i.tagBoxOptions,
|
||||
gridBoxOptions: i.gridBoxOptions,
|
||||
script: i.script,
|
||||
}
|
||||
if (i.dataField.indexOf(':') >= 0) {
|
||||
item.label = { text: captionize(i.dataField.split(':')[1]) }
|
||||
}
|
||||
item.editorOptions = {
|
||||
...item.editorOptions,
|
||||
readOnly: true,
|
||||
}
|
||||
return item
|
||||
}),
|
||||
} as GroupItem
|
||||
})
|
||||
}, [gridDto, getCachedLookupDataSource])
|
||||
|
||||
const permissionResults: PermissionResults = {
|
||||
c:
|
||||
gridDto?.gridOptions.editingOptionDto.allowAdding === true &&
|
||||
checkPermission(gridDto?.gridOptions.permissionDto.c),
|
||||
r: checkPermission(gridDto?.gridOptions.permissionDto.r),
|
||||
u:
|
||||
gridDto?.gridOptions.editingOptionDto.allowUpdating === true &&
|
||||
checkPermission(gridDto?.gridOptions.permissionDto.u),
|
||||
d:
|
||||
gridDto?.gridOptions.editingOptionDto.allowDeleting === true &&
|
||||
checkPermission(gridDto?.gridOptions.permissionDto.d),
|
||||
e: checkPermission(gridDto?.gridOptions.permissionDto.e),
|
||||
i: checkPermission(gridDto?.gridOptions.permissionDto.i),
|
||||
}
|
||||
|
||||
const onActionEdit = () => {
|
||||
navigate(
|
||||
ROUTES_ENUM.protected.admin.formEdit
|
||||
.replace(':listFormCode', listFormCode)
|
||||
.replace(':id', rowId!),
|
||||
)
|
||||
}
|
||||
|
||||
const onActionNew = () => {
|
||||
navigate(ROUTES_ENUM.protected.admin.formNew.replace(':listFormCode', listFormCode))
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="bg-white dark:bg-neutral-800 border dark:border-neutral-700 flex flex-col">
|
||||
<div
|
||||
className={`flex items-center pt-2 px-2 ${isSubForm ? 'justify-end' : 'justify-between'}`}
|
||||
>
|
||||
{!isSubForm && <h3>{translate('::' + gridDto?.gridOptions.title)}</h3>}
|
||||
{permissionResults && (
|
||||
<FormButtons
|
||||
isSubForm={true}
|
||||
mode="view"
|
||||
listFormCode={listFormCode}
|
||||
id={rowId}
|
||||
gridDto={gridDto}
|
||||
commandColumnData={{ buttons: [] }}
|
||||
dataSource={dataSource}
|
||||
permissions={permissionResults}
|
||||
handleSubmit={() => ({})}
|
||||
refreshData={refreshData}
|
||||
getSelectedRowKeys={() => [rowId]}
|
||||
getSelectedRowsData={() => [row]}
|
||||
getFilter={() => null}
|
||||
onActionEdit={onActionEdit}
|
||||
onActionNew={onActionNew}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex-grow">
|
||||
<FormDevExpress
|
||||
mode="view"
|
||||
refForm={refForm}
|
||||
formData={formData}
|
||||
formItems={formItems}
|
||||
setFormData={setFormData}
|
||||
listFormCode={listFormCode}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
import CardItem from './CardItem'
|
||||
|
||||
interface CardProps {
|
||||
listFormCode: string
|
||||
|
|
@ -218,20 +55,6 @@ const Card = (props: CardProps) => {
|
|||
searchParams ? new URLSearchParams(searchParams) : new URLSearchParams(),
|
||||
)
|
||||
|
||||
const lookupCache = useRef<Map<string, any>>(new Map())
|
||||
const getCachedLookupDataSource = useCallback(
|
||||
(editorOptions: any, colData: any, row?: any) => {
|
||||
const key = colData?.fieldName
|
||||
if (!key) return null
|
||||
|
||||
if (!lookupCache.current.has(key)) {
|
||||
lookupCache.current.set(key, getLookupDataSource(editorOptions, colData, row))
|
||||
}
|
||||
return lookupCache.current.get(key)
|
||||
},
|
||||
[getLookupDataSource],
|
||||
)
|
||||
|
||||
const onPageSizeSelect = ({ value }: Option) => {
|
||||
setPageSize(value)
|
||||
setCurrentPage(1)
|
||||
|
|
@ -499,7 +322,7 @@ const Card = (props: CardProps) => {
|
|||
listFormCode={listFormCode}
|
||||
dataSource={gridDataSource}
|
||||
refreshData={loadData}
|
||||
getCachedLookupDataSource={getCachedLookupDataSource}
|
||||
getCachedLookupDataSource={getLookupDataSource}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
|
|
|
|||
172
ui/src/views/list/CardItem.tsx
Normal file
172
ui/src/views/list/CardItem.tsx
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
import { EditingFormItemDto, GridDto, PlatformEditorTypes } from "@/proxy/form/models"
|
||||
import { useLocalization } from "@/utils/hooks/useLocalization"
|
||||
import { usePermission } from "@/utils/hooks/usePermission"
|
||||
import { usePWA } from "@/utils/hooks/usePWA"
|
||||
import CustomStore from "devextreme/data/custom_store"
|
||||
import { useMemo, useRef, useState } from "react"
|
||||
import { useNavigate } from "react-router-dom"
|
||||
import { Form as FormDx } from 'devextreme-react/form'
|
||||
import { GroupItem } from 'devextreme/ui/form'
|
||||
import { PermissionResults, SimpleItemWithColData } from "../form/types"
|
||||
import { captionize } from 'devextreme/core/utils/inflector'
|
||||
import { ROUTES_ENUM } from "@/routes/route.constant"
|
||||
import FormButtons from "../form/FormButtons"
|
||||
import FormDevExpress from "../form/FormDevExpress"
|
||||
|
||||
const CardItem = ({
|
||||
isSubForm,
|
||||
row,
|
||||
gridDto,
|
||||
listFormCode,
|
||||
dataSource,
|
||||
refreshData,
|
||||
getCachedLookupDataSource,
|
||||
}: {
|
||||
isSubForm?: boolean
|
||||
row: any
|
||||
gridDto: GridDto
|
||||
listFormCode: string
|
||||
dataSource: CustomStore
|
||||
refreshData: () => void
|
||||
getCachedLookupDataSource: (editorOptions: any, colData: any, row?: any) => any
|
||||
}) => {
|
||||
const [formData, setFormData] = useState(row)
|
||||
const refForm = useRef<FormDx>(null)
|
||||
const navigate = useNavigate()
|
||||
const { translate } = useLocalization()
|
||||
const { checkPermission } = usePermission()
|
||||
const isPwaMode = usePWA()
|
||||
|
||||
const keyField = gridDto.gridOptions.keyFieldName
|
||||
const rowId = row[keyField!]
|
||||
|
||||
// Form Items
|
||||
const formItems: GroupItem[] = useMemo(() => {
|
||||
if (!gridDto) return []
|
||||
|
||||
return gridDto.gridOptions.editingFormDto
|
||||
?.sort((a, b) => (a.order >= b.order ? 1 : -1))
|
||||
.map((e) => {
|
||||
return {
|
||||
itemType: e.itemType,
|
||||
colCount: e.colCount,
|
||||
colSpan: e.colSpan,
|
||||
caption: e.caption,
|
||||
items: e.items
|
||||
?.sort((a, b) => (a.order >= b.order ? 1 : -1))
|
||||
.map((i: EditingFormItemDto) => {
|
||||
let editorOptions = {}
|
||||
const colData = gridDto.columnFormats.find((x) => x.fieldName === i.dataField)
|
||||
|
||||
try {
|
||||
editorOptions = i.editorOptions && JSON.parse(i.editorOptions)
|
||||
} catch {}
|
||||
|
||||
const item: SimpleItemWithColData = {
|
||||
canRead: colData?.canRead ?? false,
|
||||
canUpdate: colData?.canUpdate ?? false,
|
||||
canCreate: colData?.canCreate ?? false,
|
||||
canExport: colData?.canExport ?? false,
|
||||
dataField: i.dataField,
|
||||
name: i.dataField,
|
||||
editorType2: i.editorType2,
|
||||
editorType:
|
||||
i.editorType2 == PlatformEditorTypes.dxGridBox ? 'dxDropDownBox' : i.editorType2,
|
||||
colSpan: i.colSpan,
|
||||
isRequired: i.isRequired,
|
||||
editorOptions: {
|
||||
...editorOptions,
|
||||
...(colData?.lookupDto?.dataSourceType
|
||||
? {
|
||||
dataSource: getCachedLookupDataSource(colData?.editorOptions, colData),
|
||||
valueExpr: colData?.lookupDto?.valueExpr?.toLowerCase(),
|
||||
displayExpr: colData?.lookupDto?.displayExpr?.toLowerCase(),
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
colData,
|
||||
tagBoxOptions: i.tagBoxOptions,
|
||||
gridBoxOptions: i.gridBoxOptions,
|
||||
editorScript: i.editorScript,
|
||||
}
|
||||
if (i.dataField.indexOf(':') >= 0) {
|
||||
item.label = { text: captionize(i.dataField.split(':')[1]) }
|
||||
}
|
||||
item.editorOptions = {
|
||||
...item.editorOptions,
|
||||
readOnly: true,
|
||||
}
|
||||
return item
|
||||
}),
|
||||
} as GroupItem
|
||||
})
|
||||
}, [gridDto, getCachedLookupDataSource])
|
||||
|
||||
const permissionResults: PermissionResults = {
|
||||
c:
|
||||
gridDto?.gridOptions.editingOptionDto.allowAdding === true &&
|
||||
checkPermission(gridDto?.gridOptions.permissionDto.c),
|
||||
r: checkPermission(gridDto?.gridOptions.permissionDto.r),
|
||||
u:
|
||||
gridDto?.gridOptions.editingOptionDto.allowUpdating === true &&
|
||||
checkPermission(gridDto?.gridOptions.permissionDto.u),
|
||||
d:
|
||||
gridDto?.gridOptions.editingOptionDto.allowDeleting === true &&
|
||||
checkPermission(gridDto?.gridOptions.permissionDto.d),
|
||||
e: checkPermission(gridDto?.gridOptions.permissionDto.e),
|
||||
i: checkPermission(gridDto?.gridOptions.permissionDto.i),
|
||||
}
|
||||
|
||||
const onActionEdit = () => {
|
||||
navigate(
|
||||
ROUTES_ENUM.protected.admin.formEdit
|
||||
.replace(':listFormCode', listFormCode)
|
||||
.replace(':id', rowId!),
|
||||
)
|
||||
}
|
||||
|
||||
const onActionNew = () => {
|
||||
navigate(ROUTES_ENUM.protected.admin.formNew.replace(':listFormCode', listFormCode))
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="bg-white dark:bg-neutral-800 border dark:border-neutral-700 flex flex-col">
|
||||
<div
|
||||
className={`flex items-center pt-2 px-2 ${isSubForm ? 'justify-end' : 'justify-between'}`}
|
||||
>
|
||||
{!isSubForm && <h3>{translate('::' + gridDto?.gridOptions.title)}</h3>}
|
||||
{permissionResults && (
|
||||
<FormButtons
|
||||
isSubForm={true}
|
||||
mode="view"
|
||||
listFormCode={listFormCode}
|
||||
id={rowId}
|
||||
gridDto={gridDto}
|
||||
commandColumnData={{ buttons: [] }}
|
||||
dataSource={dataSource}
|
||||
permissions={permissionResults}
|
||||
handleSubmit={() => ({})}
|
||||
refreshData={refreshData}
|
||||
getSelectedRowKeys={() => [rowId]}
|
||||
getSelectedRowsData={() => [row]}
|
||||
getFilter={() => null}
|
||||
onActionEdit={onActionEdit}
|
||||
onActionNew={onActionNew}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex-grow">
|
||||
<FormDevExpress
|
||||
mode="view"
|
||||
refForm={refForm}
|
||||
formData={formData}
|
||||
formItems={formItems}
|
||||
setFormData={setFormData}
|
||||
listFormCode={listFormCode}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default CardItem
|
||||
|
|
@ -718,9 +718,7 @@ const Grid = (props: GridProps) => {
|
|||
.flatMap((group) => group.items || [])
|
||||
.find((i) => i.dataField === editor.dataField)
|
||||
|
||||
|
||||
console.log(formItem?.dataField, formItem?.script)
|
||||
if (formItem?.script) {
|
||||
if (formItem?.editorScript) {
|
||||
const prevHandler = editor.editorOptions.onValueChanged // varsa önceki handler'ı sakla
|
||||
|
||||
editor.editorOptions.onValueChanged = (e: any) => {
|
||||
|
|
@ -745,7 +743,7 @@ const Grid = (props: GridProps) => {
|
|||
}
|
||||
}
|
||||
|
||||
eval(formItem.script!)
|
||||
eval(formItem.editorScript!)
|
||||
//setFormData({ ...formData, Path: e.value, Authority: e.value })
|
||||
|
||||
// editor.component.cellValue(
|
||||
|
|
@ -822,9 +820,9 @@ const Grid = (props: GridProps) => {
|
|||
const formItem = gridDto.gridOptions.editingFormDto
|
||||
.flatMap((group) => group.items || [])
|
||||
.find((i) => i.dataField === e.dataField)
|
||||
if (formItem?.script) {
|
||||
if (formItem?.editorScript) {
|
||||
try {
|
||||
eval(formItem.script)
|
||||
eval(formItem.editorScript)
|
||||
} catch (err) {
|
||||
console.error('Script exec error', err)
|
||||
}
|
||||
|
|
@ -946,7 +944,7 @@ const Grid = (props: GridProps) => {
|
|||
colSpan: i.colSpan,
|
||||
isRequired: i.isRequired,
|
||||
editorOptions,
|
||||
script: i.script,
|
||||
editorScript: i.editorScript,
|
||||
}
|
||||
if (i.dataField.indexOf(':') >= 0) {
|
||||
item.label = { text: captionize(i.dataField.split(':')[1]) }
|
||||
|
|
|
|||
Loading…
Reference in a new issue