Continued development

This commit is contained in:
c0d3.m0nk3y 2026-05-15 12:51:35 -04:00
parent 3defad51f8
commit 29497cc003
5 changed files with 132 additions and 62 deletions

View File

@ -390,7 +390,7 @@ namespace trakker.Data
return result;
}
public List<PTaskFS> GetFS()
public List<PTaskFS> GetFS(string projectId)
{
var results = new List<PTaskFS>();
@ -403,6 +403,8 @@ namespace trakker.Data
a.project_id
FROM
projects a
WHERE
a.project_id = $project_id
UNION
@ -414,13 +416,15 @@ namespace trakker.Data
b.project_id
FROM
tasks b
WHERE
b.project_id = $project_id
;
";
using var conn = OpenConnection();
using var cmd = conn.CreateCommand();
cmd.CommandText = sql;
cmd.Parameters.AddWithValue("$project_id", projectId);
using var reader = cmd.ExecuteReader();

View File

@ -54,8 +54,6 @@
splitContainerTasks2 = new SplitContainer();
dataGridViewProjectTasks = new DataGridView();
tableLayoutPanelTasks2 = new TableLayoutPanel();
groupBoxTaskDescription = new GroupBox();
richTextBoxTaskDescription = new RichTextBox();
groupBoxTaskComments = new GroupBox();
richTextBoxTaskComments = new RichTextBox();
MainForm_MenuStrip.SuspendLayout();
@ -78,7 +76,6 @@
splitContainerTasks2.SuspendLayout();
((System.ComponentModel.ISupportInitialize)dataGridViewProjectTasks).BeginInit();
tableLayoutPanelTasks2.SuspendLayout();
groupBoxTaskDescription.SuspendLayout();
groupBoxTaskComments.SuspendLayout();
SuspendLayout();
//
@ -327,47 +324,23 @@
//
tableLayoutPanelTasks2.ColumnCount = 1;
tableLayoutPanelTasks2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
tableLayoutPanelTasks2.Controls.Add(groupBoxTaskDescription, 0, 0);
tableLayoutPanelTasks2.Controls.Add(groupBoxTaskComments, 0, 1);
tableLayoutPanelTasks2.Controls.Add(groupBoxTaskComments, 0, 0);
tableLayoutPanelTasks2.Dock = DockStyle.Fill;
tableLayoutPanelTasks2.Location = new Point(0, 0);
tableLayoutPanelTasks2.Name = "tableLayoutPanelTasks2";
tableLayoutPanelTasks2.RowCount = 2;
tableLayoutPanelTasks2.RowStyles.Add(new RowStyle(SizeType.Percent, 25F));
tableLayoutPanelTasks2.RowStyles.Add(new RowStyle(SizeType.Percent, 75F));
tableLayoutPanelTasks2.RowCount = 1;
tableLayoutPanelTasks2.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
tableLayoutPanelTasks2.RowStyles.Add(new RowStyle(SizeType.Absolute, 20F));
tableLayoutPanelTasks2.Size = new Size(1230, 303);
tableLayoutPanelTasks2.TabIndex = 0;
//
// groupBoxTaskDescription
//
groupBoxTaskDescription.Controls.Add(richTextBoxTaskDescription);
groupBoxTaskDescription.Dock = DockStyle.Fill;
groupBoxTaskDescription.Location = new Point(3, 3);
groupBoxTaskDescription.Name = "groupBoxTaskDescription";
groupBoxTaskDescription.Size = new Size(1224, 69);
groupBoxTaskDescription.TabIndex = 0;
groupBoxTaskDescription.TabStop = false;
groupBoxTaskDescription.Text = "Description";
//
// richTextBoxTaskDescription
//
richTextBoxTaskDescription.BackColor = SystemColors.Control;
richTextBoxTaskDescription.BorderStyle = BorderStyle.None;
richTextBoxTaskDescription.Dock = DockStyle.Fill;
richTextBoxTaskDescription.Location = new Point(3, 35);
richTextBoxTaskDescription.Name = "richTextBoxTaskDescription";
richTextBoxTaskDescription.ReadOnly = true;
richTextBoxTaskDescription.Size = new Size(1218, 31);
richTextBoxTaskDescription.TabIndex = 0;
richTextBoxTaskDescription.Text = "";
//
// groupBoxTaskComments
//
groupBoxTaskComments.Controls.Add(richTextBoxTaskComments);
groupBoxTaskComments.Dock = DockStyle.Fill;
groupBoxTaskComments.Location = new Point(3, 78);
groupBoxTaskComments.Location = new Point(3, 3);
groupBoxTaskComments.Name = "groupBoxTaskComments";
groupBoxTaskComments.Size = new Size(1224, 222);
groupBoxTaskComments.Size = new Size(1224, 297);
groupBoxTaskComments.TabIndex = 1;
groupBoxTaskComments.TabStop = false;
groupBoxTaskComments.Text = "Comments";
@ -380,9 +353,10 @@
richTextBoxTaskComments.Location = new Point(3, 35);
richTextBoxTaskComments.Name = "richTextBoxTaskComments";
richTextBoxTaskComments.ReadOnly = true;
richTextBoxTaskComments.Size = new Size(1218, 184);
richTextBoxTaskComments.Size = new Size(1218, 259);
richTextBoxTaskComments.TabIndex = 1;
richTextBoxTaskComments.Text = "";
richTextBoxTaskComments.LinkClicked += richTextBoxTaskComments_LinkClicked;
//
// MainForm
//
@ -417,7 +391,6 @@
splitContainerTasks2.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)dataGridViewProjectTasks).EndInit();
tableLayoutPanelTasks2.ResumeLayout(false);
groupBoxTaskDescription.ResumeLayout(false);
groupBoxTaskComments.ResumeLayout(false);
ResumeLayout(false);
PerformLayout();
@ -449,8 +422,6 @@
private SplitContainer splitContainerTasks2;
private DataGridView dataGridViewProjectTasks;
private TableLayoutPanel tableLayoutPanelTasks2;
private GroupBox groupBoxTaskDescription;
private RichTextBox richTextBoxTaskDescription;
private GroupBox groupBoxTaskComments;
private RichTextBox richTextBoxTaskComments;
}

