DevRequest tanımlaması

This commit is contained in:
Sedat ÖZTÜRK 2026-07-30 17:37:15 +03:00
parent 899dd58cde
commit c0033be6f6
30 changed files with 1611 additions and 845 deletions

View file

@ -1509,8 +1509,8 @@
{ {
"resourceName": "Platform", "resourceName": "Platform",
"key": "App.Licence", "key": "App.Licence",
"en": "Licence", "en": "Software Licence",
"tr": "Lisans" "tr": "Yazılım Lisansı"
}, },
{ {
"resourceName": "Platform", "resourceName": "Platform",
@ -1518,6 +1518,18 @@
"en": "Licence Items", "en": "Licence Items",
"tr": "Lisans Kalemleri" "tr": "Lisans Kalemleri"
}, },
{
"resourceName": "Platform",
"key": "App.DevRequest",
"en": "Development Request",
"tr": "Geliştirme Talebi"
},
{
"resourceName": "Platform",
"key": "App.DevRequests",
"en": "Development Requests",
"tr": "Geliştirme Talepleri"
},
{ {
"resourceName": "Platform", "resourceName": "Platform",
"key": "App.Settings", "key": "App.Settings",
@ -16476,6 +16488,42 @@
"en": "Request Date", "en": "Request Date",
"tr": "İstek Tarihi" "tr": "İstek Tarihi"
}, },
{
"resourceName": "Platform",
"key": "App.Listform.ListformField.Request",
"en": "Request",
"tr": "İstek"
},
{
"resourceName": "Platform",
"key": "App.Listform.ListformField.Contribution",
"en": "Contribution",
"tr": "Katkı"
},
{
"resourceName": "Platform",
"key": "App.Listform.ListformField.Benefit",
"en": "Benefit",
"tr": "Fayda"
},
{
"resourceName": "Platform",
"key": "App.Listform.ListformField.ActionTaken",
"en": "ActionTaken",
"tr": "Yapılanlar"
},
{
"resourceName": "Platform",
"key": "App.Listform.ListformField.Importance",
"en": "Importance",
"tr": "Önem"
},
{
"resourceName": "Platform",
"key": "App.Listform.ListformField.Urgency",
"en": "Urgency",
"tr": "Aciliyet"
},
{ {
"resourceName": "Platform", "resourceName": "Platform",
"key": "App.Listform.ListformField.RequestedDeliveryDate", "key": "App.Listform.ListformField.RequestedDeliveryDate",
@ -16842,6 +16890,12 @@
"en": "Status", "en": "Status",
"tr": "Durum" "tr": "Durum"
}, },
{
"resourceName": "Platform",
"key": "App.Listform.ListformField.StatusDate",
"en": "Status Date",
"tr": "Durum Tarihi"
},
{ {
"resourceName": "Platform", "resourceName": "Platform",
"key": "App.Listform.ListformField.Connection", "key": "App.Listform.ListformField.Connection",
@ -19473,8 +19527,8 @@
{ {
"resourceName": "Platform", "resourceName": "Platform",
"key": "ListForms.ListFormFieldEdit.TodoOrderExpr", "key": "ListForms.ListFormFieldEdit.TodoOrderExpr",
"en": "Card Order Field", "en": "Order Field",
"tr": "Kart sıra alanı" "tr": "Sıra alanı"
}, },
{ {
"resourceName": "Platform", "resourceName": "Platform",
@ -19698,6 +19752,12 @@
"en": "Undo changes", "en": "Undo changes",
"tr": "Değişiklikleri geri al" "tr": "Değişiklikleri geri al"
}, },
{
"resourceName": "Platform",
"key": "ListForms.TodoBoard.SaveAndExit",
"en": "Save and exit",
"tr": "Kaydet ve çık"
},
{ {
"resourceName": "Platform", "resourceName": "Platform",
"key": "ListForms.TodoBoard.ReorderColumn", "key": "ListForms.TodoBoard.ReorderColumn",

View file

@ -5637,7 +5637,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
#endregion #endregion
} }
#endregion #endregion
#region Licence Item #region Licence Item
listFormName = AppCodes.LicenceItem; listFormName = AppCodes.LicenceItem;
if (!await _listFormRepository.AnyAsync(a => a.ListFormCode == listFormName)) if (!await _listFormRepository.AnyAsync(a => a.ListFormCode == listFormName))
@ -5907,5 +5907,320 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
#endregion #endregion
} }
#endregion #endregion
#region DevRequest
listFormName = AppCodes.DevRequest;
if (!await _listFormRepository.AnyAsync(a => a.ListFormCode == listFormName))
{
var listForm = await _listFormRepository.InsertAsync(
new ListForm()
{
ListFormType = ListFormTypeEnum.List,
PageSize = 10,
ExportJson = DefaultExportJson,
IsSubForm = false,
ShowNote = false,
LayoutJson = DefaultLayoutJson(),
CultureName = LanguageCodes.En,
ListFormCode = listFormName,
Name = listFormName,
Title = listFormName,
DataSourceCode = SeedConsts.DataSources.DefaultCode,
IsTenant = false,
IsBranch = false,
IsOrganizationUnit = false,
Description = listFormName,
SelectCommandType = SelectCommandTypeEnum.Table,
SelectCommand = TableNameResolver.GetFullTableName(nameof(TableNameEnum.DevRequest)),
KeyFieldName = "Id",
KeyFieldDbSourceType = DbType.Guid,
DefaultFilter = "\"IsDeleted\" = 'false' AND \"TenantId\" = '@TENANTID'",
SortMode = GridOptions.SortModeSingle,
FilterRowJson = DefaultFilterRowJson(),
HeaderFilterJson = DefaultHeaderFilterJson(),
SearchPanelJson = DefaultSearchPanelJson(),
GroupPanelJson = DefaultGroupPanelJson(),
SelectionJson = DefaultSelectionSingleJson,
ColumnOptionJson = DefaultColumnOptionJson(),
PermissionJson = DefaultPermissionJson(listFormName),
DeleteCommand = DefaultDeleteCommand(nameof(TableNameEnum.DevRequest)),
DeleteFieldsDefaultValueJson = DefaultDeleteFieldsDefaultValueJson(),
PagerOptionJson = DefaultPagerOptionJson,
InsertFieldsDefaultValueJson = DefaultInsertFieldsDefaultValueJson(),
EditingOptionJson = DefaultEditingOptionJson(listFormName, 800, 800, true, true, true, true, false),
EditingFormJson = JsonSerializer.Serialize(new List<EditingFormDto>
{
new() { Order = 1, ColCount = 2, ColSpan = 1, ItemType = "group" },
}),
FormFieldsDefaultValueJson = JsonSerializer.Serialize(new FieldsDefaultValue[] {
new() { FieldName = "TenantId", FieldDbType = DbType.String, Value = "@TENANTID", CustomValueType = FieldCustomValueTypeEnum.CustomKey },
new() { FieldName = "UserName", FieldDbType = DbType.String, Value = "@USERNAME", CustomValueType = FieldCustomValueTypeEnum.CustomKey },
new() { FieldName = "RequestDate", FieldDbType = DbType.Date, Value = "@NOW", CustomValueType = FieldCustomValueTypeEnum.CustomKey },
new() { FieldName = "Importance", FieldDbType = DbType.String, Value = "Low", CustomValueType = FieldCustomValueTypeEnum.Value },
new() { FieldName = "Urgency", FieldDbType = DbType.String, Value = "Low", CustomValueType = FieldCustomValueTypeEnum.Value },
new() { FieldName = "Status", FieldDbType = DbType.String, Value = "Backlog", CustomValueType = FieldCustomValueTypeEnum.Value },
})
});
#region DevRequest Fields
await _listFormFieldRepository.InsertManyAsync([
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.Guid,
FieldName = "Id",
CaptionName = "App.Listform.ListformField.Id",
Width = 0,
ListOrderNo = 0,
Visible = false,
IsActive = true,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.Guid,
FieldName = "TenantId",
EditGroupOrderNo = 1,
EditOrderNo = 1,
EditorType2 = EditorTypes.dxSelectBox,
ColSpan = 1,
CaptionName = "App.Listform.ListformField.TenantId",
LookupJson = JsonSerializer.Serialize(new LookupDto {
DataSourceType = UiLookupDataSourceTypeEnum.Query,
DisplayExpr = "Name",
ValueExpr = "Key",
LookupQuery = LookupQueryValues.TenantValues(),
}),
Width = 0,
ListOrderNo = 1,
Visible = true,
IsActive = true,
AllowSearch = true,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson,
EditorOptions = EditorOptionValues.Disabled
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "UserName",
EditGroupOrderNo = 1,
EditOrderNo = 2,
EditorType2 = EditorTypes.dxTextBox,
ColSpan = 1,
CaptionName = "App.Listform.ListformField.UserName",
Width = 0,
ListOrderNo = 2,
Visible = true,
IsActive = true,
AllowSearch = true,
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson,
EditorOptions = EditorOptionValues.Disabled
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.Date,
FieldName = "RequestDate",
EditGroupOrderNo = 1,
EditOrderNo = 3,
EditorType2 = EditorTypes.dxDateBox,
ColSpan = 1,
CaptionName = "App.Listform.ListformField.RequestDate",
Width = 0,
ListOrderNo = 3,
Visible = true,
IsActive = true,
AllowSearch = true,
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "Status",
EditGroupOrderNo = 1,
EditOrderNo = 4,
EditorType2 = EditorTypes.dxSelectBox,
LookupJson = JsonSerializer.Serialize(new LookupDto
{
DataSourceType = UiLookupDataSourceTypeEnum.StaticData,
DisplayExpr = "name",
ValueExpr = "key",
LookupQuery = JsonSerializer.Serialize(new LookupDataDto[] {
new () { Key="Backlog", Name="Backlog" },
new () { Key="Ready to Start", Name="Ready to Start" },
new () { Key="In Progress", Name="In Progress" },
new () { Key="Code Review", Name="Code Review" },
new () { Key="Testing", Name="HiTestinggh" },
new () { Key="Staging", Name="Staging" }
}),
}),
ColSpan = 1,
CaptionName = "App.Listform.ListformField.Status",
Width = 0,
ListOrderNo = 4,
Visible = true,
IsActive = true,
AllowSearch = true,
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson,
EditorOptions = EditorOptionValues.Disabled
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "Title",
EditGroupOrderNo = 1,
EditOrderNo = 5,
EditorType2 = EditorTypes.dxTextBox,
ColSpan = 2,
CaptionName = "App.Listform.ListformField.Title",
Width = 0,
ListOrderNo = 5,
Visible = true,
IsActive = true,
AllowSearch = true,
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "Description",
EditGroupOrderNo = 1,
EditOrderNo = 6,
EditorType2 = EditorTypes.dxHtmlEditor,
ColSpan = 2,
CaptionName = "App.Listform.ListformField.Description",
Width = 0,
ListOrderNo = 6,
Visible = true,
IsActive = true,
AllowSearch = true,
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson,
EditorOptions = EditorOptionValues.HtmlEditorOptions
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.DateTime,
FieldName = "DueDate",
ColSpan = 1,
CaptionName = "App.Listform.ListformField.DueDate",
Width = 0,
ListOrderNo = 7,
Visible = true,
IsActive = true,
AllowSearch = true,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "Tags",
ColSpan = 1,
CaptionName = "App.Listform.ListformField.Tags",
Width = 0,
ListOrderNo = 8,
Visible = true,
IsActive = true,
AllowSearch = true,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "Assignees",
ColSpan = 1,
CaptionName = "App.Listform.ListformField.Assignees",
Width = 0,
ListOrderNo = 9,
Visible = true,
IsActive = true,
AllowSearch = true,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson,
EditorOptions = EditorOptionValues.Disabled
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "Priority",
ColSpan = 1,
CaptionName = "App.Listform.ListformField.Priority",
Width = 0,
ListOrderNo = 10,
Visible = true,
IsActive = true,
AllowSearch = true,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.Boolean,
FieldName = "Completed",
CaptionName = "App.Listform.ListformField.Completed",
Width = 0,
ListOrderNo = 11,
Visible = true,
IsActive = true,
AllowSearch = true,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.Int32,
FieldName = "SortOrder",
CaptionName = "App.Listform.ListformField.SortOrder",
Width = 0,
ListOrderNo = 12,
Visible = true,
IsActive = true,
AllowSearch = true,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
]);
#endregion
}
#endregion
} }
} }

View file

@ -103,6 +103,32 @@ public static class ListFormSeeder_DefaultJsons
RootValue = RootValue, RootValue = RootValue,
AutoExpandAll = AutoExpandAll AutoExpandAll = AutoExpandAll
}); });
public static string DefaultTodoOptionJson(
string TitleExpr = "Title",
string StatusExpr = "Status",
string DescriptionExpr = "Description",
string DueDateExpr = "DueDate",
string TagExpr = "Tags",
string AssigneeExpr = "Assignees",
string PriorityExpr = "Priority",
string CompletedExpr = "Completed",
string OrderExpr = "SortOrder",
string StatusOrder = "Backlog, Ready to Start, In Progress, Code Review, Testing, Staging",
bool AllowDragging = true
) => JsonSerializer.Serialize(new TodoOptionDto
{
TitleExpr = TitleExpr,
StatusExpr = StatusExpr,
DescriptionExpr = DescriptionExpr,
DueDateExpr = DueDateExpr,
TagExpr = TagExpr,
AssigneeExpr = AssigneeExpr,
PriorityExpr = PriorityExpr,
CompletedExpr = CompletedExpr,
OrderExpr = OrderExpr,
StatusOrder = StatusOrder,
AllowDragging = AllowDragging
});
public static readonly string DefaultPagerOptionJson = JsonSerializer.Serialize(new GridPagerOptionDto public static readonly string DefaultPagerOptionJson = JsonSerializer.Serialize(new GridPagerOptionDto
{ {
Visible = true, Visible = true,
@ -134,9 +160,9 @@ public static class ListFormSeeder_DefaultJsons
public static string DefaultGroupingJson(int groupIndex) => JsonSerializer.Serialize(new ColumnGroupingDto public static string DefaultGroupingJson(int groupIndex) => JsonSerializer.Serialize(new ColumnGroupingDto
{ {
AllowGrouping = true, AllowGrouping = true,
GroupIndex = groupIndex, GroupIndex = groupIndex,
AutoExpandGroup = false AutoExpandGroup = false
}); });
public static readonly string DefaultValidationRuleRequiredJson = JsonSerializer.Serialize(new ValidationRuleDto[] public static readonly string DefaultValidationRuleRequiredJson = JsonSerializer.Serialize(new ValidationRuleDto[]
{ {

View file

@ -70,7 +70,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
ExportJson = DefaultExportJson, ExportJson = DefaultExportJson,
IsSubForm = false, IsSubForm = false,
ShowNote = true, ShowNote = true,
LayoutJson = DefaultLayoutJson(), LayoutJson = DefaultLayoutJson("todo"),
CultureName = LanguageCodes.En, CultureName = LanguageCodes.En,
ListFormCode = listFormName, ListFormCode = listFormName,
Name = listFormName, Name = listFormName,
@ -9667,5 +9667,321 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
} }
#endregion #endregion
#region DevRequests
listFormName = AppCodes.DevRequests;
if (!await _listFormRepository.AnyAsync(a => a.ListFormCode == listFormName))
{
var listForm = await _listFormRepository.InsertAsync(
new ListForm()
{
ListFormType = ListFormTypeEnum.List,
PageSize = 10,
ExportJson = DefaultExportJson,
IsSubForm = false,
ShowNote = false,
LayoutJson = DefaultLayoutJson("todo"),
CultureName = LanguageCodes.En,
ListFormCode = listFormName,
Name = listFormName,
Title = listFormName,
DataSourceCode = SeedConsts.DataSources.DefaultCode,
IsTenant = false,
IsBranch = false,
IsOrganizationUnit = false,
Description = listFormName,
SelectCommandType = SelectCommandTypeEnum.Table,
SelectCommand = TableNameResolver.GetFullTableName(nameof(TableNameEnum.DevRequest)),
KeyFieldName = "Id",
KeyFieldDbSourceType = DbType.Guid,
DefaultFilter = DefaultFilterJson,
SortMode = GridOptions.SortModeSingle,
FilterRowJson = DefaultFilterRowJson(),
HeaderFilterJson = DefaultHeaderFilterJson(),
SearchPanelJson = DefaultSearchPanelJson(),
GroupPanelJson = DefaultGroupPanelJson(),
SelectionJson = DefaultSelectionSingleJson,
ColumnOptionJson = DefaultColumnOptionJson(),
PermissionJson = DefaultPermissionJson(listFormName),
DeleteCommand = DefaultDeleteCommand(nameof(TableNameEnum.DevRequest)),
DeleteFieldsDefaultValueJson = DefaultDeleteFieldsDefaultValueJson(),
PagerOptionJson = DefaultPagerOptionJson,
InsertFieldsDefaultValueJson = DefaultInsertFieldsDefaultValueJson(),
EditingOptionJson = DefaultEditingOptionJson(listFormName, 800, 800, true, true, true, true, false),
EditingFormJson = JsonSerializer.Serialize(new List<EditingFormDto>
{
new() { Order = 1, ColCount = 2, ColSpan = 1, ItemType = "group" },
}),
FormFieldsDefaultValueJson = JsonSerializer.Serialize(new FieldsDefaultValue[] {
new() { FieldName = "TenantId", FieldDbType = DbType.String, Value = "@TENANTID", CustomValueType = FieldCustomValueTypeEnum.CustomKey },
new() { FieldName = "UserName", FieldDbType = DbType.String, Value = "@USERNAME", CustomValueType = FieldCustomValueTypeEnum.CustomKey },
new() { FieldName = "RequestDate", FieldDbType = DbType.Date, Value = "@NOW", CustomValueType = FieldCustomValueTypeEnum.CustomKey },
new() { FieldName = "Importance", FieldDbType = DbType.String, Value = "Low", CustomValueType = FieldCustomValueTypeEnum.Value },
new() { FieldName = "Urgency", FieldDbType = DbType.String, Value = "Low", CustomValueType = FieldCustomValueTypeEnum.Value },
new() { FieldName = "Status", FieldDbType = DbType.String, Value = "Backlog", CustomValueType = FieldCustomValueTypeEnum.Value },
}),
TodoOptionJson = DefaultTodoOptionJson()
});
#region DevRequest Fields
await _listFormFieldRepository.InsertManyAsync([
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.Guid,
FieldName = "Id",
CaptionName = "App.Listform.ListformField.Id",
Width = 0,
ListOrderNo = 0,
Visible = false,
IsActive = true,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.Guid,
FieldName = "TenantId",
EditGroupOrderNo = 1,
EditOrderNo = 1,
EditorType2 = EditorTypes.dxSelectBox,
ColSpan = 1,
CaptionName = "App.Listform.ListformField.TenantId",
LookupJson = JsonSerializer.Serialize(new LookupDto {
DataSourceType = UiLookupDataSourceTypeEnum.Query,
DisplayExpr = "Name",
ValueExpr = "Key",
LookupQuery = LookupQueryValues.TenantValues(),
}),
Width = 0,
ListOrderNo = 1,
Visible = true,
IsActive = true,
AllowSearch = true,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson,
EditorOptions = EditorOptionValues.Disabled
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "UserName",
EditGroupOrderNo = 1,
EditOrderNo = 2,
EditorType2 = EditorTypes.dxTextBox,
ColSpan = 1,
CaptionName = "App.Listform.ListformField.UserName",
Width = 0,
ListOrderNo = 2,
Visible = true,
IsActive = true,
AllowSearch = true,
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson,
EditorOptions = EditorOptionValues.Disabled
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.Date,
FieldName = "RequestDate",
EditGroupOrderNo = 1,
EditOrderNo = 3,
EditorType2 = EditorTypes.dxDateBox,
ColSpan = 1,
CaptionName = "App.Listform.ListformField.RequestDate",
Width = 0,
ListOrderNo = 3,
Visible = true,
IsActive = true,
AllowSearch = true,
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "Status",
EditGroupOrderNo = 1,
EditOrderNo = 4,
EditorType2 = EditorTypes.dxSelectBox,
LookupJson = JsonSerializer.Serialize(new LookupDto
{
DataSourceType = UiLookupDataSourceTypeEnum.StaticData,
DisplayExpr = "name",
ValueExpr = "key",
LookupQuery = JsonSerializer.Serialize(new LookupDataDto[] {
new () { Key="Backlog", Name="Backlog" },
new () { Key="Ready to Start", Name="Ready to Start" },
new () { Key="In Progress", Name="In Progress" },
new () { Key="Code Review", Name="Code Review" },
new () { Key="Testing", Name="HiTestinggh" },
new () { Key="Staging", Name="Staging" }
}),
}),
ColSpan = 1,
CaptionName = "App.Listform.ListformField.Status",
Width = 0,
ListOrderNo = 4,
Visible = true,
IsActive = true,
AllowSearch = true,
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson,
EditorOptions = EditorOptionValues.Disabled
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "Title",
EditGroupOrderNo = 1,
EditOrderNo = 5,
EditorType2 = EditorTypes.dxTextBox,
ColSpan = 2,
CaptionName = "App.Listform.ListformField.Title",
Width = 0,
ListOrderNo = 5,
Visible = true,
IsActive = true,
AllowSearch = true,
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "Description",
EditGroupOrderNo = 1,
EditOrderNo = 6,
EditorType2 = EditorTypes.dxHtmlEditor,
ColSpan = 2,
CaptionName = "App.Listform.ListformField.Description",
Width = 0,
ListOrderNo = 6,
Visible = true,
IsActive = true,
AllowSearch = true,
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson,
EditorOptions = EditorOptionValues.HtmlEditorOptions
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.DateTime,
FieldName = "DueDate",
ColSpan = 1,
CaptionName = "App.Listform.ListformField.DueDate",
Width = 0,
ListOrderNo = 7,
Visible = true,
IsActive = true,
AllowSearch = true,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "Tags",
ColSpan = 1,
CaptionName = "App.Listform.ListformField.Tags",
Width = 0,
ListOrderNo = 8,
Visible = true,
IsActive = true,
AllowSearch = true,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "Assignees",
ColSpan = 1,
CaptionName = "App.Listform.ListformField.Assignees",
Width = 0,
ListOrderNo = 9,
Visible = true,
IsActive = true,
AllowSearch = true,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson,
EditorOptions = EditorOptionValues.Disabled
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "Priority",
ColSpan = 1,
CaptionName = "App.Listform.ListformField.Priority",
Width = 0,
ListOrderNo = 10,
Visible = true,
IsActive = true,
AllowSearch = true,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.Boolean,
FieldName = "Completed",
CaptionName = "App.Listform.ListformField.Completed",
Width = 0,
ListOrderNo = 11,
Visible = true,
IsActive = true,
AllowSearch = true,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.Int32,
FieldName = "SortOrder",
CaptionName = "App.Listform.ListformField.SortOrder",
Width = 0,
ListOrderNo = 12,
Visible = true,
IsActive = true,
AllowSearch = true,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
]);
#endregion
}
#endregion
} }
} }

View file

@ -741,11 +741,21 @@
"RequiredPermissionName": "App.Contact", "RequiredPermissionName": "App.Contact",
"IsDisabled": false "IsDisabled": false
}, },
{
"ParentCode": "App.Saas",
"Code": "App.DevRequests",
"DisplayName": "App.DevRequests",
"Order": 3,
"Url": "/admin/list/App.DevRequests",
"Icon": "FcIdea",
"RequiredPermissionName": "App.DevRequests",
"IsDisabled": false
},
{ {
"ParentCode": "App.Saas", "ParentCode": "App.Saas",
"Code": "AbpTenantManagement.Tenants", "Code": "AbpTenantManagement.Tenants",
"DisplayName": "AbpTenantManagement.Tenants", "DisplayName": "AbpTenantManagement.Tenants",
"Order": 3, "Order": 4,
"Url": "/admin/list/AbpTenantManagement.Tenants", "Url": "/admin/list/AbpTenantManagement.Tenants",
"Icon": "FcDepartment", "Icon": "FcDepartment",
"RequiredPermissionName": "AbpTenantManagement.Tenants", "RequiredPermissionName": "AbpTenantManagement.Tenants",
@ -755,7 +765,7 @@
"ParentCode": "App.Saas", "ParentCode": "App.Saas",
"Code": "App.Branches", "Code": "App.Branches",
"DisplayName": "App.Branches", "DisplayName": "App.Branches",
"Order": 4, "Order": 5,
"Url": "/admin/list/App.Branches", "Url": "/admin/list/App.Branches",
"Icon": "FcTreeStructure", "Icon": "FcTreeStructure",
"RequiredPermissionName": "App.Branches", "RequiredPermissionName": "App.Branches",
@ -765,7 +775,7 @@
"ParentCode": "App.Saas", "ParentCode": "App.Saas",
"Code": "App.SettingDefinitions", "Code": "App.SettingDefinitions",
"DisplayName": "App.SettingDefinitions", "DisplayName": "App.SettingDefinitions",
"Order": 5, "Order": 6,
"Url": "/admin/list/App.SettingDefinitions", "Url": "/admin/list/App.SettingDefinitions",
"Icon": "FcSupport", "Icon": "FcSupport",
"RequiredPermissionName": "App.SettingDefinitions", "RequiredPermissionName": "App.SettingDefinitions",
@ -775,7 +785,7 @@
"ParentCode": "App.Saas", "ParentCode": "App.Saas",
"Code": "App.Languages", "Code": "App.Languages",
"DisplayName": "App.Languages", "DisplayName": "App.Languages",
"Order": 6, "Order": 7,
"Url": null, "Url": null,
"Icon": "FcGlobe", "Icon": "FcGlobe",
"RequiredPermissionName": null, "RequiredPermissionName": null,
@ -805,7 +815,7 @@
"ParentCode": "App.Saas", "ParentCode": "App.Saas",
"Code": "App.DataSource", "Code": "App.DataSource",
"DisplayName": "App.DataSource", "DisplayName": "App.DataSource",
"Order": 7, "Order": 8,
"Url": "/admin/list/App.DataSource", "Url": "/admin/list/App.DataSource",
"Icon": "FcAcceptDatabase", "Icon": "FcAcceptDatabase",
"RequiredPermissionName": "App.DataSource", "RequiredPermissionName": "App.DataSource",
@ -1093,11 +1103,21 @@
"RequiredPermissionName": "App.Licence", "RequiredPermissionName": "App.Licence",
"IsDisabled": false "IsDisabled": false
}, },
{
"ParentCode": "App.Administration",
"Code": "App.DevRequest",
"DisplayName": "App.DevRequest",
"Order": 3,
"Url": "/admin/list/App.DevRequest",
"Icon": "FcIdea",
"RequiredPermissionName": "App.DevRequest",
"IsDisabled": false
},
{ {
"ParentCode": "App.Administration", "ParentCode": "App.Administration",
"Code": "App.Setting", "Code": "App.Setting",
"DisplayName": "App.Setting", "DisplayName": "App.Setting",
"Order": 3, "Order": 4,
"Url": "/admin/settings", "Url": "/admin/settings",
"Icon": "FcSettings", "Icon": "FcSettings",
"RequiredPermissionName": "App.Setting", "RequiredPermissionName": "App.Setting",
@ -1107,7 +1127,7 @@
"ParentCode": "App.Administration", "ParentCode": "App.Administration",
"Code": "App.Administration.Intranet", "Code": "App.Administration.Intranet",
"DisplayName": "App.Intranet", "DisplayName": "App.Intranet",
"Order": 4, "Order": 5,
"Url": null, "Url": null,
"Icon": "FcConferenceCall", "Icon": "FcConferenceCall",
"RequiredPermissionName": null, "RequiredPermissionName": null,
@ -1157,7 +1177,7 @@
"ParentCode": "App.Administration.Intranet", "ParentCode": "App.Administration.Intranet",
"Code": "App.Intranet.Events.EventCategory", "Code": "App.Intranet.Events.EventCategory",
"DisplayName": "App.Intranet.Events.EventCategory", "DisplayName": "App.Intranet.Events.EventCategory",
"Order": 5, "Order": 6,
"Url": "/admin/list/App.Intranet.Events.EventCategory", "Url": "/admin/list/App.Intranet.Events.EventCategory",
"Icon": "FcTreeStructure", "Icon": "FcTreeStructure",
"RequiredPermissionName": "App.Intranet.Events.EventCategory", "RequiredPermissionName": "App.Intranet.Events.EventCategory",
@ -1177,7 +1197,7 @@
"ParentCode": "App.Administration", "ParentCode": "App.Administration",
"Code": "App.Administration.Restrictions", "Code": "App.Administration.Restrictions",
"DisplayName": "App.Restrictions", "DisplayName": "App.Restrictions",
"Order": 5, "Order": 7,
"Url": null, "Url": null,
"Icon": "FaLock", "Icon": "FaLock",
"RequiredPermissionName": null, "RequiredPermissionName": null,
@ -1207,7 +1227,7 @@
"ParentCode": "App.Administration", "ParentCode": "App.Administration",
"Code": "Abp.Identity", "Code": "Abp.Identity",
"DisplayName": "Abp.Identity", "DisplayName": "Abp.Identity",
"Order": 6, "Order": 8,
"Url": null, "Url": null,
"Icon": "FcConferenceCall", "Icon": "FcConferenceCall",
"RequiredPermissionName": null, "RequiredPermissionName": null,
@ -1297,7 +1317,7 @@
"ParentCode": "App.Administration", "ParentCode": "App.Administration",
"Code": "App.Reports.Management", "Code": "App.Reports.Management",
"DisplayName": "App.Reports.Management", "DisplayName": "App.Reports.Management",
"Order": 7, "Order": 9,
"Url": null, "Url": null,
"Icon": "FcDocument", "Icon": "FcDocument",
"RequiredPermissionName": null, "RequiredPermissionName": null,
@ -1327,7 +1347,7 @@
"ParentCode": "App.Administration", "ParentCode": "App.Administration",
"Code": "App.Videoroom.Dashboard", "Code": "App.Videoroom.Dashboard",
"DisplayName": "App.Videoroom.Dashboard", "DisplayName": "App.Videoroom.Dashboard",
"Order": 8, "Order": 10,
"Url": "/admin/videoroom/dashboard", "Url": "/admin/videoroom/dashboard",
"Icon": "FcVideoCall", "Icon": "FcVideoCall",
"RequiredPermissionName": "App.Videoroom.Dashboard", "RequiredPermissionName": "App.Videoroom.Dashboard",
@ -1337,7 +1357,7 @@
"ParentCode": "App.Administration", "ParentCode": "App.Administration",
"Code": "App.Files", "Code": "App.Files",
"DisplayName": "App.Files", "DisplayName": "App.Files",
"Order": 9, "Order": 11,
"Url": "/admin/files", "Url": "/admin/files",
"Icon": "FcFolder", "Icon": "FcFolder",
"RequiredPermissionName": "App.Files", "RequiredPermissionName": "App.Files",
@ -1347,7 +1367,7 @@
"ParentCode": "App.Administration", "ParentCode": "App.Administration",
"Code": "App.Forum", "Code": "App.Forum",
"DisplayName": "App.Forum", "DisplayName": "App.Forum",
"Order": 10, "Order": 12,
"Url": "/admin/forum", "Url": "/admin/forum",
"Icon": "FcLink", "Icon": "FcLink",
"RequiredPermissionName": "App.ForumManagement.Publish", "RequiredPermissionName": "App.ForumManagement.Publish",

View file

@ -91,6 +91,69 @@
"MultiTenancySide": 2, "MultiTenancySide": 2,
"MenuGroup": "Erp|Kurs" "MenuGroup": "Erp|Kurs"
}, },
{
"GroupName": "App.Saas",
"Name": "App.DevRequests",
"ParentName": null,
"DisplayName": "App.DevRequests",
"IsEnabled": true,
"MultiTenancySide": 2,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Saas",
"Name": "App.DevRequests.Create",
"ParentName": "App.DevRequests",
"DisplayName": "Create",
"IsEnabled": true,
"MultiTenancySide": 2,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Saas",
"Name": "App.DevRequests.Update",
"ParentName": "App.DevRequests",
"DisplayName": "Update",
"IsEnabled": true,
"MultiTenancySide": 2,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Saas",
"Name": "App.DevRequests.Delete",
"ParentName": "App.DevRequests",
"DisplayName": "Delete",
"IsEnabled": true,
"MultiTenancySide": 2,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Saas",
"Name": "App.DevRequests.Export",
"ParentName": "App.DevRequests",
"DisplayName": "Export",
"IsEnabled": true,
"MultiTenancySide": 2,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Saas",
"Name": "App.DevRequests.Import",
"ParentName": "App.DevRequests",
"DisplayName": "Import",
"IsEnabled": true,
"MultiTenancySide": 2,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Saas",
"Name": "App.DevRequests.Note",
"ParentName": "App.DevRequests",
"DisplayName": "Note",
"IsEnabled": true,
"MultiTenancySide": 2,
"MenuGroup": "Erp|Kurs"
},
{ {
"GroupName": "App.Saas", "GroupName": "App.Saas",
"Name": "App.Branches", "Name": "App.Branches",
@ -4617,6 +4680,60 @@
"IsEnabled": true, "IsEnabled": true,
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp|Kurs" "MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Administration",
"Name": "App.DevRequest",
"ParentName": null,
"DisplayName": "App.DevRequest",
"IsEnabled": true,
"MultiTenancySide": 3,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Administration",
"Name": "App.DevRequest.Create",
"ParentName": "App.DevRequest",
"DisplayName": "Create",
"IsEnabled": true,
"MultiTenancySide": 3,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Administration",
"Name": "App.DevRequest.Update",
"ParentName": "App.DevRequest",
"DisplayName": "Update",
"IsEnabled": true,
"MultiTenancySide": 3,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Administration",
"Name": "App.DevRequest.Delete",
"ParentName": "App.DevRequest",
"DisplayName": "Delete",
"IsEnabled": true,
"MultiTenancySide": 3,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Administration",
"Name": "App.DevRequest.Export",
"ParentName": "App.DevRequest",
"DisplayName": "Export",
"IsEnabled": true,
"MultiTenancySide": 3,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Administration",
"Name": "App.DevRequest.Import",
"ParentName": "App.DevRequest",
"DisplayName": "Import",
"IsEnabled": true,
"MultiTenancySide": 3,
"MenuGroup": "Erp|Kurs"
} }
] ]
} }

View file

@ -1,19 +0,0 @@
IF OBJECT_ID(N'[dbo].[Pro_T_Approval]', 'U') IS NULL
BEGIN
CREATE TABLE [dbo].[Pro_T_Approval]
(
[Id] uniqueidentifier NOT NULL,
[ApprovalUserName] nvarchar(512) NULL,
[ApprovalStatus] nvarchar(100) NULL,
[ApprovalDate] datetime NULL,
[ApprovalDescription] nvarchar(400) NULL,
[TenantId] uniqueidentifier NULL,
[Title] nvarchar(200) NULL,
[ParentTitle] nvarchar(200) 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

View file

@ -1,22 +0,0 @@
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

View file

@ -1,294 +0,0 @@
{
"Wizard": {
"WizardName": "Approval",
"ListFormCode": "App.Wizard.Approval",
"MenuCode": "App.Wizard.Approval",
"MenuOrder": 2,
"IsTenant": true,
"IsBranch": false,
"IsOrganizationUnit": false,
"AllowAdding": true,
"AllowUpdating": true,
"AllowDeleting": true,
"AllowDetail": false,
"ConfirmDelete": true,
"DefaultLayout": "tree",
"Grid": true,
"Card": true,
"Pivot": true,
"Chart": true,
"Tree": true,
"Gantt": false,
"Scheduler": false,
"Todo": false,
"LanguageTextMenuEn": "Approval",
"LanguageTextMenuTr": "Onaylama",
"LanguageTextTitleEn": "Approval",
"LanguageTextTitleTr": "Onaylama",
"LanguageTextDescEn": "Approval",
"LanguageTextDescTr": "Onaylama",
"LanguageTextMenuParentEn": "Project",
"LanguageTextMenuParentTr": "Project",
"PermissionGroupName": "App.Wizard.Project",
"MenuParentCode": "App.Wizard.Project",
"MenuParentShortName": "Pro",
"MenuParentIcon": "FcVideoProjector",
"MenuIcon": "FcApproval",
"DataSourceCode": "Default",
"DataSourceConnectionString": "",
"SelectCommandType": 1,
"SelectCommand": "Pro_T_Approval",
"KeyFieldName": "Id",
"KeyFieldDbSourceType": 9,
"TreeOptionDto": {
"KeyExpr": "Title",
"ParentIdExpr": "ParentTitle",
"HasItemsExpr": null,
"RootValue": null,
"ExpandedRowKeys": [],
"AutoExpandAll": true,
"RecursiveSelection": false,
"TitleExpr": null,
"StartExpr": null,
"EndExpr": null,
"ProgressExpr": null
},
"GanttOptionDto": {},
"SchedulerOptionDto": {},
"TodoOptionDto": {},
"WorkflowDto": {
"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": [
{
"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": "ApprovalUserName",
"CaptionName": "App.Listform.ListformField.ApprovalUserName",
"EditorType": "dxTextBox",
"EditorOptions": "",
"EditorScript": "",
"ColSpan": 1,
"IsRequired": false,
"IncludeInEditingForm": false,
"DbSourceType": 16,
"TurkishCaption": "Approval User Name",
"EnglishCaption": "Approval User Name",
"LookupDataSourceType": 1,
"ValueExpr": "Key",
"DisplayExpr": "Name",
"LookupQuery": ""
},
{
"FieldName": "ApprovalStatus",
"CaptionName": "App.Listform.ListformField.ApprovalStatus",
"EditorType": "dxTextBox",
"EditorOptions": "",
"EditorScript": "",
"ColSpan": 1,
"IsRequired": false,
"IncludeInEditingForm": false,
"DbSourceType": 16,
"TurkishCaption": "Approval Status",
"EnglishCaption": "Approval Status",
"LookupDataSourceType": 1,
"ValueExpr": "Key",
"DisplayExpr": "Name",
"LookupQuery": ""
},
{
"FieldName": "ApprovalDate",
"CaptionName": "App.Listform.ListformField.ApprovalDate",
"EditorType": "dxDateBox",
"EditorOptions": "",
"EditorScript": "",
"ColSpan": 1,
"IsRequired": false,
"IncludeInEditingForm": false,
"DbSourceType": 6,
"TurkishCaption": "Approval Date",
"EnglishCaption": "Approval Date",
"LookupDataSourceType": 1,
"ValueExpr": "Key",
"DisplayExpr": "Name",
"LookupQuery": ""
},
{
"FieldName": "ApprovalDescription",
"CaptionName": "App.Listform.ListformField.ApprovalDescription",
"EditorType": "dxTextBox",
"EditorOptions": "",
"EditorScript": "",
"ColSpan": 1,
"IsRequired": false,
"IncludeInEditingForm": false,
"DbSourceType": 16,
"TurkishCaption": "Approval Description",
"EnglishCaption": "Approval Description",
"LookupDataSourceType": 1,
"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": ""
},
{
"FieldName": "ParentTitle",
"CaptionName": "App.Listform.ListformField.ParentTitle",
"EditorType": "dxSelectBox",
"EditorOptions": "",
"EditorScript": "",
"ColSpan": 1,
"IsRequired": false,
"IncludeInEditingForm": true,
"DbSourceType": 16,
"TurkishCaption": "Parent Title",
"EnglishCaption": "Parent Title",
"LookupDataSourceType": 2,
"ValueExpr": "Key",
"DisplayExpr": "Name",
"LookupQuery": "SELECT \u0022Title\u0022 AS \u0022Key\u0022, \u0022Title\u0022 AS \u0022Name\u0022 FROM \u0022Pro_T_Approval\u0022 ORDER BY \u0022Title\u0022;"
}
]
}
],
"SubForms": [],
"Widgets": []
},
"IsDeletedField": false,
"IsCreatedField": false,
"InsertedRecords": {
"LanguageKeys": [
"App.Wizard.Approval",
"App.Wizard.Approval.Title",
"App.Wizard.Approval.Desc",
"App.Listform.ListformField.ParentTitle"
],
"PermissionGroupNames": [],
"PermissionNames": [
"App.Wizard.Approval",
"App.Wizard.Approval.Create",
"App.Wizard.Approval.Update",
"App.Wizard.Approval.Delete",
"App.Wizard.Approval.Export",
"App.Wizard.Approval.Import",
"App.Wizard.Approval.Note"
],
"MenuCodes": [
"App.Wizard.Approval"
],
"DataSourceCodes": []
}
}

