Wizard Güncellemeleri
This commit is contained in:
parent
63695be34e
commit
e9f56e0e33
7 changed files with 143 additions and 8 deletions
|
|
@ -11,4 +11,6 @@ public class WizardColumnItemInputDto
|
||||||
public int ColSpan { get; set; } = 1;
|
public int ColSpan { get; set; } = 1;
|
||||||
public bool IsRequired { get; set; }
|
public bool IsRequired { get; set; }
|
||||||
public DbType DbSourceType { get; set; } = DbType.String;
|
public DbType DbSourceType { get; set; } = DbType.String;
|
||||||
|
public string TurkishCaption { get; set; }
|
||||||
|
public string EnglishCaption { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -229,22 +229,31 @@ public class ListFormWizardAppService(
|
||||||
|
|
||||||
// ListFormField - each item in each group becomes a visible field record
|
// ListFormField - each item in each group becomes a visible field record
|
||||||
var fieldOrder = 0;
|
var fieldOrder = 0;
|
||||||
|
var captionName = string.Empty;
|
||||||
foreach (var group in input.Groups)
|
foreach (var group in input.Groups)
|
||||||
{
|
{
|
||||||
foreach (var item in group.Items)
|
foreach (var item in group.Items)
|
||||||
{
|
{
|
||||||
fieldOrder++;
|
fieldOrder++;
|
||||||
|
captionName = $"App.Listform.ListformField.{item.DataField}";
|
||||||
await repoListFormField.InsertAsync(new ListFormField
|
await repoListFormField.InsertAsync(new ListFormField
|
||||||
{
|
{
|
||||||
ListFormCode = input.ListFormCode,
|
ListFormCode = input.ListFormCode,
|
||||||
FieldName = item.DataField,
|
FieldName = item.DataField,
|
||||||
CaptionName = item.DataField,
|
CaptionName = captionName,
|
||||||
Visible = item.DataField != input.KeyFieldName,
|
Visible = item.DataField != input.KeyFieldName,
|
||||||
IsActive = true,
|
IsActive = true,
|
||||||
|
AllowSearch = true,
|
||||||
ListOrderNo = fieldOrder,
|
ListOrderNo = fieldOrder,
|
||||||
SourceDbType = item.DbSourceType,
|
SourceDbType = item.DbSourceType,
|
||||||
CultureName = PlatformConsts.DefaultLanguage,
|
CultureName = PlatformConsts.DefaultLanguage,
|
||||||
|
PermissionJson = WizardConsts.DefaultFieldPermissionJson(code),
|
||||||
|
ColumnCustomizationJson = WizardConsts.DefaultColumnCustomizationJson,
|
||||||
|
ColumnFilterJson = WizardConsts.DefaultColumnFilteringJson,
|
||||||
|
PivotSettingsJson = WizardConsts.DefaultPivotSettingsJson,
|
||||||
}, autoSave: false);
|
}, autoSave: false);
|
||||||
|
|
||||||
|
await CreateLangKey(captionName, item.EnglishCaption, item.TurkishCaption);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16304,6 +16304,18 @@
|
||||||
"en": "Columns load after selecting a Select Command",
|
"en": "Columns load after selecting a Select Command",
|
||||||
"tr": "Select Command seçince sütunlar yüklenir"
|
"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",
|
"resourceName": "Platform",
|
||||||
"key": "ListForms.Wizard.Step3.EditorOptions",
|
"key": "ListForms.Wizard.Step3.EditorOptions",
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,11 @@ using System.Data;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using Sozsoft.Platform.Enums;
|
using Sozsoft.Platform.Enums;
|
||||||
using static Sozsoft.Platform.PlatformConsts;
|
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
|
public static class WizardConsts
|
||||||
{
|
{
|
||||||
|
|
@ -26,6 +31,44 @@ public static class WizardConsts
|
||||||
public static string MenuUrl(string code) => $"/admin/list/{code}";
|
public static string MenuUrl(string code) => $"/admin/list/{code}";
|
||||||
public static string MenuIcon => "FcList";
|
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
|
public static readonly string DefaultExportJson = JsonSerializer.Serialize(new
|
||||||
{
|
{
|
||||||
Enabled = true,
|
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)
|
public static string DefaultDeleteCommand(string tableName)
|
||||||
{
|
{
|
||||||
return $"UPDATE \"{tableName}\" SET \"DeleterId\"=@DeleterId, \"DeletionTime\"=CURRENT_TIMESTAMP, \"IsDeleted\"='true' WHERE \"Id\"=@Id";
|
return $"UPDATE \"{tableName}\" SET \"DeleterId\"=@DeleterId, \"DeletionTime\"=CURRENT_TIMESTAMP, \"IsDeleted\"='true' WHERE \"Id\"=@Id";
|
||||||
|
|
|
||||||
|
|
@ -324,13 +324,14 @@ const Wizard = () => {
|
||||||
const col = selectCommandColumns.find((c) => c.columnName === item.dataField)
|
const col = selectCommandColumns.find((c) => c.columnName === item.dataField)
|
||||||
return {
|
return {
|
||||||
dataField: item.dataField,
|
dataField: item.dataField,
|
||||||
captionName: `App.Listform.ListformField.${item.dataField}`,
|
|
||||||
editorType: item.editorType,
|
editorType: item.editorType,
|
||||||
editorOptions: item.editorOptions ?? '',
|
editorOptions: item.editorOptions ?? '',
|
||||||
editorScript: item.editorScript ?? '',
|
editorScript: item.editorScript ?? '',
|
||||||
colSpan: item.colSpan,
|
colSpan: item.colSpan,
|
||||||
isRequired: item.isRequired,
|
isRequired: item.isRequired,
|
||||||
dbSourceType: col ? sqlDataTypeToDbType(col.dataType) : 12, // 12 = DbType.String
|
dbSourceType: col ? sqlDataTypeToDbType(col.dataType) : 12, // 12 = DbType.String
|
||||||
|
turkishCaption: item.turkishCaption,
|
||||||
|
englishCaption: item.englishCaption,
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
})),
|
})),
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@ export interface WizardGroupItem {
|
||||||
editorScript: string
|
editorScript: string
|
||||||
colSpan: number
|
colSpan: number
|
||||||
isRequired: boolean
|
isRequired: boolean
|
||||||
|
turkishCaption?: string
|
||||||
|
englishCaption?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WizardGroup {
|
export interface WizardGroup {
|
||||||
|
|
@ -70,6 +72,18 @@ function inferEditorType(sqlType: string): string {
|
||||||
return 'dxTextBox'
|
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 {
|
function newGroupItem(colName: string, sqlType = ''): WizardGroupItem {
|
||||||
return {
|
return {
|
||||||
id: `${colName}_${Date.now()}`,
|
id: `${colName}_${Date.now()}`,
|
||||||
|
|
@ -79,6 +93,8 @@ function newGroupItem(colName: string, sqlType = ''): WizardGroupItem {
|
||||||
editorScript: '',
|
editorScript: '',
|
||||||
colSpan: 1,
|
colSpan: 1,
|
||||||
isRequired: false,
|
isRequired: false,
|
||||||
|
turkishCaption: formatLabel(colName),
|
||||||
|
englishCaption: formatLabel(colName),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -123,6 +139,8 @@ function AvailableColumnChip({ colName }: { colName: string }) {
|
||||||
interface SortableItemProps {
|
interface SortableItemProps {
|
||||||
item: WizardGroupItem
|
item: WizardGroupItem
|
||||||
groupColCount: number
|
groupColCount: number
|
||||||
|
onTurkishCaptionChange: (val: string) => void
|
||||||
|
onEnglishCaptionChange: (val: string) => void
|
||||||
onEditorTypeChange: (val: string) => void
|
onEditorTypeChange: (val: string) => void
|
||||||
onEditorOptionsChange: (val: string) => void
|
onEditorOptionsChange: (val: string) => void
|
||||||
onEditorScriptChange: (val: string) => void
|
onEditorScriptChange: (val: string) => void
|
||||||
|
|
@ -134,6 +152,8 @@ interface SortableItemProps {
|
||||||
function SortableItem({
|
function SortableItem({
|
||||||
item,
|
item,
|
||||||
groupColCount,
|
groupColCount,
|
||||||
|
onTurkishCaptionChange,
|
||||||
|
onEnglishCaptionChange,
|
||||||
onEditorTypeChange,
|
onEditorTypeChange,
|
||||||
onEditorOptionsChange,
|
onEditorOptionsChange,
|
||||||
onEditorScriptChange,
|
onEditorScriptChange,
|
||||||
|
|
@ -198,14 +218,33 @@ function SortableItem({
|
||||||
))}
|
))}
|
||||||
</select>
|
</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 */}
|
{/* Editor Options */}
|
||||||
<div className="flex flex-col gap-0.5">
|
<div className="flex flex-col gap-0.5">
|
||||||
<span className="text-[10px] text-gray-400 font-medium">{translate('::ListForms.Wizard.Step3.EditorOptions')}</span>
|
<span className="text-[10px] text-gray-400 font-medium">{translate('::ListForms.Wizard.Step3.EditorOptions')}</span>
|
||||||
<textarea
|
<input
|
||||||
value={item.editorOptions}
|
value={item.editorOptions}
|
||||||
onChange={(e) => onEditorOptionsChange(e.target.value)}
|
onChange={(e) => onEditorOptionsChange(e.target.value)}
|
||||||
placeholder='{"readOnly": false}'
|
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"
|
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>
|
</div>
|
||||||
|
|
@ -360,6 +399,8 @@ function GroupCard({
|
||||||
key={item.id}
|
key={item.id}
|
||||||
item={item}
|
item={item}
|
||||||
groupColCount={group.colCount}
|
groupColCount={group.colCount}
|
||||||
|
onTurkishCaptionChange={(val) => onItemChange(item.id, { turkishCaption: val })}
|
||||||
|
onEnglishCaptionChange={(val) => onItemChange(item.id, { englishCaption: val })}
|
||||||
onEditorTypeChange={(val) => onItemChange(item.id, { editorType: val })}
|
onEditorTypeChange={(val) => onItemChange(item.id, { editorType: val })}
|
||||||
onEditorOptionsChange={(val) => onItemChange(item.id, { editorOptions: val })}
|
onEditorOptionsChange={(val) => onItemChange(item.id, { editorOptions: val })}
|
||||||
onEditorScriptChange={(val) => onItemChange(item.id, { editorScript: val })}
|
onEditorScriptChange={(val) => onItemChange(item.id, { editorScript: val })}
|
||||||
|
|
@ -405,7 +446,7 @@ const WizardStep3 = ({
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
id: `grp_default_${Date.now()}`,
|
id: `grp_default_${Date.now()}`,
|
||||||
caption: 'Group 1',
|
caption: '',
|
||||||
colCount: 2,
|
colCount: 2,
|
||||||
items: [] as WizardGroupItem[],
|
items: [] as WizardGroupItem[],
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -269,7 +269,7 @@ const WizardStep4 = ({
|
||||||
badge={`${g.items.length} ${translate('::ListForms.Wizard.Step4.StatField')} · ${g.colCount} ${translate('::ListForms.Wizard.Step4.StatColumn')}`}
|
badge={`${g.items.length} ${translate('::ListForms.Wizard.Step4.StatField')} · ${g.colCount} ${translate('::ListForms.Wizard.Step4.StatColumn')}`}
|
||||||
defaultOpen={false}
|
defaultOpen={false}
|
||||||
>
|
>
|
||||||
<div className="flex flex-col gap-0.5">
|
<div className="grid grid-cols-2 gap-2">
|
||||||
{g.items.length === 0 ? (
|
{g.items.length === 0 ? (
|
||||||
<span className="text-xs text-gray-300 italic">{translate('::ListForms.Wizard.Step4.NoFields') || 'Alan yok'}</span>
|
<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">
|
<span className="text-[10px] text-gray-400 bg-gray-100 dark:bg-gray-800 px-1.5 py-0.5 rounded">
|
||||||
{item.editorType}
|
{item.editorType}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-[10px] text-gray-400 ml-auto shrink-0">
|
<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">
|
||||||
span:{item.colSpan}
|
col-span-{item.colSpan}
|
||||||
{item.isRequired && (
|
{item.isRequired && (
|
||||||
<span className="ml-1 text-red-400 font-semibold">*</span>
|
<span className="ml-1 text-red-400 font-semibold">*</span>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue