Wizard tarafında kolaylaştırıcı özellikler

This commit is contained in:
Sedat Öztürk 2026-03-21 21:51:27 +03:00
parent 95b8b8e798
commit 401db7bfef
5 changed files with 87 additions and 17 deletions

View file

@ -16052,6 +16052,12 @@
"en": "Optional",
"tr": "İsteğe Bağlı"
},
{
"resourceName": "Platform",
"key": "ListForms.Wizard.Step1.Order",
"en": "Order",
"tr": "Sıra"
},
{
"resourceName": "Platform",
"key": "ListForms.Wizard.Step1.WizardName",

View file

@ -1060,7 +1060,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
new() { Order=1, ColCount=1, ColSpan=1, ItemType="group", Items = [
new EditingFormItemDto { Order=1, DataField="System", ColSpan=1, IsRequired=true, EditorType2=EditorTypes.dxTextBox },
new EditingFormItemDto { Order=2, DataField="Group", ColSpan=1, IsRequired=true, EditorType2=EditorTypes.dxTextBox },
new EditingFormItemDto { Order=3, DataField="Term", ColSpan=1, IsRequired=true, EditorType2=EditorTypes.dxTextBox },
new EditingFormItemDto { Order=3, DataField="Term", ColSpan=1, IsRequired=true, EditorType2=EditorTypes.dxSelectBox, EditorOptions=EditorOptionValues.ShowClearButton },
new EditingFormItemDto { Order=4, DataField="Url", ColSpan=1, IsRequired=true, EditorType2=EditorTypes.dxTextBox },
new EditingFormItemDto { Order=5, DataField="Weight", ColSpan=1, IsRequired=true, EditorType2=EditorTypes.dxNumberBox, EditorOptions=EditorOptionValues.NumberStandartFormat() },
]}
@ -1134,6 +1134,12 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
IsActive = true,
IsDeleted = false,
AllowSearch = true,
LookupJson = JsonSerializer.Serialize(new LookupDto {
DataSourceType = UiLookupDataSourceTypeEnum.Query,
DisplayExpr = "Name",
ValueExpr = "Key",
LookupQuery = LookupQueryValues.LanguageKeyValues
}),
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson

View file

@ -137,6 +137,20 @@ const Wizard = () => {
// ── Editing Form Groups (Step 3) ──
const [editingGroups, setEditingGroups] = useState<WizardGroup[]>([])
// Audit columns that should not be selected by default
const AUDIT_COLUMNS = new Set([
'creationtime',
'creatorid',
'lastmodificationtime',
'lastmodifierid',
'isdeleted',
'deletiontime',
'deleterid',
])
const isAuditColumn = (columnName: string) =>
AUDIT_COLUMNS.has(columnName.toLowerCase())
const loadColumns = async (dsCode: string, schema: string, name: string) => {
if (!dsCode || !name) {
setSelectCommandColumns([])
@ -149,7 +163,8 @@ const Wizard = () => {
const res = await sqlObjectManagerService.getTableColumns(dsCode, schema, name)
const cols = res.data ?? []
setSelectCommandColumns(cols)
setSelectedColumns(new Set(cols.map((c) => c.columnName)))
const selectableColumns = cols.filter((c) => !isAuditColumn(c.columnName))
setSelectedColumns(new Set(selectableColumns.map((c) => c.columnName)))
setEditingGroups([])
// Auto-select first column as key field
if (cols.length > 0) {
@ -176,7 +191,15 @@ const Wizard = () => {
})
const toggleAllColumns = (all: boolean) =>
setSelectedColumns(all ? new Set(selectCommandColumns.map((c) => c.columnName)) : new Set())
setSelectedColumns(
all
? new Set(
selectCommandColumns
.filter((c) => !isAuditColumn(c.columnName))
.map((c) => c.columnName),
)
: new Set(),
)
const getDataSourceList = async () => {
setIsLoadingDataSource(true)
@ -235,11 +258,26 @@ const Wizard = () => {
return sanitized ? `App.Wizard.${sanitized}` : ''
}
const toSpacedLabel = (value: string) =>
value
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
.replace(/([A-Z])([A-Z][a-z])/g, '$1 $2')
.trim()
const handleWizardNameChange = (name: string) => {
formikRef.current?.setFieldValue('wizardName', name)
const spacedLabel = toSpacedLabel(name)
const derived = deriveListFormCode(name)
formikRef.current?.setFieldValue('wizardName', name)
formikRef.current?.setFieldValue('listFormCode', derived)
formikRef.current?.setFieldValue('menuCode', derived)
formikRef.current?.setFieldValue('languageTextMenuEn', spacedLabel)
formikRef.current?.setFieldValue('languageTextMenuTr', spacedLabel)
formikRef.current?.setFieldValue('languageTextTitleEn', spacedLabel)
formikRef.current?.setFieldValue('languageTextTitleTr', spacedLabel)
formikRef.current?.setFieldValue('languageTextDescEn', spacedLabel)
formikRef.current?.setFieldValue('languageTextDescTr', spacedLabel)
}
const handleMenuParentChange = (code: string) => {

View file

@ -6,7 +6,7 @@ import navigationIcon from '@/proxy/menus/navigation-icon.config'
import { MenuItem } from '@/proxy/menus/menu'
import { MenuService } from '@/services/menu.service'
import { Field, FieldProps, FormikErrors, FormikTouched } from 'formik'
import { useEffect, useState } from 'react'
import { useEffect, useMemo, useState } from 'react'
import CreatableSelect from 'react-select/creatable'
import {
FaArrowRight,
@ -411,7 +411,15 @@ const WizardStep1 = ({
}: WizardStep1Props) => {
const [menuDialogOpen, setMenuDialogOpen] = useState(false)
const [menuDialogParentCode, setMenuDialogParentCode] = useState('')
const [menuDialogInitialOrder, setMenuDialogInitialOrder] = useState(999)
const menuDialogInitialOrder = useMemo(() => {
const maxOrder = rawMenuItems.reduce((max, item) => {
const order = typeof item.order === 'number' ? item.order : 0
return order > max ? order : max
}, 0)
return maxOrder + 100
}, [rawMenuItems])
const step1Missing = [
!wizardName && translate('::ListForms.Wizard.Step1.WizardName'),
@ -419,6 +427,7 @@ const WizardStep1 = ({
!values.permissionGroupName && translate('::ListForms.Wizard.Step1.PermissionGroupName'),
!values.languageTextMenuEn && translate('::ListForms.Wizard.Step4.MenuEn'),
!values.languageTextMenuTr && translate('::ListForms.Wizard.Step4.MenuTr'),
!values.menuIcon && translate('::ListForms.Wizard.Step4.MenuIcon'),
].filter(Boolean) as string[]
const step1CanGo = step1Missing.length === 0
@ -464,8 +473,6 @@ const WizardStep1 = ({
? findRootCode(rawMenuItems, values.menuParentCode)
: '',
)
const selectedItem = rawMenuItems.find((i) => i.code === values.menuParentCode)
setMenuDialogInitialOrder(selectedItem?.order ?? 999)
setMenuDialogOpen(true)
}}
className="flex items-center gap-1 px-2 py-0.5 text-xs rounded bg-green-500 text-white hover:bg-green-600"

View file

@ -203,6 +203,13 @@ export function MenuAddDialog({
'h-11 px-3 py-2 rounded-lg border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700 text-sm text-gray-400 dark:text-gray-500 cursor-not-allowed w-full'
const labelCls = 'text-xs font-medium text-gray-500 dark:text-gray-400 mb-1'
const toCodeToken = (value: string) => value.replace(/\s+/g, '')
const toSpacedLabel = (value: string) =>
value
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
.replace(/([A-Z])([A-Z][a-z])/g, '$1 $2')
.trim()
return (
<Dialog isOpen={isOpen} onClose={onClose} onRequestClose={onClose} width={680}>
<div className="flex flex-col gap-5 p-5">
@ -224,13 +231,19 @@ export function MenuAddDialog({
<input
autoFocus
value={form.name}
onChange={(e) =>
onChange={(e) => {
const codeToken = toCodeToken(e.target.value)
const spacedLabel = toSpacedLabel(codeToken)
setForm((p) => ({
...p,
name: e.target.value.replace(/\s+/g, ''),
code: `App.Wizard.${e.target.value.replace(/\s+/g, '')}`,
name: codeToken,
code: `App.Wizard.${codeToken}`,
menuTextEn: spacedLabel,
menuTextTr: spacedLabel,
shortName: codeToken.substring(0, 3),
}))
}
}}
placeholder="MyMenu"
className={fieldCls}
/>