Wizard Güncellemeleri

This commit is contained in:
Sedat Öztürk 2026-03-18 22:47:39 +03:00
parent 63695be34e
commit e9f56e0e33
7 changed files with 143 additions and 8 deletions

View file

@ -11,4 +11,6 @@ public class WizardColumnItemInputDto
public int ColSpan { get; set; } = 1;
public bool IsRequired { get; set; }
public DbType DbSourceType { get; set; } = DbType.String;
public string TurkishCaption { get; set; }
public string EnglishCaption { get; set; }
}

View file

@ -229,22 +229,31 @@ public class ListFormWizardAppService(
// ListFormField - each item in each group becomes a visible field record
var fieldOrder = 0;
var captionName = string.Empty;
foreach (var group in input.Groups)
{
foreach (var item in group.Items)
{
fieldOrder++;
captionName = $"App.Listform.ListformField.{item.DataField}";
await repoListFormField.InsertAsync(new ListFormField
{
ListFormCode = input.ListFormCode,
FieldName = item.DataField,
CaptionName = item.DataField,
CaptionName = captionName,
Visible = item.DataField != input.KeyFieldName,
IsActive = true,
AllowSearch = true,
ListOrderNo = fieldOrder,
SourceDbType = item.DbSourceType,
CultureName = PlatformConsts.DefaultLanguage,
PermissionJson = WizardConsts.DefaultFieldPermissionJson(code),
ColumnCustomizationJson = WizardConsts.DefaultColumnCustomizationJson,
ColumnFilterJson = WizardConsts.DefaultColumnFilteringJson,
PivotSettingsJson = WizardConsts.DefaultPivotSettingsJson,
}, autoSave: false);
await CreateLangKey(captionName, item.EnglishCaption, item.TurkishCaption);
}
}
}

View file

@ -16304,6 +16304,18 @@
"en": "Columns load after selecting a Select Command",
"tr": "Select Command seçince sütunlar yüklenir"
},
{
"resourceName": "Platform",
"key": "ListForms.Wizard.Step3.TurkishCaption",
"en": "Turkish Caption",
"tr": "Türkçe Başlık"
},
{
"resourceName": "Platform",
"key": "ListForms.Wizard.Step3.EnglishCaption",
"en": "English Caption",
"tr": "İngilizce Başlık"
},
{
"resourceName": "Platform",
"key": "ListForms.Wizard.Step3.EditorOptions",

View file

@ -2,6 +2,11 @@ using System.Data;
using System.Text.Json;
using Sozsoft.Platform.Enums;
using static Sozsoft.Platform.PlatformConsts;
using System.Linq;
using System.Reflection;
using System.ComponentModel.DataAnnotations;
using System.Text.RegularExpressions;
using System.Globalization;
public static class WizardConsts
{
@ -26,6 +31,44 @@ public static class WizardConsts
public static string MenuUrl(string code) => $"/admin/list/{code}";
public static string MenuIcon => "FcList";
public static class LabelHelper
{
public static string GetCamelCaseLabel<T>(string propertyName)
{
var prop = typeof(T).GetProperty(propertyName);
if (prop == null)
return propertyName;
// 1. Display varsa direkt onu kullan
var displayAttr = prop.GetCustomAttribute<DisplayAttribute>();
if (displayAttr != null && !string.IsNullOrWhiteSpace(displayAttr.Name))
return displayAttr.Name;
// 2. CamelCase → kelimelere ayır
var words = Regex
.Split(propertyName, "(?=[A-Z])")
.Where(x => !string.IsNullOrWhiteSpace(x))
.ToList();
// 3. Türkçe karakter dönüşümü + düzgün büyük harf
var culture = new CultureInfo("tr-TR");
words = words.Select(w =>
{
w = w.ToLower(culture);
// Türkçe karakter normalize (genel yaklaşım)
w = w
.Replace("i", "i") // bilinçli bırakıyoruz
.Replace("ı", "ı"); // zaten doğru
return culture.TextInfo.ToTitleCase(w);
}).ToList();
return string.Join(" ", words);
}
}
public static readonly string DefaultExportJson = JsonSerializer.Serialize(new
{
Enabled = true,
@ -83,6 +126,33 @@ public static class WizardConsts
});
}
public static string DefaultFieldPermissionJson(string permissionName)
{
return JsonSerializer.Serialize(new
{
C = permissionName + ".Create",
R = permissionName,
U = permissionName + ".Update",
E = true,
I = false,
Deny = false
});
}
public static readonly string DefaultColumnCustomizationJson = JsonSerializer.Serialize(new
{
AllowReordering = true,
});
public static readonly string DefaultColumnFilteringJson = JsonSerializer.Serialize(new
{
AllowFiltering = true,
});
public static readonly string DefaultPivotSettingsJson = JsonSerializer.Serialize(new
{
IsPivot = true
});
public static string DefaultDeleteCommand(string tableName)
{
return $"UPDATE \"{tableName}\" SET \"DeleterId\"=@DeleterId, \"DeletionTime\"=CURRENT_TIMESTAMP, \"IsDeleted\"='true' WHERE \"Id\"=@Id";

View file

@ -324,13 +324,14 @@ const Wizard = () => {
const col = selectCommandColumns.find((c) => c.columnName === item.dataField)
return {
dataField: item.dataField,
captionName: `App.Listform.ListformField.${item.dataField}`,
editorType: item.editorType,
editorOptions: item.editorOptions ?? '',
editorScript: item.editorScript ?? '',
colSpan: item.colSpan,
isRequired: item.isRequired,
dbSourceType: col ? sqlDataTypeToDbType(col.dataType) : 12, // 12 = DbType.String
turkishCaption: item.turkishCaption,
englishCaption: item.englishCaption,
}
}),
})),