View file

@ -1,276 +0,0 @@
{
"Wizard": {
"WizardName": "Todo",
"ListFormCode": "App.Wizard.Todo",
"MenuCode": "App.Wizard.Todo",
"MenuOrder": 1,
"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": false,
"Chart": true,
"Gantt": false,
"Scheduler": false,
"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,
"TreeOptionDto": {},
"GanttOptionDto": {},
"SchedulerOptionDto": {},
"TodoOptionDto": {
"TitleExpr": "Title",
"StatusExpr": "Status",
"DescriptionExpr": "Description",
"DueDateExpr": "DueDate",
"TagExpr": "Tags",
"AssigneeExpr": "Assignees",
"PriorityExpr": "Priority",
"CompletedExpr": "Completed",
"OrderExpr": "SortOrder",
"StatusOrder": "Backlog, Ready to Start, In Progress, Code Review, Testing, Staging",
"AllowDragging": true
},
"WorkflowDto": {
"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": []
}
}

View file

@ -96,4 +96,5 @@ public enum TableNameEnum
VideoroomChat, VideoroomChat,
Sequence, Sequence,
DbTableColumn, DbTableColumn,
DevRequest
} }

View file

@ -19,7 +19,7 @@ public static class PlatformConsts
{ {
public static string Disabled = "{ \"disabled\" : true }"; public static string Disabled = "{ \"disabled\" : true }";
public static string ShowClearButton = "{ \"showClearButton\" : true }"; public static string ShowClearButton = "{ \"showClearButton\" : true }";
public static string HtmlEditorOptions = "{ \"mediaResizing\": { \"enabled\": true }, \"imageUpload\": { \"tabs\": [\"file\", \"url\"], \"fileUploadMode\": \"base64\" }, \"toolbar\": { \"multiline\": true, \"items\": [ { \"name\": \"undo\" }, { \"name\": \"redo\" }, { \"name\": \"separator\" }, { \"name\": \"size\", \"acceptedValues\": [\"8pt\", \"10pt\", \"12pt\", \"14pt\", \"18pt\", \"24pt\", \"36pt\"], \"options\": { \"inputAttr\": { \"aria-label\": \"Font size\" } } }, { \"name\": \"font\", \"acceptedValues\": [\"Arial\", \"Courier New\", \"Georgia\", \"Impact\", \"Lucida Console\", \"Tahoma\", \"Times New Roman\", \"Verdana\"], \"options\": { \"inputAttr\": { \"aria-label\": \"Font family\" } } }, { \"name\": \"separator\" }, { \"name\": \"bold\" }, { \"name\": \"italic\" }, { \"name\": \"strike\" }, { \"name\": \"underline\" }, { \"name\": \"separator\" }, { \"name\": \"alignLeft\" }, { \"name\": \"alignCenter\" }, { \"name\": \"alignRight\" }, { \"name\": \"alignJustify\" }, { \"name\": \"separator\" }, { \"name\": \"orderedList\" }, { \"name\": \"bulletList\" }, { \"name\": \"separator\" }, { \"name\": \"header\", \"acceptedValues\": [false, 1, 2, 3, 4, 5] }, { \"name\": \"separator\" }, { \"name\": \"color\" }, { \"name\": \"background\" }, { \"name\": \"separator\" }, { \"name\": \"link\" }, { \"name\": \"image\" }, { \"name\": \"separator\" }, { \"name\": \"clear\" }, { \"name\": \"codeBlock\" }, { \"name\": \"blockquote\" }, { \"name\": \"separator\" }, { \"name\": \"insertTable\" }, { \"name\": \"deleteTable\" }, { \"name\": \"insertRowAbove\" }, { \"name\": \"insertRowBelow\" }, { \"name\": \"deleteRow\" }, { \"name\": \"insertColumnLeft\" }, { \"name\": \"insertColumnRight\" }, { \"name\": \"deleteColumn\" }, { \"name\": \"cellProperties\" }, { \"name\": \"tableProperties\" } ] } }"; public static string HtmlEditorOptions = "{ \"mediaResizing\": { \"enabled\": true }, \"imageUpload\": { \"tabs\": [\"file\", \"url\"], \"fileUploadMode\": \"base64\" }, \"toolbar\": { \"multiline\": true, \"items\": [ { \"name\": \"undo\" }, { \"name\": \"redo\" }, { \"name\": \"separator\" }, { \"name\": \"size\", \"acceptedValues\": [\"8pt\", \"10pt\", \"12pt\", \"14pt\", \"18pt\", \"24pt\", \"36pt\"], \"options\": { \"inputAttr\": { \"aria-label\": \"Font size\" } } }, { \"name\": \"font\", \"acceptedValues\": [\"Arial\", \"Courier New\", \"Georgia\", \"Impact\", \"Lucida Console\", \"Tahoma\", \"Times New Roman\", \"Verdana\"], \"options\": { \"inputAttr\": { \"aria-label\": \"Font family\" } } }, { \"name\": \"separator\" }, { \"name\": \"bold\" }, { \"name\": \"italic\" }, { \"name\": \"strike\" }, { \"name\": \"underline\" }, { \"name\": \"separator\" }, { \"name\": \"alignLeft\" }, { \"name\": \"alignCenter\" }, { \"name\": \"alignRight\" }, { \"name\": \"alignJustify\" }, { \"name\": \"separator\" }, { \"name\": \"orderedList\" }, { \"name\": \"bulletList\" }, { \"name\": \"separator\" }, { \"name\": \"header\", \"acceptedValues\": [false, 1, 2, 3, 4, 5] }, { \"name\": \"separator\" }, { \"name\": \"color\" }, { \"name\": \"background\" }, { \"name\": \"separator\" }, { \"name\": \"link\" }, { \"name\": \"image\" }, { \"name\": \"separator\" }, { \"name\": \"clear\" }, { \"name\": \"codeBlock\" }, { \"name\": \"blockquote\" }, { \"name\": \"separator\" }, { \"name\": \"insertTable\" }, { \"name\": \"deleteTable\" }, { \"name\": \"insertRowAbove\" }, { \"name\": \"insertRowBelow\" }, { \"name\": \"deleteRow\" }, { \"name\": \"insertColumnLeft\" }, { \"name\": \"insertColumnRight\" }, { \"name\": \"deleteColumn\" }, { \"name\": \"cellProperties\" }, { \"name\": \"tableProperties\" } ] } }, \"encodeHtml\": true }";
public static string PhoneEditorOptions = "{\"format\": \"phoneGlobal\", \"mask\":\"(000) 000-0000\", \"maskInvalidMessage\":\"Lütfen geçerli bir telefon numarası girin\", \"useMaskedValue\":false, \"maskRules\": { \"X\": \"[0-9]\" }, \"placeholder\": \"(555) 123-4567\" }"; public static string PhoneEditorOptions = "{\"format\": \"phoneGlobal\", \"mask\":\"(000) 000-0000\", \"maskInvalidMessage\":\"Lütfen geçerli bir telefon numarası girin\", \"useMaskedValue\":false, \"maskRules\": { \"X\": \"[0-9]\" }, \"placeholder\": \"(555) 123-4567\" }";
public static string TimeSpanOptions = "{\"type\":\"time\",\"pickerType\":\"list\",\"displayFormat\":\"HH:mm\",\"dateSerializationFormat\":\"yyyy-MM-ddTHH:mm:ss\",\"interval\":5,\"width\":\"100%\"}"; public static string TimeSpanOptions = "{\"type\":\"time\",\"pickerType\":\"list\",\"displayFormat\":\"HH:mm\",\"dateSerializationFormat\":\"yyyy-MM-ddTHH:mm:ss\",\"interval\":5,\"width\":\"100%\"}";
public static string NumberStandartFormat(int precision = 2) => "{ \"format\": { \"type\": \"fixedPoint\", \"precision\": " + precision + " }, \"useMaskBehavior\": true, \"showSpinButtons\": true }"; public static string NumberStandartFormat(int precision = 2) => "{ \"format\": { \"type\": \"fixedPoint\", \"precision\": " + precision + " }, \"useMaskBehavior\": true, \"showSpinButtons\": true }";
@ -529,6 +529,8 @@ public static class PlatformConsts
public const string Categories = Default + ".Categories"; public const string Categories = Default + ".Categories";
public const string ReportTemplates = Default + ".ReportTemplates"; public const string ReportTemplates = Default + ".ReportTemplates";
} }
public const string DevRequest = Prefix.App + ".DevRequest";
public const string DevRequests = Prefix.App + ".DevRequests";
} }
public static class AppErrorCodes public static class AppErrorCodes

View file

@ -71,6 +71,7 @@ public static class TableNameResolver
{ nameof(TableNameEnum.CustomEndpoint), (TablePrefix.PlatformByName, MenuPrefix.Saas) }, { nameof(TableNameEnum.CustomEndpoint), (TablePrefix.PlatformByName, MenuPrefix.Saas) },
{ nameof(TableNameEnum.CustomComponent), (TablePrefix.PlatformByName, MenuPrefix.Saas) }, { nameof(TableNameEnum.CustomComponent), (TablePrefix.PlatformByName, MenuPrefix.Saas) },
{ nameof(TableNameEnum.DynamicService), (TablePrefix.PlatformByName, MenuPrefix.Saas) }, { nameof(TableNameEnum.DynamicService), (TablePrefix.PlatformByName, MenuPrefix.Saas) },
{ nameof(TableNameEnum.DevRequest), (TablePrefix.PlatformByName, MenuPrefix.Saas) },
// 🔹 ADMINISTRATION TABLOLARI // 🔹 ADMINISTRATION TABLOLARI
{ nameof(TableNameEnum.Sector), (TablePrefix.TenantByName, MenuPrefix.Administration) }, { nameof(TableNameEnum.Sector), (TablePrefix.TenantByName, MenuPrefix.Administration) },

View file

@ -483,6 +483,8 @@ public static class SeedConsts
public const string Categories = Default + ".Categories"; public const string Categories = Default + ".Categories";
public const string ReportTemplates = Default + ".ReportTemplates"; public const string ReportTemplates = Default + ".ReportTemplates";
} }
public const string DevRequest = Prefix.App + ".DevRequest";
public const string DevRequests = Prefix.App + ".DevRequests";
} }
public static class DataSources public static class DataSources

View file

@ -0,0 +1,28 @@
using System;
using Volo.Abp.Domain.Entities.Auditing;
namespace Sozsoft.Platform.Entities;
public class DevRequest : FullAuditedEntity<Guid>
{
public Guid? TenantId { get; set; }
public string UserName { get; set; } = null!;
public DateTime? RequestDate { get; set; }
public string? Title { get; set; }
public string? Status { get; set; }
public string? Description { get; set; }
public DateTime? DueDate { get; set; }
public string? Tags { get; set; }
public string? Assignees { get; set; }
public string? Priority { get; set; }
public bool? Completed { get; set; }
public int? SortOrder { get; set; }
public DevRequest(Guid id)
{
Id = id;
}
}

View file

@ -75,7 +75,7 @@ public class DefaultValueManager : PlatformDomainService, IDefaultValueManager
if (defaultField.Value == PlatformConsts.DefaultValues.UserId) if (defaultField.Value == PlatformConsts.DefaultValues.UserId)
value = CurrentUser.Id; value = CurrentUser.Id;
else if (defaultField.Value == PlatformConsts.DefaultValues.UserName) else if (defaultField.Value == PlatformConsts.DefaultValues.UserName)
value = CurrentUser.Name; value = CurrentUser.UserName;
else if (defaultField.Value == PlatformConsts.DefaultValues.Roles) else if (defaultField.Value == PlatformConsts.DefaultValues.Roles)
value = CurrentUser.Roles; //.JoinAsString("','"); value = CurrentUser.Roles; //.JoinAsString("','");
else if (defaultField.Value == PlatformConsts.DefaultValues.Date) else if (defaultField.Value == PlatformConsts.DefaultValues.Date)

View file

@ -103,6 +103,7 @@ public class PlatformDbContext :
public DbSet<Contact> Contacts { get; set; } public DbSet<Contact> Contacts { get; set; }
public DbSet<Sector> Sectors { get; set; } public DbSet<Sector> Sectors { get; set; }
public DbSet<SkillType> SkillTypes { get; set; } public DbSet<SkillType> SkillTypes { get; set; }
public DbSet<DevRequest> DevRequests { get; set; }
// Dynamic Services // Dynamic Services
public DbSet<Skill> Skills { get; set; } public DbSet<Skill> Skills { get; set; }
@ -1583,6 +1584,23 @@ public class PlatformDbContext :
b.Property(x => x.Note).HasMaxLength(4000); b.Property(x => x.Note).HasMaxLength(4000);
}); });
builder.Entity<DevRequest>(b =>
{
b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.DevRequest)), Prefix.DbSchema);
b.ConfigureByConvention();
b.Property(e => e.UserName).HasMaxLength(50).IsRequired();
b.Property(e => e.Title).HasMaxLength(300).IsRequired();
b.Property(e => e.Status).HasMaxLength(50).IsRequired();
b.Property(e => e.Description).HasColumnType("text");
b.Property(e => e.Tags).HasMaxLength(300);
b.Property(e => e.Assignees).HasMaxLength(300);
b.Property(e => e.Priority).HasMaxLength(50);
b.Property(e => e.Completed).HasDefaultValue(false);
b.Property(e => e.SortOrder).HasDefaultValue(0);
});
ConfigureProviderSpecificModel(builder); ConfigureProviderSpecificModel(builder);
} }

