ListFormWizard SubForms, Wizard, Workflow
This commit is contained in:
parent
96cd6dfd80
commit
231860e85a
15 changed files with 2509 additions and 962 deletions
|
|
@ -68,5 +68,8 @@ public class ListFormWizardDto
|
||||||
public string SchedulerEndDateExpr { get; set; }
|
public string SchedulerEndDateExpr { get; set; }
|
||||||
|
|
||||||
public List<WizardColumnGroupInputDto> Groups { get; set; } = new();
|
public List<WizardColumnGroupInputDto> Groups { get; set; } = new();
|
||||||
|
public List<SubFormDto> SubForms { get; set; } = new();
|
||||||
|
public List<WidgetEditDto> Widgets { get; set; } = new();
|
||||||
|
public WorkflowDto Workflow { get; set; } = new();
|
||||||
|
public List<ListFormWorkflowCriteriaDto> WorkflowCriteria { get; set; } = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ public class ListFormWizardAppService(
|
||||||
IRepository<ListForm, Guid> repoListForm,
|
IRepository<ListForm, Guid> repoListForm,
|
||||||
IRepository<ListFormField, Guid> repoListFormField,
|
IRepository<ListFormField, Guid> repoListFormField,
|
||||||
IRepository<DataSource, Guid> repoDataSource,
|
IRepository<DataSource, Guid> repoDataSource,
|
||||||
|
IRepository<ListFormWorkflow, string> repoListFormWorkflow,
|
||||||
IRepository<LanguageKey, Guid> repoLangKey,
|
IRepository<LanguageKey, Guid> repoLangKey,
|
||||||
IRepository<LanguageText, Guid> repoLangText,
|
IRepository<LanguageText, Guid> repoLangText,
|
||||||
IRepository<PermissionDefinitionRecord, Guid> repoPerm,
|
IRepository<PermissionDefinitionRecord, Guid> repoPerm,
|
||||||
|
|
@ -42,6 +43,7 @@ public class ListFormWizardAppService(
|
||||||
private readonly IRepository<ListForm, Guid> repoListForm = repoListForm;
|
private readonly IRepository<ListForm, Guid> repoListForm = repoListForm;
|
||||||
private readonly IRepository<ListFormField, Guid> repoListFormField = repoListFormField;
|
private readonly IRepository<ListFormField, Guid> repoListFormField = repoListFormField;
|
||||||
private readonly IRepository<DataSource, Guid> repoDataSource = repoDataSource;
|
private readonly IRepository<DataSource, Guid> repoDataSource = repoDataSource;
|
||||||
|
private readonly IRepository<ListFormWorkflow, string> repoListFormWorkflow = repoListFormWorkflow;
|
||||||
private readonly IRepository<LanguageKey, Guid> repoLangKey = repoLangKey;
|
private readonly IRepository<LanguageKey, Guid> repoLangKey = repoLangKey;
|
||||||
private readonly IRepository<LanguageText, Guid> repoLangText = repoLangText;
|
private readonly IRepository<LanguageText, Guid> repoLangText = repoLangText;
|
||||||
private readonly IRepository<PermissionDefinitionRecord, Guid> repoPerm = repoPerm;
|
private readonly IRepository<PermissionDefinitionRecord, Guid> repoPerm = repoPerm;
|
||||||
|
|
@ -244,9 +246,17 @@ public class ListFormWizardAppService(
|
||||||
await repoListFormField.DeleteManyAsync(existingListFormFields, autoSave: true);
|
await repoListFormField.DeleteManyAsync(existingListFormFields, autoSave: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var existingWorkflowCriteria = await repoListFormWorkflow.GetListAsync(a => a.ListFormCode == input.ListFormCode);
|
||||||
|
if (existingWorkflowCriteria.Count > 0)
|
||||||
|
{
|
||||||
|
await repoListFormWorkflow.DeleteManyAsync(existingWorkflowCriteria, autoSave: true);
|
||||||
|
}
|
||||||
|
|
||||||
var tableColumns = await GetTableColumnNamesAsync(input.DataSourceCode, input.SelectCommandType, input.SelectCommand);
|
var tableColumns = await GetTableColumnNamesAsync(input.DataSourceCode, input.SelectCommandType, input.SelectCommand);
|
||||||
var isDeleted = tableColumns.Contains("IsDeleted");
|
var isDeleted = tableColumns.Contains("IsDeleted");
|
||||||
var isCreated = tableColumns.Contains("CreatorId");
|
var isCreated = tableColumns.Contains("CreatorId");
|
||||||
|
input.Workflow ??= new WorkflowDto();
|
||||||
|
input.Workflow.Criteria = input.WorkflowCriteria;
|
||||||
|
|
||||||
var listForm = await repoListForm.InsertAsync(new ListForm
|
var listForm = await repoListForm.InsertAsync(new ListForm
|
||||||
{
|
{
|
||||||
|
|
@ -254,7 +264,7 @@ public class ListFormWizardAppService(
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = WizardConsts.DefaultExportJson,
|
ExportJson = WizardConsts.DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = input.SubForms.Count > 0,
|
||||||
LayoutJson = WizardConsts.DefaultLayoutJson(input.DefaultLayout, input.Grid, input.Pivot, input.Tree, input.Chart, input.Gantt, input.Scheduler),
|
LayoutJson = WizardConsts.DefaultLayoutJson(input.DefaultLayout, input.Grid, input.Pivot, input.Tree, input.Chart, input.Gantt, input.Scheduler),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = input.ListFormCode,
|
ListFormCode = input.ListFormCode,
|
||||||
|
|
@ -284,6 +294,9 @@ public class ListFormWizardAppService(
|
||||||
PagerOptionJson = WizardConsts.DefaultPagerOptionJson,
|
PagerOptionJson = WizardConsts.DefaultPagerOptionJson,
|
||||||
EditingOptionJson = WizardConsts.DefaultEditingOptionJson(titleLangKey, 600, 500, input.AllowDeleting, input.AllowAdding, input.AllowUpdating, input.ConfirmDelete, false, input.AllowDetail),
|
EditingOptionJson = WizardConsts.DefaultEditingOptionJson(titleLangKey, 600, 500, input.AllowDeleting, input.AllowAdding, input.AllowUpdating, input.ConfirmDelete, false, input.AllowDetail),
|
||||||
EditingFormJson = editingFormDtos.Count > 0 ? JsonSerializer.Serialize(editingFormDtos) : null,
|
EditingFormJson = editingFormDtos.Count > 0 ? JsonSerializer.Serialize(editingFormDtos) : null,
|
||||||
|
SubFormsJson = input.SubForms.Count > 0 ? JsonSerializer.Serialize(input.SubForms) : null,
|
||||||
|
WidgetsJson = input.Widgets.Count > 0 ? JsonSerializer.Serialize(input.Widgets) : null,
|
||||||
|
WorkflowJson = HasWorkflow(input.Workflow, input.WorkflowCriteria) ? JsonSerializer.Serialize(input.Workflow) : null,
|
||||||
TreeOptionJson = (input.Tree || input.DefaultLayout == "tree") && !string.IsNullOrEmpty(input.TreeParentIdExpr)
|
TreeOptionJson = (input.Tree || input.DefaultLayout == "tree") && !string.IsNullOrEmpty(input.TreeParentIdExpr)
|
||||||
? JsonSerializer.Serialize(new TreeOptionDto
|
? JsonSerializer.Serialize(new TreeOptionDto
|
||||||
{
|
{
|
||||||
|
|
@ -329,6 +342,7 @@ public class ListFormWizardAppService(
|
||||||
Visible = item.DataField != input.KeyFieldName,
|
Visible = item.DataField != input.KeyFieldName,
|
||||||
IsActive = true,
|
IsActive = true,
|
||||||
AllowSearch = true,
|
AllowSearch = true,
|
||||||
|
Width = 0,
|
||||||
ListOrderNo = fieldOrder,
|
ListOrderNo = fieldOrder,
|
||||||
SourceDbType = item.DbSourceType,
|
SourceDbType = item.DbSourceType,
|
||||||
CultureName = PlatformConsts.DefaultLanguage,
|
CultureName = PlatformConsts.DefaultLanguage,
|
||||||
|
|
@ -343,6 +357,33 @@ public class ListFormWizardAppService(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var criteria in input.WorkflowCriteria)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(criteria.Id))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
await repoListFormWorkflow.InsertAsync(new ListFormWorkflow(criteria.Id)
|
||||||
|
{
|
||||||
|
ListFormCode = input.ListFormCode,
|
||||||
|
Kind = criteria.Kind,
|
||||||
|
Title = criteria.Title,
|
||||||
|
CompareColumn = criteria.CompareColumn,
|
||||||
|
CompareOperator = criteria.CompareOperator,
|
||||||
|
CompareValue = criteria.CompareValue,
|
||||||
|
Approver = criteria.Approver,
|
||||||
|
NextOnStart = criteria.NextOnStart,
|
||||||
|
NextOnTrue = criteria.NextOnTrue,
|
||||||
|
NextOnFalse = criteria.NextOnFalse,
|
||||||
|
NextOnApprove = criteria.NextOnApprove,
|
||||||
|
NextOnReject = criteria.NextOnReject,
|
||||||
|
PositionX = criteria.PositionX,
|
||||||
|
PositionY = criteria.PositionY,
|
||||||
|
CompareOutcomesJson = JsonSerializer.Serialize(criteria.CompareOutcomes ?? []),
|
||||||
|
}, autoSave: true);
|
||||||
|
}
|
||||||
|
|
||||||
// Clear Redis Cache
|
// Clear Redis Cache
|
||||||
await _languageTextAppService.ClearRedisCacheAsync();
|
await _languageTextAppService.ClearRedisCacheAsync();
|
||||||
|
|
||||||
|
|
@ -350,6 +391,17 @@ public class ListFormWizardAppService(
|
||||||
await SaveWizardSeedFileAsync(input, isDeleted, isCreated, inserted);
|
await SaveWizardSeedFileAsync(input, isDeleted, isCreated, inserted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool HasWorkflow(WorkflowDto workflow, List<ListFormWorkflowCriteriaDto> criteria)
|
||||||
|
{
|
||||||
|
return workflow != null && (
|
||||||
|
!string.IsNullOrWhiteSpace(workflow.ApprovalUserFieldName) ||
|
||||||
|
!string.IsNullOrWhiteSpace(workflow.ApprovalDateFieldName) ||
|
||||||
|
!string.IsNullOrWhiteSpace(workflow.ApprovalStatusFieldName) ||
|
||||||
|
!string.IsNullOrWhiteSpace(workflow.ApprovalDescriptionFieldName) ||
|
||||||
|
criteria.Count > 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Wizard konfigürasyonunu JSON dosyası olarak kaydeder.
|
/// Wizard konfigürasyonunu JSON dosyası olarak kaydeder.
|
||||||
/// Önce ContentRootPath'ten yukarı çıkarak Sozsoft.Platform.DbMigrator/Seeds/WizardData dizinini arar.
|
/// Önce ContentRootPath'ten yukarı çıkarak Sozsoft.Platform.DbMigrator/Seeds/WizardData dizinini arar.
|
||||||
|
|
|
||||||
|
|
@ -17803,12 +17803,6 @@
|
||||||
"key": "App.SqlQueryManager.NoIndexesDefined",
|
"key": "App.SqlQueryManager.NoIndexesDefined",
|
||||||
"en": "No indexes defined",
|
"en": "No indexes defined",
|
||||||
"tr": "Dizin tanımlanmamış"
|
"tr": "Dizin tanımlanmamış"
|
||||||
},
|
|
||||||
{
|
|
||||||
"resourceName": "Platform",
|
|
||||||
"key": "App.SqlQueryManager.NoIndexesDefined",
|
|
||||||
"en": "No indexes defined",
|
|
||||||
"tr": "Dizin tanımlanmamış"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"resourceName": "Platform",
|
"resourceName": "Platform",
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -183,7 +183,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson("tree"),
|
LayoutJson = DefaultLayoutJson("tree"),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -417,7 +417,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -635,7 +635,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -771,7 +771,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -1171,7 +1171,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -1370,7 +1370,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -1498,7 +1498,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -1695,7 +1695,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -1789,7 +1789,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -2046,7 +2046,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -2190,7 +2190,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -2383,7 +2383,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson("tree"),
|
LayoutJson = DefaultLayoutJson("tree"),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -2499,7 +2499,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson("tree"),
|
LayoutJson = DefaultLayoutJson("tree"),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -2643,7 +2643,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -3268,7 +3268,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = true,
|
IsSubForm = true,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -3548,7 +3548,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = true,
|
IsSubForm = true,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -3856,7 +3856,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -3961,7 +3961,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -4049,7 +4049,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -4444,7 +4444,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
|
||||||
|
|
@ -560,7 +560,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = true,
|
IsSubForm = true,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -1018,7 +1018,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -1178,7 +1178,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -1323,7 +1323,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -1436,7 +1436,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -1581,7 +1581,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -1671,7 +1671,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -1867,7 +1867,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -2003,7 +2003,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -2274,7 +2274,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = true,
|
IsSubForm = true,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -2477,7 +2477,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -2894,7 +2894,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = true,
|
IsSubForm = true,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -3040,7 +3040,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = true,
|
IsSubForm = true,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -3147,7 +3147,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -3694,7 +3694,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = true,
|
IsSubForm = true,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -3868,7 +3868,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -4005,7 +4005,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -4496,7 +4496,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -4586,7 +4586,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -4828,7 +4828,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -5029,7 +5029,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -5267,7 +5267,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -5442,7 +5442,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -5624,7 +5624,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -5713,7 +5713,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson("tree"),
|
LayoutJson = DefaultLayoutJson("tree"),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -6029,7 +6029,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -6258,7 +6258,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -6493,7 +6493,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -6627,7 +6627,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -7291,7 +7291,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = true,
|
IsSubForm = true,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -7459,7 +7459,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -7660,7 +7660,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
@ -8015,7 +8015,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = DefaultExportJson,
|
ExportJson = DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = false,
|
||||||
LayoutJson = DefaultLayoutJson(),
|
LayoutJson = DefaultLayoutJson(),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = listFormName,
|
ListFormCode = listFormName,
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,15 @@
|
||||||
"MultiTenancySide": 2,
|
"MultiTenancySide": 2,
|
||||||
"MenuGroup": "Erp|Kurs"
|
"MenuGroup": "Erp|Kurs"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Saas",
|
||||||
|
"Name": "AbpTenantManagement.Tenants.Note",
|
||||||
|
"ParentName": "AbpTenantManagement.Tenants",
|
||||||
|
"DisplayName": "Note",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 2,
|
||||||
|
"MenuGroup": "Erp|Kurs"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"GroupName": "App.Saas",
|
"GroupName": "App.Saas",
|
||||||
"Name": "App.Branches",
|
"Name": "App.Branches",
|
||||||
|
|
@ -1765,6 +1774,15 @@
|
||||||
"MultiTenancySide": 2,
|
"MultiTenancySide": 2,
|
||||||
"MenuGroup": "Erp|Kurs"
|
"MenuGroup": "Erp|Kurs"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Saas",
|
||||||
|
"Name": "App.Orders.SalesOrders.Note",
|
||||||
|
"ParentName": "App.Orders.SalesOrders",
|
||||||
|
"DisplayName": "Note",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 2,
|
||||||
|
"MenuGroup": "Erp|Kurs"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"GroupName": "App.Saas",
|
"GroupName": "App.Saas",
|
||||||
"Name": "App.Orders.SalesOrderItem",
|
"Name": "App.Orders.SalesOrderItem",
|
||||||
|
|
@ -3556,15 +3574,6 @@
|
||||||
"MultiTenancySide": 3,
|
"MultiTenancySide": 3,
|
||||||
"MenuGroup": "Erp|Kurs"
|
"MenuGroup": "Erp|Kurs"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"GroupName": "App.Administration",
|
|
||||||
"Name": "App.Intranet.Events.EventType.Note",
|
|
||||||
"ParentName": "App.Intranet.Events.EventType",
|
|
||||||
"DisplayName": "Note",
|
|
||||||
"IsEnabled": true,
|
|
||||||
"MultiTenancySide": 3,
|
|
||||||
"MenuGroup": "Erp|Kurs"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"GroupName": "App.Administration",
|
"GroupName": "App.Administration",
|
||||||
"Name": "App.Intranet.Events.EventCategory",
|
"Name": "App.Intranet.Events.EventCategory",
|
||||||
|
|
@ -3619,15 +3628,6 @@
|
||||||
"MultiTenancySide": 3,
|
"MultiTenancySide": 3,
|
||||||
"MenuGroup": "Erp|Kurs"
|
"MenuGroup": "Erp|Kurs"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"GroupName": "App.Administration",
|
|
||||||
"Name": "App.Intranet.Events.EventCategory.Note",
|
|
||||||
"ParentName": "App.Intranet.Events.EventCategory",
|
|
||||||
"DisplayName": "Note",
|
|
||||||
"IsEnabled": true,
|
|
||||||
"MultiTenancySide": 3,
|
|
||||||
"MenuGroup": "Erp|Kurs"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"GroupName": "App.Administration",
|
"GroupName": "App.Administration",
|
||||||
"Name": "App.Intranet.Events.Event",
|
"Name": "App.Intranet.Events.Event",
|
||||||
|
|
@ -3754,15 +3754,6 @@
|
||||||
"MultiTenancySide": 3,
|
"MultiTenancySide": 3,
|
||||||
"MenuGroup": "Erp|Kurs"
|
"MenuGroup": "Erp|Kurs"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"GroupName": "App.Administration",
|
|
||||||
"Name": "App.Intranet.Events.EventLike.Note",
|
|
||||||
"ParentName": "App.Intranet.Events.EventLike",
|
|
||||||
"DisplayName": "Note",
|
|
||||||
"IsEnabled": true,
|
|
||||||
"MultiTenancySide": 3,
|
|
||||||
"MenuGroup": "Erp|Kurs"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"GroupName": "App.Administration",
|
"GroupName": "App.Administration",
|
||||||
"Name": "App.Intranet.Announcement",
|
"Name": "App.Intranet.Announcement",
|
||||||
|
|
@ -3817,15 +3808,6 @@
|
||||||
"MultiTenancySide": 3,
|
"MultiTenancySide": 3,
|
||||||
"MenuGroup": "Erp|Kurs"
|
"MenuGroup": "Erp|Kurs"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"GroupName": "App.Administration",
|
|
||||||
"Name": "App.Intranet.Announcement.Note",
|
|
||||||
"ParentName": "App.Intranet.Announcement",
|
|
||||||
"DisplayName": "Note",
|
|
||||||
"IsEnabled": true,
|
|
||||||
"MultiTenancySide": 3,
|
|
||||||
"MenuGroup": "Erp|Kurs"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"GroupName": "App.Administration",
|
"GroupName": "App.Administration",
|
||||||
"Name": "App.Intranet.Announcement.Widget",
|
"Name": "App.Intranet.Announcement.Widget",
|
||||||
|
|
@ -3961,15 +3943,6 @@
|
||||||
"MultiTenancySide": 3,
|
"MultiTenancySide": 3,
|
||||||
"MenuGroup": "Erp|Kurs"
|
"MenuGroup": "Erp|Kurs"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"GroupName": "App.Administration",
|
|
||||||
"Name": "App.Intranet.SocialComment.Note",
|
|
||||||
"ParentName": "App.Intranet.SocialComment",
|
|
||||||
"DisplayName": "Note",
|
|
||||||
"IsEnabled": true,
|
|
||||||
"MultiTenancySide": 3,
|
|
||||||
"MenuGroup": "Erp|Kurs"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"GroupName": "App.Administration",
|
"GroupName": "App.Administration",
|
||||||
"Name": "App.Intranet.Survey",
|
"Name": "App.Intranet.Survey",
|
||||||
|
|
@ -4159,15 +4132,6 @@
|
||||||
"MultiTenancySide": 3,
|
"MultiTenancySide": 3,
|
||||||
"MenuGroup": "Erp"
|
"MenuGroup": "Erp"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"GroupName": "App.Administration",
|
|
||||||
"Name": "App.Intranet.SurveyQuestionOption.Note",
|
|
||||||
"ParentName": "App.Intranet.SurveyQuestionOption",
|
|
||||||
"DisplayName": "Note",
|
|
||||||
"IsEnabled": true,
|
|
||||||
"MultiTenancySide": 3,
|
|
||||||
"MenuGroup": "Erp"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"GroupName": "App.Administration",
|
"GroupName": "App.Administration",
|
||||||
"Name": "App.Intranet.SurveyResponse",
|
"Name": "App.Intranet.SurveyResponse",
|
||||||
|
|
@ -4285,15 +4249,6 @@
|
||||||
"MultiTenancySide": 3,
|
"MultiTenancySide": 3,
|
||||||
"MenuGroup": "Erp"
|
"MenuGroup": "Erp"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"GroupName": "App.Administration",
|
|
||||||
"Name": "App.Intranet.SurveyAnswer.Note",
|
|
||||||
"ParentName": "App.Intranet.SurveyAnswer",
|
|
||||||
"DisplayName": "Note",
|
|
||||||
"IsEnabled": true,
|
|
||||||
"MultiTenancySide": 3,
|
|
||||||
"MenuGroup": "Erp"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"GroupName": "App.Administration",
|
"GroupName": "App.Administration",
|
||||||
"Name": "App.Videoroom",
|
"Name": "App.Videoroom",
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,11 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
||||||
var input = seedFile.Wizard;
|
var input = seedFile.Wizard;
|
||||||
var isDeleted = seedFile.IsDeletedField;
|
var isDeleted = seedFile.IsDeletedField;
|
||||||
var isCreated = seedFile.IsCreatedField;
|
var isCreated = seedFile.IsCreatedField;
|
||||||
|
input.SubForms ??= new List<SubFormDto>();
|
||||||
|
input.Widgets ??= new List<WidgetEditDto>();
|
||||||
|
input.Workflow ??= new WorkflowDto();
|
||||||
|
input.WorkflowCriteria ??= new List<ListFormWorkflowCriteriaDto>();
|
||||||
|
input.Workflow.Criteria = input.WorkflowCriteria;
|
||||||
|
|
||||||
var wizardName = input.WizardName.Trim();
|
var wizardName = input.WizardName.Trim();
|
||||||
var titleLangKey = WizardConsts.WizardKeyTitle(wizardName);
|
var titleLangKey = WizardConsts.WizardKeyTitle(wizardName);
|
||||||
|
|
@ -306,7 +311,7 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
||||||
PageSize = 10,
|
PageSize = 10,
|
||||||
ExportJson = WizardConsts.DefaultExportJson,
|
ExportJson = WizardConsts.DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = true,
|
ShowNote = input.SubForms.Count > 0,
|
||||||
LayoutJson = WizardConsts.DefaultLayoutJson(input.DefaultLayout, input.Grid, input.Pivot, input.Tree, input.Chart, input.Gantt, input.Scheduler),
|
LayoutJson = WizardConsts.DefaultLayoutJson(input.DefaultLayout, input.Grid, input.Pivot, input.Tree, input.Chart, input.Gantt, input.Scheduler),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = input.ListFormCode,
|
ListFormCode = input.ListFormCode,
|
||||||
|
|
@ -340,6 +345,9 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
||||||
PagerOptionJson = WizardConsts.DefaultPagerOptionJson,
|
PagerOptionJson = WizardConsts.DefaultPagerOptionJson,
|
||||||
EditingOptionJson = WizardConsts.DefaultEditingOptionJson(titleLangKey, 600, 500, input.AllowDeleting, input.AllowAdding, input.AllowUpdating, input.ConfirmDelete, false, input.AllowDetail),
|
EditingOptionJson = WizardConsts.DefaultEditingOptionJson(titleLangKey, 600, 500, input.AllowDeleting, input.AllowAdding, input.AllowUpdating, input.ConfirmDelete, false, input.AllowDetail),
|
||||||
EditingFormJson = editingFormDtos.Count > 0 ? JsonSerializer.Serialize(editingFormDtos) : null,
|
EditingFormJson = editingFormDtos.Count > 0 ? JsonSerializer.Serialize(editingFormDtos) : null,
|
||||||
|
SubFormsJson = input.SubForms.Count > 0 ? JsonSerializer.Serialize(input.SubForms) : null,
|
||||||
|
WidgetsJson = input.Widgets.Count > 0 ? JsonSerializer.Serialize(input.Widgets) : null,
|
||||||
|
WorkflowJson = HasWorkflow(input.Workflow, input.WorkflowCriteria) ? JsonSerializer.Serialize(input.Workflow) : null,
|
||||||
}, autoSave: true);
|
}, autoSave: true);
|
||||||
|
|
||||||
// ListFormFields
|
// ListFormFields
|
||||||
|
|
@ -375,6 +383,17 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool HasWorkflow(WorkflowDto workflow, List<ListFormWorkflowCriteriaDto> criteria)
|
||||||
|
{
|
||||||
|
return workflow != null && (
|
||||||
|
!string.IsNullOrWhiteSpace(workflow.ApprovalUserFieldName) ||
|
||||||
|
!string.IsNullOrWhiteSpace(workflow.ApprovalDateFieldName) ||
|
||||||
|
!string.IsNullOrWhiteSpace(workflow.ApprovalStatusFieldName) ||
|
||||||
|
!string.IsNullOrWhiteSpace(workflow.ApprovalDescriptionFieldName) ||
|
||||||
|
(criteria?.Count ?? 0) > 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private async Task CreateLangKeyAsync(string key, string textEn, string textTr)
|
private async Task CreateLangKeyAsync(string key, string textEn, string textTr)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(key)) return;
|
if (string.IsNullOrWhiteSpace(key)) return;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
import { SelectCommandTypeEnum } from "@/proxy/form/models"
|
import { SelectCommandTypeEnum } from '@/proxy/form/models'
|
||||||
import { ListViewLayoutType } from "@/views/admin/listForm/edit/types"
|
import {
|
||||||
|
ListFormWorkflowCriteriaDto,
|
||||||
|
SubFormDto,
|
||||||
|
WidgetEditDto,
|
||||||
|
WorkflowDto,
|
||||||
|
} from '@/proxy/form/models'
|
||||||
|
import { ListViewLayoutType } from '@/views/admin/listForm/edit/types'
|
||||||
|
|
||||||
export interface ListFormWizardColumnItemDto {
|
export interface ListFormWizardColumnItemDto {
|
||||||
dataField: string
|
dataField: string
|
||||||
|
|
@ -76,6 +82,10 @@ export interface ListFormWizardDto {
|
||||||
schedulerEndDateExpr?: string
|
schedulerEndDateExpr?: string
|
||||||
|
|
||||||
groups?: ListFormWizardColumnGroupDto[]
|
groups?: ListFormWizardColumnGroupDto[]
|
||||||
|
subForms?: SubFormDto[]
|
||||||
|
widgets?: WidgetEditDto[]
|
||||||
|
workflow?: WorkflowDto
|
||||||
|
workflowCriteria?: ListFormWorkflowCriteriaDto[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WizardFileInfoDto {
|
export interface WizardFileInfoDto {
|
||||||
|
|
@ -128,4 +138,4 @@ export interface WizardSeedFileDto {
|
||||||
isDeletedField: boolean
|
isDeletedField: boolean
|
||||||
isCreatedField: boolean
|
isCreatedField: boolean
|
||||||
insertedRecords: WizardInsertedRecordsDto
|
insertedRecords: WizardInsertedRecordsDto
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ const schema = object().shape({
|
||||||
d: string(),
|
d: string(),
|
||||||
e: string(),
|
e: string(),
|
||||||
i: string(),
|
i: string(),
|
||||||
a: string(),
|
n: string(),
|
||||||
})
|
})
|
||||||
|
|
||||||
function FormTabPermissions(props: FormEditProps) {
|
function FormTabPermissions(props: FormEditProps) {
|
||||||
|
|
@ -210,31 +210,34 @@ function FormTabPermissions(props: FormEditProps) {
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<FormItem
|
|
||||||
label={translate('::ListForms.ListFormEdit.PermissionsNote')}
|
{listFormValues.showNote && (
|
||||||
invalid={errors.permissionDto?.n && touched.permissionDto?.n}
|
<FormItem
|
||||||
errorMessage={errors.permissionDto?.n}
|
label={translate('::ListForms.ListFormEdit.PermissionsNote')}
|
||||||
>
|
invalid={errors.permissionDto?.n && touched.permissionDto?.n}
|
||||||
<Field
|
errorMessage={errors.permissionDto?.n}
|
||||||
type="text"
|
|
||||||
autoComplete="off"
|
|
||||||
name="permissionDto.n"
|
|
||||||
placeholder={translate('::ListForms.ListFormEdit.PermissionsNote')}
|
|
||||||
>
|
>
|
||||||
{({ field, form }: FieldProps<SelectBoxOption>) => (
|
<Field
|
||||||
<Select
|
type="text"
|
||||||
field={field}
|
autoComplete="off"
|
||||||
form={form}
|
name="permissionDto.n"
|
||||||
isClearable={true}
|
placeholder={translate('::ListForms.ListFormEdit.PermissionsNote')}
|
||||||
options={permissions}
|
>
|
||||||
value={permissions?.filter(
|
{({ field, form }: FieldProps<SelectBoxOption>) => (
|
||||||
(option) => option.value === values.permissionDto.n,
|
<Select
|
||||||
)}
|
field={field}
|
||||||
onChange={(option) => form.setFieldValue(field.name, option?.value)}
|
form={form}
|
||||||
/>
|
isClearable={true}
|
||||||
)}
|
options={permissions}
|
||||||
</Field>
|
value={permissions?.filter(
|
||||||
</FormItem>
|
(option) => option.value === values.permissionDto.n,
|
||||||
|
)}
|
||||||
|
onChange={(option) => form.setFieldValue(field.name, option?.value)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
|
||||||
<Button block variant="solid" loading={isSubmitting} type="submit">
|
<Button block variant="solid" loading={isSubmitting} type="submit">
|
||||||
{isSubmitting ? translate('::SavingWithThreeDot') : translate('::Save')}
|
{isSubmitting ? translate('::SavingWithThreeDot') : translate('::Save')}
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ function JsonRowOpDialogSubForm({
|
||||||
|
|
||||||
const childFieldOptions = childFields.map((field) => ({
|
const childFieldOptions = childFields.map((field) => ({
|
||||||
value: field.fieldName,
|
value: field.fieldName,
|
||||||
label: field.fieldName,
|
label: `${field.fieldName} (${field.dataType})`,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const loadChildFields = async (listFormCode?: string) => {
|
const loadChildFields = async (listFormCode?: string) => {
|
||||||
|
|
@ -159,329 +159,331 @@ function JsonRowOpDialogSubForm({
|
||||||
onRequestClose={handleClose}
|
onRequestClose={handleClose}
|
||||||
>
|
>
|
||||||
{(data.operation === 'create' || data.operation === 'update') && (
|
{(data.operation === 'create' || data.operation === 'update') && (
|
||||||
<Formik
|
<Formik
|
||||||
initialValues={
|
initialValues={
|
||||||
data.subFormValues ?? {
|
data.subFormValues ?? {
|
||||||
tabTitle: '',
|
tabTitle: '',
|
||||||
tabType: 'List',
|
tabType: 'List',
|
||||||
code: '',
|
code: '',
|
||||||
isRefresh: false,
|
isRefresh: false,
|
||||||
relation: [],
|
relation: [],
|
||||||
}
|
|
||||||
}
|
}
|
||||||
validationSchema={schema}
|
}
|
||||||
onSubmit={async (values, { setSubmitting }) => {
|
validationSchema={schema}
|
||||||
setSubmitting(true)
|
onSubmit={async (values, { setSubmitting }) => {
|
||||||
try {
|
setSubmitting(true)
|
||||||
const input: ListFormJsonRowDto = {
|
try {
|
||||||
index: data.index,
|
const input: ListFormJsonRowDto = {
|
||||||
fieldName: data.tabName,
|
index: data.index,
|
||||||
itemSubForm: values as SubFormDto,
|
fieldName: data.tabName,
|
||||||
}
|
itemSubForm: values as SubFormDto,
|
||||||
|
|
||||||
if (data.index === -1) {
|
|
||||||
await postListFormJsonRow(data.id, input)
|
|
||||||
} else {
|
|
||||||
await putListFormJsonRow(data.id, input)
|
|
||||||
}
|
|
||||||
toast.push(
|
|
||||||
<Notification type="success">
|
|
||||||
{data.index === -1 ? 'Kayıt eklendi' : 'Kayıt güncellendi'}
|
|
||||||
</Notification>,
|
|
||||||
{ placement: 'top-end' },
|
|
||||||
)
|
|
||||||
handleClose()
|
|
||||||
} catch (error: any) {
|
|
||||||
toast.push(
|
|
||||||
<Notification type="danger">
|
|
||||||
Hata
|
|
||||||
<code>{error}</code>
|
|
||||||
</Notification>,
|
|
||||||
{ placement: 'top-end' },
|
|
||||||
)
|
|
||||||
} finally {
|
|
||||||
setSubmitting(false)
|
|
||||||
}
|
}
|
||||||
}}
|
|
||||||
>
|
|
||||||
{({ touched, errors, values, isSubmitting }) => (
|
|
||||||
<Form className="flex flex-col h-full">
|
|
||||||
<Dialog.Body className="flex flex-col gap-2 overflow-hidden">
|
|
||||||
<h5 className="flex-shrink-0">{data.index === -1 ? 'Add' : 'Update'}</h5>
|
|
||||||
<div className="flex-1 overflow-y-auto p-2">
|
|
||||||
<div className="grid grid-cols-4 gap-4">
|
|
||||||
<FormItem
|
|
||||||
label="Tab Title"
|
|
||||||
invalid={errors.tabTitle && touched.tabTitle}
|
|
||||||
errorMessage={errors.tabTitle}
|
|
||||||
>
|
|
||||||
<Field
|
|
||||||
autoFocus={true}
|
|
||||||
type="text"
|
|
||||||
autoComplete="off"
|
|
||||||
name="tabTitle"
|
|
||||||
placeholder="Title"
|
|
||||||
component={Input}
|
|
||||||
/>
|
|
||||||
</FormItem>
|
|
||||||
|
|
||||||
<FormItem
|
if (data.index === -1) {
|
||||||
label="Code"
|
await postListFormJsonRow(data.id, input)
|
||||||
invalid={errors.code && touched.code}
|
} else {
|
||||||
errorMessage={errors.code}
|
await putListFormJsonRow(data.id, input)
|
||||||
>
|
}
|
||||||
<Field type="text" autoComplete="off" name="code" placeholder="Code">
|
toast.push(
|
||||||
{({ field, form }: FieldProps<SelectBoxOption>) => (
|
<Notification type="success">
|
||||||
<Select
|
{data.index === -1 ? 'Kayıt eklendi' : 'Kayıt güncellendi'}
|
||||||
field={field}
|
</Notification>,
|
||||||
form={form}
|
{ placement: 'top-end' },
|
||||||
isClearable={true}
|
)
|
||||||
isLoading={isLoadingListForms}
|
handleClose()
|
||||||
options={listFormOptions}
|
} catch (error: any) {
|
||||||
value={listFormOptions.find(
|
toast.push(
|
||||||
(option) => option.value === values.code,
|
<Notification type="danger">
|
||||||
)}
|
Hata
|
||||||
onChange={(option) => {
|
<code>{error}</code>
|
||||||
form.setFieldValue(field.name, option?.value ?? '')
|
</Notification>,
|
||||||
form.setFieldValue('relation', [])
|
{ placement: 'top-end' },
|
||||||
loadChildFields(option?.value)
|
)
|
||||||
|
} finally {
|
||||||
|
setSubmitting(false)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{({ touched, errors, values, isSubmitting }) => (
|
||||||
|
<Form className="flex flex-col h-full">
|
||||||
|
<Dialog.Body className="flex flex-col gap-2 overflow-hidden">
|
||||||
|
<h5 className="flex-shrink-0">{data.index === -1 ? 'Add' : 'Update'}</h5>
|
||||||
|
<div className="flex-1 overflow-y-auto p-2">
|
||||||
|
<div className="grid grid-cols-4 gap-4">
|
||||||
|
<FormItem
|
||||||
|
label="Tab Title"
|
||||||
|
invalid={errors.tabTitle && touched.tabTitle}
|
||||||
|
errorMessage={errors.tabTitle}
|
||||||
|
>
|
||||||
|
<Field
|
||||||
|
autoFocus={true}
|
||||||
|
type="text"
|
||||||
|
autoComplete="off"
|
||||||
|
name="tabTitle"
|
||||||
|
placeholder="Title"
|
||||||
|
component={Input}
|
||||||
|
/>
|
||||||
|
</FormItem>
|
||||||
|
|
||||||
|
<FormItem
|
||||||
|
label="Code"
|
||||||
|
invalid={errors.code && touched.code}
|
||||||
|
errorMessage={errors.code}
|
||||||
|
>
|
||||||
|
<Field type="text" autoComplete="off" name="code" placeholder="Code">
|
||||||
|
{({ field, form }: FieldProps<SelectBoxOption>) => (
|
||||||
|
<Select
|
||||||
|
field={field}
|
||||||
|
form={form}
|
||||||
|
isClearable={true}
|
||||||
|
isLoading={isLoadingListForms}
|
||||||
|
options={listFormOptions}
|
||||||
|
value={listFormOptions.find((option) => option.value === values.code)}
|
||||||
|
onChange={(option) => {
|
||||||
|
form.setFieldValue(field.name, option?.value ?? '')
|
||||||
|
form.setFieldValue('relation', [])
|
||||||
|
loadChildFields(option?.value)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
</FormItem>
|
||||||
|
|
||||||
|
<FormItem
|
||||||
|
label="Tab Type"
|
||||||
|
invalid={errors.tabType && touched.tabType}
|
||||||
|
errorMessage={errors.tabType}
|
||||||
|
>
|
||||||
|
<Field type="text" autoComplete="off" name="tabType" placeholder="Tab Type">
|
||||||
|
{({ field, form }: FieldProps<SelectBoxOption>) => (
|
||||||
|
<Select
|
||||||
|
field={field}
|
||||||
|
form={form}
|
||||||
|
isClearable={true}
|
||||||
|
options={tabTypeOptions}
|
||||||
|
value={tabTypeOptions?.filter(
|
||||||
|
(option: any) => option.value === values.tabType,
|
||||||
|
)}
|
||||||
|
onChange={(option) => form.setFieldValue(field.name, option?.value)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
</FormItem>
|
||||||
|
|
||||||
|
<FormItem
|
||||||
|
label="isRefresh"
|
||||||
|
invalid={errors.isRefresh && touched.isRefresh}
|
||||||
|
errorMessage={errors.isRefresh}
|
||||||
|
>
|
||||||
|
<Field name="isRefresh" component={Checkbox} />
|
||||||
|
</FormItem>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<FormItem label="Relations">
|
||||||
|
<FieldArray
|
||||||
|
name="relation"
|
||||||
|
render={(arrayHelpers) => (
|
||||||
|
<div>
|
||||||
|
<div className="flex m-1 font-bold text-center">
|
||||||
|
<div className="w-4/12">Parent Field Name</div>
|
||||||
|
<div className="w-4/12">Child Field Name</div>
|
||||||
|
<div className="w-4/12">Db Type</div>
|
||||||
|
</div>
|
||||||
|
{values.relation && values.relation.length > 0 ? (
|
||||||
|
values.relation.map((item: SubFormRelationDto, index: any) => (
|
||||||
|
<div key={index} className="flex m-1">
|
||||||
|
<div className="w-4/12 ml-2">
|
||||||
|
<Field
|
||||||
|
type="text"
|
||||||
|
autoComplete="off"
|
||||||
|
name={`relation.${index}.parentFieldName`}
|
||||||
|
placeholder={translate(
|
||||||
|
'::ListForms.ListFormEdit.SubFormsRelation.ParentFieldName',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{({ field, form }: FieldProps<SelectBoxOption>) => (
|
||||||
|
<Select
|
||||||
|
field={field}
|
||||||
|
form={form}
|
||||||
|
isClearable={true}
|
||||||
|
options={parentFieldOptions}
|
||||||
|
value={parentFieldOptions.find(
|
||||||
|
(option) => option.value === item?.parentFieldName,
|
||||||
|
)}
|
||||||
|
onChange={(option) => {
|
||||||
|
const selectedField = parentFields.find(
|
||||||
|
(parentField) =>
|
||||||
|
parentField.fieldName === option?.value,
|
||||||
|
)
|
||||||
|
|
||||||
|
form.setFieldValue(field.name, option?.value ?? '')
|
||||||
|
form.setFieldValue(
|
||||||
|
`relation.${index}.dbType`,
|
||||||
|
selectedField?.sourceDbType ?? '',
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="w-4/12 ml-2">
|
||||||
|
<Field
|
||||||
|
type="text"
|
||||||
|
autoComplete="off"
|
||||||
|
name={`relation.${index}.childFieldName`}
|
||||||
|
placeholder={translate(
|
||||||
|
'::ListForms.ListFormEdit.SubFormsRelation.ChildFieldName',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{({ field, form }: FieldProps<SelectBoxOption>) => (
|
||||||
|
<Select
|
||||||
|
field={field}
|
||||||
|
form={form}
|
||||||
|
isClearable={true}
|
||||||
|
isLoading={isLoadingChildFields}
|
||||||
|
options={childFieldOptions}
|
||||||
|
value={childFieldOptions.find(
|
||||||
|
(option) => option.value === item?.childFieldName,
|
||||||
|
)}
|
||||||
|
onChange={(option) =>
|
||||||
|
form.setFieldValue(field.name, option?.value ?? '')
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="w-3/12 ml-2">
|
||||||
|
<Field
|
||||||
|
type="text"
|
||||||
|
autoComplete="off"
|
||||||
|
name={`relation.${index}.dbType`}
|
||||||
|
placeholder={translate('::ListForms.ListFormEdit.FieldDbType')}
|
||||||
|
>
|
||||||
|
{({ field, form }: FieldProps<any>) => (
|
||||||
|
<Select
|
||||||
|
field={field}
|
||||||
|
form={form}
|
||||||
|
isClearable={true}
|
||||||
|
isDisabled={true}
|
||||||
|
options={dbSourceTypeOptions}
|
||||||
|
value={dbSourceTypeOptions?.find(
|
||||||
|
(option: any) => option.value === item?.dbType,
|
||||||
|
)}
|
||||||
|
onChange={(option) =>
|
||||||
|
form.setFieldValue(field.name, option?.value)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="w-1/12 ml-2">
|
||||||
|
<Button
|
||||||
|
shape="circle"
|
||||||
|
variant="plain"
|
||||||
|
type="button"
|
||||||
|
size="sm"
|
||||||
|
title="Add"
|
||||||
|
icon={<FaCalendarMinus />}
|
||||||
|
onClick={() => {
|
||||||
|
arrayHelpers.remove(index)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
shape="circle"
|
||||||
|
variant="plain"
|
||||||
|
type="button"
|
||||||
|
size="sm"
|
||||||
|
title="Add"
|
||||||
|
icon={<FaCalendarPlus />}
|
||||||
|
onClick={() => {
|
||||||
|
arrayHelpers.insert(index + 1, {
|
||||||
|
parentFieldName: '',
|
||||||
|
childFieldName: '',
|
||||||
|
dbType: '',
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
shape="circle"
|
||||||
|
variant="plain"
|
||||||
|
type="button"
|
||||||
|
size="sm"
|
||||||
|
title="Add"
|
||||||
|
icon={<FaCalendarPlus />}
|
||||||
|
onClick={() => {
|
||||||
|
arrayHelpers.push({
|
||||||
|
parentFieldName: '',
|
||||||
|
childFieldName: '',
|
||||||
|
dbType: '',
|
||||||
|
})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</div>
|
||||||
</FormItem>
|
)}
|
||||||
|
/>
|
||||||
<FormItem
|
</FormItem>
|
||||||
label="Tab Type"
|
</div>
|
||||||
invalid={errors.tabType && touched.tabType}
|
</Dialog.Body>
|
||||||
errorMessage={errors.tabType}
|
<Dialog.Footer className="flex justify-end gap-2 border-t pt-3 mt-1">
|
||||||
>
|
<Button variant="plain" onClick={handleClose}>
|
||||||
<Field type="text" autoComplete="off" name="tabType" placeholder="Tab Type">
|
Cancel
|
||||||
{({ field, form }: FieldProps<SelectBoxOption>) => (
|
</Button>
|
||||||
<Select
|
<Button variant="solid" loading={isSubmitting} type="submit">
|
||||||
field={field}
|
{isSubmitting ? translate('::SavingWithThreeDot') : translate('::Save')}
|
||||||
form={form}
|
</Button>
|
||||||
isClearable={true}
|
</Dialog.Footer>
|
||||||
options={tabTypeOptions}
|
</Form>
|
||||||
value={tabTypeOptions?.filter(
|
)}
|
||||||
(option: any) => option.value === values.tabType,
|
</Formik>
|
||||||
)}
|
|
||||||
onChange={(option) => form.setFieldValue(field.name, option?.value)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Field>
|
|
||||||
</FormItem>
|
|
||||||
|
|
||||||
<FormItem
|
|
||||||
label="isRefresh"
|
|
||||||
invalid={errors.isRefresh && touched.isRefresh}
|
|
||||||
errorMessage={errors.isRefresh}
|
|
||||||
>
|
|
||||||
<Field name="isRefresh" component={Checkbox} />
|
|
||||||
</FormItem>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<FormItem label="Relations">
|
|
||||||
<FieldArray
|
|
||||||
name="relation"
|
|
||||||
render={(arrayHelpers) => (
|
|
||||||
<div>
|
|
||||||
<div className="flex m-1 font-bold text-center">
|
|
||||||
<div className="w-4/12">Parent Field Name</div>
|
|
||||||
<div className="w-4/12">Child Field Name</div>
|
|
||||||
<div className="w-4/12">Db Type</div>
|
|
||||||
</div>
|
|
||||||
{values.relation && values.relation.length > 0 ? (
|
|
||||||
values.relation.map((item: SubFormRelationDto, index: any) => (
|
|
||||||
<div key={index} className="flex m-1">
|
|
||||||
<div className="w-4/12 ml-2">
|
|
||||||
<Field
|
|
||||||
type="text"
|
|
||||||
autoComplete="off"
|
|
||||||
name={`relation.${index}.parentFieldName`}
|
|
||||||
placeholder={translate('::ListForms.ListFormEdit.SubFormsRelation.ParentFieldName')}
|
|
||||||
>
|
|
||||||
{({ field, form }: FieldProps<SelectBoxOption>) => (
|
|
||||||
<Select
|
|
||||||
field={field}
|
|
||||||
form={form}
|
|
||||||
isClearable={true}
|
|
||||||
options={parentFieldOptions}
|
|
||||||
value={parentFieldOptions.find(
|
|
||||||
(option) => option.value === item?.parentFieldName,
|
|
||||||
)}
|
|
||||||
onChange={(option) => {
|
|
||||||
const selectedField = parentFields.find(
|
|
||||||
(parentField) => parentField.fieldName === option?.value,
|
|
||||||
)
|
|
||||||
|
|
||||||
form.setFieldValue(field.name, option?.value ?? '')
|
|
||||||
form.setFieldValue(
|
|
||||||
`relation.${index}.dbType`,
|
|
||||||
selectedField?.sourceDbType ?? '',
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Field>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="w-4/12 ml-2">
|
|
||||||
<Field
|
|
||||||
type="text"
|
|
||||||
autoComplete="off"
|
|
||||||
name={`relation.${index}.childFieldName`}
|
|
||||||
placeholder={translate('::ListForms.ListFormEdit.SubFormsRelation.ChildFieldName')}
|
|
||||||
>
|
|
||||||
{({ field, form }: FieldProps<SelectBoxOption>) => (
|
|
||||||
<Select
|
|
||||||
field={field}
|
|
||||||
form={form}
|
|
||||||
isClearable={true}
|
|
||||||
isLoading={isLoadingChildFields}
|
|
||||||
options={childFieldOptions}
|
|
||||||
value={childFieldOptions.find(
|
|
||||||
(option) => option.value === item?.childFieldName,
|
|
||||||
)}
|
|
||||||
onChange={(option) =>
|
|
||||||
form.setFieldValue(field.name, option?.value ?? '')
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Field>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="w-3/12 ml-2">
|
|
||||||
<Field
|
|
||||||
type="text"
|
|
||||||
autoComplete="off"
|
|
||||||
name={`relation.${index}.dbType`}
|
|
||||||
placeholder={translate('::ListForms.ListFormEdit.FieldDbType')}
|
|
||||||
>
|
|
||||||
{({ field, form }: FieldProps<any>) => (
|
|
||||||
<Select
|
|
||||||
field={field}
|
|
||||||
form={form}
|
|
||||||
isClearable={true}
|
|
||||||
isDisabled={true}
|
|
||||||
options={dbSourceTypeOptions}
|
|
||||||
value={dbSourceTypeOptions?.find(
|
|
||||||
(option: any) =>
|
|
||||||
option.value === item?.dbType,
|
|
||||||
)}
|
|
||||||
onChange={(option) =>
|
|
||||||
form.setFieldValue(field.name, option?.value)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Field>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="w-1/12 ml-2">
|
|
||||||
<Button
|
|
||||||
shape="circle"
|
|
||||||
variant="plain"
|
|
||||||
type="button"
|
|
||||||
size="sm"
|
|
||||||
title="Add"
|
|
||||||
icon={<FaCalendarMinus />}
|
|
||||||
onClick={() => {
|
|
||||||
arrayHelpers.remove(index)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
shape="circle"
|
|
||||||
variant="plain"
|
|
||||||
type="button"
|
|
||||||
size="sm"
|
|
||||||
title="Add"
|
|
||||||
icon={<FaCalendarPlus />}
|
|
||||||
onClick={() => {
|
|
||||||
arrayHelpers.insert(index + 1, {
|
|
||||||
parentFieldName: '',
|
|
||||||
childFieldName: '',
|
|
||||||
dbType: '',
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))
|
|
||||||
) : (
|
|
||||||
<Button
|
|
||||||
shape="circle"
|
|
||||||
variant="plain"
|
|
||||||
type="button"
|
|
||||||
size="sm"
|
|
||||||
title="Add"
|
|
||||||
icon={<FaCalendarPlus />}
|
|
||||||
onClick={() => {
|
|
||||||
arrayHelpers.push({
|
|
||||||
parentFieldName: '',
|
|
||||||
childFieldName: '',
|
|
||||||
dbType: '',
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</FormItem>
|
|
||||||
</div>
|
|
||||||
</Dialog.Body>
|
|
||||||
<Dialog.Footer className="flex justify-end gap-2 border-t pt-3 mt-1">
|
|
||||||
<Button variant="plain" onClick={handleClose}>
|
|
||||||
Cancel
|
|
||||||
</Button>
|
|
||||||
<Button variant="solid" loading={isSubmitting} type="submit">
|
|
||||||
{isSubmitting ? translate('::SavingWithThreeDot') : translate('::Save')}
|
|
||||||
</Button>
|
|
||||||
</Dialog.Footer>
|
|
||||||
</Form>
|
|
||||||
)}
|
|
||||||
</Formik>
|
|
||||||
)}
|
)}
|
||||||
{data.operation === 'delete' && (
|
{data.operation === 'delete' && (
|
||||||
<Formik
|
<Formik
|
||||||
initialValues={data}
|
initialValues={data}
|
||||||
onSubmit={async (values, { setSubmitting }) => {
|
onSubmit={async (values, { setSubmitting }) => {
|
||||||
setSubmitting(true)
|
setSubmitting(true)
|
||||||
try {
|
try {
|
||||||
await deleteListFormJsonRow(data.id, data.tabName, values.index)
|
await deleteListFormJsonRow(data.id, data.tabName, values.index)
|
||||||
toast.push(<Notification type="success">Kayıt silindi </Notification>)
|
toast.push(<Notification type="success">Kayıt silindi </Notification>)
|
||||||
handleClose()
|
handleClose()
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
toast.push(
|
toast.push(
|
||||||
<Notification type="danger">
|
<Notification type="danger">
|
||||||
Hata
|
Hata
|
||||||
<code>{error}</code>
|
<code>{error}</code>
|
||||||
</Notification>,
|
</Notification>,
|
||||||
{ placement: 'top-end' },
|
{ placement: 'top-end' },
|
||||||
)
|
)
|
||||||
} finally {
|
} finally {
|
||||||
setSubmitting(false)
|
setSubmitting(false)
|
||||||
}
|
}
|
||||||
// getListFormJsonRow()
|
// getListFormJsonRow()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{({ isSubmitting }) => (
|
{({ isSubmitting }) => (
|
||||||
<Form className="flex flex-col h-full">
|
<Form className="flex flex-col h-full">
|
||||||
<Dialog.Body className="flex flex-col gap-2">
|
<Dialog.Body className="flex flex-col gap-2">
|
||||||
<h5>Delete</h5>
|
<h5>Delete</h5>
|
||||||
<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 border-t pt-3 mt-1">
|
<Dialog.Footer className="flex justify-end gap-2 border-t pt-3 mt-1">
|
||||||
<Button variant="plain" onClick={handleClose}>
|
<Button variant="plain" onClick={handleClose}>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="solid" loading={isSubmitting} type="submit">
|
<Button variant="solid" loading={isSubmitting} type="submit">
|
||||||
{isSubmitting ? 'Deleting' : 'Delete'}
|
{isSubmitting ? 'Deleting' : 'Delete'}
|
||||||
</Button>
|
</Button>
|
||||||
</Dialog.Footer>
|
</Dialog.Footer>
|
||||||
</Form>
|
</Form>
|
||||||
)}
|
)}
|
||||||
</Formik>
|
</Formik>
|
||||||
)}
|
)}
|
||||||
</Dialog>
|
</Dialog>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -23,13 +23,22 @@ import WizardStep1, {
|
||||||
} from './WizardStep1'
|
} from './WizardStep1'
|
||||||
import WizardStep2 from './WizardStep2'
|
import WizardStep2 from './WizardStep2'
|
||||||
import WizardStep3, { WizardGroup, WizardGroupItem } from './WizardStep3'
|
import WizardStep3, { WizardGroup, WizardGroupItem } from './WizardStep3'
|
||||||
|
import WizardStep7 from './WizardStep7'
|
||||||
import WizardStep4 from './WizardStep4'
|
import WizardStep4 from './WizardStep4'
|
||||||
|
import WizardStep5 from './WizardStep5'
|
||||||
|
import WizardStep6 from './WizardStep6'
|
||||||
import { Container } from '@/components/shared'
|
import { Container } from '@/components/shared'
|
||||||
import { sqlDataTypeToDbType } from '../edit/options'
|
import { sqlDataTypeToDbType } from '../edit/options'
|
||||||
import { useStoreActions } from '@/store/store'
|
import { useStoreActions } from '@/store/store'
|
||||||
import { deleteWizardFile, getWizardFile, postListFormWizard } from '@/services/wizard.service'
|
import { deleteWizardFile, getWizardFile, postListFormWizard } from '@/services/wizard.service'
|
||||||
import { UiLookupDataSourceTypeEnum } from '@/proxy/form/models'
|
import { UiLookupDataSourceTypeEnum } from '@/proxy/form/models'
|
||||||
import { ListFormWizardDto } from '@/proxy/admin/wizard/models'
|
import { ListFormWizardDto } from '@/proxy/admin/wizard/models'
|
||||||
|
import {
|
||||||
|
ListFormWorkflowCriteriaDto,
|
||||||
|
SubFormDto,
|
||||||
|
WidgetEditDto,
|
||||||
|
WorkflowDto,
|
||||||
|
} from '@/proxy/form/models'
|
||||||
|
|
||||||
// ─── Formik initial values & validation ──────────────────────────────────────
|
// ─── Formik initial values & validation ──────────────────────────────────────
|
||||||
const initialValues: ListFormWizardDto = {
|
const initialValues: ListFormWizardDto = {
|
||||||
|
|
@ -81,6 +90,16 @@ const initialValues: ListFormWizardDto = {
|
||||||
schedulerTextExpr: '',
|
schedulerTextExpr: '',
|
||||||
schedulerStartDateExpr: '',
|
schedulerStartDateExpr: '',
|
||||||
schedulerEndDateExpr: '',
|
schedulerEndDateExpr: '',
|
||||||
|
subForms: [],
|
||||||
|
widgets: [],
|
||||||
|
workflow: {
|
||||||
|
approvalUserFieldName: '',
|
||||||
|
approvalDateFieldName: '',
|
||||||
|
approvalStatusFieldName: '',
|
||||||
|
approvalDescriptionFieldName: '',
|
||||||
|
criteria: [],
|
||||||
|
},
|
||||||
|
workflowCriteria: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
const step1ValidationSchema = Yup.object().shape({
|
const step1ValidationSchema = Yup.object().shape({
|
||||||
|
|
@ -136,7 +155,11 @@ const Wizard = () => {
|
||||||
const [isLoadingDbObjects, setIsLoadingDbObjects] = useState(false)
|
const [isLoadingDbObjects, setIsLoadingDbObjects] = useState(false)
|
||||||
const [currentDataSource, setCurrentDataSource] = useState('')
|
const [currentDataSource, setCurrentDataSource] = useState('')
|
||||||
// In edit mode, stores the selectCommand to load columns for once dbObjects is ready
|
// In edit mode, stores the selectCommand to load columns for once dbObjects is ready
|
||||||
const pendingEditColumnsRef = useRef<{ dsCode: string; selectCommand: string; selectCommandType: SelectCommandTypeEnum } | null>(null)
|
const pendingEditColumnsRef = useRef<{
|
||||||
|
dsCode: string
|
||||||
|
selectCommand: string
|
||||||
|
selectCommandType: SelectCommandTypeEnum
|
||||||
|
} | null>(null)
|
||||||
|
|
||||||
const loadDbObjects = async (dsCode: string) => {
|
const loadDbObjects = async (dsCode: string) => {
|
||||||
if (!dsCode) {
|
if (!dsCode) {
|
||||||
|
|
@ -194,6 +217,16 @@ const Wizard = () => {
|
||||||
|
|
||||||
// ── Editing Form Groups (Step 3) ──
|
// ── Editing Form Groups (Step 3) ──
|
||||||
const [editingGroups, setEditingGroups] = useState<WizardGroup[]>([])
|
const [editingGroups, setEditingGroups] = useState<WizardGroup[]>([])
|
||||||
|
const [subForms, setSubForms] = useState<SubFormDto[]>([])
|
||||||
|
const [widgets, setWidgets] = useState<WidgetEditDto[]>([])
|
||||||
|
const [workflow, setWorkflow] = useState<WorkflowDto>({
|
||||||
|
approvalUserFieldName: '',
|
||||||
|
approvalDateFieldName: '',
|
||||||
|
approvalStatusFieldName: '',
|
||||||
|
approvalDescriptionFieldName: '',
|
||||||
|
criteria: [],
|
||||||
|
})
|
||||||
|
const [workflowCriteria, setWorkflowCriteria] = useState<ListFormWorkflowCriteriaDto[]>([])
|
||||||
|
|
||||||
// Audit columns that should not be selected by default
|
// Audit columns that should not be selected by default
|
||||||
const AUDIT_COLUMNS = new Set([
|
const AUDIT_COLUMNS = new Set([
|
||||||
|
|
@ -378,6 +411,16 @@ const Wizard = () => {
|
||||||
schedulerTextExpr: w.schedulerTextExpr ?? '',
|
schedulerTextExpr: w.schedulerTextExpr ?? '',
|
||||||
schedulerStartDateExpr: w.schedulerStartDateExpr ?? '',
|
schedulerStartDateExpr: w.schedulerStartDateExpr ?? '',
|
||||||
schedulerEndDateExpr: w.schedulerEndDateExpr ?? '',
|
schedulerEndDateExpr: w.schedulerEndDateExpr ?? '',
|
||||||
|
subForms: w.subForms ?? [],
|
||||||
|
widgets: w.widgets ?? [],
|
||||||
|
workflow: w.workflow ?? {
|
||||||
|
approvalUserFieldName: '',
|
||||||
|
approvalDateFieldName: '',
|
||||||
|
approvalStatusFieldName: '',
|
||||||
|
approvalDescriptionFieldName: '',
|
||||||
|
criteria: [],
|
||||||
|
},
|
||||||
|
workflowCriteria: w.workflowCriteria ?? w.workflow?.criteria ?? [],
|
||||||
})
|
})
|
||||||
|
|
||||||
// Queue column load to run once dbObjects is available
|
// Queue column load to run once dbObjects is available
|
||||||
|
|
@ -428,6 +471,19 @@ const Wizard = () => {
|
||||||
const allFields = new Set(restoredGroups.flatMap((g) => g.items.map((i) => i.dataField)))
|
const allFields = new Set(restoredGroups.flatMap((g) => g.items.map((i) => i.dataField)))
|
||||||
setSelectedColumns(allFields)
|
setSelectedColumns(allFields)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setSubForms(w.subForms ?? [])
|
||||||
|
setWidgets(w.widgets ?? [])
|
||||||
|
setWorkflow(
|
||||||
|
w.workflow ?? {
|
||||||
|
approvalUserFieldName: '',
|
||||||
|
approvalDateFieldName: '',
|
||||||
|
approvalStatusFieldName: '',
|
||||||
|
approvalDescriptionFieldName: '',
|
||||||
|
criteria: [],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
setWorkflowCriteria(w.workflowCriteria ?? w.workflow?.criteria ?? [])
|
||||||
} catch {
|
} catch {
|
||||||
toast.push(
|
toast.push(
|
||||||
<Notification type="danger">
|
<Notification type="danger">
|
||||||
|
|
@ -582,6 +638,13 @@ const Wizard = () => {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
})),
|
})),
|
||||||
|
subForms,
|
||||||
|
widgets,
|
||||||
|
workflow: {
|
||||||
|
...workflow,
|
||||||
|
criteria: workflowCriteria,
|
||||||
|
},
|
||||||
|
workflowCriteria,
|
||||||
})
|
})
|
||||||
|
|
||||||
// ✅ sonra config çek
|
// ✅ sonra config çek
|
||||||
|
|
@ -621,6 +684,9 @@ const Wizard = () => {
|
||||||
<Steps.Item
|
<Steps.Item
|
||||||
title={translate('::ListForms.Wizard.ListFormFields') || 'List Form Fields'}
|
title={translate('::ListForms.Wizard.ListFormFields') || 'List Form Fields'}
|
||||||
/>
|
/>
|
||||||
|
<Steps.Item title={translate('::ListForms.ListFormEdit.SubForms') || 'Sub Forms'} />
|
||||||
|
<Steps.Item title={translate('::ListForms.ListFormEdit.TabWidgets') || 'Widgets'} />
|
||||||
|
<Steps.Item title={translate('::ListForms.ListFormEdit.TabWorkflow') || 'Workflow'} />
|
||||||
<Steps.Item title={translate('::App.Platform.Deploy') || 'Deploy'} />
|
<Steps.Item title={translate('::App.Platform.Deploy') || 'Deploy'} />
|
||||||
</Steps>
|
</Steps>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -635,128 +701,166 @@ const Wizard = () => {
|
||||||
innerRef={formikRef}
|
innerRef={formikRef}
|
||||||
initialValues={{ ...initialValues }}
|
initialValues={{ ...initialValues }}
|
||||||
validationSchema={listFormValidationSchema}
|
validationSchema={listFormValidationSchema}
|
||||||
onSubmit={async (values, { setSubmitting }) => {
|
onSubmit={async (values, { setSubmitting }) => {
|
||||||
setSubmitting(true)
|
setSubmitting(true)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 🔴 1. Kaydet (bekle)
|
// 🔴 1. Kaydet (bekle)
|
||||||
await postListFormWizard({ ...values })
|
await postListFormWizard({ ...values })
|
||||||
|
|
||||||
// 🔴 2. Config güncelle (bekle)
|
// 🔴 2. Config güncelle (bekle)
|
||||||
await getConfig(true)
|
await getConfig(true)
|
||||||
|
|
||||||
// 🔴 3. Navigate
|
// 🔴 3. Navigate
|
||||||
navigate(
|
navigate(
|
||||||
ROUTES_ENUM.protected.admin.list.replace(':listFormCode', values.listFormCode),
|
ROUTES_ENUM.protected.admin.list.replace(':listFormCode', values.listFormCode),
|
||||||
{ replace: true },
|
{ replace: true },
|
||||||
)
|
)
|
||||||
|
|
||||||
// 🔴 4. Toast (istersen navigate öncesi de olabilir)
|
// 🔴 4. Toast (istersen navigate öncesi de olabilir)
|
||||||
toast.push(
|
toast.push(
|
||||||
<Notification type="success" duration={2000}>
|
<Notification type="success" duration={2000}>
|
||||||
{translate('::ListForms.FormBilgileriKaydedildi')}
|
{translate('::ListForms.FormBilgileriKaydedildi')}
|
||||||
</Notification>,
|
</Notification>,
|
||||||
{ placement: 'top-end' },
|
{ placement: 'top-end' },
|
||||||
)
|
)
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
toast.push(<Notification title={error.message} type="danger" />, {
|
toast.push(<Notification title={error.message} type="danger" />, {
|
||||||
placement: 'top-end',
|
placement: 'top-end',
|
||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
setSubmitting(false)
|
setSubmitting(false)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{({ touched, errors, isSubmitting, values }) => (
|
{({ touched, errors, isSubmitting, values }) => (
|
||||||
<Form>
|
<Form>
|
||||||
<FormContainer
|
<FormContainer size={currentStep >= 2 ? undefined : 'sm'}>
|
||||||
size={currentStep === 2 ? undefined : currentStep === 3 ? undefined : 'sm'}
|
{/* ─── Step 1: Basic Info ─────────────────────────────── */}
|
||||||
>
|
{currentStep === 0 && (
|
||||||
{/* ─── Step 1: Basic Info ─────────────────────────────── */}
|
<WizardStep1
|
||||||
{currentStep === 0 && (
|
values={values}
|
||||||
<WizardStep1
|
errors={errors}
|
||||||
values={values}
|
touched={touched}
|
||||||
errors={errors}
|
wizardName={values.wizardName}
|
||||||
touched={touched}
|
onWizardNameChange={handleWizardNameChange}
|
||||||
wizardName={values.wizardName}
|
rawMenuItems={rawMenuItems}
|
||||||
onWizardNameChange={handleWizardNameChange}
|
menuTree={menuTree}
|
||||||
rawMenuItems={rawMenuItems}
|
isLoadingMenu={isLoadingMenu}
|
||||||
menuTree={menuTree}
|
onMenuParentChange={handleMenuParentChange}
|
||||||
isLoadingMenu={isLoadingMenu}
|
onClearMenuParent={() => formikRef.current?.setFieldValue('menuParentCode', '')}
|
||||||
onMenuParentChange={handleMenuParentChange}
|
onReloadMenu={getMenuList}
|
||||||
onClearMenuParent={() =>
|
permissionGroupList={permissionGroupList}
|
||||||
formikRef.current?.setFieldValue('menuParentCode', '')
|
isLoadingPermissionGroup={isLoadingPermissionGroup}
|
||||||
}
|
onNext={handleNext}
|
||||||
onReloadMenu={getMenuList}
|
translate={translate}
|
||||||
permissionGroupList={permissionGroupList}
|
/>
|
||||||
isLoadingPermissionGroup={isLoadingPermissionGroup}
|
)}
|
||||||
onNext={handleNext}
|
|
||||||
translate={translate}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* ─── Step 2: Data Settings ───────────────────────────── */}
|
{/* ─── Step 2: Data Settings ───────────────────────────── */}
|
||||||
{currentStep === 1 && (
|
{currentStep === 1 && (
|
||||||
<WizardStep2
|
<WizardStep2
|
||||||
values={values}
|
values={values}
|
||||||
errors={errors}
|
errors={errors}
|
||||||
touched={touched}
|
touched={touched}
|
||||||
isLoadingDataSource={isLoadingDataSource}
|
isLoadingDataSource={isLoadingDataSource}
|
||||||
dataSourceList={dataSourceList}
|
dataSourceList={dataSourceList}
|
||||||
isDataSourceNew={isDataSourceNew}
|
isDataSourceNew={isDataSourceNew}
|
||||||
onDataSourceSelect={setCurrentDataSource}
|
onDataSourceSelect={setCurrentDataSource}
|
||||||
onDataSourceNewChange={setIsDataSourceNew}
|
onDataSourceNewChange={setIsDataSourceNew}
|
||||||
dbObjects={dbObjects}
|
dbObjects={dbObjects}
|
||||||
isLoadingDbObjects={isLoadingDbObjects}
|
isLoadingDbObjects={isLoadingDbObjects}
|
||||||
selectCommandColumns={selectCommandColumns}
|
selectCommandColumns={selectCommandColumns}
|
||||||
isLoadingColumns={isLoadingColumns}
|
isLoadingColumns={isLoadingColumns}
|
||||||
selectedColumns={selectedColumns}
|
selectedColumns={selectedColumns}
|
||||||
onLoadColumns={loadColumns}
|
onLoadColumns={loadColumns}
|
||||||
onClearColumns={() => {
|
onClearColumns={() => {
|
||||||
setSelectCommandColumns([])
|
setSelectCommandColumns([])
|
||||||
setSelectedColumns(new Set())
|
setSelectedColumns(new Set())
|
||||||
}}
|
}}
|
||||||
onToggleColumn={toggleColumn}
|
onToggleColumn={toggleColumn}
|
||||||
onToggleAllColumns={toggleAllColumns}
|
onToggleAllColumns={toggleAllColumns}
|
||||||
translate={translate}
|
translate={translate}
|
||||||
onBack={handleBack}
|
onBack={handleBack}
|
||||||
onNext={handleNext2}
|
onNext={handleNext2}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* ─── Step 3: List Form Fields ───────────────────────────── */}
|
{/* ─── Step 3: List Form Fields ───────────────────────────── */}
|
||||||
{currentStep === 2 && (
|
{currentStep === 2 && (
|
||||||
<WizardStep3
|
<WizardStep3
|
||||||
selectedColumns={selectedColumns}
|
selectedColumns={selectedColumns}
|
||||||
selectCommandColumns={selectCommandColumns}
|
selectCommandColumns={selectCommandColumns}
|
||||||
groups={editingGroups}
|
groups={editingGroups}
|
||||||
onGroupsChange={setEditingGroups}
|
onGroupsChange={setEditingGroups}
|
||||||
dbObjects={dbObjects}
|
dbObjects={dbObjects}
|
||||||
isLoadingDbObjects={isLoadingDbObjects}
|
isLoadingDbObjects={isLoadingDbObjects}
|
||||||
dsCode={currentDataSource}
|
dsCode={currentDataSource}
|
||||||
translate={translate}
|
translate={translate}
|
||||||
onBack={() => setCurrentStep(1)}
|
onBack={() => setCurrentStep(1)}
|
||||||
onNext={() => setCurrentStep(3)}
|
onNext={() => setCurrentStep(3)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* ─── Step 4: Deploy ───────────────────────────── */}
|
{/* ─── Step 4: Sub Forms ───────────────────────────── */}
|
||||||
{currentStep === 3 && (
|
{currentStep === 3 && (
|
||||||
<WizardStep4
|
<WizardStep4
|
||||||
values={values}
|
subForms={subForms}
|
||||||
wizardName={values.wizardName}
|
selectCommandColumns={selectCommandColumns}
|
||||||
selectedColumns={selectedColumns}
|
translate={translate}
|
||||||
selectCommandColumns={selectCommandColumns}
|
onChange={setSubForms}
|
||||||
groups={editingGroups}
|
onBack={() => setCurrentStep(2)}
|
||||||
translate={translate}
|
onNext={() => setCurrentStep(4)}
|
||||||
onBack={() => setCurrentStep(2)}
|
/>
|
||||||
onSubmit={handleDeploy}
|
)}
|
||||||
/>
|
|
||||||
)}
|
{/* ─── Step 5: Widgets ───────────────────────────── */}
|
||||||
</FormContainer>
|
{currentStep === 4 && (
|
||||||
</Form>
|
<WizardStep5
|
||||||
)}
|
widgets={widgets}
|
||||||
</Formik>
|
translate={translate}
|
||||||
|
onChange={setWidgets}
|
||||||
|
onBack={() => setCurrentStep(3)}
|
||||||
|
onNext={() => setCurrentStep(5)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* ─── Step 6: Workflow ───────────────────────────── */}
|
||||||
|
{currentStep === 5 && (
|
||||||
|
<WizardStep6
|
||||||
|
listFormCode={values.listFormCode}
|
||||||
|
workflow={workflow}
|
||||||
|
criteria={workflowCriteria}
|
||||||
|
selectCommandColumns={selectCommandColumns}
|
||||||
|
translate={translate}
|
||||||
|
onWorkflowChange={setWorkflow}
|
||||||
|
onCriteriaChange={setWorkflowCriteria}
|
||||||
|
onBack={() => setCurrentStep(4)}
|
||||||
|
onNext={() => setCurrentStep(6)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* ─── Step 7: Deploy ───────────────────────────── */}
|
||||||
|
{currentStep === 6 && (
|
||||||
|
<WizardStep7
|
||||||
|
values={values}
|
||||||
|
wizardName={values.wizardName}
|
||||||
|
selectedColumns={selectedColumns}
|
||||||
|
selectCommandColumns={selectCommandColumns}
|
||||||
|
groups={editingGroups}
|
||||||
|
subForms={subForms}
|
||||||
|
widgets={widgets}
|
||||||
|
workflow={workflow}
|
||||||
|
workflowCriteria={workflowCriteria}
|
||||||
|
translate={translate}
|
||||||
|
onBack={() => setCurrentStep(5)}
|
||||||
|
onSubmit={handleDeploy}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</FormContainer>
|
||||||
|
</Form>
|
||||||
|
)}
|
||||||
|
</Formik>
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,421 +1,475 @@
|
||||||
import { Button } from '@/components/ui'
|
import { Button, Card, Checkbox, Dialog, FormItem, Input, Select, Table } from '@/components/ui'
|
||||||
|
import TBody from '@/components/ui/Table/TBody'
|
||||||
|
import THead from '@/components/ui/Table/THead'
|
||||||
|
import Td from '@/components/ui/Table/Td'
|
||||||
|
import Th from '@/components/ui/Table/Th'
|
||||||
|
import Tr from '@/components/ui/Table/Tr'
|
||||||
|
import type { ColumnFormatEditDto } from '@/proxy/admin/list-form-field/models'
|
||||||
|
import { DbTypeEnum, SubFormDto, SubFormRelationDto, SubFormTabTypeEnum } from '@/proxy/form/models'
|
||||||
|
import { getListFormFields } from '@/services/admin/list-form-field.service'
|
||||||
|
import { getListForms } from '@/services/admin/list-form.service'
|
||||||
import type { DatabaseColumnDto } from '@/proxy/sql-query-manager/models'
|
import type { DatabaseColumnDto } from '@/proxy/sql-query-manager/models'
|
||||||
import { useState } from 'react'
|
import type { SelectBoxOption } from '@/types/shared'
|
||||||
|
import { Field, FieldArray, FieldProps, Form, Formik } from 'formik'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
import {
|
import {
|
||||||
FaArrowLeft,
|
FaArrowLeft,
|
||||||
FaCheckCircle,
|
FaArrowRight,
|
||||||
FaChevronDown,
|
FaCalendarMinus,
|
||||||
FaChevronRight,
|
FaCalendarPlus,
|
||||||
FaCircle,
|
FaEdit,
|
||||||
FaExclamationCircle,
|
FaFileMedical,
|
||||||
FaRocket,
|
FaTrash,
|
||||||
FaSpinner,
|
|
||||||
} from 'react-icons/fa'
|
} from 'react-icons/fa'
|
||||||
import { WizardGroup } from './WizardStep3'
|
import { object, string } from 'yup'
|
||||||
import { dbSourceTypeOptions, selectCommandTypeOptions } from '../edit/options'
|
import { dbSourceTypeOptions, sqlDataTypeToDbType, tabTypeOptions } from '../edit/options'
|
||||||
import { ListFormWizardDto } from '@/proxy/admin/wizard/models'
|
|
||||||
|
|
||||||
// ─── Types ────────────────────────────────────────────────────────────────────
|
type Props = {
|
||||||
|
subForms: SubFormDto[]
|
||||||
export interface WizardStep4Props {
|
|
||||||
values: ListFormWizardDto
|
|
||||||
wizardName: string
|
|
||||||
selectedColumns: Set<string>
|
|
||||||
selectCommandColumns: DatabaseColumnDto[]
|
selectCommandColumns: DatabaseColumnDto[]
|
||||||
groups: WizardGroup[]
|
|
||||||
translate: (key: string) => string
|
translate: (key: string) => string
|
||||||
|
onChange: (subForms: SubFormDto[]) => void
|
||||||
onBack: () => void
|
onBack: () => void
|
||||||
onSubmit: () => Promise<void>
|
onNext: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
type LogStatus = 'pending' | 'running' | 'success' | 'error'
|
const schema = object().shape({
|
||||||
|
tabTitle: string().required(),
|
||||||
|
tabType: string().required(),
|
||||||
|
code: string().required(),
|
||||||
|
})
|
||||||
|
|
||||||
interface LogEntry {
|
const emptySubForm: SubFormDto = {
|
||||||
id: number
|
tabTitle: '',
|
||||||
label: string
|
tabType: SubFormTabTypeEnum.List,
|
||||||
status: LogStatus
|
code: '',
|
||||||
detail?: string
|
isRefresh: false,
|
||||||
|
relation: [],
|
||||||
|
tabMode: 'edit',
|
||||||
|
searchParams: new URLSearchParams(),
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── Deploy log steps ─────────────────────────────────────────────────────────
|
function WizardStep4({
|
||||||
|
subForms,
|
||||||
function buildLogSteps(
|
|
||||||
values: ListFormWizardDto,
|
|
||||||
groups: WizardGroup[],
|
|
||||||
translate: (key: string, params?: Record<string, string | number>) => string,
|
|
||||||
): Omit<LogEntry, 'status'>[] {
|
|
||||||
const totalFields = groups.reduce((acc, g) => acc + g.items.length, 0)
|
|
||||||
return [
|
|
||||||
{ id: 1, label: translate('::ListForms.Wizard.Step4.Log.ValidatingConfig') },
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
label: translate('::ListForms.Wizard.Step4.Log.CreatingMenu', { 0: values.menuCode }),
|
|
||||||
detail: `Parent: ${values.menuParentCode}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
label: translate('::ListForms.Wizard.Step4.Log.SavingLanguageTexts'),
|
|
||||||
detail: `EN: ${values.languageTextMenuEn} / TR: ${values.languageTextMenuTr}`,
|
|
||||||
},
|
|
||||||
{ id: 4, label: translate('::ListForms.Wizard.Step4.Log.ConfiguringPermission', { 0: values.permissionGroupName }) },
|
|
||||||
{ id: 5, label: translate('::ListForms.Wizard.Step4.Log.ConnectingDataSource', { 0: values.dataSourceCode }) },
|
|
||||||
{
|
|
||||||
id: 6,
|
|
||||||
label: translate('::ListForms.Wizard.Step4.Log.CreatingListForm', { 0: values.listFormCode }),
|
|
||||||
detail: `Key: ${values.keyFieldName}`,
|
|
||||||
},
|
|
||||||
{ id: 7, label: translate('::ListForms.Wizard.Step4.Log.SavingFormGroups', { 0: groups.length, 1: totalFields }) },
|
|
||||||
{ id: 8, label: translate('::ListForms.Wizard.Step4.Log.Deploying') },
|
|
||||||
{ id: 9, label: translate('::ListForms.Wizard.Step4.Log.Completed') },
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
// ─── Mini-components ──────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
function LogIcon({ status }: { status: LogStatus }) {
|
|
||||||
if (status === 'running') return <FaSpinner className="text-indigo-500 animate-spin shrink-0" />
|
|
||||||
if (status === 'success') return <FaCheckCircle className="text-emerald-500 shrink-0" />
|
|
||||||
if (status === 'error') return <FaExclamationCircle className="text-red-500 shrink-0" />
|
|
||||||
return <FaCircle className="text-gray-300 dark:text-gray-600 shrink-0 text-[8px] mt-1" />
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SectionProps {
|
|
||||||
title: string
|
|
||||||
badge?: string | number
|
|
||||||
children: React.ReactNode
|
|
||||||
defaultOpen?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
function Section({ title, badge, children, defaultOpen = true }: SectionProps) {
|
|
||||||
const [open, setOpen] = useState(defaultOpen)
|
|
||||||
return (
|
|
||||||
<div className="rounded-xl border border-gray-200 dark:border-gray-700 overflow-hidden">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => setOpen((v) => !v)}
|
|
||||||
className="w-full flex items-center justify-between px-4 py-2.5 bg-gray-50 dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-750 transition-colors"
|
|
||||||
>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
{open ? (
|
|
||||||
<FaChevronDown className="text-gray-400 text-xs" />
|
|
||||||
) : (
|
|
||||||
<FaChevronRight className="text-gray-400 text-xs" />
|
|
||||||
)}
|
|
||||||
<span className="text-sm font-semibold text-gray-700 dark:text-gray-200">{title}</span>
|
|
||||||
</div>
|
|
||||||
{badge !== undefined && (
|
|
||||||
<span className="text-xs bg-indigo-100 dark:bg-indigo-900/40 text-indigo-600 dark:text-indigo-400 px-2 py-0.5 rounded-full font-medium">
|
|
||||||
{badge}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</button>
|
|
||||||
{open && <div className="px-4 py-3 bg-white dark:bg-gray-900">{children}</div>}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function Row({ label, value }: { label: string; value?: string | number }) {
|
|
||||||
if (!value && value !== 0) return null
|
|
||||||
return (
|
|
||||||
<div className="flex gap-2 py-1 border-b border-gray-100 dark:border-gray-800 last:border-0">
|
|
||||||
<span className="text-xs text-gray-400 w-40 shrink-0">{label}</span>
|
|
||||||
<span className="text-xs text-gray-700 dark:text-gray-200 font-medium break-all">
|
|
||||||
{value}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ─── WizardStep4 ──────────────────────────────────────────────────────────────
|
|
||||||
const WizardStep4 = ({
|
|
||||||
values,
|
|
||||||
wizardName,
|
|
||||||
selectedColumns,
|
|
||||||
selectCommandColumns,
|
selectCommandColumns,
|
||||||
groups,
|
|
||||||
translate,
|
translate,
|
||||||
|
onChange,
|
||||||
onBack,
|
onBack,
|
||||||
onSubmit,
|
onNext,
|
||||||
}: WizardStep4Props) => {
|
}: Props) {
|
||||||
const [logs, setLogs] = useState<LogEntry[]>([])
|
const [dialogIndex, setDialogIndex] = useState<number | null>(null)
|
||||||
const [isDeploying, setIsDeploying] = useState(false)
|
const [deleteIndex, setDeleteIndex] = useState<number | null>(null)
|
||||||
const [isDone, setIsDone] = useState(false)
|
const [listFormOptions, setListFormOptions] = useState<SelectBoxOption[]>([])
|
||||||
const [hasError, setHasError] = useState(false)
|
const [childFields, setChildFields] = useState<ColumnFormatEditDto[]>([])
|
||||||
|
const [isLoadingListForms, setIsLoadingListForms] = useState(false)
|
||||||
|
const [isLoadingChildFields, setIsLoadingChildFields] = useState(false)
|
||||||
|
|
||||||
const steps = buildLogSteps(values, groups, translate)
|
const parentFieldOptions = selectCommandColumns.map((column) => ({
|
||||||
|
value: column.columnName,
|
||||||
|
label: `${column.columnName} (${column.dataType})`,
|
||||||
|
}))
|
||||||
|
|
||||||
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms))
|
const childFieldOptions = childFields
|
||||||
|
.filter((field) => field.fieldName)
|
||||||
|
.map((field) => ({
|
||||||
|
value: field.fieldName,
|
||||||
|
label: `${field.fieldName} (${field.dataType})`,
|
||||||
|
}))
|
||||||
|
|
||||||
const runDeploy = async () => {
|
const loadChildFields = async (listFormCode?: string) => {
|
||||||
if (isDeploying) return
|
if (!listFormCode) {
|
||||||
setIsDeploying(true)
|
setChildFields([])
|
||||||
setHasError(false)
|
return
|
||||||
setIsDone(false)
|
|
||||||
|
|
||||||
// Initialize all as pending
|
|
||||||
setLogs(steps.map((s) => ({ ...s, status: 'pending' })))
|
|
||||||
|
|
||||||
const setStatus = (id: number, status: LogStatus) =>
|
|
||||||
setLogs((prev) => prev.map((l) => (l.id === id ? { ...l, status } : l)))
|
|
||||||
|
|
||||||
// Steps 1-7: pre-deploy simulation (fast)
|
|
||||||
for (let i = 0; i < steps.length - 2; i++) {
|
|
||||||
const step = steps[i]
|
|
||||||
setStatus(step.id, 'running')
|
|
||||||
await sleep(300 + Math.random() * 200)
|
|
||||||
setStatus(step.id, 'success')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 8: actual API call
|
setIsLoadingChildFields(true)
|
||||||
const deployStep = steps[steps.length - 2]
|
|
||||||
setStatus(deployStep.id, 'running')
|
|
||||||
try {
|
try {
|
||||||
await onSubmit()
|
const resp = await getListFormFields({
|
||||||
setStatus(deployStep.id, 'success')
|
listFormCode,
|
||||||
await sleep(200)
|
sorting: 'ListOrderNo',
|
||||||
// Step 9: done
|
maxResultCount: 1000,
|
||||||
const doneStep = steps[steps.length - 1]
|
})
|
||||||
setStatus(doneStep.id, 'running')
|
setChildFields(resp.data?.items ?? [])
|
||||||
await sleep(300)
|
} catch {
|
||||||
setStatus(doneStep.id, 'success')
|
setChildFields([])
|
||||||
setIsDone(true)
|
|
||||||
} catch (err: any) {
|
|
||||||
setStatus(deployStep.id, 'error')
|
|
||||||
setLogs((prev) => [
|
|
||||||
...prev,
|
|
||||||
{
|
|
||||||
id: 999,
|
|
||||||
label: `Hata: ${err?.message ?? 'Bilinmeyen hata'}`,
|
|
||||||
status: 'error',
|
|
||||||
},
|
|
||||||
])
|
|
||||||
setHasError(true)
|
|
||||||
} finally {
|
} finally {
|
||||||
setIsDeploying(false)
|
setIsLoadingChildFields(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const totalFields = groups.reduce((acc, g) => acc + g.items.length, 0)
|
useEffect(() => {
|
||||||
|
if (dialogIndex === null) return
|
||||||
|
|
||||||
|
const loadListForms = async () => {
|
||||||
|
setIsLoadingListForms(true)
|
||||||
|
try {
|
||||||
|
const resp = await getListForms({ sorting: 'ListFormCode', maxResultCount: 1000 })
|
||||||
|
setListFormOptions(
|
||||||
|
(resp.data?.items ?? [])
|
||||||
|
.filter((item) => item.listFormCode)
|
||||||
|
.map((item) => ({
|
||||||
|
value: item.listFormCode,
|
||||||
|
label: `${item.listFormCode}${item.title ? ` - ${translate(`::${item.title}`)}` : ''}`,
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
} catch {
|
||||||
|
setListFormOptions([])
|
||||||
|
} finally {
|
||||||
|
setIsLoadingListForms(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadListForms()
|
||||||
|
|
||||||
|
if (dialogIndex !== -1) {
|
||||||
|
loadChildFields(subForms[dialogIndex]?.code)
|
||||||
|
} else {
|
||||||
|
setChildFields([])
|
||||||
|
}
|
||||||
|
}, [dialogIndex])
|
||||||
|
|
||||||
|
const upsertSubForm = (values: SubFormDto) => {
|
||||||
|
const next = [...subForms]
|
||||||
|
if (dialogIndex === -1) next.push(values)
|
||||||
|
else if (dialogIndex !== null) next[dialogIndex] = values
|
||||||
|
onChange(next)
|
||||||
|
setDialogIndex(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeSubForm = () => {
|
||||||
|
if (deleteIndex === null) return
|
||||||
|
onChange(subForms.filter((_, index) => index !== deleteIndex))
|
||||||
|
setDeleteIndex(null)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="grid grid-cols-[3fr_2fr] gap-5 pb-24 items-start">
|
<div className="flex h-[calc(100vh-250px)] min-h-[500px] flex-col overflow-hidden">
|
||||||
{/* ── Left: Summary ──────────────────────────────────────────── */}
|
<div className="flex-1 overflow-y-auto pr-1">
|
||||||
<div className="flex flex-col gap-3">
|
<Card
|
||||||
<div className="grid grid-cols-2 gap-3 items-start">
|
bodyClass="p-0"
|
||||||
<Section title={translate('::ListForms.Wizard.Step4.MenuInfo')}>
|
header={translate('::ListForms.ListFormEdit.SubForms')}
|
||||||
<Row label={translate('::ListForms.Wizard.Step4.WizardName')} value={wizardName} />
|
headerExtra={translate('::ListForms.ListFormEdit.SubFormsDescription')}
|
||||||
<Row label={translate('::ListForms.Wizard.Step4.MenuCode')} value={values.menuCode} />
|
>
|
||||||
<Row label={translate('::ListForms.Wizard.Step4.MenuParent')} value={values.menuParentCode} />
|
<Table compact>
|
||||||
<Row label={translate('::ListForms.Wizard.Step4.PermissionGroup')} value={values.permissionGroupName} />
|
<THead>
|
||||||
<Row label={translate('::App.Listform.ListformField.Icon')} value={values.menuIcon} />
|
<Tr>
|
||||||
<Row label={translate('::ListForms.Wizard.Step4.MenuTr')} value={values.languageTextMenuTr} />
|
<Th className="text-center min-w-[100px]">
|
||||||
<Row label={translate('::ListForms.Wizard.Step4.MenuEn')} value={values.languageTextMenuEn} />
|
<Button
|
||||||
<Row label={translate('::ListForms.Wizard.Step4.MenuParentTr')} value={values.languageTextMenuParentTr} />
|
shape="circle"
|
||||||
<Row label={translate('::ListForms.Wizard.Step4.MenuParentEn')} value={values.languageTextMenuParentEn} />
|
variant="plain"
|
||||||
</Section>
|
type="button"
|
||||||
|
size="sm"
|
||||||
<Section title={translate('::ListForms.Wizard.Step4.ListFormSettings')}>
|
title="Add"
|
||||||
<Row label={translate('::ListForms.Wizard.Step4.ListFormCode')} value={values.listFormCode} />
|
icon={<FaFileMedical />}
|
||||||
<Row label={translate('::ListForms.Wizard.Step4.TitleTr')} value={values.languageTextTitleTr} />
|
onClick={() => setDialogIndex(-1)}
|
||||||
<Row label={translate('::ListForms.Wizard.Step4.TitleEn')} value={values.languageTextTitleEn} />
|
/>
|
||||||
<Row label={translate('::ListForms.Wizard.Step4.DescTr')} value={values.languageTextDescTr} />
|
</Th>
|
||||||
<Row label={translate('::ListForms.Wizard.Step4.DescEn')} value={values.languageTextDescEn} />
|
<Th>{translate('::ListForms.ListFormEdit.SubFormsTabTitle')}</Th>
|
||||||
<Row label={translate('::ListForms.Wizard.Step4.DataSource')} value={values.dataSourceCode} />
|
<Th>{translate('::ListForms.ListFormEdit.SubFormsTabType')}</Th>
|
||||||
<Row label={translate('::App.Listform.ListformField.ConnectionString')} value={values.dataSourceConnectionString} />
|
<Th>{translate('::App.Listform.ListformField.ListFormCode')}</Th>
|
||||||
<Row
|
<Th>{translate('::ListForms.ListFormEdit.SubFormsIsRefresh')}</Th>
|
||||||
label={translate('::ListForms.Wizard.Step4.CommandType')}
|
<Th>{translate('::ListForms.ListFormEdit.SubFormsRelation')}</Th>
|
||||||
value={
|
</Tr>
|
||||||
selectCommandTypeOptions.find((o) => o.value === values.selectCommandType)?.label ||
|
</THead>
|
||||||
values.selectCommandType
|
<TBody>
|
||||||
}
|
{subForms.map((row, index) => (
|
||||||
/>
|
<Tr key={`${row.code}-${index}`}>
|
||||||
<Row label={translate('::ListForms.Wizard.Step4.SelectCommand')} value={values.selectCommand} />
|
<Td>
|
||||||
<Row label={translate('::ListForms.Wizard.Step4.KeyField')} value={values.keyFieldName} />
|
<div className="flex items-center gap-2">
|
||||||
<Row
|
<Button
|
||||||
label={translate('::ListForms.Wizard.Step4.KeyFieldType')}
|
shape="circle"
|
||||||
value={
|
variant="plain"
|
||||||
dbSourceTypeOptions.find((o: any) => o.value === values.keyFieldDbSourceType)
|
type="button"
|
||||||
?.label ?? String(values.keyFieldDbSourceType)
|
size="sm"
|
||||||
}
|
title="Edit"
|
||||||
/>
|
icon={<FaEdit />}
|
||||||
</Section>
|
onClick={() => setDialogIndex(index)}
|
||||||
</div>
|
/>
|
||||||
|
<Button
|
||||||
<Section title={translate('::ListForms.Wizard.Step4.SelectedColumns')} badge={selectedColumns.size}>
|
shape="circle"
|
||||||
<div className="flex flex-wrap gap-1.5">
|
variant="plain"
|
||||||
{[...selectedColumns].map((col) => {
|
type="button"
|
||||||
const meta = selectCommandColumns.find((c) => c.columnName === col)
|
size="sm"
|
||||||
return (
|
title="Delete"
|
||||||
<span
|
icon={<FaTrash />}
|
||||||
key={col}
|
onClick={() => setDeleteIndex(index)}
|
||||||
className="inline-flex items-center gap-1 px-2 py-0.5 text-xs rounded-full bg-indigo-50 dark:bg-indigo-900/30 text-indigo-700 dark:text-indigo-300 border border-indigo-200 dark:border-indigo-700"
|
/>
|
||||||
>
|
|
||||||
{col}
|
|
||||||
{meta?.dataType && (
|
|
||||||
<span className="text-[10px] text-indigo-400 opacity-70">{meta.dataType}</span>
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</Section>
|
|
||||||
|
|
||||||
<Section title={translate('::ListForms.Wizard.Step4.FormGroups')} badge={groups.length}>
|
|
||||||
<div className="flex flex-col gap-3">
|
|
||||||
{groups.map((g) => (
|
|
||||||
<Section
|
|
||||||
key={g.id}
|
|
||||||
title={g.caption || `(${translate('::ListForms.Wizard.Step4.StatGroup')})`}
|
|
||||||
badge={`${g.items.length} ${translate('::ListForms.Wizard.Step4.StatField')} · ${g.colCount} ${translate('::App.Listform.ListformField.Column')}`}
|
|
||||||
defaultOpen={false}
|
|
||||||
>
|
|
||||||
<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>
|
|
||||||
) : (
|
|
||||||
g.items.map((item) => (
|
|
||||||
<div
|
|
||||||
key={item.id}
|
|
||||||
className="flex items-center gap-2 py-1 border-b border-gray-100 dark:border-gray-800 last:border-0"
|
|
||||||
>
|
|
||||||
<span className="text-xs font-medium text-indigo-600 dark:text-indigo-400 w-36 shrink-0 truncate">
|
|
||||||
{item.dataField}
|
|
||||||
</span>
|
|
||||||
<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 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>
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
))
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Section>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</Section>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* ── Right: Deploy ──────────────────────────────────────────── */}
|
|
||||||
<div className="sticky top-4 flex flex-col gap-3 max-h-[calc(100vh-200px)]">
|
|
||||||
{/* Stats */}
|
|
||||||
<div className="grid grid-cols-3 gap-2">
|
|
||||||
{[
|
|
||||||
{ label: translate('::ListForms.Wizard.Step4.StatGroup'), value: groups.length },
|
|
||||||
{ label: translate('::ListForms.Wizard.Step4.StatField'), value: totalFields },
|
|
||||||
{ label: translate('::App.Listform.ListformField.Column'), value: selectedColumns.size },
|
|
||||||
].map((s) => (
|
|
||||||
<div
|
|
||||||
key={s.label}
|
|
||||||
className="rounded-xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 p-3 text-center shadow-sm"
|
|
||||||
>
|
|
||||||
<div className="text-2xl font-bold text-indigo-600 dark:text-indigo-400">
|
|
||||||
{s.value}
|
|
||||||
</div>
|
|
||||||
<div className="text-xs text-gray-400 mt-0.5">{s.label}</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Log panel — grows to fill remaining height */}
|
|
||||||
<div className="rounded-xl border border-gray-200 dark:border-gray-700 overflow-hidden flex flex-col flex-1 min-h-0">
|
|
||||||
<div className="px-4 py-2.5 bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between shrink-0">
|
|
||||||
<span className="text-sm font-semibold text-gray-700 dark:text-gray-200 flex items-center gap-2">
|
|
||||||
<FaRocket className="text-indigo-400 text-xs" />
|
|
||||||
{translate('::ListForms.Wizard.Step4.DeployLog') || 'Deploy Log'}
|
|
||||||
</span>
|
|
||||||
{isDone && (
|
|
||||||
<span className="text-xs text-emerald-500 font-semibold flex items-center gap-1">
|
|
||||||
<FaCheckCircle /> {translate('::ListForms.Wizard.Step4.Success') || 'Başarılı'}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
{hasError && (
|
|
||||||
<span className="text-xs text-red-500 font-semibold flex items-center gap-1">
|
|
||||||
<FaExclamationCircle /> {translate('::ListForms.Wizard.Step4.Error') || 'Hata'}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex-1 overflow-y-auto p-4 bg-[#0d1117] dark:bg-black font-mono min-h-[360px]">
|
|
||||||
{logs.length === 0 ? (
|
|
||||||
<div className="flex flex-col items-center justify-center h-full gap-3 py-10 select-none">
|
|
||||||
<FaRocket className="text-gray-700 text-3xl" />
|
|
||||||
<span className="text-xs text-gray-600 italic text-center">
|
|
||||||
{translate('::ListForms.Wizard.Step4.AllInfoReady') || 'Tüm bilgiler hazır.'}
|
|
||||||
<br />
|
|
||||||
{translate('::ListForms.Wizard.Step4.DeployStartHint')}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="flex flex-col gap-2">
|
|
||||||
{logs.map((log) => (
|
|
||||||
<div key={log.id} className="flex items-start gap-2.5">
|
|
||||||
<span className="mt-0.5 shrink-0">
|
|
||||||
<LogIcon status={log.status} />
|
|
||||||
</span>
|
|
||||||
<div>
|
|
||||||
<span
|
|
||||||
className={`text-xs leading-relaxed ${
|
|
||||||
log.status === 'success'
|
|
||||||
? 'text-emerald-400'
|
|
||||||
: log.status === 'error'
|
|
||||||
? 'text-red-400'
|
|
||||||
: log.status === 'running'
|
|
||||||
? 'text-yellow-300'
|
|
||||||
: 'text-gray-600'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{log.label}
|
|
||||||
</span>
|
|
||||||
{log.detail && (
|
|
||||||
<div className="text-[10px] text-gray-600 mt-0.5">{log.detail}</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Td>
|
||||||
))}
|
<Td>{row.tabTitle}</Td>
|
||||||
{isDone && (
|
<Td>{row.tabType}</Td>
|
||||||
<div className="mt-4 rounded-lg border border-emerald-800 bg-emerald-950/40 px-4 py-2.5 text-xs text-emerald-400 text-center font-semibold">
|
<Td>{row.code}</Td>
|
||||||
🎉 {translate('::ListForms.Wizard.Step4.DeploySuccess')}
|
<Td>{row.isRefresh ? 'Active' : 'Inactive'}</Td>
|
||||||
</div>
|
<Td>
|
||||||
)}
|
{(row.relation || []).map((item) => (
|
||||||
</div>
|
<div key={`${item.parentFieldName}-${item.childFieldName}`}>
|
||||||
)}
|
{item.parentFieldName} : {item.childFieldName}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
))}
|
||||||
|
</Td>
|
||||||
|
</Tr>
|
||||||
|
))}
|
||||||
|
</TBody>
|
||||||
|
</Table>
|
||||||
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* ── Fixed Footer ─────────────────────────────────────────────── */}
|
<div className="fixed bottom-0 left-0 right-0 z-10 bg-white dark:bg-gray-900 border-t border-gray-200 dark:border-gray-700 px-4 py-2 min-h-16 flex items-center">
|
||||||
<div className="fixed bottom-0 left-0 right-0 z-10 bg-white dark:bg-gray-900 border-t border-gray-200 dark:border-gray-700 px-6 py-0 h-16 flex items-center">
|
<div className="flex flex-wrap items-center gap-2 w-full">
|
||||||
<div className="flex items-center gap-3 w-full">
|
<Button size="sm" variant="default" type="button" icon={<FaArrowLeft />} onClick={onBack}>
|
||||||
<Button
|
|
||||||
size='sm'
|
|
||||||
variant="default"
|
|
||||||
type="button"
|
|
||||||
icon={<FaArrowLeft />}
|
|
||||||
onClick={onBack}
|
|
||||||
disabled={isDeploying}
|
|
||||||
>
|
|
||||||
{translate('::Back') || 'Back'}
|
{translate('::Back') || 'Back'}
|
||||||
</Button>
|
</Button>
|
||||||
<div className="flex-1 flex items-center justify-end">
|
<div className="flex-1 flex items-center justify-end gap-3">
|
||||||
<Button
|
<Button
|
||||||
size='sm'
|
size="sm"
|
||||||
variant="solid"
|
variant="solid"
|
||||||
type="button"
|
type="button"
|
||||||
icon={<FaRocket />}
|
icon={<FaArrowRight />}
|
||||||
loading={isDeploying}
|
onClick={onNext}
|
||||||
disabled={isDeploying || isDone}
|
|
||||||
onClick={runDeploy}
|
|
||||||
>
|
>
|
||||||
{isDeploying ? translate('::ListForms.Wizard.Step4.Log.Deploying') : isDone ? `✓ ${translate('::ListForms.Wizard.Step4.Log.Completed')}` : translate('::ListForms.Wizard.Step4.DeployAndSave')}
|
{translate('::Next') || 'Next'}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<Dialog
|
||||||
|
width={900}
|
||||||
|
height="90vh"
|
||||||
|
isOpen={dialogIndex !== null}
|
||||||
|
preventScroll
|
||||||
|
onClose={() => setDialogIndex(null)}
|
||||||
|
onRequestClose={() => setDialogIndex(null)}
|
||||||
|
>
|
||||||
|
{dialogIndex !== null && (
|
||||||
|
<Formik
|
||||||
|
initialValues={dialogIndex === -1 ? emptySubForm : subForms[dialogIndex]}
|
||||||
|
validationSchema={schema}
|
||||||
|
onSubmit={upsertSubForm}
|
||||||
|
>
|
||||||
|
{({ values, errors, touched }) => (
|
||||||
|
<Form className="flex flex-col h-full">
|
||||||
|
<Dialog.Body className="flex flex-col gap-3 overflow-y-auto">
|
||||||
|
<h5>{dialogIndex === -1 ? 'Add' : 'Update'}</h5>
|
||||||
|
<div className="grid grid-cols-4 gap-4">
|
||||||
|
<FormItem
|
||||||
|
label="Tab Title"
|
||||||
|
invalid={errors.tabTitle && touched.tabTitle}
|
||||||
|
errorMessage={errors.tabTitle}
|
||||||
|
>
|
||||||
|
<Field name="tabTitle" component={Input} />
|
||||||
|
</FormItem>
|
||||||
|
<FormItem
|
||||||
|
label="Code"
|
||||||
|
invalid={errors.code && touched.code}
|
||||||
|
errorMessage={errors.code}
|
||||||
|
>
|
||||||
|
<Field name="code">
|
||||||
|
{({ field, form }: FieldProps<SelectBoxOption>) => (
|
||||||
|
<Select
|
||||||
|
field={field}
|
||||||
|
form={form}
|
||||||
|
isClearable
|
||||||
|
isLoading={isLoadingListForms}
|
||||||
|
options={listFormOptions}
|
||||||
|
value={listFormOptions.find((option) => option.value === values.code)}
|
||||||
|
onChange={(option) => {
|
||||||
|
form.setFieldValue(field.name, option?.value ?? '')
|
||||||
|
form.setFieldValue('relation', [])
|
||||||
|
loadChildFields(option?.value)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
</FormItem>
|
||||||
|
<FormItem
|
||||||
|
label="Tab Type"
|
||||||
|
invalid={errors.tabType && touched.tabType}
|
||||||
|
errorMessage={errors.tabType}
|
||||||
|
>
|
||||||
|
<Field name="tabType">
|
||||||
|
{({ field, form }: FieldProps) => (
|
||||||
|
<Select
|
||||||
|
field={field}
|
||||||
|
form={form}
|
||||||
|
options={tabTypeOptions}
|
||||||
|
value={tabTypeOptions.find((option) => option.value === values.tabType)}
|
||||||
|
onChange={(option: any) =>
|
||||||
|
form.setFieldValue(field.name, option?.value)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
</FormItem>
|
||||||
|
<FormItem label="isRefresh">
|
||||||
|
<Field name="isRefresh" component={Checkbox} />
|
||||||
|
</FormItem>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<FormItem label="Relations">
|
||||||
|
<FieldArray
|
||||||
|
name="relation"
|
||||||
|
render={(arrayHelpers) => (
|
||||||
|
<div>
|
||||||
|
<div className="flex m-1 font-bold text-center">
|
||||||
|
<div className="w-4/12">Parent Field Name</div>
|
||||||
|
<div className="w-4/12">Child Field Name</div>
|
||||||
|
<div className="w-3/12">Db Type</div>
|
||||||
|
<div className="w-1/12" />
|
||||||
|
</div>
|
||||||
|
{values.relation && values.relation.length > 0 ? (
|
||||||
|
values.relation.map((item: SubFormRelationDto, index) => (
|
||||||
|
<div key={index} className="flex m-1">
|
||||||
|
<div className="w-4/12 ml-2">
|
||||||
|
<Field name={`relation.${index}.parentFieldName`}>
|
||||||
|
{({ field, form }: FieldProps<SelectBoxOption>) => (
|
||||||
|
<Select
|
||||||
|
field={field}
|
||||||
|
form={form}
|
||||||
|
isClearable
|
||||||
|
options={parentFieldOptions}
|
||||||
|
value={parentFieldOptions.find(
|
||||||
|
(option) => option.value === item.parentFieldName,
|
||||||
|
)}
|
||||||
|
onChange={(option) => {
|
||||||
|
const column = selectCommandColumns.find(
|
||||||
|
(c) => c.columnName === option?.value,
|
||||||
|
)
|
||||||
|
form.setFieldValue(field.name, option?.value ?? '')
|
||||||
|
form.setFieldValue(
|
||||||
|
`relation.${index}.dbType`,
|
||||||
|
column
|
||||||
|
? sqlDataTypeToDbType(column.dataType)
|
||||||
|
: DbTypeEnum.String,
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="w-4/12 ml-2">
|
||||||
|
<Field name={`relation.${index}.childFieldName`}>
|
||||||
|
{({ field, form }: FieldProps<SelectBoxOption>) => (
|
||||||
|
<Select
|
||||||
|
field={field}
|
||||||
|
form={form}
|
||||||
|
isClearable
|
||||||
|
isLoading={isLoadingChildFields}
|
||||||
|
options={childFieldOptions}
|
||||||
|
value={childFieldOptions.find(
|
||||||
|
(option) => option.value === item.childFieldName,
|
||||||
|
)}
|
||||||
|
onChange={(option) =>
|
||||||
|
form.setFieldValue(field.name, option?.value ?? '')
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="w-3/12 ml-2">
|
||||||
|
<Field name={`relation.${index}.dbType`}>
|
||||||
|
{({ field, form }: FieldProps) => (
|
||||||
|
<Select
|
||||||
|
field={field}
|
||||||
|
form={form}
|
||||||
|
isClearable
|
||||||
|
isDisabled
|
||||||
|
options={dbSourceTypeOptions}
|
||||||
|
value={dbSourceTypeOptions.find(
|
||||||
|
(option: any) => option.value === item.dbType,
|
||||||
|
)}
|
||||||
|
onChange={(option: any) =>
|
||||||
|
form.setFieldValue(field.name, option?.value)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="w-1/12 ml-2 flex items-center">
|
||||||
|
<Button
|
||||||
|
shape="circle"
|
||||||
|
variant="plain"
|
||||||
|
type="button"
|
||||||
|
size="sm"
|
||||||
|
title="Remove"
|
||||||
|
icon={<FaCalendarMinus />}
|
||||||
|
onClick={() => arrayHelpers.remove(index)}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
shape="circle"
|
||||||
|
variant="plain"
|
||||||
|
type="button"
|
||||||
|
size="sm"
|
||||||
|
title="Add"
|
||||||
|
icon={<FaCalendarPlus />}
|
||||||
|
onClick={() => {
|
||||||
|
arrayHelpers.insert(index + 1, {
|
||||||
|
parentFieldName: '',
|
||||||
|
childFieldName: '',
|
||||||
|
dbType: DbTypeEnum.String,
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
shape="circle"
|
||||||
|
variant="plain"
|
||||||
|
type="button"
|
||||||
|
size="sm"
|
||||||
|
title="Add"
|
||||||
|
icon={<FaCalendarPlus />}
|
||||||
|
onClick={() => {
|
||||||
|
arrayHelpers.push({
|
||||||
|
parentFieldName: '',
|
||||||
|
childFieldName: '',
|
||||||
|
dbType: DbTypeEnum.String,
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</FormItem>
|
||||||
|
</Dialog.Body>
|
||||||
|
<Dialog.Footer className="flex justify-end gap-2">
|
||||||
|
<Button type="button" variant="plain" onClick={() => setDialogIndex(null)}>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button type="submit" variant="solid">
|
||||||
|
{translate('::Save')}
|
||||||
|
</Button>
|
||||||
|
</Dialog.Footer>
|
||||||
|
</Form>
|
||||||
|
)}
|
||||||
|
</Formik>
|
||||||
|
)}
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
|
<Dialog
|
||||||
|
isOpen={deleteIndex !== null}
|
||||||
|
onClose={() => setDeleteIndex(null)}
|
||||||
|
onRequestClose={() => setDeleteIndex(null)}
|
||||||
|
>
|
||||||
|
<Dialog.Body>
|
||||||
|
<h5>Delete</h5>
|
||||||
|
<p>Silmek istediğinize emin misiniz?</p>
|
||||||
|
</Dialog.Body>
|
||||||
|
<Dialog.Footer className="flex justify-end gap-2">
|
||||||
|
<Button variant="plain" onClick={() => setDeleteIndex(null)}>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button variant="solid" onClick={removeSubForm}>
|
||||||
|
Delete
|
||||||
|
</Button>
|
||||||
|
</Dialog.Footer>
|
||||||
|
</Dialog>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
355
ui/src/views/admin/listForm/wizard/WizardStep5.tsx
Normal file
355
ui/src/views/admin/listForm/wizard/WizardStep5.tsx
Normal file
|
|
@ -0,0 +1,355 @@
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
Checkbox,
|
||||||
|
Dialog,
|
||||||
|
FormItem,
|
||||||
|
Input,
|
||||||
|
Select,
|
||||||
|
Table,
|
||||||
|
Tooltip,
|
||||||
|
} from '@/components/ui'
|
||||||
|
import TBody from '@/components/ui/Table/TBody'
|
||||||
|
import THead from '@/components/ui/Table/THead'
|
||||||
|
import Td from '@/components/ui/Table/Td'
|
||||||
|
import Th from '@/components/ui/Table/Th'
|
||||||
|
import Tr from '@/components/ui/Table/Tr'
|
||||||
|
import { WidgetEditDto } from '@/proxy/form/models'
|
||||||
|
import SqlEditor from '@/views/developerKit/SqlEditor'
|
||||||
|
import { Field, FieldProps, Form, Formik } from 'formik'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import { FaArrowLeft, FaArrowRight, FaEdit, FaFileMedical, FaTrash } from 'react-icons/fa'
|
||||||
|
import { number, object, string } from 'yup'
|
||||||
|
import { colSpanOptions } from '../edit/options'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
widgets: WidgetEditDto[]
|
||||||
|
translate: (key: string) => string
|
||||||
|
onChange: (widgets: WidgetEditDto[]) => void
|
||||||
|
onBack: () => void
|
||||||
|
onNext: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const schema = object().shape({
|
||||||
|
colGap: number().required(),
|
||||||
|
colSpan: number().required(),
|
||||||
|
sqlQuery: string().required(),
|
||||||
|
title: string().required(),
|
||||||
|
value: string().required(),
|
||||||
|
})
|
||||||
|
|
||||||
|
const emptyWidget: WidgetEditDto = {
|
||||||
|
colGap: 3,
|
||||||
|
colSpan: 3,
|
||||||
|
sqlQuery:
|
||||||
|
"SELECT 'Total Records' as title, COUNT(*) as value, 'blue' as color, 'FaChartBar' as icon, 'Active records' as subTitle FROM YourTable",
|
||||||
|
className: 'mb-3',
|
||||||
|
valueClassName: 'text-3xl',
|
||||||
|
title: 'title',
|
||||||
|
value: 'value',
|
||||||
|
color: 'color',
|
||||||
|
icon: 'icon',
|
||||||
|
subTitle: 'subTitle',
|
||||||
|
onClick: '',
|
||||||
|
isActive: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
function WizardStep5({ widgets, translate, onChange, onBack, onNext }: Props) {
|
||||||
|
const [dialogIndex, setDialogIndex] = useState<number | null>(null)
|
||||||
|
const [deleteIndex, setDeleteIndex] = useState<number | null>(null)
|
||||||
|
|
||||||
|
const upsertWidget = (values: WidgetEditDto) => {
|
||||||
|
const next = [...widgets]
|
||||||
|
if (dialogIndex === -1) next.push(values)
|
||||||
|
else if (dialogIndex !== null) next[dialogIndex] = values
|
||||||
|
onChange(next)
|
||||||
|
setDialogIndex(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeWidget = () => {
|
||||||
|
if (deleteIndex === null) return
|
||||||
|
onChange(widgets.filter((_, index) => index !== deleteIndex))
|
||||||
|
setDeleteIndex(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex h-[calc(100vh-250px)] min-h-[500px] flex-col overflow-hidden">
|
||||||
|
<div className="flex-1 overflow-y-auto pr-1">
|
||||||
|
<Card
|
||||||
|
bodyClass="p-0"
|
||||||
|
header={translate('::ListForms.ListFormEdit.TabWidgets')}
|
||||||
|
headerExtra={translate('::ListForms.ListFormEdit.WidgetsDescription')}
|
||||||
|
>
|
||||||
|
<Table compact>
|
||||||
|
<THead>
|
||||||
|
<Tr>
|
||||||
|
<Th className="text-center min-w-[100px]">
|
||||||
|
<Button
|
||||||
|
shape="circle"
|
||||||
|
variant="plain"
|
||||||
|
type="button"
|
||||||
|
size="sm"
|
||||||
|
title="Add"
|
||||||
|
icon={<FaFileMedical />}
|
||||||
|
onClick={() => setDialogIndex(-1)}
|
||||||
|
/>
|
||||||
|
</Th>
|
||||||
|
<Th>{translate('::ListForms.ListFormEdit.WidgetColGap')}</Th>
|
||||||
|
<Th>{translate('::ListForms.ListFormEdit.EditingFormColumnSpan')}</Th>
|
||||||
|
<Th>{translate('::ListForms.ListFormEdit.SqlQuery')}</Th>
|
||||||
|
<Th>{translate('::ListForms.ListFormEdit.WidgetClassName')}</Th>
|
||||||
|
<Th>{translate('::ListForms.ListFormEdit.WidgetValueClassName')}</Th>
|
||||||
|
<Th>{translate('::Abp.Identity.User.LockoutManagement.Status')}</Th>
|
||||||
|
</Tr>
|
||||||
|
</THead>
|
||||||
|
<TBody>
|
||||||
|
{widgets.map((row, index) => (
|
||||||
|
<Tr key={index}>
|
||||||
|
<Td>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Button
|
||||||
|
shape="circle"
|
||||||
|
variant="plain"
|
||||||
|
type="button"
|
||||||
|
size="sm"
|
||||||
|
title="Edit"
|
||||||
|
icon={<FaEdit />}
|
||||||
|
onClick={() => setDialogIndex(index)}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
shape="circle"
|
||||||
|
variant="plain"
|
||||||
|
type="button"
|
||||||
|
size="sm"
|
||||||
|
title="Delete"
|
||||||
|
icon={<FaTrash />}
|
||||||
|
onClick={() => setDeleteIndex(index)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Td>
|
||||||
|
<Td>{row.colGap}</Td>
|
||||||
|
<Td>{row.colSpan}</Td>
|
||||||
|
<Td className="max-w-[360px] truncate">{row.sqlQuery}</Td>
|
||||||
|
<Td>{row.className}</Td>
|
||||||
|
<Td>{row.valueClassName}</Td>
|
||||||
|
<Td>{row.isActive ? 'Active' : 'Inactive'}</Td>
|
||||||
|
</Tr>
|
||||||
|
))}
|
||||||
|
</TBody>
|
||||||
|
</Table>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="fixed bottom-0 left-0 right-0 z-10 bg-white dark:bg-gray-900 border-t border-gray-200 dark:border-gray-700 px-4 py-2 min-h-16 flex items-center">
|
||||||
|
<div className="flex flex-wrap items-center gap-2 w-full">
|
||||||
|
<Button size="sm" variant="default" type="button" icon={<FaArrowLeft />} onClick={onBack}>
|
||||||
|
{translate('::Back') || 'Back'}
|
||||||
|
</Button>
|
||||||
|
<div className="flex-1 flex items-center justify-end gap-3">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="solid"
|
||||||
|
type="button"
|
||||||
|
icon={<FaArrowRight />}
|
||||||
|
onClick={onNext}
|
||||||
|
>
|
||||||
|
{translate('::Next') || 'Next'}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Dialog
|
||||||
|
width={900}
|
||||||
|
height="90vh"
|
||||||
|
isOpen={dialogIndex !== null}
|
||||||
|
preventScroll
|
||||||
|
onClose={() => setDialogIndex(null)}
|
||||||
|
onRequestClose={() => setDialogIndex(null)}
|
||||||
|
>
|
||||||
|
{dialogIndex !== null && (
|
||||||
|
<Formik
|
||||||
|
initialValues={dialogIndex === -1 ? emptyWidget : widgets[dialogIndex]}
|
||||||
|
validationSchema={schema}
|
||||||
|
onSubmit={upsertWidget}
|
||||||
|
>
|
||||||
|
{({ values, errors, touched, setFieldValue }) => (
|
||||||
|
<Form className="flex flex-col h-full">
|
||||||
|
<Dialog.Body className="flex flex-col gap-3 overflow-y-auto">
|
||||||
|
<h5>{dialogIndex === -1 ? 'Add' : 'Update'}</h5>
|
||||||
|
<div className="grid grid-cols-5 gap-3">
|
||||||
|
<FormItem
|
||||||
|
label="Column Gap"
|
||||||
|
invalid={errors.colGap && touched.colGap}
|
||||||
|
errorMessage={errors.colGap}
|
||||||
|
>
|
||||||
|
<Field type="number" name="colGap" component={Input} />
|
||||||
|
</FormItem>
|
||||||
|
<FormItem
|
||||||
|
label="Column Span"
|
||||||
|
invalid={errors.colSpan && touched.colSpan}
|
||||||
|
errorMessage={errors.colSpan}
|
||||||
|
>
|
||||||
|
<Field name="colSpan">
|
||||||
|
{({ field, form }: FieldProps) => (
|
||||||
|
<Select
|
||||||
|
field={field}
|
||||||
|
form={form}
|
||||||
|
options={colSpanOptions}
|
||||||
|
value={colSpanOptions.find(
|
||||||
|
(option: any) => option.value === values.colSpan,
|
||||||
|
)}
|
||||||
|
onChange={(option: any) =>
|
||||||
|
form.setFieldValue(field.name, option?.value)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
</FormItem>
|
||||||
|
<Tooltip
|
||||||
|
title={
|
||||||
|
<div className="text-xs">
|
||||||
|
<div className="font-semibold mb-1">Widget Container CSS Classes</div>
|
||||||
|
<div>Examples: mb-3, mt-2, p-4, rounded-lg, shadow-md</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<FormItem label="Class Name">
|
||||||
|
<Field name="className" component={Input} />
|
||||||
|
</FormItem>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip
|
||||||
|
title={
|
||||||
|
<div className="text-xs">
|
||||||
|
<div className="font-semibold mb-1">Value Display CSS Classes</div>
|
||||||
|
<div>Examples: text-3xl, text-2xl, font-bold, text-sm</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<FormItem label="Value Class Name">
|
||||||
|
<Field name="valueClassName" component={Input} />
|
||||||
|
</FormItem>
|
||||||
|
</Tooltip>
|
||||||
|
<FormItem label="IsActive">
|
||||||
|
<Field name="isActive" component={Checkbox} />
|
||||||
|
</FormItem>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Tooltip
|
||||||
|
title={
|
||||||
|
<div className="text-xs max-h-96 overflow-y-auto">
|
||||||
|
<div className="font-semibold mb-2">SQL Query Examples:</div>
|
||||||
|
<code className="block rounded bg-gray-800 p-2 text-xs text-white">
|
||||||
|
SELECT 'Aktif' as title, COUNT(Id) as value, 'blue' as color, 'FaChartBar'
|
||||||
|
as icon, 'Aktif kayitlar' as subTitle FROM YourTable
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span className="text-sm font-semibold text-gray-700 dark:text-gray-200">
|
||||||
|
Sql Query
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
<FormItem
|
||||||
|
invalid={errors.sqlQuery && touched.sqlQuery}
|
||||||
|
errorMessage={errors.sqlQuery}
|
||||||
|
>
|
||||||
|
<div className="h-[25vh] min-h-[180px] overflow-hidden rounded-lg border border-gray-200 dark:border-gray-700">
|
||||||
|
<SqlEditor
|
||||||
|
value={values.sqlQuery || ''}
|
||||||
|
onChange={(value) => setFieldValue('sqlQuery', value || '')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</FormItem>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-5 gap-3">
|
||||||
|
<FormItem
|
||||||
|
label="Title Field"
|
||||||
|
invalid={errors.title && touched.title}
|
||||||
|
errorMessage={errors.title}
|
||||||
|
>
|
||||||
|
<Field name="title" component={Input} />
|
||||||
|
</FormItem>
|
||||||
|
<FormItem
|
||||||
|
label="Value Field"
|
||||||
|
invalid={errors.value && touched.value}
|
||||||
|
errorMessage={errors.value}
|
||||||
|
>
|
||||||
|
<Field name="value" component={Input} />
|
||||||
|
</FormItem>
|
||||||
|
<Tooltip
|
||||||
|
title={
|
||||||
|
<div className="grid grid-cols-2 gap-1 text-xs">
|
||||||
|
<div>blue</div>
|
||||||
|
<div>green</div>
|
||||||
|
<div>purple</div>
|
||||||
|
<div>gray</div>
|
||||||
|
<div>red</div>
|
||||||
|
<div>yellow</div>
|
||||||
|
<div>teal</div>
|
||||||
|
<div>orange</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<FormItem label="Color Field">
|
||||||
|
<Field name="color" component={Input} />
|
||||||
|
</FormItem>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip
|
||||||
|
title={
|
||||||
|
<div className="text-xs">
|
||||||
|
<div className="font-semibold mb-1">Popular Font Awesome icons</div>
|
||||||
|
<div>FaChartBar, FaChartLine, FaUsers, FaShoppingCart, FaBell</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<FormItem label="Icon Field">
|
||||||
|
<Field name="icon" component={Input} />
|
||||||
|
</FormItem>
|
||||||
|
</Tooltip>
|
||||||
|
<FormItem label="Sub Title Field">
|
||||||
|
<Field name="subTitle" component={Input} />
|
||||||
|
</FormItem>
|
||||||
|
</div>
|
||||||
|
<FormItem label="On Click">
|
||||||
|
<Field name="onClick" component={Input} />
|
||||||
|
</FormItem>
|
||||||
|
</Dialog.Body>
|
||||||
|
<Dialog.Footer className="flex justify-end gap-2">
|
||||||
|
<Button type="button" variant="plain" onClick={() => setDialogIndex(null)}>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button type="submit" variant="solid">
|
||||||
|
{translate('::Save')}
|
||||||
|
</Button>
|
||||||
|
</Dialog.Footer>
|
||||||
|
</Form>
|
||||||
|
)}
|
||||||
|
</Formik>
|
||||||
|
)}
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
|
<Dialog
|
||||||
|
isOpen={deleteIndex !== null}
|
||||||
|
onClose={() => setDeleteIndex(null)}
|
||||||
|
onRequestClose={() => setDeleteIndex(null)}
|
||||||
|
>
|
||||||
|
<Dialog.Body>
|
||||||
|
<h5>Delete</h5>
|
||||||
|
<p>Silmek istediğinize emin misiniz?</p>
|
||||||
|
</Dialog.Body>
|
||||||
|
<Dialog.Footer className="flex justify-end gap-2">
|
||||||
|
<Button variant="plain" onClick={() => setDeleteIndex(null)}>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button variant="solid" onClick={removeWidget}>
|
||||||
|
Delete
|
||||||
|
</Button>
|
||||||
|
</Dialog.Footer>
|
||||||
|
</Dialog>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default WizardStep5
|
||||||
368
ui/src/views/admin/listForm/wizard/WizardStep6.tsx
Normal file
368
ui/src/views/admin/listForm/wizard/WizardStep6.tsx
Normal file
|
|
@ -0,0 +1,368 @@
|
||||||
|
import { Button, Card, FormContainer, FormItem, Select } from '@/components/ui'
|
||||||
|
import type { DatabaseColumnDto } from '@/proxy/sql-query-manager/models'
|
||||||
|
import { ListFormWorkflowCriteriaDto, WorkflowDto } from '@/proxy/form/models'
|
||||||
|
import { getUsers } from '@/services/identity.service'
|
||||||
|
import type { WorkflowCriteriaDto } from '@/services/workflow.service'
|
||||||
|
import { SelectBoxOption } from '@/types/shared'
|
||||||
|
import {
|
||||||
|
buildFitLayout,
|
||||||
|
emptyCriteria,
|
||||||
|
normalizeCriteria,
|
||||||
|
toCriteriaForm,
|
||||||
|
type WorkflowCriteriaForm,
|
||||||
|
} from '@/utils/workflow/workflowHelpers'
|
||||||
|
import { Field, FieldProps, Form, Formik } from 'formik'
|
||||||
|
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||||
|
import type { FormEvent } from 'react'
|
||||||
|
import { FaArrowLeft, FaArrowRight } from 'react-icons/fa'
|
||||||
|
import { WorkflowDesigner } from '../workflow/WorkflowDesigner'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
listFormCode: string
|
||||||
|
workflow: WorkflowDto
|
||||||
|
criteria: ListFormWorkflowCriteriaDto[]
|
||||||
|
selectCommandColumns: DatabaseColumnDto[]
|
||||||
|
translate: (key: string) => string
|
||||||
|
onWorkflowChange: (workflow: WorkflowDto) => void
|
||||||
|
onCriteriaChange: (criteria: ListFormWorkflowCriteriaDto[]) => void
|
||||||
|
onBack: () => void
|
||||||
|
onNext: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
type PendingLink = {
|
||||||
|
sourceId: string
|
||||||
|
outcome: string
|
||||||
|
} | null
|
||||||
|
|
||||||
|
const toDesignerCriteria = (items: ListFormWorkflowCriteriaDto[]): WorkflowCriteriaDto[] =>
|
||||||
|
items.map((item) => ({
|
||||||
|
...item,
|
||||||
|
nodeId: item.id,
|
||||||
|
compareOutcomes: item.compareOutcomes || [],
|
||||||
|
}))
|
||||||
|
|
||||||
|
const toWizardCriteria = (items: WorkflowCriteriaDto[]): ListFormWorkflowCriteriaDto[] =>
|
||||||
|
items.map(({ nodeId: _nodeId, ...item }) => item)
|
||||||
|
|
||||||
|
const nextId = () => `WF${Date.now()}${Math.floor(Math.random() * 1000)}`
|
||||||
|
|
||||||
|
function WizardStep6({
|
||||||
|
listFormCode,
|
||||||
|
workflow,
|
||||||
|
criteria,
|
||||||
|
selectCommandColumns,
|
||||||
|
translate,
|
||||||
|
onWorkflowChange,
|
||||||
|
onCriteriaChange,
|
||||||
|
onBack,
|
||||||
|
onNext,
|
||||||
|
}: Props) {
|
||||||
|
const [userList, setUserList] = useState<SelectBoxOption[]>([])
|
||||||
|
const [selectedId, setSelectedId] = useState('')
|
||||||
|
const [pendingLink, setPendingLink] = useState<PendingLink>(null)
|
||||||
|
const [criteriaForm, setCriteriaForm] = useState<WorkflowCriteriaForm>(
|
||||||
|
emptyCriteria('Start', listFormCode),
|
||||||
|
)
|
||||||
|
const [dragPreview, setDragPreview] = useState<any>(null)
|
||||||
|
const [canvasZoom, setCanvasZoom] = useState(1)
|
||||||
|
const [designerTab, setDesignerTab] = useState('flow')
|
||||||
|
const canvasRef = useRef<HTMLDivElement | null>(null)
|
||||||
|
|
||||||
|
const currentCriteria = useMemo(() => toDesignerCriteria(criteria), [criteria])
|
||||||
|
const columnOptions: SelectBoxOption[] = selectCommandColumns.map((column) => ({
|
||||||
|
value: column.columnName,
|
||||||
|
label: `${column.columnName} (${column.dataType})`,
|
||||||
|
}))
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getUsers(0, 1000).then((response) => {
|
||||||
|
setUserList(
|
||||||
|
(response.data?.items ?? []).map((user: any) => ({
|
||||||
|
value: user.userName,
|
||||||
|
label: `${user.userName} (${user.name} ${user.surname})`,
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const selected = currentCriteria.find((item) => item.id === selectedId)
|
||||||
|
setCriteriaForm(selected ? toCriteriaForm(selected) : emptyCriteria('Start', listFormCode))
|
||||||
|
}, [currentCriteria, listFormCode, selectedId])
|
||||||
|
|
||||||
|
const updateCriteria = (next: WorkflowCriteriaDto[]) => onCriteriaChange(toWizardCriteria(next))
|
||||||
|
|
||||||
|
const saveCriteria = (event: FormEvent<HTMLFormElement>) => {
|
||||||
|
event.preventDefault()
|
||||||
|
const normalized = normalizeCriteria({ ...criteriaForm, listFormCode })
|
||||||
|
const id = normalized.id || nextId()
|
||||||
|
const nextItem = { ...normalized, id, nodeId: id } as WorkflowCriteriaDto
|
||||||
|
const exists = currentCriteria.some((item) => item.id === id)
|
||||||
|
updateCriteria(
|
||||||
|
exists
|
||||||
|
? currentCriteria.map((item) => (item.id === id ? nextItem : item))
|
||||||
|
: [...currentCriteria, nextItem],
|
||||||
|
)
|
||||||
|
setSelectedId(id)
|
||||||
|
setDesignerTab('flow')
|
||||||
|
}
|
||||||
|
|
||||||
|
const addCriteria = (kind: string) => {
|
||||||
|
const id = nextId()
|
||||||
|
const nextItem = {
|
||||||
|
...normalizeCriteria(emptyCriteria(kind, listFormCode)),
|
||||||
|
id,
|
||||||
|
nodeId: id,
|
||||||
|
positionX: 80 + (currentCriteria.length % 5) * 230,
|
||||||
|
positionY: 220 + Math.floor(currentCriteria.length / 5) * 140,
|
||||||
|
} as WorkflowCriteriaDto
|
||||||
|
updateCriteria([...currentCriteria, nextItem])
|
||||||
|
setSelectedId(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteCriteria = (criteriaId: string = selectedId) => {
|
||||||
|
if (!criteriaId) return
|
||||||
|
updateCriteria(
|
||||||
|
currentCriteria
|
||||||
|
.filter((item) => item.id !== criteriaId)
|
||||||
|
.map((item) => ({
|
||||||
|
...item,
|
||||||
|
nextOnStart: item.nextOnStart === criteriaId ? '' : item.nextOnStart,
|
||||||
|
nextOnTrue: item.nextOnTrue === criteriaId ? '' : item.nextOnTrue,
|
||||||
|
nextOnFalse: item.nextOnFalse === criteriaId ? '' : item.nextOnFalse,
|
||||||
|
nextOnApprove: item.nextOnApprove === criteriaId ? '' : item.nextOnApprove,
|
||||||
|
nextOnReject: item.nextOnReject === criteriaId ? '' : item.nextOnReject,
|
||||||
|
compareOutcomes: (item.compareOutcomes || []).map((outcome) => ({
|
||||||
|
...outcome,
|
||||||
|
targetId: outcome.targetId === criteriaId ? null : outcome.targetId,
|
||||||
|
})),
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
setSelectedId('')
|
||||||
|
}
|
||||||
|
|
||||||
|
const disconnectLink = (sourceId: string, outcome: string) => {
|
||||||
|
updateCriteria(
|
||||||
|
currentCriteria.map((item) => {
|
||||||
|
if (item.id !== sourceId) return item
|
||||||
|
if (outcome.startsWith('compareOutcomes:')) {
|
||||||
|
const index = Number(outcome.split(':')[1])
|
||||||
|
const compareOutcomes = [...(item.compareOutcomes || [])]
|
||||||
|
if (compareOutcomes[index])
|
||||||
|
compareOutcomes[index] = { ...compareOutcomes[index], targetId: null }
|
||||||
|
return { ...item, compareOutcomes }
|
||||||
|
}
|
||||||
|
return { ...item, [outcome]: '' }
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
setPendingLink(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
const connectNodes = (sourceId: string, outcome: string, targetId: string) => {
|
||||||
|
if (sourceId === targetId) return
|
||||||
|
updateCriteria(
|
||||||
|
currentCriteria.map((item) => {
|
||||||
|
if (item.id !== sourceId) return item
|
||||||
|
if (outcome.startsWith('compareOutcomes:')) {
|
||||||
|
const index = Number(outcome.split(':')[1])
|
||||||
|
const compareOutcomes = [...(item.compareOutcomes || [])]
|
||||||
|
compareOutcomes[index] = { ...compareOutcomes[index], targetId }
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
compareOutcomes,
|
||||||
|
nextOnTrue: index === 0 ? targetId : item.nextOnTrue,
|
||||||
|
nextOnFalse: index === 1 ? targetId : item.nextOnFalse,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { ...item, [outcome]: targetId }
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
setPendingLink(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
const fitFlowLayout = () => {
|
||||||
|
const positions = buildFitLayout(currentCriteria)
|
||||||
|
updateCriteria(
|
||||||
|
currentCriteria.map((item) => {
|
||||||
|
const position = positions.get(item.id)
|
||||||
|
return position ? { ...item, positionX: position.x, positionY: position.y } : item
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
setCanvasZoom(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetDemo = () => {
|
||||||
|
const startId = nextId()
|
||||||
|
const approvalId = nextId()
|
||||||
|
const endId = nextId()
|
||||||
|
updateCriteria([
|
||||||
|
{
|
||||||
|
...normalizeCriteria(emptyCriteria('Start', listFormCode)),
|
||||||
|
id: startId,
|
||||||
|
nodeId: startId,
|
||||||
|
nextOnStart: approvalId,
|
||||||
|
positionX: 72,
|
||||||
|
positionY: 160,
|
||||||
|
} as WorkflowCriteriaDto,
|
||||||
|
{
|
||||||
|
...normalizeCriteria(emptyCriteria('Approval', listFormCode)),
|
||||||
|
id: approvalId,
|
||||||
|
nodeId: approvalId,
|
||||||
|
nextOnApprove: endId,
|
||||||
|
positionX: 360,
|
||||||
|
positionY: 160,
|
||||||
|
} as WorkflowCriteriaDto,
|
||||||
|
{
|
||||||
|
...normalizeCriteria(emptyCriteria('End', listFormCode)),
|
||||||
|
id: endId,
|
||||||
|
nodeId: endId,
|
||||||
|
positionX: 650,
|
||||||
|
positionY: 160,
|
||||||
|
} as WorkflowCriteriaDto,
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex h-[calc(100vh-250px)] min-h-[500px] flex-col overflow-hidden">
|
||||||
|
<div className="flex-1 overflow-y-auto pr-1">
|
||||||
|
<Formik
|
||||||
|
initialValues={workflow}
|
||||||
|
enableReinitialize
|
||||||
|
onSubmit={(values) => onWorkflowChange({ ...values, criteria })}
|
||||||
|
>
|
||||||
|
{({ values }) => (
|
||||||
|
<Form>
|
||||||
|
<Card className="mb-4" header={translate('::ListForms.ListFormEdit.TabWorkflow')}>
|
||||||
|
<FormContainer>
|
||||||
|
<div className="grid grid-cols-4 gap-4">
|
||||||
|
{[
|
||||||
|
[
|
||||||
|
'approvalUserFieldName',
|
||||||
|
'::ListForms.ListFormEdit.Workflow.ApprovalUserFieldName',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'approvalStatusFieldName',
|
||||||
|
'::ListForms.ListFormEdit.Workflow.ApprovalStatusFieldName',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'approvalDateFieldName',
|
||||||
|
'::ListForms.ListFormEdit.Workflow.ApprovalDateFieldName',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'approvalDescriptionFieldName',
|
||||||
|
'::ListForms.ListFormEdit.Workflow.ApprovalDescriptionFieldName',
|
||||||
|
],
|
||||||
|
].map(([name, label]) => (
|
||||||
|
<FormItem key={name} label={translate(label)}>
|
||||||
|
<Field name={name}>
|
||||||
|
{({ field, form }: FieldProps) => (
|
||||||
|
<Select
|
||||||
|
field={field}
|
||||||
|
form={form}
|
||||||
|
isClearable
|
||||||
|
options={columnOptions}
|
||||||
|
value={columnOptions.find(
|
||||||
|
(option) => option.value === (values as any)[name],
|
||||||
|
)}
|
||||||
|
onChange={(option: any) => {
|
||||||
|
form.setFieldValue(field.name, option?.value ?? '')
|
||||||
|
onWorkflowChange({
|
||||||
|
...values,
|
||||||
|
[field.name]: option?.value ?? '',
|
||||||
|
criteria,
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
</FormItem>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</FormContainer>
|
||||||
|
</Card>
|
||||||
|
</Form>
|
||||||
|
)}
|
||||||
|
</Formik>
|
||||||
|
|
||||||
|
<WorkflowDesigner
|
||||||
|
busy={false}
|
||||||
|
canvasRef={canvasRef}
|
||||||
|
canvasZoom={canvasZoom}
|
||||||
|
criteriaForm={criteriaForm}
|
||||||
|
currentCriteria={currentCriteria}
|
||||||
|
designerTab={designerTab}
|
||||||
|
dragPreview={dragPreview}
|
||||||
|
pendingLink={pendingLink}
|
||||||
|
selectedCriteriaId={selectedId}
|
||||||
|
userList={userList}
|
||||||
|
selectCommandColumns={selectCommandColumns}
|
||||||
|
isLoadingSelectCommandColumns={false}
|
||||||
|
onAddCriteria={addCriteria}
|
||||||
|
onBeginLink={(sourceId, outcome) => {
|
||||||
|
setPendingLink({ sourceId, outcome })
|
||||||
|
setSelectedId(sourceId)
|
||||||
|
}}
|
||||||
|
onChangeCriteriaForm={setCriteriaForm}
|
||||||
|
onClearSelection={() => {
|
||||||
|
setPendingLink(null)
|
||||||
|
setSelectedId('')
|
||||||
|
}}
|
||||||
|
onConnect={connectNodes}
|
||||||
|
onDeleteCriteria={deleteCriteria}
|
||||||
|
onDeleteLink={disconnectLink}
|
||||||
|
onDragMove={(event: any) =>
|
||||||
|
setDragPreview(event ? { id: event.active.id, delta: event.delta } : null)
|
||||||
|
}
|
||||||
|
onFitLayout={fitFlowLayout}
|
||||||
|
onOpenDetails={(id) => {
|
||||||
|
setSelectedId(id)
|
||||||
|
setDesignerTab('criteria')
|
||||||
|
}}
|
||||||
|
onResetDemo={resetDemo}
|
||||||
|
onSaveCriteria={saveCriteria}
|
||||||
|
onSelectCriteria={setSelectedId}
|
||||||
|
onSetDesignerTab={setDesignerTab}
|
||||||
|
onUpdateNodePosition={(event: any) => {
|
||||||
|
setDragPreview(null)
|
||||||
|
updateCriteria(
|
||||||
|
currentCriteria.map((item) =>
|
||||||
|
item.id === event.active.id
|
||||||
|
? {
|
||||||
|
...item,
|
||||||
|
positionX: Math.max(12, Math.round(item.positionX + event.delta.x)),
|
||||||
|
positionY: Math.max(12, Math.round(item.positionY + event.delta.y)),
|
||||||
|
}
|
||||||
|
: item,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
onZoomIn={() => setCanvasZoom((value) => Math.min(1.6, Number((value + 0.1).toFixed(2))))}
|
||||||
|
onZoomOut={() =>
|
||||||
|
setCanvasZoom((value) => Math.max(0.6, Number((value - 0.1).toFixed(2))))
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="fixed bottom-0 left-0 right-0 z-10 bg-white dark:bg-gray-900 border-t border-gray-200 dark:border-gray-700 px-4 py-2 min-h-16 flex items-center">
|
||||||
|
<div className="flex flex-wrap items-center gap-2 w-full">
|
||||||
|
<Button size="sm" variant="default" type="button" icon={<FaArrowLeft />} onClick={onBack}>
|
||||||
|
{translate('::Back') || 'Back'}
|
||||||
|
</Button>
|
||||||
|
<div className="flex-1 flex items-center justify-end gap-3">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="solid"
|
||||||
|
type="button"
|
||||||
|
icon={<FaArrowRight />}
|
||||||
|
onClick={onNext}
|
||||||
|
>
|
||||||
|
{translate('::Next') || 'Next'}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default WizardStep6
|
||||||
628
ui/src/views/admin/listForm/wizard/WizardStep7.tsx
Normal file
628
ui/src/views/admin/listForm/wizard/WizardStep7.tsx
Normal file
|
|
@ -0,0 +1,628 @@
|
||||||
|
import { Button } from '@/components/ui'
|
||||||
|
import type { DatabaseColumnDto } from '@/proxy/sql-query-manager/models'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import {
|
||||||
|
FaArrowLeft,
|
||||||
|
FaCheckCircle,
|
||||||
|
FaChevronDown,
|
||||||
|
FaChevronRight,
|
||||||
|
FaCircle,
|
||||||
|
FaExclamationCircle,
|
||||||
|
FaRocket,
|
||||||
|
FaSpinner,
|
||||||
|
} from 'react-icons/fa'
|
||||||
|
import { WizardGroup } from './WizardStep3'
|
||||||
|
import { dbSourceTypeOptions, selectCommandTypeOptions } from '../edit/options'
|
||||||
|
import { ListFormWizardDto } from '@/proxy/admin/wizard/models'
|
||||||
|
import {
|
||||||
|
ListFormWorkflowCriteriaDto,
|
||||||
|
SubFormDto,
|
||||||
|
WidgetEditDto,
|
||||||
|
WorkflowDto,
|
||||||
|
} from '@/proxy/form/models'
|
||||||
|
|
||||||
|
// ─── Types ────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
export interface WizardStep7Props {
|
||||||
|
values: ListFormWizardDto
|
||||||
|
wizardName: string
|
||||||
|
selectedColumns: Set<string>
|
||||||
|
selectCommandColumns: DatabaseColumnDto[]
|
||||||
|
groups: WizardGroup[]
|
||||||
|
subForms: SubFormDto[]
|
||||||
|
widgets: WidgetEditDto[]
|
||||||
|
workflow: WorkflowDto
|
||||||
|
workflowCriteria: ListFormWorkflowCriteriaDto[]
|
||||||
|
translate: (key: string) => string
|
||||||
|
onBack: () => void
|
||||||
|
onSubmit: () => Promise<void>
|
||||||
|
}
|
||||||
|
|
||||||
|
type LogStatus = 'pending' | 'running' | 'success' | 'error'
|
||||||
|
|
||||||
|
interface LogEntry {
|
||||||
|
id: number
|
||||||
|
label: string
|
||||||
|
status: LogStatus
|
||||||
|
detail?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── Deploy log steps ─────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
function buildLogSteps(
|
||||||
|
values: ListFormWizardDto,
|
||||||
|
groups: WizardGroup[],
|
||||||
|
translate: (key: string, params?: Record<string, string | number>) => string,
|
||||||
|
): Omit<LogEntry, 'status'>[] {
|
||||||
|
const totalFields = groups.reduce((acc, g) => acc + g.items.length, 0)
|
||||||
|
return [
|
||||||
|
{ id: 1, label: translate('::ListForms.Wizard.Step4.Log.ValidatingConfig') },
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
label: translate('::ListForms.Wizard.Step4.Log.CreatingMenu', { 0: values.menuCode }),
|
||||||
|
detail: `Parent: ${values.menuParentCode}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
label: translate('::ListForms.Wizard.Step4.Log.SavingLanguageTexts'),
|
||||||
|
detail: `EN: ${values.languageTextMenuEn} / TR: ${values.languageTextMenuTr}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
label: translate('::ListForms.Wizard.Step4.Log.ConfiguringPermission', {
|
||||||
|
0: values.permissionGroupName,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
label: translate('::ListForms.Wizard.Step4.Log.ConnectingDataSource', {
|
||||||
|
0: values.dataSourceCode,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
label: translate('::ListForms.Wizard.Step4.Log.CreatingListForm', { 0: values.listFormCode }),
|
||||||
|
detail: `Key: ${values.keyFieldName}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 7,
|
||||||
|
label: translate('::ListForms.Wizard.Step4.Log.SavingFormGroups', {
|
||||||
|
0: groups.length,
|
||||||
|
1: totalFields,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{ id: 8, label: translate('::ListForms.Wizard.Step4.Log.Deploying') },
|
||||||
|
{ id: 9, label: translate('::ListForms.Wizard.Step4.Log.Completed') },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── Mini-components ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
function LogIcon({ status }: { status: LogStatus }) {
|
||||||
|
if (status === 'running') return <FaSpinner className="text-indigo-500 animate-spin shrink-0" />
|
||||||
|
if (status === 'success') return <FaCheckCircle className="text-emerald-500 shrink-0" />
|
||||||
|
if (status === 'error') return <FaExclamationCircle className="text-red-500 shrink-0" />
|
||||||
|
return <FaCircle className="text-gray-300 dark:text-gray-600 shrink-0 text-[8px] mt-1" />
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SectionProps {
|
||||||
|
title: string
|
||||||
|
badge?: string | number
|
||||||
|
children: React.ReactNode
|
||||||
|
defaultOpen?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
function Section({ title, badge, children, defaultOpen = true }: SectionProps) {
|
||||||
|
const [open, setOpen] = useState(defaultOpen)
|
||||||
|
return (
|
||||||
|
<div className="rounded-xl border border-gray-200 dark:border-gray-700 overflow-hidden">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setOpen((v) => !v)}
|
||||||
|
className="w-full flex items-center justify-between px-4 py-2.5 bg-gray-50 dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-750 transition-colors"
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
{open ? (
|
||||||
|
<FaChevronDown className="text-gray-400 text-xs" />
|
||||||
|
) : (
|
||||||
|
<FaChevronRight className="text-gray-400 text-xs" />
|
||||||
|
)}
|
||||||
|
<span className="text-sm font-semibold text-gray-700 dark:text-gray-200">{title}</span>
|
||||||
|
</div>
|
||||||
|
{badge !== undefined && (
|
||||||
|
<span className="text-xs bg-indigo-100 dark:bg-indigo-900/40 text-indigo-600 dark:text-indigo-400 px-2 py-0.5 rounded-full font-medium">
|
||||||
|
{badge}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
{open && <div className="px-4 py-3 bg-white dark:bg-gray-900">{children}</div>}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Row({ label, value }: { label: string; value?: string | number }) {
|
||||||
|
if (!value && value !== 0) return null
|
||||||
|
return (
|
||||||
|
<div className="flex gap-2 py-1 border-b border-gray-100 dark:border-gray-800 last:border-0">
|
||||||
|
<span className="text-xs text-gray-400 w-40 shrink-0">{label}</span>
|
||||||
|
<span className="text-xs text-gray-700 dark:text-gray-200 font-medium break-all">
|
||||||
|
{value}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── WizardStep7 ──────────────────────────────────────────────────────────────
|
||||||
|
const WizardStep7 = ({
|
||||||
|
values,
|
||||||
|
wizardName,
|
||||||
|
selectedColumns,
|
||||||
|
selectCommandColumns,
|
||||||
|
groups,
|
||||||
|
subForms,
|
||||||
|
widgets,
|
||||||
|
workflow,
|
||||||
|
workflowCriteria,
|
||||||
|
translate,
|
||||||
|
onBack,
|
||||||
|
onSubmit,
|
||||||
|
}: WizardStep7Props) => {
|
||||||
|
const [logs, setLogs] = useState<LogEntry[]>([])
|
||||||
|
const [isDeploying, setIsDeploying] = useState(false)
|
||||||
|
const [isDone, setIsDone] = useState(false)
|
||||||
|
const [hasError, setHasError] = useState(false)
|
||||||
|
|
||||||
|
const steps = buildLogSteps(values, groups, translate)
|
||||||
|
|
||||||
|
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms))
|
||||||
|
|
||||||
|
const runDeploy = async () => {
|
||||||
|
if (isDeploying) return
|
||||||
|
setIsDeploying(true)
|
||||||
|
setHasError(false)
|
||||||
|
setIsDone(false)
|
||||||
|
|
||||||
|
// Initialize all as pending
|
||||||
|
setLogs(steps.map((s) => ({ ...s, status: 'pending' })))
|
||||||
|
|
||||||
|
const setStatus = (id: number, status: LogStatus) =>
|
||||||
|
setLogs((prev) => prev.map((l) => (l.id === id ? { ...l, status } : l)))
|
||||||
|
|
||||||
|
// Steps 1-7: pre-deploy simulation (fast)
|
||||||
|
for (let i = 0; i < steps.length - 2; i++) {
|
||||||
|
const step = steps[i]
|
||||||
|
setStatus(step.id, 'running')
|
||||||
|
await sleep(300 + Math.random() * 200)
|
||||||
|
setStatus(step.id, 'success')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 8: actual API call
|
||||||
|
const deployStep = steps[steps.length - 2]
|
||||||
|
setStatus(deployStep.id, 'running')
|
||||||
|
try {
|
||||||
|
await onSubmit()
|
||||||
|
setStatus(deployStep.id, 'success')
|
||||||
|
await sleep(200)
|
||||||
|
// Step 9: done
|
||||||
|
const doneStep = steps[steps.length - 1]
|
||||||
|
setStatus(doneStep.id, 'running')
|
||||||
|
await sleep(300)
|
||||||
|
setStatus(doneStep.id, 'success')
|
||||||
|
setIsDone(true)
|
||||||
|
} catch (err: any) {
|
||||||
|
setStatus(deployStep.id, 'error')
|
||||||
|
setLogs((prev) => [
|
||||||
|
...prev,
|
||||||
|
{
|
||||||
|
id: 999,
|
||||||
|
label: `Hata: ${err?.message ?? 'Bilinmeyen hata'}`,
|
||||||
|
status: 'error',
|
||||||
|
},
|
||||||
|
])
|
||||||
|
setHasError(true)
|
||||||
|
} finally {
|
||||||
|
setIsDeploying(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const totalFields = groups.reduce((acc, g) => acc + g.items.length, 0)
|
||||||
|
const hasWorkflowFields = Boolean(
|
||||||
|
workflow.approvalUserFieldName ||
|
||||||
|
workflow.approvalDateFieldName ||
|
||||||
|
workflow.approvalStatusFieldName ||
|
||||||
|
workflow.approvalDescriptionFieldName,
|
||||||
|
)
|
||||||
|
const workflowItems = workflowCriteria.length > 0 ? workflowCriteria : (workflow.criteria ?? [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="grid grid-cols-[3fr_2fr] gap-5 pb-24 items-start">
|
||||||
|
{/* ── Left: Summary ──────────────────────────────────────────── */}
|
||||||
|
<div className="flex flex-col gap-3">
|
||||||
|
<div className="grid grid-cols-2 gap-3 items-start">
|
||||||
|
<Section title={translate('::ListForms.Wizard.Step4.MenuInfo')}>
|
||||||
|
<Row label={translate('::ListForms.Wizard.Step4.WizardName')} value={wizardName} />
|
||||||
|
<Row label={translate('::ListForms.Wizard.Step4.MenuCode')} value={values.menuCode} />
|
||||||
|
<Row
|
||||||
|
label={translate('::ListForms.Wizard.Step4.MenuParent')}
|
||||||
|
value={values.menuParentCode}
|
||||||
|
/>
|
||||||
|
<Row
|
||||||
|
label={translate('::ListForms.Wizard.Step4.PermissionGroup')}
|
||||||
|
value={values.permissionGroupName}
|
||||||
|
/>
|
||||||
|
<Row label={translate('::App.Listform.ListformField.Icon')} value={values.menuIcon} />
|
||||||
|
<Row
|
||||||
|
label={translate('::ListForms.Wizard.Step4.MenuTr')}
|
||||||
|
value={values.languageTextMenuTr}
|
||||||
|
/>
|
||||||
|
<Row
|
||||||
|
label={translate('::ListForms.Wizard.Step4.MenuEn')}
|
||||||
|
value={values.languageTextMenuEn}
|
||||||
|
/>
|
||||||
|
<Row
|
||||||
|
label={translate('::ListForms.Wizard.Step4.MenuParentTr')}
|
||||||
|
value={values.languageTextMenuParentTr}
|
||||||
|
/>
|
||||||
|
<Row
|
||||||
|
label={translate('::ListForms.Wizard.Step4.MenuParentEn')}
|
||||||
|
value={values.languageTextMenuParentEn}
|
||||||
|
/>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
<Section title={translate('::ListForms.Wizard.Step4.ListFormSettings')}>
|
||||||
|
<Row
|
||||||
|
label={translate('::ListForms.Wizard.Step4.ListFormCode')}
|
||||||
|
value={values.listFormCode}
|
||||||
|
/>
|
||||||
|
<Row
|
||||||
|
label={translate('::ListForms.Wizard.Step4.TitleTr')}
|
||||||
|
value={values.languageTextTitleTr}
|
||||||
|
/>
|
||||||
|
<Row
|
||||||
|
label={translate('::ListForms.Wizard.Step4.TitleEn')}
|
||||||
|
value={values.languageTextTitleEn}
|
||||||
|
/>
|
||||||
|
<Row
|
||||||
|
label={translate('::ListForms.Wizard.Step4.DescTr')}
|
||||||
|
value={values.languageTextDescTr}
|
||||||
|
/>
|
||||||
|
<Row
|
||||||
|
label={translate('::ListForms.Wizard.Step4.DescEn')}
|
||||||
|
value={values.languageTextDescEn}
|
||||||
|
/>
|
||||||
|
<Row
|
||||||
|
label={translate('::ListForms.Wizard.Step4.DataSource')}
|
||||||
|
value={values.dataSourceCode}
|
||||||
|
/>
|
||||||
|
<Row
|
||||||
|
label={translate('::App.Listform.ListformField.ConnectionString')}
|
||||||
|
value={values.dataSourceConnectionString}
|
||||||
|
/>
|
||||||
|
<Row
|
||||||
|
label={translate('::ListForms.Wizard.Step4.CommandType')}
|
||||||
|
value={
|
||||||
|
selectCommandTypeOptions.find((o) => o.value === values.selectCommandType)?.label ||
|
||||||
|
values.selectCommandType
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Row
|
||||||
|
label={translate('::ListForms.Wizard.Step4.SelectCommand')}
|
||||||
|
value={values.selectCommand}
|
||||||
|
/>
|
||||||
|
<Row
|
||||||
|
label={translate('::ListForms.Wizard.Step4.KeyField')}
|
||||||
|
value={values.keyFieldName}
|
||||||
|
/>
|
||||||
|
<Row
|
||||||
|
label={translate('::ListForms.Wizard.Step4.KeyFieldType')}
|
||||||
|
value={
|
||||||
|
dbSourceTypeOptions.find((o: any) => o.value === values.keyFieldDbSourceType)
|
||||||
|
?.label ?? String(values.keyFieldDbSourceType)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Section
|
||||||
|
title={translate('::ListForms.Wizard.Step4.SelectedColumns')}
|
||||||
|
badge={selectedColumns.size}
|
||||||
|
>
|
||||||
|
<div className="flex flex-wrap gap-1.5">
|
||||||
|
{[...selectedColumns].map((col) => {
|
||||||
|
const meta = selectCommandColumns.find((c) => c.columnName === col)
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
key={col}
|
||||||
|
className="inline-flex items-center gap-1 px-2 py-0.5 text-xs rounded-full bg-indigo-50 dark:bg-indigo-900/30 text-indigo-700 dark:text-indigo-300 border border-indigo-200 dark:border-indigo-700"
|
||||||
|
>
|
||||||
|
{col}
|
||||||
|
{meta?.dataType && (
|
||||||
|
<span className="text-[10px] text-indigo-400 opacity-70">{meta.dataType}</span>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
<Section title={translate('::ListForms.Wizard.Step4.FormGroups')} badge={groups.length}>
|
||||||
|
<div className="flex flex-col gap-3">
|
||||||
|
{groups.map((g) => (
|
||||||
|
<Section
|
||||||
|
key={g.id}
|
||||||
|
title={g.caption || `(${translate('::ListForms.Wizard.Step4.StatGroup')})`}
|
||||||
|
badge={`${g.items.length} ${translate('::ListForms.Wizard.Step4.StatField')} · ${g.colCount} ${translate('::App.Listform.ListformField.Column')}`}
|
||||||
|
defaultOpen={false}
|
||||||
|
>
|
||||||
|
<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>
|
||||||
|
) : (
|
||||||
|
g.items.map((item) => (
|
||||||
|
<div
|
||||||
|
key={item.id}
|
||||||
|
className="flex items-center gap-2 py-1 border-b border-gray-100 dark:border-gray-800 last:border-0"
|
||||||
|
>
|
||||||
|
<span className="text-xs font-medium text-indigo-600 dark:text-indigo-400 w-36 shrink-0 truncate">
|
||||||
|
{item.dataField}
|
||||||
|
</span>
|
||||||
|
<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 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>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{subForms.length > 0 && (
|
||||||
|
<Section
|
||||||
|
title={translate('::ListForms.ListFormEdit.SubForms') || 'Sub Forms'}
|
||||||
|
badge={subForms.length}
|
||||||
|
>
|
||||||
|
<div className="flex flex-col gap-3">
|
||||||
|
{subForms.map((subForm, index) => (
|
||||||
|
<div
|
||||||
|
key={`${subForm.code}-${index}`}
|
||||||
|
className="rounded-lg border border-gray-100 dark:border-gray-800 px-3 py-2"
|
||||||
|
>
|
||||||
|
<Row label="Tab Title" value={subForm.tabTitle} />
|
||||||
|
<Row label="List Form Code" value={subForm.code} />
|
||||||
|
<Row label="Tab Type" value={subForm.tabType} />
|
||||||
|
<Row label="Refresh" value={subForm.isRefresh ? 'Active' : 'Inactive'} />
|
||||||
|
{(subForm.relation || []).length > 0 && (
|
||||||
|
<div className="pt-2">
|
||||||
|
<span className="text-xs text-gray-400">Relations</span>
|
||||||
|
<div className="mt-1 flex flex-wrap gap-1.5">
|
||||||
|
{subForm.relation.map((relation, relationIndex) => (
|
||||||
|
<span
|
||||||
|
key={`${relation.parentFieldName}-${relation.childFieldName}-${relationIndex}`}
|
||||||
|
className="rounded bg-gray-100 dark:bg-gray-800 px-2 py-0.5 text-xs text-gray-600 dark:text-gray-300"
|
||||||
|
>
|
||||||
|
{relation.parentFieldName} : {relation.childFieldName}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{widgets.length > 0 && (
|
||||||
|
<Section
|
||||||
|
title={translate('::ListForms.ListFormEdit.TabWidgets') || 'Widgets'}
|
||||||
|
badge={widgets.length}
|
||||||
|
>
|
||||||
|
<div className="flex flex-col gap-3">
|
||||||
|
{widgets.map((widget, index) => (
|
||||||
|
<div
|
||||||
|
key={`${widget.title}-${widget.value}-${index}`}
|
||||||
|
className="rounded-lg border border-gray-100 dark:border-gray-800 px-3 py-2"
|
||||||
|
>
|
||||||
|
<Row label="Title Field" value={widget.title} />
|
||||||
|
<Row label="Value Field" value={widget.value} />
|
||||||
|
<Row label="Color Field" value={widget.color} />
|
||||||
|
<Row label="Icon Field" value={widget.icon} />
|
||||||
|
<Row label="Column Gap" value={widget.colGap} />
|
||||||
|
<Row label="Column Span" value={widget.colSpan} />
|
||||||
|
<Row label="Class Name" value={widget.className} />
|
||||||
|
<Row label="Value Class Name" value={widget.valueClassName} />
|
||||||
|
<Row label="Status" value={widget.isActive ? 'Active' : 'Inactive'} />
|
||||||
|
<Row label="Sql Query" value={widget.sqlQuery} />
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{(hasWorkflowFields || workflowItems.length > 0) && (
|
||||||
|
<Section
|
||||||
|
title={translate('::ListForms.ListFormEdit.TabWorkflow') || 'Workflow'}
|
||||||
|
badge={workflowItems.length}
|
||||||
|
>
|
||||||
|
<div className="grid grid-cols-2 gap-3">
|
||||||
|
<div>
|
||||||
|
<Row label="Approval User" value={workflow.approvalUserFieldName} />
|
||||||
|
<Row label="Approval Date" value={workflow.approvalDateFieldName} />
|
||||||
|
<Row label="Approval Status" value={workflow.approvalStatusFieldName} />
|
||||||
|
<Row label="Approval Description" value={workflow.approvalDescriptionFieldName} />
|
||||||
|
</div>
|
||||||
|
{workflowItems.length > 0 && (
|
||||||
|
<div className="flex flex-col gap-2">
|
||||||
|
{workflowItems.map((criteria, index) => (
|
||||||
|
<div
|
||||||
|
key={criteria.id || index}
|
||||||
|
className="rounded bg-gray-50 dark:bg-gray-800 px-3 py-2"
|
||||||
|
>
|
||||||
|
<div className="text-xs font-semibold text-gray-700 dark:text-gray-200">
|
||||||
|
{criteria.title || criteria.kind || `Criteria ${index + 1}`}
|
||||||
|
</div>
|
||||||
|
<div className="mt-1 text-[11px] text-gray-500 dark:text-gray-400">
|
||||||
|
{criteria.compareColumn} {criteria.compareOperator} {criteria.compareValue}
|
||||||
|
</div>
|
||||||
|
<div className="text-[11px] text-gray-500 dark:text-gray-400">
|
||||||
|
Approver: {criteria.approver}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* ── Right: Deploy ──────────────────────────────────────────── */}
|
||||||
|
<div className="sticky top-4 flex flex-col gap-3 max-h-[calc(100vh-200px)]">
|
||||||
|
{/* Stats */}
|
||||||
|
<div className="grid grid-cols-3 gap-2">
|
||||||
|
{[
|
||||||
|
{ label: translate('::ListForms.Wizard.Step4.StatGroup'), value: groups.length },
|
||||||
|
{ label: translate('::ListForms.Wizard.Step4.StatField'), value: totalFields },
|
||||||
|
{
|
||||||
|
label: translate('::App.Listform.ListformField.Column'),
|
||||||
|
value: selectedColumns.size,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: translate('::ListForms.ListFormEdit.SubForms') || 'Sub Forms',
|
||||||
|
value: subForms.length,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: translate('::ListForms.ListFormEdit.TabWidgets') || 'Widgets',
|
||||||
|
value: widgets.length,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: translate('::ListForms.ListFormEdit.TabWorkflow') || 'Workflow',
|
||||||
|
value: workflowItems.length,
|
||||||
|
},
|
||||||
|
].map((s) => (
|
||||||
|
<div
|
||||||
|
key={s.label}
|
||||||
|
className="rounded-xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 p-3 text-center shadow-sm"
|
||||||
|
>
|
||||||
|
<div className="text-2xl font-bold text-indigo-600 dark:text-indigo-400">
|
||||||
|
{s.value}
|
||||||
|
</div>
|
||||||
|
<div className="text-xs text-gray-400 mt-0.5">{s.label}</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Log panel — grows to fill remaining height */}
|
||||||
|
<div className="rounded-xl border border-gray-200 dark:border-gray-700 overflow-hidden flex flex-col flex-1 min-h-0">
|
||||||
|
<div className="px-4 py-2.5 bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between shrink-0">
|
||||||
|
<span className="text-sm font-semibold text-gray-700 dark:text-gray-200 flex items-center gap-2">
|
||||||
|
<FaRocket className="text-indigo-400 text-xs" />
|
||||||
|
{translate('::ListForms.Wizard.Step4.DeployLog') || 'Deploy Log'}
|
||||||
|
</span>
|
||||||
|
{isDone && (
|
||||||
|
<span className="text-xs text-emerald-500 font-semibold flex items-center gap-1">
|
||||||
|
<FaCheckCircle /> {translate('::ListForms.Wizard.Step4.Success') || 'Başarılı'}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{hasError && (
|
||||||
|
<span className="text-xs text-red-500 font-semibold flex items-center gap-1">
|
||||||
|
<FaExclamationCircle /> {translate('::ListForms.Wizard.Step4.Error') || 'Hata'}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex-1 overflow-y-auto p-4 bg-[#0d1117] dark:bg-black font-mono min-h-[360px]">
|
||||||
|
{logs.length === 0 ? (
|
||||||
|
<div className="flex flex-col items-center justify-center h-full gap-3 py-10 select-none">
|
||||||
|
<FaRocket className="text-gray-700 text-3xl" />
|
||||||
|
<span className="text-xs text-gray-600 italic text-center">
|
||||||
|
{translate('::ListForms.Wizard.Step4.AllInfoReady') || 'Tüm bilgiler hazır.'}
|
||||||
|
<br />
|
||||||
|
{translate('::ListForms.Wizard.Step4.DeployStartHint')}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="flex flex-col gap-2">
|
||||||
|
{logs.map((log) => (
|
||||||
|
<div key={log.id} className="flex items-start gap-2.5">
|
||||||
|
<span className="mt-0.5 shrink-0">
|
||||||
|
<LogIcon status={log.status} />
|
||||||
|
</span>
|
||||||
|
<div>
|
||||||
|
<span
|
||||||
|
className={`text-xs leading-relaxed ${
|
||||||
|
log.status === 'success'
|
||||||
|
? 'text-emerald-400'
|
||||||
|
: log.status === 'error'
|
||||||
|
? 'text-red-400'
|
||||||
|
: log.status === 'running'
|
||||||
|
? 'text-yellow-300'
|
||||||
|
: 'text-gray-600'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{log.label}
|
||||||
|
</span>
|
||||||
|
{log.detail && (
|
||||||
|
<div className="text-[10px] text-gray-600 mt-0.5">{log.detail}</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
{isDone && (
|
||||||
|
<div className="mt-4 rounded-lg border border-emerald-800 bg-emerald-950/40 px-4 py-2.5 text-xs text-emerald-400 text-center font-semibold">
|
||||||
|
🎉 {translate('::ListForms.Wizard.Step4.DeploySuccess')}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* ── Fixed Footer ─────────────────────────────────────────────── */}
|
||||||
|
<div className="fixed bottom-0 left-0 right-0 z-10 bg-white dark:bg-gray-900 border-t border-gray-200 dark:border-gray-700 px-6 py-0 h-16 flex items-center">
|
||||||
|
<div className="flex items-center gap-3 w-full">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="default"
|
||||||
|
type="button"
|
||||||
|
icon={<FaArrowLeft />}
|
||||||
|
onClick={onBack}
|
||||||
|
disabled={isDeploying}
|
||||||
|
>
|
||||||
|
{translate('::Back') || 'Back'}
|
||||||
|
</Button>
|
||||||
|
<div className="flex-1 flex items-center justify-end">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="solid"
|
||||||
|
type="button"
|
||||||
|
icon={<FaRocket />}
|
||||||
|
loading={isDeploying}
|
||||||
|
disabled={isDeploying || isDone}
|
||||||
|
onClick={runDeploy}
|
||||||
|
>
|
||||||
|
{isDeploying
|
||||||
|
? translate('::ListForms.Wizard.Step4.Log.Deploying')
|
||||||
|
: isDone
|
||||||
|
? `✓ ${translate('::ListForms.Wizard.Step4.Log.Completed')}`
|
||||||
|
: translate('::ListForms.Wizard.Step4.DeployAndSave')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default WizardStep7
|
||||||
Loading…
Reference in a new issue