Gantt düzenlemesi

This commit is contained in:
Sedat Öztürk 2025-12-02 01:05:05 +03:00
parent 3e588fb98b
commit 7cf448ec13
19 changed files with 798 additions and 337 deletions

View file

@ -38,5 +38,25 @@ public class TreeOptionDto
/// Alt kayıtlar seçildiğinde parent kayıtları da seç (recursive selection) /// Alt kayıtlar seçildiğinde parent kayıtları da seç (recursive selection)
/// </summary> /// </summary>
public bool RecursiveSelection { get; set; } = false; public bool RecursiveSelection { get; set; } = false;
/// <summary>
/// Başlık alanı (örn: "Title")
/// </summary>
public string TitleExpr { get; set; }
/// <summary>
/// Başlangıç Tarihi ifadesi (örn: "0001-01-01")
/// </summary>
public string StartExpr { get; set; }
/// <summary>
/// Bitiş Tarihi ifadesi (örn: "9999-12-31")
/// </summary>
public string EndExpr { get; set; }
/// <summary>
/// İlerleme ifadesi (örn: "%50")
/// </summary>
public string ProgressExpr { get; set; }
} }

View file

@ -4561,6 +4561,30 @@
"en": "Parent Field Name", "en": "Parent Field Name",
"tr": "Üst Kimlik İfadesi" "tr": "Üst Kimlik İfadesi"
}, },
{
"resourceName": "Platform",
"key": "ListForms.ListFormEdit.TitleExpr",
"en": "Title Field Name",
"tr": "Başlık Alanı Adı"
},
{
"resourceName": "Platform",
"key": "ListForms.ListFormEdit.StartExpr",
"en": "Start Field Name",
"tr": "Başlangıç Alanı Adı"
},
{
"resourceName": "Platform",
"key": "ListForms.ListFormEdit.EndExpr",
"en": "End Field Name",
"tr": "Bitiş Alanı Adı"
},
{
"resourceName": "Platform",
"key": "ListForms.ListFormEdit.ProgressExpr",
"en": "Progress Field Name",
"tr": "İlerleme Alanı Adı"
},
{ {
"resourceName": "Platform", "resourceName": "Platform",
"key": "ListForms.ListFormEdit.RootValue", "key": "ListForms.ListFormEdit.RootValue",

View file

@ -53,7 +53,8 @@ public class ListFormSeeder_Project : IDataSeedContributor, ITransientDependency
var listForm = await _listFormRepository.InsertAsync( var listForm = await _listFormRepository.InsertAsync(
new ListForm() new ListForm()
{ {
ListFormType = ListFormTypeEnum.List, ExportJson = DefaultExportJson, ListFormType = ListFormTypeEnum.List,
ExportJson = DefaultExportJson,
IsSubForm = false, IsSubForm = false,
ShowNote = true, ShowNote = true,
LayoutJson = DefaultLayoutJson, LayoutJson = DefaultLayoutJson,
@ -176,7 +177,8 @@ public class ListFormSeeder_Project : IDataSeedContributor, ITransientDependency
var listForm = await _listFormRepository.InsertAsync( var listForm = await _listFormRepository.InsertAsync(
new ListForm() new ListForm()
{ {
ListFormType = ListFormTypeEnum.List, ExportJson = DefaultExportJson, ListFormType = ListFormTypeEnum.List,
ExportJson = DefaultExportJson,
IsSubForm = false, IsSubForm = false,
ShowNote = true, ShowNote = true,
LayoutJson = DefaultLayoutJson, LayoutJson = DefaultLayoutJson,
@ -299,7 +301,8 @@ public class ListFormSeeder_Project : IDataSeedContributor, ITransientDependency
var listForm = await _listFormRepository.InsertAsync( var listForm = await _listFormRepository.InsertAsync(
new ListForm() new ListForm()
{ {
ListFormType = ListFormTypeEnum.List, ExportJson = DefaultExportJson, ListFormType = ListFormTypeEnum.List,
ExportJson = DefaultExportJson,
IsSubForm = false, IsSubForm = false,
ShowNote = true, ShowNote = true,
LayoutJson = DefaultLayoutJson, LayoutJson = DefaultLayoutJson,
@ -422,7 +425,8 @@ public class ListFormSeeder_Project : IDataSeedContributor, ITransientDependency
var listForm = await _listFormRepository.InsertAsync( var listForm = await _listFormRepository.InsertAsync(
new ListForm() new ListForm()
{ {
ListFormType = ListFormTypeEnum.List, ExportJson = DefaultExportJson, ListFormType = ListFormTypeEnum.List,
ExportJson = DefaultExportJson,
IsSubForm = false, IsSubForm = false,
ShowNote = true, ShowNote = true,
LayoutJson = DefaultLayoutJson, LayoutJson = DefaultLayoutJson,
@ -545,7 +549,8 @@ public class ListFormSeeder_Project : IDataSeedContributor, ITransientDependency
var listForm = await _listFormRepository.InsertAsync( var listForm = await _listFormRepository.InsertAsync(
new ListForm() new ListForm()
{ {
ListFormType = ListFormTypeEnum.List, ExportJson = DefaultExportJson, ListFormType = ListFormTypeEnum.List,
ExportJson = DefaultExportJson,
IsSubForm = false, IsSubForm = false,
ShowNote = true, ShowNote = true,
LayoutJson = DefaultLayoutJson, LayoutJson = DefaultLayoutJson,
@ -668,7 +673,8 @@ public class ListFormSeeder_Project : IDataSeedContributor, ITransientDependency
var listForm = await _listFormRepository.InsertAsync( var listForm = await _listFormRepository.InsertAsync(
new ListForm() new ListForm()
{ {
ListFormType = ListFormTypeEnum.List, ExportJson = DefaultExportJson, ListFormType = ListFormTypeEnum.List,
ExportJson = DefaultExportJson,
IsSubForm = false, IsSubForm = false,
ShowNote = true, ShowNote = true,
LayoutJson = DefaultLayoutJson, LayoutJson = DefaultLayoutJson,
@ -791,7 +797,8 @@ public class ListFormSeeder_Project : IDataSeedContributor, ITransientDependency
var listForm = await _listFormRepository.InsertAsync( var listForm = await _listFormRepository.InsertAsync(
new ListForm() new ListForm()
{ {
ListFormType = ListFormTypeEnum.List, ExportJson = DefaultExportJson, ListFormType = ListFormTypeEnum.List,
ExportJson = DefaultExportJson,
IsSubForm = false, IsSubForm = false,
ShowNote = true, ShowNote = true,
LayoutJson = DefaultLayoutJson, LayoutJson = DefaultLayoutJson,
@ -1199,7 +1206,8 @@ public class ListFormSeeder_Project : IDataSeedContributor, ITransientDependency
var listForm = await _listFormRepository.InsertAsync( var listForm = await _listFormRepository.InsertAsync(
new ListForm() new ListForm()
{ {
ListFormType = ListFormTypeEnum.List, ExportJson = DefaultExportJson, ListFormType = ListFormTypeEnum.List,
ExportJson = DefaultExportJson,
IsSubForm = true, IsSubForm = true,
ShowNote = true, ShowNote = true,
LayoutJson = DefaultLayoutJson, LayoutJson = DefaultLayoutJson,
@ -1286,7 +1294,7 @@ public class ListFormSeeder_Project : IDataSeedContributor, ITransientDependency
var listForm = await _listFormRepository.InsertAsync( var listForm = await _listFormRepository.InsertAsync(
new ListForm() new ListForm()
{ {
ListFormType = ListFormTypeEnum.Tree, ListFormType = ListFormTypeEnum.List,
IsSubForm = true, IsSubForm = true,
ShowNote = true, ShowNote = true,
LayoutJson = DefaultLayoutJson, LayoutJson = DefaultLayoutJson,
@ -1422,7 +1430,8 @@ public class ListFormSeeder_Project : IDataSeedContributor, ITransientDependency
var listForm = await _listFormRepository.InsertAsync( var listForm = await _listFormRepository.InsertAsync(
new ListForm() new ListForm()
{ {
ListFormType = ListFormTypeEnum.List, ExportJson = DefaultExportJson, ListFormType = ListFormTypeEnum.List,
ExportJson = DefaultExportJson,
IsSubForm = false, IsSubForm = false,
ShowNote = true, ShowNote = true,
LayoutJson = DefaultLayoutJson, LayoutJson = DefaultLayoutJson,
@ -1774,7 +1783,8 @@ public class ListFormSeeder_Project : IDataSeedContributor, ITransientDependency
var listForm = await _listFormRepository.InsertAsync( var listForm = await _listFormRepository.InsertAsync(
new ListForm() new ListForm()
{ {
ListFormType = ListFormTypeEnum.List, ExportJson = DefaultExportJson, ListFormType = ListFormTypeEnum.List,
ExportJson = DefaultExportJson,
IsSubForm = false, IsSubForm = false,
ShowNote = true, ShowNote = true,
LayoutJson = DefaultLayoutJson, LayoutJson = DefaultLayoutJson,
@ -2059,6 +2069,196 @@ public class ListFormSeeder_Project : IDataSeedContributor, ITransientDependency
} }
#endregion #endregion
#region Project Task Workload
listFormName = AppCodes.Project.Workload;
if (!await _listFormRepository.AnyAsync(a => a.ListFormCode == listFormName))
{
var listForm = await _listFormRepository.InsertAsync(
new ListForm()
{
ListFormType = ListFormTypeEnum.List,
ExportJson = DefaultExportJson,
IsSubForm = false,
ShowNote = true,
LayoutJson = DefaultLayoutJson,
CultureName = LanguageCodes.En,
ListFormCode = listFormName,
Name = listFormName,
Title = listFormName,
DataSourceCode = SeedConsts.DataSources.DefaultCode,
IsTenant = true,
IsBranch = false,
IsOrganizationUnit = false,
Description = listFormName,
SelectCommandType = SelectCommandTypeEnum.Table,
SelectCommand = TableNameResolver.GetFullViewName(nameof(TableNameEnum.ProjectTask)),
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),
TreeOptionJson = JsonSerializer.Serialize(new TreeOptionDto
{
KeyExpr = "Id",
ParentIdExpr = "ParentId",
RootValue = null,
AutoExpandAll = true,
TitleExpr = "Name",
StartExpr = "StartDate",
EndExpr = "EndDate",
ProgressExpr = "Progress"
}),
DeleteCommand = DefaultDeleteCommand(nameof(TableNameEnum.ProjectTask)),
DeleteFieldsDefaultValueJson = DefaultDeleteFieldsDefaultValueJson,
PagerOptionJson = DefaultPagerOptionJson,
EditingOptionJson = DefaultEditingOptionJson(listFormName, 800, 400, true, true, true, true, false),
InsertFieldsDefaultValueJson = DefaultInsertFieldsDefaultValueJson,
EditingFormJson = JsonSerializer.Serialize(new List<EditingFormDto>()
{
new() {
Order=1, ColCount=2, ColSpan=1, ItemType="group", Items =[
new EditingFormItemDto { Order = 1, DataField="Name", ColSpan = 1, IsRequired = true, EditorType2 = EditorTypes.dxTextBox },
new EditingFormItemDto { Order = 2, DataField="Description", ColSpan = 2, EditorType2 = EditorTypes.dxTextArea },
new EditingFormItemDto { Order = 3, DataField="StartDate", ColSpan = 1, IsRequired = true, EditorType2 = EditorTypes.dxDateBox, EditorOptions = EditorOptionValues.DateTimeFormat },
new EditingFormItemDto { Order = 4, DataField="EndDate", ColSpan = 1, IsRequired = true, EditorType2 = EditorTypes.dxDateBox, EditorOptions = EditorOptionValues.DateTimeFormat },
]}
}),
}, autoSave: true
);
#region Project Task Workload Fields
await _listFormFieldRepository.InsertManyAsync([
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.Guid,
FieldName = "Id",
Width = 100,
ListOrderNo = 1,
Visible = false,
IsActive = true,
IsDeleted = false,
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.Guid,
FieldName = "ParentId",
Width = 200,
ListOrderNo = 2,
Visible = false,
IsActive = true,
IsDeleted = false,
AllowSearch = true,
LookupJson = JsonSerializer.Serialize(new LookupDto
{
DataSourceType = UiLookupDataSourceTypeEnum.Query,
DisplayExpr = "Name",
ValueExpr = "Key",
LookupQuery = LookupQueryValues.DefaultLookupQuery(nameof(TableNameEnum.Projects), "Id", "Name"),
CascadeEmptyFields = "PhaseId"
}),
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "Name",
Width = 200,
ListOrderNo = 3,
Visible = true,
IsActive = true,
IsDeleted = false,
AllowSearch = true,
SortIndex = 1,
SortDirection = GridColumnOptions.SortOrderAsc,
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "Description",
Width = 400,
ListOrderNo = 4,
Visible = true,
IsActive = true,
IsDeleted = false,
AllowSearch = true,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.DateTime,
FieldName = "StartDate",
Width = 150,
ListOrderNo = 5,
Visible = true,
IsActive = true,
IsDeleted = false,
AllowSearch = true,
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.DateTime,
FieldName = "EndDate",
Width = 150,
ListOrderNo = 6,
Visible = true,
IsActive = true,
IsDeleted = false,
AllowSearch = true,
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.Decimal,
FieldName = "Progress",
Width = 100,
ListOrderNo = 7,
Visible = true,
IsActive = true,
IsDeleted = false,
AllowSearch = true,
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
]);
#endregion
}
#endregion
#region Project Task Daily #region Project Task Daily
listFormName = AppCodes.Project.ProjectTaskDaily; listFormName = AppCodes.Project.ProjectTaskDaily;
if (!await _listFormRepository.AnyAsync(a => a.ListFormCode == listFormName)) if (!await _listFormRepository.AnyAsync(a => a.ListFormCode == listFormName))
@ -2066,7 +2266,8 @@ public class ListFormSeeder_Project : IDataSeedContributor, ITransientDependency
var listForm = await _listFormRepository.InsertAsync( var listForm = await _listFormRepository.InsertAsync(
new ListForm() new ListForm()
{ {
ListFormType = ListFormTypeEnum.List, ExportJson = DefaultExportJson, ListFormType = ListFormTypeEnum.List,
ExportJson = DefaultExportJson,
IsSubForm = false, IsSubForm = false,
ShowNote = true, ShowNote = true,
LayoutJson = DefaultLayoutJson, LayoutJson = DefaultLayoutJson,

View file

@ -2558,7 +2558,6 @@
"RequiredPermissionName": null, "RequiredPermissionName": null,
"IsDisabled": false "IsDisabled": false
}, },
{ {
"ParentCode": "App.Store.Definitions", "ParentCode": "App.Store.Definitions",
"Code": "App.Store.WarehouseType", "Code": "App.Store.WarehouseType",
@ -2804,7 +2803,7 @@
"Code": "App.Project.Workload", "Code": "App.Project.Workload",
"DisplayName": "App.Project.Workload", "DisplayName": "App.Project.Workload",
"Order": 7, "Order": 7,
"Url": "/admin/projects/workload", "Url": "/admin/list/App.Project.Workload",
"Icon": "FcComboChart", "Icon": "FcComboChart",
"RequiredPermissionName": "App.Project.Workload", "RequiredPermissionName": "App.Project.Workload",
"IsDisabled": false "IsDisabled": false

View file

@ -5557,7 +5557,6 @@
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp"
}, },
{ {
"GroupName": "App.SupplyChain", "GroupName": "App.SupplyChain",
"Name": "App.SupplyChain.SupplyType", "Name": "App.SupplyChain.SupplyType",
@ -5999,7 +5998,6 @@
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp"
}, },
{ {
"GroupName": "App.SupplyChain", "GroupName": "App.SupplyChain",
"Name": "App.SupplyChain.QuotationStatus", "Name": "App.SupplyChain.QuotationStatus",
@ -6423,7 +6421,6 @@
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp"
}, },
{ {
"GroupName": "App.SupplyChain", "GroupName": "App.SupplyChain",
"Name": "App.SupplyChain.QuotationItem", "Name": "App.SupplyChain.QuotationItem",
@ -6487,7 +6484,6 @@
"MultiTenancySide": 3, "MultiTenancySide": 3,
"MenuGroup": "Erp" "MenuGroup": "Erp"
}, },
{ {
"GroupName": "App.SupplyChain", "GroupName": "App.SupplyChain",
"Name": "App.SupplyChain.Approval", "Name": "App.SupplyChain.Approval",

View file

@ -92,11 +92,11 @@ public static class SeederDefaults
Mode = GridOptions.SelectionModeMultiple, Mode = GridOptions.SelectionModeMultiple,
SelectAllMode = GridOptions.SelectionAllModeAllPages SelectAllMode = GridOptions.SelectionAllModeAllPages
}); });
public static string DefaultTreeOptionJson(string KeyExpr, string ParentIdExpr, bool AutoExpandAll = true) => JsonSerializer.Serialize(new TreeOptionDto public static string DefaultTreeOptionJson(string KeyExpr, string ParentIdExpr, bool AutoExpandAll = true, object RootValue = null) => JsonSerializer.Serialize(new TreeOptionDto
{ {
KeyExpr = KeyExpr, KeyExpr = KeyExpr,
ParentIdExpr = ParentIdExpr, ParentIdExpr = ParentIdExpr,
RootValue = null, RootValue = RootValue,
AutoExpandAll = AutoExpandAll AutoExpandAll = AutoExpandAll
}); });
public static readonly string DefaultPagerOptionJson = JsonSerializer.Serialize(new GridPagerOptionDto public static readonly string DefaultPagerOptionJson = JsonSerializer.Serialize(new GridPagerOptionDto

View file

@ -5,8 +5,5 @@ public static class ListFormTypeEnum
public const string List = "List"; public const string List = "List";
public const string Form = "Form"; public const string Form = "Form";
public const string Chart = "Chart"; public const string Chart = "Chart";
public const string Pivot = "Pivot";
public const string Tree = "Tree";
public const string Gantt = "Gantt";
} }

View file

@ -587,6 +587,7 @@ public static class SeedConsts
public const string ProjectRisk = Default + ".ProjectRisk"; public const string ProjectRisk = Default + ".ProjectRisk";
public const string ProjectTeam = Default + ".ProjectTeam"; public const string ProjectTeam = Default + ".ProjectTeam";
public const string ProjectTask = Default + ".ProjectTask"; public const string ProjectTask = Default + ".ProjectTask";
public const string Workload = Default + ".Workload";
public const string ProjectTaskDaily = Default + ".ProjectTaskDaily"; public const string ProjectTaskDaily = Default + ".ProjectTaskDaily";
} }

View file

@ -36,6 +36,8 @@ public class DatabaseViewSeeder : IDataSeedContributor, ITransientDependency
await CreateOrUpdateMaterialGroupView(dbContext, nameof(TableNameEnum.MaterialGroup)); await CreateOrUpdateMaterialGroupView(dbContext, nameof(TableNameEnum.MaterialGroup));
await CreateOrUpdateProjectTaskView(dbContext, nameof(TableNameEnum.ProjectTask));
_logger.LogInformation("Database view seeding completed successfully."); _logger.LogInformation("Database view seeding completed successfully.");
} }
catch (Exception ex) catch (Exception ex)
@ -102,5 +104,75 @@ public class DatabaseViewSeeder : IDataSeedContributor, ITransientDependency
throw; throw;
} }
} }
/// <summary>
/// Creates or updates the V_T_Scp_ProjectWorkload view
/// </summary>
private async Task CreateOrUpdateProjectTaskView(PlatformDbContext dbContext, string viewName)
{
string fullViewName = TableNameResolver.GetFullViewName(viewName);
try
{
var createViewSql = $@"
IF EXISTS (SELECT * FROM sys.views WHERE object_id = OBJECT_ID(N'[dbo].[{fullViewName}]'))
DROP VIEW [dbo].[{fullViewName}];
EXEC('
CREATE VIEW [dbo].[{fullViewName}]
AS
SELECT
TenantId,
Id,
NULL AS ParentId,
[Name],
[Description],
[StartDate],
[EndDate],
[IsDeleted],
[Progress]
FROM [Erp].[dbo].[Prj_T_Projects]
UNION ALL
SELECT
TenantId,
Id,
ProjectId AS ParentId,
[Name],
[Description],
[StartDate],
[EndDate],
[IsDeleted],
100 AS [Progress]
FROM [Erp].[dbo].[Prj_T_ProjectPhase]
UNION ALL
SELECT
TenantId,
Id,
PhaseId AS ParentId,
[Name],
[Description],
[StartDate],
[EndDate],
[IsDeleted],
[Progress]
FROM [Erp].[dbo].[Prj_T_ProjectTask]
')
";
await dbContext.Database.ExecuteSqlRawAsync(createViewSql);
_logger.LogInformation($"Created/Updated {fullViewName} view successfully.");
}
catch (Exception ex)
{
_logger.LogError(ex, $"Error occurred while creating {fullViewName} view.");
throw;
}
}
} }

8
ui/public/css/gantt/dx-gantt.min.css vendored Normal file

File diff suppressed because one or more lines are too long

39
ui/public/css/gantt/dx-gantt.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -1,3 +1,5 @@
import { Gantt } from 'devextreme-react'
export const extraFilterControlTypeOptions = [ export const extraFilterControlTypeOptions = [
{ value: 'Select', label: 'Select' }, { value: 'Select', label: 'Select' },
{ value: 'TextBox', label: 'TextBox' }, { value: 'TextBox', label: 'TextBox' },
@ -73,55 +75,55 @@ export const ListFormEditTabs = {
} as const } as const
export const tabVisibilityConfig: Record<string, string[]> = { export const tabVisibilityConfig: Record<string, string[]> = {
List: [ List: [
'details', 'details',
'database', 'database',
'permissions', 'permissions',
'commands', 'commands',
'edit', 'edit',
'sortingForm', 'sortingForm',
'filterRow', 'filterRow',
'rowForm', 'rowForm',
'search', 'search',
'group', 'group',
'select', 'select',
'columns', 'columns',
'pivots', 'pivots',
'tree', 'tree',
'pager', 'pager',
'state', 'state',
'extrafilter', 'extrafilter',
'customization', 'customization',
'fields', 'fields',
'editForm', 'editForm',
'widget', 'widget',
//Chart tabları //Chart tabları
'commonSettings', 'commonSettings',
'series', 'series',
'axis', 'axis',
'panes', 'panes',
'animationsOptions', 'animationsOptions',
'annotations', 'annotations',
'zoomAndPanSettings', 'zoomAndPanSettings',
'legendSettings', 'legendSettings',
'exportSettings', 'exportSettings',
'crosshairOptions', 'crosshairOptions',
'subForms', 'subForms',
], ],
Form: [ Form: [
'details', 'details',
'database', 'database',
'permissions', 'permissions',
'commands', 'commands',
'edit', 'edit',
'fields', 'fields',
'editForm', 'editForm',
'widget', 'widget',
'subForms', 'subForms',
], ],
} }
export const themeOptions = [ export const themeOptions = [
{ value: 'generic.dark', label: 'Generic Dark' }, { value: 'generic.dark', label: 'Generic Dark' },
{ value: 'generic.light', label: 'Generic Carmine' }, { value: 'generic.light', label: 'Generic Carmine' },
{ value: 'generic.contrast', label: 'Generic Contrast' }, { value: 'generic.contrast', label: 'Generic Contrast' },

View file

@ -386,6 +386,10 @@ export interface TreeOptionDto {
expandedRowKeys?: any[] expandedRowKeys?: any[]
autoExpandAll?: boolean autoExpandAll?: boolean
recursiveSelection?: boolean recursiveSelection?: boolean
titleExpr?: string
startExpr?: string
endExpr?: string
progressExpr?: string
} }
export interface GridEditingDto { export interface GridEditingDto {

View file

@ -36,7 +36,7 @@ import FormTabWidgets from './FormTabWidgets'
import FormTabExtraFilters from './FormTabExtraFilters' import FormTabExtraFilters from './FormTabExtraFilters'
import FormTabEditForm from './FormTabEditForm' import FormTabEditForm from './FormTabEditForm'
import FormTabPivots from './FormTabPivots' import FormTabPivots from './FormTabPivots'
import FormTabTree from './FormTabTree' import FormTabTreeGantt from './FormTabTreeGantt'
import ChartTabAnimation from './ChartTabAnimation' import ChartTabAnimation from './ChartTabAnimation'
import ChartTabAnnotations from './ChartTabAnnotations' import ChartTabAnnotations from './ChartTabAnnotations'
import ChartTabZoomAndPan from './ChartTabZoomAndPan' import ChartTabZoomAndPan from './ChartTabZoomAndPan'
@ -360,7 +360,7 @@ const FormEdit = () => {
<FormTabPivots onSubmit={onSubmit} /> <FormTabPivots onSubmit={onSubmit} />
</TabContent> </TabContent>
<TabContent value="tree" className="px-2"> <TabContent value="tree" className="px-2">
<FormTabTree onSubmit={onSubmit} /> <FormTabTreeGantt onSubmit={onSubmit} />
</TabContent> </TabContent>
<TabContent value="pager" className="px-2"> <TabContent value="pager" className="px-2">
<FormTabPager onSubmit={onSubmit} /> <FormTabPager onSubmit={onSubmit} />

View file

@ -28,6 +28,7 @@ const schema = Yup.object().shape({
pivot: Yup.boolean(), pivot: Yup.boolean(),
chart: Yup.boolean(), chart: Yup.boolean(),
tree: Yup.boolean(), tree: Yup.boolean(),
gantt: Yup.boolean(),
defaultLayout: Yup.string(), defaultLayout: Yup.string(),
cardLayoutColumn: Yup.number(), cardLayoutColumn: Yup.number(),
}), }),

View file

@ -1,203 +0,0 @@
import { Container } from '@/components/shared'
import {
Button,
Notification,
Checkbox,
FormContainer,
FormItem,
Input,
Select,
toast,
} from '@/components/ui'
import { ListFormEditTabs } from '@/proxy/admin/list-form/options'
import { useStoreState } from '@/store'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { Field, FieldProps, Form, Formik } from 'formik'
import * as Yup from 'yup'
import { FormEditProps } from './FormEdit'
import { SelectBoxOption } from '@/types/shared'
import { useEffect, useState } from 'react'
import { getListFormFields } from '@/services/admin/list-form-field.service'
import { groupBy } from 'lodash'
import { useParams } from 'react-router-dom'
const validationSchema = Yup.object().shape({})
function FormTabTree(props: FormEditProps) {
const { listFormCode } = useParams()
const { translate } = useLocalization()
const [fieldList, setFieldList] = useState<SelectBoxOption[]>([])
const getFields = async () => {
if (!listFormCode) {
return
}
try {
const resp = await getListFormFields({
listFormCode,
sorting: 'ListOrderNo',
maxResultCount: 1000,
})
if (resp.data?.items) {
const fieldNames = groupBy(resp?.data?.items, 'fieldName')
setFieldList(
Object.keys(fieldNames).map((a) => ({
value: a,
label: a,
})),
)
}
} catch (error: any) {
toast.push(
<Notification type="danger" duration={2000}>
Alanlar getirilemedi
{error.toString()}
</Notification>,
{
placement: 'top-end',
},
)
}
}
useEffect(() => {
getFields()
}, [listFormCode])
const listFormValues = useStoreState((s) => s.admin.lists.values)
if (!listFormValues) {
return null
}
return (
<Container className="grid xl:grid-cols-2">
<Formik
initialValues={listFormValues}
validationSchema={validationSchema}
onSubmit={async (values, formikHelpers) => {
await props.onSubmit(ListFormEditTabs.TreeForm, values, formikHelpers)
}}
>
{({ touched, errors, isSubmitting, values }) => (
<Form>
<FormContainer size="sm">
<FormItem
label={translate('::ListForms.ListFormEdit.DatabaseDataSourceKeyFieldName')}
invalid={errors.treeOptionDto?.keyExpr && touched.treeOptionDto?.keyExpr}
errorMessage={errors.treeOptionDto?.keyExpr}
>
<Field
type="text"
name="treeOptionDto.keyExpr"
placeholder={translate('::ListForms.ListFormEdit.DatabaseDataSourceKeyFieldName')}
>
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
isClearable={true}
options={fieldList}
value={fieldList?.filter(
(option) => option.value === values.treeOptionDto.keyExpr,
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>
)}
</Field>
</FormItem>
<FormItem
label={translate('::ListForms.ListFormEdit.ParentIdExpr')}
invalid={errors.treeOptionDto?.parentIdExpr && touched.treeOptionDto?.parentIdExpr}
errorMessage={errors.treeOptionDto?.parentIdExpr}
>
<Field
type="text"
name="treeOptionDto.parentIdExpr"
placeholder={translate('::ListForms.ListFormEdit.ParentIdExpr')}
>
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
isClearable={true}
options={fieldList}
value={fieldList?.filter(
(option) => option.value === values.treeOptionDto.parentIdExpr,
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>
)}
</Field>
</FormItem>
<FormItem
label={translate('::ListForms.ListFormEdit.HasItemsExpr')}
invalid={errors.treeOptionDto?.hasItemsExpr && touched.treeOptionDto?.hasItemsExpr}
errorMessage={errors.treeOptionDto?.hasItemsExpr}
>
<Field
type="text"
autoComplete="off"
name="treeOptionDto.hasItemsExpr"
placeholder={translate('::ListForms.ListFormEdit.HasItemsExpr')}
component={Input}
/>
</FormItem>
<FormItem
label={translate('::ListForms.ListFormEdit.RootValue')}
invalid={!!(errors.treeOptionDto?.rootValue && touched.treeOptionDto?.rootValue)}
errorMessage={errors.treeOptionDto?.rootValue as string}
>
<Field
type="text"
autoComplete="off"
name="treeOptionDto.rootValue"
placeholder={translate('::ListForms.ListFormEdit.RootValue')}
component={Input}
/>
</FormItem>
<FormItem
label={translate('::ListForms.ListFormEdit.AutoExpandAll')}
invalid={
errors.treeOptionDto?.autoExpandAll && touched.treeOptionDto?.autoExpandAll
}
errorMessage={errors.treeOptionDto?.autoExpandAll}
>
<Field
name="treeOptionDto.autoExpandAll"
placeholder={translate('::ListForms.ListFormEdit.AutoExpandAll')}
component={Checkbox}
/>
</FormItem>
<FormItem
label={translate('::ListForms.ListFormEdit.RecursiveSelection')}
invalid={
errors.treeOptionDto?.recursiveSelection &&
touched.treeOptionDto?.recursiveSelection
}
errorMessage={errors.treeOptionDto?.recursiveSelection}
>
<Field
name="treeOptionDto.recursiveSelection"
placeholder={translate('::ListForms.ListFormEdit.RecursiveSelection')}
component={Checkbox}
/>
</FormItem>
<Button block variant="solid" loading={isSubmitting} type="submit" className="my-2">
{isSubmitting ? translate('::SavingWithThreeDot') : translate('::Save')}
</Button>
</FormContainer>
</Form>
)}
</Formik>
</Container>
)
}
export default FormTabTree

View file

@ -0,0 +1,315 @@
import { Container } from '@/components/shared'
import {
Button,
Notification,
Checkbox,
FormContainer,
FormItem,
Input,
Select,
toast,
Card,
} from '@/components/ui'
import { ListFormEditTabs } from '@/proxy/admin/list-form/options'
import { useStoreState } from '@/store'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { Field, FieldProps, Form, Formik } from 'formik'
import * as Yup from 'yup'
import { FormEditProps } from './FormEdit'
import { SelectBoxOption } from '@/types/shared'
import { useEffect, useState } from 'react'
import { getListFormFields } from '@/services/admin/list-form-field.service'
import { groupBy } from 'lodash'
import { useParams } from 'react-router-dom'
const validationSchema = Yup.object().shape({})
function FormTabTreeGantt(props: FormEditProps) {
const { listFormCode } = useParams()
const { translate } = useLocalization()
const [fieldList, setFieldList] = useState<SelectBoxOption[]>([])
const getFields = async () => {
if (!listFormCode) {
return
}
try {
const resp = await getListFormFields({
listFormCode,
sorting: 'ListOrderNo',
maxResultCount: 1000,
})
if (resp.data?.items) {
const fieldNames = groupBy(resp?.data?.items, 'fieldName')
setFieldList(
Object.keys(fieldNames).map((a) => ({
value: a,
label: a,
})),
)
}
} catch (error: any) {
toast.push(
<Notification type="danger" duration={2000}>
Alanlar getirilemedi
{error.toString()}
</Notification>,
{
placement: 'top-end',
},
)
}
}
useEffect(() => {
getFields()
}, [listFormCode])
const listFormValues = useStoreState((s) => s.admin.lists.values)
if (!listFormValues) {
return null
}
return (
<Formik
initialValues={listFormValues}
validationSchema={validationSchema}
onSubmit={async (values, formikHelpers) => {
await props.onSubmit(ListFormEditTabs.TreeForm, values, formikHelpers)
}}
>
{({ touched, errors, isSubmitting, values }) => (
<Form>
<FormContainer size="sm">
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
<Card className="my-2" header="Tree Options">
<FormItem
label={translate('::ListForms.ListFormEdit.DatabaseDataSourceKeyFieldName')}
invalid={errors.treeOptionDto?.keyExpr && touched.treeOptionDto?.keyExpr}
errorMessage={errors.treeOptionDto?.keyExpr}
>
<Field
type="text"
name="treeOptionDto.keyExpr"
placeholder={translate(
'::ListForms.ListFormEdit.DatabaseDataSourceKeyFieldName',
)}
>
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
isClearable={true}
options={fieldList}
value={fieldList?.filter(
(option) => option.value === values.treeOptionDto.keyExpr,
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>
)}
</Field>
</FormItem>
<FormItem
label={translate('::ListForms.ListFormEdit.ParentIdExpr')}
invalid={
errors.treeOptionDto?.parentIdExpr && touched.treeOptionDto?.parentIdExpr
}
errorMessage={errors.treeOptionDto?.parentIdExpr}
>
<Field
type="text"
name="treeOptionDto.parentIdExpr"
placeholder={translate('::ListForms.ListFormEdit.ParentIdExpr')}
>
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
isClearable={true}
options={fieldList}
value={fieldList?.filter(
(option) => option.value === values.treeOptionDto.parentIdExpr,
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>
)}
</Field>
</FormItem>
<FormItem
label={translate('::ListForms.ListFormEdit.HasItemsExpr')}
invalid={
errors.treeOptionDto?.hasItemsExpr && touched.treeOptionDto?.hasItemsExpr
}
errorMessage={errors.treeOptionDto?.hasItemsExpr}
>
<Field
type="text"
autoComplete="off"
name="treeOptionDto.hasItemsExpr"
placeholder={translate('::ListForms.ListFormEdit.HasItemsExpr')}
component={Input}
/>
</FormItem>
<FormItem
label={translate('::ListForms.ListFormEdit.RootValue')}
invalid={!!(errors.treeOptionDto?.rootValue && touched.treeOptionDto?.rootValue)}
errorMessage={errors.treeOptionDto?.rootValue as string}
>
<Field
type="text"
autoComplete="off"
name="treeOptionDto.rootValue"
placeholder={translate('::ListForms.ListFormEdit.RootValue')}
component={Input}
/>
</FormItem>
<FormItem
label={translate('::ListForms.ListFormEdit.AutoExpandAll')}
invalid={
errors.treeOptionDto?.autoExpandAll && touched.treeOptionDto?.autoExpandAll
}
errorMessage={errors.treeOptionDto?.autoExpandAll}
>
<Field
name="treeOptionDto.autoExpandAll"
placeholder={translate('::ListForms.ListFormEdit.AutoExpandAll')}
component={Checkbox}
/>
</FormItem>
<FormItem
label={translate('::ListForms.ListFormEdit.RecursiveSelection')}
invalid={
errors.treeOptionDto?.recursiveSelection &&
touched.treeOptionDto?.recursiveSelection
}
errorMessage={errors.treeOptionDto?.recursiveSelection}
>
<Field
name="treeOptionDto.recursiveSelection"
placeholder={translate('::ListForms.ListFormEdit.RecursiveSelection')}
component={Checkbox}
/>
</FormItem>
</Card>
<Card className="my-2" header="Gantt Options">
<FormItem
label={translate('::ListForms.ListFormEdit.TitleExpr')}
invalid={errors.treeOptionDto?.titleExpr && touched.treeOptionDto?.titleExpr}
errorMessage={errors.treeOptionDto?.titleExpr}
>
<Field
type="text"
name="treeOptionDto.titleExpr"
placeholder={translate('::ListForms.ListFormEdit.TitleExpr')}
>
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
isClearable={true}
options={fieldList}
value={fieldList?.filter(
(option) => option.value === values.treeOptionDto.titleExpr,
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>
)}
</Field>
</FormItem>
<FormItem
label={translate('::ListForms.ListFormEdit.StartExpr')}
invalid={errors.treeOptionDto?.startExpr && touched.treeOptionDto?.startExpr}
errorMessage={errors.treeOptionDto?.startExpr}
>
<Field
type="text"
name="treeOptionDto.startExpr"
placeholder={translate('::ListForms.ListFormEdit.StartExpr')}
>
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
isClearable={true}
options={fieldList}
value={fieldList?.filter(
(option) => option.value === values.treeOptionDto.startExpr,
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>
)}
</Field>
</FormItem>
<FormItem
label={translate('::ListForms.ListFormEdit.EndExpr')}
invalid={errors.treeOptionDto?.endExpr && touched.treeOptionDto?.endExpr}
errorMessage={errors.treeOptionDto?.endExpr}
>
<Field
type="text"
name="treeOptionDto.endExpr"
placeholder={translate('::ListForms.ListFormEdit.EndExpr')}
>
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
isClearable={true}
options={fieldList}
value={fieldList?.filter(
(option) => option.value === values.treeOptionDto.endExpr,
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>
)}
</Field>
</FormItem>
<FormItem
label={translate('::ListForms.ListFormEdit.ProgressExpr')}
invalid={
errors.treeOptionDto?.progressExpr && touched.treeOptionDto?.progressExpr
}
errorMessage={errors.treeOptionDto?.progressExpr}
>
<Field
type="text"
name="treeOptionDto.progressExpr"
placeholder={translate('::ListForms.ListFormEdit.ProgressExpr')}
>
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
isClearable={true}
options={fieldList}
value={fieldList?.filter(
(option) => option.value === values.treeOptionDto.progressExpr,
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>
)}
</Field>
</FormItem>
</Card>
</div>
<Button block variant="solid" loading={isSubmitting} type="submit" className="my-2">
{isSubmitting ? translate('::SavingWithThreeDot') : translate('::Save')}
</Button>
</FormContainer>
</Form>
)}
</Formik>
)
}
export default FormTabTreeGantt

View file

@ -203,7 +203,6 @@ export const columnEditorTypeListOptions = [
export const listFormTypeOptions = [ export const listFormTypeOptions = [
{ value: 'Form', label: 'Form' }, { value: 'Form', label: 'Form' },
{ value: 'List', label: 'List' }, { value: 'List', label: 'List' },
{ value: 'Tree', label: 'Tree' },
{ value: 'Chart', label: 'Chart' }, { value: 'Chart', label: 'Chart' },
] ]

View file

@ -6,17 +6,14 @@ import { useLocalization } from '@/utils/hooks/useLocalization'
import useResponsive from '@/utils/hooks/useResponsive' import useResponsive from '@/utils/hooks/useResponsive'
import Gantt, { import Gantt, {
Column, Column,
Dependencies,
Editing, Editing,
GanttRef, GanttRef,
GanttTypes, Item,
ResourceAssignments,
Resources,
Tasks, Tasks,
Toolbar,
Validation, Validation,
} from 'devextreme-react/gantt' } from 'devextreme-react/gantt'
import { Button } from '@/components/ui' import DataSource from 'devextreme/data/data_source'
import CustomStore from 'devextreme/data/custom_store'
import { useCallback, useEffect, useRef, useState } from 'react' import { useCallback, useEffect, useRef, useState } from 'react'
import { Helmet } from 'react-helmet' import { Helmet } from 'react-helmet'
import { getList } from '@/services/form.service' import { getList } from '@/services/form.service'
@ -45,7 +42,7 @@ const GanttView = (props: GanttViewProps) => {
const refListFormCode = useRef('') const refListFormCode = useRef('')
const widgetGroupRef = useRef<HTMLDivElement>(null) const widgetGroupRef = useRef<HTMLDivElement>(null)
const [ganttDataSource, setGanttDataSource] = useState<CustomStore<any, any>>() const [ganttDataSource, setGanttDataSource] = useState<DataSource<any, any>>()
const [gridDto, setGridDto] = useState<GridDto>() const [gridDto, setGridDto] = useState<GridDto>()
const [widgetGroupHeight, setWidgetGroupHeight] = useState(0) const [widgetGroupHeight, setWidgetGroupHeight] = useState(0)
@ -132,7 +129,7 @@ const GanttView = (props: GanttViewProps) => {
useEffect(() => { useEffect(() => {
if (!gridDto) return if (!gridDto) return
const dataSource = createSelectDataSource( const customStore = createSelectDataSource(
gridDto.gridOptions, gridDto.gridOptions,
listFormCode, listFormCode,
searchParams, searchParams,
@ -140,8 +137,14 @@ const GanttView = (props: GanttViewProps) => {
undefined, undefined,
) )
// Gantt için DataSource wrapper'ı oluştur
const dataSource = new DataSource({
store: customStore,
reshapeOnPush: true,
})
setGanttDataSource(dataSource) setGanttDataSource(dataSource)
}, [gridDto, searchParams]) }, [gridDto, searchParams, createSelectDataSource])
useEffect(() => { useEffect(() => {
refListFormCode.current = listFormCode refListFormCode.current = listFormCode
@ -201,52 +204,14 @@ const GanttView = (props: GanttViewProps) => {
titleTemplate="%s | Erp Platform" titleTemplate="%s | Erp Platform"
title={translate('::' + gridDto?.gridOptions.title)} title={translate('::' + gridDto?.gridOptions.title)}
defaultTitle="Erp Platform" defaultTitle="Erp Platform"
></Helmet> >
<link rel="stylesheet" href="/css/gantt/dx-gantt.min.css" />
</Helmet>
)} )}
{!gridDto && <div className="p-4">Loading gantt configuration...</div>} {!gridDto && <div className="p-4">Loading gantt configuration...</div>}
{gridDto && !ganttDataSource && <div className="p-4">Loading data source...</div>} {gridDto && !ganttDataSource && <div className="p-4">Loading data source...</div>}
{gridDto && ganttDataSource && ( {gridDto && ganttDataSource && (
<> <>
{/* Custom Toolbar */}
{(toolbarData.length > 0 || filterToolbarData.length > 0) && (
<div className="flex flex-wrap gap-2 p-2 border-b bg-white">
{toolbarData.map((item: any) => {
if (item.widget === 'dxButton' && item.options) {
return (
<Button
key={item.name}
size="sm"
variant={item.options.type || 'solid'}
icon={item.options.icon}
onClick={item.options.onClick}
disabled={item.options.disabled}
>
{item.options.text}
</Button>
)
}
return null
})}
{filterToolbarData.map((item: any) => {
if (item.widget === 'dxButton' && item.options) {
return (
<Button
key={item.name}
size="sm"
variant={item.options.type || 'solid'}
icon={item.options.icon}
onClick={item.options.onClick}
disabled={item.options.disabled}
>
{item.options.text}
</Button>
)
}
return null
})}
</div>
)}
<div className="p-1"> <div className="p-1">
<Gantt <Gantt
ref={ganttRef as any} ref={ganttRef as any}
@ -254,6 +219,12 @@ const GanttView = (props: GanttViewProps) => {
id={'Gantt-' + listFormCode} id={'Gantt-' + listFormCode}
taskListWidth={500} taskListWidth={500}
scaleType="weeks" scaleType="weeks"
rootValue={
gridDto.gridOptions.treeOptionDto?.rootValue === '' ||
gridDto.gridOptions.treeOptionDto?.rootValue === undefined
? null
: gridDto.gridOptions.treeOptionDto?.rootValue
}
height={ height={
gridDto.gridOptions.height > 0 gridDto.gridOptions.height > 0
? gridDto.gridOptions.height ? gridDto.gridOptions.height
@ -267,17 +238,32 @@ const GanttView = (props: GanttViewProps) => {
onTaskUpdated={onTaskUpdated} onTaskUpdated={onTaskUpdated}
onTaskDeleted={onTaskDeleted} onTaskDeleted={onTaskDeleted}
> >
<Tasks dataSource={ganttDataSource} /> <Tasks
<Dependencies dataSource={[]} /> dataSource={ganttDataSource}
<Resources dataSource={[]} /> keyExpr={gridDto.gridOptions.treeOptionDto?.keyExpr}
<ResourceAssignments dataSource={[]} /> parentIdExpr={gridDto.gridOptions.treeOptionDto?.parentIdExpr}
titleExpr={gridDto.gridOptions.treeOptionDto?.titleExpr}
startExpr={gridDto.gridOptions.treeOptionDto?.startExpr}
endExpr={gridDto.gridOptions.treeOptionDto?.endExpr}
progressExpr={gridDto.gridOptions.treeOptionDto?.progressExpr}
/>
<Toolbar>
<Item name="undo" />
<Item name="redo" />
<Item name="separator" />
<Item name="collapseAll" />
<Item name="expandAll" />
<Item name="separator" />
<Item name="addTask" />
<Item name="deleteTask" />
<Item name="separator" />
<Item name="zoomIn" />
<Item name="zoomOut" />
</Toolbar>
<Editing <Editing
enabled={ enabled={gridDto.gridOptions.editingOptionDto?.allowUpdating}
gridDto.gridOptions.editingOptionDto?.allowAdding ||
gridDto.gridOptions.editingOptionDto?.allowUpdating ||
gridDto.gridOptions.editingOptionDto?.allowDeleting
}
allowTaskAdding={gridDto.gridOptions.editingOptionDto?.allowAdding} allowTaskAdding={gridDto.gridOptions.editingOptionDto?.allowAdding}
allowTaskUpdating={gridDto.gridOptions.editingOptionDto?.allowUpdating} allowTaskUpdating={gridDto.gridOptions.editingOptionDto?.allowUpdating}
allowTaskDeleting={gridDto.gridOptions.editingOptionDto?.allowDeleting} allowTaskDeleting={gridDto.gridOptions.editingOptionDto?.allowDeleting}