View file

@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore;
namespace Sozsoft.Platform.Migrations namespace Sozsoft.Platform.Migrations
{ {
[DbContext(typeof(PlatformDbContext))] [DbContext(typeof(PlatformDbContext))]
[Migration("20260717065637_Initial")] [Migration("20260730083424_Initial")]
partial class Initial partial class Initial
{ {
/// <inheritdoc /> /// <inheritdoc />
@ -2217,6 +2217,95 @@ namespace Sozsoft.Platform.Migrations
b.ToTable("Adm_T_Department", (string)null); b.ToTable("Adm_T_Department", (string)null);
}); });
modelBuilder.Entity("Sozsoft.Platform.Entities.DevRequest", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<string>("Assignees")
.HasMaxLength(300)
.HasColumnType("nvarchar(300)");
b.Property<bool?>("Completed")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false);
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime2")
.HasColumnName("DeletionTime");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<DateTime?>("DueDate")
.HasColumnType("datetime2");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<string>("Priority")
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.Property<DateTime?>("RequestDate")
.HasColumnType("datetime2");
b.Property<int?>("SortOrder")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasDefaultValue(0);
b.Property<string>("Status")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.Property<string>("Tags")
.HasMaxLength(300)
.HasColumnType("nvarchar(300)");
b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier");
b.Property<string>("Title")
.IsRequired()
.HasMaxLength(300)
.HasColumnType("nvarchar(300)");
b.Property<string>("UserName")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.HasKey("Id");
b.ToTable("Sas_H_DevRequest", (string)null);
});
modelBuilder.Entity("Sozsoft.Platform.Entities.District", b => modelBuilder.Entity("Sozsoft.Platform.Entities.District", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")

View file

@ -1249,6 +1249,36 @@ namespace Sozsoft.Platform.Migrations
table.PrimaryKey("PK_Sas_H_Demo", x => x.Id); table.PrimaryKey("PK_Sas_H_Demo", x => x.Id);
}); });
migrationBuilder.CreateTable(
name: "Sas_H_DevRequest",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
UserName = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
RequestDate = table.Column<DateTime>(type: "datetime2", nullable: true),
Title = table.Column<string>(type: "nvarchar(300)", maxLength: 300, nullable: false),
Status = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
Description = table.Column<string>(type: "text", nullable: true),
DueDate = table.Column<DateTime>(type: "datetime2", nullable: true),
Tags = table.Column<string>(type: "nvarchar(300)", maxLength: 300, nullable: true),
Assignees = table.Column<string>(type: "nvarchar(300)", maxLength: 300, nullable: true),
Priority = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: true),
Completed = table.Column<bool>(type: "bit", nullable: true, defaultValue: false),
SortOrder = table.Column<int>(type: "int", nullable: true, defaultValue: 0),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Sas_H_DevRequest", x => x.Id);
});
migrationBuilder.CreateTable( migrationBuilder.CreateTable(
name: "Sas_H_DynamicService", name: "Sas_H_DynamicService",
columns: table => new columns: table => new
@ -4462,6 +4492,9 @@ namespace Sozsoft.Platform.Migrations
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "Sas_H_Demo"); name: "Sas_H_Demo");
migrationBuilder.DropTable(
name: "Sas_H_DevRequest");
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "Sas_H_District"); name: "Sas_H_District");

View file