View File

@ -152,7 +152,14 @@ namespace trakker
}
public void FillDataGridViewProjects(BindingSource projects)
{
int idx = 0;
if (dataGridViewProjects.CurrentRow != null)
{
idx = dataGridViewProjects.CurrentRow.Index;
}
//MessageBox.Show($"Project idx: {idx}", "Debug Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
dataGridViewProjects.DataSource = projects;
dataGridViewProjects.Rows[idx].Selected = true;
}
public void InitDataGridViewProjects()
{
@ -292,21 +299,32 @@ namespace trakker
}
};
dataGridViewClients.SelectionChanged += (s, e) =>
dataGridViewProjects.SelectionChanged += (s, e) =>
{
if (dataGridViewClients.SelectedRows.Count > 0)
if (_ctrl == null) return; // Safety check to prevent null reference exceptions during initialization)
if (dataGridViewProjects.SelectedRows.Count > 0)
{
var selectedClient = dataGridViewClients.SelectedRows[0].DataBoundItem as Client;
if (selectedClient != null)
var selectedProject = dataGridViewProjects.SelectedRows[0].DataBoundItem as Project;
if (selectedProject != null)
{
// Handle the selected client as needed
// MessageBox.Show($"Selected Client: {selectedClient.AddressStreet}", "Client Selected", MessageBoxButtons.OK, MessageBoxIcon.Information );
// Handle the selected project as needed
//MessageBox.Show($"Project ID: {selectedProject.ProjectId}, Selected Project: {selectedProject.ProjectName}", "Project Selected", MessageBoxButtons.OK, MessageBoxIcon.Information );
_ctrl.LoadTasks(selectedProject.ProjectId); // Load tasks for the selected project
InitProjectTasks();
}
}
};
}
public void InitProjectTasks()
{
//dataGridViewProjectTasks.Rows.Clear();
//richTextBoxTaskComments.Text = string.Empty;
richTextBoxTaskComments.WordWrap = false;
richTextBoxTaskComments.ReadOnly = true;
}
public void InitTreeViewTasks()
{
// Basic TreeView configuration
@ -315,21 +333,33 @@ namespace trakker
treeViewTasks1.ShowLines = true;
treeViewTasks1.ShowRootLines = true;
treeViewTasks1.HideSelection = false;
treeViewTasks1.FullRowSelect = true;
treeViewTasks1.EndUpdate();
// When a tree node is clicked, fetch and show notebooks for that folder
treeViewTasks1.NodeMouseClick += (sender, e) =>
{
PTaskFS? selectedNode = (PTaskFS?)e.Node.Tag ?? new PTaskFS();
if (selectedNode?.Parent == "/" || selectedNode?.GUID == "/")
{
_ctrl.LoadTasksRecursive(selectedNode.ProjectId, PTask.RecursiveRoot.PARENT_TASK_ID); // Load all tasks for the project when root node is clicked
return;
}
_ctrl.LoadTasksRecursive(selectedNode?.GUID ?? "/", PTask.RecursiveRoot.TASK_ID); // Load all tasks for the project when root node is clicked
TreeViewTasks1_NodeMouseClick(e.Node, e.Button);
};
}
public void TreeViewTasks1_NodeMouseClick(TreeNode node, MouseButtons button = MouseButtons.Left)
{
if (node == null) return;
// Put all your NodeMouseClick logic here
treeViewTasks1.SelectedNode = node; // Usually what you want
node.EnsureVisible();
// ... your other code (open form, load data, etc.)
PTaskFS? selectedNode = (PTaskFS?)node.Tag ?? new PTaskFS();
if (selectedNode?.Parent == "/" || selectedNode?.GUID == "/")
{
_ctrl.LoadTasksRecursive(selectedNode.ProjectId, PTask.RecursiveRoot.PARENT_TASK_ID); // Load all tasks for the project when root node is clicked
return;
}
_ctrl.LoadTasksRecursive(selectedNode?.GUID ?? "/", PTask.RecursiveRoot.TASK_ID); // Load all tasks for the project when root node is clicked
}
public void FillTreeViewTasks(List<PTaskFS> items)
{
if (items == null) return;
@ -340,7 +370,7 @@ namespace trakker
// Root node
PTaskFS root = new();
root.GUID = "/";
root.Node = "/Projects";
root.Node = "/Project";
root.Parent = string.Empty;
TreeNode rootNode = new TreeNode(root.Node) { Tag = root };
treeViewTasks1.Nodes.Add(rootNode);
@ -372,7 +402,7 @@ namespace trakker
{
var text = string.IsNullOrWhiteSpace(child.Node) ? "(unnamed)" : child.Node!.Trim();
var tn = new TreeNode(text) { Tag = child };
//tn.Expand();
tn.Expand();
parentNode.Nodes.Add(tn);
// Recurse using this child's node text as the parent key
@ -383,9 +413,13 @@ namespace trakker
// // Start recursion from root key
AddChildren(rootNode, "/");
//rootNode.ExpandAll();
rootNode.Expand(); // Expand first level for better UX
rootNode.ExpandAll();
treeViewTasks1.EndUpdate(); // End the update
TreeNode node = rootNode.FirstNode;
TreeViewTasks1_NodeMouseClick(node, MouseButtons.Left);
//treeViewTasks1.SelectedNode = node;
//treeViewTasks1.Focus();
}
private void addTaskSubtaskToolStripMenuItem_Click(object sender, EventArgs e)
@ -416,7 +450,7 @@ namespace trakker
try
{
taskData.Upsert(task);
treeViewTasks1.SelectedNode.Nodes.Add(new TreeNode(task.Title ?? "") { Tag = new PTaskFS { GUID = task.TaskId ?? "", Node = task.Title ?? "", Parent = task.ParentTaskId ?? "", HourlyRate = task.HourlyRate, ProjectId = task.ProjectId ?? "" } });
treeViewTasks1.SelectedNode.Nodes.Add(new TreeNode(task.Title ?? "") { Tag = new PTaskFS { GUID = task.TaskId ?? "", Node = task.Title ?? "", Parent = task.ParentTaskId ?? "", HourlyRate = task.HourlyRate, ProjectId = task.ProjectId ?? "" } });
//_ctrl.LoadTasks();
}
catch (Exception ex)
@ -649,6 +683,48 @@ namespace trakker
{
dataGridViewProjectTasks_SelectionChanged(s, e);
};
dataGridViewProjectTasks.DoubleClick += (s, e) =>
{ // BCN
var projectIdx = dataGridViewProjects.SelectedRows[0].Index;
var taskIdx = dataGridViewProjectTasks.SelectedRows[0].Index;
var row = dataGridViewProjectTasks.SelectedRows[0];
if (row != null)
{
var task = dataGridViewProjectTasks.SelectedRows[0].DataBoundItem as PTask;
TaskForm dialog = new TaskForm(task!, _ctrl.GetLOV("task.status"), _ctrl.GetLOV("task.priority"));
DialogResult result = dialog.ShowDialog(this);
if (result == DialogResult.OK)
{
task = dialog.Task;
try
{
TaskData taskData = new TaskData(connectionString);
taskData.Upsert(task);
//_ctrl.LoadTasks(task.ProjectId ?? string.Empty); // Reload tasks to update the DataGridView with any changes
_ctrl.LoadProjects(); // Reload projects to update the DataGridView with any changes
_ctrl.LoadTasksRecursive(task.TaskId ?? string.Empty, PTask.RecursiveRoot.TASK_ID); // Reload tasks to update the tree view with any changes
dataGridViewProjects.ClearSelection();
if (projectIdx >= 0 && projectIdx < dataGridViewProjects.Rows.Count)
{
dataGridViewProjects.Rows[projectIdx].Selected = true;
}
dataGridViewProjectTasks.ClearSelection();
if (taskIdx >= 0 && taskIdx < dataGridViewProjectTasks.Rows.Count)
{
dataGridViewProjectTasks.Rows[taskIdx].Selected = true;
}
}
catch (Exception ex)
{
MessageBox.Show($"Error saving task: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
};
}
public void dataGridViewProjectTasks_SelectionChanged(object? sender, EventArgs? e)
{
@ -658,7 +734,6 @@ namespace trakker
var selectedTask = dataGridViewProjectTasks.SelectedRows[0].DataBoundItem as PTask;
if (selectedTask != null)
{
richTextBoxTaskDescription.Text = selectedTask.Description;
TaskData taskData = new TaskData(connectionString);
List<PTaskComment> comments = taskData.GetComments(selectedTask.TaskId ?? string.Empty);
richTextBoxTaskComments.Clear();
@ -671,9 +746,26 @@ namespace trakker
}
public void FillDataGridViewProjectTasks(BindingSource tasks)
{
//dataGridViewProjectTasks.Rows.Clear();
dataGridViewProjectTasks.DataSource = tasks;
dataGridViewProjectTasks.Refresh();
//dataGridViewProjectTasks.Refresh();
}
private void richTextBoxTaskComments_LinkClicked(object sender, LinkClickedEventArgs e)
{
try
{
// Open the URL in the default browser
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
{
FileName = e.LinkText,
UseShellExecute = true
});
}
catch (Exception ex)
{
DialogExtensions.GenericError(String.Format($"Failed to open link: {ex.Message}"));
}
}
}
}

View File

@ -16,6 +16,7 @@ namespace trakker.Interfaces
void FillTreeViewTasks(List<PTaskFS> items);
void InitTreeViewTasks();
void InitDataGridViewProjectTasks();
void InitProjectTasks();
void FillDataGridViewProjectTasks(BindingSource tasks);
}
}

View File

@ -59,12 +59,14 @@ namespace trakker.Services
var x = project.Status;
}
_view.FillDataGridViewProjects(new BindingSource { DataSource = projects });
LoadTasks();
//LoadTasks();
}
internal void LoadTasks()
internal void LoadTasks(string projectId)
{
var dbo = new TaskData(_connectionString);
_view.FillTreeViewTasks(dbo.GetFS());
_view.FillTreeViewTasks(dbo.GetFS(projectId));
_view.InitProjectTasks();
//_view.InitDataGridViewProjectTasks();
}
internal void LoadTasksRecursive(string id, PTask.RecursiveRoot root)
{