Compare commits
14 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab6a33c340 | ||
|
|
319afbcb13 | ||
|
|
b87d7a94c8 | ||
|
|
95b0b0ce89 | ||
|
|
24e92fcb82 | ||
|
|
412ad236cc | ||
|
|
d38e4f851a | ||
|
|
6174253a40 | ||
|
|
248af7ca1a | ||
|
|
535ed6835f | ||
|
|
4805e8c4d9 | ||
|
|
28ec641275 | ||
|
|
1d05d24e41 | ||
|
|
b53a4243ab |
132 changed files with 11562 additions and 3977 deletions
|
|
@ -10,6 +10,11 @@ namespace Sozsoft.Platform.ListForms;
|
|||
|
||||
public class ColumnFormatDto : AuditedEntityDto<Guid>
|
||||
{
|
||||
private static readonly JsonSerializerOptions EditorOptionsSerializerOptions = new()
|
||||
{
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
|
||||
public ColumnFormatDto() { }
|
||||
|
||||
public string FieldName { get; set; }
|
||||
|
|
@ -240,6 +245,41 @@ public class ColumnFormatDto : AuditedEntityDto<Guid>
|
|||
|
||||
public string Alignment { get; set; }
|
||||
public string Format { get; set; }
|
||||
|
||||
public int? EditOrderNo { get; set; }
|
||||
public int? EditGroupOrderNo { get; set; }
|
||||
public string EditorType2 { get; set; }
|
||||
public int? ColSpan { get; set; }
|
||||
|
||||
public string EditorOptions { get; set; }
|
||||
public GridBoxOptionsDto GridBoxOptions =>
|
||||
DeserializeEditorOptions<GridBoxOptionsDto>(PlatformConsts.EditorTypes.dxGridBox);
|
||||
public TagBoxOptionsDto TagBoxOptions =>
|
||||
DeserializeEditorOptions<TagBoxOptionsDto>(PlatformConsts.EditorTypes.dxTagBox);
|
||||
public ImageUploadOptionsDto ImageUploadOptions =>
|
||||
DeserializeEditorOptions<ImageUploadOptionsDto>(
|
||||
PlatformConsts.EditorTypes.dxImageUpload,
|
||||
PlatformConsts.EditorTypes.dxImageViewer);
|
||||
public string EditorScript { get; set; }
|
||||
|
||||
private T DeserializeEditorOptions<T>(params string[] editorTypes) where T : class
|
||||
{
|
||||
if (!Array.Exists(
|
||||
editorTypes,
|
||||
editorType => string.Equals(EditorType2, editorType, StringComparison.OrdinalIgnoreCase)) ||
|
||||
string.IsNullOrWhiteSpace(EditorOptions))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return JsonSerializer.Deserialize<T>(EditorOptions, EditorOptionsSerializerOptions);
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,35 +16,5 @@ public class EditingFormDto
|
|||
public string Caption { get; set; }
|
||||
public int ColCount { get; set; } = 2;
|
||||
public int ColSpan { get; set; } = 2;
|
||||
/// <summary> Type: Array<Simple Form Item | Group Form Item | Tabbed Form Item | Empty Form Item | Button Form Item>
|
||||
/// Bu kisma suan sadece string olarak doldurulacak
|
||||
/// items: ['FirstName', 'LastName',
|
||||
/// { dataField: 'Notes', editorType: 'dxTextArea', colSpan: 2, editorOptions: { height: 100, }, }
|
||||
/// ],
|
||||
/// </summary>
|
||||
//[TextArea]
|
||||
//public string[] Items { get; set; }
|
||||
public EditingFormItemDto[] Items { get; set; }
|
||||
}
|
||||
|
||||
public class EditingFormItemDto
|
||||
{
|
||||
/// <summary>
|
||||
/// DataField Accepted Values: 'dxAutocomplete' | 'dxCalendar' | 'dxCheckBox' | 'dxColorBox' | 'dxDateBox' | 'dxDateRangeBox' | 'dxDropDownBox' | 'dxHtmlEditor' | 'dxLookup' | 'dxNumberBox' | 'dxRadioGroup' | 'dxRangeSlider' | 'dxSelectBox' | 'dxSlider' | 'dxSwitch' | 'dxTagBox' | 'dxTextArea' | 'dxTextBox' | 'dxImageViewer' | 'dxImageUpload';
|
||||
/// </summary>
|
||||
[JsonPropertyName("order")]
|
||||
public int Order { get; set; }
|
||||
[JsonPropertyName("dataField")]
|
||||
public string DataField { get; set; }
|
||||
[JsonPropertyName("editorType2")]
|
||||
public string EditorType2 { get; set; }
|
||||
[JsonPropertyName("colSpan")]
|
||||
public int ColSpan { get; set; }
|
||||
[JsonPropertyName("editorOptions")]
|
||||
public string EditorOptions { get; set; }
|
||||
public GridBoxOptionsDto GridBoxOptions { get; set; }
|
||||
public TagBoxOptionsDto TagBoxOptions { get; set; }
|
||||
[JsonPropertyName("editorScript")]
|
||||
public string EditorScript { get; set; }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -190,6 +190,19 @@ public class GridOptionsDto : AuditedEntityDto<Guid>
|
|||
set { SchedulerOptionJson = JsonSerializer.Serialize(value); }
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public string TodoOptionJson { get; set; }
|
||||
public TodoOptionDto TodoOptionDto
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!string.IsNullOrEmpty(TodoOptionJson))
|
||||
return JsonSerializer.Deserialize<TodoOptionDto>(TodoOptionJson);
|
||||
return new TodoOptionDto();
|
||||
}
|
||||
set { TodoOptionJson = JsonSerializer.Serialize(value); }
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public string PagerOptionJson { get; set; }
|
||||
public GridPagerOptionDto PagerOptionDto
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
namespace Sozsoft.Platform.ListForms;
|
||||
|
||||
public class ImageUploadOptionsDto
|
||||
{
|
||||
public string UploadUrl { get; set; }
|
||||
public string Accept { get; set; }
|
||||
public bool? Multiple { get; set; }
|
||||
public long? MaxFileSize { get; set; }
|
||||
public int? Width { get; set; }
|
||||
public int? Height { get; set; }
|
||||
}
|
||||
|
|
@ -3,11 +3,13 @@
|
|||
public class LayoutDto
|
||||
{
|
||||
public bool Grid { get; set; } = true;
|
||||
public bool Card { get; set; } = true;
|
||||
public bool Pivot { get; set; } = true;
|
||||
public bool Chart { get; set; } = true;
|
||||
public bool Tree { get; set; } = true;
|
||||
public bool Gantt { get; set; } = true;
|
||||
public bool Scheduler { get; set; } = true;
|
||||
public bool Todo { get; set; } = false;
|
||||
public string DefaultLayout { get; set; } = "grid";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
namespace Sozsoft.Platform.ListForms;
|
||||
|
||||
/// <summary>
|
||||
/// Dinamik bir listeyi Todo/Kanban panosu olarak gostermek icin alan eslemeleri.
|
||||
/// TitleExpr ve StatusExpr zorunlu, diger alanlar opsiyoneldir.
|
||||
/// </summary>
|
||||
public class TodoOptionDto
|
||||
{
|
||||
public string TitleExpr { get; set; }
|
||||
public string StatusExpr { get; set; }
|
||||
public string DescriptionExpr { get; set; }
|
||||
public string DueDateExpr { get; set; }
|
||||
public string TagExpr { get; set; }
|
||||
public string AssigneeExpr { get; set; }
|
||||
public string PriorityExpr { get; set; }
|
||||
public string CompletedExpr { get; set; }
|
||||
public string OrderExpr { get; set; }
|
||||
public string StatusOrder { get; set; }
|
||||
public bool AllowDragging { get; set; } = true;
|
||||
}
|
||||
|
|
@ -5,10 +5,10 @@ namespace Sozsoft.Platform.ListForms;
|
|||
public class WorkflowDto
|
||||
{
|
||||
public string ApprovalUserFieldName { get; set; }
|
||||
public bool IsFilterUserName { get; set; }
|
||||
public string ApprovalDateFieldName { get; set; }
|
||||
public string ApprovalStatusFieldName { get; set; }
|
||||
public string ApprovalDescriptionFieldName { get; set; }
|
||||
public bool ApprovalIsFilterUserName { get; set; }
|
||||
|
||||
public List<ListFormWorkflowCriteriaDto> Criteria { get; set; } = [];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ public class ListFormEditTabs
|
|||
public const string TreeForm = "tree";
|
||||
public const string GanttForm = "gantt";
|
||||
public const string SchedulerForm = "scheduler";
|
||||
public const string TodoForm = "todo";
|
||||
public const string PagerForm = "pager";
|
||||
public const string StateForm = "state";
|
||||
public const string SubFormJsonRow = "subForm";
|
||||
|
|
|
|||
|
|
@ -22,11 +22,13 @@ public class ListFormWizardDto
|
|||
|
||||
public string DefaultLayout { get; set; }
|
||||
public bool Grid { get; set; }
|
||||
public bool Card { get; set; }
|
||||
public bool Pivot { get; set; }
|
||||
public bool Tree { get; set; }
|
||||
public bool Chart { get; set; }
|
||||
public bool Gantt { get; set; }
|
||||
public bool Scheduler { get; set; }
|
||||
public bool Todo { get; set; }
|
||||
|
||||
public string LanguageTextMenuEn { get; set; }
|
||||
public string LanguageTextMenuTr { get; set; }
|
||||
|
|
@ -39,6 +41,7 @@ public class ListFormWizardDto
|
|||
|
||||
public string PermissionGroupName { get; set; }
|
||||
public string MenuParentCode { get; set; }
|
||||
public string MenuParentShortName { get; set; }
|
||||
public string MenuParentIcon { get; set; }
|
||||
public string MenuIcon { get; set; }
|
||||
public string DataSourceCode { get; set; }
|
||||
|
|
@ -68,9 +71,28 @@ public class ListFormWizardDto
|
|||
public string SchedulerStartDateExpr { get; set; }
|
||||
public string SchedulerEndDateExpr { get; set; }
|
||||
|
||||
// Todo options (required when DefaultLayout = "todo")
|
||||
public string TodoTitleExpr { get; set; }
|
||||
public string TodoStatusExpr { get; set; }
|
||||
public string TodoDescriptionExpr { get; set; }
|
||||
public string TodoDueDateExpr { get; set; }
|
||||
public string TodoTagExpr { get; set; }
|
||||
public string TodoAssigneeExpr { get; set; }
|
||||
public string TodoPriorityExpr { get; set; }
|
||||
public string TodoCompletedExpr { get; set; }
|
||||
public string TodoOrderExpr { get; set; }
|
||||
public string TodoStatusOrder { get; set; }
|
||||
public bool TodoAllowDragging { get; set; } = true;
|
||||
|
||||
// Workflow options (required when DefaultLayout = "workflow")
|
||||
public string ApprovalUserFieldName { get; set; }
|
||||
public string ApprovalDateFieldName { get; set; }
|
||||
public string ApprovalStatusFieldName { get; set; }
|
||||
public string ApprovalDescriptionFieldName { get; set; }
|
||||
public bool ApprovalIsFilterUserName { get; set; }
|
||||
public List<ListFormWorkflowCriteriaDto> Criteria { get; set; } = [];
|
||||
|
||||
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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ namespace Sozsoft.Platform.ListForms;
|
|||
|
||||
public class WizardColumnItemInputDto
|
||||
{
|
||||
public string DataField { get; set; }
|
||||
public string FieldName { get; set; }
|
||||
public string CaptionName { get; set; }
|
||||
public string EditorType { get; set; }
|
||||
public string EditorOptions { get; set; }
|
||||
|
|
|
|||
|
|
@ -185,6 +185,7 @@ public static class LookupQueryValues
|
|||
$"LEFT OUTER JOIN \"{FullNameTable(TableNameEnum.LanguageText)}\" " +
|
||||
$"ON \"{FullNameTable(TableNameEnum.Product)}\".\"Name\" = \"{FullNameTable(TableNameEnum.LanguageText)}\".\"Key\" " +
|
||||
$"WHERE \"{FullNameTable(TableNameEnum.Product)}\".\"IsDeleted\" = 'false' " +
|
||||
$"AND \"{FullNameTable(TableNameEnum.LanguageText)}\".\"CultureName\" = 'tr' " +
|
||||
$"ORDER BY \"{FullNameTable(TableNameEnum.LanguageText)}\".\"Value\";";
|
||||
|
||||
public static string MenuCodeValues =
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using Volo.Abp.Application.Services;
|
|||
using Volo.Abp.Domain.Repositories;
|
||||
using System.Threading.Tasks;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Sozsoft.Platform.AiBots;
|
||||
|
||||
|
|
@ -25,16 +26,31 @@ public class AiBotAppService : CrudAppService<
|
|||
{
|
||||
await CheckGetListPolicyAsync();
|
||||
|
||||
var query = await CreateFilteredQueryAsync(input);
|
||||
|
||||
if (CurrentTenant.IsAvailable && !string.IsNullOrWhiteSpace(CurrentTenant.Name))
|
||||
{
|
||||
var tenantName = CurrentTenant.Name;
|
||||
query = query.Where(aiBot =>
|
||||
string.IsNullOrWhiteSpace(aiBot.Tenants) ||
|
||||
aiBot.Tenants.Contains($"\"{tenantName}\""));
|
||||
List<AiBot> tenantEntities;
|
||||
|
||||
using (CurrentTenant.Change(null))
|
||||
{
|
||||
var hostQuery = await CreateFilteredQueryAsync(input);
|
||||
tenantEntities = await AsyncExecuter.ToListAsync(hostQuery);
|
||||
}
|
||||
|
||||
var filteredQuery = tenantEntities
|
||||
.Where(aiBot => IsAvailableForTenant(aiBot.Tenants, tenantName))
|
||||
.AsQueryable();
|
||||
|
||||
var tenantTotalCount = filteredQuery.LongCount();
|
||||
filteredQuery = ApplySorting(filteredQuery, input);
|
||||
filteredQuery = ApplyPaging(filteredQuery, input);
|
||||
|
||||
var tenantDtos = await MapToGetListOutputDtosAsync(filteredQuery.ToList());
|
||||
|
||||
return new PagedResultDto<AiBotDto>(tenantTotalCount, tenantDtos);
|
||||
}
|
||||
|
||||
var query = await CreateFilteredQueryAsync(input);
|
||||
var totalCount = await AsyncExecuter.CountAsync(query);
|
||||
query = ApplySorting(query, input);
|
||||
query = ApplyPaging(query, input);
|
||||
|
|
@ -44,5 +60,17 @@ public class AiBotAppService : CrudAppService<
|
|||
|
||||
return new PagedResultDto<AiBotDto>(totalCount, dtos);
|
||||
}
|
||||
|
||||
private static bool IsAvailableForTenant(string tenants, string tenantName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(tenants))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return tenants
|
||||
.Split('|', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
||||
.Any(name => string.Equals(name, tenantName, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,26 +47,33 @@ public class ListFormFieldsAppService : CrudAppService<
|
|||
|
||||
protected override void MapToEntity(ColumnFormatEditDto updateInput, ListFormField entity)
|
||||
{
|
||||
entity.CultureName = updateInput.CultureName;
|
||||
entity.RoleId = updateInput.RoleId;
|
||||
entity.ListFormCode = updateInput.ListFormCode;
|
||||
entity.FieldName = updateInput.FieldName;
|
||||
entity.CultureName = updateInput.CultureName;
|
||||
entity.CaptionName = updateInput.CaptionName;
|
||||
entity.PlaceHolder = updateInput.PlaceHolder;
|
||||
entity.BandName = updateInput.BandName;
|
||||
entity.IsActive = updateInput.IsActive;
|
||||
entity.Visible = updateInput.Visible;
|
||||
entity.AllowSearch = updateInput.AllowSearch;
|
||||
entity.AllowEditing = updateInput.AllowEditing;
|
||||
entity.AllowAdding = updateInput.AllowAdding;
|
||||
entity.ListOrderNo = updateInput.ListOrderNo;
|
||||
entity.SourceDbType = updateInput.SourceDbType;
|
||||
entity.Alignment = updateInput.Alignment;
|
||||
entity.Format = updateInput.Format;
|
||||
entity.EditorOptions = updateInput.EditorOptions;
|
||||
entity.EditorScript = updateInput.EditorScript;
|
||||
entity.ListOrderNo = updateInput.ListOrderNo;
|
||||
entity.Width = updateInput.Width;
|
||||
entity.SortDirection = updateInput.SortDirection;
|
||||
entity.SortIndex = updateInput.SortIndex;
|
||||
entity.Format = updateInput.Format;
|
||||
entity.Alignment = updateInput.Alignment;
|
||||
entity.EditorOptions = updateInput.EditorOptions;
|
||||
entity.EditOrderNo = updateInput.EditOrderNo;
|
||||
entity.EditGroupOrderNo = updateInput.EditGroupOrderNo;
|
||||
entity.ColSpan = updateInput.ColSpan;
|
||||
entity.EditorType2 = updateInput.EditorType2;
|
||||
entity.AllowEditing = updateInput.AllowEditing;
|
||||
entity.AllowAdding = updateInput.AllowAdding;
|
||||
entity.PermissionJson = JsonSerializer.Serialize(updateInput.PermissionDto);
|
||||
entity.LookupJson = JsonSerializer.Serialize(updateInput.LookupDto);
|
||||
entity.ColumnCustomizationJson = JsonSerializer.Serialize(updateInput.ColumnCustomizationDto);
|
||||
entity.ColumnFilterJson = JsonSerializer.Serialize(updateInput.ColumnFilterDto);
|
||||
entity.ColumnHeaderJson = JsonSerializer.Serialize(updateInput.ColumnHeaderDto);
|
||||
|
|
@ -74,12 +81,10 @@ public class ListFormFieldsAppService : CrudAppService<
|
|||
entity.GroupSummaryJson = updateInput.ColumnGroupSummaryDto.SummaryType.IsNullOrEmpty() ? "" : JsonSerializer.Serialize(updateInput.ColumnGroupSummaryDto);
|
||||
entity.TotalSummaryJson = updateInput.ColumnTotalSummaryDto.SummaryType.IsNullOrEmpty() ? "" : JsonSerializer.Serialize(updateInput.ColumnTotalSummaryDto);
|
||||
entity.JoinTableJson = JsonSerializer.Serialize(updateInput.ColumnJoinTableDto);
|
||||
entity.LookupJson = JsonSerializer.Serialize(updateInput.LookupDto);
|
||||
entity.ColumnCssClass = updateInput.ColumnCssClass;
|
||||
entity.ColumnCssValue = updateInput.ColumnCssValue;
|
||||
entity.ValidationRuleJson = JsonSerializer.Serialize(updateInput.ValidationRuleDto);
|
||||
entity.ColumnStylingJson = JsonSerializer.Serialize(updateInput.ColumnStylingDto);
|
||||
entity.PermissionJson = JsonSerializer.Serialize(updateInput.PermissionDto);
|
||||
entity.PivotSettingsJson = JsonSerializer.Serialize(updateInput.PivotSettingsDto);
|
||||
}
|
||||
|
||||
|
|
@ -136,6 +141,9 @@ public class ListFormFieldsAppService : CrudAppService<
|
|||
item.Alignment = input.Alignment;
|
||||
item.Format = input.Format;
|
||||
item.EditorOptions = input.EditorOptions;
|
||||
item.IsActive = input.IsActive;
|
||||
item.Visible = input.Visible;
|
||||
item.AllowSearch = input.AllowSearch;
|
||||
}
|
||||
else if (input.EditType == ListFormFieldEditTabs.PermissionsForm)
|
||||
{
|
||||
|
|
@ -152,6 +160,11 @@ public class ListFormFieldsAppService : CrudAppService<
|
|||
item.AllowSearch = input.AllowSearch;
|
||||
item.AllowEditing = input.AllowEditing;
|
||||
item.AllowAdding = input.AllowAdding;
|
||||
item.EditGroupOrderNo = input.EditGroupOrderNo;
|
||||
item.EditOrderNo = input.EditOrderNo;
|
||||
item.ColSpan = input.ColSpan;
|
||||
item.EditorType2 = input.EditorType2;
|
||||
item.EditorScript = input.EditorScript;
|
||||
}
|
||||
else if (input.EditType == ListFormFieldEditTabs.CustomizationForm)
|
||||
{
|
||||
|
|
@ -257,6 +270,9 @@ public class ListFormFieldsAppService : CrudAppService<
|
|||
field.CaptionName = sourceField.CaptionName;
|
||||
field.PlaceHolder = sourceField.PlaceHolder;
|
||||
field.SourceDbType = sourceField.SourceDbType;
|
||||
field.Alignment = sourceField.Alignment;
|
||||
field.Format = sourceField.Format;
|
||||
field.EditorOptions = sourceField.EditorOptions;
|
||||
}
|
||||
if (input.CopiedFields.All || input.CopiedFields.Options)
|
||||
{
|
||||
|
|
@ -269,35 +285,40 @@ public class ListFormFieldsAppService : CrudAppService<
|
|||
field.AllowSearch = sourceField.AllowSearch;
|
||||
field.AllowEditing = sourceField.AllowEditing;
|
||||
field.AllowAdding = sourceField.AllowAdding;
|
||||
field.EditGroupOrderNo = sourceField.EditGroupOrderNo;
|
||||
field.EditOrderNo = sourceField.EditOrderNo;
|
||||
field.ColSpan = sourceField.ColSpan;
|
||||
field.EditorType2 = sourceField.EditorType2;
|
||||
field.EditorScript = sourceField.EditorScript;
|
||||
}
|
||||
else if (input.CopiedFields.All || input.CopiedFields.Permission)
|
||||
if (input.CopiedFields.All || input.CopiedFields.Permission)
|
||||
{
|
||||
field.PermissionJson = sourceField.PermissionJson;
|
||||
}
|
||||
else if (input.CopiedFields.All || input.CopiedFields.Customization)
|
||||
if (input.CopiedFields.All || input.CopiedFields.Customization)
|
||||
field.ColumnCustomizationJson = sourceField.ColumnCustomizationJson;
|
||||
else if (input.CopiedFields.All || input.CopiedFields.Filtering)
|
||||
if (input.CopiedFields.All || input.CopiedFields.Filtering)
|
||||
field.ColumnFilterJson = sourceField.ColumnFilterJson;
|
||||
else if (input.CopiedFields.All || input.CopiedFields.Headering)
|
||||
if (input.CopiedFields.All || input.CopiedFields.Headering)
|
||||
field.ColumnHeaderJson = sourceField.ColumnHeaderJson;
|
||||
else if (input.CopiedFields.All || input.CopiedFields.Grouping)
|
||||
if (input.CopiedFields.All || input.CopiedFields.Grouping)
|
||||
field.GroupingJson = sourceField.GroupingJson;
|
||||
else if (input.CopiedFields.All || input.CopiedFields.GroupSummary)
|
||||
if (input.CopiedFields.All || input.CopiedFields.GroupSummary)
|
||||
field.GroupSummaryJson = sourceField.GroupSummaryJson;
|
||||
else if (input.CopiedFields.All || input.CopiedFields.TotalSummary)
|
||||
if (input.CopiedFields.All || input.CopiedFields.TotalSummary)
|
||||
field.TotalSummaryJson = sourceField.TotalSummaryJson;
|
||||
else if (input.CopiedFields.All || input.CopiedFields.JoinOptions)
|
||||
if (input.CopiedFields.All || input.CopiedFields.JoinOptions)
|
||||
field.JoinTableJson = sourceField.JoinTableJson;
|
||||
else if (input.CopiedFields.All || input.CopiedFields.CssOptions)
|
||||
if (input.CopiedFields.All || input.CopiedFields.CssOptions)
|
||||
{
|
||||
field.ColumnCssClass = sourceField.ColumnCssClass;
|
||||
field.ColumnCssValue = sourceField.ColumnCssValue;
|
||||
}
|
||||
else if (input.CopiedFields.All || input.CopiedFields.ValidationRules)
|
||||
if (input.CopiedFields.All || input.CopiedFields.ValidationRules)
|
||||
field.ValidationRuleJson = sourceField.ValidationRuleJson;
|
||||
else if (input.CopiedFields.All || input.CopiedFields.Formatting)
|
||||
if (input.CopiedFields.All || input.CopiedFields.Formatting)
|
||||
field.ColumnStylingJson = sourceField.ColumnStylingJson;
|
||||
else if (input.CopiedFields.All || input.CopiedFields.PivotSetting)
|
||||
if (input.CopiedFields.All || input.CopiedFields.PivotSetting)
|
||||
field.PivotSettingsJson = sourceField.PivotSettingsJson;
|
||||
|
||||
await Repository.InsertAsync(field);
|
||||
|
|
|
|||
|
|
@ -166,6 +166,10 @@ public class ListFormsAppService : CrudAppService<
|
|||
{
|
||||
item.SchedulerOptionJson = JsonSerializer.Serialize(input.SchedulerOptionDto);
|
||||
}
|
||||
else if (input.EditType == ListFormEditTabs.TodoForm)
|
||||
{
|
||||
item.TodoOptionJson = JsonSerializer.Serialize(input.TodoOptionDto);
|
||||
}
|
||||
else if (input.EditType == ListFormEditTabs.PagerForm)
|
||||
{
|
||||
item.PageSize = input.PageSize;
|
||||
|
|
|
|||
|
|
@ -180,11 +180,18 @@ public class ListFormWizardAppService(
|
|||
Code = input.MenuParentCode,
|
||||
DisplayName = input.MenuParentCode,
|
||||
IsDisabled = false,
|
||||
ShortName = input.MenuParentShortName?.Trim(),
|
||||
Icon = menuParentIcon,
|
||||
Order = maxRootOrder + 1,
|
||||
}, autoSave: false);
|
||||
inserted.MenuCodes.Add(input.MenuParentCode);
|
||||
}
|
||||
else if (string.IsNullOrWhiteSpace(menuParent.ShortName) &&
|
||||
!string.IsNullOrWhiteSpace(input.MenuParentShortName))
|
||||
{
|
||||
menuParent.ShortName = input.MenuParentShortName.Trim();
|
||||
await repoMenu.UpdateAsync(menuParent, autoSave: false);
|
||||
}
|
||||
|
||||
//Menu
|
||||
var maxChildOrder = menuQueryable.Where(a => a.ParentCode == menuParent.Code).Select(a => (int?)a.Order).Max() ?? 0;
|
||||
|
|
@ -230,21 +237,9 @@ public class ListFormWizardAppService(
|
|||
Caption = g.Caption,
|
||||
ColCount = g.ColCount,
|
||||
ColSpan = g.ColCount,
|
||||
ItemType = "group",
|
||||
Items = g.Items
|
||||
.Where(i => i.IncludeInEditingForm && i.DataField != input.KeyFieldName)
|
||||
.Select((it, ii) => new EditingFormItemDto
|
||||
{
|
||||
Order = ii + 1,
|
||||
DataField = it.DataField,
|
||||
EditorType2 = it.EditorType,
|
||||
ColSpan = it.ColSpan,
|
||||
EditorOptions = string.IsNullOrWhiteSpace(it.EditorOptions) ? null : it.EditorOptions,
|
||||
EditorScript = string.IsNullOrWhiteSpace(it.EditorScript) ? null : it.EditorScript,
|
||||
})
|
||||
.ToArray()
|
||||
ItemType = "group"
|
||||
})
|
||||
.Where(g => g.Items.Length > 0)
|
||||
.Where((_, index) => input.Groups[index].Items.Any(i => i.IncludeInEditingForm && i.FieldName != input.KeyFieldName))
|
||||
.ToList();
|
||||
|
||||
//ListForm - varsa sil, yeniden ekle
|
||||
|
|
@ -269,10 +264,18 @@ public class ListFormWizardAppService(
|
|||
var tableColumns = await GetTableColumnNamesAsync(input.DataSourceCode, input.SelectCommandType, input.SelectCommand);
|
||||
var isDeleted = tableColumns.Contains("IsDeleted");
|
||||
var isCreated = tableColumns.Contains("CreatorId");
|
||||
input.Workflow ??= new WorkflowDto();
|
||||
input.Workflow.Criteria = input.WorkflowCriteria;
|
||||
EnsureUniqueWorkflowCriteriaTitles(input.WorkflowCriteria);
|
||||
NormalizeWorkflowCriteriaIds(listFormCode, input.WorkflowCriteria);
|
||||
input.Criteria ??= [];
|
||||
EnsureUniqueWorkflowCriteriaTitles(input.Criteria);
|
||||
NormalizeWorkflowCriteriaIds(listFormCode, input.Criteria);
|
||||
var workflow = new WorkflowDto
|
||||
{
|
||||
ApprovalUserFieldName = input.ApprovalUserFieldName,
|
||||
ApprovalIsFilterUserName = input.ApprovalIsFilterUserName,
|
||||
ApprovalDateFieldName = input.ApprovalDateFieldName,
|
||||
ApprovalStatusFieldName = input.ApprovalStatusFieldName,
|
||||
ApprovalDescriptionFieldName = input.ApprovalDescriptionFieldName,
|
||||
Criteria = input.Criteria,
|
||||
};
|
||||
|
||||
await repoListForm.InsertAsync(new ListForm
|
||||
{
|
||||
|
|
@ -280,8 +283,8 @@ public class ListFormWizardAppService(
|
|||
PageSize = 10,
|
||||
ExportJson = WizardConsts.DefaultExportJson,
|
||||
IsSubForm = false,
|
||||
ShowNote = input.SubForms.Count > 0 || input.WorkflowCriteria.Count > 0,
|
||||
LayoutJson = WizardConsts.DefaultLayoutJson(input.DefaultLayout, input.Grid, input.Pivot, input.Tree, input.Chart, input.Gantt, input.Scheduler),
|
||||
ShowNote = input.SubForms.Count > 0 || input.Criteria.Count > 0,
|
||||
LayoutJson = WizardConsts.DefaultLayoutJson(input.DefaultLayout, input.Grid, input.Card, input.Pivot, input.Tree, input.Chart, input.Gantt, input.Scheduler, input.Todo),
|
||||
CultureName = LanguageCodes.En,
|
||||
ListFormCode = input.ListFormCode,
|
||||
Name = nameLangKey,
|
||||
|
|
@ -301,18 +304,18 @@ public class ListFormWizardAppService(
|
|||
HeaderFilterJson = WizardConsts.DefaultHeaderFilterJson(),
|
||||
SearchPanelJson = WizardConsts.DefaultSearchPanelJson(),
|
||||
GroupPanelJson = WizardConsts.DefaultGroupPanelJson(),
|
||||
SelectionJson = WizardConsts.DefaultSelectionSingleJson(input.WorkflowCriteria.Count > 0 ? PlatformConsts.GridOptions.SelectionModeSingle : PlatformConsts.GridOptions.SelectionModeNone),
|
||||
SelectionJson = WizardConsts.DefaultSelectionSingleJson(input.Criteria.Count > 0 ? PlatformConsts.GridOptions.SelectionModeSingle : PlatformConsts.GridOptions.SelectionModeNone),
|
||||
ColumnOptionJson = WizardConsts.DefaultColumnOptionJson(),
|
||||
PermissionJson = WizardConsts.DefaultPermissionJson(code),
|
||||
DeleteCommand = isDeleted ? WizardConsts.DefaultDeleteCommand(input.SelectCommand) : null,
|
||||
DeleteFieldsDefaultValueJson = isDeleted ? WizardConsts.DefaultDeleteFieldsDefaultValueJson(input.KeyFieldDbSourceType) : WizardConsts.DefaultFieldsJsonOnlyId(input.KeyFieldDbSourceType),
|
||||
InsertFieldsDefaultValueJson = isCreated ? WizardConsts.DefaultInsertFieldsDefaultValueJson(input.KeyFieldDbSourceType) : WizardConsts.DefaultFieldsJsonOnlyId(input.KeyFieldDbSourceType),
|
||||
DeleteFieldsDefaultValueJson = isDeleted ? WizardConsts.DefaultDeleteFieldsDefaultValueJson(input.KeyFieldDbSourceType) : WizardConsts.DefaultDeleteFieldsJsonOnlyId(input.KeyFieldDbSourceType),
|
||||
InsertFieldsDefaultValueJson = isCreated ? WizardConsts.DefaultInsertFieldsDefaultValueJson(input.KeyFieldDbSourceType) : WizardConsts.DefaultInsertFieldsJsonOnlyId(input.KeyFieldDbSourceType),
|
||||
PagerOptionJson = WizardConsts.DefaultPagerOptionJson,
|
||||
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,
|
||||
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,
|
||||
WorkflowJson = HasWorkflow(workflow, input.Criteria) ? JsonSerializer.Serialize(workflow) : null,
|
||||
TreeOptionJson = (input.Tree || input.DefaultLayout == "tree") && !string.IsNullOrEmpty(input.TreeParentIdExpr)
|
||||
? JsonSerializer.Serialize(new TreeOptionDto
|
||||
{
|
||||
|
|
@ -341,25 +344,58 @@ public class ListFormWizardAppService(
|
|||
EndDateExpr = input.SchedulerEndDateExpr,
|
||||
})
|
||||
: null,
|
||||
TodoOptionJson = (input.Todo || input.DefaultLayout == "todo") &&
|
||||
!string.IsNullOrEmpty(input.TodoTitleExpr) &&
|
||||
!string.IsNullOrEmpty(input.TodoStatusExpr)
|
||||
? JsonSerializer.Serialize(new TodoOptionDto
|
||||
{
|
||||
TitleExpr = input.TodoTitleExpr,
|
||||
StatusExpr = input.TodoStatusExpr,
|
||||
DescriptionExpr = input.TodoDescriptionExpr,
|
||||
DueDateExpr = input.TodoDueDateExpr,
|
||||
TagExpr = input.TodoTagExpr,
|
||||
AssigneeExpr = input.TodoAssigneeExpr,
|
||||
PriorityExpr = input.TodoPriorityExpr,
|
||||
CompletedExpr = input.TodoCompletedExpr,
|
||||
OrderExpr = input.TodoOrderExpr,
|
||||
StatusOrder = input.TodoStatusOrder,
|
||||
AllowDragging = input.TodoAllowDragging,
|
||||
})
|
||||
: null,
|
||||
}, autoSave: true);
|
||||
|
||||
// ListFormField - each item in each group becomes a visible field record
|
||||
var fieldOrder = 0;
|
||||
var editGroupOrder = 0;
|
||||
foreach (var group in input.Groups)
|
||||
{
|
||||
editGroupOrder++;
|
||||
var editOrder = 0;
|
||||
foreach (var item in group.Items)
|
||||
{
|
||||
fieldOrder++;
|
||||
if (item.IncludeInEditingForm && item.FieldName != input.KeyFieldName)
|
||||
{
|
||||
editOrder++;
|
||||
}
|
||||
await repoListFormField.InsertAsync(new ListFormField
|
||||
{
|
||||
ListFormCode = input.ListFormCode,
|
||||
FieldName = item.DataField,
|
||||
FieldName = item.FieldName,
|
||||
CaptionName = item.CaptionName,
|
||||
Visible = item.DataField != input.KeyFieldName,
|
||||
Visible = item.FieldName != input.KeyFieldName,
|
||||
IsActive = true,
|
||||
AllowSearch = true,
|
||||
Width = 0,
|
||||
ListOrderNo = fieldOrder,
|
||||
EditGroupOrderNo = item.IncludeInEditingForm ? editGroupOrder : null,
|
||||
EditOrderNo = item.IncludeInEditingForm && item.FieldName != input.KeyFieldName
|
||||
? editOrder
|
||||
: null,
|
||||
EditorType2 = item.EditorType,
|
||||
ColSpan = item.ColSpan,
|
||||
EditorOptions = string.IsNullOrWhiteSpace(item.EditorOptions) ? null : item.EditorOptions,
|
||||
EditorScript = string.IsNullOrWhiteSpace(item.EditorScript) ? null : item.EditorScript,
|
||||
SourceDbType = item.DbSourceType,
|
||||
CultureName = PlatformConsts.DefaultLanguage,
|
||||
PermissionJson = WizardConsts.DefaultFieldPermissionJson(code),
|
||||
|
|
@ -373,7 +409,7 @@ public class ListFormWizardAppService(
|
|||
}
|
||||
}
|
||||
|
||||
foreach (var criteria in input.WorkflowCriteria)
|
||||
foreach (var criteria in input.Criteria)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(criteria.Id))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ using Volo.Abp.PermissionManagement;
|
|||
using Volo.Abp.TenantManagement;
|
||||
using static Sozsoft.Platform.Data.Seeds.SeedConsts;
|
||||
using Sozsoft.Languages;
|
||||
using Sozsoft.Languages.Languages;
|
||||
using Sozsoft.Platform.ListForms;
|
||||
|
||||
namespace Sozsoft.Platform.Menus;
|
||||
|
|
@ -131,6 +132,30 @@ public class MenuAppService : CrudAppService<
|
|||
.ToList();
|
||||
|
||||
entityDtos = await base.MapToGetListOutputDtosAsync(entities);
|
||||
|
||||
var languageKeys = entityDtos
|
||||
.Select(item => string.IsNullOrWhiteSpace(item.DisplayName) ? item.Code : item.DisplayName)
|
||||
.Where(key => !string.IsNullOrWhiteSpace(key))
|
||||
.Distinct()
|
||||
.ToList();
|
||||
var languageTexts = await _repositoryText.GetListAsync(text =>
|
||||
text.ResourceName == PlatformConsts.AppName &&
|
||||
languageKeys.Contains(text.Key) &&
|
||||
(text.CultureName == PlatformConsts.DefaultLanguage ||
|
||||
text.CultureName == LanguageCodes.Tr));
|
||||
|
||||
foreach (var menu in entityDtos)
|
||||
{
|
||||
var languageKey = string.IsNullOrWhiteSpace(menu.DisplayName)
|
||||
? menu.Code
|
||||
: menu.DisplayName;
|
||||
menu.MenuTextEn = languageTexts.FirstOrDefault(text =>
|
||||
text.Key == languageKey &&
|
||||
text.CultureName == PlatformConsts.DefaultLanguage)?.Value;
|
||||
menu.MenuTextTr = languageTexts.FirstOrDefault(text =>
|
||||
text.Key == languageKey &&
|
||||
text.CultureName == LanguageCodes.Tr)?.Value;
|
||||
}
|
||||
}
|
||||
|
||||
return new PagedResultDto<MenuDto>(
|
||||
|
|
|
|||
|
|
@ -1443,8 +1443,8 @@
|
|||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Reports.List",
|
||||
"en": "List Report",
|
||||
"tr": "Liste Raporu"
|
||||
"en": "Grid Report",
|
||||
"tr": "Tablo Raporu"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
|
|
@ -1506,6 +1506,18 @@
|
|||
"en": "Settings",
|
||||
"tr": "Ayarlar"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Licence",
|
||||
"en": "Licence",
|
||||
"tr": "Lisans"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.LicenceItem",
|
||||
"en": "Licence Items",
|
||||
"tr": "Lisans Kalemleri"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Settings",
|
||||
|
|
@ -4428,6 +4440,24 @@
|
|||
"en": "Tree",
|
||||
"tr": "Ağaç"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormEdit.TabCard",
|
||||
"en": "Card",
|
||||
"tr": "Kart"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormEdit.TabChart",
|
||||
"en": "Chart",
|
||||
"tr": "Grafik"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormEdit.TabGrid",
|
||||
"en": "Grid",
|
||||
"tr": "Tablo"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormEdit.TabGantt",
|
||||
|
|
@ -4656,6 +4686,12 @@
|
|||
"en": "Scheduler Layout",
|
||||
"tr": "Zamanlayıcı Düzeni"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormEdit.DetailsLayoutDto.TodoLayout",
|
||||
"en": "Todo Layout",
|
||||
"tr": "İşler Düzeni"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormEdit.DetailsLayoutDto.GanttLayout",
|
||||
|
|
@ -4668,6 +4704,12 @@
|
|||
"en": "Grid Layout",
|
||||
"tr": "Liste Düzeni"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormEdit.DetailsLayoutDto.CardLayout",
|
||||
"en": "Card Layout",
|
||||
"tr": "Kart Düzeni"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormEdit.DetailsLayoutDto.PivotLayout",
|
||||
|
|
@ -5150,15 +5192,15 @@
|
|||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormEdit.EditingFormFormFields",
|
||||
"en": "Editing Form Fields",
|
||||
"tr": "Düzenleme Form Alanları"
|
||||
"key": "ListForms.ListFormEdit.EditingFormFormGroups",
|
||||
"en": "Editing Form Groups",
|
||||
"tr": "Düzenleme Form Grupları"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormEdit.EditingFormFormFieldsDescription",
|
||||
"en": "Edit formunda çıkacak field'lar",
|
||||
"tr": "Form Sütunları"
|
||||
"key": "ListForms.ListFormEdit.EditingFormFormGroupsDescription",
|
||||
"en": "Groups that will appear in Edit form",
|
||||
"tr": "Düzenleme formunda çıkacak gruplar"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
|
|
@ -5880,6 +5922,30 @@
|
|||
"en": "Field Name",
|
||||
"tr": "Alan Adı"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormFieldEdit.EditorType",
|
||||
"en": "Editor Type",
|
||||
"tr": "Editör Tipi"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormFieldEdit.EditFormGroup",
|
||||
"en": "Edit Form Group",
|
||||
"tr": "Düzenleme Form Grubu"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormFieldEdit.EditFormOrderNo",
|
||||
"en": "Edit Order No",
|
||||
"tr": "Düzenleme Sıra No"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormFieldEdit.EditFormColSpan",
|
||||
"en": "Edit Col Span",
|
||||
"tr": "Düzenleme Col Span"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormFieldEdit.PlaceHolder",
|
||||
|
|
@ -9318,12 +9384,6 @@
|
|||
"tr": "Seçili bölümün düzenlenebilir alanları burada gösterilir.",
|
||||
"en": "Select a block on the page to edit its properties here."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "Public.designer.save",
|
||||
"tr": "Kaydet",
|
||||
"en": "Save"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.DeveloperKit.Component.Description",
|
||||
|
|
@ -10152,12 +10212,6 @@
|
|||
"en": "Save Entity",
|
||||
"tr": "Varlığı Kaydet"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.DeveloperKit.EntityEditor.Saving",
|
||||
"en": "Saving...",
|
||||
"tr": "Kaydediliyor..."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.DeveloperKit.EntityEditor.BasicInfo",
|
||||
|
|
@ -10290,18 +10344,6 @@
|
|||
"en": "Inactive",
|
||||
"tr": "Pasif"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.DeveloperKit.ComponentEditor.Save",
|
||||
"en": "Save",
|
||||
"tr": "Kaydet"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.DeveloperKit.ComponentEditor.Saving",
|
||||
"en": "Saving...",
|
||||
"tr": "Kaydediliyor..."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.DeveloperKit.ComponentEditor.ValidationError.Title",
|
||||
|
|
@ -11598,12 +11640,6 @@
|
|||
"tr": "Hedef Data Sourcelar",
|
||||
"en": "Target Data Sources"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Platform.Save",
|
||||
"tr": "Kaydet",
|
||||
"en": "Save"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Platform.SaveQuery",
|
||||
|
|
@ -12306,12 +12342,6 @@
|
|||
"tr": "Alan seçin...",
|
||||
"en": "Select field..."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Platform.ChartDrawer.Save",
|
||||
"tr": "Kaydet",
|
||||
"en": "Save"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Platform.ChartDrawer.ChartSaved",
|
||||
|
|
@ -18792,12 +18822,6 @@
|
|||
"en": "If checked, existing object in the target will be dropped and recreated.",
|
||||
"tr": "İşaretlenirse hedefteki mevcut obje silinip yeniden oluşturulur."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.SqlQueryManager.Save",
|
||||
"en": "Save",
|
||||
"tr": "Kaydet"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.SqlQueryManager.Next",
|
||||
|
|
@ -19374,6 +19398,396 @@
|
|||
"en": "Successfully Saved",
|
||||
"tr": "Başarıyla Kaydedildi"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormFieldEdit.TodoTitleExpr",
|
||||
"en": "Title Field",
|
||||
"tr": "Başlık alanı"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormFieldEdit.TodoStatusExpr",
|
||||
"en": "Column / Status Field",
|
||||
"tr": "Kolon / durum alanı"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormFieldEdit.TodoDescriptionExpr",
|
||||
"en": "Description Field",
|
||||
"tr": "Açıklama alanı"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormFieldEdit.TodoDueDateExpr",
|
||||
"en": "Due Date Field",
|
||||
"tr": "Termin tarihi alanı"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormFieldEdit.TodoTagExpr",
|
||||
"en": "Tag Field",
|
||||
"tr": "Etiket alanı"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormFieldEdit.TodoAssigneeExpr",
|
||||
"en": "Assignee Field",
|
||||
"tr": "Atanan kişi alanı"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormFieldEdit.TodoPriorityExpr",
|
||||
"en": "Priority Field",
|
||||
"tr": "Öncelik alanı"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormFieldEdit.TodoCompletedExpr",
|
||||
"en": "Completed Field",
|
||||
"tr": "Tamamlandı alanı"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormFieldEdit.TodoOrderExpr",
|
||||
"en": "Card Order Field",
|
||||
"tr": "Kart sıra alanı"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormFieldEdit.TodoFieldsLoadFailed",
|
||||
"en": "Fields could not be loaded: {0}",
|
||||
"tr": "Alanlar getirilemedi: {0}"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormFieldEdit.TodoStatusOrder",
|
||||
"en": "Status order (comma-separated)",
|
||||
"tr": "Durum sırası (virgülle ayırın)"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormFieldEdit.TodoStatusOrderPlaceholder",
|
||||
"en": "Backlog, Ready to Start, In Progress, Code Review, Testing, Staging",
|
||||
"tr": "Gelen Kutusu, Bugün, Bu Hafta, Bu Ay, Daha Sonra, Tamamlandı"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormFieldEdit.TodoAllowDragging",
|
||||
"en": "Allow cards to be dragged between columns",
|
||||
"tr": "Kartları kolonlar arasında sürüklemeye izin ver"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormFieldEdit.TodoRequiredFields",
|
||||
"en": "Title field and column / status field are required.",
|
||||
"tr": "Başlık alanı ve kolon / durum alanı zorunludur."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormFieldEdit.TodoDisabledInListSettings",
|
||||
"en": "Todo view is disabled in the list settings. You can skip this step or enable the Todo view in the previous steps.",
|
||||
"tr": "Todo görünümü liste ayarlarında kapalı. Bu adımı atlayabilir veya önceki adımlardan Todo görünümünü etkinleştirebilirsiniz."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.Uncategorized",
|
||||
"en": "Uncategorized",
|
||||
"tr": "Kategorisiz"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.PriorityRating",
|
||||
"en": "{0}/5 priority",
|
||||
"tr": "{0}/5 öncelik"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.NoPriority",
|
||||
"en": "No priority",
|
||||
"tr": "Öncelik yok"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.DuplicateColumnName",
|
||||
"en": "A Kanban column with this name already exists.",
|
||||
"tr": "Bu isimde bir kanban zaten var."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.ColumnNotEmptyMessage",
|
||||
"en": "This Kanban column cannot be deleted. First move its {0} todo item(s) to another column.",
|
||||
"tr": "Bu kanban silinemez. Önce içindeki {0} todo’yu başka bir kanbana taşıyın."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.ConfirmDeleteColumn",
|
||||
"en": "Delete the “{0}” Kanban column?",
|
||||
"tr": "“{0}” kanbanı silinsin mi?"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.RenameRequiresUpdateService",
|
||||
"en": "An update service is required to rename a Kanban column that contains todo items.",
|
||||
"tr": "Todo içeren bir kanbanı yeniden adlandırmak için update servisi gereklidir."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.ColumnNameSaveFailed",
|
||||
"en": "The Kanban column name could not be saved. Please try again.",
|
||||
"tr": "Kanban adı kaydedilemedi. Lütfen tekrar deneyin."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.ConfirmDeleteTodo",
|
||||
"en": "Delete “{0}”?",
|
||||
"tr": "“{0}” silinsin mi?"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.Loading",
|
||||
"en": "Loading…",
|
||||
"tr": "Yükleniyor…"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.BackToBoard",
|
||||
"en": "Back to board",
|
||||
"tr": "Panoya dön"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.EditRequiresUpdateService",
|
||||
"en": "An update service must be defined to edit.",
|
||||
"tr": "Düzenlemek için update servisi tanımlanmalıdır."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.DeleteTodo",
|
||||
"en": "Delete todo",
|
||||
"tr": "Todo sil"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.Title",
|
||||
"en": "Title",
|
||||
"tr": "Başlık"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.Description",
|
||||
"en": "Description",
|
||||
"tr": "Açıklama"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.DescriptionPlaceholder",
|
||||
"en": "Enter a todo description…",
|
||||
"tr": "Todo açıklamasını yazın…"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.Assignees",
|
||||
"en": "Assignees",
|
||||
"tr": "Atanan kişiler"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.UsersLoading",
|
||||
"en": "Loading users…",
|
||||
"tr": "Kullanıcılar yükleniyor…"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.SelectUser",
|
||||
"en": "Select a user",
|
||||
"tr": "Kullanıcı seçin"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.Tags",
|
||||
"en": "Tags",
|
||||
"tr": "Etiketler"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.TagsPlaceholder",
|
||||
"en": "Select a tag or enter a new one",
|
||||
"tr": "Etiket seçin veya yeni etiket yazın"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.Status",
|
||||
"en": "Kanban / Status",
|
||||
"tr": "Kanban / Durum"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.DueDate",
|
||||
"en": "Due date",
|
||||
"tr": "Termin tarihi"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.Priority",
|
||||
"en": "Priority",
|
||||
"tr": "Öncelik"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.PriorityVeryLow",
|
||||
"en": "Very low",
|
||||
"tr": "Çok düşük"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.PriorityLow",
|
||||
"en": "Low",
|
||||
"tr": "Düşük"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.PriorityMedium",
|
||||
"en": "Medium",
|
||||
"tr": "Orta"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.PriorityHigh",
|
||||
"en": "High",
|
||||
"tr": "Yüksek"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.PriorityUrgent",
|
||||
"en": "Urgent",
|
||||
"tr": "Acil"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.Completed",
|
||||
"en": "Completed",
|
||||
"tr": "Tamamlandı"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.UndoChanges",
|
||||
"en": "Undo changes",
|
||||
"tr": "Değişiklikleri geri al"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.ReorderColumn",
|
||||
"en": "Reorder Kanban column",
|
||||
"tr": "Kanbanı sırala"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.ColumnName",
|
||||
"en": "Kanban column name",
|
||||
"tr": "Kanban adı"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.Cancel",
|
||||
"en": "Cancel",
|
||||
"tr": "Vazgeç"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.RenameColumn",
|
||||
"en": "Rename Kanban column",
|
||||
"tr": "Kanban adını değiştir"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.NewTodo",
|
||||
"en": "New todo",
|
||||
"tr": "Yeni todo"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.ColumnWithTodosCannotBeDeleted",
|
||||
"en": "A Kanban column containing todo items cannot be deleted",
|
||||
"tr": "İçinde todo bulunan kanban silinemez"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.DeleteColumn",
|
||||
"en": "Delete Kanban column",
|
||||
"tr": "Kanbanı sil"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.Close",
|
||||
"en": "Close",
|
||||
"tr": "Kapat"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.TodoTitlePlaceholder",
|
||||
"en": "Todo title…",
|
||||
"tr": "Todo başlığı…"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.DropHere",
|
||||
"en": "Drop here",
|
||||
"tr": "Buraya bırak"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.ChangePriority",
|
||||
"en": "Change priority",
|
||||
"tr": "Önceliği değiştir"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.ReopenTodo",
|
||||
"en": "Reopen todo",
|
||||
"tr": "Todo’yu yeniden aç"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.CompleteTodo",
|
||||
"en": "Complete todo",
|
||||
"tr": "Todo’yu tamamla"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.NewColumn",
|
||||
"en": "New Kanban",
|
||||
"tr": "Yeni kanban"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.AddNewColumn",
|
||||
"en": "Add a new Kanban",
|
||||
"tr": "Yeni kanban ekle"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.NewColumnName",
|
||||
"en": "New Kanban column name",
|
||||
"tr": "Yeni kanban adı"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.NewColumnPlaceholder",
|
||||
"en": "E.g. In Review",
|
||||
"tr": "Örn. İnceleniyor"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.TodoBoard.AddColumn",
|
||||
"en": "Add Kanban column",
|
||||
"tr": "Kanbanı ekle"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormEdit.TabTodo",
|
||||
"en": "Todo",
|
||||
"tr": "İşler"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormEdit.Workflow.Criteria",
|
||||
|
|
@ -19448,7 +19862,7 @@
|
|||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormEdit.Workflow.IsFilterUserName",
|
||||
"key": "ListForms.ListFormEdit.Workflow.ApprovalIsFilterUserName",
|
||||
"en": "Filter User Name?",
|
||||
"tr": "Kullanıcı Adı Filtresin mi?"
|
||||
},
|
||||
|
|
@ -19949,6 +20363,72 @@
|
|||
"key": "App.Tenant.Create",
|
||||
"en": "Tenant Create",
|
||||
"tr": "Tenant Oluştur"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.CheckUpdate",
|
||||
"en": "Checking...",
|
||||
"tr": "Kontrol ediliyor..."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.CheckForUpdates",
|
||||
"en": "Check for Updates",
|
||||
"tr": "Güncellemeyi Kontrol Et"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.NotSupportServiceWorkerUpdate",
|
||||
"en": "Your browser does not support service worker updates.",
|
||||
"tr": "Tarayıcınız service worker güncellemelerini desteklemiyor."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.NewVersionAvailable",
|
||||
"en": "A new service worker has been found. The application will automatically update when the files are ready.",
|
||||
"tr": "Dosyalar hazırlandığında uygulama otomatik olarak güncellenecek."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.ManualUpdateFailed",
|
||||
"en": "Please check your connection and try again.",
|
||||
"tr": "Lütfen bağlantınızı kontrol edip tekrar deneyin."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.ChangeLogDescription",
|
||||
"en": "Check if there's a new application version available on the server.",
|
||||
"tr": "Sunucuda yeni bir uygulama sürümü olup olmadığını kontrol edin."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.NoNewVersionFound",
|
||||
"en": "No new version was found available.",
|
||||
"tr": "Kullanılabilir yeni bir sürüm bulunamadı."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.UpToDate",
|
||||
"en": "The app is up to date.",
|
||||
"tr": "Uygulama güncel"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.UpdateCouldNotBeChecked",
|
||||
"en": "Update could not be checked",
|
||||
"tr": "Güncelleme kontrol edilemedi"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.NewVersionFound",
|
||||
"en": "New version found.",
|
||||
"tr": "Yeni sürüm bulundu"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.UpdateCheckFailed",
|
||||
"en": "Update check failed.",
|
||||
"tr": "Güncelleme kontrolü başarısız"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -67,11 +67,13 @@ public static class ListFormSeeder_DefaultJsons
|
|||
public static string DefaultLayoutJson(string DefaultLayout = "grid") => JsonSerializer.Serialize(new LayoutDto()
|
||||
{
|
||||
Grid = true,
|
||||
Card = true,
|
||||
Pivot = true,
|
||||
Chart = true,
|
||||
Tree = true,
|
||||
Gantt = true,
|
||||
Scheduler = true,
|
||||
Todo = true,
|
||||
DefaultLayout = DefaultLayout,
|
||||
});
|
||||
public static readonly string DefaultExportJson = JsonSerializer.Serialize(new ChartExportDto
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -984,22 +984,22 @@
|
|||
},
|
||||
{
|
||||
"ParentCode": "App.DeveloperKit",
|
||||
"Code": "App.DeveloperKit.Components",
|
||||
"DisplayName": "App.DeveloperKit.Components",
|
||||
"Code": "App.DeveloperKit.DynamicServices",
|
||||
"DisplayName": "App.DeveloperKit.DynamicServices",
|
||||
"Order": 4,
|
||||
"Url": "/admin/developerkit/components",
|
||||
"Icon": "FcBiohazard",
|
||||
"RequiredPermissionName": "App.DeveloperKit.Components",
|
||||
"Url": "/admin/developerkit/dynamic-services",
|
||||
"Icon": "FcCommandLine",
|
||||
"RequiredPermissionName": "App.DeveloperKit.DynamicServices",
|
||||
"IsDisabled": false
|
||||
},
|
||||
{
|
||||
"ParentCode": "App.DeveloperKit",
|
||||
"Code": "App.DeveloperKit.DynamicServices",
|
||||
"DisplayName": "App.DeveloperKit.DynamicServices",
|
||||
"Code": "App.DeveloperKit.Components",
|
||||
"DisplayName": "App.DeveloperKit.Components",
|
||||
"Order": 5,
|
||||
"Url": "/admin/developerkit/dynamic-services",
|
||||
"Icon": "FcCommandLine",
|
||||
"RequiredPermissionName": "App.DeveloperKit.DynamicServices",
|
||||
"Url": "/admin/developerkit/components",
|
||||
"Icon": "FcBiohazard",
|
||||
"RequiredPermissionName": "App.DeveloperKit.Components",
|
||||
"IsDisabled": false
|
||||
},
|
||||
{
|
||||
|
|
@ -1083,11 +1083,21 @@
|
|||
"RequiredPermissionName": "App.Definitions.OrgChart",
|
||||
"IsDisabled": false
|
||||
},
|
||||
{
|
||||
"ParentCode": "App.Administration",
|
||||
"Code": "App.Licence",
|
||||
"DisplayName": "App.Licence",
|
||||
"Order": 2,
|
||||
"Url": "/admin/form/App.Licence",
|
||||
"Icon": "FcRules",
|
||||
"RequiredPermissionName": "App.Licence",
|
||||
"IsDisabled": false
|
||||
},
|
||||
{
|
||||
"ParentCode": "App.Administration",
|
||||
"Code": "App.Setting",
|
||||
"DisplayName": "App.Setting",
|
||||
"Order": 2,
|
||||
"Order": 3,
|
||||
"Url": "/admin/settings",
|
||||
"Icon": "FcSettings",
|
||||
"RequiredPermissionName": "App.Setting",
|
||||
|
|
@ -1097,7 +1107,7 @@
|
|||
"ParentCode": "App.Administration",
|
||||
"Code": "App.Administration.Intranet",
|
||||
"DisplayName": "App.Intranet",
|
||||
"Order": 3,
|
||||
"Order": 4,
|
||||
"Url": null,
|
||||
"Icon": "FcConferenceCall",
|
||||
"RequiredPermissionName": null,
|
||||
|
|
@ -1167,7 +1177,7 @@
|
|||
"ParentCode": "App.Administration",
|
||||
"Code": "App.Administration.Restrictions",
|
||||
"DisplayName": "App.Restrictions",
|
||||
"Order": 4,
|
||||
"Order": 5,
|
||||
"Url": null,
|
||||
"Icon": "FaLock",
|
||||
"RequiredPermissionName": null,
|
||||
|
|
@ -1197,7 +1207,7 @@
|
|||
"ParentCode": "App.Administration",
|
||||
"Code": "Abp.Identity",
|
||||
"DisplayName": "Abp.Identity",
|
||||
"Order": 5,
|
||||
"Order": 6,
|
||||
"Url": null,
|
||||
"Icon": "FcConferenceCall",
|
||||
"RequiredPermissionName": null,
|
||||
|
|
@ -1287,7 +1297,7 @@
|
|||
"ParentCode": "App.Administration",
|
||||
"Code": "App.Reports.Management",
|
||||
"DisplayName": "App.Reports.Management",
|
||||
"Order": 6,
|
||||
"Order": 7,
|
||||
"Url": null,
|
||||
"Icon": "FcDocument",
|
||||
"RequiredPermissionName": null,
|
||||
|
|
@ -1317,7 +1327,7 @@
|
|||
"ParentCode": "App.Administration",
|
||||
"Code": "App.Videoroom.Dashboard",
|
||||
"DisplayName": "App.Videoroom.Dashboard",
|
||||
"Order": 7,
|
||||
"Order": 8,
|
||||
"Url": "/admin/videoroom/dashboard",
|
||||
"Icon": "FcVideoCall",
|
||||
"RequiredPermissionName": "App.Videoroom.Dashboard",
|
||||
|
|
@ -1327,7 +1337,7 @@
|
|||
"ParentCode": "App.Administration",
|
||||
"Code": "App.Files",
|
||||
"DisplayName": "App.Files",
|
||||
"Order": 8,
|
||||
"Order": 9,
|
||||
"Url": "/admin/files",
|
||||
"Icon": "FcFolder",
|
||||
"RequiredPermissionName": "App.Files",
|
||||
|
|
@ -1337,7 +1347,7 @@
|
|||
"ParentCode": "App.Administration",
|
||||
"Code": "App.Forum",
|
||||
"DisplayName": "App.Forum",
|
||||
"Order": 9,
|
||||
"Order": 10,
|
||||
"Url": "/admin/forum",
|
||||
"Icon": "FcLink",
|
||||
"RequiredPermissionName": "App.ForumManagement.Publish",
|
||||
|
|
|
|||
|
|
@ -4175,7 +4175,7 @@
|
|||
"DisplayName": "App.Intranet.Survey",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4184,7 +4184,7 @@
|
|||
"DisplayName": "Create",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4193,7 +4193,7 @@
|
|||
"DisplayName": "Update",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4202,7 +4202,7 @@
|
|||
"DisplayName": "Delete",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4211,7 +4211,7 @@
|
|||
"DisplayName": "Export",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4220,7 +4220,7 @@
|
|||
"DisplayName": "Import",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4229,7 +4229,7 @@
|
|||
"DisplayName": "Note",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4238,7 +4238,7 @@
|
|||
"DisplayName": "Widget",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4247,7 +4247,7 @@
|
|||
"DisplayName": "App.Intranet.SurveyQuestion",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4256,7 +4256,7 @@
|
|||
"DisplayName": "Create",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4265,7 +4265,7 @@
|
|||
"DisplayName": "Update",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4274,7 +4274,7 @@
|
|||
"DisplayName": "Delete",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4283,7 +4283,7 @@
|
|||
"DisplayName": "Export",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4292,7 +4292,7 @@
|
|||
"DisplayName": "Import",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4301,7 +4301,7 @@
|
|||
"DisplayName": "Note",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4310,7 +4310,7 @@
|
|||
"DisplayName": "App.Intranet.SurveyQuestionOption",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4319,7 +4319,7 @@
|
|||
"DisplayName": "Create",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4328,7 +4328,7 @@
|
|||
"DisplayName": "Update",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4337,7 +4337,7 @@
|
|||
"DisplayName": "Delete",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4346,7 +4346,7 @@
|
|||
"DisplayName": "Export",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4355,7 +4355,7 @@
|
|||
"DisplayName": "Import",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4364,7 +4364,7 @@
|
|||
"DisplayName": "App.Intranet.SurveyResponse",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4373,7 +4373,7 @@
|
|||
"DisplayName": "Create",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4382,7 +4382,7 @@
|
|||
"DisplayName": "Update",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4391,7 +4391,7 @@
|
|||
"DisplayName": "Delete",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4400,7 +4400,7 @@
|
|||
"DisplayName": "Export",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4409,7 +4409,7 @@
|
|||
"DisplayName": "Import",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4418,7 +4418,7 @@
|
|||
"DisplayName": "Note",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4427,7 +4427,7 @@
|
|||
"DisplayName": "App.Intranet.SurveyAnswer",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4436,7 +4436,7 @@
|
|||
"DisplayName": "Create",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4445,7 +4445,7 @@
|
|||
"DisplayName": "Update",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4454,7 +4454,7 @@
|
|||
"DisplayName": "Delete",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4463,7 +4463,7 @@
|
|||
"DisplayName": "Export",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4472,7 +4472,7 @@
|
|||
"DisplayName": "Import",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp"
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4480,8 +4480,8 @@
|
|||
"ParentName": null,
|
||||
"DisplayName": "App.Videoroom",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 2,
|
||||
"MenuGroup": "Kurs"
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4489,8 +4489,8 @@
|
|||
"ParentName": "App.Videoroom",
|
||||
"DisplayName": "App.Videoroom.Dashboard",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 2,
|
||||
"MenuGroup": "Kurs"
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4498,8 +4498,8 @@
|
|||
"ParentName": "App.Videoroom",
|
||||
"DisplayName": "App.Videoroom.List",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 2,
|
||||
"MenuGroup": "Kurs"
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
|
|
@ -4507,8 +4507,116 @@
|
|||
"ParentName": "App.Videoroom",
|
||||
"DisplayName": "App.Videoroom.RoomDetail",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 2,
|
||||
"MenuGroup": "Kurs"
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
"Name": "App.Licence",
|
||||
"ParentName": null,
|
||||
"DisplayName": "App.Licence",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
"Name": "App.Licence.Create",
|
||||
"ParentName": "App.Licence",
|
||||
"DisplayName": "Create",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
"Name": "App.Licence.Update",
|
||||
"ParentName": "App.Licence",
|
||||
"DisplayName": "Update",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
"Name": "App.Licence.Delete",
|
||||
"ParentName": "App.Licence",
|
||||
"DisplayName": "Delete",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
"Name": "App.Licence.Export",
|
||||
"ParentName": "App.Licence",
|
||||
"DisplayName": "Export",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
"Name": "App.Licence.Import",
|
||||
"ParentName": "App.Licence",
|
||||
"DisplayName": "Import",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
"Name": "App.LicenceItem",
|
||||
"ParentName": null,
|
||||
"DisplayName": "App.LicenceItem",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
"Name": "App.LicenceItem.Create",
|
||||
"ParentName": "App.LicenceItem",
|
||||
"DisplayName": "Create",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
"Name": "App.LicenceItem.Update",
|
||||
"ParentName": "App.LicenceItem",
|
||||
"DisplayName": "Update",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
"Name": "App.LicenceItem.Delete",
|
||||
"ParentName": "App.LicenceItem",
|
||||
"DisplayName": "Delete",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
"Name": "App.LicenceItem.Export",
|
||||
"ParentName": "App.LicenceItem",
|
||||
"DisplayName": "Export",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
"Name": "App.LicenceItem.Import",
|
||||
"ParentName": "App.LicenceItem",
|
||||
"DisplayName": "Import",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,917 @@
|
|||
CREATE OR REPLACE FUNCTION dbo."Sas_H_ListFormFieldsDictionaryJson"
|
||||
(
|
||||
p_definition_culture_name VARCHAR(10) DEFAULT 'en',
|
||||
p_ui_culture_name VARCHAR(10) DEFAULT 'tr',
|
||||
p_list_form_code VARCHAR(64) DEFAULT NULL,
|
||||
p_only_base_definitions BOOLEAN DEFAULT TRUE,
|
||||
p_resource_name VARCHAR(64) DEFAULT NULL
|
||||
)
|
||||
RETURNS JSONB
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
v_result JSONB;
|
||||
BEGIN
|
||||
|
||||
WITH list_form_source AS
|
||||
(
|
||||
SELECT
|
||||
l."Id",
|
||||
l."ListFormCode",
|
||||
l."CultureName",
|
||||
l."Name",
|
||||
|
||||
lt_name."Value" AS name_value,
|
||||
|
||||
l."Title",
|
||||
lt_title."Value" AS title_value,
|
||||
|
||||
l."Description",
|
||||
lt_desc."Value" AS description_value,
|
||||
|
||||
l."TableName",
|
||||
|
||||
NULLIF(
|
||||
BTRIM(l."SelectCommand"::TEXT),
|
||||
''
|
||||
) AS select_command_text,
|
||||
|
||||
l."KeyFieldName",
|
||||
l."UserId",
|
||||
l."RoleId"
|
||||
|
||||
FROM dbo."Sas_H_ListForm" l
|
||||
|
||||
/*
|
||||
SQL Server OUTER APPLY TOP (1)
|
||||
PostgreSQL LEFT JOIN LATERAL ... LIMIT 1
|
||||
*/
|
||||
LEFT JOIN LATERAL
|
||||
(
|
||||
SELECT lt."Value"
|
||||
FROM dbo."Sas_H_LanguageText" lt
|
||||
WHERE lt."CultureName" = p_ui_culture_name
|
||||
AND lt."Key" = l."Name"
|
||||
AND
|
||||
(
|
||||
p_resource_name IS NULL
|
||||
OR lt."ResourceName" = p_resource_name
|
||||
)
|
||||
ORDER BY lt."ResourceName"
|
||||
LIMIT 1
|
||||
) lt_name ON TRUE
|
||||
|
||||
LEFT JOIN LATERAL
|
||||
(
|
||||
SELECT lt."Value"
|
||||
FROM dbo."Sas_H_LanguageText" lt
|
||||
WHERE lt."CultureName" = p_ui_culture_name
|
||||
AND lt."Key" = l."Title"
|
||||
AND
|
||||
(
|
||||
p_resource_name IS NULL
|
||||
OR lt."ResourceName" = p_resource_name
|
||||
)
|
||||
ORDER BY lt."ResourceName"
|
||||
LIMIT 1
|
||||
) lt_title ON TRUE
|
||||
|
||||
LEFT JOIN LATERAL
|
||||
(
|
||||
SELECT lt."Value"
|
||||
FROM dbo."Sas_H_LanguageText" lt
|
||||
WHERE lt."CultureName" = p_ui_culture_name
|
||||
AND lt."Key" = l."Description"
|
||||
AND
|
||||
(
|
||||
p_resource_name IS NULL
|
||||
OR lt."ResourceName" = p_resource_name
|
||||
)
|
||||
ORDER BY lt."ResourceName"
|
||||
LIMIT 1
|
||||
) lt_desc ON TRUE
|
||||
|
||||
WHERE
|
||||
(
|
||||
p_definition_culture_name IS NULL
|
||||
OR l."CultureName" = p_definition_culture_name
|
||||
)
|
||||
|
||||
AND
|
||||
(
|
||||
p_list_form_code IS NULL
|
||||
OR l."ListFormCode" = p_list_form_code
|
||||
)
|
||||
|
||||
AND
|
||||
(
|
||||
p_only_base_definitions = FALSE
|
||||
|
||||
OR
|
||||
(
|
||||
l."UserId" IS NULL
|
||||
AND l."RoleId" IS NULL
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
list_forms_json AS
|
||||
(
|
||||
SELECT
|
||||
jsonb_build_object
|
||||
(
|
||||
'listFormCode',
|
||||
l."ListFormCode",
|
||||
|
||||
'displayName',
|
||||
COALESCE(
|
||||
l.name_value::TEXT,
|
||||
l."Name",
|
||||
''
|
||||
),
|
||||
|
||||
'title',
|
||||
COALESCE(
|
||||
l.title_value::TEXT,
|
||||
l."Title",
|
||||
''
|
||||
),
|
||||
|
||||
'description',
|
||||
COALESCE(
|
||||
l.description_value::TEXT,
|
||||
l."Description",
|
||||
''
|
||||
),
|
||||
|
||||
'tableName',
|
||||
COALESCE(
|
||||
l."TableName",
|
||||
''
|
||||
),
|
||||
|
||||
'sqlSourceName',
|
||||
COALESCE(
|
||||
NULLIF(
|
||||
l."TableName",
|
||||
''
|
||||
),
|
||||
l.select_command_text,
|
||||
''
|
||||
),
|
||||
|
||||
'sourceKind',
|
||||
CASE
|
||||
|
||||
WHEN COALESCE(
|
||||
NULLIF(
|
||||
l."TableName",
|
||||
''
|
||||
),
|
||||
l.select_command_text
|
||||
) IS NULL
|
||||
THEN 'unknown'
|
||||
|
||||
WHEN UPPER(
|
||||
BTRIM(
|
||||
COALESCE(
|
||||
NULLIF(
|
||||
l."TableName",
|
||||
''
|
||||
),
|
||||
l.select_command_text
|
||||
)
|
||||
)
|
||||
) LIKE 'SELECT%'
|
||||
THEN 'selectSql'
|
||||
|
||||
ELSE 'table'
|
||||
|
||||
END,
|
||||
|
||||
'keyFieldName',
|
||||
COALESCE(
|
||||
l."KeyFieldName",
|
||||
''
|
||||
),
|
||||
|
||||
'searchText',
|
||||
CONCAT_WS(
|
||||
' ',
|
||||
l."ListFormCode",
|
||||
l."TableName",
|
||||
l.select_command_text,
|
||||
|
||||
COALESCE(
|
||||
l.name_value::TEXT,
|
||||
l."Name"
|
||||
),
|
||||
|
||||
COALESCE(
|
||||
l.title_value::TEXT,
|
||||
l."Title"
|
||||
),
|
||||
|
||||
COALESCE(
|
||||
l.description_value::TEXT,
|
||||
l."Description"
|
||||
)
|
||||
),
|
||||
|
||||
'fields',
|
||||
COALESCE
|
||||
(
|
||||
(
|
||||
SELECT
|
||||
jsonb_agg
|
||||
(
|
||||
jsonb_build_object
|
||||
(
|
||||
'field',
|
||||
f."FieldName",
|
||||
|
||||
'displayName',
|
||||
COALESCE(
|
||||
lt_cap."Value"::TEXT,
|
||||
f."CaptionName",
|
||||
''
|
||||
),
|
||||
|
||||
'sqlDataType',
|
||||
sc.sql_data_type,
|
||||
|
||||
'listOrderNo',
|
||||
f."ListOrderNo",
|
||||
|
||||
'isVisible',
|
||||
COALESCE(
|
||||
f."Visible",
|
||||
TRUE
|
||||
),
|
||||
|
||||
'isBooleanColumn',
|
||||
CASE
|
||||
|
||||
WHEN sc.sql_data_type = 'boolean'
|
||||
THEN TRUE
|
||||
|
||||
WHEN f."FieldName" LIKE 'Is%'
|
||||
THEN TRUE
|
||||
|
||||
WHEN f."FieldName" LIKE 'Has%'
|
||||
THEN TRUE
|
||||
|
||||
WHEN f."FieldName" IN
|
||||
(
|
||||
'Monday',
|
||||
'Tuesday',
|
||||
'Wednesday',
|
||||
'Thursday',
|
||||
'Friday',
|
||||
'Saturday',
|
||||
'Sunday'
|
||||
)
|
||||
THEN TRUE
|
||||
|
||||
WHEN f."FieldName" IN
|
||||
(
|
||||
'EmailConfirmed',
|
||||
'TwoFactorEnabled',
|
||||
'IsVerified',
|
||||
'IsDefault',
|
||||
'IsPublic',
|
||||
'IsEnabled',
|
||||
'IsPublished',
|
||||
'IsPinned',
|
||||
'IsAnonymous',
|
||||
'IsFixed',
|
||||
'IsCustomized',
|
||||
'IsEncrypted',
|
||||
'IsInherited',
|
||||
'ZipRequired',
|
||||
'StateRequired'
|
||||
)
|
||||
THEN TRUE
|
||||
|
||||
ELSE FALSE
|
||||
|
||||
END,
|
||||
|
||||
'lookupJsonText',
|
||||
lj.lookup_json_text_decoded,
|
||||
|
||||
'lookupTableName',
|
||||
COALESCE
|
||||
(
|
||||
CASE
|
||||
WHEN lj.lookup_json IS NOT NULL
|
||||
THEN COALESCE
|
||||
(
|
||||
lj.lookup_json ->> 'tableName',
|
||||
lj.lookup_json ->> 'sqlTableName',
|
||||
lj.lookup_json ->> 'lookupTableName',
|
||||
lj.lookup_json #>> '{dataSource,tableName}',
|
||||
lj.lookup_json #>> '{dataSource,sqlTableName}'
|
||||
)
|
||||
END,
|
||||
|
||||
lkp.parsed_lookup_table_name
|
||||
),
|
||||
|
||||
'lookupValueColumn',
|
||||
COALESCE
|
||||
(
|
||||
CASE
|
||||
WHEN lj.lookup_json IS NOT NULL
|
||||
THEN COALESCE
|
||||
(
|
||||
lj.lookup_json ->> 'valueExpr',
|
||||
lj.lookup_json ->> 'valueField',
|
||||
lj.lookup_json ->> 'valueColumn',
|
||||
lj.lookup_json ->> 'keyField',
|
||||
lj.lookup_json ->> 'keyFieldName'
|
||||
)
|
||||
END,
|
||||
|
||||
lkp.parsed_lookup_value_column
|
||||
),
|
||||
|
||||
'lookupDisplayColumn',
|
||||
COALESCE
|
||||
(
|
||||
CASE
|
||||
WHEN lj.lookup_json IS NOT NULL
|
||||
THEN COALESCE
|
||||
(
|
||||
lj.lookup_json ->> 'displayExpr',
|
||||
lj.lookup_json ->> 'displayField',
|
||||
lj.lookup_json ->> 'displayColumn',
|
||||
lj.lookup_json ->> 'textField',
|
||||
lj.lookup_json ->> 'textColumn',
|
||||
lj.lookup_json ->> 'nameField',
|
||||
lj.lookup_json ->> 'nameColumn'
|
||||
)
|
||||
END,
|
||||
|
||||
lkp.parsed_lookup_display_column
|
||||
),
|
||||
|
||||
'lookupJoinMode',
|
||||
CASE
|
||||
|
||||
WHEN lj.lookup_json_text_decoded IS NOT NULL
|
||||
AND f."FieldName" NOT LIKE '%Id'
|
||||
AND COALESCE(
|
||||
lkp.parsed_lookup_value_column,
|
||||
''
|
||||
) IN
|
||||
(
|
||||
'Name',
|
||||
'Code',
|
||||
'Key',
|
||||
'Value',
|
||||
'key',
|
||||
'value'
|
||||
)
|
||||
THEN 'direct-string'
|
||||
|
||||
WHEN lj.lookup_json_text_decoded IS NOT NULL
|
||||
AND f."FieldName" NOT LIKE '%Id'
|
||||
THEN 'direct-string'
|
||||
|
||||
WHEN lj.lookup_json_text_decoded IS NOT NULL
|
||||
OR f."FieldName" LIKE '%Id'
|
||||
THEN 'convert-nvarchar-safe'
|
||||
|
||||
ELSE NULL
|
||||
|
||||
END,
|
||||
|
||||
'lookupFallbackToSourceColumn',
|
||||
CASE
|
||||
WHEN
|
||||
lj.lookup_json_text_decoded IS NOT NULL
|
||||
AND f."FieldName" NOT LIKE '%Id'
|
||||
THEN TRUE
|
||||
|
||||
ELSE FALSE
|
||||
END,
|
||||
|
||||
'lookupSearchText',
|
||||
CASE
|
||||
WHEN lj.lookup_json_text_decoded IS NOT NULL
|
||||
THEN CONCAT_WS
|
||||
(
|
||||
' ',
|
||||
f."FieldName",
|
||||
f."CaptionName",
|
||||
lt_cap."Value"::TEXT,
|
||||
lj.lookup_json_text_decoded
|
||||
)
|
||||
END,
|
||||
|
||||
'isActiveStatusColumn',
|
||||
f."FieldName" IN
|
||||
(
|
||||
'IsActive',
|
||||
'IsEnabled',
|
||||
'IsPublished'
|
||||
),
|
||||
|
||||
'isDeletedStatusColumn',
|
||||
f."FieldName" IN
|
||||
(
|
||||
'IsDeleted',
|
||||
'Deleted',
|
||||
'IsRemoved'
|
||||
),
|
||||
|
||||
'isSensitive',
|
||||
CASE
|
||||
WHEN f."FieldName" LIKE '%Password%'
|
||||
OR f."FieldName" LIKE '%ConnectionString%'
|
||||
OR f."FieldName" LIKE '%Token%'
|
||||
OR f."FieldName" LIKE '%Secret%'
|
||||
OR f."FieldName" LIKE '%ApiKey%'
|
||||
OR f."FieldName" LIKE '%PrivateKey%'
|
||||
THEN TRUE
|
||||
|
||||
ELSE FALSE
|
||||
END,
|
||||
|
||||
'isDefaultSelectColumn',
|
||||
CASE
|
||||
WHEN
|
||||
COALESCE(
|
||||
f."Visible",
|
||||
TRUE
|
||||
) = TRUE
|
||||
|
||||
AND COALESCE(
|
||||
f."IsActive",
|
||||
TRUE
|
||||
) = TRUE
|
||||
|
||||
AND f."FieldName" NOT LIKE '%Password%'
|
||||
|
||||
AND f."FieldName" NOT LIKE '%ConnectionString%'
|
||||
|
||||
AND f."FieldName" NOT LIKE '%Token%'
|
||||
|
||||
AND f."FieldName" NOT LIKE '%Secret%'
|
||||
|
||||
AND f."FieldName" NOT LIKE '%ApiKey%'
|
||||
|
||||
AND f."FieldName" NOT LIKE '%PrivateKey%'
|
||||
|
||||
AND f."FieldName" NOT IN
|
||||
(
|
||||
'Avatar',
|
||||
'ExtraProperties'
|
||||
)
|
||||
|
||||
THEN TRUE
|
||||
|
||||
ELSE FALSE
|
||||
END
|
||||
)
|
||||
|
||||
ORDER BY
|
||||
COALESCE(
|
||||
f."ListOrderNo",
|
||||
999999
|
||||
),
|
||||
f."FieldName"
|
||||
)
|
||||
|
||||
FROM dbo."Sas_H_ListFormField" f
|
||||
|
||||
/*
|
||||
SQL Server:
|
||||
sys.tables
|
||||
sys.columns
|
||||
TYPE_NAME()
|
||||
|
||||
PostgreSQL:
|
||||
information_schema.columns
|
||||
*/
|
||||
LEFT JOIN LATERAL
|
||||
(
|
||||
SELECT
|
||||
c.data_type AS sql_data_type
|
||||
|
||||
FROM information_schema.columns c
|
||||
|
||||
WHERE
|
||||
c.table_schema = 'dbo'
|
||||
|
||||
AND c.table_name =
|
||||
l."TableName"
|
||||
|
||||
AND c.column_name =
|
||||
f."FieldName"
|
||||
|
||||
LIMIT 1
|
||||
|
||||
) sc ON TRUE
|
||||
|
||||
|
||||
/*
|
||||
LookupJson decode
|
||||
*/
|
||||
LEFT JOIN LATERAL
|
||||
(
|
||||
SELECT
|
||||
|
||||
NULLIF
|
||||
(
|
||||
BTRIM
|
||||
(
|
||||
REPLACE(
|
||||
REPLACE(
|
||||
REPLACE(
|
||||
REPLACE(
|
||||
REPLACE(
|
||||
NULLIF(
|
||||
BTRIM(
|
||||
f."LookupJson"::TEXT
|
||||
),
|
||||
''
|
||||
),
|
||||
|
||||
'\\u0022',
|
||||
'"'
|
||||
),
|
||||
|
||||
'\u0022',
|
||||
'"'
|
||||
),
|
||||
|
||||
'\\u0027',
|
||||
''''
|
||||
),
|
||||
|
||||
'\u0027',
|
||||
''''
|
||||
),
|
||||
|
||||
'"',
|
||||
'"'
|
||||
)
|
||||
),
|
||||
|
||||
''
|
||||
) AS lookup_json_text_decoded
|
||||
|
||||
) lj_text ON TRUE
|
||||
|
||||
|
||||
/*
|
||||
PostgreSQL'de ISJSON yerine
|
||||
güvenli JSON parse işlemi gerekiyor.
|
||||
|
||||
LookupJson kolonu zaten JSON/JSONB ise
|
||||
doğrudan kullanılabilir.
|
||||
*/
|
||||
LEFT JOIN LATERAL
|
||||
(
|
||||
SELECT
|
||||
|
||||
lj_text.lookup_json_text_decoded,
|
||||
|
||||
CASE
|
||||
|
||||
WHEN
|
||||
lj_text.lookup_json_text_decoded
|
||||
~ '^\s*[\{\[]'
|
||||
|
||||
THEN
|
||||
lj_text.lookup_json_text_decoded::JSONB
|
||||
|
||||
ELSE NULL
|
||||
|
||||
END AS lookup_json
|
||||
|
||||
) lj ON TRUE
|
||||
|
||||
|
||||
/*
|
||||
LookupQuery değerini al
|
||||
*/
|
||||
LEFT JOIN LATERAL
|
||||
(
|
||||
SELECT
|
||||
|
||||
CASE
|
||||
WHEN lj.lookup_json IS NOT NULL
|
||||
THEN
|
||||
lj.lookup_json
|
||||
->> 'LookupQuery'
|
||||
END AS lookup_query_text
|
||||
|
||||
) lq ON TRUE
|
||||
|
||||
|
||||
/*
|
||||
LookupQuery temizleme
|
||||
*/
|
||||
LEFT JOIN LATERAL
|
||||
(
|
||||
SELECT
|
||||
|
||||
NULLIF
|
||||
(
|
||||
BTRIM
|
||||
(
|
||||
REGEXP_REPLACE
|
||||
(
|
||||
REPLACE(
|
||||
REPLACE(
|
||||
REPLACE(
|
||||
REPLACE(
|
||||
COALESCE(
|
||||
lq.lookup_query_text,
|
||||
''
|
||||
),
|
||||
|
||||
'"',
|
||||
''
|
||||
),
|
||||
|
||||
'[',
|
||||
''
|
||||
),
|
||||
|
||||
']',
|
||||
''
|
||||
),
|
||||
|
||||
'`',
|
||||
''
|
||||
),
|
||||
|
||||
'\s+',
|
||||
' ',
|
||||
'g'
|
||||
)
|
||||
),
|
||||
|
||||
''
|
||||
) AS clean_lookup_query
|
||||
|
||||
) lqc ON TRUE
|
||||
|
||||
|
||||
/*
|
||||
SQL Server prosedürü LookupQuery içerisindeki
|
||||
SELECT ... FROM ... ifadesini string işlemleri
|
||||
ile parse ediyor.
|
||||
|
||||
PostgreSQL'de regexp_match daha temiz.
|
||||
*/
|
||||
LEFT JOIN LATERAL
|
||||
(
|
||||
SELECT
|
||||
|
||||
(
|
||||
REGEXP_MATCH
|
||||
(
|
||||
lqc.clean_lookup_query,
|
||||
|
||||
'(?i)\bFROM\s+([a-zA-Z0-9_\."]+)'
|
||||
)
|
||||
)[1] AS parsed_table,
|
||||
|
||||
COALESCE
|
||||
(
|
||||
NULLIF(
|
||||
lj.lookup_json
|
||||
->> 'ValueExpr',
|
||||
''
|
||||
),
|
||||
|
||||
NULLIF(
|
||||
lj.lookup_json
|
||||
->> 'valueExpr',
|
||||
''
|
||||
),
|
||||
|
||||
NULLIF(
|
||||
lj.lookup_json
|
||||
->> 'valueField',
|
||||
''
|
||||
),
|
||||
|
||||
NULLIF(
|
||||
lj.lookup_json
|
||||
->> 'valueColumn',
|
||||
''
|
||||
),
|
||||
|
||||
NULLIF(
|
||||
lj.lookup_json
|
||||
->> 'keyField',
|
||||
''
|
||||
),
|
||||
|
||||
NULLIF(
|
||||
lj.lookup_json
|
||||
->> 'keyFieldName',
|
||||
''
|
||||
)
|
||||
)
|
||||
AS parsed_lookup_value_column,
|
||||
|
||||
COALESCE
|
||||
(
|
||||
NULLIF(
|
||||
lj.lookup_json
|
||||
->> 'DisplayExpr',
|
||||
''
|
||||
),
|
||||
|
||||
NULLIF(
|
||||
lj.lookup_json
|
||||
->> 'displayExpr',
|
||||
''
|
||||
),
|
||||
|
||||
NULLIF(
|
||||
lj.lookup_json
|
||||
->> 'displayField',
|
||||
''
|
||||
),
|
||||
|
||||
NULLIF(
|
||||
lj.lookup_json
|
||||
->> 'displayColumn',
|
||||
''
|
||||
),
|
||||
|
||||
NULLIF(
|
||||
lj.lookup_json
|
||||
->> 'textField',
|
||||
''
|
||||
),
|
||||
|
||||
NULLIF(
|
||||
lj.lookup_json
|
||||
->> 'textColumn',
|
||||
''
|
||||
),
|
||||
|
||||
NULLIF(
|
||||
lj.lookup_json
|
||||
->> 'nameField',
|
||||
''
|
||||
),
|
||||
|
||||
NULLIF(
|
||||
lj.lookup_json
|
||||
->> 'nameColumn',
|
||||
''
|
||||
)
|
||||
)
|
||||
AS parsed_lookup_display_column
|
||||
|
||||
) parsed ON TRUE
|
||||
|
||||
|
||||
LEFT JOIN LATERAL
|
||||
(
|
||||
SELECT
|
||||
|
||||
NULLIF
|
||||
(
|
||||
REGEXP_REPLACE
|
||||
(
|
||||
COALESCE(
|
||||
parsed.parsed_table,
|
||||
''
|
||||
),
|
||||
|
||||
'^(?i:dbo\.)',
|
||||
|
||||
''
|
||||
),
|
||||
|
||||
''
|
||||
)
|
||||
AS parsed_lookup_table_name,
|
||||
|
||||
parsed.parsed_lookup_value_column,
|
||||
|
||||
parsed.parsed_lookup_display_column
|
||||
|
||||
) lkp ON TRUE
|
||||
|
||||
|
||||
/*
|
||||
Caption translation
|
||||
*/
|
||||
LEFT JOIN LATERAL
|
||||
(
|
||||
SELECT
|
||||
lt."Value"
|
||||
|
||||
FROM dbo."Sas_H_LanguageText" lt
|
||||
|
||||
WHERE
|
||||
lt."CultureName" =
|
||||
p_ui_culture_name
|
||||
|
||||
AND lt."Key" =
|
||||
f."CaptionName"
|
||||
|
||||
AND
|
||||
(
|
||||
p_resource_name IS NULL
|
||||
|
||||
OR lt."ResourceName" =
|
||||
p_resource_name
|
||||
)
|
||||
|
||||
ORDER BY
|
||||
lt."ResourceName"
|
||||
|
||||
LIMIT 1
|
||||
|
||||
) lt_cap ON TRUE
|
||||
|
||||
|
||||
WHERE
|
||||
|
||||
f."ListFormCode" =
|
||||
l."ListFormCode"
|
||||
|
||||
AND f."CultureName" =
|
||||
l."CultureName"
|
||||
|
||||
AND
|
||||
(
|
||||
p_definition_culture_name IS NULL
|
||||
|
||||
OR f."CultureName" =
|
||||
p_definition_culture_name
|
||||
)
|
||||
|
||||
AND
|
||||
(
|
||||
p_only_base_definitions = FALSE
|
||||
|
||||
OR
|
||||
(
|
||||
f."UserId" IS NULL
|
||||
AND f."RoleId" IS NULL
|
||||
)
|
||||
)
|
||||
|
||||
),
|
||||
|
||||
'[]'::JSONB
|
||||
)
|
||||
)
|
||||
AS form_json,
|
||||
|
||||
l."ListFormCode"
|
||||
|
||||
FROM list_form_source l
|
||||
)
|
||||
|
||||
SELECT
|
||||
jsonb_build_object
|
||||
(
|
||||
'listForms',
|
||||
|
||||
COALESCE
|
||||
(
|
||||
jsonb_agg
|
||||
(
|
||||
form_json
|
||||
|
||||
ORDER BY
|
||||
"ListFormCode"
|
||||
),
|
||||
|
||||
'[]'::JSONB
|
||||
)
|
||||
)
|
||||
|
||||
INTO v_result
|
||||
|
||||
FROM list_forms_json;
|
||||
|
||||
|
||||
RETURN COALESCE
|
||||
(
|
||||
v_result,
|
||||
|
||||
jsonb_build_object
|
||||
(
|
||||
'listForms',
|
||||
'[]'::JSONB
|
||||
)
|
||||
);
|
||||
|
||||
END;
|
||||
$$;
|
||||
|
|
@ -0,0 +1,239 @@
|
|||
CREATE OR REPLACE FUNCTION dbo."Sas_H_ListFormFieldsDictionaryJson_SaveDbTableColumns"
|
||||
(
|
||||
p_tenant_name VARCHAR(128) DEFAULT 'Sozsoft',
|
||||
p_definition_culture_name VARCHAR(10) DEFAULT 'en',
|
||||
p_ui_culture_name VARCHAR(10) DEFAULT 'tr',
|
||||
p_list_form_code VARCHAR(64) DEFAULT NULL,
|
||||
p_only_base_definitions BOOLEAN DEFAULT TRUE,
|
||||
p_resource_name VARCHAR(64) DEFAULT NULL,
|
||||
p_max_forms INTEGER DEFAULT 500,
|
||||
p_deactivate_previous BOOLEAN DEFAULT TRUE,
|
||||
p_note VARCHAR(4000) DEFAULT NULL
|
||||
)
|
||||
RETURNS TABLE
|
||||
(
|
||||
"TenantName" VARCHAR,
|
||||
"DictionaryType" VARCHAR,
|
||||
"DefinitionCultureName" VARCHAR,
|
||||
"UiCultureName" VARCHAR,
|
||||
"ListFormCode" VARCHAR,
|
||||
"OnlyBaseDefinitions" BOOLEAN,
|
||||
"ResourceName" VARCHAR,
|
||||
"MaxForms" INTEGER,
|
||||
"CacheKey" TEXT,
|
||||
"FormCount" INTEGER,
|
||||
"FieldCount" INTEGER,
|
||||
"JsonLength" INTEGER,
|
||||
"IsActive" BOOLEAN,
|
||||
"RefreshedAt" TIMESTAMP,
|
||||
"SourceProcedure" VARCHAR,
|
||||
"Note" VARCHAR
|
||||
)
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
v_json_data JSONB;
|
||||
v_cache_key TEXT;
|
||||
v_form_count INTEGER := 0;
|
||||
v_field_count INTEGER := 0;
|
||||
v_json_length INTEGER := 0;
|
||||
BEGIN
|
||||
|
||||
/*
|
||||
SQL Server:
|
||||
EXEC dbo.Sas_H_ListFormFieldsDictionaryJson
|
||||
|
||||
PostgreSQL tarafında bunun JSON / JSONB döndüren bir FUNCTION
|
||||
olduğu varsayılmıştır.
|
||||
*/
|
||||
SELECT dbo."Sas_H_ListFormFieldsDictionaryJson"
|
||||
(
|
||||
p_definition_culture_name,
|
||||
p_ui_culture_name,
|
||||
p_list_form_code,
|
||||
p_only_base_definitions,
|
||||
p_resource_name
|
||||
)
|
||||
INTO v_json_data;
|
||||
|
||||
|
||||
/*
|
||||
JSON boş kontrolü
|
||||
*/
|
||||
IF v_json_data IS NULL THEN
|
||||
RAISE EXCEPTION
|
||||
'JSON veri sözlüğü boş döndü. dbo.Sas_H_ListFormFieldsDictionaryJson çıktısını kontrol edin.'
|
||||
USING ERRCODE = 'P0001';
|
||||
END IF;
|
||||
|
||||
|
||||
/*
|
||||
CacheKey oluşturulması
|
||||
*/
|
||||
v_cache_key :=
|
||||
'ListFormJson|'
|
||||
|| COALESCE(p_tenant_name, '')
|
||||
|| '|'
|
||||
|| COALESCE(p_definition_culture_name, '')
|
||||
|| '|'
|
||||
|| COALESCE(p_ui_culture_name, '')
|
||||
|| '|'
|
||||
|| COALESCE(p_list_form_code, '')
|
||||
|| '|'
|
||||
|| CASE
|
||||
WHEN COALESCE(p_only_base_definitions, TRUE)
|
||||
THEN '1'
|
||||
ELSE '0'
|
||||
END
|
||||
|| '|'
|
||||
|| COALESCE(p_resource_name, '')
|
||||
|| '|'
|
||||
|| COALESCE(p_max_forms, 500)::TEXT;
|
||||
|
||||
|
||||
/*
|
||||
Form sayısı
|
||||
|
||||
JSON:
|
||||
{
|
||||
"listForms": [...]
|
||||
}
|
||||
*/
|
||||
IF jsonb_typeof(v_json_data -> 'listForms') = 'array' THEN
|
||||
|
||||
v_form_count :=
|
||||
jsonb_array_length(v_json_data -> 'listForms');
|
||||
|
||||
END IF;
|
||||
|
||||
|
||||
/*
|
||||
Toplam Field sayısı
|
||||
|
||||
Her listForms elemanının:
|
||||
{
|
||||
"fields": [...]
|
||||
}
|
||||
|
||||
alanındaki kayıtlar sayılır.
|
||||
*/
|
||||
SELECT COUNT(*)::INTEGER
|
||||
INTO v_field_count
|
||||
FROM jsonb_array_elements(
|
||||
COALESCE(
|
||||
v_json_data -> 'listForms',
|
||||
'[]'::JSONB
|
||||
)
|
||||
) AS lf
|
||||
CROSS JOIN LATERAL jsonb_array_elements(
|
||||
CASE
|
||||
WHEN jsonb_typeof(lf -> 'fields') = 'array'
|
||||
THEN lf -> 'fields'
|
||||
ELSE '[]'::JSONB
|
||||
END
|
||||
) AS ff;
|
||||
|
||||
|
||||
/*
|
||||
JSON karakter uzunluğu
|
||||
*/
|
||||
v_json_length := LENGTH(v_json_data::TEXT);
|
||||
|
||||
|
||||
/*
|
||||
PostgreSQL function çağrısı kendi transaction'ı içerisinde
|
||||
çalıştığı için SQL Server'daki BEGIN TRAN / COMMIT burada
|
||||
ayrıca kullanılmaz.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
Önceki aktif kaydı pasif yap
|
||||
*/
|
||||
IF p_deactivate_previous THEN
|
||||
|
||||
UPDATE dbo."Sas_H_DbTableColumn"
|
||||
SET "IsActive" = FALSE
|
||||
WHERE "DictionaryType" = 'ListFormJson'
|
||||
AND "CacheKey" = v_cache_key
|
||||
AND COALESCE("IsActive", FALSE) = TRUE;
|
||||
|
||||
END IF;
|
||||
|
||||
|
||||
/*
|
||||
Yeni JSON kaydını ekle
|
||||
*/
|
||||
INSERT INTO dbo."Sas_H_DbTableColumn"
|
||||
(
|
||||
"TenantName",
|
||||
"DictionaryType",
|
||||
"DefinitionCultureName",
|
||||
"UiCultureName",
|
||||
"ListFormCode",
|
||||
"OnlyBaseDefinitions",
|
||||
"ResourceName",
|
||||
"MaxForms",
|
||||
"CacheKey",
|
||||
"JsonData",
|
||||
"FormCount",
|
||||
"FieldCount",
|
||||
"JsonLength",
|
||||
"IsActive",
|
||||
"RefreshedAt",
|
||||
"SourceProcedure",
|
||||
"Note"
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
COALESCE(p_tenant_name, 'Sozsoft'),
|
||||
'ListFormJson',
|
||||
COALESCE(p_definition_culture_name, 'en'),
|
||||
COALESCE(p_ui_culture_name, 'tr'),
|
||||
p_list_form_code,
|
||||
COALESCE(p_only_base_definitions, TRUE),
|
||||
p_resource_name,
|
||||
COALESCE(p_max_forms, 500),
|
||||
v_cache_key,
|
||||
v_json_data,
|
||||
v_form_count,
|
||||
v_field_count,
|
||||
v_json_length,
|
||||
TRUE,
|
||||
CURRENT_TIMESTAMP,
|
||||
'dbo.Sas_H_ListFormFieldsDictionaryJson',
|
||||
p_note
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
Eklenen aktif kaydı döndür
|
||||
*/
|
||||
RETURN QUERY
|
||||
|
||||
SELECT
|
||||
T."TenantName",
|
||||
T."DictionaryType",
|
||||
T."DefinitionCultureName",
|
||||
T."UiCultureName",
|
||||
T."ListFormCode",
|
||||
T."OnlyBaseDefinitions",
|
||||
T."ResourceName",
|
||||
T."MaxForms",
|
||||
T."CacheKey",
|
||||
T."FormCount",
|
||||
T."FieldCount",
|
||||
T."JsonLength",
|
||||
T."IsActive",
|
||||
T."RefreshedAt",
|
||||
T."SourceProcedure",
|
||||
T."Note"
|
||||
FROM dbo."Sas_H_DbTableColumn" T
|
||||
WHERE T."DictionaryType" = 'ListFormJson'
|
||||
AND T."CacheKey" = v_cache_key
|
||||
AND T."IsActive" = TRUE
|
||||
ORDER BY T."RefreshedAt" DESC
|
||||
LIMIT 1;
|
||||
|
||||
END;
|
||||
$$;
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
CREATE OR REPLACE VIEW dbo."Sas_H_OrderItem_ByTenantId"
|
||||
AS
|
||||
|
||||
SELECT
|
||||
oi."Id",
|
||||
o."TenantId",
|
||||
oi."ProductId",
|
||||
oi."ProductName",
|
||||
oi."BillingCycle",
|
||||
oi."Period",
|
||||
oi."Quantity",
|
||||
oi."Price",
|
||||
oi."VatRate",
|
||||
oi."VatAmount",
|
||||
oi."TotalPrice",
|
||||
oi."OrderId",
|
||||
o."IsActive"
|
||||
|
||||
FROM dbo."Sas_H_Order" o
|
||||
|
||||
INNER JOIN dbo."Sas_H_OrderItem" oi
|
||||
ON o."Id" = oi."OrderId";
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
-- Create View
|
||||
CREATE OR ALTER VIEW [dbo].[Sas_H_OrderItem_ByTenantId]
|
||||
AS
|
||||
|
||||
SELECT dbo.Sas_H_OrderItem.Id, dbo.Sas_H_Order.TenantId, dbo.Sas_H_OrderItem.ProductId, dbo.Sas_H_OrderItem.ProductName, dbo.Sas_H_OrderItem.BillingCycle, dbo.Sas_H_OrderItem.Period, dbo.Sas_H_OrderItem.Quantity,
|
||||
dbo.Sas_H_OrderItem.Price, dbo.Sas_H_OrderItem.VatRate, dbo.Sas_H_OrderItem.VatAmount, dbo.Sas_H_OrderItem.TotalPrice, dbo.Sas_H_OrderItem.OrderId, dbo.Sas_H_Order.IsActive
|
||||
FROM dbo.Sas_H_Order INNER JOIN
|
||||
dbo.Sas_H_OrderItem ON dbo.Sas_H_Order.Id = dbo.Sas_H_OrderItem.OrderId
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
IF OBJECT_ID(N'[dbo].[Pro_T_Approval]', 'U') IS NULL
|
||||
BEGIN
|
||||
CREATE TABLE [dbo].[Pro_T_Approval]
|
||||
(
|
||||
[Id] uniqueidentifier NOT NULL DEFAULT NEWID(),
|
||||
[ApprovalUserName] nvarchar(256) NULL,
|
||||
[ApprovalStatus] nvarchar(50) NULL,
|
||||
[ApprovalDate] datetime NULL,
|
||||
[ApprovalDescription] nvarchar(200) NULL,
|
||||
[TenantId] uniqueidentifier NULL,
|
||||
[Title] nvarchar(100) NULL,
|
||||
CONSTRAINT [PK_Pro_T_Approval] PRIMARY KEY NONCLUSTERED
|
||||
(
|
||||
[Id] ASC
|
||||
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
|
||||
) ON [PRIMARY]
|
||||
END
|
||||
GO
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
IF OBJECT_ID(N'[dbo].[Pro_T_Todo]', 'U') IS NULL
|
||||
BEGIN
|
||||
CREATE TABLE [dbo].[Pro_T_Todo]
|
||||
(
|
||||
[Id] uniqueidentifier NOT NULL DEFAULT NEWID(),
|
||||
[Title] nvarchar(300) NOT NULL,
|
||||
[Status] nvarchar(50) NOT NULL DEFAULT N'Inbox',
|
||||
[Description] nvarchar(MAX) NULL,
|
||||
[DueDate] datetime2 NULL,
|
||||
[Tags] nvarchar(500) NULL,
|
||||
[Assignees] nvarchar(500) NULL,
|
||||
[Priority] nvarchar(50) NULL,
|
||||
[Completed] bit NOT NULL DEFAULT 0,
|
||||
[SortOrder] int NOT NULL DEFAULT 0,
|
||||
[TenantId] uniqueidentifier NULL,
|
||||
CONSTRAINT [PK_Table] PRIMARY KEY NONCLUSTERED
|
||||
(
|
||||
[Id] ASC
|
||||
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
|
||||
) ON [PRIMARY]
|
||||
END
|
||||
GO
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
IF OBJECT_ID(N'[dbo].[Sal_T_Approval]', 'U') IS NULL
|
||||
BEGIN
|
||||
CREATE TABLE [dbo].[Sal_T_Approval]
|
||||
(
|
||||
[Id] uniqueidentifier NOT NULL DEFAULT NEWID(),
|
||||
[CreationTime] datetime2 NOT NULL DEFAULT GETUTCDATE(),
|
||||
[CreatorId] uniqueidentifier NULL,
|
||||
[LastModificationTime] datetime2 NULL,
|
||||
[LastModifierId] uniqueidentifier NULL,
|
||||
[IsDeleted] bit NOT NULL DEFAULT 0,
|
||||
[DeletionTime] datetime2 NULL,
|
||||
[DeleterId] uniqueidentifier NULL,
|
||||
[TenantId] uniqueidentifier NULL,
|
||||
[ApprovalUserName] nvarchar(256) NULL,
|
||||
[ApprovalStatus] nvarchar(50) NULL,
|
||||
[ApprovalDate] datetime NULL,
|
||||
[ApprovalDescription] nvarchar(200) NULL,
|
||||
[Name] nvarchar(100) NULL,
|
||||
CONSTRAINT [PK_Sal_T_Approval] PRIMARY KEY NONCLUSTERED
|
||||
(
|
||||
[Id] ASC
|
||||
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
|
||||
) ON [PRIMARY]
|
||||
END
|
||||
GO
|
||||
|
|
@ -13,27 +13,30 @@
|
|||
"ConfirmDelete": true,
|
||||
"DefaultLayout": "grid",
|
||||
"Grid": true,
|
||||
"Card": true,
|
||||
"Pivot": true,
|
||||
"Tree": true,
|
||||
"Chart": true,
|
||||
"Gantt": true,
|
||||
"Scheduler": true,
|
||||
"Todo": false,
|
||||
"LanguageTextMenuEn": "Approval",
|
||||
"LanguageTextMenuTr": "Approval",
|
||||
"LanguageTextMenuTr": "Onaylama",
|
||||
"LanguageTextTitleEn": "Approval",
|
||||
"LanguageTextTitleTr": "Onaylama",
|
||||
"LanguageTextDescEn": "Approval",
|
||||
"LanguageTextDescTr": "Onaylama",
|
||||
"LanguageTextMenuParentEn": "Sales",
|
||||
"LanguageTextMenuParentTr": "Sat\u0131\u015F",
|
||||
"PermissionGroupName": "App.Wizard.Sales",
|
||||
"MenuParentCode": "App.Wizard.Sales",
|
||||
"MenuParentIcon": "FcAssistant",
|
||||
"MenuIcon": "FcAndroidOs",
|
||||
"LanguageTextMenuParentEn": "Project",
|
||||
"LanguageTextMenuParentTr": "Project",
|
||||
"PermissionGroupName": "App.Wizard.Project",
|
||||
"MenuParentCode": "App.Wizard.Project",
|
||||
"MenuParentShortName": "Pro",
|
||||
"MenuParentIcon": "FcVideoProjector",
|
||||
"MenuIcon": "FcApproval",
|
||||
"DataSourceCode": "Default",
|
||||
"DataSourceConnectionString": "",
|
||||
"SelectCommandType": 1,
|
||||
"SelectCommand": "Sal_T_Approval",
|
||||
"SelectCommand": "Pro_T_Approval",
|
||||
"KeyFieldName": "Id",
|
||||
"KeyFieldDbSourceType": 9,
|
||||
"TreeKeyExpr": "",
|
||||
|
|
@ -49,13 +52,103 @@
|
|||
"SchedulerTextExpr": "",
|
||||
"SchedulerStartDateExpr": "",
|
||||
"SchedulerEndDateExpr": "",
|
||||
"TodoTitleExpr": "",
|
||||
"TodoStatusExpr": "",
|
||||
"TodoDescriptionExpr": "",
|
||||
"TodoDueDateExpr": "",
|
||||
"TodoTagExpr": "",
|
||||
"TodoAssigneeExpr": "",
|
||||
"TodoPriorityExpr": "",
|
||||
"TodoCompletedExpr": "",
|
||||
"TodoOrderExpr": "",
|
||||
"TodoStatusOrder": "Backlog, Ready to Start, In Progress, Code Review, Testing, Staging",
|
||||
"TodoAllowDragging": true,
|
||||
"ApprovalUserFieldName": "ApprovalUserName",
|
||||
"ApprovalDateFieldName": "ApprovalDate",
|
||||
"ApprovalStatusFieldName": "ApprovalStatus",
|
||||
"ApprovalDescriptionFieldName": "ApprovalDescription",
|
||||
"ApprovalIsFilterUserName": false,
|
||||
"Criteria": [
|
||||
{
|
||||
"ListFormCode": "App.Wizard.Approval",
|
||||
"Kind": "Start",
|
||||
"Title": "\u0130\u015F Ak\u0131\u015F\u0131 Ba\u015Flat1",
|
||||
"CompareColumn": "Price",
|
||||
"CompareOperator": "\u003E",
|
||||
"CompareValue": 5000,
|
||||
"Approver": "",
|
||||
"NextOnStart": "App.Wizard.Approval-N002",
|
||||
"NextOnTrue": "",
|
||||
"NextOnFalse": "",
|
||||
"NextOnApprove": "",
|
||||
"NextOnReject": "",
|
||||
"PositionX": 46,
|
||||
"PositionY": 46,
|
||||
"CompareOutcomes": [],
|
||||
"Id": "App.Wizard.Approval-N001"
|
||||
},
|
||||
{
|
||||
"ListFormCode": "App.Wizard.Approval",
|
||||
"Kind": "Approval",
|
||||
"Title": "Onay1",
|
||||
"CompareColumn": "Price",
|
||||
"CompareOperator": "\u003E",
|
||||
"CompareValue": 5000,
|
||||
"Approver": "system@sozsoft.com",
|
||||
"NextOnStart": "",
|
||||
"NextOnTrue": "",
|
||||
"NextOnFalse": "",
|
||||
"NextOnApprove": "App.Wizard.Approval-N003",
|
||||
"NextOnReject": "App.Wizard.Approval-N004",
|
||||
"PositionX": 337,
|
||||
"PositionY": 39,
|
||||
"CompareOutcomes": [],
|
||||
"Id": "App.Wizard.Approval-N002"
|
||||
},
|
||||
{
|
||||
"ListFormCode": "App.Wizard.Approval",
|
||||
"Kind": "Inform",
|
||||
"Title": "Bilgilendirme1",
|
||||
"CompareColumn": "Price",
|
||||
"CompareOperator": "\u003E",
|
||||
"CompareValue": 5000,
|
||||
"Approver": "system@sozsoft.com",
|
||||
"NextOnStart": "App.Wizard.Approval-N004",
|
||||
"NextOnTrue": "",
|
||||
"NextOnFalse": "",
|
||||
"NextOnApprove": "",
|
||||
"NextOnReject": "",
|
||||
"PositionX": 538,
|
||||
"PositionY": 324,
|
||||
"CompareOutcomes": [],
|
||||
"Id": "App.Wizard.Approval-N003"
|
||||
},
|
||||
{
|
||||
"ListFormCode": "App.Wizard.Approval",
|
||||
"Kind": "End",
|
||||
"Title": "\u0130\u015F Ak\u0131\u015F\u0131 Bitir1",
|
||||
"CompareColumn": "Price",
|
||||
"CompareOperator": "\u003E",
|
||||
"CompareValue": 5000,
|
||||
"Approver": "",
|
||||
"NextOnStart": "",
|
||||
"NextOnTrue": "",
|
||||
"NextOnFalse": "",
|
||||
"NextOnApprove": "",
|
||||
"NextOnReject": "",
|
||||
"PositionX": 852,
|
||||
"PositionY": 26,
|
||||
"CompareOutcomes": [],
|
||||
"Id": "App.Wizard.Approval-N004"
|
||||
}
|
||||
],
|
||||
"Groups": [
|
||||
{
|
||||
"Caption": "",
|
||||
"ColCount": 1,
|
||||
"Items": [
|
||||
{
|
||||
"DataField": "Id",
|
||||
"FieldName": "Id",
|
||||
"CaptionName": "App.Listform.ListformField.Id",
|
||||
"EditorType": "dxTextBox",
|
||||
"EditorOptions": "",
|
||||
|
|
@ -72,24 +165,7 @@
|
|||
"LookupQuery": ""
|
||||
},
|
||||
{
|
||||
"DataField": "Name",
|
||||
"CaptionName": "App.Listform.ListformField.Name",
|
||||
"EditorType": "dxTextBox",
|
||||
"EditorOptions": "",
|
||||
"EditorScript": "",
|
||||
"ColSpan": 1,
|
||||
"IsRequired": true,
|
||||
"IncludeInEditingForm": true,
|
||||
"DbSourceType": 16,
|
||||
"TurkishCaption": "Name",
|
||||
"EnglishCaption": "Name",
|
||||
"LookupDataSourceType": 1,
|
||||
"ValueExpr": "Key",
|
||||
"DisplayExpr": "Name",
|
||||
"LookupQuery": ""
|
||||
},
|
||||
{
|
||||
"DataField": "ApprovalUserName",
|
||||
"FieldName": "ApprovalUserName",
|
||||
"CaptionName": "App.Listform.ListformField.ApprovalUserName",
|
||||
"EditorType": "dxTextBox",
|
||||
"EditorOptions": "",
|
||||
|
|
@ -106,7 +182,7 @@
|
|||
"LookupQuery": ""
|
||||
},
|
||||
{
|
||||
"DataField": "ApprovalStatus",
|
||||
"FieldName": "ApprovalStatus",
|
||||
"CaptionName": "App.Listform.ListformField.ApprovalStatus",
|
||||
"EditorType": "dxTextBox",
|
||||
"EditorOptions": "",
|
||||
|
|
@ -123,7 +199,7 @@
|
|||
"LookupQuery": ""
|
||||
},
|
||||
{
|
||||
"DataField": "ApprovalDate",
|
||||
"FieldName": "ApprovalDate",
|
||||
"CaptionName": "App.Listform.ListformField.ApprovalDate",
|
||||
"EditorType": "dxDateBox",
|
||||
"EditorOptions": "",
|
||||
|
|
@ -140,7 +216,7 @@
|
|||
"LookupQuery": ""
|
||||
},
|
||||
{
|
||||
"DataField": "ApprovalDescription",
|
||||
"FieldName": "ApprovalDescription",
|
||||
"CaptionName": "App.Listform.ListformField.ApprovalDescription",
|
||||
"EditorType": "dxTextBox",
|
||||
"EditorOptions": "",
|
||||
|
|
@ -155,219 +231,39 @@
|
|||
"ValueExpr": "Key",
|
||||
"DisplayExpr": "Name",
|
||||
"LookupQuery": ""
|
||||
},
|
||||
{
|
||||
"FieldName": "Title",
|
||||
"CaptionName": "App.Listform.ListformField.Title",
|
||||
"EditorType": "dxTextBox",
|
||||
"EditorOptions": "",
|
||||
"EditorScript": "",
|
||||
"ColSpan": 1,
|
||||
"IsRequired": false,
|
||||
"IncludeInEditingForm": true,
|
||||
"DbSourceType": 16,
|
||||
"TurkishCaption": "Title",
|
||||
"EnglishCaption": "Title",
|
||||
"LookupDataSourceType": 1,
|
||||
"ValueExpr": "Key",
|
||||
"DisplayExpr": "Name",
|
||||
"LookupQuery": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"SubForms": [],
|
||||
"Widgets": [],
|
||||
"Workflow": {
|
||||
"ApprovalUserFieldName": "ApprovalUserName",
|
||||
"IsFilterUserName": true,
|
||||
"ApprovalDateFieldName": "ApprovalDate",
|
||||
"ApprovalStatusFieldName": "ApprovalStatus",
|
||||
"ApprovalDescriptionFieldName": "ApprovalDescription",
|
||||
"Criteria": [
|
||||
{
|
||||
"ListFormCode": "App.Wizard.Approval",
|
||||
"Kind": "Start",
|
||||
"Title": "\u0130\u015F Ak\u0131\u015F\u0131 Ba\u015Flat1",
|
||||
"CompareColumn": "Price",
|
||||
"CompareOperator": "\u003E",
|
||||
"CompareValue": 5000,
|
||||
"Approver": "",
|
||||
"NextOnStart": "N002",
|
||||
"NextOnTrue": "",
|
||||
"NextOnFalse": "",
|
||||
"NextOnApprove": "",
|
||||
"NextOnReject": "",
|
||||
"PositionX": 34,
|
||||
"PositionY": 104,
|
||||
"CompareOutcomes": [],
|
||||
"Id": "N001"
|
||||
},
|
||||
{
|
||||
"ListFormCode": "App.Wizard.Approval",
|
||||
"Kind": "Approval",
|
||||
"Title": "Onay1",
|
||||
"CompareColumn": "Price",
|
||||
"CompareOperator": "\u003E",
|
||||
"CompareValue": 5000,
|
||||
"Approver": "admin@sozsoft.com",
|
||||
"NextOnStart": "",
|
||||
"NextOnTrue": "",
|
||||
"NextOnFalse": "",
|
||||
"NextOnApprove": "N003",
|
||||
"NextOnReject": "N004",
|
||||
"PositionX": 323,
|
||||
"PositionY": 104,
|
||||
"CompareOutcomes": [],
|
||||
"Id": "N002"
|
||||
},
|
||||
{
|
||||
"ListFormCode": "App.Wizard.Approval",
|
||||
"Kind": "Approval",
|
||||
"Title": "Onay2",
|
||||
"CompareColumn": "Price",
|
||||
"CompareOperator": "\u003E",
|
||||
"CompareValue": 5000,
|
||||
"Approver": "demo@sozsoft.com",
|
||||
"NextOnStart": "",
|
||||
"NextOnTrue": "",
|
||||
"NextOnFalse": "",
|
||||
"NextOnApprove": "N004",
|
||||
"NextOnReject": "N004",
|
||||
"PositionX": 586,
|
||||
"PositionY": 104,
|
||||
"CompareOutcomes": [],
|
||||
"Id": "N003"
|
||||
},
|
||||
{
|
||||
"ListFormCode": "App.Wizard.Approval",
|
||||
"Kind": "Inform",
|
||||
"Title": "Bilgilendirme1",
|
||||
"CompareColumn": "Price",
|
||||
"CompareOperator": "\u003E",
|
||||
"CompareValue": 5000,
|
||||
"Approver": "system@sozsoft.com",
|
||||
"NextOnStart": "N005",
|
||||
"NextOnTrue": "",
|
||||
"NextOnFalse": "",
|
||||
"NextOnApprove": "",
|
||||
"NextOnReject": "",
|
||||
"PositionX": 458,
|
||||
"PositionY": 411,
|
||||
"CompareOutcomes": [],
|
||||
"Id": "N004"
|
||||
},
|
||||
{
|
||||
"ListFormCode": "App.Wizard.Approval",
|
||||
"Kind": "End",
|
||||
"Title": "\u0130\u015F Ak\u0131\u015F\u0131 Bitir1",
|
||||
"CompareColumn": "Price",
|
||||
"CompareOperator": "\u003E",
|
||||
"CompareValue": 5000,
|
||||
"Approver": "",
|
||||
"NextOnStart": "",
|
||||
"NextOnTrue": "",
|
||||
"NextOnFalse": "",
|
||||
"NextOnApprove": "",
|
||||
"NextOnReject": "",
|
||||
"PositionX": 792,
|
||||
"PositionY": 412,
|
||||
"CompareOutcomes": [],
|
||||
"Id": "N005"
|
||||
}
|
||||
]
|
||||
},
|
||||
"WorkflowCriteria": [
|
||||
{
|
||||
"ListFormCode": "App.Wizard.Approval",
|
||||
"Kind": "Start",
|
||||
"Title": "\u0130\u015F Ak\u0131\u015F\u0131 Ba\u015Flat1",
|
||||
"CompareColumn": "Price",
|
||||
"CompareOperator": "\u003E",
|
||||
"CompareValue": 5000,
|
||||
"Approver": "",
|
||||
"NextOnStart": "N002",
|
||||
"NextOnTrue": "",
|
||||
"NextOnFalse": "",
|
||||
"NextOnApprove": "",
|
||||
"NextOnReject": "",
|
||||
"PositionX": 34,
|
||||
"PositionY": 104,
|
||||
"CompareOutcomes": [],
|
||||
"Id": "N001"
|
||||
},
|
||||
{
|
||||
"ListFormCode": "App.Wizard.Approval",
|
||||
"Kind": "Approval",
|
||||
"Title": "Onay1",
|
||||
"CompareColumn": "Price",
|
||||
"CompareOperator": "\u003E",
|
||||
"CompareValue": 5000,
|
||||
"Approver": "admin@sozsoft.com",
|
||||
"NextOnStart": "",
|
||||
"NextOnTrue": "",
|
||||
"NextOnFalse": "",
|
||||
"NextOnApprove": "N003",
|
||||
"NextOnReject": "N004",
|
||||
"PositionX": 323,
|
||||
"PositionY": 104,
|
||||
"CompareOutcomes": [],
|
||||
"Id": "N002"
|
||||
},
|
||||
{
|
||||
"ListFormCode": "App.Wizard.Approval",
|
||||
"Kind": "Approval",
|
||||
"Title": "Onay2",
|
||||
"CompareColumn": "Price",
|
||||
"CompareOperator": "\u003E",
|
||||
"CompareValue": 5000,
|
||||
"Approver": "demo@sozsoft.com",
|
||||
"NextOnStart": "",
|
||||
"NextOnTrue": "",
|
||||
"NextOnFalse": "",
|
||||
"NextOnApprove": "N004",
|
||||
"NextOnReject": "N004",
|
||||
"PositionX": 586,
|
||||
"PositionY": 104,
|
||||
"CompareOutcomes": [],
|
||||
"Id": "N003"
|
||||
},
|
||||
{
|
||||
"ListFormCode": "App.Wizard.Approval",
|
||||
"Kind": "Inform",
|
||||
"Title": "Bilgilendirme1",
|
||||
"CompareColumn": "Price",
|
||||
"CompareOperator": "\u003E",
|
||||
"CompareValue": 5000,
|
||||
"Approver": "system@sozsoft.com",
|
||||
"NextOnStart": "N005",
|
||||
"NextOnTrue": "",
|
||||
"NextOnFalse": "",
|
||||
"NextOnApprove": "",
|
||||
"NextOnReject": "",
|
||||
"PositionX": 458,
|
||||
"PositionY": 411,
|
||||
"CompareOutcomes": [],
|
||||
"Id": "N004"
|
||||
},
|
||||
{
|
||||
"ListFormCode": "App.Wizard.Approval",
|
||||
"Kind": "End",
|
||||
"Title": "\u0130\u015F Ak\u0131\u015F\u0131 Bitir1",
|
||||
"CompareColumn": "Price",
|
||||
"CompareOperator": "\u003E",
|
||||
"CompareValue": 5000,
|
||||
"Approver": "",
|
||||
"NextOnStart": "",
|
||||
"NextOnTrue": "",
|
||||
"NextOnFalse": "",
|
||||
"NextOnApprove": "",
|
||||
"NextOnReject": "",
|
||||
"PositionX": 792,
|
||||
"PositionY": 412,
|
||||
"CompareOutcomes": [],
|
||||
"Id": "N005"
|
||||
}
|
||||
]
|
||||
"Widgets": []
|
||||
},
|
||||
"IsDeletedField": true,
|
||||
"IsCreatedField": true,
|
||||
"IsDeletedField": false,
|
||||
"IsCreatedField": false,
|
||||
"InsertedRecords": {
|
||||
"LanguageKeys": [
|
||||
"App.Wizard.Approval",
|
||||
"App.Wizard.Approval.Title",
|
||||
"App.Wizard.Approval.Desc",
|
||||
"App.Listform.ListformField.ApprovalUserName",
|
||||
"App.Listform.ListformField.ApprovalStatus",
|
||||
"App.Listform.ListformField.ApprovalDate",
|
||||
"App.Listform.ListformField.ApprovalDescription"
|
||||
],
|
||||
"PermissionGroupNames": [
|
||||
"App.Wizard.Sales"
|
||||
"App.Wizard.Approval.Desc"
|
||||
],
|
||||
"PermissionGroupNames": [],
|
||||
"PermissionNames": [
|
||||
"App.Wizard.Approval",
|
||||
"App.Wizard.Approval.Create",
|
||||
|
|
@ -0,0 +1,281 @@
|
|||
{
|
||||
"Wizard": {
|
||||
"WizardName": "Todo",
|
||||
"ListFormCode": "App.Wizard.Todo",
|
||||
"MenuCode": "App.Wizard.Todo",
|
||||
"IsTenant": true,
|
||||
"IsBranch": false,
|
||||
"IsOrganizationUnit": false,
|
||||
"AllowAdding": true,
|
||||
"AllowUpdating": true,
|
||||
"AllowDeleting": true,
|
||||
"AllowDetail": false,
|
||||
"ConfirmDelete": true,
|
||||
"DefaultLayout": "todo",
|
||||
"Grid": true,
|
||||
"Card": true,
|
||||
"Pivot": true,
|
||||
"Tree": true,
|
||||
"Chart": true,
|
||||
"Gantt": true,
|
||||
"Scheduler": true,
|
||||
"Todo": true,
|
||||
"LanguageTextMenuEn": "Todo",
|
||||
"LanguageTextMenuTr": "\u0130\u015Fler",
|
||||
"LanguageTextTitleEn": "Todo",
|
||||
"LanguageTextTitleTr": "\u0130\u015Fler",
|
||||
"LanguageTextDescEn": "Todo",
|
||||
"LanguageTextDescTr": "\u0130\u015Fler",
|
||||
"LanguageTextMenuParentEn": "Project",
|
||||
"LanguageTextMenuParentTr": "Project",
|
||||
"PermissionGroupName": "App.Wizard.Project",
|
||||
"MenuParentCode": "App.Wizard.Project",
|
||||
"MenuParentShortName": "Pro",
|
||||
"MenuParentIcon": "FcVideoProjector",
|
||||
"MenuIcon": "FcTodoList",
|
||||
"DataSourceCode": "Default",
|
||||
"DataSourceConnectionString": "",
|
||||
"SelectCommandType": 1,
|
||||
"SelectCommand": "Pro_T_Todo",
|
||||
"KeyFieldName": "Id",
|
||||
"KeyFieldDbSourceType": 9,
|
||||
"TreeKeyExpr": "",
|
||||
"TreeParentIdExpr": "",
|
||||
"TreeAutoExpandAll": false,
|
||||
"GanttKeyExpr": "",
|
||||
"GanttParentIdExpr": "",
|
||||
"GanttAutoExpandAll": false,
|
||||
"GanttTitleExpr": "",
|
||||
"GanttStartExpr": "",
|
||||
"GanttEndExpr": "",
|
||||
"GanttProgressExpr": "",
|
||||
"SchedulerTextExpr": "",
|
||||
"SchedulerStartDateExpr": "",
|
||||
"SchedulerEndDateExpr": "",
|
||||
"TodoTitleExpr": "Title",
|
||||
"TodoStatusExpr": "Status",
|
||||
"TodoDescriptionExpr": "Description",
|
||||
"TodoDueDateExpr": "DueDate",
|
||||
"TodoTagExpr": "Tags",
|
||||
"TodoAssigneeExpr": "Assignees",
|
||||
"TodoPriorityExpr": "Priority",
|
||||
"TodoCompletedExpr": "Completed",
|
||||
"TodoOrderExpr": "SortOrder",
|
||||
"TodoStatusOrder": "Backlog, Ready to Start, In Progress, Code Review, Testing, Staging",
|
||||
"TodoAllowDragging": true,
|
||||
"ApprovalUserFieldName": "",
|
||||
"ApprovalDateFieldName": "",
|
||||
"ApprovalStatusFieldName": "",
|
||||
"ApprovalDescriptionFieldName": "",
|
||||
"ApprovalIsFilterUserName": false,
|
||||
"Criteria": [],
|
||||
"Groups": [
|
||||
{
|
||||
"Caption": "",
|
||||
"ColCount": 1,
|
||||
"Items": [
|
||||
{
|
||||
"FieldName": "Id",
|
||||
"CaptionName": "App.Listform.ListformField.Id",
|
||||
"EditorType": "dxTextBox",
|
||||
"EditorOptions": "",
|
||||
"EditorScript": "",
|
||||
"ColSpan": 1,
|
||||
"IsRequired": true,
|
||||
"IncludeInEditingForm": true,
|
||||
"DbSourceType": 9,
|
||||
"TurkishCaption": "Id",
|
||||
"EnglishCaption": "Id",
|
||||
"LookupDataSourceType": 1,
|
||||
"ValueExpr": "Key",
|
||||
"DisplayExpr": "Name",
|
||||
"LookupQuery": ""
|
||||
},
|
||||
{
|
||||
"FieldName": "Title",
|
||||
"CaptionName": "App.Listform.ListformField.Title",
|
||||
"EditorType": "dxTextBox",
|
||||
"EditorOptions": "",
|
||||
"EditorScript": "",
|
||||
"ColSpan": 1,
|
||||
"IsRequired": true,
|
||||
"IncludeInEditingForm": true,
|
||||
"DbSourceType": 16,
|
||||
"TurkishCaption": "Title",
|
||||
"EnglishCaption": "Title",
|
||||
"LookupDataSourceType": 1,
|
||||
"ValueExpr": "Key",
|
||||
"DisplayExpr": "Name",
|
||||
"LookupQuery": ""
|
||||
},
|
||||
{
|
||||
"FieldName": "Status",
|
||||
"CaptionName": "App.Listform.ListformField.Status",
|
||||
"EditorType": "dxTextBox",
|
||||
"EditorOptions": "",
|
||||
"EditorScript": "",
|
||||
"ColSpan": 1,
|
||||
"IsRequired": true,
|
||||
"IncludeInEditingForm": false,
|
||||
"DbSourceType": 16,
|
||||
"TurkishCaption": "Status",
|
||||
"EnglishCaption": "Status",
|
||||
"LookupDataSourceType": 1,
|
||||
"ValueExpr": "Key",
|
||||
"DisplayExpr": "Name",
|
||||
"LookupQuery": ""
|
||||
},
|
||||
{
|
||||
"FieldName": "Description",
|
||||
"CaptionName": "App.Listform.ListformField.Description",
|
||||
"EditorType": "dxHtmlEditor",
|
||||
"EditorOptions": "{\u0022mediaResizing\u0022:{\u0022enabled\u0022:true},\u0022imageUpload\u0022:{\u0022tabs\u0022:[\u0022file\u0022,\u0022url\u0022],\u0022fileUploadMode\u0022:\u0022base64\u0022},\u0022toolbar\u0022:{\u0022multiline\u0022:true,\u0022items\u0022:[{\u0022name\u0022:\u0022undo\u0022},{\u0022name\u0022:\u0022redo\u0022},{\u0022name\u0022:\u0022separator\u0022},{\u0022name\u0022:\u0022size\u0022,\u0022acceptedValues\u0022:[\u00228pt\u0022,\u002210pt\u0022,\u002212pt\u0022,\u002214pt\u0022,\u002218pt\u0022,\u002224pt\u0022,\u002236pt\u0022],\u0022options\u0022:{\u0022inputAttr\u0022:{\u0022aria-label\u0022:\u0022Font size\u0022}}},{\u0022name\u0022:\u0022font\u0022,\u0022acceptedValues\u0022:[\u0022Arial\u0022,\u0022Courier New\u0022,\u0022Georgia\u0022,\u0022Impact\u0022,\u0022Lucida Console\u0022,\u0022Tahoma\u0022,\u0022Times New Roman\u0022,\u0022Verdana\u0022],\u0022options\u0022:{\u0022inputAttr\u0022:{\u0022aria-label\u0022:\u0022Font family\u0022}}},{\u0022name\u0022:\u0022separator\u0022},{\u0022name\u0022:\u0022bold\u0022},{\u0022name\u0022:\u0022italic\u0022},{\u0022name\u0022:\u0022strike\u0022},{\u0022name\u0022:\u0022underline\u0022},{\u0022name\u0022:\u0022separator\u0022},{\u0022name\u0022:\u0022alignLeft\u0022},{\u0022name\u0022:\u0022alignCenter\u0022},{\u0022name\u0022:\u0022alignRight\u0022},{\u0022name\u0022:\u0022alignJustify\u0022},{\u0022name\u0022:\u0022separator\u0022},{\u0022name\u0022:\u0022orderedList\u0022},{\u0022name\u0022:\u0022bulletList\u0022},{\u0022name\u0022:\u0022separator\u0022},{\u0022name\u0022:\u0022header\u0022,\u0022acceptedValues\u0022:[false,1,2,3,4,5]},{\u0022name\u0022:\u0022separator\u0022},{\u0022name\u0022:\u0022color\u0022},{\u0022name\u0022:\u0022background\u0022},{\u0022name\u0022:\u0022separator\u0022},{\u0022name\u0022:\u0022link\u0022},{\u0022name\u0022:\u0022image\u0022},{\u0022name\u0022:\u0022separator\u0022},{\u0022name\u0022:\u0022clear\u0022},{\u0022name\u0022:\u0022codeBlock\u0022},{\u0022name\u0022:\u0022blockquote\u0022},{\u0022name\u0022:\u0022separator\u0022},{\u0022name\u0022:\u0022insertTable\u0022},{\u0022name\u0022:\u0022deleteTable\u0022},{\u0022name\u0022:\u0022insertRowAbove\u0022},{\u0022name\u0022:\u0022insertRowBelow\u0022},{\u0022name\u0022:\u0022deleteRow\u0022},{\u0022name\u0022:\u0022insertColumnLeft\u0022},{\u0022name\u0022:\u0022insertColumnRight\u0022},{\u0022name\u0022:\u0022deleteColumn\u0022},{\u0022name\u0022:\u0022cellProperties\u0022},{\u0022name\u0022:\u0022tableProperties\u0022}]}}",
|
||||
"EditorScript": "",
|
||||
"ColSpan": 1,
|
||||
"IsRequired": false,
|
||||
"IncludeInEditingForm": false,
|
||||
"DbSourceType": 16,
|
||||
"TurkishCaption": "Description",
|
||||
"EnglishCaption": "Description",
|
||||
"LookupDataSourceType": 1,
|
||||
"ValueExpr": "Key",
|
||||
"DisplayExpr": "Name",
|
||||
"LookupQuery": ""
|
||||
},
|
||||
{
|
||||
"FieldName": "DueDate",
|
||||
"CaptionName": "App.Listform.ListformField.DueDate",
|
||||
"EditorType": "dxDateBox",
|
||||
"EditorOptions": "",
|
||||
"EditorScript": "",
|
||||
"ColSpan": 1,
|
||||
"IsRequired": false,
|
||||
"IncludeInEditingForm": false,
|
||||
"DbSourceType": 6,
|
||||
"TurkishCaption": "Due Date",
|
||||
"EnglishCaption": "Due Date",
|
||||
"LookupDataSourceType": 1,
|
||||
"ValueExpr": "Key",
|
||||
"DisplayExpr": "Name",
|
||||
"LookupQuery": ""
|
||||
},
|
||||
{
|
||||
"FieldName": "Tags",
|
||||
"CaptionName": "App.Listform.ListformField.Tags",
|
||||
"EditorType": "dxTextBox",
|
||||
"EditorOptions": "",
|
||||
"EditorScript": "",
|
||||
"ColSpan": 1,
|
||||
"IsRequired": false,
|
||||
"IncludeInEditingForm": false,
|
||||
"DbSourceType": 16,
|
||||
"TurkishCaption": "Tags",
|
||||
"EnglishCaption": "Tags",
|
||||
"LookupDataSourceType": 1,
|
||||
"ValueExpr": "Key",
|
||||
"DisplayExpr": "Name",
|
||||
"LookupQuery": ""
|
||||
},
|
||||
{
|
||||
"FieldName": "Assignees",
|
||||
"CaptionName": "App.Listform.ListformField.Assignees",
|
||||
"EditorType": "dxTextBox",
|
||||
"EditorOptions": "",
|
||||
"EditorScript": "",
|
||||
"ColSpan": 1,
|
||||
"IsRequired": false,
|
||||
"IncludeInEditingForm": false,
|
||||
"DbSourceType": 16,
|
||||
"TurkishCaption": "Assignees",
|
||||
"EnglishCaption": "Assignees",
|
||||
"LookupDataSourceType": 1,
|
||||
"ValueExpr": "Key",
|
||||
"DisplayExpr": "Name",
|
||||
"LookupQuery": ""
|
||||
},
|
||||
{
|
||||
"FieldName": "Priority",
|
||||
"CaptionName": "App.Listform.ListformField.Priority",
|
||||
"EditorType": "dxTextBox",
|
||||
"EditorOptions": "",
|
||||
"EditorScript": "",
|
||||
"ColSpan": 1,
|
||||
"IsRequired": false,
|
||||
"IncludeInEditingForm": false,
|
||||
"DbSourceType": 16,
|
||||
"TurkishCaption": "Priority",
|
||||
"EnglishCaption": "Priority",
|
||||
"LookupDataSourceType": 1,
|
||||
"ValueExpr": "Key",
|
||||
"DisplayExpr": "Name",
|
||||
"LookupQuery": ""
|
||||
},
|
||||
{
|
||||
"FieldName": "Completed",
|
||||
"CaptionName": "App.Listform.ListformField.Completed",
|
||||
"EditorType": "dxCheckBox",
|
||||
"EditorOptions": "",
|
||||
"EditorScript": "",
|
||||
"ColSpan": 1,
|
||||
"IsRequired": true,
|
||||
"IncludeInEditingForm": false,
|
||||
"DbSourceType": 3,
|
||||
"TurkishCaption": "Completed",
|
||||
"EnglishCaption": "Completed",
|
||||
"LookupDataSourceType": 1,
|
||||
"ValueExpr": "Key",
|
||||
"DisplayExpr": "Name",
|
||||
"LookupQuery": ""
|
||||
},
|
||||
{
|
||||
"FieldName": "SortOrder",
|
||||
"CaptionName": "App.Listform.ListformField.SortOrder",
|
||||
"EditorType": "dxNumberBox",
|
||||
"EditorOptions": "",
|
||||
"EditorScript": "",
|
||||
"ColSpan": 1,
|
||||
"IsRequired": true,
|
||||
"IncludeInEditingForm": false,
|
||||
"DbSourceType": 11,
|
||||
"TurkishCaption": "Sort Order",
|
||||
"EnglishCaption": "Sort Order",
|
||||
"LookupDataSourceType": 1,
|
||||
"ValueExpr": "Key",
|
||||
"DisplayExpr": "Name",
|
||||
"LookupQuery": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"SubForms": [],
|
||||
"Widgets": []
|
||||
},
|
||||
"IsDeletedField": false,
|
||||
"IsCreatedField": false,
|
||||
"InsertedRecords": {
|
||||
"LanguageKeys": [
|
||||
"App.Wizard.Todo",
|
||||
"App.Wizard.Todo.Title",
|
||||
"App.Wizard.Todo.Desc",
|
||||
"App.Listform.ListformField.Assignees",
|
||||
"App.Listform.ListformField.Completed",
|
||||
"App.Listform.ListformField.SortOrder"
|
||||
],
|
||||
"PermissionGroupNames": [
|
||||
"App.Wizard.Project"
|
||||
],
|
||||
"PermissionNames": [
|
||||
"App.Wizard.Todo",
|
||||
"App.Wizard.Todo.Create",
|
||||
"App.Wizard.Todo.Update",
|
||||
"App.Wizard.Todo.Delete",
|
||||
"App.Wizard.Todo.Export",
|
||||
"App.Wizard.Todo.Import",
|
||||
"App.Wizard.Todo.Note"
|
||||
],
|
||||
"MenuCodes": [
|
||||
"App.Wizard.Todo"
|
||||
],
|
||||
"DataSourceCodes": []
|
||||
}
|
||||
}
|
||||
|
|
@ -107,6 +107,8 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
|
||||
var fileName = Path.GetFileName(filePath);
|
||||
|
||||
await BackfillMenuParentShortNameAsync(seedFile.Wizard);
|
||||
|
||||
// Zaten seeded mi kontrol et (ListForm var mı?)
|
||||
if (await _repoListForm.AnyAsync(a => a.ListFormCode == seedFile.Wizard.ListFormCode))
|
||||
{
|
||||
|
|
@ -132,14 +134,17 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
var isCreated = seedFile.IsCreatedField;
|
||||
input.SubForms ??= new List<SubFormDto>();
|
||||
input.Widgets ??= new List<WidgetEditDto>();
|
||||
input.Workflow ??= new WorkflowDto();
|
||||
input.WorkflowCriteria ??= new List<ListFormWorkflowCriteriaDto>();
|
||||
if (input.WorkflowCriteria.Count == 0 && input.Workflow.Criteria?.Count > 0)
|
||||
input.Criteria ??= [];
|
||||
EnsureUniqueWorkflowCriteriaTitles(input.Criteria);
|
||||
var workflow = new WorkflowDto
|
||||
{
|
||||
input.WorkflowCriteria = input.Workflow.Criteria;
|
||||
}
|
||||
input.Workflow.Criteria = input.WorkflowCriteria;
|
||||
EnsureUniqueWorkflowCriteriaTitles(input.WorkflowCriteria);
|
||||
ApprovalUserFieldName = input.ApprovalUserFieldName,
|
||||
ApprovalIsFilterUserName = input.ApprovalIsFilterUserName,
|
||||
ApprovalDateFieldName = input.ApprovalDateFieldName,
|
||||
ApprovalStatusFieldName = input.ApprovalStatusFieldName,
|
||||
ApprovalDescriptionFieldName = input.ApprovalDescriptionFieldName,
|
||||
Criteria = input.Criteria,
|
||||
};
|
||||
|
||||
var wizardName = input.WizardName.Trim();
|
||||
var code = string.IsNullOrWhiteSpace(input.MenuCode)
|
||||
|
|
@ -148,7 +153,7 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
var listFormCode = string.IsNullOrWhiteSpace(input.ListFormCode)
|
||||
? code
|
||||
: input.ListFormCode.Trim();
|
||||
NormalizeWorkflowCriteriaIds(listFormCode, input.WorkflowCriteria);
|
||||
NormalizeWorkflowCriteriaIds(listFormCode, input.Criteria);
|
||||
var titleLangKey = $"{listFormCode}.Title";
|
||||
var nameLangKey = code;
|
||||
var descLangKey = $"{listFormCode}.Desc";
|
||||
|
|
@ -250,6 +255,7 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
Code = input.MenuParentCode,
|
||||
DisplayName = input.MenuParentCode,
|
||||
IsDisabled = false,
|
||||
ShortName = input.MenuParentShortName,
|
||||
Icon = menuParentIcon,
|
||||
Order = maxRootOrder + 1,
|
||||
}, autoSave: true);
|
||||
|
|
@ -299,21 +305,9 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
Caption = g.Caption,
|
||||
ColCount = g.ColCount,
|
||||
ColSpan = g.ColCount,
|
||||
ItemType = "group",
|
||||
Items = g.Items
|
||||
.Where(i => i.IncludeInEditingForm && i.DataField != input.KeyFieldName)
|
||||
.Select((it, ii) => new EditingFormItemDto
|
||||
{
|
||||
Order = ii + 1,
|
||||
DataField = it.DataField,
|
||||
EditorType2 = it.EditorType,
|
||||
ColSpan = it.ColSpan,
|
||||
EditorOptions = string.IsNullOrWhiteSpace(it.EditorOptions) ? null : it.EditorOptions,
|
||||
EditorScript = string.IsNullOrWhiteSpace(it.EditorScript) ? null : it.EditorScript,
|
||||
})
|
||||
.ToArray()
|
||||
ItemType = "group"
|
||||
})
|
||||
.Where(g => g.Items.Length > 0)
|
||||
.Where((_, index) => input.Groups[index].Items.Any(i => i.IncludeInEditingForm && i.FieldName != input.KeyFieldName))
|
||||
.ToList();
|
||||
|
||||
// ListForm - varsa sil, yeniden ekle
|
||||
|
|
@ -338,8 +332,8 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
// EditingForm'da required olan alanları tespit et, ValidationRuleJson eklemek için
|
||||
var editingFormFieldNames = input.Groups
|
||||
.SelectMany(g => g.Items)
|
||||
.Where(i => i.IncludeInEditingForm && i.DataField != input.KeyFieldName)
|
||||
.Select(i => new { FieldName = i.DataField, Isrequired = i.IsRequired })
|
||||
.Where(i => i.IncludeInEditingForm && i.FieldName != input.KeyFieldName)
|
||||
.Select(i => new { FieldName = i.FieldName, Isrequired = i.IsRequired })
|
||||
.ToList();
|
||||
|
||||
// Heigth ve Width hesaplama
|
||||
|
|
@ -347,7 +341,7 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
.Select(g =>
|
||||
{
|
||||
var items = g.Items
|
||||
.Where(i => i.IncludeInEditingForm && i.DataField != input.KeyFieldName)
|
||||
.Where(i => i.IncludeInEditingForm && i.FieldName != input.KeyFieldName)
|
||||
.ToList();
|
||||
|
||||
var columnCount = g.ColCount;
|
||||
|
|
@ -392,8 +386,8 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
PageSize = 10,
|
||||
ExportJson = WizardConsts.DefaultExportJson,
|
||||
IsSubForm = false,
|
||||
ShowNote = input.SubForms.Count > 0 || input.WorkflowCriteria.Count > 0,
|
||||
LayoutJson = WizardConsts.DefaultLayoutJson(input.DefaultLayout, input.Grid, input.Pivot, input.Tree, input.Chart, input.Gantt, input.Scheduler),
|
||||
ShowNote = input.SubForms.Count > 0 || input.Criteria.Count > 0,
|
||||
LayoutJson = WizardConsts.DefaultLayoutJson(input.DefaultLayout, input.Grid, input.Card, input.Pivot, input.Tree, input.Chart, input.Gantt, input.Scheduler, input.Todo),
|
||||
CultureName = LanguageCodes.En,
|
||||
ListFormCode = input.ListFormCode,
|
||||
Name = nameLangKey,
|
||||
|
|
@ -413,41 +407,74 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
HeaderFilterJson = WizardConsts.DefaultHeaderFilterJson(),
|
||||
SearchPanelJson = WizardConsts.DefaultSearchPanelJson(),
|
||||
GroupPanelJson = WizardConsts.DefaultGroupPanelJson(),
|
||||
SelectionJson = WizardConsts.DefaultSelectionSingleJson(input.WorkflowCriteria.Count > 0 ? GridOptions.SelectionModeSingle : GridOptions.SelectionModeNone),
|
||||
SelectionJson = WizardConsts.DefaultSelectionSingleJson(input.Criteria.Count > 0 ? GridOptions.SelectionModeSingle : GridOptions.SelectionModeNone),
|
||||
ColumnOptionJson = WizardConsts.DefaultColumnOptionJson(),
|
||||
PermissionJson = WizardConsts.DefaultPermissionJson(code),
|
||||
DeleteCommand = isDeleted ? WizardConsts.DefaultDeleteCommand(input.SelectCommand) : null,
|
||||
DeleteFieldsDefaultValueJson = isDeleted
|
||||
? WizardConsts.DefaultDeleteFieldsDefaultValueJson(input.KeyFieldDbSourceType)
|
||||
: WizardConsts.DefaultFieldsJsonOnlyId(input.KeyFieldDbSourceType),
|
||||
: WizardConsts.DefaultDeleteFieldsJsonOnlyId(input.KeyFieldDbSourceType),
|
||||
InsertFieldsDefaultValueJson = isCreated
|
||||
? WizardConsts.DefaultInsertFieldsDefaultValueJson(input.KeyFieldDbSourceType)
|
||||
: WizardConsts.DefaultFieldsJsonOnlyId(input.KeyFieldDbSourceType),
|
||||
: WizardConsts.DefaultInsertFieldsJsonOnlyId(input.KeyFieldDbSourceType),
|
||||
PagerOptionJson = WizardConsts.DefaultPagerOptionJson,
|
||||
EditingOptionJson = WizardConsts.DefaultEditingOptionJson(titleLangKey, formWidth, formHeight, input.AllowDeleting, input.AllowAdding, input.AllowUpdating, input.ConfirmDelete, false, input.AllowDetail),
|
||||
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,
|
||||
WorkflowJson = HasWorkflow(workflow, input.Criteria) ? JsonSerializer.Serialize(workflow) : null,
|
||||
TodoOptionJson = (input.Todo || input.DefaultLayout == "todo") &&
|
||||
!string.IsNullOrEmpty(input.TodoTitleExpr) &&
|
||||
!string.IsNullOrEmpty(input.TodoStatusExpr)
|
||||
? JsonSerializer.Serialize(new TodoOptionDto
|
||||
{
|
||||
TitleExpr = input.TodoTitleExpr,
|
||||
StatusExpr = input.TodoStatusExpr,
|
||||
DescriptionExpr = input.TodoDescriptionExpr,
|
||||
DueDateExpr = input.TodoDueDateExpr,
|
||||
TagExpr = input.TodoTagExpr,
|
||||
AssigneeExpr = input.TodoAssigneeExpr,
|
||||
PriorityExpr = input.TodoPriorityExpr,
|
||||
CompletedExpr = input.TodoCompletedExpr,
|
||||
OrderExpr = input.TodoOrderExpr,
|
||||
StatusOrder = input.TodoStatusOrder,
|
||||
AllowDragging = input.TodoAllowDragging,
|
||||
})
|
||||
: null,
|
||||
}, autoSave: true);
|
||||
|
||||
// ListFormFields
|
||||
var fieldOrder = 0;
|
||||
var editGroupOrder = 0;
|
||||
foreach (var group in input.Groups)
|
||||
{
|
||||
editGroupOrder++;
|
||||
var editOrder = 0;
|
||||
foreach (var item in group.Items)
|
||||
{
|
||||
fieldOrder++;
|
||||
if (item.IncludeInEditingForm && item.FieldName != input.KeyFieldName)
|
||||
{
|
||||
editOrder++;
|
||||
}
|
||||
await _repoListFormField.InsertAsync(new ListFormField
|
||||
{
|
||||
ListFormCode = input.ListFormCode,
|
||||
FieldName = item.DataField,
|
||||
FieldName = item.FieldName,
|
||||
CaptionName = item.CaptionName,
|
||||
Visible = item.DataField != input.KeyFieldName,
|
||||
Visible = item.FieldName != input.KeyFieldName,
|
||||
IsActive = true,
|
||||
Width = 0, //Fit columns için hepsine sıfır veriyorum.
|
||||
AllowSearch = true,
|
||||
ListOrderNo = fieldOrder,
|
||||
EditGroupOrderNo = item.IncludeInEditingForm ? editGroupOrder : null,
|
||||
EditOrderNo = item.IncludeInEditingForm && item.FieldName != input.KeyFieldName
|
||||
? editOrder
|
||||
: null,
|
||||
EditorType2 = item.EditorType,
|
||||
ColSpan = item.ColSpan,
|
||||
EditorOptions = string.IsNullOrWhiteSpace(item.EditorOptions) ? null : item.EditorOptions,
|
||||
EditorScript = string.IsNullOrWhiteSpace(item.EditorScript) ? null : item.EditorScript,
|
||||
SourceDbType = item.DbSourceType,
|
||||
CultureName = PlatformConsts.DefaultLanguage,
|
||||
PermissionJson = WizardConsts.DefaultFieldPermissionJson(code),
|
||||
|
|
@ -457,7 +484,7 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
LookupJson = !string.IsNullOrWhiteSpace(item.LookupQuery)
|
||||
? WizardConsts.DefaultLookupJson(item.LookupDataSourceType, item.DisplayExpr, item.ValueExpr, item.LookupQuery)
|
||||
: null,
|
||||
ValidationRuleJson = editingFormFieldNames.Any(f => f.FieldName == item.DataField && f.Isrequired)
|
||||
ValidationRuleJson = editingFormFieldNames.Any(f => f.FieldName == item.FieldName && f.Isrequired)
|
||||
? WizardConsts.DefaultValidationRuleRequiredJson
|
||||
: null
|
||||
}, autoSave: true);
|
||||
|
|
@ -466,7 +493,7 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
}
|
||||
}
|
||||
|
||||
foreach (var criteria in input.WorkflowCriteria)
|
||||
foreach (var criteria in input.Criteria)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(criteria.Id))
|
||||
{
|
||||
|
|
@ -495,6 +522,24 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
}
|
||||
}
|
||||
|
||||
private async Task BackfillMenuParentShortNameAsync(ListFormWizardDto input)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(input.MenuParentCode) ||
|
||||
string.IsNullOrWhiteSpace(input.MenuParentShortName))
|
||||
return;
|
||||
|
||||
var menuParent = await _repoMenu.FirstOrDefaultAsync(a => a.Code == input.MenuParentCode);
|
||||
if (menuParent == null || !string.IsNullOrWhiteSpace(menuParent.ShortName))
|
||||
return;
|
||||
|
||||
menuParent.ShortName = input.MenuParentShortName.Trim();
|
||||
await _repoMenu.UpdateAsync(menuParent, autoSave: true);
|
||||
_logger.LogInformation(
|
||||
"Menu parent '{MenuParentCode}' ShortName backfilled as '{ShortName}'.",
|
||||
input.MenuParentCode,
|
||||
menuParent.ShortName);
|
||||
}
|
||||
|
||||
private static bool HasWorkflow(WorkflowDto workflow, List<ListFormWorkflowCriteriaDto> criteria)
|
||||
{
|
||||
return workflow != null && (
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ public enum TableNameEnum
|
|||
InstallmentOption,
|
||||
Order,
|
||||
OrderItem,
|
||||
OrderItem_ByTenantId,
|
||||
BlogCategory,
|
||||
BlogPost,
|
||||
Demo,
|
||||
|
|
@ -94,5 +95,5 @@ public enum TableNameEnum
|
|||
VideoroomAttandance,
|
||||
VideoroomChat,
|
||||
Sequence,
|
||||
DbTableColumn
|
||||
DbTableColumn,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -758,6 +758,7 @@ public static class PlatformConsts
|
|||
public const string dxDateBox = "dxDateBox";
|
||||
public const string dxDateRangeBox = "dxDateRangeBox";
|
||||
public const string dxDropDownBox = "dxDropDownBox";
|
||||
public const string dxGridBox = "dxGridBox";
|
||||
public const string dxHtmlEditor = "dxHtmlEditor";
|
||||
public const string dxLookup = "dxHtmlEdidxLookuptor";
|
||||
public const string dxNumberBox = "dxNumberBox";
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ public static class TableNameResolver
|
|||
{ nameof(TableNameEnum.InstallmentOption), (TablePrefix.PlatformByName, MenuPrefix.Saas) },
|
||||
{ nameof(TableNameEnum.Order), (TablePrefix.PlatformByName, MenuPrefix.Saas) },
|
||||
{ nameof(TableNameEnum.OrderItem), (TablePrefix.PlatformByName, MenuPrefix.Saas) },
|
||||
{ nameof(TableNameEnum.OrderItem_ByTenantId), (TablePrefix.PlatformByName, MenuPrefix.Saas) },
|
||||
{ nameof(TableNameEnum.BlogCategory), (TablePrefix.PlatformByName, MenuPrefix.Saas) },
|
||||
{ nameof(TableNameEnum.BlogPost), (TablePrefix.PlatformByName, MenuPrefix.Saas) },
|
||||
{ nameof(TableNameEnum.Demo), (TablePrefix.PlatformByName, MenuPrefix.Saas) },
|
||||
|
|
|
|||
|
|
@ -84,14 +84,16 @@ public static class WizardConsts
|
|||
Margin = 10
|
||||
});
|
||||
|
||||
public static string DefaultLayoutJson(string DefaultLayout = "grid", bool Grid = true, bool Pivot = true, bool Chart = true, bool Tree = true, bool Gantt = true, bool Scheduler = true) => JsonSerializer.Serialize(new
|
||||
public static string DefaultLayoutJson(string DefaultLayout = "grid", bool Grid = true, bool Card = true, bool Pivot = true, bool Chart = true, bool Tree = true, bool Gantt = true, bool Scheduler = true, bool Todo = true) => JsonSerializer.Serialize(new
|
||||
{
|
||||
Grid = Grid,
|
||||
Card = Card,
|
||||
Pivot = Pivot,
|
||||
Chart = Chart,
|
||||
Tree = Tree,
|
||||
Gantt = Gantt,
|
||||
Scheduler = Scheduler,
|
||||
Todo = Todo,
|
||||
DefaultLayout = DefaultLayout,
|
||||
});
|
||||
|
||||
|
|
@ -196,6 +198,14 @@ public static class WizardConsts
|
|||
});
|
||||
}
|
||||
|
||||
public static string DefaultInsertFieldsJsonOnlyId(DbType dbType = DbType.Guid)
|
||||
{
|
||||
return JsonSerializer.Serialize(new[]
|
||||
{
|
||||
new { FieldName = "Id", FieldDbType = dbType, Value = "@NEWID", CustomValueType = FieldCustomValueTypeEnum.CustomKey }
|
||||
});
|
||||
}
|
||||
|
||||
public static string DefaultDeleteFieldsDefaultValueJson(DbType dbType = DbType.Guid)
|
||||
{
|
||||
return JsonSerializer.Serialize(new[]
|
||||
|
|
@ -205,11 +215,11 @@ public static class WizardConsts
|
|||
});
|
||||
}
|
||||
|
||||
public static string DefaultFieldsJsonOnlyId(DbType dbType = DbType.Guid)
|
||||
public static string DefaultDeleteFieldsJsonOnlyId(DbType dbType = DbType.Guid)
|
||||
{
|
||||
return JsonSerializer.Serialize(new[]
|
||||
{
|
||||
new { FieldName = "Id", FieldDbType = dbType, Value = "@NEWID", CustomValueType = FieldCustomValueTypeEnum.CustomKey }
|
||||
new { FieldName = "Id", FieldDbType = dbType, Value = "@ID", CustomValueType = FieldCustomValueTypeEnum.CustomKey }
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -416,6 +416,8 @@ public static class SeedConsts
|
|||
public const string RecurringJobs = Default + ".RecurringJobs";
|
||||
public const string Jobs = Default + ".Jobs";
|
||||
}
|
||||
public const string Licence = Prefix.App + ".Licence";
|
||||
public const string LicenceItem = Prefix.App + ".LicenceItem";
|
||||
|
||||
//Web Site
|
||||
public const string Home = Prefix.App + ".Home";
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ using Volo.Abp.MultiTenancy;
|
|||
|
||||
namespace Sozsoft.Platform.Entities
|
||||
{
|
||||
public class ReportCategory : FullAuditedEntity<string>, IMultiTenant
|
||||
public class ReportCategory : FullAuditedEntity<Guid>, IMultiTenant
|
||||
{
|
||||
public Guid? TenantId { get; set; }
|
||||
|
||||
|
|
@ -15,9 +15,12 @@ namespace Sozsoft.Platform.Entities
|
|||
|
||||
public ICollection<ReportTemplate> ReportTemplates { get; set; }
|
||||
|
||||
public ReportCategory(string id)
|
||||
protected ReportCategory()
|
||||
{
|
||||
}
|
||||
|
||||
public ReportCategory(Guid id) : base(id)
|
||||
{
|
||||
Id = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ namespace Sozsoft.Platform.Entities
|
|||
public string Description { get; set; }
|
||||
public string HtmlContent { get; set; }
|
||||
|
||||
public string CategoryId { get; set; }
|
||||
public Guid CategoryId { get; set; }
|
||||
public ReportCategory ReportCategory { get; set; }
|
||||
|
||||
public string Status { get; set; }
|
||||
|
|
@ -23,7 +23,7 @@ namespace Sozsoft.Platform.Entities
|
|||
string name,
|
||||
string description,
|
||||
string htmlContent,
|
||||
string categoryId,
|
||||
Guid categoryId,
|
||||
string status
|
||||
) : base(id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ public class ListForm : Entity<Guid>
|
|||
public string TreeOptionJson { get; set; } // Tree yapisi ile ilgili ayarlar
|
||||
public string GanttOptionJson { get; set; } // Gantt yapisi ile ilgili ayarlar
|
||||
public string SchedulerOptionJson { get; set; } // Scheduler yapisi ile ilgili ayarlar
|
||||
public string TodoOptionJson { get; set; } // Todo board alan esleme ayarlari
|
||||
public string FilterRowJson { get; set; } // Filtre ayarlari, Json olarak tutulur, donus sinifi FilterRowDto
|
||||
public string RowJson { get; set; } // Row ayarları, Json olarak tutulur, donus sinifi FilterRowDto
|
||||
public string HeaderFilterJson { get; set; } // Header filtreleme ayarlari, Json olarak tutulur
|
||||
|
|
|
|||
|
|
@ -53,6 +53,12 @@ public class ListFormField : Entity<Guid>
|
|||
|
||||
public string Alignment { get; set; } = "left"; // Sütunun Sağa, sola veya ortalama gösterimi
|
||||
public string Format { get; set; } // Cell bazında sütunun formatlanması
|
||||
|
||||
public int? EditOrderNo { get; set; }
|
||||
public int? EditGroupOrderNo { get; set; }
|
||||
public string EditorType2 { get; set; }
|
||||
public int? ColSpan { get; set; }
|
||||
public string EditorScript { get; set; } //Sütunun ekstra javascript ile yönetilmesi
|
||||
public string EditorOptions { get; set; } //Sütunun ekstra özellikleri yönetilmesi
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,58 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using Volo.Abp.Domain.Values;
|
||||
|
||||
namespace Sozsoft.Platform.Queries;
|
||||
|
||||
// public class EditingForm : ValueObject
|
||||
// {
|
||||
// public int Order { get; set; }
|
||||
// public string ItemType { get; set; }
|
||||
// public string Caption { get; set; }
|
||||
// public int ColCount { get; set; }
|
||||
// public int ColSpan { get; set; }
|
||||
// /// <summary> Type: Array<Simple Form Item | Group Form Item | Tabbed Form Item | Empty Form Item | Button Form Item>
|
||||
// /// Bu kisma suan sadece string olarak doldurulacak
|
||||
// /// items: ['FirstName', 'LastName',
|
||||
// /// { dataField: 'Notes', editorType: 'dxTextArea', colSpan: 2, editorOptions: { height: 100, }, }
|
||||
// /// ],
|
||||
// /// </summary>
|
||||
// //[TextArea]
|
||||
// //public string[] Items { get; set; }
|
||||
// public EditingFormItem[] Items { get; set; }
|
||||
|
||||
// protected override IEnumerable<object> GetAtomicValues()
|
||||
// {
|
||||
// yield return ItemType;
|
||||
// yield return Caption;
|
||||
// yield return ColCount;
|
||||
// yield return ColSpan;
|
||||
// yield return Items;
|
||||
// }
|
||||
// }
|
||||
|
||||
// public class EditingFormItem : ValueObject
|
||||
// {
|
||||
// [JsonPropertyName("order")]
|
||||
// public int Order { get; set; }
|
||||
// [JsonPropertyName("dataField")]
|
||||
// public string DataField { get; set; }
|
||||
// [JsonPropertyName("editorType2")]
|
||||
// public string EditorType2 { get; set; }
|
||||
// [JsonPropertyName("colSpan")]
|
||||
// public int ColSpan { get; set; }
|
||||
// [JsonPropertyName("editorOptions")]
|
||||
// public string EditorOptions { get; set; }
|
||||
// [JsonPropertyName("isRequired")]
|
||||
// public bool IsRequired { get; set; }
|
||||
|
||||
// protected override IEnumerable<object> GetAtomicValues()
|
||||
// {
|
||||
// yield return DataField;
|
||||
// yield return EditorType2;
|
||||
// yield return ColSpan;
|
||||
// yield return EditorOptions;
|
||||
// yield return IsRequired;
|
||||
// }
|
||||
// }
|
||||
|
||||
|
|
@ -52,7 +52,9 @@ public class QueryHelper
|
|||
case DbType.String:
|
||||
case DbType.AnsiString:
|
||||
var strValues = values.Select(a => a?.ToString()).ToArray();
|
||||
value = string.Join(PlatformConsts.MultiValueDelimiter, strValues);
|
||||
value = isArray
|
||||
? string.Join(PlatformConsts.MultiValueDelimiter, strValues)
|
||||
: strValues[0];
|
||||
break;
|
||||
case DbType.Date:
|
||||
case DbType.DateTime:
|
||||
|
|
|
|||
|
|
@ -170,7 +170,8 @@ public class QueryManager : PlatformDomainService, IQueryManager
|
|||
// oncelik Command alanindadir, dolu ise silme islemi buradaki sorguya yonlendirilir
|
||||
if (!string.IsNullOrEmpty(command))
|
||||
{
|
||||
sql = NormalizeCollectionParameterCommand(command, parameters, dataSourceType);
|
||||
// sql = NormalizeCollectionParameterCommand(command, parameters, dataSourceType);
|
||||
sql = command;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -188,12 +189,6 @@ public class QueryManager : PlatformDomainService, IQueryManager
|
|||
}
|
||||
else if (op == OperationEnum.Update)
|
||||
{
|
||||
var where = dataSourceType switch
|
||||
{
|
||||
DataSourceTypeEnum.Mssql => $"\"{listForm.KeyFieldName}\" IN @{listForm.KeyFieldName}",
|
||||
DataSourceTypeEnum.Postgresql => $"\"{listForm.KeyFieldName}\" = ANY(@{listForm.KeyFieldName})",
|
||||
_ => string.Empty,
|
||||
};
|
||||
var updateFields = parameters.Select(a => $"\"{a.Key}\" = @{a.Key}").ToList();
|
||||
var val = QueryHelper.GetFormattedValue(listForm.KeyFieldDbSourceType, keys);
|
||||
if (!parameters.ContainsKey(listForm.KeyFieldName))
|
||||
|
|
@ -202,6 +197,18 @@ public class QueryManager : PlatformDomainService, IQueryManager
|
|||
listForm.KeyFieldName,
|
||||
val.GetType().IsArray ? val : new object[] { val });
|
||||
}
|
||||
|
||||
var where = BuildWhereCondition(
|
||||
listForm.KeyFieldName,
|
||||
parameters[listForm.KeyFieldName],
|
||||
dataSourceType);
|
||||
|
||||
if (parameters.TryGetValue("TenantId", out var tenantId)
|
||||
&& !string.Equals(listForm.KeyFieldName, "TenantId", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
where += $" AND {BuildWhereCondition("TenantId", tenantId, dataSourceType)}";
|
||||
}
|
||||
|
||||
sql = $"UPDATE \"{listForm.SelectCommand}\" SET {string.Join(',', updateFields)} WHERE {where}";
|
||||
}
|
||||
else if (op == OperationEnum.Delete)
|
||||
|
|
@ -212,12 +219,7 @@ public class QueryManager : PlatformDomainService, IQueryManager
|
|||
{
|
||||
where = string.Join(
|
||||
" AND ",
|
||||
parameters.Select(a => dataSourceType switch
|
||||
{
|
||||
DataSourceTypeEnum.Mssql => $"\"{a.Key}\" IN @{a.Key}",
|
||||
DataSourceTypeEnum.Postgresql => $"\"{a.Key}\" = ANY(@{a.Key})",
|
||||
_ => "1 = 0",
|
||||
}).ToList());
|
||||
parameters.Select(a => BuildWhereCondition(a.Key, a.Value, dataSourceType)).ToList());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -240,77 +242,101 @@ public class QueryManager : PlatformDomainService, IQueryManager
|
|||
return sql;
|
||||
}
|
||||
|
||||
private static string NormalizeCollectionParameterCommand(
|
||||
string command,
|
||||
Dictionary<string, object> parameters,
|
||||
DataSourceTypeEnum dataSourceType)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(command) || parameters == null || parameters.Count == 0)
|
||||
{
|
||||
return command;
|
||||
}
|
||||
|
||||
var sql = command;
|
||||
foreach (var parameter in parameters)
|
||||
{
|
||||
if (!IsCollectionParameter(parameter.Value))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var escapedParameterName = Regex.Escape(parameter.Key);
|
||||
sql = dataSourceType switch
|
||||
{
|
||||
DataSourceTypeEnum.Mssql => NormalizeMssqlCollectionParameter(sql, escapedParameterName, parameter.Key),
|
||||
DataSourceTypeEnum.Postgresql => NormalizePostgresqlCollectionParameter(sql, escapedParameterName, parameter.Key),
|
||||
_ => sql
|
||||
};
|
||||
}
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
private static bool IsCollectionParameter(object value)
|
||||
private static bool IsCollectionValue(object value)
|
||||
{
|
||||
return value is System.Collections.IEnumerable
|
||||
&& value is not string
|
||||
&& value is not byte[];
|
||||
}
|
||||
|
||||
private static string NormalizeMssqlCollectionParameter(
|
||||
string sql,
|
||||
string escapedParameterName,
|
||||
string parameterName)
|
||||
private static string BuildWhereCondition(
|
||||
string fieldName,
|
||||
object value,
|
||||
DataSourceTypeEnum dataSourceType)
|
||||
{
|
||||
sql = Regex.Replace(
|
||||
sql,
|
||||
$@"IN\s*\(\s*@{escapedParameterName}\s*\)",
|
||||
$"IN @{parameterName}",
|
||||
RegexOptions.IgnoreCase);
|
||||
|
||||
return Regex.Replace(
|
||||
sql,
|
||||
$@"(?<column>(""[^""]+""|\[[^\]]+\]|`[^`]+`|\w+))\s*=\s*@{escapedParameterName}\b",
|
||||
match => $"{match.Groups["column"].Value} IN @{parameterName}",
|
||||
RegexOptions.IgnoreCase);
|
||||
return dataSourceType switch
|
||||
{
|
||||
DataSourceTypeEnum.Mssql when value is null or DBNull => $"\"{fieldName}\" IS NULL",
|
||||
DataSourceTypeEnum.Postgresql when value is null or DBNull => $"\"{fieldName}\" IS NULL",
|
||||
DataSourceTypeEnum.Mssql when IsCollectionValue(value) => $"\"{fieldName}\" IN @{fieldName}",
|
||||
DataSourceTypeEnum.Postgresql when IsCollectionValue(value) => $"\"{fieldName}\" = ANY(@{fieldName})",
|
||||
DataSourceTypeEnum.Mssql => $"\"{fieldName}\" = @{fieldName}",
|
||||
DataSourceTypeEnum.Postgresql => $"\"{fieldName}\" = @{fieldName}",
|
||||
_ => "1 = 0",
|
||||
};
|
||||
}
|
||||
|
||||
private static string NormalizePostgresqlCollectionParameter(
|
||||
string sql,
|
||||
string escapedParameterName,
|
||||
string parameterName)
|
||||
{
|
||||
sql = Regex.Replace(
|
||||
sql,
|
||||
$@"IN\s*\(\s*@{escapedParameterName}\s*\)",
|
||||
$"= ANY(@{parameterName})",
|
||||
RegexOptions.IgnoreCase);
|
||||
// private static string NormalizeCollectionParameterCommand(
|
||||
// string command,
|
||||
// Dictionary<string, object> parameters,
|
||||
// DataSourceTypeEnum dataSourceType)
|
||||
// {
|
||||
// if (string.IsNullOrWhiteSpace(command) || parameters == null || parameters.Count == 0)
|
||||
// {
|
||||
// return command;
|
||||
// }
|
||||
|
||||
return Regex.Replace(
|
||||
sql,
|
||||
$@"(?<column>(""[^""]+""|\[[^\]]+\]|`[^`]+`|\w+))\s*=\s*@{escapedParameterName}\b",
|
||||
match => $"{match.Groups["column"].Value} = ANY(@{parameterName})",
|
||||
RegexOptions.IgnoreCase);
|
||||
}
|
||||
// var sql = command;
|
||||
// foreach (var parameter in parameters)
|
||||
// {
|
||||
// if (!IsCollectionParameter(parameter.Value))
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// var escapedParameterName = Regex.Escape(parameter.Key);
|
||||
// sql = dataSourceType switch
|
||||
// {
|
||||
// DataSourceTypeEnum.Mssql => NormalizeMssqlCollectionParameter(sql, escapedParameterName, parameter.Key),
|
||||
// DataSourceTypeEnum.Postgresql => NormalizePostgresqlCollectionParameter(sql, escapedParameterName, parameter.Key),
|
||||
// _ => sql
|
||||
// };
|
||||
// }
|
||||
|
||||
// return sql;
|
||||
// }
|
||||
|
||||
// private static bool IsCollectionParameter(object value)
|
||||
// {
|
||||
// return value is System.Collections.IEnumerable
|
||||
// && value is not string
|
||||
// && value is not byte[];
|
||||
// }
|
||||
|
||||
// private static string NormalizeMssqlCollectionParameter(
|
||||
// string sql,
|
||||
// string escapedParameterName,
|
||||
// string parameterName)
|
||||
// {
|
||||
// sql = Regex.Replace(
|
||||
// sql,
|
||||
// $@"IN\s*\(\s*@{escapedParameterName}\s*\)",
|
||||
// $"IN @{parameterName}",
|
||||
// RegexOptions.IgnoreCase);
|
||||
|
||||
// return Regex.Replace(
|
||||
// sql,
|
||||
// $@"(?<column>(""[^""]+""|\[[^\]]+\]|`[^`]+`|\w+))\s*=\s*@{escapedParameterName}\b",
|
||||
// match => $"{match.Groups["column"].Value} IN @{parameterName}",
|
||||
// RegexOptions.IgnoreCase);
|
||||
// }
|
||||
|
||||
// private static string NormalizePostgresqlCollectionParameter(
|
||||
// string sql,
|
||||
// string escapedParameterName,
|
||||
// string parameterName)
|
||||
// {
|
||||
// sql = Regex.Replace(
|
||||
// sql,
|
||||
// $@"IN\s*\(\s*@{escapedParameterName}\s*\)",
|
||||
// $"= ANY(@{parameterName})",
|
||||
// RegexOptions.IgnoreCase);
|
||||
|
||||
// return Regex.Replace(
|
||||
// sql,
|
||||
// $@"(?<column>(""[^""]+""|\[[^\]]+\]|`[^`]+`|\w+))\s*=\s*@{escapedParameterName}\b",
|
||||
// match => $"{match.Groups["column"].Value} = ANY(@{parameterName})",
|
||||
// RegexOptions.IgnoreCase);
|
||||
// }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -469,7 +469,7 @@ public class SelectQueryManager : PlatformDomainService, ISelectQueryManager
|
|||
if (listform.WorkflowJson.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
var workflow = JsonSerializer.Deserialize<Workflow>(listform.WorkflowJson);
|
||||
if (workflow != null && workflow.IsFilterUserName)
|
||||
if (workflow != null && workflow.ApprovalIsFilterUserName)
|
||||
{
|
||||
if (whereParts.Any())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,18 +6,18 @@ namespace Sozsoft.Platform.Queries;
|
|||
public class Workflow : ValueObject
|
||||
{
|
||||
public string ApprovalUserFieldName { get; set; }
|
||||
public bool IsFilterUserName { get; set; }
|
||||
public string ApprovalDateFieldName { get; set; }
|
||||
public string ApprovalStatusFieldName { get; set; }
|
||||
public string ApprovalDescriptionFieldName { get; set; }
|
||||
public bool ApprovalIsFilterUserName { get; set; }
|
||||
|
||||
protected override IEnumerable<object> GetAtomicValues()
|
||||
{
|
||||
yield return ApprovalUserFieldName;
|
||||
yield return IsFilterUserName;
|
||||
yield return ApprovalDateFieldName;
|
||||
yield return ApprovalStatusFieldName;
|
||||
yield return ApprovalDescriptionFieldName;
|
||||
yield return ApprovalIsFilterUserName;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -378,6 +378,7 @@ public class PlatformDbContext :
|
|||
b.Property(a => a.WorkflowJson).HasColumnType("text");
|
||||
b.Property(a => a.ExtraFilterJson).HasColumnType("text");
|
||||
b.Property(a => a.LayoutJson).HasColumnType("text");
|
||||
b.Property(a => a.TodoOptionJson).HasColumnType("text");
|
||||
b.Property(a => a.CommonJson).HasColumnType("text");
|
||||
b.Property(a => a.DataSourceJson).HasColumnType("text");
|
||||
b.Property(a => a.AdaptiveLayoutJson).HasColumnType("text");
|
||||
|
|
@ -454,6 +455,8 @@ public class PlatformDbContext :
|
|||
b.Property(a => a.Alignment).HasMaxLength(20).HasDefaultValue("left");
|
||||
b.Property(a => a.Format).HasMaxLength(128);
|
||||
b.Property(a => a.EditorOptions).HasColumnType("text");
|
||||
b.Property(a => a.EditorType2).HasMaxLength(64);
|
||||
b.Property(a => a.EditorScript).HasColumnType("text");
|
||||
|
||||
b.HasIndex(x => new { x.ListFormCode, x.UserId, x.RoleId, x.CultureName, x.FieldName }).IsUnique().HasFilter(null);
|
||||
});
|
||||
|
|
@ -660,7 +663,6 @@ public class PlatformDbContext :
|
|||
b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.ReportCategory)), Prefix.DbSchema);
|
||||
b.ConfigureByConvention();
|
||||
|
||||
b.Property(x => x.Id).HasMaxLength(256);
|
||||
b.Property(x => x.Name).IsRequired().HasMaxLength(256);
|
||||
b.Property(x => x.Description).HasMaxLength(4096); // JSON string
|
||||
b.Property(x => x.Icon).HasMaxLength(64);
|
||||
|
|
@ -674,7 +676,6 @@ public class PlatformDbContext :
|
|||
b.ConfigureByConvention();
|
||||
|
||||
b.Property(x => x.Name).IsRequired().HasMaxLength(256);
|
||||
b.Property(x => x.CategoryId).HasMaxLength(256);
|
||||
b.Property(x => x.Description).HasMaxLength(1024);
|
||||
b.Property(x => x.HtmlContent).IsRequired();
|
||||
b.Property(x => x.Status).HasMaxLength(20);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore;
|
|||
namespace Sozsoft.Platform.Migrations
|
||||
{
|
||||
[DbContext(typeof(PlatformDbContext))]
|
||||
[Migration("20260713103339_Initial")]
|
||||
[Migration("20260717065637_Initial")]
|
||||
partial class Initial
|
||||
{
|
||||
/// <inheritdoc />
|
||||
|
|
@ -3264,6 +3264,9 @@ namespace Sozsoft.Platform.Migrations
|
|||
b.Property<string>("TitleJson")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("TodoOptionJson")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("TooltipJson")
|
||||
.HasColumnType("text");
|
||||
|
||||
|
|
@ -3412,6 +3415,9 @@ namespace Sozsoft.Platform.Migrations
|
|||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<int?>("ColSpan")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("ColumnCssClass")
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("nvarchar(128)");
|
||||
|
|
@ -3437,9 +3443,22 @@ namespace Sozsoft.Platform.Migrations
|
|||
.HasMaxLength(10)
|
||||
.HasColumnType("nvarchar(10)");
|
||||
|
||||
b.Property<int?>("EditGroupOrderNo")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("EditOrderNo")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("EditorOptions")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("EditorScript")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("EditorType2")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("nvarchar(64)");
|
||||
|
||||
b.Property<string>("FieldName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
|
|
@ -4482,9 +4501,8 @@ namespace Sozsoft.Platform.Migrations
|
|||
|
||||
modelBuilder.Entity("Sozsoft.Platform.Entities.ReportCategory", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("datetime2")
|
||||
|
|
@ -4547,9 +4565,8 @@ namespace Sozsoft.Platform.Migrations
|
|||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("CategoryId")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
b.Property<Guid>("CategoryId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("datetime2")
|
||||
|
|
@ -8820,7 +8837,8 @@ namespace Sozsoft.Platform.Migrations
|
|||
b.HasOne("Sozsoft.Platform.Entities.ReportCategory", "ReportCategory")
|
||||
.WithMany("ReportTemplates")
|
||||
.HasForeignKey("CategoryId")
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("ReportCategory");
|
||||
});
|
||||
|
|
@ -650,7 +650,7 @@ namespace Sozsoft.Platform.Migrations
|
|||
name: "Adm_T_ReportCategory",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false),
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
Name = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false),
|
||||
Description = table.Column<string>(type: "nvarchar(max)", maxLength: 4096, nullable: true),
|
||||
|
|
@ -1392,6 +1392,7 @@ namespace Sozsoft.Platform.Migrations
|
|||
TreeOptionJson = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
GanttOptionJson = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
SchedulerOptionJson = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
TodoOptionJson = table.Column<string>(type: "text", nullable: true),
|
||||
FilterRowJson = table.Column<string>(type: "text", nullable: true),
|
||||
RowJson = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
HeaderFilterJson = table.Column<string>(type: "text", nullable: true),
|
||||
|
|
@ -2259,7 +2260,7 @@ namespace Sozsoft.Platform.Migrations
|
|||
Name = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false),
|
||||
Description = table.Column<string>(type: "nvarchar(1024)", maxLength: 1024, nullable: true),
|
||||
HtmlContent = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
||||
CategoryId = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
|
||||
CategoryId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
Status = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: true),
|
||||
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
|
|
@ -2790,6 +2791,11 @@ namespace Sozsoft.Platform.Migrations
|
|||
PivotSettingsJson = table.Column<string>(type: "text", nullable: true),
|
||||
Alignment = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: true, defaultValue: "left"),
|
||||
Format = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: true),
|
||||
EditOrderNo = table.Column<int>(type: "int", nullable: true),
|
||||
EditGroupOrderNo = table.Column<int>(type: "int", nullable: true),
|
||||
EditorType2 = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: true),
|
||||
ColSpan = table.Column<int>(type: "int", nullable: true),
|
||||
EditorScript = table.Column<string>(type: "text", nullable: true),
|
||||
EditorOptions = table.Column<string>(type: "text", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
|
|
@ -3261,6 +3261,9 @@ namespace Sozsoft.Platform.Migrations
|
|||
b.Property<string>("TitleJson")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("TodoOptionJson")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("TooltipJson")
|
||||
.HasColumnType("text");
|
||||
|
||||
|
|
@ -3409,6 +3412,9 @@ namespace Sozsoft.Platform.Migrations
|
|||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<int?>("ColSpan")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("ColumnCssClass")
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("nvarchar(128)");
|
||||
|
|
@ -3434,9 +3440,22 @@ namespace Sozsoft.Platform.Migrations
|
|||
.HasMaxLength(10)
|
||||
.HasColumnType("nvarchar(10)");
|
||||
|
||||
b.Property<int?>("EditGroupOrderNo")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("EditOrderNo")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("EditorOptions")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("EditorScript")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("EditorType2")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("nvarchar(64)");
|
||||
|
||||
b.Property<string>("FieldName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
|
|
@ -4479,9 +4498,8 @@ namespace Sozsoft.Platform.Migrations
|
|||
|
||||
modelBuilder.Entity("Sozsoft.Platform.Entities.ReportCategory", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("datetime2")
|
||||
|
|
@ -4544,9 +4562,8 @@ namespace Sozsoft.Platform.Migrations
|
|||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("CategoryId")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
b.Property<Guid>("CategoryId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("datetime2")
|
||||
|
|
@ -8817,7 +8834,8 @@ namespace Sozsoft.Platform.Migrations
|
|||
b.HasOne("Sozsoft.Platform.Entities.ReportCategory", "ReportCategory")
|
||||
.WithMany("ReportTemplates")
|
||||
.HasForeignKey("CategoryId")
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("ReportCategory");
|
||||
});
|
||||
|
|
|
|||
|
|
@ -491,7 +491,7 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
private readonly IRepository<GlobalSearch, int> _globalSearch;
|
||||
private readonly IRepository<CustomEndpoint, Guid> _customEndpointRepository;
|
||||
private readonly IRepository<CustomComponent, Guid> _customComponentRepository;
|
||||
private readonly IRepository<ReportCategory, string> _reportCategoriesRepository;
|
||||
private readonly IRepository<ReportCategory, Guid> _reportCategoriesRepository;
|
||||
private readonly IRepository<ReportTemplate, Guid> _reportTemplatesRepository;
|
||||
private readonly IRepository<Home, Guid> _homeRepository;
|
||||
private readonly IRepository<About, Guid> _aboutRepository;
|
||||
|
|
@ -548,7 +548,7 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
IRepository<SkillLevel, string> skillLevelRepository,
|
||||
IRepository<CustomEndpoint, Guid> customEndpointRepository,
|
||||
IRepository<CustomComponent, Guid> customComponentRepository,
|
||||
IRepository<ReportCategory, string> reportCategoriesRepository,
|
||||
IRepository<ReportCategory, Guid> reportCategoriesRepository,
|
||||
IRepository<ReportTemplate, Guid> reportTemplatesRepository,
|
||||
IRepository<Home, Guid> homeRepository,
|
||||
IRepository<About, Guid> aboutRepository,
|
||||
|
|
@ -867,7 +867,7 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
|
||||
if (!exists)
|
||||
{
|
||||
await _reportCategoriesRepository.InsertAsync(new ReportCategory(item.Name)
|
||||
await _reportCategoriesRepository.InsertAsync(new ReportCategory(Guid.NewGuid())
|
||||
{
|
||||
Name = item.Name,
|
||||
Description = item.Description,
|
||||
|
|
|
|||
|
|
@ -542,14 +542,16 @@ public class DynamicFormReport : XtraReport
|
|||
.Where(x => x.IsActive != false)
|
||||
.ToDictionary(x => x.FieldName, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
var formItems = GetEditingFormItems(listForm)
|
||||
.Where(x => !string.IsNullOrWhiteSpace(x.DataField))
|
||||
var editFields = fields
|
||||
.Where(x => x.EditOrderNo.HasValue)
|
||||
.OrderBy(x => x.EditGroupOrderNo ?? 1)
|
||||
.ThenBy(x => x.EditOrderNo)
|
||||
.ToList();
|
||||
|
||||
var orderedFields = formItems.Count > 0
|
||||
? formItems
|
||||
.Where(x => fieldsByName.ContainsKey(x.DataField))
|
||||
.Select(x => new FieldWithEditor(fieldsByName[x.DataField], x.EditorType2, x.ColSpan))
|
||||
var orderedFields = editFields.Count > 0
|
||||
? editFields
|
||||
.Where(x => fieldsByName.ContainsKey(x.FieldName))
|
||||
.Select(x => new FieldWithEditor(x, x.EditorType2, x.ColSpan ?? 1))
|
||||
.ToList()
|
||||
: fields
|
||||
.Where(x => !string.IsNullOrWhiteSpace(x.FieldName) && x.FieldName != "undefined")
|
||||
|
|
@ -582,10 +584,9 @@ public class DynamicFormReport : XtraReport
|
|||
var usedFields = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var group in groups)
|
||||
{
|
||||
var groupFields = (group.Items ?? [])
|
||||
.OrderBy(x => x.Order)
|
||||
.Where(x => !string.IsNullOrWhiteSpace(x.DataField) && fieldsByName.ContainsKey(x.DataField))
|
||||
.Select(x => fieldsByName[x.DataField])
|
||||
var groupFields = fields
|
||||
.Where(x => (x.Field.EditGroupOrderNo ?? 1) == group.Order)
|
||||
.OrderBy(x => x.Field.EditOrderNo ?? int.MaxValue)
|
||||
.ToList();
|
||||
|
||||
foreach (var field in groupFields)
|
||||
|
|
@ -625,13 +626,6 @@ public class DynamicFormReport : XtraReport
|
|||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<EditingFormItemDto> GetEditingFormItems(ListForm listForm)
|
||||
{
|
||||
return GetEditingFormGroups(listForm)
|
||||
.OrderBy(x => x.Order)
|
||||
.SelectMany(x => (x.Items ?? []).OrderBy(i => i.Order));
|
||||
}
|
||||
|
||||
private static IEnumerable<(SubFormDto Form, string Filter)> GetListSubForms(
|
||||
ListForm listForm,
|
||||
IDictionary<string, object> row)
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ public class DynamicGridReport : XtraReport
|
|||
|
||||
await selectQueryManager.PrepareQueriesAsync(listForm, fields, dataSourceType, customizations, queryParams);
|
||||
var selectFieldsByName = DynamicReportImageHelper.CreateSelectFieldMap(selectQueryManager.SelectFields);
|
||||
var editorTypesByField = DynamicReportImageHelper.CreateEditorTypeMap(listForm);
|
||||
var editorTypesByField = DynamicReportImageHelper.CreateEditorTypeMap(fields);
|
||||
|
||||
var availableFields = fields
|
||||
.Where(x => !string.IsNullOrWhiteSpace(x.FieldName) && x.FieldName != "undefined")
|
||||
|
|
|
|||
|
|
@ -73,28 +73,16 @@ internal static class DynamicReportImageHelper
|
|||
return map;
|
||||
}
|
||||
|
||||
public static Dictionary<string, string> CreateEditorTypeMap(ListForm listForm)
|
||||
public static Dictionary<string, string> CreateEditorTypeMap(IEnumerable<ListFormField> fields)
|
||||
{
|
||||
var map = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
if (string.IsNullOrWhiteSpace(listForm?.EditingFormJson))
|
||||
foreach (var field in fields ?? [])
|
||||
{
|
||||
return map;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var groups = JsonSerializer.Deserialize<List<EditingFormDto>>(listForm.EditingFormJson) ?? [];
|
||||
foreach (var item in groups.SelectMany(x => x.Items ?? []))
|
||||
if (!string.IsNullOrWhiteSpace(field.FieldName) && !string.IsNullOrWhiteSpace(field.EditorType2))
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(item.DataField))
|
||||
{
|
||||
map[item.DataField] = item.EditorType2;
|
||||
}
|
||||
map[field.FieldName] = field.EditorType2;
|
||||
}
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
|
@ -452,25 +440,16 @@ internal static class DynamicReportImageHelper
|
|||
return editorType is PlatformConsts.EditorTypes.dxImageUpload or PlatformConsts.EditorTypes.dxImageViewer;
|
||||
}
|
||||
|
||||
public static bool HasImageEditor(ListForm listForm, string fieldName)
|
||||
public static bool HasImageEditor(IEnumerable<ListFormField> fields, string fieldName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(listForm?.EditingFormJson) || string.IsNullOrWhiteSpace(fieldName))
|
||||
if (string.IsNullOrWhiteSpace(fieldName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var groups = JsonSerializer.Deserialize<List<EditingFormDto>>(listForm.EditingFormJson) ?? [];
|
||||
return groups
|
||||
.SelectMany(x => x.Items ?? [])
|
||||
.Any(x => string.Equals(x.DataField, fieldName, StringComparison.OrdinalIgnoreCase) &&
|
||||
IsImageEditor(x.EditorType2));
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return (fields ?? []).Any(x =>
|
||||
string.Equals(x.FieldName, fieldName, StringComparison.OrdinalIgnoreCase) &&
|
||||
IsImageEditor(x.EditorType2));
|
||||
}
|
||||
|
||||
public static float GetGridImageHeight() => DefaultGridImageHeight;
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ public class DynamicTreeReport : XtraReport
|
|||
|
||||
await selectQueryManager.PrepareQueriesAsync(listForm, fields, dataSourceType, customizations, queryParams);
|
||||
var selectFieldsByName = DynamicReportImageHelper.CreateSelectFieldMap(selectQueryManager.SelectFields);
|
||||
var editorTypesByField = DynamicReportImageHelper.CreateEditorTypeMap(listForm);
|
||||
var editorTypesByField = DynamicReportImageHelper.CreateEditorTypeMap(fields);
|
||||
|
||||
var availableFields = fields
|
||||
.Where(x => !string.IsNullOrWhiteSpace(x.FieldName) && x.FieldName != "undefined")
|
||||
|
|
|
|||
|
|
@ -1,6 +1,29 @@
|
|||
{
|
||||
"commit": "e7be51a",
|
||||
"commit": "8146adf",
|
||||
"releases": [
|
||||
{
|
||||
"version": "1.1.08",
|
||||
"buildDate": "2026-07-16",
|
||||
"commit": "24e92fcb82eef0ee26ca5d65e08c5404f132a09e",
|
||||
"changeLog": [
|
||||
"- CardView komponenti geliştirildi.",
|
||||
"- Todo / Kanban komponenti geliştirildi.",
|
||||
"- Licence information",
|
||||
"- Check New Versiyon komponenti."
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.1.07",
|
||||
"buildDate": "2026-07-13",
|
||||
"commit": "50cb3eaf979eb5027172a92a4e941ed64aa3671e",
|
||||
"changeLog": [
|
||||
"- localStorage tüm bilgiler easy-peasy içerisinde birleştirildi.",
|
||||
"- Codex 5.6 sol optimizasyon yapıldı. Bir çok komponent Lazy load ile yüklendi.",
|
||||
"- Workflow komponentinden birden fazla kişi onay verebilir.",
|
||||
"- Posta Kodu eklendi.",
|
||||
"- Sales Order kısmında Yeni ve Eski müşteri sipariş ayrımı yapıldı"
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.1.06",
|
||||
"buildDate": "2026-07-06",
|
||||
|
|
|
|||
|
|
@ -193,12 +193,8 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
|
|||
const [foundTenantName, setFoundTenantName] = useState('')
|
||||
const navigate = useNavigate()
|
||||
const { translate } = useLocalization()
|
||||
const { tenantData, tenantFormDraft } = useStoreState(
|
||||
(state) => state.client.order,
|
||||
)
|
||||
const { setTenantFormDraft, clearTenant } = useStoreActions(
|
||||
(actions) => actions.client.order,
|
||||
)
|
||||
const { tenantData, tenantFormDraft } = useStoreState((state) => state.client.order)
|
||||
const { setTenantFormDraft, clearTenant } = useStoreActions((actions) => actions.client.order)
|
||||
const hasRestoredTenantData = useRef(false)
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -681,7 +677,9 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
|
|||
|
||||
<div className="flex items-center gap-2">
|
||||
<FaPhone className="w-4 h-4 text-gray-500" />
|
||||
<span className="font-medium">{translate('::Abp.Identity.User.UserInformation.PhoneNumber')}:</span>
|
||||
<span className="font-medium">
|
||||
{translate('::Abp.Identity.User.UserInformation.PhoneNumber')}:
|
||||
</span>
|
||||
<span>{formData.phoneNumber}</span>
|
||||
</div>
|
||||
|
||||
|
|
@ -999,41 +997,6 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
{translate('::Public.contact.taxOffice')}
|
||||
</label>
|
||||
<div className="relative">
|
||||
<FaBuilding className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
||||
<input
|
||||
type="text"
|
||||
required
|
||||
placeholder="Sarıgazi"
|
||||
value={formData.taxOffice}
|
||||
onChange={(e) => handleInputChange('taxOffice', e.target.value)}
|
||||
className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg bg-white text-gray-900 placeholder-gray-500 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100 dark:placeholder-gray-400 focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
{translate('::Public.contact.taxNumber')}
|
||||
</label>
|
||||
<div className="relative">
|
||||
<FaDollarSign className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
||||
<input
|
||||
type="text"
|
||||
required
|
||||
placeholder="1234567890"
|
||||
value={formData.vknTckn}
|
||||
onChange={(e) => handleInputChange('vknTckn', e.target.value)}
|
||||
className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg bg-white text-gray-900 placeholder-gray-500 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100 dark:placeholder-gray-400 focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
|
|
@ -1094,6 +1057,41 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
{translate('::Public.contact.taxOffice')}
|
||||
</label>
|
||||
<div className="relative">
|
||||
<FaBuilding className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
||||
<input
|
||||
type="text"
|
||||
required
|
||||
placeholder="Sarıgazi"
|
||||
value={formData.taxOffice}
|
||||
onChange={(e) => handleInputChange('taxOffice', e.target.value)}
|
||||
className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg bg-white text-gray-900 placeholder-gray-500 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100 dark:placeholder-gray-400 focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
{translate('::Public.contact.taxNumber')}
|
||||
</label>
|
||||
<div className="relative">
|
||||
<FaDollarSign className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
||||
<input
|
||||
type="text"
|
||||
required
|
||||
placeholder="1234567890"
|
||||
value={formData.vknTckn}
|
||||
onChange={(e) => handleInputChange('vknTckn', e.target.value)}
|
||||
className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg bg-white text-gray-900 placeholder-gray-500 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100 dark:placeholder-gray-400 focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import Drawer from '@/components/ui/Drawer'
|
|||
import SidePanelContent, { SidePanelContentProps } from './SidePanelContent'
|
||||
import CopyButton from '../ThemeConfigurator/CopyButton'
|
||||
import withHeaderItem from '@/utils/hoc/withHeaderItem'
|
||||
import { useStoreState, useStoreActions } from '@/store'
|
||||
import { useStoreActions, useStoreState } from '@/store'
|
||||
import type { CommonProps } from '@/proxy/common'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import { FcEngineering } from 'react-icons/fc'
|
||||
|
|
|
|||
|
|
@ -16,8 +16,7 @@ import {
|
|||
import { useStoreState } from '@/store'
|
||||
import useMenuActive from '@/utils/hooks/useMenuActive'
|
||||
import isEmpty from 'lodash/isEmpty'
|
||||
import React from 'react'
|
||||
import { useEffect } from 'react'
|
||||
import React, { useEffect } from 'react'
|
||||
import { FaQuestionCircle } from 'react-icons/fa'
|
||||
import { Link, useLocation } from 'react-router-dom'
|
||||
|
||||
|
|
|
|||
|
|
@ -6,22 +6,31 @@ import withHeaderItem from '@/utils/hoc/withHeaderItem'
|
|||
import useAuth from '@/utils/hooks/useAuth'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import classNames from 'classnames'
|
||||
import type { ReactElement } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { Avatar } from '../ui'
|
||||
import { FcEngineering, FcNext, FcNfcSign, FcVoicePresentation } from 'react-icons/fc'
|
||||
import {
|
||||
FcEngineering,
|
||||
FcNext,
|
||||
FcNfcSign,
|
||||
FcSynchronize,
|
||||
FcVoicePresentation,
|
||||
} from 'react-icons/fc'
|
||||
import { useManualUpdateCheck } from '@/views/version/ChangeLog'
|
||||
|
||||
type DropdownList = {
|
||||
label: string
|
||||
path: string
|
||||
icon: JSX.Element
|
||||
icon: ReactElement
|
||||
}
|
||||
|
||||
const _UserDropdown = ({ className }: CommonProps) => {
|
||||
const UserDropdownBase = ({ className }: CommonProps) => {
|
||||
const { setPanelExpand } = useStoreActions((actions) => actions.theme)
|
||||
const { userName, name, email, avatar } = useStoreState((state) => state.auth.user)
|
||||
const tenant = useStoreState((state) => state.abpConfig.config?.currentTenant)
|
||||
const { translate } = useLocalization()
|
||||
const { signOut } = useAuth()
|
||||
const { isCheckingUpdate, checkForUpdate } = useManualUpdateCheck()
|
||||
const displayName = name || userName
|
||||
const tenantName = tenant?.name
|
||||
|
||||
|
|
@ -113,6 +122,23 @@ const _UserDropdown = ({ className }: CommonProps) => {
|
|||
)
|
||||
})}
|
||||
|
||||
<Dropdown.Item
|
||||
eventKey="Check New Version"
|
||||
className="mb-1 px-0"
|
||||
onClick={checkForUpdate}
|
||||
>
|
||||
<span className="flex h-full w-full items-center gap-2 px-2">
|
||||
<span className={classNames('text-xl opacity-50', isCheckingUpdate && 'animate-spin')}>
|
||||
<FcSynchronize />
|
||||
</span>
|
||||
<span>
|
||||
{isCheckingUpdate
|
||||
? translate('::App.CheckUpdate')
|
||||
: translate('::App.CheckForUpdates')}
|
||||
</span>
|
||||
</span>
|
||||
</Dropdown.Item>
|
||||
|
||||
{/* <Dropdown.Item variant="divider" /> */}
|
||||
<Dropdown.Item eventKey="Sign Out" className="mb-1 px-2" onClick={signOut}>
|
||||
<span className="text-xl opacity-50">
|
||||
|
|
@ -124,6 +150,6 @@ const _UserDropdown = ({ className }: CommonProps) => {
|
|||
)
|
||||
}
|
||||
|
||||
const UserDropdown = withHeaderItem(_UserDropdown)
|
||||
const UserDropdown = withHeaderItem(UserDropdownBase)
|
||||
|
||||
export default UserDropdown
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import {
|
||||
import React, {
|
||||
Children,
|
||||
cloneElement,
|
||||
forwardRef,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { createContext } from 'react'
|
||||
import React, { createContext } from 'react'
|
||||
|
||||
export type CheckboxValue = string | number
|
||||
export type CheckboxGroupValue = CheckboxValue[]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import {
|
||||
import React, {
|
||||
forwardRef,
|
||||
useState,
|
||||
useRef,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import type { CommonProps } from '../../@types/common'
|
|||
import type { MonthBaseProps } from './components/Month'
|
||||
import type { DayKeydownPayload } from './components/types'
|
||||
import type { RefObject } from 'react'
|
||||
import React from 'react'
|
||||
|
||||
export interface DateTableProps extends CommonProps, MonthBaseProps {
|
||||
dateViewCount: number
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import {
|
||||
import React, {
|
||||
forwardRef,
|
||||
useState,
|
||||
useRef,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import {
|
||||
import React, {
|
||||
forwardRef,
|
||||
useRef,
|
||||
useState,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useState, useEffect, useCallback, useMemo } from 'react'
|
||||
import React, { useState, useEffect, useCallback, useMemo } from 'react'
|
||||
import classNames from 'classnames'
|
||||
import { FaChevronCircleLeft, FaEllipsisH, FaChevronCircleRight } from 'react-icons/fa';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import {
|
||||
import React, {
|
||||
forwardRef,
|
||||
useState,
|
||||
useCallback,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { FaCheckCircle, FaInfoCircle, FaExclamation, FaTimesCircle } from 'react-icons/fa';
|
||||
import type { TypeAttributes, CommonProps } from '../@types/common'
|
||||
import type { ReactNode } from 'react'
|
||||
import type { ReactElement, ReactNode } from 'react'
|
||||
|
||||
export interface StatusIconProps extends CommonProps {
|
||||
type: TypeAttributes.Status
|
||||
custom?: ReactNode | JSX.Element
|
||||
custom?: ReactNode | ReactElement
|
||||
iconColor?: string
|
||||
}
|
||||
|
||||
|
|
@ -12,7 +12,7 @@ const ICONS: Record<
|
|||
TypeAttributes.Status,
|
||||
{
|
||||
color: string
|
||||
icon: JSX.Element
|
||||
icon: ReactElement
|
||||
}
|
||||
> = {
|
||||
success: {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useState, useCallback, useRef, useEffect } from 'react'
|
||||
import React, { useState, useCallback, useRef, useEffect } from 'react'
|
||||
import useCallbackRef from './useCallbackRef'
|
||||
|
||||
type UseControllableStateParams<T> = {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,22 @@ body {
|
|||
font-size: 14px; /* body’ye font-size uygulanmaz */
|
||||
}
|
||||
|
||||
.list-card-view.dx-cardview {
|
||||
padding: 0;
|
||||
border-radius: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.list-card-view .dx-cardview-card,
|
||||
.list-card-view .dx-cardview-card-header .dx-toolbar,
|
||||
.list-card-view .dx-cardview-card-footer {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
.list-card-view .dx-toolbar .dx-button-text {
|
||||
text-transform: none !important;
|
||||
}
|
||||
|
||||
.dx-form-group-with-caption > .dx-form-group-content {
|
||||
padding-top: 2px !important;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,4 +33,5 @@ export interface ListFormJsonRowDto {
|
|||
export interface ListState {
|
||||
listFormCode: string
|
||||
layout: ListViewLayoutType
|
||||
cardColumnCount?: number
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ export const ListFormEditTabs = {
|
|||
TreeForm: 'tree',
|
||||
GanttForm: 'gantt',
|
||||
SchedulerForm: 'scheduler',
|
||||
TodoForm: 'todo',
|
||||
PagerForm: 'pager',
|
||||
StateForm: 'state',
|
||||
SubForm: 'subForm',
|
||||
|
|
@ -93,6 +94,7 @@ export const tabVisibilityConfig: Record<string, string[]> = {
|
|||
'tree',
|
||||
'gantt',
|
||||
'scheduler',
|
||||
'todo',
|
||||
'pager',
|
||||
'state',
|
||||
'extrafilter',
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
import { SelectCommandTypeEnum } from '@/proxy/form/models'
|
||||
import {
|
||||
ListFormWorkflowCriteriaDto,
|
||||
SubFormDto,
|
||||
WidgetEditDto,
|
||||
WorkflowDto,
|
||||
SelectCommandTypeEnum,
|
||||
} from '@/proxy/form/models'
|
||||
import { ListViewLayoutType } from '@/views/admin/listForm/edit/types'
|
||||
|
||||
export interface ListFormWizardColumnItemDto {
|
||||
dataField: string
|
||||
fieldName: string
|
||||
editorType: string
|
||||
editorOptions: string
|
||||
editorScript: string
|
||||
|
|
@ -39,11 +38,13 @@ export interface ListFormWizardDto {
|
|||
|
||||
defaultLayout: ListViewLayoutType
|
||||
grid: boolean
|
||||
card: boolean
|
||||
pivot: boolean
|
||||
tree: boolean
|
||||
chart: boolean
|
||||
gantt: boolean
|
||||
scheduler: boolean
|
||||
todo: boolean
|
||||
|
||||
languageTextMenuEn: string
|
||||
languageTextMenuTr: string
|
||||
|
|
@ -55,6 +56,7 @@ export interface ListFormWizardDto {
|
|||
languageTextMenuParentTr: string
|
||||
permissionGroupName: string
|
||||
menuParentCode: string
|
||||
menuParentShortName?: string
|
||||
menuParentIcon?: string
|
||||
menuIcon: string
|
||||
dataSourceCode: string
|
||||
|
|
@ -83,11 +85,30 @@ export interface ListFormWizardDto {
|
|||
schedulerStartDateExpr?: string
|
||||
schedulerEndDateExpr?: string
|
||||
|
||||
// Todo options (required when defaultLayout = 'todo')
|
||||
todoTitleExpr: string
|
||||
todoStatusExpr: string
|
||||
todoDescriptionExpr: string
|
||||
todoDueDateExpr: string
|
||||
todoTagExpr: string
|
||||
todoAssigneeExpr: string
|
||||
todoPriorityExpr: string
|
||||
todoCompletedExpr: string
|
||||
todoOrderExpr: string
|
||||
todoStatusOrder: string
|
||||
todoAllowDragging: boolean
|
||||
|
||||
// Workflow options (required when defaultLayout = 'workflow')
|
||||
approvalUserFieldName: string
|
||||
approvalDateFieldName: string
|
||||
approvalStatusFieldName: string
|
||||
approvalDescriptionFieldName: string
|
||||
approvalIsFilterUserName: boolean
|
||||
criteria: ListFormWorkflowCriteriaDto[]
|
||||
|
||||
groups?: ListFormWizardColumnGroupDto[]
|
||||
subForms?: SubFormDto[]
|
||||
widgets?: WidgetEditDto[]
|
||||
workflow?: WorkflowDto
|
||||
workflowCriteria?: ListFormWorkflowCriteriaDto[]
|
||||
}
|
||||
|
||||
export interface WizardFileInfoDto {
|
||||
|
|
@ -109,7 +130,7 @@ export interface WizardInsertedRecordsDto {
|
|||
}
|
||||
|
||||
export interface WizardSeedFileItemDto {
|
||||
dataField: string
|
||||
fieldName: string
|
||||
editorType: string
|
||||
editorOptions: string
|
||||
editorScript: string
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import type {
|
|||
StartEditAction,
|
||||
StateStoreType,
|
||||
} from 'devextreme/ui/data_grid_types'
|
||||
import type { FormItemComponent } from 'devextreme/ui/form'
|
||||
import { AuditedEntityDto } from '../abp'
|
||||
import { EditorType2, RowMode } from '../../views/form/types'
|
||||
import {
|
||||
|
|
@ -195,7 +194,7 @@ export interface ColumnFilterDto {
|
|||
}
|
||||
|
||||
export interface ColumnFormatDto extends AuditedEntityDto<string> {
|
||||
fieldName?: string
|
||||
fieldName: string
|
||||
captionName?: string
|
||||
placeHolder?: string
|
||||
readOnly: boolean
|
||||
|
|
@ -245,6 +244,14 @@ export interface ColumnFormatDto extends AuditedEntityDto<string> {
|
|||
alignment?: HorizontalAlignment
|
||||
format?: string
|
||||
editorOptions?: string
|
||||
editOrderNo?: number
|
||||
editGroupOrderNo?: number
|
||||
editorType2: EditorType2
|
||||
colSpan?: number
|
||||
gridBoxOptions?: GridBoxOptionsDto
|
||||
tagBoxOptions?: TagBoxOptionsDto
|
||||
imageUploadOptions?: ImageUploadOptionsDto
|
||||
editorScript?: string
|
||||
}
|
||||
|
||||
export enum AuthorizationTypeEnum {
|
||||
|
|
@ -442,6 +449,20 @@ export interface SchedulerOptionDto {
|
|||
resources?: SchedulerResourceDto[]
|
||||
}
|
||||
|
||||
export interface TodoOptionDto {
|
||||
titleExpr?: string
|
||||
statusExpr?: string
|
||||
descriptionExpr?: string
|
||||
dueDateExpr?: string
|
||||
tagExpr?: string
|
||||
assigneeExpr?: string
|
||||
priorityExpr?: string
|
||||
completedExpr?: string
|
||||
orderExpr?: string
|
||||
statusOrder?: string
|
||||
allowDragging?: boolean
|
||||
}
|
||||
|
||||
export interface SchedulerResourceDto {
|
||||
fieldExpr?: string
|
||||
dataSource?: any[]
|
||||
|
|
@ -478,20 +499,6 @@ export interface EditingFormDto {
|
|||
caption?: string
|
||||
colCount: number
|
||||
colSpan: number
|
||||
items?: EditingFormItemDto[]
|
||||
}
|
||||
|
||||
export interface EditingFormItemDto {
|
||||
order: number
|
||||
dataField: string
|
||||
editorType: FormItemComponent
|
||||
editorType2: EditorType2
|
||||
colSpan?: number
|
||||
editorOptions?: string
|
||||
gridBoxOptions?: GridBoxOptionsDto
|
||||
tagBoxOptions?: TagBoxOptionsDto
|
||||
imageUploadOptions?: ImageUploadOptionsDto
|
||||
editorScript?: string
|
||||
}
|
||||
|
||||
export interface GridEditingPopupDto {
|
||||
|
|
@ -557,6 +564,8 @@ export interface GridOptionsDto extends AuditedEntityDto<string> {
|
|||
ganttOptionDto: GanttOptionDto
|
||||
schedulerOptionJson?: string
|
||||
schedulerOptionDto: SchedulerOptionDto
|
||||
todoOptionJson?: string
|
||||
todoOptionDto: TodoOptionDto
|
||||
pagerOptionJson?: string
|
||||
pagerOptionDto: GridPagerOptionDto
|
||||
editingOptionJson?: string
|
||||
|
|
@ -911,10 +920,10 @@ export interface WidgetEditDto {
|
|||
|
||||
export interface WorkflowDto {
|
||||
approvalUserFieldName: string
|
||||
isFilterUserName: boolean
|
||||
approvalDateFieldName: string
|
||||
approvalStatusFieldName: string
|
||||
approvalDescriptionFieldName: string
|
||||
approvalIsFilterUserName: boolean
|
||||
criteria: ListFormWorkflowCriteriaDto[]
|
||||
}
|
||||
|
||||
|
|
@ -951,11 +960,13 @@ export interface ListFormWorkflowCriteriaDto {
|
|||
|
||||
export interface LayoutDto {
|
||||
grid: boolean
|
||||
card: boolean
|
||||
pivot: boolean
|
||||
tree: boolean
|
||||
chart: boolean
|
||||
gantt: boolean
|
||||
scheduler: boolean
|
||||
todo: boolean
|
||||
defaultLayout: ListViewLayoutType
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { LayoutType } from '../theme/models'
|
||||
import type { LazyExoticComponent, ReactNode } from 'react'
|
||||
import type { LazyExoticComponent, ReactElement, ReactNode } from 'react'
|
||||
|
||||
export interface Meta {
|
||||
pageContainerType?: 'default' | 'gutterless' | 'contained'
|
||||
header?: string | ReactNode
|
||||
headerContainer?: boolean
|
||||
extraHeader?: LazyExoticComponent<() => JSX.Element>
|
||||
extraHeader?: LazyExoticComponent<() => ReactElement>
|
||||
footer?: boolean
|
||||
layout?: LayoutType
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ export interface Meta {
|
|||
export type Route = {
|
||||
key: string
|
||||
path: string
|
||||
component: LazyExoticComponent<<T extends Meta>(props: T) => JSX.Element>
|
||||
component: LazyExoticComponent<<T extends Meta>(props: T) => ReactElement>
|
||||
authority: string[]
|
||||
meta?: Meta
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ export const adminModel: AdminModel = {
|
|||
setStates: action((state, payload) => {
|
||||
const stateId = state.states.findIndex((s) => s.listFormCode === payload.listFormCode)
|
||||
if (stateId !== -1) {
|
||||
state.states[stateId] = payload
|
||||
state.states[stateId] = { ...state.states[stateId], ...payload }
|
||||
} else {
|
||||
state.states = [...state.states, payload]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ export const store = createStore<StoreModel>(
|
|||
},
|
||||
{
|
||||
allow: ['auth', 'theme', 'locale', 'client', 'admin'],
|
||||
storage: 'localStorage',
|
||||
},
|
||||
),
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { useLocation } from 'react-router-dom'
|
|||
import { FaUser } from 'react-icons/fa'
|
||||
import navigationIcon from '@/proxy/menus/navigation-icon.config'
|
||||
import { navigationTreeToFlat } from '@/utils/navigation'
|
||||
import { ReactElement } from 'react'
|
||||
|
||||
const extractListFormCode = (path: string): string | null => {
|
||||
const p = (path ?? '').toLowerCase()
|
||||
|
|
@ -14,7 +15,7 @@ const extractListFormCode = (path: string): string | null => {
|
|||
return null
|
||||
}
|
||||
|
||||
export function useCurrentMenuIcon(className = 'w-6 h-6'): JSX.Element {
|
||||
export function useCurrentMenuIcon(className = 'w-6 h-6'): ReactElement {
|
||||
const mainMenu = useStoreState((state) => state.abpConfig.menu.mainMenu)
|
||||
const location = useLocation()
|
||||
const menus = navigationTreeToFlat(mainMenu)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useEffect, useState } from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
|
||||
function useTimeOutMessage(
|
||||
interval = 3000,
|
||||
|
|
|
|||
|
|
@ -27,7 +27,11 @@ import FormTabSubForm from './FormTabSubForm'
|
|||
import FormFields from './form-fields/FormFields'
|
||||
import { putListForms } from '@/services/admin/list-form.service'
|
||||
import { getRoles, getUsers } from '@/services/identity.service'
|
||||
import { SelectCommandTypeEnum, GridOptionsEditDto, ListFormCustomizationDto } from '@/proxy/form/models'
|
||||
import {
|
||||
SelectCommandTypeEnum,
|
||||
GridOptionsEditDto,
|
||||
ListFormCustomizationDto,
|
||||
} from '@/proxy/form/models'
|
||||
import { IdentityRoleDto, IdentityUserDto } from '@/proxy/admin/models'
|
||||
import { getListFormCustomizations } from '@/services/admin/list-form-customization.service'
|
||||
import { sqlObjectManagerService } from '@/services/sql-query-manager.service'
|
||||
|
|
@ -54,6 +58,7 @@ import FormTabSorting from './FormTabSorting'
|
|||
import FormTabRow from './FormTabRow'
|
||||
import FormTabGantt from './FormTabGantt'
|
||||
import FormTabScheduler from './FormTabScheduler'
|
||||
import FormTabTodo from './FormTabTodo'
|
||||
import { APP_NAME } from '@/constants/app.constant'
|
||||
import { FormTabWorkflow } from './FormTabWorkflow'
|
||||
|
||||
|
|
@ -295,6 +300,9 @@ const FormEdit = () => {
|
|||
{translate('::ListForms.ListFormEdit.ExtraFilters')}
|
||||
</TabNav>
|
||||
)}
|
||||
{visibleTabs.includes('editForm') && (
|
||||
<TabNav value="editForm">{translate('::ListForms.ListFormEdit.EditingForm')}</TabNav>
|
||||
)}
|
||||
{visibleTabs.includes('fields') && (
|
||||
<TabNav value="fields">{translate('::ListForms.ListFormEdit.TabFields')}</TabNav>
|
||||
)}
|
||||
|
|
@ -303,9 +311,6 @@ const FormEdit = () => {
|
|||
{translate('::ListForms.ListFormEdit.TabCustomization')}
|
||||
</TabNav>
|
||||
)}
|
||||
{visibleTabs.includes('editForm') && (
|
||||
<TabNav value="editForm">{translate('::ListForms.ListFormEdit.EditingForm')}</TabNav>
|
||||
)}
|
||||
{visibleTabs.includes('pivots') && (
|
||||
<TabNav value="pivots">{translate('::ListForms.ListFormEdit.TabPivot')}</TabNav>
|
||||
)}
|
||||
|
|
@ -318,6 +323,7 @@ const FormEdit = () => {
|
|||
{visibleTabs.includes('scheduler') && (
|
||||
<TabNav value="scheduler">{translate('::ListForms.ListFormEdit.TabScheduler')}</TabNav>
|
||||
)}
|
||||
{visibleTabs.includes('todo') && <TabNav value="todo">Todo</TabNav>}
|
||||
{visibleTabs.includes('subForms') && (
|
||||
<TabNav value="subForms">{translate('::ListForms.ListFormEdit.SubForms')}</TabNav>
|
||||
)}
|
||||
|
|
@ -431,6 +437,9 @@ const FormEdit = () => {
|
|||
<TabContent value="scheduler" className="px-2">
|
||||
<FormTabScheduler onSubmit={onSubmit} />
|
||||
</TabContent>
|
||||
<TabContent value="todo" className="px-2">
|
||||
<FormTabTodo onSubmit={onSubmit} />
|
||||
</TabContent>
|
||||
<TabContent value="pager" className="px-2">
|
||||
<FormTabPager onSubmit={onSubmit} />
|
||||
</TabContent>
|
||||
|
|
@ -455,6 +464,7 @@ const FormEdit = () => {
|
|||
<TabContent value="fields" className="px-2">
|
||||
<FormFields
|
||||
listFormCode={listFormCode}
|
||||
editingFormGroups={listFormValues.editingFormDto ?? []}
|
||||
langOptions={langOptions}
|
||||
roleList={roleList}
|
||||
userList={userList}
|
||||
|
|
|
|||
|
|
@ -26,10 +26,13 @@ const schema = Yup.object().shape({
|
|||
defaultLayout: Yup.string(),
|
||||
layoutDto: Yup.object().shape({
|
||||
grid: Yup.boolean(),
|
||||
card: Yup.boolean(),
|
||||
pivot: Yup.boolean(),
|
||||
chart: Yup.boolean(),
|
||||
tree: Yup.boolean(),
|
||||
gantt: Yup.boolean(),
|
||||
scheduler: Yup.boolean(),
|
||||
todo: Yup.boolean(),
|
||||
defaultLayout: Yup.string(),
|
||||
}),
|
||||
})
|
||||
|
|
@ -312,6 +315,22 @@ function FormTabDetails(
|
|||
/>
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
label={translate('::ListForms.ListFormEdit.DetailsLayoutDto.CardLayout')}
|
||||
invalid={errors.layoutDto?.card && touched.layoutDto?.card}
|
||||
errorMessage={errors.layoutDto?.card}
|
||||
>
|
||||
<Field
|
||||
className="w-20"
|
||||
autoComplete="off"
|
||||
name="layoutDto.card"
|
||||
placeholder={translate(
|
||||
'::ListForms.ListFormEdit.DetailsLayoutDto.CardLayout',
|
||||
)}
|
||||
component={Checkbox}
|
||||
/>
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
label={translate('::ListForms.ListFormEdit.DetailsLayoutDto.PivotLayout')}
|
||||
invalid={errors.layoutDto?.pivot && touched.layoutDto?.pivot}
|
||||
|
|
@ -393,6 +412,19 @@ function FormTabDetails(
|
|||
component={Checkbox}
|
||||
/>
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
label={translate('::ListForms.ListFormEdit.DetailsLayoutDto.TodoLayout')}
|
||||
invalid={errors.layoutDto?.todo && touched.layoutDto?.todo}
|
||||
errorMessage={errors.layoutDto?.todo}
|
||||
>
|
||||
<Field
|
||||
className="w-20"
|
||||
autoComplete="off"
|
||||
name="layoutDto.todo"
|
||||
component={Checkbox}
|
||||
/>
|
||||
</FormItem>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,6 @@ function FormTabEditForm(props: { listFormCode: string }) {
|
|||
<Th>{translate('::ListForms.ListFormEdit.DetailsTitle')}</Th>
|
||||
<Th>{translate('::ListForms.ListFormEdit.EditingFormColumnCount')}</Th>
|
||||
<Th>{translate('::ListForms.ListFormEdit.EditingFormColumnSpan')}</Th>
|
||||
<Th>{translate('::ListForms.ListFormEdit.EditingFormItems')}</Th>
|
||||
</Tr>
|
||||
</THead>
|
||||
<TBody>
|
||||
|
|
@ -109,13 +108,6 @@ function FormTabEditForm(props: { listFormCode: string }) {
|
|||
<Td>{row.caption}</Td>
|
||||
<Td>{row.colCount}</Td>
|
||||
<Td>{row.colSpan}</Td>
|
||||
<Td>
|
||||
<ul className="list-disc">
|
||||
{row.items?.map((i, idx) => (
|
||||
<li key={`items-${i.dataField}-${idx}`}>{i.dataField}</li>
|
||||
))}
|
||||
</ul>
|
||||
</Td>
|
||||
</Tr>
|
||||
))}
|
||||
</TBody>
|
||||
|
|
|
|||
137
ui/src/views/admin/listForm/edit/FormTabTodo.tsx
Normal file
137
ui/src/views/admin/listForm/edit/FormTabTodo.tsx
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
FormContainer,
|
||||
FormItem,
|
||||
Input,
|
||||
Notification,
|
||||
Select,
|
||||
toast,
|
||||
} from '@/components/ui'
|
||||
import { ListFormEditTabs } from '@/proxy/admin/list-form/options'
|
||||
import type { GridOptionsEditDto } from '@/proxy/form/models'
|
||||
import { getListFormFields } from '@/services/admin/list-form-field.service'
|
||||
import { useStoreState } from '@/store'
|
||||
import type { SelectBoxOption } from '@/types/shared'
|
||||
import { Field, FieldProps, Form, Formik } from 'formik'
|
||||
import groupBy from 'lodash/groupBy'
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { useParams } from 'react-router-dom'
|
||||
import type { FormEditProps } from './FormEdit'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
|
||||
const mappings: Array<{
|
||||
name: keyof GridOptionsEditDto['todoOptionDto']
|
||||
labelKey: string
|
||||
required?: boolean
|
||||
}> = [
|
||||
{ name: 'titleExpr', labelKey: 'TodoTitleExpr', required: true },
|
||||
{ name: 'statusExpr', labelKey: 'TodoStatusExpr', required: true },
|
||||
{ name: 'descriptionExpr', labelKey: 'TodoDescriptionExpr' },
|
||||
{ name: 'dueDateExpr', labelKey: 'TodoDueDateExpr' },
|
||||
{ name: 'tagExpr', labelKey: 'TodoTagExpr' },
|
||||
{ name: 'assigneeExpr', labelKey: 'TodoAssigneeExpr' },
|
||||
{ name: 'priorityExpr', labelKey: 'TodoPriorityExpr' },
|
||||
{ name: 'completedExpr', labelKey: 'TodoCompletedExpr' },
|
||||
{ name: 'orderExpr', labelKey: 'TodoOrderExpr' },
|
||||
]
|
||||
|
||||
const FormTabTodo = ({ onSubmit }: FormEditProps) => {
|
||||
const { listFormCode } = useParams()
|
||||
const values = useStoreState((state) => state.admin.lists.values)
|
||||
const [fields, setFields] = useState<SelectBoxOption[]>([])
|
||||
const { translate } = useLocalization()
|
||||
const translateRef = useRef(translate)
|
||||
translateRef.current = translate
|
||||
|
||||
const loadFields = useCallback(async () => {
|
||||
if (!listFormCode) return
|
||||
try {
|
||||
const response = await getListFormFields({
|
||||
listFormCode,
|
||||
sorting: 'ListOrderNo',
|
||||
maxResultCount: 1000,
|
||||
})
|
||||
const names = groupBy(response.data?.items ?? [], 'fieldName')
|
||||
setFields(Object.keys(names).map((name) => ({ value: name, label: name })))
|
||||
} catch (error: any) {
|
||||
toast.push(
|
||||
<Notification type="danger">
|
||||
{translateRef.current('::ListForms.ListFormFieldEdit.TodoFieldsLoadFailed', {
|
||||
0: error.toString(),
|
||||
})}
|
||||
</Notification>,
|
||||
)
|
||||
}
|
||||
}, [listFormCode])
|
||||
|
||||
useEffect(() => {
|
||||
loadFields()
|
||||
}, [loadFields])
|
||||
if (!values) return null
|
||||
|
||||
return (
|
||||
<Formik
|
||||
initialValues={values}
|
||||
onSubmit={(formValues, helpers) => onSubmit(ListFormEditTabs.TodoForm, formValues, helpers)}
|
||||
>
|
||||
{({ isSubmitting, values: formValues }) => (
|
||||
<Form>
|
||||
<FormContainer size="sm">
|
||||
<div className="grid grid-cols-1 gap-3 md:grid-cols-2 lg:grid-cols-4">
|
||||
{mappings.map((mapping) => (
|
||||
<FormItem
|
||||
key={mapping.name}
|
||||
label={`${translate(
|
||||
`::ListForms.ListFormFieldEdit.${mapping.labelKey}`,
|
||||
)}${mapping.required ? ' *' : ''}`}
|
||||
>
|
||||
<Field name={`todoOptionDto.${mapping.name}`}>
|
||||
{({ field, form }: FieldProps) => (
|
||||
<Select
|
||||
field={field}
|
||||
form={form}
|
||||
isClearable={!mapping.required}
|
||||
options={fields}
|
||||
value={fields.find(
|
||||
(option) => option.value === formValues.todoOptionDto?.[mapping.name],
|
||||
)}
|
||||
onChange={(option) => form.setFieldValue(field.name, option?.value)}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</FormItem>
|
||||
))}
|
||||
</div>
|
||||
<div className="mt-3 grid grid-cols-1 gap-3 md:grid-cols-2">
|
||||
<FormItem label={translate('::ListForms.ListFormFieldEdit.TodoStatusOrder')}>
|
||||
<Field
|
||||
name="todoOptionDto.statusOrder"
|
||||
component={Input}
|
||||
placeholder={translate(
|
||||
'::ListForms.ListFormFieldEdit.TodoStatusOrderPlaceholder',
|
||||
)}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label={translate('::ListForms.ListFormFieldEdit.TodoAllowDragging')}>
|
||||
<Field name="todoOptionDto.allowDragging" component={Checkbox} />
|
||||
</FormItem>
|
||||
</div>
|
||||
<Button
|
||||
block
|
||||
size="sm"
|
||||
variant="solid"
|
||||
loading={isSubmitting}
|
||||
type="submit"
|
||||
className="my-3"
|
||||
>
|
||||
{translate('::Save')}
|
||||
</Button>
|
||||
</FormContainer>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
)
|
||||
}
|
||||
|
||||
export default FormTabTodo
|
||||
|
|
@ -314,10 +314,10 @@ export function FormTabWorkflow(
|
|||
const schema = object().shape({
|
||||
workflowDto: object().shape({
|
||||
approvalUserFieldName: string().required(),
|
||||
isFilterUserName: bool(),
|
||||
approvalStatusFieldName: string().required(),
|
||||
approvalDateFieldName: string(),
|
||||
approvalDescriptionFieldName: string(),
|
||||
approvalIsFilterUserName: bool(),
|
||||
}),
|
||||
})
|
||||
|
||||
|
|
@ -442,16 +442,16 @@ export function FormTabWorkflow(
|
|||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
label={translate('::ListForms.ListFormEdit.Workflow.IsFilterUserName')}
|
||||
label={translate('::ListForms.ListFormEdit.Workflow.ApprovalIsFilterUserName')}
|
||||
invalid={
|
||||
!!(
|
||||
errors.workflowDto?.isFilterUserName &&
|
||||
touched.workflowDto?.isFilterUserName
|
||||
errors.workflowDto?.approvalIsFilterUserName &&
|
||||
touched.workflowDto?.approvalIsFilterUserName
|
||||
)
|
||||
}
|
||||
errorMessage={errors.workflowDto?.isFilterUserName as string}
|
||||
errorMessage={errors.workflowDto?.approvalIsFilterUserName as string}
|
||||
>
|
||||
<Field name="workflowDto.isFilterUserName" component={Checkbox} />
|
||||
<Field name="workflowDto.approvalIsFilterUserName" component={Checkbox} />
|
||||
</FormItem>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -20,14 +20,17 @@ import FormFieldTabTotalSummary from './FormFieldTabTotalSummary'
|
|||
import FormFieldTabValidationRules from './FormFieldTabValidationRules'
|
||||
import { FormFieldEditProps } from './FormFields'
|
||||
import FormFieldTabPivotSetting from './FormFieldTabPivotSetting'
|
||||
import type { EditingFormDto } from '@/proxy/form/models'
|
||||
|
||||
function FormFieldEdit({
|
||||
item,
|
||||
onSubmit,
|
||||
fields,
|
||||
editingFormGroups,
|
||||
}: {
|
||||
item: ColumnFormatEditDto | null
|
||||
fields: ColumnFormatEditDto[]
|
||||
editingFormGroups: EditingFormDto[]
|
||||
} & FormFieldEditProps) {
|
||||
const { translate } = useLocalization()
|
||||
|
||||
|
|
@ -72,13 +75,18 @@ function FormFieldEdit({
|
|||
<TabNav value="pivotSetting">
|
||||
{translate('::ListForms.ListFormFieldEdit.TabPivotSettings')}
|
||||
</TabNav>
|
||||
</TabList>
|
||||
</TabList>
|
||||
<div className="pt-4">
|
||||
<TabContent value="details">
|
||||
<FormFieldTabDetails initialValues={item} onSubmit={onSubmit} />
|
||||
</TabContent>
|
||||
<TabContent value="options">
|
||||
<FormFieldTabOptions initialValues={item} onSubmit={onSubmit} />
|
||||
<FormFieldTabOptions
|
||||
initialValues={item}
|
||||
editingFormGroups={editingFormGroups}
|
||||
fields={fields}
|
||||
onSubmit={onSubmit}
|
||||
/>
|
||||
</TabContent>
|
||||
<TabContent value="permissions">
|
||||
<FormFieldTabPermissions initialValues={item} onSubmit={onSubmit} />
|
||||
|
|
@ -96,18 +104,10 @@ function FormFieldEdit({
|
|||
<FormFieldTabGrouping initialValues={item} onSubmit={onSubmit} />
|
||||
</TabContent>
|
||||
<TabContent value="groupSummary">
|
||||
<FormFieldTabGroupSummary
|
||||
initialValues={item}
|
||||
fields={fields}
|
||||
onSubmit={onSubmit}
|
||||
/>
|
||||
<FormFieldTabGroupSummary initialValues={item} fields={fields} onSubmit={onSubmit} />
|
||||
</TabContent>
|
||||
<TabContent value="totalSummary">
|
||||
<FormFieldTabTotalSummary
|
||||
initialValues={item}
|
||||
fields={fields}
|
||||
onSubmit={onSubmit}
|
||||
/>
|
||||
<FormFieldTabTotalSummary initialValues={item} fields={fields} onSubmit={onSubmit} />
|
||||
</TabContent>
|
||||
<TabContent value="joinOptions">
|
||||
<FormFieldTabJoinOptions initialValues={item} onSubmit={onSubmit} />
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { Button, Card, FormItem, Input, Select } from '@/components/ui'
|
||||
import { Button, Card, Checkbox, FormItem, Input, Select } from '@/components/ui'
|
||||
import { ColumnFormatEditDto, ListFormFieldEditTabs } from '@/proxy/admin/list-form-field/models'
|
||||
import { SelectBoxOption } from '@/types/shared'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import { Field, FieldProps, Form, Formik } from 'formik'
|
||||
import { useState } from 'react'
|
||||
import { FaSlidersH } from 'react-icons/fa'
|
||||
import { number, object, string } from 'yup'
|
||||
import { bool, number, object, string } from 'yup'
|
||||
import { dbSourceTypeOptions, listFormAlignmentOptions } from '../options'
|
||||
import EditorOptionsBuilderDialog from '../json-row-operations/EditorOptionsBuilderDialog'
|
||||
import { FormFieldEditProps } from './FormFields'
|
||||
|
|
@ -16,10 +16,13 @@ const schema = object().shape({
|
|||
captionName: string(),
|
||||
placeHolder: string(),
|
||||
bandName: string(),
|
||||
isActive: bool().required(),
|
||||
visible: bool().required(),
|
||||
allowSearch: bool().required(),
|
||||
sourceDbType: number().required(),
|
||||
alignment: string(),
|
||||
format: string(),
|
||||
editorOptions: string().max(1000),
|
||||
editorOptions: string(),
|
||||
})
|
||||
|
||||
function FormFieldTabDetails({
|
||||
|
|
@ -72,6 +75,32 @@ function FormFieldTabDetails({
|
|||
>
|
||||
<Field type="text" name="bandName" component={Input} />
|
||||
</FormItem>
|
||||
<div className="flex w-full gap-4">
|
||||
<FormItem
|
||||
className="flex-1"
|
||||
label={translate('::ListForms.ListFormFieldEdit.HeaderingAllowSearch')}
|
||||
>
|
||||
<Field name="allowSearch" component={Checkbox} />
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
className="flex-1"
|
||||
label={translate('::ListForms.ListFormFieldEdit.OptionsIsActive')}
|
||||
invalid={errors.isActive && touched.isActive}
|
||||
errorMessage={errors.isActive}
|
||||
>
|
||||
<Field name="isActive" component={Checkbox} />
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
className="flex-1"
|
||||
label={translate('::ListForms.ListFormFieldEdit.OptionsVisible')}
|
||||
invalid={errors.visible && touched.visible}
|
||||
errorMessage={errors.visible}
|
||||
>
|
||||
<Field name="visible" component={Checkbox} />
|
||||
</FormItem>
|
||||
</div>
|
||||
</Card>
|
||||
<Card>
|
||||
<FormItem label={translate('::ListForms.ListFormEdit.CustomValueType')}>
|
||||
|
|
@ -132,7 +161,7 @@ function FormFieldTabDetails({
|
|||
type="text"
|
||||
name="editorOptions"
|
||||
component={Input}
|
||||
rows={4}
|
||||
rows={3}
|
||||
textArea={true}
|
||||
/>
|
||||
<Button
|
||||
|
|
@ -154,7 +183,14 @@ function FormFieldTabDetails({
|
|||
onClose={() => setIsEditorOptionsDialogOpen(false)}
|
||||
onApply={(val) => setFieldValue('editorOptions', val)}
|
||||
/>
|
||||
<Button block size="sm" className="mt-1" variant="solid" loading={isSubmitting} type="submit">
|
||||
<Button
|
||||
block
|
||||
size="sm"
|
||||
className="mt-1"
|
||||
variant="solid"
|
||||
loading={isSubmitting}
|
||||
type="submit"
|
||||
>
|
||||
{isSubmitting ? translate('::Saving') : translate('::Save')}
|
||||
</Button>
|
||||
</Form>
|
||||
|
|
|
|||
|
|
@ -4,29 +4,50 @@ import { SelectBoxOption } from '@/types/shared'
|
|||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import { Field, FieldProps, Form, Formik } from 'formik'
|
||||
import { bool, number, object, string } from 'yup'
|
||||
import { sortDirectionOptions } from '../options'
|
||||
import { columnEditorTypeListOptions, sortDirectionOptions } from '../options'
|
||||
import { FormFieldEditProps } from './FormFields'
|
||||
import { SortDirectionEnum } from '@/proxy/form/models'
|
||||
import { EditingFormDto, SortDirectionEnum } from '@/proxy/form/models'
|
||||
import { FaCode } from 'react-icons/fa'
|
||||
import { useState } from 'react'
|
||||
import EditorScriptBuilderDialog from '../json-row-operations/EditorScriptBuilderDialog'
|
||||
|
||||
const schema = object().shape({
|
||||
listOrderNo: number(),
|
||||
width: number(),
|
||||
sortDirection: string().oneOf(Object.values(SortDirectionEnum) as string[]),
|
||||
sortIndex: number(),
|
||||
isActive: bool().required(),
|
||||
visible: bool().required(),
|
||||
allowSearch: bool().required(),
|
||||
editGroupOrderNo: number().nullable(),
|
||||
editOrderNo: number().nullable(),
|
||||
colSpan: number().nullable(),
|
||||
allowEditing: bool().required(),
|
||||
allowAdding: bool().required(),
|
||||
editorScript: string(),
|
||||
})
|
||||
|
||||
function FormFieldTabOptions({
|
||||
initialValues,
|
||||
editingFormGroups,
|
||||
fields,
|
||||
onSubmit,
|
||||
}: {
|
||||
initialValues: ColumnFormatEditDto
|
||||
editingFormGroups: EditingFormDto[]
|
||||
fields: ColumnFormatEditDto[]
|
||||
} & FormFieldEditProps) {
|
||||
const { translate } = useLocalization()
|
||||
const [isEditorScriptDialogOpen, setIsEditorScriptDialogOpen] = useState(false)
|
||||
const editingFormGroupOptions: SelectBoxOption[] = [...editingFormGroups]
|
||||
.sort((left, right) => left.order - right.order)
|
||||
.map((group) => ({
|
||||
value: String(group.order),
|
||||
label: `${group.order} - ${group.caption || translate('::ListForms.ListFormFieldEdit.EditFormGroup')}`,
|
||||
}))
|
||||
const editorScriptFields: SelectBoxOption[] = fields
|
||||
.filter((field) => field.fieldName)
|
||||
.map((field) => ({
|
||||
value: field.fieldName,
|
||||
label: field.captionName || field.fieldName,
|
||||
}))
|
||||
|
||||
return (
|
||||
<Formik
|
||||
|
|
@ -37,7 +58,7 @@ function FormFieldTabOptions({
|
|||
await onSubmit(ListFormFieldEditTabs.OptionsForm, values, formikHelpers)
|
||||
}}
|
||||
>
|
||||
{({ touched, errors, isSubmitting, values }) => (
|
||||
{({ touched, errors, isSubmitting, values, setFieldValue }) => (
|
||||
<Form>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||
<Card>
|
||||
|
|
@ -82,25 +103,7 @@ function FormFieldTabOptions({
|
|||
>
|
||||
<Field type="number" name="sortIndex" component={Input} />
|
||||
</FormItem>
|
||||
</Card>
|
||||
<Card>
|
||||
<FormItem
|
||||
label={translate('::ListForms.ListFormFieldEdit.OptionsIsActive')}
|
||||
invalid={errors.isActive && touched.isActive}
|
||||
errorMessage={errors.isActive}
|
||||
>
|
||||
<Field name="isActive" component={Checkbox} />
|
||||
</FormItem>
|
||||
<FormItem
|
||||
label={translate('::ListForms.ListFormFieldEdit.OptionsVisible')}
|
||||
invalid={errors.visible && touched.visible}
|
||||
errorMessage={errors.visible}
|
||||
>
|
||||
<Field name="visible" component={Checkbox} />
|
||||
</FormItem>
|
||||
<FormItem label={translate('::ListForms.ListFormFieldEdit.HeaderingAllowSearch')}>
|
||||
<Field name="allowSearch" component={Checkbox} />
|
||||
</FormItem>
|
||||
|
||||
<FormItem label={translate('::ListForms.ListFormEdit.AllowEditing')}>
|
||||
<Field name="allowEditing" component={Checkbox} />
|
||||
</FormItem>
|
||||
|
|
@ -108,9 +111,100 @@ function FormFieldTabOptions({
|
|||
<Field name="allowAdding" component={Checkbox} />
|
||||
</FormItem>
|
||||
</Card>
|
||||
<Card>
|
||||
<FormItem
|
||||
invalid={errors.editorType2 && touched.editorType2}
|
||||
errorMessage={errors.editorType2}
|
||||
label={translate('::ListForms.ListFormFieldEdit.EditorType')}
|
||||
>
|
||||
<Field name="editorType2">
|
||||
{({ field, form }: FieldProps<SelectBoxOption>) => (
|
||||
<Select
|
||||
isClearable
|
||||
options={columnEditorTypeListOptions}
|
||||
value={columnEditorTypeListOptions.find(
|
||||
(option) => option.value === field.value,
|
||||
)}
|
||||
onChange={(option) => form.setFieldValue(field.name, option?.value)}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
invalid={errors.editGroupOrderNo && touched.editGroupOrderNo}
|
||||
errorMessage={errors.editGroupOrderNo}
|
||||
label={translate('::ListForms.ListFormFieldEdit.EditFormGroup')}
|
||||
>
|
||||
<Field name="editGroupOrderNo">
|
||||
{({ field, form }: FieldProps<SelectBoxOption>) => (
|
||||
<Select
|
||||
isClearable
|
||||
options={editingFormGroupOptions}
|
||||
value={editingFormGroupOptions.find(
|
||||
(option) => Number(option.value) === Number(field.value),
|
||||
)}
|
||||
onChange={(option) =>
|
||||
form.setFieldValue(
|
||||
field.name,
|
||||
option?.value == null ? null : Number(option.value),
|
||||
)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
invalid={errors.editOrderNo && touched.editOrderNo}
|
||||
errorMessage={errors.editOrderNo}
|
||||
label={translate('::ListForms.ListFormFieldEdit.EditFormOrderNo')}
|
||||
>
|
||||
<Field type="number" name="editOrderNo" component={Input} />
|
||||
</FormItem>
|
||||
<FormItem
|
||||
invalid={errors.colSpan && touched.colSpan}
|
||||
errorMessage={errors.colSpan}
|
||||
label={translate('::ListForms.ListFormFieldEdit.EditFormColSpan')}
|
||||
>
|
||||
<Field type="number" name="colSpan" component={Input} />
|
||||
</FormItem>
|
||||
<FormItem label={translate('::ListForms.Wizard.Step3.EditorScript')}>
|
||||
<div className="flex gap-2 items-start">
|
||||
<Field
|
||||
type="text"
|
||||
name="editorScript"
|
||||
component={Input}
|
||||
rows={3}
|
||||
textArea={true}
|
||||
/>
|
||||
<Button
|
||||
shape="circle"
|
||||
variant="plain"
|
||||
type="button"
|
||||
size="sm"
|
||||
title="Build editor script"
|
||||
icon={<FaCode />}
|
||||
onClick={() => setIsEditorScriptDialogOpen(true)}
|
||||
/>
|
||||
</div>
|
||||
</FormItem>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<Button block size="sm" className="mt-1" variant="solid" loading={isSubmitting} type="submit">
|
||||
<EditorScriptBuilderDialog
|
||||
isOpen={isEditorScriptDialogOpen}
|
||||
value={values.editorScript}
|
||||
currentField={values.fieldName}
|
||||
fields={editorScriptFields}
|
||||
onClose={() => setIsEditorScriptDialogOpen(false)}
|
||||
onApply={(val) => setFieldValue('editorScript', val)}
|
||||
/>
|
||||
<Button
|
||||
block
|
||||
size="sm"
|
||||
className="mt-1"
|
||||
variant="solid"
|
||||
loading={isSubmitting}
|
||||
type="submit"
|
||||
>
|
||||
{isSubmitting ? translate('::Saving') : translate('::Save')}
|
||||
</Button>
|
||||
</Form>
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ import { dbSourceTypeOptions, sqlDataTypeToDbType } from '../options'
|
|||
import { IdentityRoleDto, IdentityUserDto } from '@/proxy/admin/models'
|
||||
import { sqlObjectManagerService } from '@/services/sql-query-manager.service'
|
||||
import type { DatabaseColumnDto } from '@/proxy/sql-query-manager/models'
|
||||
import type { EditingFormDto } from '@/proxy/form/models'
|
||||
|
||||
export interface FormFieldEditProps {
|
||||
onSubmit: (
|
||||
|
|
@ -71,12 +72,14 @@ const copyFieldSchema = object().shape({
|
|||
|
||||
function FormFields({
|
||||
listFormCode,
|
||||
editingFormGroups,
|
||||
langOptions,
|
||||
roleList,
|
||||
userList,
|
||||
columns,
|
||||
}: {
|
||||
listFormCode: string
|
||||
editingFormGroups: EditingFormDto[]
|
||||
langOptions: SelectBoxOption[]
|
||||
roleList: SelectBoxOption[]
|
||||
userList: SelectBoxOption[]
|
||||
|
|
@ -219,42 +222,45 @@ function FormFields({
|
|||
await getFields()
|
||||
}
|
||||
|
||||
const getFields = useCallback(async (cultureName?: string, roleId?: string, userId?: string) => {
|
||||
if (!listFormCode) {
|
||||
return
|
||||
}
|
||||
const getFields = useCallback(
|
||||
async (cultureName?: string, roleId?: string, userId?: string) => {
|
||||
if (!listFormCode) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const resp = await getListFormFields({
|
||||
listFormCode,
|
||||
cultureName,
|
||||
roleId,
|
||||
userId,
|
||||
sorting: 'ListOrderNo',
|
||||
maxResultCount: 1000,
|
||||
})
|
||||
setNull(resp?.data?.items)
|
||||
setFields(resp?.data?.items)
|
||||
if (resp.data?.items) {
|
||||
setFieldList(
|
||||
resp?.data?.items.map((f: ColumnFormatEditDto) => ({
|
||||
value: f.fieldName,
|
||||
label: f.fieldName,
|
||||
})),
|
||||
try {
|
||||
const resp = await getListFormFields({
|
||||
listFormCode,
|
||||
cultureName,
|
||||
roleId,
|
||||
userId,
|
||||
sorting: 'ListOrderNo',
|
||||
maxResultCount: 1000,
|
||||
})
|
||||
setNull(resp?.data?.items)
|
||||
setFields(resp?.data?.items)
|
||||
if (resp.data?.items) {
|
||||
setFieldList(
|
||||
resp?.data?.items.map((f: ColumnFormatEditDto) => ({
|
||||
value: f.fieldName,
|
||||
label: f.fieldName,
|
||||
})),
|
||||
)
|
||||
}
|
||||
} catch (error: any) {
|
||||
toast.push(
|
||||
<Notification type="danger" duration={2000}>
|
||||
Alanlar getirilemedi
|
||||
{error.toString()}
|
||||
</Notification>,
|
||||
{
|
||||
placement: 'bottom-end',
|
||||
},
|
||||
)
|
||||
}
|
||||
} catch (error: any) {
|
||||
toast.push(
|
||||
<Notification type="danger" duration={2000}>
|
||||
Alanlar getirilemedi
|
||||
{error.toString()}
|
||||
</Notification>,
|
||||
{
|
||||
placement: 'bottom-end',
|
||||
},
|
||||
)
|
||||
}
|
||||
}, [listFormCode])
|
||||
},
|
||||
[listFormCode],
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
getFields()
|
||||
|
|
@ -405,7 +411,7 @@ function FormFields({
|
|||
<Table compact>
|
||||
<THead>
|
||||
<Tr>
|
||||
<Th className='w-3/12'>
|
||||
<Th className="w-3/12">
|
||||
<div>
|
||||
<Button
|
||||
shape="circle"
|
||||
|
|
@ -478,12 +484,19 @@ function FormFields({
|
|||
}
|
||||
}}
|
||||
/>
|
||||
<span>{field.listOrderNo}</span>
|
||||
<span>{!field?.visible && <FaEyeSlash />}</span>
|
||||
<span>{!field?.isActive && <FaTimes />}</span>
|
||||
<span style={{ visibility: !field?.visible ? 'visible' : 'hidden' }}>
|
||||
<FaEyeSlash />
|
||||
</span>
|
||||
<span style={{ visibility: !field?.isActive ? 'visible' : 'hidden' }}>
|
||||
<FaTimes />
|
||||
</span>
|
||||
<span className="ml-5">
|
||||
{field.listOrderNo}
|
||||
{field.editOrderNo ? ` (${field.editOrderNo})` : ''}
|
||||
</span>
|
||||
</Td>
|
||||
<Td className='!p-0'>{field.fieldName}</Td>
|
||||
<Td className='align-middle text-center !p-0'>
|
||||
<Td className="!p-0">{field.fieldName}</Td>
|
||||
<Td className="align-middle text-center !p-0">
|
||||
<Avatar
|
||||
size={18}
|
||||
shape="circle"
|
||||
|
|
@ -505,7 +518,12 @@ function FormFields({
|
|||
</Table>
|
||||
</div>
|
||||
<div className="2xl:col-span-3 lg:col-span-3 xl:col-span-2">
|
||||
<FormFieldEdit item={row} fields={fields} onSubmit={onSubmit} />
|
||||
<FormFieldEdit
|
||||
item={row}
|
||||
fields={fields}
|
||||
editingFormGroups={editingFormGroups}
|
||||
onSubmit={onSubmit}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</AdaptableCard>
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -224,11 +224,13 @@ export const listFormTypeOptions = [
|
|||
|
||||
export const listFormDefaultLayoutOptions = [
|
||||
{ value: 'grid', label: 'Grid' },
|
||||
{ value: 'card', label: 'Card' },
|
||||
{ value: 'pivot', label: 'Pivot' },
|
||||
{ value: 'chart', label: 'Chart' },
|
||||
{ value: 'tree', label: 'Tree' },
|
||||
{ value: 'gantt', label: 'Gantt' },
|
||||
{ value: 'scheduler', label: 'Scheduler' },
|
||||
{ value: 'todo', label: 'Todo' },
|
||||
]
|
||||
|
||||
export const listFormAlignmentOptions = [
|
||||
|
|
|
|||
|
|
@ -1,12 +1,22 @@
|
|||
export type ChartOperation = '' | 'select' | 'insert' | 'update' | 'delete'
|
||||
export type ChartDialogType = '' | 'pane' | 'serie' | 'annotation' | 'axis'
|
||||
export type ListViewLayoutType = 'grid' | 'pivot' | 'tree' | 'chart' | 'gantt' | 'scheduler'
|
||||
export type ListViewLayoutType =
|
||||
| 'grid'
|
||||
| 'card'
|
||||
| 'pivot'
|
||||
| 'tree'
|
||||
| 'chart'
|
||||
| 'gantt'
|
||||
| 'scheduler'
|
||||
| 'todo'
|
||||
|
||||
export const layoutTypes = {
|
||||
grid: 'Grid',
|
||||
card: 'Card',
|
||||
pivot: 'Pivot',
|
||||
tree: 'Tree',
|
||||
chart: 'Chart',
|
||||
gantt: 'Gantt',
|
||||
scheduler: 'Scheduler',
|
||||
todo: 'Todo',
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import WizardStep1, {
|
|||
import WizardStep2 from './WizardStep2'
|
||||
import WizardStep3, { WizardGroup, WizardGroupItem } from './WizardStep3'
|
||||
import WizardStep7 from './WizardStep7'
|
||||
import WizardStep8 from './WizardStep8'
|
||||
import WizardStep4 from './WizardStep4'
|
||||
import WizardStep5 from './WizardStep5'
|
||||
import WizardStep6 from './WizardStep6'
|
||||
|
|
@ -57,11 +58,24 @@ const initialValues: ListFormWizardDto = {
|
|||
allowDetail: false,
|
||||
defaultLayout: 'grid',
|
||||
grid: true,
|
||||
card: true,
|
||||
pivot: true,
|
||||
tree: true,
|
||||
chart: true,
|
||||
gantt: true,
|
||||
scheduler: true,
|
||||
todo: false,
|
||||
todoTitleExpr: '',
|
||||
todoStatusExpr: '',
|
||||
todoDescriptionExpr: '',
|
||||
todoDueDateExpr: '',
|
||||
todoTagExpr: '',
|
||||
todoAssigneeExpr: '',
|
||||
todoPriorityExpr: '',
|
||||
todoCompletedExpr: '',
|
||||
todoOrderExpr: '',
|
||||
todoStatusOrder: 'Backlog, Ready to Start, In Progress, Code Review, Testing, Staging',
|
||||
todoAllowDragging: true,
|
||||
languageTextMenuEn: '',
|
||||
languageTextMenuTr: '',
|
||||
languageTextTitleEn: '',
|
||||
|
|
@ -72,6 +86,7 @@ const initialValues: ListFormWizardDto = {
|
|||
languageTextMenuParentTr: '',
|
||||
permissionGroupName: '',
|
||||
menuParentCode: '',
|
||||
menuParentShortName: '',
|
||||
menuParentIcon: '',
|
||||
menuIcon: '',
|
||||
dataSourceCode: '',
|
||||
|
|
@ -95,15 +110,12 @@ const initialValues: ListFormWizardDto = {
|
|||
schedulerEndDateExpr: '',
|
||||
subForms: [],
|
||||
widgets: [],
|
||||
workflow: {
|
||||
approvalUserFieldName: '',
|
||||
isFilterUserName: false,
|
||||
approvalDateFieldName: '',
|
||||
approvalStatusFieldName: '',
|
||||
approvalDescriptionFieldName: '',
|
||||
criteria: [],
|
||||
},
|
||||
workflowCriteria: [],
|
||||
approvalUserFieldName: '',
|
||||
approvalDateFieldName: '',
|
||||
approvalStatusFieldName: '',
|
||||
approvalDescriptionFieldName: '',
|
||||
approvalIsFilterUserName: false,
|
||||
criteria: [],
|
||||
}
|
||||
|
||||
const step1ValidationSchema = Yup.object().shape({
|
||||
|
|
@ -135,7 +147,26 @@ const step2ValidationSchema = Yup.object().shape({
|
|||
confirmDelete: Yup.boolean(),
|
||||
})
|
||||
|
||||
const listFormValidationSchema = step1ValidationSchema.concat(step2ValidationSchema)
|
||||
const todoValidationSchema = Yup.object().shape({
|
||||
todoTitleExpr: Yup.string()
|
||||
.trim()
|
||||
.when('todo', {
|
||||
is: true,
|
||||
then: (schema) => schema.required(),
|
||||
otherwise: (schema) => schema.notRequired(),
|
||||
}),
|
||||
todoStatusExpr: Yup.string()
|
||||
.trim()
|
||||
.when('todo', {
|
||||
is: true,
|
||||
then: (schema) => schema.required(),
|
||||
otherwise: (schema) => schema.notRequired(),
|
||||
}),
|
||||
})
|
||||
|
||||
const listFormValidationSchema = step1ValidationSchema
|
||||
.concat(step2ValidationSchema)
|
||||
.concat(todoValidationSchema)
|
||||
|
||||
// ─── Wizard ───────────────────────────────────────────────────────────────────
|
||||
|
||||
|
|
@ -225,13 +256,13 @@ const Wizard = () => {
|
|||
const [widgets, setWidgets] = useState<WidgetEditDto[]>([])
|
||||
const [workflow, setWorkflow] = useState<WorkflowDto>({
|
||||
approvalUserFieldName: '',
|
||||
isFilterUserName: false,
|
||||
approvalDateFieldName: '',
|
||||
approvalStatusFieldName: '',
|
||||
approvalDescriptionFieldName: '',
|
||||
approvalIsFilterUserName: false,
|
||||
criteria: [],
|
||||
})
|
||||
const [workflowCriteria, setWorkflowCriteria] = useState<ListFormWorkflowCriteriaDto[]>([])
|
||||
const [criteria, setCriteria] = useState<ListFormWorkflowCriteriaDto[]>([])
|
||||
|
||||
// Audit columns that should not be selected by default
|
||||
const AUDIT_COLUMNS = new Set([
|
||||
|
|
@ -255,7 +286,7 @@ const Wizard = () => {
|
|||
const removeTenantGroupItems = (groups: WizardGroup[]) =>
|
||||
groups.map((group) => ({
|
||||
...group,
|
||||
items: group.items.filter((item) => !isTenantColumn(item.dataField)),
|
||||
items: group.items.filter((item) => !isTenantColumn(item.fieldName)),
|
||||
}))
|
||||
|
||||
const loadColumns = async (dsCode: string, schema: string, name: string) => {
|
||||
|
|
@ -406,11 +437,26 @@ const Wizard = () => {
|
|||
allowDetail: w.allowDetail ?? false,
|
||||
defaultLayout: w.defaultLayout ?? 'grid',
|
||||
grid: w.grid ?? true,
|
||||
card: w.card ?? true,
|
||||
pivot: w.pivot ?? true,
|
||||
tree: w.tree ?? true,
|
||||
chart: w.chart ?? true,
|
||||
gantt: w.gantt ?? true,
|
||||
scheduler: w.scheduler ?? true,
|
||||
todo: w.todo ?? true,
|
||||
todoTitleExpr: w.todoTitleExpr ?? '',
|
||||
todoStatusExpr: w.todoStatusExpr ?? '',
|
||||
todoDescriptionExpr: w.todoDescriptionExpr ?? '',
|
||||
todoDueDateExpr: w.todoDueDateExpr ?? '',
|
||||
todoTagExpr: w.todoTagExpr ?? '',
|
||||
todoAssigneeExpr: w.todoAssigneeExpr ?? '',
|
||||
todoPriorityExpr: w.todoPriorityExpr ?? '',
|
||||
todoCompletedExpr: w.todoCompletedExpr ?? '',
|
||||
todoOrderExpr: w.todoOrderExpr ?? '',
|
||||
todoStatusOrder:
|
||||
w.todoStatusOrder ??
|
||||
'Backlog, Ready to Start, In Progress, Code Review, Testing, Staging',
|
||||
todoAllowDragging: w.todoAllowDragging ?? true,
|
||||
languageTextMenuEn: w.languageTextMenuEn ?? '',
|
||||
languageTextMenuTr: w.languageTextMenuTr ?? '',
|
||||
languageTextTitleEn: w.languageTextTitleEn ?? '',
|
||||
|
|
@ -421,6 +467,7 @@ const Wizard = () => {
|
|||
languageTextMenuParentTr: w.languageTextMenuParentTr ?? '',
|
||||
permissionGroupName: w.permissionGroupName ?? '',
|
||||
menuParentCode: w.menuParentCode ?? '',
|
||||
menuParentShortName: w.menuParentShortName ?? '',
|
||||
menuParentIcon: w.menuParentIcon ?? '',
|
||||
menuIcon: w.menuIcon ?? '',
|
||||
dataSourceCode: w.dataSourceCode ?? '',
|
||||
|
|
@ -444,15 +491,12 @@ const Wizard = () => {
|
|||
schedulerEndDateExpr: w.schedulerEndDateExpr ?? '',
|
||||
subForms: w.subForms ?? [],
|
||||
widgets: w.widgets ?? [],
|
||||
workflow: w.workflow ?? {
|
||||
approvalUserFieldName: '',
|
||||
isFilterUserName: false,
|
||||
approvalDateFieldName: '',
|
||||
approvalStatusFieldName: '',
|
||||
approvalDescriptionFieldName: '',
|
||||
criteria: [],
|
||||
},
|
||||
workflowCriteria: w.workflowCriteria ?? w.workflow?.criteria ?? [],
|
||||
approvalUserFieldName: w.approvalUserFieldName ?? '',
|
||||
approvalDateFieldName: w.approvalDateFieldName ?? '',
|
||||
approvalStatusFieldName: w.approvalStatusFieldName ?? '',
|
||||
approvalDescriptionFieldName: w.approvalDescriptionFieldName ?? '',
|
||||
approvalIsFilterUserName: w.approvalIsFilterUserName ?? false,
|
||||
criteria: w.criteria ?? [],
|
||||
})
|
||||
|
||||
// Queue column load to run once dbObjects is available
|
||||
|
|
@ -476,19 +520,19 @@ const Wizard = () => {
|
|||
caption: g.caption ?? '',
|
||||
colCount: g.colCount ?? 2,
|
||||
items: (g.items ?? []).map(
|
||||
(it: any, ii: number) =>
|
||||
(it: WizardGroupItem, ii: number) =>
|
||||
({
|
||||
id: `${it.dataField}_edit_${ii}_${Date.now()}`,
|
||||
dataField: it.dataField ?? '',
|
||||
id: `${it.fieldName}_edit_${ii}_${Date.now()}`,
|
||||
fieldName: it.fieldName ?? '',
|
||||
editorType: it.editorType ?? 'dxTextBox',
|
||||
editorOptions: it.editorOptions ?? '',
|
||||
editorScript: it.editorScript ?? '',
|
||||
colSpan: it.colSpan ?? 1,
|
||||
isRequired: it.isRequired ?? false,
|
||||
includeInEditingForm: it.includeInEditingForm ?? true,
|
||||
turkishCaption: it.turkishCaption ?? it.dataField,
|
||||
englishCaption: it.englishCaption ?? it.dataField,
|
||||
captionName: it.captionName ?? `App.Listform.ListformField.${it.dataField}`,
|
||||
turkishCaption: it.turkishCaption ?? it.fieldName,
|
||||
englishCaption: it.englishCaption ?? it.fieldName,
|
||||
captionName: it.captionName ?? `App.Listform.ListformField.${it.fieldName}`,
|
||||
lookupDataSourceType:
|
||||
(it.lookupDataSourceType as UiLookupDataSourceTypeEnum) ??
|
||||
UiLookupDataSourceTypeEnum.StaticData,
|
||||
|
|
@ -501,23 +545,21 @@ const Wizard = () => {
|
|||
setEditingGroups(restoredGroups)
|
||||
|
||||
// Restore selectedColumns from all group items
|
||||
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.fieldName)))
|
||||
setSelectedColumns(allFields)
|
||||
}
|
||||
|
||||
setSubForms(w.subForms ?? [])
|
||||
setWidgets(w.widgets ?? [])
|
||||
setWorkflow(
|
||||
w.workflow ?? {
|
||||
approvalUserFieldName: '',
|
||||
isFilterUserName: false,
|
||||
approvalDateFieldName: '',
|
||||
approvalStatusFieldName: '',
|
||||
approvalDescriptionFieldName: '',
|
||||
criteria: [],
|
||||
},
|
||||
)
|
||||
setWorkflowCriteria(w.workflowCriteria ?? w.workflow?.criteria ?? [])
|
||||
setWorkflow({
|
||||
approvalUserFieldName: w.approvalUserFieldName ?? '',
|
||||
approvalDateFieldName: w.approvalDateFieldName ?? '',
|
||||
approvalStatusFieldName: w.approvalStatusFieldName ?? '',
|
||||
approvalDescriptionFieldName: w.approvalDescriptionFieldName ?? '',
|
||||
approvalIsFilterUserName: w.approvalIsFilterUserName ?? false,
|
||||
criteria: w.criteria ?? [],
|
||||
})
|
||||
setCriteria(w.criteria ?? [])
|
||||
} catch {
|
||||
toast.push(
|
||||
<Notification type="danger">
|
||||
|
|
@ -619,8 +661,16 @@ const Wizard = () => {
|
|||
formikRef.current?.setFieldValue('menuParentCode', code)
|
||||
const selectedMenu = rawMenuItems.find((item) => item.code === code)
|
||||
formikRef.current?.setFieldValue('menuParentIcon', selectedMenu?.icon ?? '')
|
||||
if (!code) return
|
||||
applyPermissionGroupFromRoot(findRootCode(rawMenuItems, code))
|
||||
formikRef.current?.setFieldValue('languageTextMenuParentEn', selectedMenu?.menuTextEn ?? '')
|
||||
formikRef.current?.setFieldValue('languageTextMenuParentTr', selectedMenu?.menuTextTr ?? '')
|
||||
if (!code) {
|
||||
formikRef.current?.setFieldValue('menuParentShortName', '')
|
||||
return
|
||||
}
|
||||
const rootCode = findRootCode(rawMenuItems, code)
|
||||
const rootMenu = rawMenuItems.find((item) => item.code === rootCode)
|
||||
formikRef.current?.setFieldValue('menuParentShortName', rootMenu?.shortName ?? '')
|
||||
applyPermissionGroupFromRoot(rootCode)
|
||||
}
|
||||
|
||||
const handleMenuCreated = async (menu: {
|
||||
|
|
@ -629,6 +679,7 @@ const Wizard = () => {
|
|||
menuTextEn: string
|
||||
menuTextTr: string
|
||||
icon?: string
|
||||
shortName?: string
|
||||
}) => {
|
||||
formikRef.current?.setFieldValue('menuParentCode', menu.code)
|
||||
formikRef.current?.setFieldValue('menuParentIcon', menu.icon ?? '')
|
||||
|
|
@ -636,6 +687,11 @@ const Wizard = () => {
|
|||
formikRef.current?.setFieldValue('languageTextMenuParentTr', menu.menuTextTr)
|
||||
|
||||
const rootCode = menu.parentCode ? findRootCode(rawMenuItems, menu.parentCode) : menu.code
|
||||
const existingRoot = rawMenuItems.find((item) => item.code === rootCode)
|
||||
formikRef.current?.setFieldValue(
|
||||
'menuParentShortName',
|
||||
menu.parentCode ? (existingRoot?.shortName ?? '') : (menu.shortName ?? ''),
|
||||
)
|
||||
applyPermissionGroupFromRoot(rootCode)
|
||||
|
||||
await getMenuList()
|
||||
|
|
@ -707,10 +763,10 @@ const Wizard = () => {
|
|||
caption: g.caption,
|
||||
colCount: g.colCount,
|
||||
items: g.items.map((item) => {
|
||||
const col = selectCommandColumns.find((c) => c.columnName === item.dataField)
|
||||
const col = selectCommandColumns.find((c) => c.columnName === item.fieldName)
|
||||
|
||||
return {
|
||||
dataField: item.dataField,
|
||||
fieldName: item.fieldName,
|
||||
editorType: item.editorType,
|
||||
editorOptions: item.editorOptions ?? '',
|
||||
editorScript: item.editorScript ?? '',
|
||||
|
|
@ -730,11 +786,12 @@ const Wizard = () => {
|
|||
})),
|
||||
subForms,
|
||||
widgets,
|
||||
workflow: {
|
||||
...workflow,
|
||||
criteria: workflowCriteria,
|
||||
},
|
||||
workflowCriteria,
|
||||
approvalUserFieldName: workflow.approvalUserFieldName,
|
||||
approvalDateFieldName: workflow.approvalDateFieldName,
|
||||
approvalStatusFieldName: workflow.approvalStatusFieldName,
|
||||
approvalDescriptionFieldName: workflow.approvalDescriptionFieldName,
|
||||
approvalIsFilterUserName: workflow.approvalIsFilterUserName,
|
||||
criteria,
|
||||
})
|
||||
|
||||
// ✅ sonra config çek
|
||||
|
|
@ -780,6 +837,7 @@ const Wizard = () => {
|
|||
<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('::ListForms.ListFormEdit.TabTodo') || 'Todo / Kanban'} />
|
||||
<Steps.Item title={translate('::App.Platform.Deploy') || 'Deploy'} />
|
||||
</Steps>
|
||||
</div>
|
||||
|
|
@ -815,6 +873,7 @@ const Wizard = () => {
|
|||
onMenuParentChange={handleMenuParentChange}
|
||||
onClearMenuParent={() => {
|
||||
formikRef.current?.setFieldValue('menuParentCode', '')
|
||||
formikRef.current?.setFieldValue('menuParentShortName', '')
|
||||
formikRef.current?.setFieldValue('menuParentIcon', '')
|
||||
}}
|
||||
onMenuCreated={handleMenuCreated}
|
||||
|
|
@ -900,19 +959,30 @@ const Wizard = () => {
|
|||
<WizardStep6
|
||||
listFormCode={values.listFormCode}
|
||||
workflow={workflow}
|
||||
criteria={workflowCriteria}
|
||||
criteria={criteria}
|
||||
selectCommandColumns={selectCommandColumns}
|
||||
translate={translate}
|
||||
onWorkflowChange={setWorkflow}
|
||||
onCriteriaChange={setWorkflowCriteria}
|
||||
onCriteriaChange={setCriteria}
|
||||
onBack={() => setCurrentStep(4)}
|
||||
onNext={() => setCurrentStep(6)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* ─── Step 7: Deploy ───────────────────────────── */}
|
||||
{/* ─── Step 7: Todo / Kanban ────────────────────── */}
|
||||
{currentStep === 6 && (
|
||||
<WizardStep7
|
||||
selectedColumns={selectedColumns}
|
||||
selectCommandColumns={selectCommandColumns}
|
||||
translate={translate}
|
||||
onBack={() => setCurrentStep(5)}
|
||||
onNext={() => setCurrentStep(7)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* ─── Step 8: Deploy ───────────────────────────── */}
|
||||
{currentStep === 7 && (
|
||||
<WizardStep8
|
||||
values={values}
|
||||
wizardName={values.wizardName}
|
||||
selectedColumns={selectedColumns}
|
||||
|
|
@ -921,9 +991,9 @@ const Wizard = () => {
|
|||
subForms={subForms}
|
||||
widgets={widgets}
|
||||
workflow={workflow}
|
||||
workflowCriteria={workflowCriteria}
|
||||
criteria={criteria}
|
||||
translate={translate}
|
||||
onBack={() => setCurrentStep(5)}
|
||||
onBack={() => setCurrentStep(6)}
|
||||
onSubmit={handleDeploy}
|
||||
/>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import { ListFormWizardDto } from '@/proxy/admin/wizard/models'
|
|||
export interface MenuTreeNode {
|
||||
code: string
|
||||
displayName: string
|
||||
shortName?: string
|
||||
icon?: string
|
||||
url?: string
|
||||
order?: number
|
||||
|
|
@ -41,6 +42,7 @@ export function buildMenuTree(items: MenuItem[]): MenuTreeNode[] {
|
|||
map.set(item.code!, {
|
||||
code: item.code!,
|
||||
displayName: item.displayName ?? item.code!,
|
||||
shortName: item.shortName ?? undefined,
|
||||
icon: item.icon ?? undefined,
|
||||
url: item.url ?? undefined,
|
||||
order: item.order ?? undefined,
|
||||
|
|
|
|||
|
|
@ -516,6 +516,20 @@ const WizardStep2 = ({
|
|||
/>
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
label={translate('::ListForms.ListFormEdit.DetailsLayoutDto.CardLayout')}
|
||||
invalid={errors?.card && touched?.card}
|
||||
errorMessage={errors?.card}
|
||||
>
|
||||
<Field
|
||||
className="w-20"
|
||||
autoComplete="off"
|
||||
name="card"
|
||||
placeholder={translate('::ListForms.ListFormEdit.DetailsLayoutDto.CardLayout')}
|
||||
component={Checkbox}
|
||||
/>
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
label={translate('::ListForms.ListFormEdit.DetailsLayoutDto.PivotLayout')}
|
||||
invalid={errors?.pivot && touched?.pivot}
|
||||
|
|
@ -585,6 +599,20 @@ const WizardStep2 = ({
|
|||
component={Checkbox}
|
||||
/>
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
label={translate('::ListForms.ListFormEdit.DetailsLayoutDto.TodoLayout')}
|
||||
invalid={errors?.todo && touched?.todo}
|
||||
errorMessage={errors?.todo}
|
||||
>
|
||||
<Field
|
||||
className="w-20"
|
||||
autoComplete="off"
|
||||
name="todo"
|
||||
placeholder={translate('::ListForms.ListFormEdit.DetailsLayoutDto.TodoLayout')}
|
||||
component={Checkbox}
|
||||
/>
|
||||
</FormItem>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { Button, Dialog } from '@/components/ui'
|
||||
import type { SelectBoxOption } from '@/types/shared'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import {
|
||||
columnEditorTypeListOptions,
|
||||
|
|
@ -28,14 +29,17 @@ import {
|
|||
FaTrash,
|
||||
FaArrowRight,
|
||||
FaCode,
|
||||
FaSlidersH,
|
||||
} from 'react-icons/fa'
|
||||
import { UiLookupDataSourceTypeEnum } from '@/proxy/form/models'
|
||||
import EditorOptionsBuilderDialog from '../edit/json-row-operations/EditorOptionsBuilderDialog'
|
||||
import EditorScriptBuilderDialog from '../edit/json-row-operations/EditorScriptBuilderDialog'
|
||||
import { buildLookupQuery } from '../lookupQuery'
|
||||
|
||||
// ─── Types ────────────────────────────────────────────────────────────────────
|
||||
export interface WizardGroupItem {
|
||||
id: string
|
||||
dataField: string
|
||||
fieldName: string
|
||||
editorType: string
|
||||
editorOptions: string
|
||||
editorScript: string
|
||||
|
|
@ -109,7 +113,7 @@ function newGroupItem(colName: string, meta?: DatabaseColumnDto): WizardGroupIte
|
|||
const sqlType = meta?.dataType ?? ''
|
||||
return {
|
||||
id: `${colName}_${Date.now()}`,
|
||||
dataField: colName,
|
||||
fieldName: colName,
|
||||
editorType: inferEditorType(sqlType),
|
||||
editorOptions: '',
|
||||
editorScript: '',
|
||||
|
|
@ -169,6 +173,7 @@ interface SortableItemProps {
|
|||
groupColCount: number
|
||||
dbObjects: SqlObjectExplorerDto | null
|
||||
dsCode: string
|
||||
editorScriptFields: SelectBoxOption[]
|
||||
onTurkishCaptionChange: (val: string) => void
|
||||
onEnglishCaptionChange: (val: string) => void
|
||||
onEditorTypeChange: (val: string) => void
|
||||
|
|
@ -190,6 +195,7 @@ function SortableItem({
|
|||
groupColCount,
|
||||
dbObjects,
|
||||
dsCode,
|
||||
editorScriptFields,
|
||||
onTurkishCaptionChange,
|
||||
onEnglishCaptionChange,
|
||||
onEditorTypeChange,
|
||||
|
|
@ -207,6 +213,8 @@ function SortableItem({
|
|||
}: SortableItemProps) {
|
||||
const { translate } = useLocalization()
|
||||
const [isTablePickerOpen, setIsTablePickerOpen] = useState(false)
|
||||
const [isEditorOptionsDialogOpen, setIsEditorOptionsDialogOpen] = useState(false)
|
||||
const [isEditorScriptDialogOpen, setIsEditorScriptDialogOpen] = useState(false)
|
||||
const [tableSearch, setTableSearch] = useState('')
|
||||
const [pickerStep, setPickerStep] = useState<'table' | 'columns'>('table')
|
||||
const [pickerTable, setPickerTable] = useState<{ schemaName: string; tableName: string } | null>(
|
||||
|
|
@ -248,7 +256,7 @@ function SortableItem({
|
|||
tabIndex={-1}
|
||||
/>
|
||||
<span className="flex-1 text-xs font-semibold text-indigo-600 dark:text-indigo-400 truncate">
|
||||
{item.dataField}
|
||||
{item.fieldName}
|
||||
</span>
|
||||
<Button
|
||||
type="button"
|
||||
|
|
@ -564,12 +572,23 @@ function SortableItem({
|
|||
<span className="text-[10px] text-gray-400 font-medium">
|
||||
{translate('::ListForms.Wizard.Step3.EditorOptions')}
|
||||
</span>
|
||||
<input
|
||||
value={item.editorOptions}
|
||||
onChange={(e) => onEditorOptionsChange(e.target.value)}
|
||||
placeholder='{"readOnly": false}'
|
||||
className="w-full text-xs px-1.5 py-1 rounded border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-700 text-gray-700 dark:text-gray-200 focus:outline-none focus:border-indigo-400 resize-none font-mono"
|
||||
/>
|
||||
<div className="flex items-center gap-1">
|
||||
<input
|
||||
value={item.editorOptions}
|
||||
onChange={(e) => onEditorOptionsChange(e.target.value)}
|
||||
placeholder='{"readOnly": false}'
|
||||
className="min-w-0 flex-1 text-xs px-1.5 py-1 rounded border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-700 text-gray-700 dark:text-gray-200 focus:outline-none focus:border-indigo-400 resize-none font-mono"
|
||||
/>
|
||||
<Button
|
||||
shape="circle"
|
||||
variant="plain"
|
||||
type="button"
|
||||
size="sm"
|
||||
title="Build editor options"
|
||||
icon={<FaSlidersH />}
|
||||
onClick={() => setIsEditorOptionsDialogOpen(true)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Editor Script */}
|
||||
|
|
@ -577,14 +596,41 @@ function SortableItem({
|
|||
<span className="text-[10px] text-gray-400 font-medium">
|
||||
{translate('::ListForms.Wizard.Step3.EditorScript')}
|
||||
</span>
|
||||
<input
|
||||
value={item.editorScript}
|
||||
onChange={(e) => onEditorScriptChange(e.target.value)}
|
||||
placeholder="(e) => { /* e.component */ }"
|
||||
className="w-full text-xs px-1.5 py-1 rounded border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-700 text-gray-700 dark:text-gray-200 focus:outline-none focus:border-indigo-400 resize-none font-mono"
|
||||
/>
|
||||
<div className="flex items-center gap-1">
|
||||
<input
|
||||
value={item.editorScript}
|
||||
onChange={(e) => onEditorScriptChange(e.target.value)}
|
||||
placeholder="(e) => { /* e.component */ }"
|
||||
className="min-w-0 flex-1 text-xs px-1.5 py-1 rounded border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-700 text-gray-700 dark:text-gray-200 focus:outline-none focus:border-indigo-400 resize-none font-mono"
|
||||
/>
|
||||
<Button
|
||||
shape="circle"
|
||||
variant="plain"
|
||||
type="button"
|
||||
size="sm"
|
||||
title="Build editor script"
|
||||
icon={<FaCode />}
|
||||
onClick={() => setIsEditorScriptDialogOpen(true)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<EditorOptionsBuilderDialog
|
||||
isOpen={isEditorOptionsDialogOpen}
|
||||
value={item.editorOptions}
|
||||
editorType={item.editorType}
|
||||
onClose={() => setIsEditorOptionsDialogOpen(false)}
|
||||
onApply={onEditorOptionsChange}
|
||||
/>
|
||||
<EditorScriptBuilderDialog
|
||||
isOpen={isEditorScriptDialogOpen}
|
||||
value={item.editorScript}
|
||||
currentField={item.fieldName}
|
||||
fields={editorScriptFields}
|
||||
onClose={() => setIsEditorScriptDialogOpen(false)}
|
||||
onApply={onEditorScriptChange}
|
||||
/>
|
||||
|
||||
{/* Bottom row: ColSpan + Editing Form + Required */}
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex items-center gap-1">
|
||||
|
|
@ -639,6 +685,7 @@ interface GroupCardProps {
|
|||
hasAvailable: boolean
|
||||
dbObjects: SqlObjectExplorerDto | null
|
||||
dsCode: string
|
||||
editorScriptFields: SelectBoxOption[]
|
||||
onCaptionChange: (val: string) => void
|
||||
onColCountChange: (val: number) => void
|
||||
onItemChange: (itemId: string, patch: Partial<WizardGroupItem>) => void
|
||||
|
|
@ -653,6 +700,7 @@ function GroupCard({
|
|||
hasAvailable,
|
||||
dbObjects,
|
||||
dsCode,
|
||||
editorScriptFields,
|
||||
onCaptionChange,
|
||||
onColCountChange,
|
||||
onItemChange,
|
||||
|
|
@ -759,6 +807,7 @@ function GroupCard({
|
|||
groupColCount={group.colCount}
|
||||
dbObjects={dbObjects}
|
||||
dsCode={dsCode}
|
||||
editorScriptFields={editorScriptFields}
|
||||
onCaptionNameChange={(val) => onItemChange(item.id, { captionName: val })}
|
||||
onTurkishCaptionChange={(val) => onItemChange(item.id, { turkishCaption: val })}
|
||||
onEnglishCaptionChange={(val) => onItemChange(item.id, { englishCaption: val })}
|
||||
|
|
@ -809,7 +858,7 @@ const WizardStep3 = ({
|
|||
// 1. Remove items that are no longer in selectedColumns
|
||||
const cleaned = groups.map((g) => ({
|
||||
...g,
|
||||
items: g.items.filter((i) => selectedColumns.has(i.dataField)),
|
||||
items: g.items.filter((i) => selectedColumns.has(i.fieldName)),
|
||||
}))
|
||||
|
||||
// 2. Ensure at least one empty group exists for the user to drag into
|
||||
|
|
@ -835,8 +884,14 @@ const WizardStep3 = ({
|
|||
}, [selectedColumns])
|
||||
|
||||
// ── Available columns = selected but NOT yet placed ───────────────────────
|
||||
const placedColumns = new Set(groups.flatMap((g) => g.items.map((i) => i.dataField)))
|
||||
const placedColumns = new Set(groups.flatMap((g) => g.items.map((i) => i.fieldName)))
|
||||
const availableColumns = [...selectedColumns].filter((c) => !placedColumns.has(c))
|
||||
const editorScriptFields: SelectBoxOption[] = groups.flatMap((group) =>
|
||||
group.items.map((item) => ({
|
||||
value: item.fieldName,
|
||||
label: item.captionName || item.fieldName,
|
||||
})),
|
||||
)
|
||||
|
||||
// ── Helpers ───────────────────────────────────────────────────────────────
|
||||
const colMeta = (name: string) => selectCommandColumns.find((c) => c.columnName === name)
|
||||
|
|
@ -878,7 +933,7 @@ const WizardStep3 = ({
|
|||
}
|
||||
|
||||
const addAllToGroup = (groupId: string) => {
|
||||
const placed = new Set(groups.flatMap((g) => g.items.map((i) => i.dataField)))
|
||||
const placed = new Set(groups.flatMap((g) => g.items.map((i) => i.fieldName)))
|
||||
const toAdd = [...selectedColumns].filter((c) => !placed.has(c))
|
||||
if (toAdd.length === 0) return
|
||||
onGroupsChange(
|
||||
|
|
@ -1018,7 +1073,7 @@ const WizardStep3 = ({
|
|||
<div className="flex items-center gap-2 px-3 py-2 rounded-lg border border-indigo-400 bg-indigo-50 text-sm shadow-lg cursor-grabbing">
|
||||
<FaGripVertical className="text-indigo-300 text-xs" />
|
||||
<span className="text-xs font-semibold text-indigo-600 bg-indigo-100 px-2 py-0.5 rounded">
|
||||
{item.dataField}
|
||||
{item.fieldName}
|
||||
</span>
|
||||
<span className="text-xs text-gray-500">{item.editorType}</span>
|
||||
</div>
|
||||
|
|
@ -1087,6 +1142,7 @@ const WizardStep3 = ({
|
|||
hasAvailable={availableColumns.length > 0}
|
||||
dbObjects={dbObjects}
|
||||
dsCode={dsCode}
|
||||
editorScriptFields={editorScriptFields}
|
||||
onCaptionChange={(val) => updateGroup(group.id, { caption: val })}
|
||||
onColCountChange={(val) => updateGroup(group.id, { colCount: val })}
|
||||
onItemChange={(itemId, patch) => updateItem(group.id, itemId, patch)}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ type PendingLink = {
|
|||
outcome: string
|
||||
} | null
|
||||
|
||||
type RequiredWorkflowField = 'approvalUserFieldName' | 'approvalStatusFieldName'
|
||||
|
||||
const toDesignerCriteria = (items: ListFormWorkflowCriteriaDto[]): WorkflowCriteriaDto[] =>
|
||||
items.map((item) => ({
|
||||
...item,
|
||||
|
|
@ -67,6 +69,9 @@ function WizardStep6({
|
|||
const [dragPreview, setDragPreview] = useState<any>(null)
|
||||
const [canvasZoom, setCanvasZoom] = useState(1)
|
||||
const [designerTab, setDesignerTab] = useState('flow')
|
||||
const [workflowErrors, setWorkflowErrors] = useState<
|
||||
Partial<Record<RequiredWorkflowField, string>>
|
||||
>({})
|
||||
const canvasRef = useRef<HTMLDivElement | null>(null)
|
||||
|
||||
const currentCriteria = useMemo(() => toDesignerCriteria(criteria), [criteria])
|
||||
|
|
@ -91,6 +96,10 @@ function WizardStep6({
|
|||
setCriteriaForm(selected ? toCriteriaForm(selected) : emptyCriteria('Start', listFormCode))
|
||||
}, [currentCriteria, listFormCode, selectedId])
|
||||
|
||||
useEffect(() => {
|
||||
if (criteria.length === 0) setWorkflowErrors({})
|
||||
}, [criteria.length])
|
||||
|
||||
const updateCriteria = (next: WorkflowCriteriaDto[]) => onCriteriaChange(toWizardCriteria(next))
|
||||
|
||||
const saveCriteria = (event: FormEvent<HTMLFormElement>) => {
|
||||
|
|
@ -250,6 +259,26 @@ function WizardStep6({
|
|||
])
|
||||
}
|
||||
|
||||
const continueToTodo = () => {
|
||||
if (criteria.length === 0) {
|
||||
setWorkflowErrors({})
|
||||
onNext()
|
||||
return
|
||||
}
|
||||
|
||||
const requiredMessage = translate('::ListForms.Wizard.Required')
|
||||
const nextErrors: Partial<Record<RequiredWorkflowField, string>> = {}
|
||||
if (!workflow.approvalUserFieldName?.trim()) {
|
||||
nextErrors.approvalUserFieldName = requiredMessage
|
||||
}
|
||||
if (!workflow.approvalStatusFieldName?.trim()) {
|
||||
nextErrors.approvalStatusFieldName = requiredMessage
|
||||
}
|
||||
|
||||
setWorkflowErrors(nextErrors)
|
||||
if (Object.keys(nextErrors).length === 0) onNext()
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex h-[calc(100vh-250px)] min-h-[500px] flex-col overflow-hidden">
|
||||
<div className="flex-1 overflow-y-auto pr-1">
|
||||
|
|
@ -280,44 +309,62 @@ function WizardStep6({
|
|||
'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>
|
||||
))}
|
||||
].map(([name, label]) => {
|
||||
const requiredForCriteria =
|
||||
criteria.length > 0 &&
|
||||
(name === 'approvalUserFieldName' || name === 'approvalStatusFieldName')
|
||||
const error = workflowErrors[name as RequiredWorkflowField]
|
||||
|
||||
return (
|
||||
<FormItem
|
||||
key={name}
|
||||
errorMessage={error}
|
||||
invalid={Boolean(error)}
|
||||
label={`${translate(label)}${requiredForCriteria ? ' *' : ''}`}
|
||||
>
|
||||
<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 ?? '')
|
||||
setWorkflowErrors((current) => ({
|
||||
...current,
|
||||
[field.name]: undefined,
|
||||
}))
|
||||
onWorkflowChange({
|
||||
...values,
|
||||
[field.name]: option?.value ?? '',
|
||||
criteria,
|
||||
})
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</FormItem>
|
||||
)
|
||||
})}
|
||||
<FormItem
|
||||
label={translate('::ListForms.ListFormEdit.Workflow.IsFilterUserName')}
|
||||
label={translate(
|
||||
'::ListForms.ListFormEdit.Workflow.ApprovalIsFilterUserName',
|
||||
)}
|
||||
>
|
||||
<Field name="isFilterUserName">
|
||||
<Field name="approvalIsFilterUserName">
|
||||
{({ field, form }: FieldProps<boolean>) => (
|
||||
<Checkbox
|
||||
name={field.name}
|
||||
checked={Boolean(values.isFilterUserName)}
|
||||
checked={Boolean(values.approvalIsFilterUserName)}
|
||||
onChange={(checked) => {
|
||||
form.setFieldValue(field.name, checked)
|
||||
onWorkflowChange({
|
||||
...values,
|
||||
isFilterUserName: checked,
|
||||
approvalIsFilterUserName: checked,
|
||||
criteria,
|
||||
})
|
||||
}}
|
||||
|
|
@ -402,7 +449,7 @@ function WizardStep6({
|
|||
variant="solid"
|
||||
type="button"
|
||||
icon={<FaArrowRight />}
|
||||
onClick={onNext}
|
||||
onClick={continueToTodo}
|
||||
>
|
||||
{translate('::Next') || 'Next'}
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -1,714 +1,169 @@
|
|||
import { Button } from '@/components/ui'
|
||||
import { Button, Checkbox, FormItem, Input, Select } from '@/components/ui'
|
||||
import type { ListFormWizardDto } from '@/proxy/admin/wizard/models'
|
||||
import type { DatabaseColumnDto } from '@/proxy/sql-query-manager/models'
|
||||
import React, { 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'
|
||||
import { formatWorkflowApprovers } from '@/utils/workflow/workflowHelpers'
|
||||
import type { SelectBoxOption } from '@/types/shared'
|
||||
import { Field, type FieldProps, useFormikContext } from 'formik'
|
||||
import { useMemo, useState } from 'react'
|
||||
import { FaArrowLeft, FaArrowRight } from 'react-icons/fa'
|
||||
|
||||
// ─── Types ────────────────────────────────────────────────────────────────────
|
||||
|
||||
export interface WizardStep7Props {
|
||||
values: ListFormWizardDto
|
||||
wizardName: string
|
||||
interface WizardStep7Props {
|
||||
selectedColumns: Set<string>
|
||||
selectCommandColumns: DatabaseColumnDto[]
|
||||
groups: WizardGroup[]
|
||||
subForms: SubFormDto[]
|
||||
widgets: WidgetEditDto[]
|
||||
workflow: WorkflowDto
|
||||
workflowCriteria: ListFormWorkflowCriteriaDto[]
|
||||
translate: (key: string) => string
|
||||
onBack: () => void
|
||||
onSubmit: () => Promise<void>
|
||||
onNext: () => void
|
||||
}
|
||||
|
||||
type LogStatus = 'pending' | 'running' | 'success' | 'error'
|
||||
const mappings: Array<{
|
||||
name:
|
||||
| 'todoTitleExpr'
|
||||
| 'todoStatusExpr'
|
||||
| 'todoDescriptionExpr'
|
||||
| 'todoDueDateExpr'
|
||||
| 'todoTagExpr'
|
||||
| 'todoAssigneeExpr'
|
||||
| 'todoPriorityExpr'
|
||||
| 'todoCompletedExpr'
|
||||
| 'todoOrderExpr'
|
||||
translationKey: string
|
||||
required?: boolean
|
||||
}> = [
|
||||
{
|
||||
name: 'todoTitleExpr',
|
||||
translationKey: '::ListForms.ListFormFieldEdit.TodoTitleExpr',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'todoStatusExpr',
|
||||
translationKey: '::ListForms.ListFormFieldEdit.TodoStatusExpr',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'todoDescriptionExpr',
|
||||
translationKey: '::ListForms.ListFormFieldEdit.TodoDescriptionExpr',
|
||||
},
|
||||
{
|
||||
name: 'todoDueDateExpr',
|
||||
translationKey: '::ListForms.ListFormFieldEdit.TodoDueDateExpr',
|
||||
},
|
||||
{ name: 'todoTagExpr', translationKey: '::ListForms.ListFormFieldEdit.TodoTagExpr' },
|
||||
{
|
||||
name: 'todoAssigneeExpr',
|
||||
translationKey: '::ListForms.ListFormFieldEdit.TodoAssigneeExpr',
|
||||
},
|
||||
{
|
||||
name: 'todoPriorityExpr',
|
||||
translationKey: '::ListForms.ListFormFieldEdit.TodoPriorityExpr',
|
||||
},
|
||||
{
|
||||
name: 'todoCompletedExpr',
|
||||
translationKey: '::ListForms.ListFormFieldEdit.TodoCompletedExpr',
|
||||
},
|
||||
{ name: 'todoOrderExpr', translationKey: '::ListForms.ListFormFieldEdit.TodoOrderExpr' },
|
||||
]
|
||||
|
||||
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)}
|
||||
variant="plain"
|
||||
shape="none"
|
||||
className="w-full !h-auto !items-center !justify-between !rounded-none !bg-gray-50 !px-4 !py-2.5 transition-colors hover:!bg-gray-100 dark:!bg-gray-800 dark:hover:!bg-gray-700"
|
||||
>
|
||||
<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,
|
||||
onNext,
|
||||
}: WizardStep7Props) => {
|
||||
const [logs, setLogs] = useState<LogEntry[]>([])
|
||||
const [isDeploying, setIsDeploying] = useState(false)
|
||||
const [isDone, setIsDone] = useState(false)
|
||||
const [hasError, setHasError] = useState(false)
|
||||
const { errors, touched, values, setFieldTouched, setFieldValue, validateForm } =
|
||||
useFormikContext<ListFormWizardDto>()
|
||||
const [validationError, setValidationError] = useState('')
|
||||
const fieldOptions = useMemo<SelectBoxOption[]>(
|
||||
() =>
|
||||
selectCommandColumns
|
||||
.filter((column) => selectedColumns.has(column.columnName))
|
||||
.map((column) => ({ value: column.columnName, label: column.columnName })),
|
||||
[selectCommandColumns, selectedColumns],
|
||||
)
|
||||
|
||||
const steps = buildLogSteps(values, groups, translate)
|
||||
const continueToDeploy = async () => {
|
||||
await Promise.all([
|
||||
setFieldTouched('todoTitleExpr', true, false),
|
||||
setFieldTouched('todoStatusExpr', true, false),
|
||||
])
|
||||
const validationErrors = await validateForm()
|
||||
|
||||
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)
|
||||
if (validationErrors.todoTitleExpr || validationErrors.todoStatusExpr) {
|
||||
setValidationError(translate('::ListForms.ListFormFieldEdit.TodoRequiredFields'))
|
||||
return
|
||||
}
|
||||
setValidationError('')
|
||||
onNext()
|
||||
}
|
||||
|
||||
const totalFields = groups.reduce((acc, g) => acc + g.items.length, 0)
|
||||
const editingFormFields = groups.flatMap((g) =>
|
||||
g.items
|
||||
.filter((item) => item.includeInEditingForm && item.dataField !== values.keyFieldName)
|
||||
.map((item) => ({ ...item, groupCaption: g.caption })),
|
||||
)
|
||||
const groupedFieldNames = new Set(groups.flatMap((g) => g.items.map((item) => item.dataField)))
|
||||
const ungroupedSelectedColumns = [...selectedColumns].filter((col) => !groupedFieldNames.has(col))
|
||||
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>
|
||||
<div className="pb-20">
|
||||
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3">
|
||||
{mappings.map((mapping) => {
|
||||
const isRequired = Boolean(mapping.required && values.todo)
|
||||
|
||||
<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.SelectCommand')}
|
||||
value={`${values.selectCommand} (${
|
||||
selectCommandTypeOptions.find((o: any) => o.value === values.selectCommandType)
|
||||
?.label ?? String(values.selectCommandType)
|
||||
})`}
|
||||
/>
|
||||
<Row
|
||||
label={translate('::ListForms.Wizard.Step4.KeyField')}
|
||||
value={`${values.keyFieldName} (${
|
||||
dbSourceTypeOptions.find((o: any) => o.value === values.keyFieldDbSourceType)
|
||||
?.label ?? String(values.keyFieldDbSourceType)
|
||||
})`}
|
||||
/>
|
||||
</Section>
|
||||
</div>
|
||||
|
||||
<Section
|
||||
title={
|
||||
translate('::ListForms.Wizard.Step4.ColumnsAndFormLayout') || 'Columns & Form Layout'
|
||||
}
|
||||
badge={`${selectedColumns.size} ${translate('::App.Listform.ListformField.Column')} / ${editingFormFields.length} ${translate('::ListForms.Wizard.Step4.EditingForm') || 'Popup Form'}`}
|
||||
>
|
||||
<div className="mb-3 grid grid-cols-3 gap-2">
|
||||
{[
|
||||
{
|
||||
label: translate('::ListForms.Wizard.Step4.SelectedColumns'),
|
||||
value: selectedColumns.size,
|
||||
className: 'text-indigo-600 dark:text-indigo-400',
|
||||
},
|
||||
{
|
||||
label: translate('::ListForms.Wizard.Step4.EditingForm') || 'Popup Form',
|
||||
value: editingFormFields.length,
|
||||
className: 'text-emerald-600 dark:text-emerald-400',
|
||||
},
|
||||
{
|
||||
label: translate('::ListForms.Wizard.Step4.FormGroups'),
|
||||
value: groups.length,
|
||||
className: 'text-gray-700 dark:text-gray-200',
|
||||
},
|
||||
].map((item) => (
|
||||
<div
|
||||
key={item.label}
|
||||
className="rounded-lg border border-gray-100 dark:border-gray-800 bg-gray-50 dark:bg-gray-800 px-3 py-2"
|
||||
>
|
||||
<div className={`text-lg font-semibold leading-none ${item.className}`}>
|
||||
{item.value}
|
||||
</div>
|
||||
<div className="mt-1 text-[11px] text-gray-400 truncate">{item.label}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
{groups.map((g) => (
|
||||
<div
|
||||
key={g.id}
|
||||
className="overflow-hidden rounded-lg border border-gray-100 dark:border-gray-800"
|
||||
>
|
||||
<div className="flex items-center justify-between gap-3 bg-gray-50 dark:bg-gray-800 px-3 py-2">
|
||||
<span className="text-xs font-semibold text-gray-700 dark:text-gray-200 truncate">
|
||||
{g.caption || `(${translate('::ListForms.Wizard.Step4.StatGroup')})`}
|
||||
</span>
|
||||
<div className="flex items-center gap-1.5 text-[10px] text-gray-400 shrink-0">
|
||||
<span className="rounded bg-white dark:bg-gray-900 px-1.5 py-0.5">
|
||||
{g.items.length} {translate('::ListForms.Wizard.Step4.StatField')}
|
||||
</span>
|
||||
<span className="rounded bg-white dark:bg-gray-900 px-1.5 py-0.5">
|
||||
{g.colCount} {translate('::App.Listform.ListformField.Column')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="divide-y divide-gray-100 dark:divide-gray-800">
|
||||
{g.items.length === 0 ? (
|
||||
<span className="block px-3 py-2 text-xs text-gray-300 italic">
|
||||
{translate('::ListForms.Wizard.Step4.NoFields') || 'Alan yok'}
|
||||
</span>
|
||||
) : (
|
||||
g.items.map((item) => {
|
||||
const meta = selectCommandColumns.find((c) => c.columnName === item.dataField)
|
||||
const isKeyField = item.dataField === values.keyFieldName
|
||||
const isPopupField = item.includeInEditingForm && !isKeyField
|
||||
return (
|
||||
<div
|
||||
key={item.id}
|
||||
className="grid grid-cols-[minmax(150px,1fr)_auto] items-center gap-3 px-3 py-1.5"
|
||||
>
|
||||
<div className="flex min-w-0 items-center gap-2">
|
||||
<span className="text-xs font-medium text-indigo-600 dark:text-indigo-400 truncate">
|
||||
{item.dataField}
|
||||
</span>
|
||||
{meta?.dataType && (
|
||||
<span className="text-[10px] text-gray-400 truncate">
|
||||
{meta.dataType}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-wrap justify-end gap-1">
|
||||
<span className="rounded bg-indigo-50 dark:bg-indigo-900/30 px-1.5 py-0.5 text-[10px] text-indigo-600 dark:text-indigo-300">
|
||||
{translate('::ListForms.Wizard.Step4.SelectedColumns') || 'List'}
|
||||
</span>
|
||||
{isPopupField && (
|
||||
<span className="rounded bg-emerald-50 dark:bg-emerald-900/30 px-1.5 py-0.5 text-[10px] text-emerald-600 dark:text-emerald-300">
|
||||
{translate('::ListForms.Wizard.Step4.EditingForm') || 'Popup Form'}
|
||||
</span>
|
||||
)}
|
||||
{isKeyField && (
|
||||
<span className="rounded bg-amber-50 dark:bg-amber-900/30 px-1.5 py-0.5 text-[10px] text-amber-600 dark:text-amber-300">
|
||||
{translate('::ListForms.Wizard.Step4.KeyField')}
|
||||
</span>
|
||||
)}
|
||||
<span className="rounded bg-gray-100 dark:bg-gray-800 px-1.5 py-0.5 text-[10px] text-gray-400">
|
||||
{item.editorType}
|
||||
</span>
|
||||
<span className="rounded bg-gray-100 dark:bg-gray-800 px-1.5 py-0.5 text-[10px] text-gray-400">
|
||||
span-{item.colSpan}
|
||||
{item.isRequired && <span className="ml-1 text-red-400">*</span>}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
{ungroupedSelectedColumns.length > 0 && (
|
||||
<div className="rounded-lg border border-amber-100 dark:border-amber-900/40 bg-amber-50/50 dark:bg-amber-900/10 px-3 py-2">
|
||||
<div className="mb-1.5 text-xs font-semibold text-amber-700 dark:text-amber-300">
|
||||
{translate('::ListForms.Wizard.Step4.UngroupedColumns') || 'Ungrouped columns'}
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-1.5">
|
||||
{ungroupedSelectedColumns.map((col) => {
|
||||
const meta = selectCommandColumns.find((c) => c.columnName === col)
|
||||
return (
|
||||
<span
|
||||
key={col}
|
||||
className="inline-flex items-center gap-1 rounded-full border border-amber-200 dark:border-amber-800 bg-white dark:bg-gray-900 px-2 py-0.5 text-xs text-amber-700 dark:text-amber-300"
|
||||
>
|
||||
{col}
|
||||
{meta?.dataType && (
|
||||
<span className="text-[10px] text-amber-500 opacity-70">
|
||||
{meta.dataType}
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</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} />
|
||||
<Row
|
||||
label="Is Filter User Name?"
|
||||
value={workflow.isFilterUserName === true ? 'Yes' : 'No'}
|
||||
/>
|
||||
</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>
|
||||
{criteria.kind === 'Compare' && (
|
||||
<div className="mt-1 text-[11px] text-gray-500 dark:text-gray-400">
|
||||
{criteria.compareColumn} {criteria.compareOperator}{' '}
|
||||
{criteria.compareValue}
|
||||
</div>
|
||||
)}
|
||||
{(criteria.kind === 'Approval' || criteria.kind === 'Inform') &&
|
||||
criteria.approver && (
|
||||
<div className="text-[11px] text-gray-500 dark:text-gray-400">
|
||||
Approver: {formatWorkflowApprovers(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-7 gap-2">
|
||||
{[
|
||||
{ label: translate('::ListForms.Wizard.Step4.StatGroup'), value: groups.length },
|
||||
{ label: translate('::ListForms.Wizard.Step4.StatField'), value: totalFields },
|
||||
{
|
||||
label: translate('::ListForms.Wizard.Step4.EditingForm') || 'Popup Form',
|
||||
value: editingFormFields.length,
|
||||
},
|
||||
{
|
||||
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"
|
||||
return (
|
||||
<FormItem
|
||||
key={mapping.name}
|
||||
label={`${translate(mapping.translationKey)}${isRequired ? ' *' : ''}`}
|
||||
invalid={Boolean(touched[mapping.name] && errors[mapping.name])}
|
||||
errorMessage={touched[mapping.name] ? errors[mapping.name] : undefined}
|
||||
>
|
||||
<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>
|
||||
<Field name={mapping.name}>
|
||||
{({ field, form }: FieldProps) => (
|
||||
<Select
|
||||
field={field}
|
||||
form={form}
|
||||
isClearable={!isRequired}
|
||||
options={fieldOptions}
|
||||
value={fieldOptions.find((option) => option.value === values[mapping.name])}
|
||||
onChange={(option) => {
|
||||
form.setFieldValue(field.name, option?.value ?? '')
|
||||
setValidationError('')
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Field>
|
||||
</FormItem>
|
||||
)
|
||||
})}
|
||||
</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">
|
||||
<div className="mt-5 grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<FormItem label={translate('::ListForms.ListFormFieldEdit.TodoStatusOrder')}>
|
||||
<Field
|
||||
name="todoStatusOrder"
|
||||
component={Input}
|
||||
placeholder={translate('::ListForms.ListFormFieldEdit.TodoStatusOrderPlaceholder')}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label={translate('::ListForms.ListFormFieldEdit.TodoAllowDragging')}>
|
||||
<Field name="todoAllowDragging">
|
||||
{({ field }: FieldProps<boolean>) => (
|
||||
<Checkbox
|
||||
checked={Boolean(field.value)}
|
||||
onChange={(checked) => setFieldValue(field.name, checked)}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</FormItem>
|
||||
</div>
|
||||
|
||||
{validationError && <p className="mt-4 text-sm text-red-500">{validationError}</p>}
|
||||
|
||||
<div className="fixed bottom-0 left-0 right-0 z-10 flex h-16 items-center border-t border-gray-200 bg-white px-6 dark:border-gray-700 dark:bg-gray-900">
|
||||
<div className="flex w-full items-center justify-between gap-3">
|
||||
<Button size="sm" variant="default" type="button" icon={<FaArrowLeft />} onClick={onBack}>
|
||||
{translate('::Back')}
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="default"
|
||||
variant="solid"
|
||||
type="button"
|
||||
icon={<FaArrowLeft />}
|
||||
onClick={onBack}
|
||||
disabled={isDeploying}
|
||||
icon={<FaArrowRight />}
|
||||
onClick={continueToDeploy}
|
||||
>
|
||||
{translate('::Back') || 'Back'}
|
||||
{translate('::Next')}
|
||||
</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>
|
||||
|
|
|
|||
777
ui/src/views/admin/listForm/wizard/WizardStep8.tsx
Normal file
777
ui/src/views/admin/listForm/wizard/WizardStep8.tsx
Normal file
|
|
@ -0,0 +1,777 @@
|
|||
import { Button } from '@/components/ui'
|
||||
import type { DatabaseColumnDto } from '@/proxy/sql-query-manager/models'
|
||||
import React, { 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'
|
||||
import { formatWorkflowApprovers } from '@/utils/workflow/workflowHelpers'
|
||||
|
||||
// ─── Types ────────────────────────────────────────────────────────────────────
|
||||
|
||||
export interface WizardStep8Props {
|
||||
values: ListFormWizardDto
|
||||
wizardName: string
|
||||
selectedColumns: Set<string>
|
||||
selectCommandColumns: DatabaseColumnDto[]
|
||||
groups: WizardGroup[]
|
||||
subForms: SubFormDto[]
|
||||
widgets: WidgetEditDto[]
|
||||
workflow: WorkflowDto
|
||||
criteria: 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"
|
||||
variant="plain"
|
||||
shape="none"
|
||||
className="w-full !h-auto !items-center !justify-between !rounded-none !bg-gray-50 !px-4 !py-2.5 transition-colors hover:!bg-gray-100 dark:!bg-gray-800 dark:hover:!bg-gray-700"
|
||||
onClick={() => setOpen((v) => !v)}
|
||||
>
|
||||
<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>
|
||||
)
|
||||
}
|
||||
|
||||
// ─── WizardStep8 ──────────────────────────────────────────────────────────────
|
||||
const WizardStep8 = ({
|
||||
values,
|
||||
wizardName,
|
||||
selectedColumns,
|
||||
selectCommandColumns,
|
||||
groups,
|
||||
subForms,
|
||||
widgets,
|
||||
workflow,
|
||||
criteria,
|
||||
translate,
|
||||
onBack,
|
||||
onSubmit,
|
||||
}: WizardStep8Props) => {
|
||||
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: `${translate('::ListForms.Wizard.Step4.Error')}: ${
|
||||
err?.message ?? translate('::App.Platform.Unknown')
|
||||
}`,
|
||||
status: 'error',
|
||||
},
|
||||
])
|
||||
setHasError(true)
|
||||
} finally {
|
||||
setIsDeploying(false)
|
||||
}
|
||||
}
|
||||
|
||||
const totalFields = groups.reduce((acc, g) => acc + g.items.length, 0)
|
||||
const editingFormFields = groups.flatMap((g) =>
|
||||
g.items
|
||||
.filter((item) => item.includeInEditingForm && item.fieldName !== values.keyFieldName)
|
||||
.map((item) => ({ ...item, groupCaption: g.caption })),
|
||||
)
|
||||
const groupedFieldNames = new Set(groups.flatMap((g) => g.items.map((item) => item.fieldName)))
|
||||
const ungroupedSelectedColumns = [...selectedColumns].filter((col) => !groupedFieldNames.has(col))
|
||||
const hasWorkflowFields = Boolean(
|
||||
workflow.approvalUserFieldName ||
|
||||
workflow.approvalDateFieldName ||
|
||||
workflow.approvalStatusFieldName ||
|
||||
workflow.approvalDescriptionFieldName,
|
||||
)
|
||||
const workflowItems = criteria.length > 0 ? criteria : (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.SelectCommand')}
|
||||
value={`${values.selectCommand} (${
|
||||
selectCommandTypeOptions.find((o: any) => o.value === values.selectCommandType)
|
||||
?.label ?? String(values.selectCommandType)
|
||||
})`}
|
||||
/>
|
||||
<Row
|
||||
label={translate('::ListForms.Wizard.Step4.KeyField')}
|
||||
value={`${values.keyFieldName} (${
|
||||
dbSourceTypeOptions.find((o: any) => o.value === values.keyFieldDbSourceType)
|
||||
?.label ?? String(values.keyFieldDbSourceType)
|
||||
})`}
|
||||
/>
|
||||
</Section>
|
||||
</div>
|
||||
|
||||
<Section
|
||||
title={
|
||||
translate('::ListForms.Wizard.Step4.ColumnsAndFormLayout') || 'Columns & Form Layout'
|
||||
}
|
||||
badge={`${selectedColumns.size} ${translate('::App.Listform.ListformField.Column')} / ${editingFormFields.length} ${translate('::ListForms.Wizard.Step4.EditingForm') || 'Popup Form'}`}
|
||||
>
|
||||
<div className="mb-3 grid grid-cols-3 gap-2">
|
||||
{[
|
||||
{
|
||||
label: translate('::ListForms.Wizard.Step4.SelectedColumns'),
|
||||
value: selectedColumns.size,
|
||||
className: 'text-indigo-600 dark:text-indigo-400',
|
||||
},
|
||||
{
|
||||
label: translate('::ListForms.Wizard.Step4.EditingForm') || 'Popup Form',
|
||||
value: editingFormFields.length,
|
||||
className: 'text-emerald-600 dark:text-emerald-400',
|
||||
},
|
||||
{
|
||||
label: translate('::ListForms.Wizard.Step4.FormGroups'),
|
||||
value: groups.length,
|
||||
className: 'text-gray-700 dark:text-gray-200',
|
||||
},
|
||||
].map((item) => (
|
||||
<div
|
||||
key={item.label}
|
||||
className="rounded-lg border border-gray-100 dark:border-gray-800 bg-gray-50 dark:bg-gray-800 px-3 py-2"
|
||||
>
|
||||
<div className={`text-lg font-semibold leading-none ${item.className}`}>
|
||||
{item.value}
|
||||
</div>
|
||||
<div className="mt-1 text-[11px] text-gray-400 truncate">{item.label}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
{groups.map((g) => (
|
||||
<div
|
||||
key={g.id}
|
||||
className="overflow-hidden rounded-lg border border-gray-100 dark:border-gray-800"
|
||||
>
|
||||
<div className="flex items-center justify-between gap-3 bg-gray-50 dark:bg-gray-800 px-3 py-2">
|
||||
<span className="text-xs font-semibold text-gray-700 dark:text-gray-200 truncate">
|
||||
{g.caption || `(${translate('::ListForms.Wizard.Step4.StatGroup')})`}
|
||||
</span>
|
||||
<div className="flex items-center gap-1.5 text-[10px] text-gray-400 shrink-0">
|
||||
<span className="rounded bg-white dark:bg-gray-900 px-1.5 py-0.5">
|
||||
{g.items.length} {translate('::ListForms.Wizard.Step4.StatField')}
|
||||
</span>
|
||||
<span className="rounded bg-white dark:bg-gray-900 px-1.5 py-0.5">
|
||||
{g.colCount} {translate('::App.Listform.ListformField.Column')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="divide-y divide-gray-100 dark:divide-gray-800">
|
||||
{g.items.length === 0 ? (
|
||||
<span className="block px-3 py-2 text-xs text-gray-300 italic">
|
||||
{translate('::ListForms.Wizard.Step4.NoFields') || 'Alan yok'}
|
||||
</span>
|
||||
) : (
|
||||
g.items.map((item) => {
|
||||
const meta = selectCommandColumns.find((c) => c.columnName === item.fieldName)
|
||||
const isKeyField = item.fieldName === values.keyFieldName
|
||||
const isPopupField = item.includeInEditingForm && !isKeyField
|
||||
return (
|
||||
<div
|
||||
key={item.id}
|
||||
className="grid grid-cols-[minmax(150px,1fr)_auto] items-center gap-3 px-3 py-1.5"
|
||||
>
|
||||
<div className="flex min-w-0 items-center gap-2">
|
||||
<span className="text-xs font-medium text-indigo-600 dark:text-indigo-400 truncate">
|
||||
{item.fieldName}
|
||||
</span>
|
||||
{meta?.dataType && (
|
||||
<span className="text-[10px] text-gray-400 truncate">
|
||||
{meta.dataType}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-wrap justify-end gap-1">
|
||||
<span className="rounded bg-indigo-50 dark:bg-indigo-900/30 px-1.5 py-0.5 text-[10px] text-indigo-600 dark:text-indigo-300">
|
||||
{translate('::ListForms.Wizard.Step4.SelectedColumns') || 'List'}
|
||||
</span>
|
||||
{isPopupField && (
|
||||
<span className="rounded bg-emerald-50 dark:bg-emerald-900/30 px-1.5 py-0.5 text-[10px] text-emerald-600 dark:text-emerald-300">
|
||||
{translate('::ListForms.Wizard.Step4.EditingForm') || 'Popup Form'}
|
||||
</span>
|
||||
)}
|
||||
{isKeyField && (
|
||||
<span className="rounded bg-amber-50 dark:bg-amber-900/30 px-1.5 py-0.5 text-[10px] text-amber-600 dark:text-amber-300">
|
||||
{translate('::ListForms.Wizard.Step4.KeyField')}
|
||||
</span>
|
||||
)}
|
||||
<span className="rounded bg-gray-100 dark:bg-gray-800 px-1.5 py-0.5 text-[10px] text-gray-400">
|
||||
{item.editorType}
|
||||
</span>
|
||||
<span className="rounded bg-gray-100 dark:bg-gray-800 px-1.5 py-0.5 text-[10px] text-gray-400">
|
||||
span-{item.colSpan}
|
||||
{item.isRequired && <span className="ml-1 text-red-400">*</span>}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
{ungroupedSelectedColumns.length > 0 && (
|
||||
<div className="rounded-lg border border-amber-100 dark:border-amber-900/40 bg-amber-50/50 dark:bg-amber-900/10 px-3 py-2">
|
||||
<div className="mb-1.5 text-xs font-semibold text-amber-700 dark:text-amber-300">
|
||||
{translate('::ListForms.Wizard.Step4.UngroupedColumns') || 'Ungrouped columns'}
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-1.5">
|
||||
{ungroupedSelectedColumns.map((col) => {
|
||||
const meta = selectCommandColumns.find((c) => c.columnName === col)
|
||||
return (
|
||||
<span
|
||||
key={col}
|
||||
className="inline-flex items-center gap-1 rounded-full border border-amber-200 dark:border-amber-800 bg-white dark:bg-gray-900 px-2 py-0.5 text-xs text-amber-700 dark:text-amber-300"
|
||||
>
|
||||
{col}
|
||||
{meta?.dataType && (
|
||||
<span className="text-[10px] text-amber-500 opacity-70">
|
||||
{meta.dataType}
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</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} />
|
||||
<Row
|
||||
label="Is Filter User Name?"
|
||||
value={workflow.approvalIsFilterUserName === true ? 'Yes' : 'No'}
|
||||
/>
|
||||
</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>
|
||||
{criteria.kind === 'Compare' && (
|
||||
<div className="mt-1 text-[11px] text-gray-500 dark:text-gray-400">
|
||||
{criteria.compareColumn} {criteria.compareOperator}{' '}
|
||||
{criteria.compareValue}
|
||||
</div>
|
||||
)}
|
||||
{(criteria.kind === 'Approval' || criteria.kind === 'Inform') &&
|
||||
criteria.approver && (
|
||||
<div className="text-[11px] text-gray-500 dark:text-gray-400">
|
||||
Approver: {formatWorkflowApprovers(criteria.approver)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Section>
|
||||
)}
|
||||
|
||||
{values.todo && (
|
||||
<Section title={translate('::ListForms.ListFormEdit.TabTodo') || 'Todo / Kanban'}>
|
||||
<div className="grid grid-cols-2 gap-x-4">
|
||||
<Row
|
||||
label={translate('::ListForms.ListFormFieldEdit.TodoTitleExpr')}
|
||||
value={values.todoTitleExpr}
|
||||
/>
|
||||
<Row
|
||||
label={translate('::ListForms.ListFormFieldEdit.TodoStatusExpr')}
|
||||
value={values.todoStatusExpr}
|
||||
/>
|
||||
<Row
|
||||
label={translate('::ListForms.ListFormFieldEdit.TodoDescriptionExpr')}
|
||||
value={values.todoDescriptionExpr}
|
||||
/>
|
||||
<Row
|
||||
label={translate('::ListForms.ListFormFieldEdit.TodoDueDateExpr')}
|
||||
value={values.todoDueDateExpr}
|
||||
/>
|
||||
<Row
|
||||
label={translate('::ListForms.ListFormFieldEdit.TodoTagExpr')}
|
||||
value={values.todoTagExpr}
|
||||
/>
|
||||
<Row
|
||||
label={translate('::ListForms.ListFormFieldEdit.TodoAssigneeExpr')}
|
||||
value={values.todoAssigneeExpr}
|
||||
/>
|
||||
<Row
|
||||
label={translate('::ListForms.ListFormFieldEdit.TodoPriorityExpr')}
|
||||
value={values.todoPriorityExpr}
|
||||
/>
|
||||
<Row
|
||||
label={translate('::ListForms.ListFormFieldEdit.TodoCompletedExpr')}
|
||||
value={values.todoCompletedExpr}
|
||||
/>
|
||||
<Row
|
||||
label={translate('::ListForms.ListFormFieldEdit.TodoOrderExpr')}
|
||||
value={values.todoOrderExpr}
|
||||
/>
|
||||
<Row
|
||||
label={translate('::ListForms.ListFormFieldEdit.TodoStatusOrder')}
|
||||
value={values.todoStatusOrder}
|
||||
/>
|
||||
<Row
|
||||
label={translate('::ListForms.ListFormFieldEdit.TodoAllowDragging')}
|
||||
value={translate(
|
||||
values.todoAllowDragging ? '::App.Status.Active' : '::App.Status.Inactive',
|
||||
)}
|
||||
/>
|
||||
</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-8 gap-2">
|
||||
{[
|
||||
{ label: translate('::ListForms.Wizard.Step4.StatGroup'), value: groups.length },
|
||||
{ label: translate('::ListForms.Wizard.Step4.StatField'), value: totalFields },
|
||||
{
|
||||
label: translate('::ListForms.Wizard.Step4.EditingForm') || 'Popup Form',
|
||||
value: editingFormFields.length,
|
||||
},
|
||||
{
|
||||
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,
|
||||
},
|
||||
{
|
||||
label: translate('::ListForms.ListFormEdit.TabTodo') || 'Todo',
|
||||
value: values.todo ? 1 : 0,
|
||||
},
|
||||
].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')}
|
||||
</span>
|
||||
)}
|
||||
{hasError && (
|
||||
<span className="text-xs text-red-500 font-semibold flex items-center gap-1">
|
||||
<FaExclamationCircle /> {translate('::ListForms.Wizard.Step4.Error')}
|
||||
</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')}
|
||||
<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 />}
|
||||
disabled={isDeploying}
|
||||
onClick={onBack}
|
||||
>
|
||||
{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 WizardStep8
|
||||
|
|
@ -383,7 +383,7 @@ const OrganizationUnits = () => {
|
|||
}
|
||||
}
|
||||
|
||||
const Node = memo(({ node, style, dragHandle }: NodeRendererProps<any>) => {
|
||||
const Node = memo(function Node({ node, style, dragHandle }: NodeRendererProps<any>) {
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue