Wizard üzerindeki problemler giderildi.

This commit is contained in:
Sedat ÖZTÜRK 2026-06-05 12:30:40 +03:00
parent 975bc8dd6c
commit ebab6ea114
10 changed files with 121 additions and 63 deletions

View file

@ -674,7 +674,7 @@
"code": "Abp.Account.EnableLocalLogin", "code": "Abp.Account.EnableLocalLogin",
"nameKey": "Abp.Account.EnableLocalLogin", "nameKey": "Abp.Account.EnableLocalLogin",
"descriptionKey": "Abp.Account.EnableLocalLogin.Description", "descriptionKey": "Abp.Account.EnableLocalLogin.Description",
"defaultValue": "False", "defaultValue": "True",
"isVisibleToClients": false, "isVisibleToClients": false,
"providers": "G|D", "providers": "G|D",
"isInherited": false, "isInherited": false,

View file

@ -773,10 +773,10 @@ public static class PlatformConsts
{ {
public static class ParameterTypes public static class ParameterTypes
{ {
public const string Static = "S"; public const string Static = "Static";
public const string Query = "Q"; public const string Query = "Query";
public const string Path = "P"; public const string Path = "Path";
public const string Body = "B"; public const string Body = "Body";
} }
} }

View file

@ -324,16 +324,16 @@
"Url": "/dil/", "Url": "/dil/",
"Method": "GET", "Method": "GET",
"DataSourceCode": "Default", "DataSourceCode": "Default",
"Sql": "SELECT * FROM Plat_H_Language WHERE IsEnabled = @IsEnabled AND CultureName = @CultureName", "Sql": "SELECT * FROM Sas_H_Language WHERE IsEnabled = @IsEnabled AND CultureName = @CultureName",
"ParametersJson": [ "ParametersJson": [
{ {
"Type": "P", "Type": "Path",
"Name": "CultureName", "Name": "CultureName",
"DefaultValue": "ar", "DefaultValue": "ar",
"Path": "/dil/:CultureName/" "Path": "/dil/:CultureName/"
}, },
{ {
"Type": "S", "Type": "Static",
"Name": "IsEnabled", "Name": "IsEnabled",
"DefaultValue": "true" "DefaultValue": "true"
} }

View file

@ -3,6 +3,7 @@ import { ROUTES_ENUM } from '@/routes/route.constant'
import { SelectBoxOption } from '@/types/shared' import { SelectBoxOption } from '@/types/shared'
import { useLocalization } from '@/utils/hooks/useLocalization' import { useLocalization } from '@/utils/hooks/useLocalization'
import { Form, Formik, FormikProps } from 'formik' import { Form, Formik, FormikProps } from 'formik'
import type { KeyboardEvent } from 'react'
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
import { Helmet } from 'react-helmet' import { Helmet } from 'react-helmet'
import { useLocation, useNavigate } from 'react-router-dom' import { useLocation, useNavigate } from 'react-router-dom'
@ -516,24 +517,38 @@ const Wizard = () => {
.trim() .trim()
const handleWizardNameChange = (name: string) => { const handleWizardNameChange = (name: string) => {
const formik = formikRef.current
const spacedLabel = toSpacedLabel(name) const spacedLabel = toSpacedLabel(name)
const previousSpacedLabel = toSpacedLabel(formik?.values.wizardName ?? '')
const derived = deriveListFormCode(name) const derived = deriveListFormCode(name)
formikRef.current?.setFieldValue('wizardName', name) const setAutoText = (field: keyof Pick<
formikRef.current?.setFieldValue('listFormCode', derived) ListFormWizardDto,
formikRef.current?.setFieldValue('menuCode', derived) | 'languageTextMenuEn'
formikRef.current?.setFieldValue('languageTextMenuEn', spacedLabel) | 'languageTextMenuTr'
formikRef.current?.setFieldValue('languageTextMenuTr', spacedLabel) | 'languageTextTitleEn'
formikRef.current?.setFieldValue('languageTextTitleEn', spacedLabel) | 'languageTextTitleTr'
formikRef.current?.setFieldValue('languageTextTitleTr', spacedLabel) | 'languageTextDescEn'
formikRef.current?.setFieldValue('languageTextDescEn', spacedLabel) | 'languageTextDescTr'
formikRef.current?.setFieldValue('languageTextDescTr', spacedLabel) >) => {
const current = formik?.values[field]
if (!current || current === previousSpacedLabel) {
formik?.setFieldValue(field, spacedLabel)
}
}
formik?.setFieldValue('wizardName', name)
formik?.setFieldValue('listFormCode', derived)
formik?.setFieldValue('menuCode', derived)
setAutoText('languageTextMenuEn')
setAutoText('languageTextMenuTr')
setAutoText('languageTextTitleEn')
setAutoText('languageTextTitleTr')
setAutoText('languageTextDescEn')
setAutoText('languageTextDescTr')
} }
const handleMenuParentChange = (code: string) => { const applyPermissionGroupFromRoot = (rootCode: string) => {
formikRef.current?.setFieldValue('menuParentCode', code)
if (!code) return
const rootCode = findRootCode(rawMenuItems, code)
const rootItem = rawMenuItems.find((i) => i.code === rootCode) const rootItem = rawMenuItems.find((i) => i.code === rootCode)
// 1. Use group field if set // 1. Use group field if set
@ -565,6 +580,28 @@ const Wizard = () => {
formikRef.current?.setFieldValue('permissionGroupName', rootCode) formikRef.current?.setFieldValue('permissionGroupName', rootCode)
} }
const handleMenuParentChange = (code: string) => {
formikRef.current?.setFieldValue('menuParentCode', code)
if (!code) return
applyPermissionGroupFromRoot(findRootCode(rawMenuItems, code))
}
const handleMenuCreated = async (menu: {
code: string
parentCode?: string
menuTextEn: string
menuTextTr: string
}) => {
formikRef.current?.setFieldValue('menuParentCode', menu.code)
formikRef.current?.setFieldValue('languageTextMenuParentEn', menu.menuTextEn)
formikRef.current?.setFieldValue('languageTextMenuParentTr', menu.menuTextTr)
const rootCode = menu.parentCode ? findRootCode(rawMenuItems, menu.parentCode) : menu.code
applyPermissionGroupFromRoot(rootCode)
await getMenuList()
}
const handleNext = async () => { const handleNext = async () => {
if (!formikRef.current) return if (!formikRef.current) return
const errors = await formikRef.current.validateForm() const errors = await formikRef.current.validateForm()
@ -586,6 +623,19 @@ const Wizard = () => {
const handleBack = () => setCurrentStep(0) const handleBack = () => setCurrentStep(0)
const { getConfig } = useStoreActions((a) => a.abpConfig) const { getConfig } = useStoreActions((a) => a.abpConfig)
const preventEnterSubmit = (event: KeyboardEvent<HTMLFormElement>) => {
if (event.key !== 'Enter') return
const target = event.target as HTMLElement
const tagName = target.tagName.toLowerCase()
const isTextArea = tagName === 'textarea'
const isExplicitSubmit = target.getAttribute('type') === 'submit'
if (!isTextArea && !isExplicitSubmit) {
event.preventDefault()
}
}
const handleNext2 = async () => { const handleNext2 = async () => {
if (!formikRef.current) return if (!formikRef.current) return
const errors = await formikRef.current.validateForm() const errors = await formikRef.current.validateForm()
@ -704,40 +754,12 @@ const Wizard = () => {
innerRef={formikRef} innerRef={formikRef}
initialValues={{ ...initialValues }} initialValues={{ ...initialValues }}
validationSchema={listFormValidationSchema} validationSchema={listFormValidationSchema}
onSubmit={async (values, { setSubmitting }) => { onSubmit={(_, { setSubmitting }) => {
setSubmitting(true) setSubmitting(false)
try {
// 🔴 1. Kaydet (bekle)
await postListFormWizard({ ...values })
// 🔴 2. Config güncelle (bekle)
await getConfig(true)
// 🔴 3. Navigate
navigate(
ROUTES_ENUM.protected.admin.list.replace(':listFormCode', values.listFormCode),
{ replace: true },
)
// 🔴 4. Toast (istersen navigate öncesi de olabilir)
toast.push(
<Notification type="success" duration={2000}>
{translate('::ListForms.FormBilgileriKaydedildi')}
</Notification>,
{ placement: 'top-end' },
)
} catch (error: any) {
toast.push(<Notification title={error.message} type="danger" />, {
placement: 'top-end',
})
} finally {
setSubmitting(false)
}
}} }}
> >
{({ touched, errors, isSubmitting, values }) => ( {({ touched, errors, isSubmitting, values }) => (
<Form> <Form onKeyDown={preventEnterSubmit}>
<FormContainer size={currentStep >= 2 ? undefined : 'sm'}> <FormContainer size={currentStep >= 2 ? undefined : 'sm'}>
{/* ─── Step 1: Basic Info ─────────────────────────────── */} {/* ─── Step 1: Basic Info ─────────────────────────────── */}
{currentStep === 0 && ( {currentStep === 0 && (
@ -752,6 +774,7 @@ const Wizard = () => {
isLoadingMenu={isLoadingMenu} isLoadingMenu={isLoadingMenu}
onMenuParentChange={handleMenuParentChange} onMenuParentChange={handleMenuParentChange}
onClearMenuParent={() => formikRef.current?.setFieldValue('menuParentCode', '')} onClearMenuParent={() => formikRef.current?.setFieldValue('menuParentCode', '')}
onMenuCreated={handleMenuCreated}
onReloadMenu={getMenuList} onReloadMenu={getMenuList}
permissionGroupList={permissionGroupList} permissionGroupList={permissionGroupList}
isLoadingPermissionGroup={isLoadingPermissionGroup} isLoadingPermissionGroup={isLoadingPermissionGroup}

View file

@ -414,6 +414,14 @@ export interface WizardStep1Props {
isLoadingMenu: boolean isLoadingMenu: boolean
onMenuParentChange: (code: string) => void onMenuParentChange: (code: string) => void
onClearMenuParent: () => void onClearMenuParent: () => void
onMenuCreated: (menu: {
code: string
parentCode?: string
menuTextEn: string
menuTextTr: string
icon?: string
shortName?: string
}) => void | Promise<void>
onReloadMenu: () => void onReloadMenu: () => void
permissionGroupList: SelectBoxOption[] permissionGroupList: SelectBoxOption[]
isLoadingPermissionGroup: boolean isLoadingPermissionGroup: boolean
@ -432,6 +440,7 @@ const WizardStep1 = ({
isLoadingMenu, isLoadingMenu,
onMenuParentChange, onMenuParentChange,
onClearMenuParent, onClearMenuParent,
onMenuCreated,
onReloadMenu, onReloadMenu,
permissionGroupList, permissionGroupList,
isLoadingPermissionGroup, isLoadingPermissionGroup,
@ -544,7 +553,7 @@ const WizardStep1 = ({
initialParentCode={menuDialogParentCode} initialParentCode={menuDialogParentCode}
initialOrder={menuDialogInitialOrder} initialOrder={menuDialogInitialOrder}
rawItems={rawMenuItems} rawItems={rawMenuItems}
onSaved={onReloadMenu} onSaved={onMenuCreated}
/> />
</div> </div>

View file

@ -719,6 +719,7 @@ const WizardStep2 = ({
<div className="flex items-center gap-2 ml-3"> <div className="flex items-center gap-2 ml-3">
<Button <Button
variant="solid" variant="solid"
type="button"
onClick={() => onToggleAllColumns(true)} onClick={() => onToggleAllColumns(true)}
className="text-xs px-2 py-0.5 rounded bg-indigo-500 text-white hover:bg-indigo-600" className="text-xs px-2 py-0.5 rounded bg-indigo-500 text-white hover:bg-indigo-600"
> >
@ -726,6 +727,7 @@ const WizardStep2 = ({
</Button> </Button>
<Button <Button
variant="default" variant="default"
type="button"
onClick={() => onToggleAllColumns(false)} onClick={() => onToggleAllColumns(false)}
className="text-xs px-2 py-0.5 rounded border border-gray-300 dark:border-gray-600 text-gray-500 hover:text-red-500 hover:border-red-400" className="text-xs px-2 py-0.5 rounded border border-gray-300 dark:border-gray-600 text-gray-500 hover:text-red-500 hover:border-red-400"
> >

View file

@ -462,10 +462,10 @@ function WizardStep4({
<p>Silmek istediğinize emin misiniz?</p> <p>Silmek istediğinize emin misiniz?</p>
</Dialog.Body> </Dialog.Body>
<Dialog.Footer className="flex justify-end gap-2"> <Dialog.Footer className="flex justify-end gap-2">
<Button variant="plain" onClick={() => setDeleteIndex(null)}> <Button type="button" variant="plain" onClick={() => setDeleteIndex(null)}>
Cancel Cancel
</Button> </Button>
<Button variant="solid" onClick={removeSubForm}> <Button type="button" variant="solid" onClick={removeSubForm}>
Delete Delete
</Button> </Button>
</Dialog.Footer> </Dialog.Footer>

View file

@ -340,10 +340,10 @@ function WizardStep5({ widgets, translate, onChange, onBack, onNext }: Props) {
<p>Silmek istediğinize emin misiniz?</p> <p>Silmek istediğinize emin misiniz?</p>
</Dialog.Body> </Dialog.Body>
<Dialog.Footer className="flex justify-end gap-2"> <Dialog.Footer className="flex justify-end gap-2">
<Button variant="plain" onClick={() => setDeleteIndex(null)}> <Button type="button" variant="plain" onClick={() => setDeleteIndex(null)}>
Cancel Cancel
</Button> </Button>
<Button variant="solid" onClick={removeWidget}> <Button type="button" variant="solid" onClick={removeWidget}>
Delete Delete
</Button> </Button>
</Dialog.Footer> </Dialog.Footer>

View file

@ -1943,7 +1943,14 @@ const SqlTableDesignerDialog = ({
initialParentCode={selectedMenuCode} initialParentCode={selectedMenuCode}
initialOrder={999} initialOrder={999}
rawItems={rawMenuItems} rawItems={rawMenuItems}
onSaved={() => reloadMenus()} onSaved={(menu) =>
reloadMenus((items) => {
const savedMenu = items.find((item) => item.code === menu.code)
if (savedMenu?.code && savedMenu.shortName) {
onMenuCodeSelect(savedMenu.code)
}
})
}
/> />
</div> </div>

View file

@ -128,7 +128,14 @@ export interface MenuAddDialogProps {
initialParentCode: string initialParentCode: string
initialOrder: number initialOrder: number
rawItems: (MenuItem & { id?: string })[] rawItems: (MenuItem & { id?: string })[]
onSaved: () => void onSaved: (menu: {
code: string
parentCode?: string
menuTextEn: string
menuTextTr: string
icon?: string
shortName?: string
}) => void | Promise<void>
} }
export function MenuAddDialog({ export function MenuAddDialog({
@ -172,7 +179,7 @@ export function MenuAddDialog({
if (shortNameRequired && !form.shortName.trim()) return if (shortNameRequired && !form.shortName.trim()) return
setSaving(true) setSaving(true)
try { try {
await menuService.createWithLanguageKeyText({ const savedMenu = {
code: form.code.trim(), code: form.code.trim(),
displayName: form.code.trim(), displayName: form.code.trim(),
parentCode: form.parentCode.trim() || undefined, parentCode: form.parentCode.trim() || undefined,
@ -182,9 +189,18 @@ export function MenuAddDialog({
isDisabled: false, isDisabled: false,
menuTextTr: form.menuTextTr.trim(), menuTextTr: form.menuTextTr.trim(),
menuTextEn: form.menuTextEn.trim(), menuTextEn: form.menuTextEn.trim(),
} as MenuDto) } as MenuDto
onSaved() await menuService.createWithLanguageKeyText(savedMenu)
await onSaved({
code: savedMenu.code!,
parentCode: savedMenu.parentCode,
menuTextEn: savedMenu.menuTextEn!,
menuTextTr: savedMenu.menuTextTr!,
icon: savedMenu.icon,
shortName: savedMenu.shortName,
})
onClose() onClose()
} catch (e: any) { } catch (e: any) {
toast.push(<Notification title={e.message} type="danger" />, { placement: 'top-end' }) toast.push(<Notification title={e.message} type="danger" />, { placement: 'top-end' })
@ -342,10 +358,11 @@ export function MenuAddDialog({
{/* Footer */} {/* Footer */}
<div className="flex justify-end gap-2 pt-1 border-t border-gray-100 dark:border-gray-700"> <div className="flex justify-end gap-2 pt-1 border-t border-gray-100 dark:border-gray-700">
<Button size="sm" variant="plain" onClick={onClose}> <Button type="button" size="sm" variant="plain" onClick={onClose}>
{translate('::Cancel') || 'İptal'} {translate('::Cancel') || 'İptal'}
</Button> </Button>
<Button <Button
type="button"
size="sm" size="sm"
variant="solid" variant="solid"
loading={saving} loading={saving}