Workflow problemleri
This commit is contained in:
parent
2f1b9d4e77
commit
64084679e8
15 changed files with 132 additions and 46 deletions
|
|
@ -305,7 +305,7 @@ public class ListFormWizardAppService(
|
|||
HeaderFilterJson = WizardConsts.DefaultHeaderFilterJson,
|
||||
SearchPanelJson = WizardConsts.DefaultSearchPanelJson,
|
||||
GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }),
|
||||
SelectionJson = WizardConsts.DefaultSelectionSingleJson,
|
||||
SelectionJson = WizardConsts.DefaultSelectionSingleJson(input.Widgets.Count > 0 ? GridOptions.SelectionModeSingle : GridOptions.SelectionModeNone),
|
||||
ColumnOptionJson = WizardConsts.DefaultColumnOptionJson(),
|
||||
PermissionJson = WizardConsts.DefaultPermissionJson(code),
|
||||
DeleteCommand = isDeleted ? WizardConsts.DefaultDeleteCommand(input.SelectCommand) : null,
|
||||
|
|
|
|||
|
|
@ -18038,6 +18038,12 @@
|
|||
"en": "Add Multi-Tenant Column",
|
||||
"tr": "MultiTenant Sütunları Ekle"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.SqlQueryManager.AddWorkflowColumns",
|
||||
"en": "Add Workflow Column",
|
||||
"tr": "Workflow Sütunları Ekle"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.SqlQueryManager.ClearAllColumns",
|
||||
|
|
|
|||
|
|
@ -797,7 +797,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
|||
PermissionJson = DefaultPermissionJson(PlatformConsts.IdentityPermissions.Users.Create, listFormName, PlatformConsts.IdentityPermissions.Users.Update, PlatformConsts.IdentityPermissions.Users.Delete, PlatformConsts.IdentityPermissions.Users.Export, PlatformConsts.IdentityPermissions.Users.Import, PlatformConsts.IdentityPermissions.Users.Note),
|
||||
DeleteCommand = $"UPDATE \"AbpUsers\" SET \"DeleterId\"=@DeleterId, \"DeletionTime\"=CURRENT_TIMESTAMP, \"IsDeleted\"='true' WHERE \"Id\"=@Id",
|
||||
DeleteFieldsDefaultValueJson = DefaultDeleteFieldsDefaultValueJson(),
|
||||
EditingOptionJson = DefaultEditingOptionJson(listFormName, 500, 730, true, true, true, true, false),
|
||||
EditingOptionJson = DefaultEditingOptionJson(listFormName, 500, 710, true, true, true, true, false),
|
||||
EditingFormJson = JsonSerializer.Serialize(new List<EditingFormDto>() {
|
||||
new () { Order=1,ColCount=1,ColSpan=1,ItemType="group",Items=[
|
||||
new EditingFormItemDto { Order=1, DataField="Email", ColSpan=1, IsRequired=true, EditorType2=EditorTypes.dxTextBox },
|
||||
|
|
|
|||
|
|
@ -352,7 +352,7 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
HeaderFilterJson = WizardConsts.DefaultHeaderFilterJson,
|
||||
SearchPanelJson = WizardConsts.DefaultSearchPanelJson,
|
||||
GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }),
|
||||
SelectionJson = WizardConsts.DefaultSelectionSingleJson,
|
||||
SelectionJson = WizardConsts.DefaultSelectionSingleJson(input.Widgets.Count > 0 ? GridOptions.SelectionModeSingle : GridOptions.SelectionModeNone),
|
||||
ColumnOptionJson = WizardConsts.DefaultColumnOptionJson(),
|
||||
PermissionJson = WizardConsts.DefaultPermissionJson(code),
|
||||
DeleteCommand = isDeleted ? WizardConsts.DefaultDeleteCommand(input.SelectCommand) : null,
|
||||
|
|
|
|||
|
|
@ -95,9 +95,9 @@ public static class WizardConsts
|
|||
public static readonly string DefaultSearchPanelJson = JsonSerializer.Serialize(new { Visible = true });
|
||||
public static readonly string DefaultGroupPanelJson = JsonSerializer.Serialize(new { Visible = true });
|
||||
|
||||
public static readonly string DefaultSelectionSingleJson = JsonSerializer.Serialize(new
|
||||
public static string DefaultSelectionSingleJson(string Mode = "none") => JsonSerializer.Serialize(new
|
||||
{
|
||||
Mode = GridOptions.SelectionModeNone,
|
||||
Mode = Mode,
|
||||
AllowSelectAll = false
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -347,7 +347,8 @@ export function toCriteriaForm(item: WorkflowCriteriaDto): WorkflowCriteriaForm
|
|||
}
|
||||
|
||||
export function normalizeCriteria(item: WorkflowCriteriaForm): SaveCriteriaInput {
|
||||
const sharedPerson = item.approver || ''
|
||||
const sharedPerson =
|
||||
item.kind === 'Approval' || item.kind === 'Inform' ? item.approver || '' : ''
|
||||
const compareOutcomes = (item.compareOutcomes || [])
|
||||
.slice(0, 4)
|
||||
.filter((outcome) => outcome.label?.trim())
|
||||
|
|
@ -504,7 +505,7 @@ export function criteriaSummary(item: WorkflowCriteriaDto) {
|
|||
if (item.kind === 'Approval' || item.kind === 'Inform') {
|
||||
return `${item.title} ${item.approver ? `- ${item.approver}` : ''}`
|
||||
}
|
||||
return `${item.title} ${item.approver ? `- ${item.approver}` : ''}`
|
||||
return item.title
|
||||
}
|
||||
|
||||
export function targetTitle(criteria: WorkflowCriteriaDto[], id?: string | null) {
|
||||
|
|
|
|||
|
|
@ -296,10 +296,12 @@ export function FormTabWorkflow(
|
|||
}
|
||||
|
||||
const schema = object().shape({
|
||||
approvalUserFieldName: string().required(),
|
||||
approvalStatusFieldName: string().required(),
|
||||
approvalDateFieldName: string(),
|
||||
approvalDescriptionFieldName: string(),
|
||||
workflowDto: object().shape({
|
||||
approvalUserFieldName: string().required(),
|
||||
approvalStatusFieldName: string().required(),
|
||||
approvalDateFieldName: string(),
|
||||
approvalDescriptionFieldName: string(),
|
||||
}),
|
||||
})
|
||||
|
||||
const initialValues = useStoreState((s) => s.admin.lists.values)
|
||||
|
|
@ -423,7 +425,7 @@ export function FormTabWorkflow(
|
|||
</FormItem>
|
||||
</div>
|
||||
|
||||
<Button block variant="solid" loading={isSubmitting}>
|
||||
<Button block variant="solid" type="submit" loading={isSubmitting}>
|
||||
{isSubmitting ? translate('::SavingWithThreeDot') : translate('::Save')}
|
||||
</Button>
|
||||
</Card>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { Button, Checkbox, FormItem, Input, Select } from '@/components/ui'
|
|||
import { SelectCommandTypeEnum } from '@/proxy/form/models'
|
||||
import type { DatabaseColumnDto, SqlObjectExplorerDto } from '@/proxy/sql-query-manager/models'
|
||||
import { SelectBoxOption } from '@/types/shared'
|
||||
import { Field, FieldProps, FormikErrors, FormikTouched } from 'formik'
|
||||
import { Field, FieldProps, FormikErrors, FormikTouched, useFormikContext } from 'formik'
|
||||
import { useState } from 'react'
|
||||
import CreatableSelect from 'react-select/creatable'
|
||||
import { FaArrowLeft, FaArrowRight, FaPlus } from 'react-icons/fa'
|
||||
|
|
@ -68,6 +68,16 @@ const WizardStep2 = ({
|
|||
onNext,
|
||||
}: WizardStep2Props) => {
|
||||
const [showTableDesignerDialog, setShowTableDesignerDialog] = useState(false)
|
||||
const formik = useFormikContext<ListFormWizardDto>()
|
||||
|
||||
const handleTableDeployed = async (table: { schemaName: string; tableName: string }) => {
|
||||
await onDbObjectsRefresh(values.dataSourceCode)
|
||||
formik.setFieldValue('selectCommand', table.tableName)
|
||||
formik.setFieldValue('selectCommandType', SelectCommandTypeEnum.Table)
|
||||
formik.setFieldValue('keyFieldName', '')
|
||||
formik.setFieldTouched('keyFieldName', false)
|
||||
onLoadColumns(values.dataSourceCode, table.schemaName || 'dbo', table.tableName)
|
||||
}
|
||||
|
||||
const step2Missing = [
|
||||
!values.listFormCode && translate('::App.Listform.ListformField.ListFormCode'),
|
||||
|
|
@ -825,7 +835,7 @@ const WizardStep2 = ({
|
|||
onClose={() => setShowTableDesignerDialog(false)}
|
||||
dataSource={values.dataSourceCode}
|
||||
initialTableData={null}
|
||||
onDeployed={() => onDbObjectsRefresh(values.dataSourceCode)}
|
||||
onDeployed={handleTableDeployed}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import { useEffect, useMemo, useRef, useState } from 'react'
|
|||
import type { FormEvent } from 'react'
|
||||
import { FaArrowLeft, FaArrowRight } from 'react-icons/fa'
|
||||
import { WorkflowDesigner } from '../workflow/WorkflowDesigner'
|
||||
import { IdentityUserDto } from '@/proxy/admin/models'
|
||||
|
||||
type Props = {
|
||||
listFormCode: string
|
||||
|
|
@ -77,7 +78,7 @@ function WizardStep6({
|
|||
useEffect(() => {
|
||||
getUsers(0, 1000).then((response) => {
|
||||
setUserList(
|
||||
(response.data?.items ?? []).map((user: any) => ({
|
||||
(response.data?.items ?? []).map((user: IdentityUserDto) => ({
|
||||
value: user.userName,
|
||||
label: `${user.userName} (${user.name} ${user.surname})`,
|
||||
})),
|
||||
|
|
|
|||
|
|
@ -476,9 +476,12 @@ const WizardStep7 = ({
|
|||
{criteria.compareColumn} {criteria.compareOperator} {criteria.compareValue}
|
||||
</div>
|
||||
)}
|
||||
<div className="text-[11px] text-gray-500 dark:text-gray-400">
|
||||
Approver: {criteria.approver}
|
||||
</div>
|
||||
{(criteria.kind === 'Approval' || criteria.kind === 'Inform') &&
|
||||
criteria.approver && (
|
||||
<div className="text-[11px] text-gray-500 dark:text-gray-400">
|
||||
Approver: {criteria.approver}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -257,17 +257,19 @@ export function WorkflowCriteria({
|
|||
onChange={(event) => setField('title', event.target.value)}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
label={translate('::App.Listform.ListformField.Approver')}
|
||||
asterisk={formValues.kind === 'Approval' || formValues.kind === 'Inform'}
|
||||
>
|
||||
<SelectField
|
||||
required={formValues.kind === 'Approval' || formValues.kind === 'Inform'}
|
||||
options={userList}
|
||||
value={formValues.approver}
|
||||
onChange={(value) => setField('approver', value)}
|
||||
/>
|
||||
</FormItem>
|
||||
{(formValues.kind === 'Approval' || formValues.kind === 'Inform') && (
|
||||
<FormItem
|
||||
label={translate('::App.Listform.ListformField.Approver')}
|
||||
asterisk
|
||||
>
|
||||
<SelectField
|
||||
required
|
||||
options={userList}
|
||||
value={formValues.approver}
|
||||
onChange={(value) => setField('approver', value)}
|
||||
/>
|
||||
</FormItem>
|
||||
)}
|
||||
|
||||
{(formValues.kind === 'Start' || formValues.kind === 'Inform') && (
|
||||
<FormItem
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ type SqlDataType =
|
|||
| 'decimal'
|
||||
| 'float'
|
||||
| 'bit'
|
||||
| 'datetime'
|
||||
| 'datetime2'
|
||||
| 'date'
|
||||
| 'uniqueidentifier'
|
||||
|
|
@ -68,7 +69,7 @@ interface TableDesignerDialogProps {
|
|||
isOpen: boolean
|
||||
onClose: () => void
|
||||
dataSource: string | null
|
||||
onDeployed?: () => void
|
||||
onDeployed?: (table: { schemaName: string; tableName: string }) => void | Promise<void>
|
||||
initialTableData?: { schemaName: string; tableName: string } | null
|
||||
}
|
||||
|
||||
|
|
@ -98,6 +99,7 @@ const DATA_TYPES: { value: SqlDataType; label: string }[] = [
|
|||
{ value: 'decimal', label: 'Decimal (decimal 18,4)' },
|
||||
{ value: 'float', label: 'Float (float)' },
|
||||
{ value: 'bit', label: 'Bool (bit)' },
|
||||
{ value: 'datetime', label: 'DateTime (datetime)' },
|
||||
{ value: 'datetime2', label: 'DateTime (datetime2)' },
|
||||
{ value: 'date', label: 'Date (date)' },
|
||||
{ value: 'uniqueidentifier', label: 'Guid (uniqueidentifier)' },
|
||||
|
|
@ -226,6 +228,45 @@ const TENANT_COLUMN: ColumnDefinition = {
|
|||
description: 'Tenant ID for multi-tenancy',
|
||||
}
|
||||
|
||||
const WORKFLOW_COLUMNS: ColumnDefinition[] = [
|
||||
{
|
||||
id: '__ApprovalUserId',
|
||||
columnName: 'ApprovalUserName',
|
||||
dataType: 'nvarchar',
|
||||
maxLength: '256',
|
||||
isNullable: true,
|
||||
defaultValue: '',
|
||||
description: 'Workflow approval user name',
|
||||
},
|
||||
{
|
||||
id: '__ApprovalStatus',
|
||||
columnName: 'ApprovalStatus',
|
||||
dataType: 'nvarchar',
|
||||
maxLength: '50',
|
||||
isNullable: true,
|
||||
defaultValue: '',
|
||||
description: 'Workflow approval status',
|
||||
},
|
||||
{
|
||||
id: '__ApprovalDate',
|
||||
columnName: 'ApprovalDate',
|
||||
dataType: 'datetime',
|
||||
maxLength: '',
|
||||
isNullable: true,
|
||||
defaultValue: '',
|
||||
description: 'Workflow approval date',
|
||||
},
|
||||
{
|
||||
id: '__ApprovalDescription',
|
||||
columnName: 'ApprovalDescription',
|
||||
dataType: 'nvarchar',
|
||||
maxLength: '200',
|
||||
isNullable: true,
|
||||
defaultValue: '',
|
||||
description: 'Workflow approval description',
|
||||
},
|
||||
]
|
||||
|
||||
const CREATE_TABLE_SCRIPT_STORAGE_KEY = 'sqlQueryManager.lastCreateTableScript'
|
||||
|
||||
// ─── T-SQL Generator ──────────────────────────────────────────────────────────
|
||||
|
|
@ -405,6 +446,8 @@ function dbColToColumnDef(col: {
|
|||
dataType = 'float'
|
||||
} else if (dt === 'bit') {
|
||||
dataType = 'bit'
|
||||
} else if (dt === 'datetime') {
|
||||
dataType = 'datetime'
|
||||
} else if (dt.startsWith('datetime') || dt === 'smalldatetime') {
|
||||
dataType = 'datetime2'
|
||||
} else if (dt === 'date') {
|
||||
|
|
@ -476,6 +519,7 @@ function mapSqlTypeToDesigner(dataTypeRaw: string, lengthRaw: string): {
|
|||
if (dt === 'decimal' || dt === 'numeric') return { dataType: 'decimal', maxLength: '' }
|
||||
if (dt === 'float' || dt === 'real') return { dataType: 'float', maxLength: '' }
|
||||
if (dt === 'bit') return { dataType: 'bit', maxLength: '' }
|
||||
if (dt === 'datetime') return { dataType: 'datetime', maxLength: '' }
|
||||
if (dt.startsWith('datetime') || dt === 'smalldatetime' || dt === 'time') {
|
||||
return { dataType: 'datetime2', maxLength: '' }
|
||||
}
|
||||
|
|
@ -1224,6 +1268,18 @@ const SqlTableDesignerDialog = ({
|
|||
}
|
||||
}
|
||||
|
||||
const addWorkflowColumns = () => {
|
||||
const existingNames = new Set(columns.map((c) => c.columnName.trim().toLowerCase()))
|
||||
const toAdd = WORKFLOW_COLUMNS.filter((c) => !existingNames.has(c.columnName.toLowerCase()))
|
||||
|
||||
if (toAdd.length > 0) {
|
||||
setColumns((prev) => {
|
||||
const nonEmpty = prev.filter((c) => c.columnName.trim() !== '')
|
||||
return [...nonEmpty, ...toAdd.map((c) => ({ ...c })), createEmptyColumn()]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const importColumnsFromRememberedCreateTable = async () => {
|
||||
let script = ''
|
||||
|
||||
|
|
@ -1591,7 +1647,10 @@ const SqlTableDesignerDialog = ({
|
|||
} catch {
|
||||
// Non-blocking: seed file save failure does not affect deploy success
|
||||
}
|
||||
onDeployed?.()
|
||||
await onDeployed?.({
|
||||
schemaName: initialTableData?.schemaName || 'dbo',
|
||||
tableName: deployedTable,
|
||||
})
|
||||
handleClose()
|
||||
} else {
|
||||
toast.push(
|
||||
|
|
@ -1690,6 +1749,9 @@ const SqlTableDesignerDialog = ({
|
|||
<Button size="xs" variant="solid" color="green-600" onClick={addMultiTenantColumns}>
|
||||
{translate('::App.SqlQueryManager.AddMultiTenantColumns')}
|
||||
</Button>
|
||||
<Button size="xs" variant="solid" color="indigo-600" onClick={addWorkflowColumns}>
|
||||
{translate('::App.SqlQueryManager.AddWorkflowColumns')}
|
||||
</Button>
|
||||
<Button
|
||||
size="xs"
|
||||
variant="solid"
|
||||
|
|
@ -2678,7 +2740,7 @@ const SqlTableDesignerDialog = ({
|
|||
// ── Render ─────────────────────────────────────────────────────────────────
|
||||
|
||||
return (
|
||||
<Dialog isOpen={isOpen} onClose={handleClose} onRequestClose={handleClose} width={900}>
|
||||
<Dialog isOpen={isOpen} onClose={handleClose} onRequestClose={handleClose} width={1100}>
|
||||
<Dialog.Body className="flex flex-col gap-2">
|
||||
{/* Header */}
|
||||
<div className="flex items-center gap-3 border-b pb-3 flex-shrink-0">
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ const Grid = (props: GridProps) => {
|
|||
const { listFormCode, searchParams, isSubForm, level, gridDto: extGridDto } = props
|
||||
const { translate } = useLocalization()
|
||||
const { smaller } = useResponsive()
|
||||
const config = useStoreState((state) => state.abpConfig.config)
|
||||
const currentUser = useStoreState((state) => state.auth.user)
|
||||
|
||||
const gridRef = useRef<DataGridRef>()
|
||||
const refListFormCode = useRef('')
|
||||
|
|
@ -374,10 +374,10 @@ const Grid = (props: GridProps) => {
|
|||
grd,
|
||||
gridDto?.gridOptions.workflowDto,
|
||||
selectedRowsData ?? grd.getSelectedRowsData(),
|
||||
config?.currentUser,
|
||||
currentUser,
|
||||
)
|
||||
},
|
||||
[config?.currentUser, gridDto],
|
||||
[currentUser, gridDto],
|
||||
)
|
||||
|
||||
const refreshData = useCallback(() => {
|
||||
|
|
@ -997,7 +997,7 @@ const Grid = (props: GridProps) => {
|
|||
|
||||
// Kolonları oluştur - dil değiştiğinde güncelle
|
||||
const memoizedColumns = useMemo(() => {
|
||||
if (!gridDto || !config) return undefined
|
||||
if (!gridDto) return undefined
|
||||
|
||||
const cols = getBandedColumns()
|
||||
|
||||
|
|
@ -1038,7 +1038,7 @@ const Grid = (props: GridProps) => {
|
|||
})
|
||||
|
||||
return cols
|
||||
}, [gridDto, config])
|
||||
}, [gridDto])
|
||||
|
||||
useEffect(() => {
|
||||
setColumnData(memoizedColumns)
|
||||
|
|
|
|||
|
|
@ -232,6 +232,7 @@ const Tree = (props: TreeProps) => {
|
|||
const { listFormCode, searchParams, isSubForm, level, gridDto: extGridDto } = props
|
||||
const { translate } = useLocalization()
|
||||
const { smaller } = useResponsive()
|
||||
const currentUser = useStoreState((state) => state.auth.user)
|
||||
|
||||
const gridRef = useRef<TreeListRef>()
|
||||
const refListFormCode = useRef('')
|
||||
|
|
@ -251,7 +252,6 @@ const Tree = (props: TreeProps) => {
|
|||
const [widgetGroupHeight, setWidgetGroupHeight] = useState(0)
|
||||
|
||||
const [expandedRowKeys, setExpandedRowKeys] = useState<any[]>([])
|
||||
const config = useStoreState((state) => state.abpConfig.config)
|
||||
|
||||
type EditorOptionsWithButtons = {
|
||||
buttons?: any[]
|
||||
|
|
@ -409,10 +409,10 @@ const Tree = (props: TreeProps) => {
|
|||
tree,
|
||||
gridDto?.gridOptions.workflowDto,
|
||||
selectedRowsData ?? tree.getSelectedRowsData(),
|
||||
config?.currentUser,
|
||||
currentUser,
|
||||
)
|
||||
},
|
||||
[config?.currentUser, gridDto],
|
||||
[currentUser, gridDto],
|
||||
)
|
||||
|
||||
const refreshData = useCallback(() => {
|
||||
|
|
@ -900,7 +900,7 @@ const Tree = (props: TreeProps) => {
|
|||
}, [gridDto])
|
||||
|
||||
useEffect(() => {
|
||||
if (!gridDto || !config) return
|
||||
if (!gridDto) return
|
||||
|
||||
const cols = getBandedColumns()
|
||||
setColumnData(cols)
|
||||
|
|
@ -913,7 +913,7 @@ const Tree = (props: TreeProps) => {
|
|||
cols,
|
||||
)
|
||||
setTreeListDataSource(dataSource)
|
||||
}, [gridDto, searchParams, config])
|
||||
}, [gridDto, searchParams])
|
||||
|
||||
useEffect(() => {
|
||||
const activeFilters = extraFilters.filter((f) => f.value)
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ const useToolbar = ({
|
|||
const { translate } = useLocalization()
|
||||
const { checkPermission } = usePermission()
|
||||
const isPwaMode = usePWA()
|
||||
const config = useStoreState((state) => state.abpConfig.config)
|
||||
const currentUser = useStoreState((state) => state.auth.user)
|
||||
|
||||
const [toolbarData, setToolbarData] = useState<ToolbarItem[]>([])
|
||||
const [toolbarModalData, setToolbarModalData] = useState<ToolbarModalData>()
|
||||
|
|
@ -204,7 +204,7 @@ const useToolbar = ({
|
|||
row,
|
||||
workflowOptions,
|
||||
criteria.title,
|
||||
getCurrentUserWorkflowIdentities(config?.currentUser),
|
||||
getCurrentUserWorkflowIdentities(currentUser),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -483,10 +483,9 @@ const useToolbar = ({
|
|||
|
||||
useEffect(() => {
|
||||
if (!gridDto && !listFormCode) return
|
||||
if (!config) return
|
||||
|
||||
getToolbarData()
|
||||
}, [gridDto, listFormCode, config])
|
||||
}, [gridDto, listFormCode, currentUser])
|
||||
|
||||
return {
|
||||
toolbarData,
|
||||
|
|
|
|||
Loading…
Reference in a new issue