View file

@ -27,6 +27,8 @@ export interface WizardGroupItem {
editorScript: string
colSpan: number
isRequired: boolean
turkishCaption?: string
englishCaption?: string
}
export interface WizardGroup {
@ -70,6 +72,18 @@ function inferEditorType(sqlType: string): string {
return 'dxTextBox'
}
const formatLabel = (text: string) => {
return text
// CamelCase → kelimelere ayır
.split(/(?=[A-Z])/)
.filter(Boolean)
.map(word =>
word.charAt(0).toUpperCase() +
word.slice(1).toLowerCase()
)
.join(" ");
};
function newGroupItem(colName: string, sqlType = ''): WizardGroupItem {
return {
id: `${colName}_${Date.now()}`,
@ -79,6 +93,8 @@ function newGroupItem(colName: string, sqlType = ''): WizardGroupItem {
editorScript: '',
colSpan: 1,
isRequired: false,
turkishCaption: formatLabel(colName),
englishCaption: formatLabel(colName),
}
}
@ -123,6 +139,8 @@ function AvailableColumnChip({ colName }: { colName: string }) {
interface SortableItemProps {
item: WizardGroupItem
groupColCount: number
onTurkishCaptionChange: (val: string) => void
onEnglishCaptionChange: (val: string) => void
onEditorTypeChange: (val: string) => void
onEditorOptionsChange: (val: string) => void
onEditorScriptChange: (val: string) => void
@ -134,6 +152,8 @@ interface SortableItemProps {
function SortableItem({
item,
groupColCount,
onTurkishCaptionChange,
onEnglishCaptionChange,
onEditorTypeChange,
onEditorOptionsChange,
onEditorScriptChange,
@ -198,14 +218,33 @@ function SortableItem({
))}
</select>
{/* Turkish Caption */}
<div className="flex flex-col gap-0.5">
<span className="text-[10px] text-gray-400 font-medium">{translate('::ListForms.Wizard.Step3.TurkishCaption')}</span>
<input
value={item.turkishCaption}
onChange={(e) => onTurkishCaptionChange(e.target.value)}
className="w-full text-xs px-1.5 py-1 rounded border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-700 text-gray-700 dark:text-gray-200 focus:outline-none focus:border-indigo-400 resize-none font-mono"
/>
</div>
{/* English Caption */}
<div className="flex flex-col gap-0.5">
<span className="text-[10px] text-gray-400 font-medium">{translate('::ListForms.Wizard.Step3.EnglishCaption')}</span>
<input
value={item.englishCaption}
onChange={(e) => onEnglishCaptionChange(e.target.value)}
className="w-full text-xs px-1.5 py-1 rounded border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-700 text-gray-700 dark:text-gray-200 focus:outline-none focus:border-indigo-400 resize-none font-mono"
/>
</div>
{/* Editor Options */}
<div className="flex flex-col gap-0.5">
<span className="text-[10px] text-gray-400 font-medium">{translate('::ListForms.Wizard.Step3.EditorOptions')}</span>
<textarea
<input
value={item.editorOptions}
onChange={(e) => onEditorOptionsChange(e.target.value)}
placeholder='{"readOnly": false}'
rows={2}
className="w-full text-xs px-1.5 py-1 rounded border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-700 text-gray-700 dark:text-gray-200 focus:outline-none focus:border-indigo-400 resize-none font-mono"
/>
</div>
@ -360,6 +399,8 @@ function GroupCard({
key={item.id}
item={item}
groupColCount={group.colCount}
onTurkishCaptionChange={(val) => onItemChange(item.id, { turkishCaption: val })}
onEnglishCaptionChange={(val) => onItemChange(item.id, { englishCaption: val })}
onEditorTypeChange={(val) => onItemChange(item.id, { editorType: val })}
onEditorOptionsChange={(val) => onItemChange(item.id, { editorOptions: val })}
onEditorScriptChange={(val) => onItemChange(item.id, { editorScript: val })}
@ -405,7 +446,7 @@ const WizardStep3 = ({
? [
{
id: `grp_default_${Date.now()}`,
caption: 'Group 1',
caption: '',
colCount: 2,
items: [] as WizardGroupItem[],
},

View file

@ -269,7 +269,7 @@ const WizardStep4 = ({
badge={`${g.items.length} ${translate('::ListForms.Wizard.Step4.StatField')} · ${g.colCount} ${translate('::ListForms.Wizard.Step4.StatColumn')}`}
defaultOpen={false}
>
<div className="flex flex-col gap-0.5">
<div className="grid grid-cols-2 gap-2">
{g.items.length === 0 ? (
<span className="text-xs text-gray-300 italic">{translate('::ListForms.Wizard.Step4.NoFields') || 'Alan yok'}</span>
) : (
@ -284,8 +284,8 @@ const WizardStep4 = ({
<span className="text-[10px] text-gray-400 bg-gray-100 dark:bg-gray-800 px-1.5 py-0.5 rounded">
{item.editorType}
</span>
<span className="text-[10px] text-gray-400 ml-auto shrink-0">
span:{item.colSpan}
<span className="text-[10px] text-gray-400 mr-auto shrink-0 bg-gray-100 dark:bg-gray-800 px-1.5 py-0.5 rounded">
col-span-{item.colSpan}
{item.isRequired && (
<span className="ml-1 text-red-400 font-semibold">*</span>
)}