@ -2214,6 +2214,95 @@ namespace Sozsoft.Platform.Migrations
b.ToTable("Adm_T_Department", (string)null); b.ToTable("Adm_T_Department", (string)null);
}); });
modelBuilder.Entity("Sozsoft.Platform.Entities.DevRequest", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<string>("Assignees")
.HasMaxLength(300)
.HasColumnType("nvarchar(300)");
b.Property<bool?>("Completed")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false);
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime2")
.HasColumnName("DeletionTime");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<DateTime?>("DueDate")
.HasColumnType("datetime2");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<string>("Priority")
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.Property<DateTime?>("RequestDate")
.HasColumnType("datetime2");
b.Property<int?>("SortOrder")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasDefaultValue(0);
b.Property<string>("Status")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.Property<string>("Tags")
.HasMaxLength(300)
.HasColumnType("nvarchar(300)");
b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier");
b.Property<string>("Title")
.IsRequired()
.HasMaxLength(300)
.HasColumnType("nvarchar(300)");
b.Property<string>("UserName")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.HasKey("Id");
b.ToTable("Sas_H_DevRequest", (string)null);
});
modelBuilder.Entity("Sozsoft.Platform.Entities.District", b => modelBuilder.Entity("Sozsoft.Platform.Entities.District", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")

View file

@ -4,6 +4,89 @@ body {
font-size: 14px; /* bodyye font-size uygulanmaz */ font-size: 14px; /* bodyye font-size uygulanmaz */
} }
/*
* Shared list-view toolbar contract. Keep these dimensions centralized so
* switching between Grid, Tree, Todo, Gantt, Pivot, Chart, Scheduler and Card
* views does not visually resize or shift the toolbar.
*/
.list-view-toolbar-host.dx-toolbar,
.list-view-toolbar-host .dx-toolbar {
min-height: 37px !important;
padding: 0 !important;
border: 0 !important;
background-color: transparent !important;
font-size: 12px !important;
}
.list-view-toolbar-host.dx-toolbar .dx-toolbar-items-container,
.list-view-toolbar-host .dx-toolbar .dx-toolbar-items-container {
min-height: 37px !important;
height: 37px !important;
align-items: center !important;
}
.list-view-toolbar-host.dx-toolbar .dx-toolbar-before,
.list-view-toolbar-host.dx-toolbar .dx-toolbar-center,
.list-view-toolbar-host.dx-toolbar .dx-toolbar-after,
.list-view-toolbar-host .dx-toolbar .dx-toolbar-before,
.list-view-toolbar-host .dx-toolbar .dx-toolbar-center,
.list-view-toolbar-host .dx-toolbar .dx-toolbar-after {
height: 37px !important;
align-items: center !important;
}
.list-view-toolbar-host.dx-toolbar .dx-toolbar-item,
.list-view-toolbar-host .dx-toolbar .dx-toolbar-item {
padding: 0 2px !important;
}
.list-view-toolbar-host.dx-toolbar .dx-button,
.list-view-toolbar-host .dx-toolbar .dx-button {
min-height: 28px !important;
height: 28px !important;
}
.list-view-toolbar-host.dx-toolbar .dx-button-content,
.list-view-toolbar-host .dx-toolbar .dx-button-content {
min-height: 28px !important;
padding: 4px 6px !important;
}
.list-view-toolbar-host.dx-toolbar .dx-button-text,
.list-view-toolbar-host .dx-toolbar .dx-button-text {
font-size: 12px !important;
line-height: 20px !important;
font-weight: 400 !important;
text-transform: none !important;
}
.list-view-toolbar-host.dx-toolbar .dx-icon,
.list-view-toolbar-host .dx-toolbar .dx-icon {
font-size: 16px !important;
line-height: 20px !important;
}
.list-view-toolbar-host.dx-toolbar .dx-texteditor,
.list-view-toolbar-host .dx-toolbar .dx-texteditor {
min-height: 28px !important;
height: 28px !important;
font-size: 12px !important;
}
.list-view-toolbar-host.dx-toolbar .dx-texteditor-input,
.list-view-toolbar-host .dx-toolbar .dx-texteditor-input {
min-height: 28px !important;
height: 28px !important;
padding-block: 4px !important;
font-size: 12px !important;
line-height: 20px !important;
}
.list-view-toolbar-host.dx-toolbar .dx-toolbar-menu-container,
.list-view-toolbar-host .dx-toolbar .dx-toolbar-menu-container {
margin-left: 2px !important;
}
.list-card-view.dx-cardview { .list-card-view.dx-cardview {
padding: 0; padding: 0;
border-radius: 0; border-radius: 0;
@ -135,7 +218,7 @@ div.dialog-after-open > div.dialog-content.maximized {
} }
.dark .dx-datagrid-header-panel.pivot-toolbar-panel { .dark .dx-datagrid-header-panel.pivot-toolbar-panel {
background-color: #202020 !important; background-color: transparent !important;
} }
.dx-datagrid-header-panel.pivot-toolbar-panel .button, .dx-datagrid-header-panel.pivot-toolbar-panel .button,
@ -157,7 +240,8 @@ div.dialog-after-open > div.dialog-content.maximized {
} }
.dx-datagrid-header-panel.pivot-toolbar-panel > .dx-toolbar .dx-toolbar-items-container { .dx-datagrid-header-panel.pivot-toolbar-panel > .dx-toolbar .dx-toolbar-items-container {
min-height: 28px !important; min-height: 37px !important;
height: 37px !important;
} }
.dx-datagrid-header-panel.pivot-toolbar-panel > .dx-toolbar .dx-toolbar-before { .dx-datagrid-header-panel.pivot-toolbar-panel > .dx-toolbar .dx-toolbar-before {
@ -181,8 +265,8 @@ div.dialog-after-open > div.dialog-content.maximized {
.dx-datagrid-header-panel.pivot-toolbar-panel .chart-toolbar-search { .dx-datagrid-header-panel.pivot-toolbar-panel .chart-toolbar-search {
width: 160px; width: 160px;
height: 32px; height: 28px;
padding: 6px 12px 6px 34px; padding: 4px 12px 4px 34px;
border: 0 !important; border: 0 !important;
border-bottom: 1px solid #d1d5db !important; border-bottom: 1px solid #d1d5db !important;
border-radius: 0 !important; border-radius: 0 !important;

View file

@ -304,7 +304,7 @@ const TODO_COLUMNS: ColumnDefinition[] = [
dataType: 'nvarchar', dataType: 'nvarchar',
maxLength: '50', maxLength: '50',
isNullable: false, isNullable: false,
defaultValue: "N'Inbox'", defaultValue: "N'Backlog'",
description: 'Todo board column/status', description: 'Todo board column/status',
}, },
{ {

View file

@ -1068,7 +1068,7 @@ const CardView = (props: CardViewProps) => {
cardsPerRow={cardColumnCount} cardsPerRow={cardColumnCount}
allowColumnReordering={gridDto.gridOptions.columnOptionDto?.allowColumnReordering} allowColumnReordering={gridDto.gridOptions.columnOptionDto?.allowColumnReordering}
rtlEnabled={gridDto.gridOptions.columnOptionDto?.rtlEnabled} rtlEnabled={gridDto.gridOptions.columnOptionDto?.rtlEnabled}
className="list-card-view" className="list-card-view list-view-toolbar-host"
hoverStateEnabled={gridDto.gridOptions.columnOptionDto?.hoverStateEnabled} hoverStateEnabled={gridDto.gridOptions.columnOptionDto?.hoverStateEnabled}
remoteOperations={{ paging: true, filtering: true, sorting: true }} remoteOperations={{ paging: true, filtering: true, sorting: true }}
wordWrapEnabled={gridDto.gridOptions.rowDto?.whiteSpace !== 'nowrap'} wordWrapEnabled={gridDto.gridOptions.rowDto?.whiteSpace !== 'nowrap'}

View file

@ -365,7 +365,7 @@ const Chart = (props: ChartProps) => {
)} )}
{_listFormCode && chartOptions && ( {_listFormCode && chartOptions && (
<div className="p-1"> <div className="p-1">
<div className="dx-datagrid-header-panel pivot-toolbar-panel text-black dark:text-white"> <div className="list-view-toolbar-host dx-datagrid-header-panel pivot-toolbar-panel text-black dark:text-white">
<Toolbar width="100%"> <Toolbar width="100%">
<Item <Item
location="before" location="before"

View file

@ -371,6 +371,7 @@ const GanttView = (props: GanttViewProps) => {
ref={gridRef as any} ref={gridRef as any}
key={`Gantt-${listFormCode}-${ganttDataSource ? 'loaded' : 'loading'}`} key={`Gantt-${listFormCode}-${ganttDataSource ? 'loaded' : 'loading'}`}
id={'Gantt-' + listFormCode} id={'Gantt-' + listFormCode}
className="list-view-toolbar-host"
taskListWidth={taskListWidth} taskListWidth={taskListWidth}
scaleType={scaleType} scaleType={scaleType}
rootValue={ rootValue={

View file

@ -1415,6 +1415,7 @@ const Grid = (props: GridProps) => {
ref={gridRef as any} ref={gridRef as any}
key={'Grid-' + listFormCode} key={'Grid-' + listFormCode}
id={'Grid-' + listFormCode} id={'Grid-' + listFormCode}
className="list-view-toolbar-host"
height={ height={
gridDto.gridOptions.height > 0 gridDto.gridOptions.height > 0
? gridDto.gridOptions.height ? gridDto.gridOptions.height

View file

@ -443,7 +443,7 @@ const Pivot = (props: PivotProps) => {
)} )}
{gridDto && columnData && ( {gridDto && columnData && (
<div className="p-1"> <div className="p-1">
<div className="dx-datagrid-header-panel pivot-toolbar-panel text-black"> <div className="list-view-toolbar-host dx-datagrid-header-panel pivot-toolbar-panel text-black">
<Toolbar width="100%"> <Toolbar width="100%">
<Item <Item
location="before" location="before"

View file

@ -649,6 +649,7 @@ const SchedulerView = (props: SchedulerViewProps) => {
ref={schedulerRef as any} ref={schedulerRef as any}
key={`Scheduler-${listFormCode}-${schedulerDataSource ? 'loaded' : 'loading'}`} key={`Scheduler-${listFormCode}-${schedulerDataSource ? 'loaded' : 'loading'}`}
id={'Scheduler-' + listFormCode} id={'Scheduler-' + listFormCode}
className="list-view-toolbar-host"
dataSource={schedulerDataSource} dataSource={schedulerDataSource}
dateSerializationFormat="yyyy-MM-ddTHH:mm:ss" dateSerializationFormat="yyyy-MM-ddTHH:mm:ss"
textExpr={gridDto.gridOptions.schedulerOptionDto?.textExpr || 'text'} textExpr={gridDto.gridOptions.schedulerOptionDto?.textExpr || 'text'}

View file

@ -2,9 +2,17 @@ import type { GridDto, TodoOptionDto } from '@/proxy/form/models'
import type { IdentityUserDto } from '@/proxy/admin/models' import type { IdentityUserDto } from '@/proxy/admin/models'
import type { DataGridRef } from 'devextreme-react/data-grid' import type { DataGridRef } from 'devextreme-react/data-grid'
import type CustomStore from 'devextreme/data/custom_store' import type CustomStore from 'devextreme/data/custom_store'
import { HtmlEditor, ImageUpload, Item, MediaResizing, Toolbar } from 'devextreme-react/html-editor' import {
HtmlEditor,
ImageUpload,
Item as HtmlEditorItem,
MediaResizing,
Toolbar as HtmlEditorToolbar,
} from 'devextreme-react/html-editor'
import Toolbar, { Item as ToolbarItem } from 'devextreme-react/toolbar'
import TagBox from 'devextreme-react/tag-box' import TagBox from 'devextreme-react/tag-box'
import { AVATAR_URL } from '@/constants/app.constant' import { AVATAR_URL } from '@/constants/app.constant'
import { ROUTES_ENUM } from '@/routes/route.constant'
import { import {
fontFamilyOptions, fontFamilyOptions,
fontSizeOptions, fontSizeOptions,
@ -33,7 +41,10 @@ import { useListFormCustomDataSource } from './useListFormCustomDataSource'
import { useListFormStateStoring } from './useListFormStateStoring' import { useListFormStateStoring } from './useListFormStateStoring'
import { Avatar, Rate } from '@/components/ui' import { Avatar, Rate } from '@/components/ui'
import { getUsers } from '@/services/identity.service' import { getUsers } from '@/services/identity.service'
import { getTenants } from '@/services/tenant.service'
import { useLocalization } from '@/utils/hooks/useLocalization' import { useLocalization } from '@/utils/hooks/useLocalization'
import { usePermission } from '@/utils/hooks/usePermission'
import { usePWA } from '@/utils/hooks/usePWA'
dayjs.extend(relativeTime) dayjs.extend(relativeTime)
@ -69,6 +80,8 @@ interface UserOption {
const fieldValue = (row: TodoRow, field?: string) => (field ? row[field] : undefined) const fieldValue = (row: TodoRow, field?: string) => (field ? row[field] : undefined)
const tenantIdValue = (row: TodoRow) => row.TenantId ?? row.tenantId
const htmlToPlainText = (value: unknown) => { const htmlToPlainText = (value: unknown) => {
const html = String(value ?? '') const html = String(value ?? '')
if (!html) return '' if (!html) return ''
@ -146,6 +159,13 @@ const priorityLabel = (
const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => { const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
const options = gridDto.gridOptions.todoOptionDto as TodoOptionDto const options = gridDto.gridOptions.todoOptionDto as TodoOptionDto
const editingOptions = gridDto.gridOptions.editingOptionDto
const canAdd =
editingOptions?.allowAdding === true && Boolean(gridDto.gridOptions.insertServiceAddress)
const canUpdate =
editingOptions?.allowUpdating === true && Boolean(gridDto.gridOptions.updateServiceAddress)
const canDelete =
editingOptions?.allowDeleting === true && Boolean(gridDto.gridOptions.deleteServiceAddress)
const keyField = gridDto.gridOptions.keyFieldName ?? 'id' const keyField = gridDto.gridOptions.keyFieldName ?? 'id'
const stateStoring = gridDto.gridOptions.stateStoringDto const stateStoring = gridDto.gridOptions.stateStoringDto
const gridRef = useRef<DataGridRef<any, any>>() const gridRef = useRef<DataGridRef<any, any>>()
@ -172,10 +192,13 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
const [renamingStatus, setRenamingStatus] = useState(false) const [renamingStatus, setRenamingStatus] = useState(false)
const [columnConfig, setColumnConfig] = useState<StoredBoardColumns>() const [columnConfig, setColumnConfig] = useState<StoredBoardColumns>()
const [userOptions, setUserOptions] = useState<UserOption[]>([]) const [userOptions, setUserOptions] = useState<UserOption[]>([])
const [tenantNames, setTenantNames] = useState<Map<string, string>>(new Map())
const [usersLoading, setUsersLoading] = useState(false) const [usersLoading, setUsersLoading] = useState(false)
const columnConfigRef = useRef<StoredBoardColumns>({ columns: [], retired: [] }) const columnConfigRef = useRef<StoredBoardColumns>({ columns: [], retired: [] })
const dragActiveRef = useRef(false) const dragActiveRef = useRef(false)
const { translate } = useLocalization() const { translate } = useLocalization()
const { checkPermission } = usePermission()
const isPwaMode = usePWA()
const uncategorized = translate('::ListForms.TodoBoard.Uncategorized') const uncategorized = translate('::ListForms.TodoBoard.Uncategorized')
const clearDragState = useCallback(() => { const clearDragState = useCallback(() => {
@ -244,6 +267,27 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
} }
}, []) }, [])
useEffect(() => {
let cancelled = false
getTenants(0, 1000)
.then((response) => {
if (cancelled) return
setTenantNames(
new Map(
(response.data?.items ?? [])
.filter((tenant) => Boolean(tenant.id && tenant.name))
.map((tenant) => [String(tenant.id).toLowerCase(), tenant.name!] as const),
),
)
})
.catch((error) => console.error('Todo tenants load error:', error))
return () => {
cancelled = true
}
}, [])
const loadRows = async (dataSource: CustomStore<any, any>) => { const loadRows = async (dataSource: CustomStore<any, any>) => {
const result: any = await dataSource.load({ skip: 0, take: 1000, requireTotalCount: true }) const result: any = await dataSource.load({ skip: 0, take: 1000, requireTotalCount: true })
const loadedRows = Array.isArray(result) ? result : (result?.data ?? []) const loadedRows = Array.isArray(result) ? result : (result?.data ?? [])
@ -251,6 +295,72 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
return loadedRows as TodoRow[] return loadedRows as TodoRow[]
} }
const refreshData = async () => {
if (!store) return
const loadedRows = await loadRows(store)
if (!selected) return
const refreshed = loadedRows.find((row) => row[keyField] === selected[keyField])
if (refreshed) {
setSelected(refreshed)
setDraft({ ...refreshed })
} else {
setSelected(undefined)
}
}
const openFormManager = () => {
window.open(
ROUTES_ENUM.protected.saas.listFormManagement.edit.replace(':listFormCode', listFormCode),
isPwaMode ? '_self' : '_blank',
)
}
const renderToolbar = (showBackToBoard = false) => (
<Toolbar className="list-view-toolbar-host mt-1">
{showBackToBoard && (
<ToolbarItem
location="before"
widget="dxButton"
locateInMenu="auto"
showText="always"
options={{
icon: 'back',
text: translate('::ListForms.TodoBoard.BackToBoard'),
hint: translate('::ListForms.TodoBoard.BackToBoard'),
onClick: () => setSelected(undefined),
}}
/>
)}
<ToolbarItem
location="after"
widget="dxButton"
locateInMenu="auto"
showText="always"
options={{
icon: 'refresh',
text: translate('::ListForms.ListForm.Refresh'),
hint: translate('::ListForms.ListForm.Refresh'),
onClick: refreshData,
}}
/>
{checkPermission('App.Listforms.Listform.Update') && (
<ToolbarItem
location="after"
widget="dxButton"
locateInMenu="auto"
showText="always"
options={{
icon: 'preferences',
text: translate('::ListForms.ListForm.Manage'),
hint: translate('::ListForms.ListForm.Manage'),
onClick: openFormManager,
}}
/>
)}
</Toolbar>
)
useEffect(() => { useEffect(() => {
const dataSource = createSelectDataSource( const dataSource = createSelectDataSource(
gridDto.gridOptions, gridDto.gridOptions,
@ -398,6 +508,7 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
} }
const reorderColumn = (targetStatus: string) => { const reorderColumn = (targetStatus: string) => {
if (!canUpdate) return
if (!draggedColumn || draggedColumn === targetStatus) return if (!draggedColumn || draggedColumn === targetStatus) return
setStatuses((current) => { setStatuses((current) => {
const next = current.filter((status) => status !== draggedColumn) const next = current.filter((status) => status !== draggedColumn)
@ -410,6 +521,7 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
} }
const addStatus = () => { const addStatus = () => {
if (!canAdd) return
const nextName = newStatusName.trim() const nextName = newStatusName.trim()
if (!nextName) return if (!nextName) return
if (statuses.some((status) => status.toLocaleLowerCase() === nextName.toLocaleLowerCase())) { if (statuses.some((status) => status.toLocaleLowerCase() === nextName.toLocaleLowerCase())) {
@ -428,6 +540,7 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
} }
const deleteStatus = (status: string) => { const deleteStatus = (status: string) => {
if (!canDelete) return
const itemCount = itemsForStatus(status).length const itemCount = itemsForStatus(status).length
if (itemCount) { if (itemCount) {
setStatusNotice({ setStatusNotice({
@ -449,6 +562,7 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
} }
const renameStatus = async (status: string) => { const renameStatus = async (status: string) => {
if (!canUpdate) return
const nextName = statusName.trim() const nextName = statusName.trim()
if (!nextName || nextName === status) { if (!nextName || nextName === status) {
setEditingStatus(undefined) setEditingStatus(undefined)
@ -512,7 +626,13 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
const moveTodo = async (status: string, targetIndex: number, transferredKey?: string) => { const moveTodo = async (status: string, targetIndex: number, transferredKey?: string) => {
const effectiveKey = const effectiveKey =
draggedKey ?? rows.find((row) => String(row[keyField]) === transferredKey)?.[keyField] draggedKey ?? rows.find((row) => String(row[keyField]) === transferredKey)?.[keyField]
if (effectiveKey === undefined || !store || !options.statusExpr || !options.allowDragging) if (
effectiveKey === undefined ||
!store ||
!options.statusExpr ||
!options.allowDragging ||
!canUpdate
)
return return
const moved = rows.find((row) => row[keyField] === effectiveKey) const moved = rows.find((row) => row[keyField] === effectiveKey)
@ -556,7 +676,7 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
const addTodo = async (status: string) => { const addTodo = async (status: string) => {
const title = newTodoTitle.trim() const title = newTodoTitle.trim()
if (!title || !store || !options.titleExpr || !options.statusExpr) return if (!canAdd || !title || !store || !options.titleExpr || !options.statusExpr) return
const values: Record<string, any> = { const values: Record<string, any> = {
[options.titleExpr]: title, [options.titleExpr]: title,
@ -578,7 +698,7 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
} }
const deleteTodo = async (row: TodoRow) => { const deleteTodo = async (row: TodoRow) => {
if (!store || !gridDto.gridOptions.deleteServiceAddress) return if (!canDelete || !store) return
if ( if (
!window.confirm( !window.confirm(
translate('::ListForms.TodoBoard.ConfirmDeleteTodo', { translate('::ListForms.TodoBoard.ConfirmDeleteTodo', {
@ -597,8 +717,8 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
setDraft({ ...row }) setDraft({ ...row })
} }
const saveTodo = async () => { const saveTodo = async (exitAfterSave = false) => {
if (!selected || !store || !gridDto.gridOptions.updateServiceAddress) return if (!canUpdate || !selected || !store) return
const mappedFields = [ const mappedFields = [
options.titleExpr, options.titleExpr,
options.statusExpr, options.statusExpr,
@ -619,14 +739,15 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
setRows((current) => setRows((current) =>
current.map((row) => (row[keyField] === selected[keyField] ? updated : row)), current.map((row) => (row[keyField] === selected[keyField] ? updated : row)),
) )
setSelected(updated)
setDraft(updated) setDraft(updated)
setSelected(exitAfterSave ? undefined : updated)
} finally { } finally {
setSaving(false) setSaving(false)
} }
} }
const updateTodoInline = async (row: TodoRow, values: Record<string, any>) => { const updateTodoInline = async (row: TodoRow, values: Record<string, any>) => {
if (!canUpdate) return
const updated = { ...row, ...values } const updated = { ...row, ...values }
setRows((current) => current.map((item) => (item[keyField] === row[keyField] ? updated : item))) setRows((current) => current.map((item) => (item[keyField] === row[keyField] ? updated : item)))
if (selected?.[keyField] === row[keyField]) { if (selected?.[keyField] === row[keyField]) {
@ -646,37 +767,23 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
) )
if (selected) { if (selected) {
const canEdit = Boolean(gridDto.gridOptions.updateServiceAddress)
const inputClass = const inputClass =
'w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm outline-none transition focus:border-blue-500 focus:ring-2 focus:ring-blue-500/20 disabled:bg-gray-100 dark:border-gray-600 dark:bg-gray-800 dark:disabled:bg-gray-900' 'w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm outline-none transition focus:border-blue-500 focus:ring-2 focus:ring-blue-500/20 disabled:bg-gray-100 dark:border-gray-600 dark:bg-gray-800 dark:disabled:bg-gray-900'
const labelClass = 'mb-1.5 block text-xs font-semibold uppercase tracking-wide text-gray-500' const labelClass = 'mb-1.5 block text-xs font-semibold uppercase tracking-wide text-gray-500'
const selectedTenantId = tenantIdValue(selected)
const selectedTenantName = selectedTenantId
? tenantNames.get(String(selectedTenantId).toLowerCase())
: undefined
return ( return (
<section className="min-h-[420px] rounded-xl py-5 shadow-sm"> <section className="min-h-[420px] rounded-xl shadow-sm">
<div className="mb-6 flex items-center justify-between border-b border-gray-200 pb-4 dark:border-gray-700"> {renderToolbar(true)}
<button <div className="mb-6 flex justify-end border-b border-gray-200 dark:border-gray-700">
type="button" {editingOptions?.allowUpdating === true &&
className="inline-flex items-center gap-2 text-sm text-gray-500 hover:text-blue-500" !gridDto.gridOptions.updateServiceAddress && (
onClick={() => setSelected(undefined)}
>
<FaArrowLeft /> {translate('::ListForms.TodoBoard.BackToBoard')}
</button>
<div className="flex items-center gap-2">
{!canEdit && (
<span className="text-xs text-amber-600"> <span className="text-xs text-amber-600">
{translate('::ListForms.TodoBoard.EditRequiresUpdateService')} {translate('::ListForms.TodoBoard.EditRequiresUpdateService')}
</span> </span>
)} )}
{gridDto.gridOptions.deleteServiceAddress && (
<button
type="button"
className="rounded-lg p-2 text-gray-400 hover:bg-red-50 hover:text-red-500 dark:hover:bg-red-950"
title={translate('::ListForms.TodoBoard.DeleteTodo')}
onClick={() => deleteTodo(selected)}
>
<FaTrash />
</button>
)}
</div>
</div> </div>
<div className="grid gap-5 lg:grid-cols-3"> <div className="grid gap-5 lg:grid-cols-3">
<div className="space-y-5 lg:col-span-2"> <div className="space-y-5 lg:col-span-2">
@ -685,7 +792,7 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
<label className={labelClass}>{translate('::ListForms.TodoBoard.Title')}</label> <label className={labelClass}>{translate('::ListForms.TodoBoard.Title')}</label>
<input <input
className={`${inputClass} text-lg font-semibold`} className={`${inputClass} text-lg font-semibold`}
disabled={!canEdit} disabled={!canUpdate}
value={String(draft[options.titleExpr] ?? '')} value={String(draft[options.titleExpr] ?? '')}
onChange={(event) => onChange={(event) =>
setDraft((current) => ({ setDraft((current) => ({
@ -704,7 +811,7 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
<HtmlEditor <HtmlEditor
height={220} height={220}
placeholder={translate('::ListForms.TodoBoard.DescriptionPlaceholder')} placeholder={translate('::ListForms.TodoBoard.DescriptionPlaceholder')}
readOnly={!canEdit} readOnly={!canUpdate}
value={String(draft[options.descriptionExpr] ?? '')} value={String(draft[options.descriptionExpr] ?? '')}
onValueChanged={(event) => onValueChanged={(event) =>
setDraft((current) => ({ setDraft((current) => ({
@ -715,36 +822,48 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
> >
<MediaResizing enabled={true} /> <MediaResizing enabled={true} />
<ImageUpload fileUploadMode="base64" /> <ImageUpload fileUploadMode="base64" />
<Toolbar multiline> <HtmlEditorToolbar multiline>
<Item name="undo" /> <HtmlEditorItem name="undo" />
<Item name="redo" /> <HtmlEditorItem name="redo" />
<Item name="separator" /> <HtmlEditorItem name="separator" />
<Item name="size" acceptedValues={sizeValues} options={fontSizeOptions} /> <HtmlEditorItem
<Item name="font" acceptedValues={fontValues} options={fontFamilyOptions} /> name="size"
<Item name="separator" /> acceptedValues={sizeValues}
<Item name="bold" /> options={fontSizeOptions}
<Item name="italic" /> />
<Item name="underline" /> <HtmlEditorItem
<Item name="strike" /> name="font"
<Item name="separator" /> acceptedValues={fontValues}
<Item name="orderedList" /> options={fontFamilyOptions}
<Item name="bulletList" /> />
<Item name="separator" /> <HtmlEditorItem name="separator" />
<Item name="header" acceptedValues={headerValues} options={headerOptions} /> <HtmlEditorItem name="bold" />
<Item name="separator" /> <HtmlEditorItem name="italic" />
<Item name="color" /> <HtmlEditorItem name="underline" />
<Item name="background" /> <HtmlEditorItem name="strike" />
<Item name="separator" /> <HtmlEditorItem name="separator" />
<Item name="alignLeft" /> <HtmlEditorItem name="orderedList" />
<Item name="alignCenter" /> <HtmlEditorItem name="bulletList" />
<Item name="alignRight" /> <HtmlEditorItem name="separator" />
<Item name="alignJustify" /> <HtmlEditorItem
<Item name="separator" /> name="header"
<Item name="link" /> acceptedValues={headerValues}
<Item name="image" /> options={headerOptions}
<Item name="separator" /> />
<Item name="clear" /> <HtmlEditorItem name="separator" />
</Toolbar> <HtmlEditorItem name="color" />
<HtmlEditorItem name="background" />
<HtmlEditorItem name="separator" />
<HtmlEditorItem name="alignLeft" />
<HtmlEditorItem name="alignCenter" />
<HtmlEditorItem name="alignRight" />
<HtmlEditorItem name="alignJustify" />
<HtmlEditorItem name="separator" />
<HtmlEditorItem name="link" />
<HtmlEditorItem name="image" />
<HtmlEditorItem name="separator" />
<HtmlEditorItem name="clear" />
</HtmlEditorToolbar>
</HtmlEditor> </HtmlEditor>
</div> </div>
)} )}
@ -758,7 +877,7 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
searchEnabled searchEnabled
showClearButton showClearButton
showSelectionControls showSelectionControls
disabled={!canEdit || usersLoading} disabled={!canUpdate || usersLoading}
displayExpr="label" displayExpr="label"
items={assigneeOptions} items={assigneeOptions}
valueExpr="value" valueExpr="value"
@ -789,7 +908,7 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
searchEnabled searchEnabled
showClearButton showClearButton
showSelectionControls showSelectionControls
disabled={!canEdit} disabled={!canUpdate}
items={tagSuggestions} items={tagSuggestions}
value={draftTags} value={draftTags}
applyValueMode="instantly" applyValueMode="instantly"
@ -812,12 +931,22 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
</div> </div>
</div> </div>
<aside className="space-y-4 rounded-xl bg-gray-50 p-4 dark:bg-gray-800/60"> <aside className="space-y-4 rounded-xl bg-gray-50 p-4 dark:bg-gray-800/60">
{selectedTenantId && (
<div>
<label className={labelClass}>Tenant</label>
<input
readOnly
className={`${inputClass} cursor-default`}
value={selectedTenantName ?? ''}
/>
</div>
)}
{options.statusExpr && ( {options.statusExpr && (
<div> <div>
<label className={labelClass}>{translate('::ListForms.TodoBoard.Status')}</label> <label className={labelClass}>{translate('::ListForms.TodoBoard.Status')}</label>
<select <select
className={inputClass} className={inputClass}
disabled={!canEdit} disabled={!canUpdate}
value={String(draft[options.statusExpr] ?? '')} value={String(draft[options.statusExpr] ?? '')}
onChange={(event) => onChange={(event) =>
setDraft((current) => ({ setDraft((current) => ({
@ -840,7 +969,7 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
<input <input
type="datetime-local" type="datetime-local"
className={inputClass} className={inputClass}
disabled={!canEdit} disabled={!canUpdate}
value={ value={
draft[options.dueDateExpr] draft[options.dueDateExpr]
? dayjs(draft[options.dueDateExpr]).format('YYYY-MM-DDTHH:mm') ? dayjs(draft[options.dueDateExpr]).format('YYYY-MM-DDTHH:mm')
@ -862,7 +991,7 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
<Rate <Rate
allowClear allowClear
color="yellow" color="yellow"
disabled={!canEdit} disabled={!canUpdate}
gap={7} gap={7}
size={24} size={24}
tooltips={[ tooltips={[
@ -891,7 +1020,7 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
<input <input
type="checkbox" type="checkbox"
className="h-4 w-4 accent-emerald-500" className="h-4 w-4 accent-emerald-500"
disabled={!canEdit} disabled={!canUpdate}
checked={isCompleted(draft[options.completedExpr])} checked={isCompleted(draft[options.completedExpr])}
onChange={(event) => onChange={(event) =>
setDraft((current) => ({ setDraft((current) => ({
@ -905,25 +1034,47 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
)} )}
</aside> </aside>
</div> </div>
{canEdit && ( {(canUpdate || canDelete) && (
<div className="mt-6 flex justify-end gap-2 border-t border-gray-200 pt-4 dark:border-gray-700"> <div className="mt-6 flex items-center justify-between gap-3 border-t border-gray-200 pt-4 dark:border-gray-700">
<button <div>
type="button" {canDelete && (
className="rounded-lg border border-gray-300 px-4 py-2 text-sm hover:bg-gray-50 dark:border-gray-600 dark:hover:bg-gray-800" <button
onClick={() => setDraft({ ...selected })} type="button"
> className="inline-flex items-center gap-2 rounded-lg border border-red-300 px-4 py-2 text-sm font-semibold text-red-600 hover:bg-red-50 dark:border-red-800 dark:text-red-400 dark:hover:bg-red-950"
{translate('::ListForms.TodoBoard.UndoChanges')} onClick={() => deleteTodo(selected)}
</button> >
<button <FaTrash />
type="button" {translate('::Delete')}
className="rounded-lg bg-blue-600 px-5 py-2 text-sm font-semibold text-white hover:bg-blue-700 disabled:opacity-50" </button>
disabled={saving || !String(draft[options.titleExpr ?? ''] ?? '').trim()} )}
onClick={saveTodo} </div>
> {canUpdate && (
{saving <div className="flex items-center gap-2">
? translate('::Saving') <button
: translate('::Save')} type="button"
</button> className="rounded-lg border border-gray-300 px-4 py-2 text-sm hover:bg-gray-50 dark:border-gray-600 dark:hover:bg-gray-800"
onClick={() => setDraft({ ...selected })}
>
{translate('::ListForms.TodoBoard.UndoChanges')}
</button>
<button
type="button"
className="rounded-lg bg-blue-600 px-5 py-2 text-sm font-semibold text-white hover:bg-blue-700 disabled:opacity-50"
disabled={saving || !String(draft[options.titleExpr ?? ''] ?? '').trim()}
onClick={() => saveTodo()}
>
{saving ? translate('::Saving') : translate('::Save')}
</button>
<button
type="button"
className="rounded-lg bg-emerald-600 px-5 py-2 text-sm font-semibold text-white hover:bg-emerald-700 disabled:opacity-50"
disabled={saving || !String(draft[options.titleExpr ?? ''] ?? '').trim()}
onClick={() => saveTodo(true)}
>
{saving ? translate('::Saving') : translate('::ListForms.TodoBoard.SaveAndExit')}
</button>
</div>
)}
</div> </div>
)} )}
</section> </section>
@ -932,8 +1083,9 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
return ( return (
<div className="pb-3"> <div className="pb-3">
{renderToolbar()}
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<div className="flex min-h-[420px] min-w-max gap-3 pt-3"> <div className="flex min-h-[420px] min-w-max gap-3">
{statuses.map((status) => { {statuses.map((status) => {
const items = itemsForStatus(status) const items = itemsForStatus(status)
const isAdding = newTodoStatus === status const isAdding = newTodoStatus === status
@ -963,8 +1115,8 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
> >
<header className="mb-2 flex min-h-9 items-center gap-2 px-1"> <header className="mb-2 flex min-h-9 items-center gap-2 px-1">
<span <span
draggable draggable={canUpdate}
className="cursor-grab rounded p-1 text-gray-400 hover:bg-gray-200 hover:text-gray-600 active:cursor-grabbing dark:hover:bg-gray-700" className={`rounded p-1 text-gray-400 ${canUpdate ? 'cursor-grab hover:bg-gray-200 hover:text-gray-600 active:cursor-grabbing dark:hover:bg-gray-700' : 'cursor-default opacity-50'}`}
title={translate('::ListForms.TodoBoard.ReorderColumn')} title={translate('::ListForms.TodoBoard.ReorderColumn')}
onDragStart={(event) => { onDragStart={(event) => {
event.stopPropagation() event.stopPropagation()
@ -1027,24 +1179,26 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
<h4 className="min-w-0 truncate font-sm" title={status}> <h4 className="min-w-0 truncate font-sm" title={status}>
{status} {status}
</h4> </h4>
<button {canUpdate && (
type="button" <button
className="rounded p-1 text-gray-400 opacity-0 transition hover:bg-gray-200 hover:text-blue-600 group-hover:opacity-100 dark:hover:bg-gray-700" type="button"
title={translate('::ListForms.TodoBoard.RenameColumn')} className="rounded p-1 text-gray-400 opacity-0 transition hover:bg-gray-200 hover:text-blue-600 group-hover:opacity-100 dark:hover:bg-gray-700"
onClick={() => { title={translate('::ListForms.TodoBoard.RenameColumn')}
setEditingStatus(status) onClick={() => {
setStatusName(status) setEditingStatus(status)
setStatusError('') setStatusName(status)
}} setStatusError('')
> }}
<FaPencilAlt className="text-xs" /> >
</button> <FaPencilAlt className="text-xs" />
</button>
)}
</> </>
)} )}
<span className="ml-auto rounded-full bg-gray-200 px-2 py-0.5 text-xs dark:bg-gray-700"> <span className="ml-auto rounded-full bg-gray-200 px-2 py-0.5 text-xs dark:bg-gray-700">
{items.length} {items.length}
</span> </span>
{gridDto.gridOptions.insertServiceAddress && ( {canAdd && (
<button <button
type="button" type="button"
draggable={false} draggable={false}
@ -1058,20 +1212,22 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
<FaPlus /> <FaPlus />
</button> </button>
)} )}
<button {canDelete && (
type="button" <button
draggable={false} type="button"
aria-disabled={items.length > 0} draggable={false}
className={`rounded p-1 transition ${items.length ? 'cursor-not-allowed text-gray-300 dark:text-gray-600' : 'text-gray-400 hover:bg-red-100 hover:text-red-600 dark:hover:bg-red-950'}`} aria-disabled={items.length > 0}
title={ className={`rounded p-1 transition ${items.length ? 'cursor-not-allowed text-gray-300 dark:text-gray-600' : 'text-gray-400 hover:bg-red-100 hover:text-red-600 dark:hover:bg-red-950'}`}
items.length title={
? translate('::ListForms.TodoBoard.ColumnWithTodosCannotBeDeleted') items.length
: translate('::ListForms.TodoBoard.DeleteColumn') ? translate('::ListForms.TodoBoard.ColumnWithTodosCannotBeDeleted')
} : translate('::ListForms.TodoBoard.DeleteColumn')
onClick={() => deleteStatus(status)} }
> onClick={() => deleteStatus(status)}
<FaTrash className="text-xs" /> >
</button> <FaTrash className="text-xs" />
</button>
)}
</header> </header>
{editingStatus === status && statusError && ( {editingStatus === status && statusError && (
<p className="mb-2 px-1 text-xs text-red-500">{statusError}</p> <p className="mb-2 px-1 text-xs text-red-500">{statusError}</p>
@ -1135,6 +1291,10 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
const due = fieldValue(row, options.dueDateExpr) const due = fieldValue(row, options.dueDateExpr)
const completed = isCompleted(fieldValue(row, options.completedExpr)) const completed = isCompleted(fieldValue(row, options.completedExpr))
const priority = fieldValue(row, options.priorityExpr) const priority = fieldValue(row, options.priorityExpr)
const tenantId = tenantIdValue(row)
const tenantName = tenantId
? tenantNames.get(String(tenantId).toLowerCase())
: undefined
const isDragged = draggedKey === key const isDragged = draggedKey === key
const hiddenAssigneeLabels = assignees const hiddenAssigneeLabels = assignees
.slice(2) .slice(2)
@ -1151,7 +1311,7 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
</div> </div>
)} )}
<article <article
draggable={Boolean(options.allowDragging)} draggable={Boolean(options.allowDragging && canUpdate)}
className={`group/card cursor-pointer rounded border bg-white p-3 shadow-sm transition hover:-translate-y-0.5 hover:shadow-md dark:bg-gray-800 ${isDragged ? 'scale-95 border-blue-400 opacity-35' : completed ? 'border-emerald-300 opacity-75 dark:border-emerald-800' : 'border-gray-200 dark:border-gray-700'}`} className={`group/card cursor-pointer rounded border bg-white p-3 shadow-sm transition hover:-translate-y-0.5 hover:shadow-md dark:bg-gray-800 ${isDragged ? 'scale-95 border-blue-400 opacity-35' : completed ? 'border-emerald-300 opacity-75 dark:border-emerald-800' : 'border-gray-200 dark:border-gray-700'}`}
onDragStart={(event) => { onDragStart={(event) => {
event.stopPropagation() event.stopPropagation()
@ -1187,7 +1347,7 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
</span> </span>
</h4> </h4>
<div className="ml-auto flex items-center gap-1"> <div className="ml-auto flex items-center gap-1">
{gridDto.gridOptions.deleteServiceAddress && ( {canDelete && (
<button <button
type="button" type="button"
className="hidden rounded p-1 text-gray-400 hover:bg-red-50 hover:text-red-500 group-hover/card:block dark:hover:bg-red-950" className="hidden rounded p-1 text-gray-400 hover:bg-red-50 hover:text-red-500 group-hover/card:block dark:hover:bg-red-950"
@ -1202,6 +1362,14 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
)} )}
</div> </div>
</div> </div>
{tenantName && (
<div
className="mt-1 text-[11px] text-gray-500 dark:text-gray-400"
title={tenantName}
>
{tenantName}
</div>
)}
{fieldValue(row, options.descriptionExpr) && ( {fieldValue(row, options.descriptionExpr) && (
<p className="mt-1 line-clamp-2 text-xs leading-5 text-gray-500 dark:text-gray-400"> <p className="mt-1 line-clamp-2 text-xs leading-5 text-gray-500 dark:text-gray-400">
{htmlToPlainText(fieldValue(row, options.descriptionExpr))} {htmlToPlainText(fieldValue(row, options.descriptionExpr))}
@ -1223,6 +1391,7 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
<Rate <Rate
allowClear allowClear
color="yellow" color="yellow"
disabled={!canUpdate}
gap={2} gap={2}
size={14} size={14}
value={priorityRating(priority)} value={priorityRating(priority)}
@ -1285,6 +1454,7 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
<button <button
type="button" type="button"
draggable={false} draggable={false}
disabled={!canUpdate}
className={`ml-1 shrink-0 rounded-full p-1 text-lg transition ${completed ? 'text-emerald-500 hover:bg-emerald-50 dark:hover:bg-emerald-950' : 'text-gray-400 hover:bg-gray-100 hover:text-emerald-500 dark:hover:bg-gray-700'}`} className={`ml-1 shrink-0 rounded-full p-1 text-lg transition ${completed ? 'text-emerald-500 hover:bg-emerald-50 dark:hover:bg-emerald-950' : 'text-gray-400 hover:bg-gray-100 hover:text-emerald-500 dark:hover:bg-gray-700'}`}
title={ title={
completed completed
@ -1319,94 +1489,96 @@ const TodoBoard = ({ listFormCode, searchParams, gridDto }: TodoBoardProps) => {
</section> </section>
) )
})} })}
<section className="group w-[310px] shrink-0 rounded-xl border-2 border-transparent bg-gray-50 p-2 dark:bg-gray-900/60"> {canAdd && (
<header className="mb-2 flex min-h-9 items-center gap-2 px-1"> <section className="group w-[310px] shrink-0 rounded-xl border-2 border-transparent bg-gray-50 p-2 dark:bg-gray-900/60">
<FaGripVertical className="text-gray-300 dark:text-gray-700" /> <header className="mb-2 flex min-h-9 items-center gap-2 px-1">
<h3 className="font-semibold text-gray-500 dark:text-gray-400"> <FaGripVertical className="text-gray-300 dark:text-gray-700" />
{translate('::ListForms.TodoBoard.NewColumn')} <h3 className="font-semibold text-gray-500 dark:text-gray-400">
</h3> {translate('::ListForms.TodoBoard.NewColumn')}
<span className="ml-auto rounded-full bg-gray-200 px-2 py-0.5 text-xs text-gray-500 dark:bg-gray-700 dark:text-gray-400"> </h3>
0 <span className="ml-auto rounded-full bg-gray-200 px-2 py-0.5 text-xs text-gray-500 dark:bg-gray-700 dark:text-gray-400">
</span> 0
<button </span>
type="button"
className="rounded p-1 text-gray-400 hover:bg-blue-100 hover:text-blue-600 dark:hover:bg-blue-950"
title={translate('::ListForms.TodoBoard.AddNewColumn')}
onClick={() => {
setIsAddingStatus(true)
setStatusError('')
}}
>
<FaPlus />
</button>
</header>
<div className="h-1 overflow-hidden rounded-full bg-gray-200 dark:bg-gray-700" />
<div className="mt-3">
{isAddingStatus ? (
<form
className="rounded-lg border border-blue-300 bg-white p-3 shadow-sm dark:border-blue-800 dark:bg-gray-800"
onSubmit={(event) => {
event.preventDefault()
addStatus()
}}
>
<label className="mb-2 block text-sm font-semibold" htmlFor="new-kanban-name">
{translate('::ListForms.TodoBoard.NewColumnName')}
</label>
<input
autoFocus
id="new-kanban-name"
className="w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm outline-none focus:border-blue-500 focus:ring-2 focus:ring-blue-500/20 dark:border-gray-600 dark:bg-gray-800"
placeholder={translate('::ListForms.TodoBoard.NewColumnPlaceholder')}
value={newStatusName}
onChange={(event) => {
setNewStatusName(event.target.value)
setStatusError('')
}}
onKeyDown={(event) => {
if (event.key === 'Escape') {
setIsAddingStatus(false)
setNewStatusName('')
setStatusError('')
}
}}
/>
{statusError && <p className="mt-2 text-xs text-red-500">{statusError}</p>}
<div className="mt-3 flex gap-2">
<button
type="submit"
className="rounded-lg bg-blue-600 px-3 py-2 text-xs font-semibold text-white hover:bg-blue-700 disabled:opacity-40"
disabled={!newStatusName.trim()}
>
{translate('::ListForms.TodoBoard.AddColumn')}
</button>
<button
type="button"
className="rounded-lg px-3 py-2 text-xs font-semibold text-gray-500 hover:bg-gray-200 dark:hover:bg-gray-800"
onClick={() => {
setIsAddingStatus(false)
setNewStatusName('')
setStatusError('')
}}
>
{translate('::Cancel')}
</button>
</div>
</form>
) : (
<button <button
type="button" type="button"
className="flex min-h-24 w-full items-center justify-center gap-2 rounded-lg border-2 border-dashed border-gray-200 px-4 text-sm font-medium text-gray-400 transition hover:border-blue-400 hover:bg-blue-50 hover:text-blue-600 dark:border-gray-700 dark:hover:bg-blue-950/20" className="rounded p-1 text-gray-400 hover:bg-blue-100 hover:text-blue-600 dark:hover:bg-blue-950"
title={translate('::ListForms.TodoBoard.AddNewColumn')}
onClick={() => { onClick={() => {
setIsAddingStatus(true) setIsAddingStatus(true)
setStatusError('') setStatusError('')
}} }}
> >
<FaPlus /> {translate('::ListForms.TodoBoard.AddNewColumn')} <FaPlus />
</button> </button>
)} </header>
</div> <div className="h-1 overflow-hidden rounded-full bg-gray-200 dark:bg-gray-700" />
</section> <div className="mt-3">
{isAddingStatus ? (
<form
className="rounded-lg border border-blue-300 bg-white p-3 shadow-sm dark:border-blue-800 dark:bg-gray-800"
onSubmit={(event) => {
event.preventDefault()
addStatus()
}}
>
<label className="mb-2 block text-sm font-semibold" htmlFor="new-kanban-name">
{translate('::ListForms.TodoBoard.NewColumnName')}
</label>
<input
autoFocus
id="new-kanban-name"
className="w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm outline-none focus:border-blue-500 focus:ring-2 focus:ring-blue-500/20 dark:border-gray-600 dark:bg-gray-800"
placeholder={translate('::ListForms.TodoBoard.NewColumnPlaceholder')}
value={newStatusName}
onChange={(event) => {
setNewStatusName(event.target.value)
setStatusError('')
}}
onKeyDown={(event) => {
if (event.key === 'Escape') {
setIsAddingStatus(false)
setNewStatusName('')
setStatusError('')
}
}}
/>
{statusError && <p className="mt-2 text-xs text-red-500">{statusError}</p>}
<div className="mt-3 flex gap-2">
<button
type="submit"
className="rounded-lg bg-blue-600 px-3 py-2 text-xs font-semibold text-white hover:bg-blue-700 disabled:opacity-40"
disabled={!newStatusName.trim()}
>
{translate('::ListForms.TodoBoard.AddColumn')}
</button>
<button
type="button"
className="rounded-lg px-3 py-2 text-xs font-semibold text-gray-500 hover:bg-gray-200 dark:hover:bg-gray-800"
onClick={() => {
setIsAddingStatus(false)
setNewStatusName('')
setStatusError('')
}}
>
{translate('::Cancel')}
</button>
</div>
</form>
) : (
<button
type="button"
className="flex min-h-24 w-full items-center justify-center gap-2 rounded-lg border-2 border-dashed border-gray-200 px-4 text-sm font-medium text-gray-400 transition hover:border-blue-400 hover:bg-blue-50 hover:text-blue-600 dark:border-gray-700 dark:hover:bg-blue-950/20"
onClick={() => {
setIsAddingStatus(true)
setStatusError('')
}}
>
<FaPlus /> {translate('::ListForms.TodoBoard.AddNewColumn')}
</button>
)}
</div>
</section>
)}
</div> </div>
</div> </div>
</div> </div>

View file

@ -1049,6 +1049,7 @@ const Tree = (props: TreeProps) => {
<TreeListDx <TreeListDx
ref={gridRef as any} ref={gridRef as any}
id={'TreeList-' + listFormCode} id={'TreeList-' + listFormCode}
className="list-view-toolbar-host"
height={ height={
gridDto.gridOptions.height > 0 gridDto.gridOptions.height > 0
? gridDto.gridOptions.height ? gridDto.gridOptions.height