|
@@ -1,13 +1,16 @@
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
+using System.ComponentModel;
|
|
|
using System.Drawing;
|
|
|
using System.Globalization;
|
|
|
using System.Linq;
|
|
|
using System.Reflection;
|
|
|
+using System.Runtime.CompilerServices;
|
|
|
using System.Windows;
|
|
|
using System.Windows.Controls;
|
|
|
using System.Windows.Data;
|
|
|
using System.Windows.Input;
|
|
|
+using System.Windows.Media.Imaging;
|
|
|
using Comal.Classes;
|
|
|
using InABox.Clients;
|
|
|
using InABox.Core;
|
|
@@ -16,711 +19,623 @@ using InABox.WPF;
|
|
|
using Syncfusion.UI.Xaml.Kanban;
|
|
|
using Syncfusion.Windows.Tools.Controls;
|
|
|
|
|
|
-namespace PRSDesktop
|
|
|
+namespace PRSDesktop;
|
|
|
+
|
|
|
+public class TasksByUserEmployeeHeader
|
|
|
+{
|
|
|
+ public Guid EmployeeID { get; set; }
|
|
|
+
|
|
|
+ public string Name { get; set; }
|
|
|
+
|
|
|
+ public BitmapImage Image { get; set; }
|
|
|
+
|
|
|
+ public int NumTasks { get => Tasks.Count(); }
|
|
|
+
|
|
|
+ public double NumHours { get => Tasks.Sum(x => x.EstimatedTime.TotalHours); }
|
|
|
+
|
|
|
+ public IEnumerable<TaskModel> Tasks => Model.Categories
|
|
|
+ .SelectMany(x => x.EmployeeCategoryDictionary.GetValueOrDefault(EmployeeID)?.Tasks ?? Enumerable.Empty<TaskModel>());
|
|
|
+
|
|
|
+ private TasksByUserModel Model;
|
|
|
+
|
|
|
+ public TasksByUserEmployeeHeader(Guid employeeID, string name, BitmapImage image, TasksByUserModel model)
|
|
|
+ {
|
|
|
+ EmployeeID = employeeID;
|
|
|
+ Name = name;
|
|
|
+ Image = image;
|
|
|
+ Model = model;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+public class TasksByUserEmployeeCategory
|
|
|
{
|
|
|
- /*
|
|
|
- public class UserTasksHeaderImageConverter : IValueConverter
|
|
|
+ public Guid EmployeeID { get; set; }
|
|
|
+
|
|
|
+ public List<TaskModel> Tasks { get; set; } = new();
|
|
|
+
|
|
|
+ public TasksByUserEmployeeCategory(Guid employeeID)
|
|
|
{
|
|
|
- public static Dictionary<Guid, byte[]> Images { get; set; }
|
|
|
- public static Dictionary<Guid, Guid> Employees { get; set; }
|
|
|
+ EmployeeID = employeeID;
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
|
|
- {
|
|
|
- var anonymous = Resources.anonymous.AsBitmapImage();
|
|
|
+public class TasksByUserCategory
|
|
|
+{
|
|
|
+ public string Category { get; set; }
|
|
|
+
|
|
|
+ public IEnumerable<TasksByUserEmployeeCategory> EmployeeCategories => EmployeeCategoryDictionary.Values;
|
|
|
|
|
|
- if (Images == null)
|
|
|
- return anonymous;
|
|
|
+ public Dictionary<Guid, TasksByUserEmployeeCategory> EmployeeCategoryDictionary { get; set; } = new();
|
|
|
+
|
|
|
+ public TasksByUserCategory(string category)
|
|
|
+ {
|
|
|
+ Category = category;
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- if (Employees == null)
|
|
|
- return anonymous;
|
|
|
+public class TasksByUserModel
|
|
|
+{
|
|
|
+ public List<TasksByUserEmployeeHeader> SectionHeaders { get; set; } = new();
|
|
|
|
|
|
- var dataContext = value as ColumnTag;
|
|
|
- if (dataContext == null)
|
|
|
- return anonymous;
|
|
|
+ public List<TasksByUserCategory> Categories { get; set; } = new();
|
|
|
+}
|
|
|
|
|
|
- var getter = dataContext.GetType().GetProperty("Column", BindingFlags.NonPublic | BindingFlags.Instance);
|
|
|
- if (getter == null)
|
|
|
- return anonymous;
|
|
|
+public partial class TasksByUserControl : UserControl, INotifyPropertyChanged, ITaskControl
|
|
|
+{
|
|
|
+ private static readonly BitmapImage anonymous = PRSDesktop.Resources.anonymous.AsBitmapImage();
|
|
|
|
|
|
- var column = (KanbanColumn)getter.GetValue(dataContext);
|
|
|
- if (column == null)
|
|
|
- return anonymous;
|
|
|
+ public TasksByUserModel Model { get; set; }
|
|
|
|
|
|
- if (!Guid.TryParse(column.Categories, out var empid))
|
|
|
- return anonymous;
|
|
|
+ private ILookup<Guid, Guid> TeamEmployees;
|
|
|
|
|
|
- if (!Employees.TryGetValue(empid, out var imageid))
|
|
|
- return anonymous;
|
|
|
+ private Dictionary<Guid, EmployeeModel> Employees;
|
|
|
|
|
|
- if (!Images.TryGetValue(imageid, out var data))
|
|
|
- return anonymous;
|
|
|
+ private KanbanViewMode _mode;
|
|
|
|
|
|
- return ImageUtils.LoadImage(data);
|
|
|
- }
|
|
|
+ private bool bPopulating;
|
|
|
|
|
|
- public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
|
|
+ public KanbanViewMode Mode
|
|
|
+ {
|
|
|
+ get => _mode;
|
|
|
+ set
|
|
|
{
|
|
|
- throw new NotImplementedException();
|
|
|
+ _mode = value;
|
|
|
+ OnPropertyChanged();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- public class UserTasksHeaderTimeConverter : IValueConverter
|
|
|
+ public TasksByUserControl()
|
|
|
{
|
|
|
- public static IEnumerable<TaskModel> Kanbans { get; set; }
|
|
|
+ InitializeComponent();
|
|
|
+ }
|
|
|
|
|
|
- public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
|
|
- {
|
|
|
- if (Kanbans == null)
|
|
|
- return "0:00";
|
|
|
+ #region INotifyPropertyChanged
|
|
|
+
|
|
|
+ public event PropertyChangedEventHandler? PropertyChanged;
|
|
|
|
|
|
- var dataContext = value as ColumnTag;
|
|
|
- if (dataContext == null)
|
|
|
- return "0:00";
|
|
|
+ // Create the OnPropertyChanged method to raise the event
|
|
|
+ // The calling member's name will be used as the parameter.
|
|
|
+ protected void OnPropertyChanged([CallerMemberName] string? name = null)
|
|
|
+ {
|
|
|
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
|
|
|
+ }
|
|
|
|
|
|
- var getter = dataContext.GetType().GetProperty("Column", BindingFlags.NonPublic | BindingFlags.Instance);
|
|
|
- if (getter == null)
|
|
|
- return "0:00";
|
|
|
+ #endregion
|
|
|
|
|
|
- var column = (KanbanColumn)getter.GetValue(dataContext);
|
|
|
- if (column == null)
|
|
|
- return "0:00";
|
|
|
+ #region Setup
|
|
|
+
|
|
|
+ private void LoadEmployees()
|
|
|
+ {
|
|
|
+ var empfilter = LookupFactory.DefineFilter<Employee>();
|
|
|
|
|
|
- double result = 0.0F;
|
|
|
- foreach (var kanban in Kanbans.Where(x => Equals(x.Category, column.Categories)))
|
|
|
- result += kanban.EstimatedTime.TotalHours;
|
|
|
- return string.Format("{0:F2}", result);
|
|
|
+ var results = Client.QueryMultiple(
|
|
|
+ new KeyedQueryDef<Employee>(
|
|
|
+ LookupFactory.DefineFilter<Employee>(),
|
|
|
+ new Columns<Employee>(x => x.ID)
|
|
|
+ .Add(x => x.Name)
|
|
|
+ .Add(x => x.Thumbnail.ID),
|
|
|
+ new SortOrder<Employee>(x => x.Name)),
|
|
|
+ new KeyedQueryDef<Team>(
|
|
|
+ LookupFactory.DefineFilter<Team>(),
|
|
|
+ new Columns<Team>(x => x.ID)
|
|
|
+ .Add(x => x.Name),
|
|
|
+ new SortOrder<Team>(x => x.Name)),
|
|
|
+ new KeyedQueryDef<EmployeeTeam>(
|
|
|
+ LookupFactory.DefineFilter<EmployeeTeam>(),
|
|
|
+ new Columns<EmployeeTeam>(x => x.EmployeeLink.ID)
|
|
|
+ .Add(x => x.TeamLink.ID)));
|
|
|
+
|
|
|
+ TeamEmployees = results.Get<EmployeeTeam>().ToLookup<EmployeeTeam, Guid, Guid>(x => x.TeamLink.ID, x => x.EmployeeLink.ID);
|
|
|
+ Employees = results.GetObjects<Employee>().ToDictionary(
|
|
|
+ x => x.ID,
|
|
|
+ x => new EmployeeModel(x.ID, x.Name, x.Thumbnail.ID, null));
|
|
|
+
|
|
|
+ var teams = results.GetObjects<Team>().ToDictionary(x => x.ID, x => x.Name);
|
|
|
+ SelectedTeams.ItemsSource = teams;
|
|
|
+ foreach (var team in Host.KanbanSettings.UserSettings.SelectedTeams)
|
|
|
+ {
|
|
|
+ SelectedTeams.SelectedItems.Add(teams.Where(x => x.Key == team));
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
|
|
+ private void PopulateEmployees()
|
|
|
+ {
|
|
|
+ bPopulating = true;
|
|
|
+ try
|
|
|
{
|
|
|
- throw new NotImplementedException();
|
|
|
+ var availableemployees = new List<Guid>();
|
|
|
+ foreach (var team in SelectedTeams.SelectedItems.Select(v => (KeyValuePair<Guid, string>)v))
|
|
|
+ availableemployees.AddRange(TeamEmployees[team.Key].Where(x => !availableemployees.Contains(x)));
|
|
|
+
|
|
|
+ SelectedEmployees.ItemsSource = Employees.Where(x => availableemployees.Contains(x.Key));
|
|
|
+ SelectedEmployees.SelectedItems.Clear();
|
|
|
+ foreach (var employee in Host.KanbanSettings.UserSettings.SelectedEmployees.Where(x => availableemployees.Contains(x)))
|
|
|
+ SelectedEmployees.SelectedItems.Add(Employees.FirstOrDefault(x => Equals(x.Key, employee)));
|
|
|
}
|
|
|
+ catch (Exception e)
|
|
|
+ {
|
|
|
+ }
|
|
|
+
|
|
|
+ bPopulating = false;
|
|
|
}
|
|
|
|
|
|
-//public class TaskHeaderWidthConverter : IValueConverter
|
|
|
-//{
|
|
|
+ private void SetupToolbar()
|
|
|
+ {
|
|
|
+ IncludeCompleted.Visibility = Security.IsAllowed<CanHideTaskCompletedColumn>() ? Visibility.Visible : Visibility.Collapsed;
|
|
|
+ IncludeCompleted.IsChecked = IncludeCompleted.Visibility == Visibility.Visible ? Host.KanbanSettings.UserSettings.IncludeCompleted : true;
|
|
|
+ IncludeObserved.IsChecked = Host.KanbanSettings.UserSettings.IncludeObserved;
|
|
|
+ IncludeManaged.IsChecked = Host.KanbanSettings.UserSettings.IncludeManaged;
|
|
|
+ ViewType.SelectedIndex = Host.KanbanSettings.UserSettings.CompactView ? 1 : 0;
|
|
|
+ }
|
|
|
|
|
|
-// public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
|
|
-// {
|
|
|
-// var dataContext = (value as ColumnTag);
|
|
|
-// if (dataContext == null)
|
|
|
-// return 150;
|
|
|
+ private void PopulateKanbanTypes()
|
|
|
+ {
|
|
|
+ TaskType.Items.Add("");
|
|
|
+ foreach (var kanbanType in Host.KanbanTypes)
|
|
|
+ {
|
|
|
+ TaskType.Items.Add(kanbanType);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
-// PropertyInfo getter = dataContext.GetType().GetProperty("Column", BindingFlags.NonPublic | BindingFlags.Instance);
|
|
|
-// if (getter == null)
|
|
|
-// return 150;
|
|
|
+ public void Setup()
|
|
|
+ {
|
|
|
+ SetupToolbar();
|
|
|
|
|
|
-// KanbanColumn column = (KanbanColumn)getter.GetValue(dataContext);
|
|
|
-// if (column == null)
|
|
|
-// return 150;
|
|
|
+ SplitPanel.AnchorWidth = Host.KanbanSettings.UserSettings.AnchorWidth;
|
|
|
+ TeamsRow.Height = new GridLength(Host.KanbanSettings.UserSettings.TeamsHeight);
|
|
|
|
|
|
-// return Math.Max(150, column.Width) - 20 ;
|
|
|
+ LoadEmployees();
|
|
|
+ PopulateEmployees();
|
|
|
|
|
|
-// }
|
|
|
+ Mode = Host.KanbanSettings.StatusSettings.CompactView ? KanbanViewMode.Compact : KanbanViewMode.Full;
|
|
|
|
|
|
-// public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
|
|
-// {
|
|
|
-// throw new NotImplementedException();
|
|
|
-// }
|
|
|
-//}
|
|
|
+ PopulateKanbanTypes();
|
|
|
+ }
|
|
|
|
|
|
- /// <summary>
|
|
|
- /// Interaction logic for TaskListPanel.xaml
|
|
|
- /// </summary>
|
|
|
- public partial class TasksByUserControl : UserControl, ITaskControl
|
|
|
- {
|
|
|
- private Dictionary<Guid, string> _employees;
|
|
|
+ #endregion
|
|
|
|
|
|
- private List<TaskModel> _models = new();
|
|
|
- private ILookup<Guid, Guid> _teamemployees;
|
|
|
- private Dictionary<Guid, string> _teams;
|
|
|
+ #region Refresh
|
|
|
|
|
|
- private bool bPopulating;
|
|
|
+ private Filter<KanbanSubscriber> GetKanbanSubscriberFilter()
|
|
|
+ {
|
|
|
+ var filter = new Filter<KanbanSubscriber>(c => c.Kanban.Closed).IsEqualTo(DateTime.MinValue)
|
|
|
+ .And(x => x.Kanban.Locked).IsEqualTo(false);
|
|
|
|
|
|
- public TasksByUserControl()
|
|
|
+ var privateFilter = new Filter<KanbanSubscriber>(x => x.Kanban.Private).IsEqualTo(false);
|
|
|
+ if (App.EmployeeID != Guid.Empty)
|
|
|
{
|
|
|
- InitializeComponent();
|
|
|
+ privateFilter = privateFilter.Or(x => x.Employee.ID).IsEqualTo(App.EmployeeID);
|
|
|
}
|
|
|
-
|
|
|
- public bool IsReady { get; set; }
|
|
|
+ filter.And(privateFilter);
|
|
|
|
|
|
- #region Setup
|
|
|
-
|
|
|
- public void Setup()
|
|
|
+ if (Host.Job != null)
|
|
|
{
|
|
|
- SetupToolbar();
|
|
|
-
|
|
|
- SplitPanel.AnchorWidth = Host.KanbanSettings.UserSettings.AnchorWidth;
|
|
|
-
|
|
|
- TeamsRow.Height = new GridLength(Host.KanbanSettings.UserSettings.TeamsHeight);
|
|
|
+ if (Host.Job.ID != Guid.Empty)
|
|
|
+ filter = filter.And(c => c.Kanban.JobLink.ID).IsEqualTo(Host.Job.ID);
|
|
|
+ else
|
|
|
+ filter = filter.And(c => c.Kanban.JobLink.ID).None();
|
|
|
+ }
|
|
|
|
|
|
- LoadEmployees();
|
|
|
+ if (!Host.KanbanSettings.UserSettings.IncludeCompleted)
|
|
|
+ filter = filter.And(new Filter<KanbanSubscriber>(x => x.Kanban.Completed).IsEqualTo(DateTime.MinValue));
|
|
|
|
|
|
- foreach (var team in Host.KanbanSettings.UserSettings.SelectedTeams)
|
|
|
- SelectedTeams.SelectedItems.Add(_teams.FirstOrDefault(x => Equals(x.Key, team)));
|
|
|
+ var emps = Employees.Where(x => Host.KanbanSettings.UserSettings.SelectedEmployees.Contains(x.Key));
|
|
|
|
|
|
- PopulateEmployees();
|
|
|
- PopulateKanbanTypes();
|
|
|
+ filter = filter.And(c => c.Employee.ID).InList(emps.Select(x => x.Key).ToArray());
|
|
|
+ if (!Host.KanbanSettings.UserSettings.IncludeObserved)
|
|
|
+ {
|
|
|
+ if (Host.KanbanSettings.UserSettings.IncludeManaged)
|
|
|
+ filter = filter.And(new Filter<KanbanSubscriber>(x => x.Manager).IsEqualTo(true).Or(x => x.Assignee).IsEqualTo(true));
|
|
|
+ else
|
|
|
+ filter = filter.And(x => x.Assignee).IsEqualTo(true);
|
|
|
}
|
|
|
+ return filter;
|
|
|
+ }
|
|
|
|
|
|
- private void PopulateKanbanTypes()
|
|
|
+ private void ReloadColumns()
|
|
|
+ {
|
|
|
+ Model.SectionHeaders.Clear();
|
|
|
+ foreach (var employeeID in Host.KanbanSettings.UserSettings.SelectedEmployees)
|
|
|
{
|
|
|
- TaskType.Items.Add("");
|
|
|
- foreach(var kanbanType in Host.KanbanTypes)
|
|
|
+ if (Employees.TryGetValue(employeeID, out var employee))
|
|
|
{
|
|
|
- TaskType.Items.Add(kanbanType);
|
|
|
+ Model.SectionHeaders.Add(new TasksByUserEmployeeHeader(employeeID, employee.Name, employee.Image ?? anonymous, Model));
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Refresh()
|
|
|
+ {
|
|
|
+ var categoryOrder = new Dictionary<string, int>
|
|
|
+ {
|
|
|
+ { Kanban.OPEN, 0 },
|
|
|
+ { Kanban.INPROGRESS, 1 },
|
|
|
+ { Kanban.WAITING, 2 },
|
|
|
+ { Kanban.COMPLETE, 3 }
|
|
|
+ };
|
|
|
+ var filter = GetKanbanSubscriberFilter();
|
|
|
+
|
|
|
+ using (new WaitCursor())
|
|
|
+ {
|
|
|
+ var kanbans = new Client<KanbanSubscriber>().Query(
|
|
|
+ filter,
|
|
|
+ new Columns<KanbanSubscriber>
|
|
|
+ (
|
|
|
+ x => x.Kanban.ID,
|
|
|
+ x => x.Kanban.DueDate,
|
|
|
+ x => x.Kanban.Completed,
|
|
|
+ //x => x.Kanban.Description,
|
|
|
+ x => x.Kanban.Summary,
|
|
|
+ x => x.Kanban.Category,
|
|
|
+ x => x.Kanban.EmployeeLink.ID,
|
|
|
+ x => x.Kanban.EmployeeLink.Name,
|
|
|
+ x => x.Kanban.ManagerLink.ID,
|
|
|
+ x => x.Kanban.ManagerLink.Name,
|
|
|
+ x => x.Kanban.Notes,
|
|
|
+ x => x.Kanban.Title,
|
|
|
+ x => x.Kanban.JobLink.ID,
|
|
|
+ x => x.Kanban.JobLink.JobNumber,
|
|
|
+ x => x.Kanban.JobLink.Name,
|
|
|
+ x => x.Kanban.Type.ID,
|
|
|
+ x => x.Kanban.Type.Code,
|
|
|
+ x => x.Kanban.Number,
|
|
|
+ x => x.Kanban.Attachments,
|
|
|
+ x => x.Kanban.Locked,
|
|
|
+ x => x.Employee.ID,
|
|
|
+ x => x.Kanban.EstimatedTime
|
|
|
+ ),
|
|
|
+ new SortOrder<KanbanSubscriber>(x => x.Kanban.DueDate) { Direction = SortDirection.Ascending }
|
|
|
+ );
|
|
|
+ var models = CreateModels(kanbans.ToObjects<KanbanSubscriber>()).ToList();
|
|
|
|
|
|
- #endregion
|
|
|
+ ReloadColumns();
|
|
|
|
|
|
- private void SetupToolbar()
|
|
|
- {
|
|
|
- IncludeCompleted.Visibility = Security.IsAllowed<CanHideTaskCompletedColumn>() ? Visibility.Visible : Visibility.Collapsed;
|
|
|
- IncludeCompleted.IsChecked = IncludeCompleted.Visibility == Visibility.Visible ? Host.KanbanSettings.UserSettings.IncludeCompleted : true;
|
|
|
- IncludeObserved.IsChecked = Host.KanbanSettings.UserSettings.IncludeObserved;
|
|
|
- IncludeManaged.IsChecked = Host.KanbanSettings.UserSettings.IncludeManaged;
|
|
|
- ViewType.SelectedIndex = Host.KanbanSettings.UserSettings.CompactView ? 1 : 0;
|
|
|
+ AllTasks = models.OrderBy(x => categoryOrder[x.Category]).ThenBy(x => x.DueDate).ToList();
|
|
|
+ FilterKanbans();
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- public void Refresh(bool resetselection)
|
|
|
- {
|
|
|
- var _swimlanes = new Dictionary<string, int>
|
|
|
+ private void FilterKanbans()
|
|
|
+ {
|
|
|
+ var categoryOrder = new Dictionary<string, int>
|
|
|
{
|
|
|
- { "Open", 0 },
|
|
|
- { "In Progress", 1 },
|
|
|
- { "Waiting", 2 },
|
|
|
- { "Complete", 3 }
|
|
|
+ { Kanban.OPEN, 0 },
|
|
|
+ { Kanban.INPROGRESS, 1 },
|
|
|
+ { Kanban.WAITING, 2 },
|
|
|
+ { Kanban.COMPLETE, 3 }
|
|
|
};
|
|
|
|
|
|
- var filter = new Filter<KanbanSubscriber>(c => c.Kanban.Closed).IsEqualTo(DateTime.MinValue)
|
|
|
- .And(x => x.Kanban.Locked).IsEqualTo(false);
|
|
|
+ IEnumerable<TaskModel> filtered = AllTasks;
|
|
|
+ if (TaskType.SelectedItem is KanbanType kanbanType)
|
|
|
+ {
|
|
|
+ filtered = filtered.Where(x => x.Type.ID == kanbanType.ID);
|
|
|
+ }
|
|
|
+ if (!string.IsNullOrWhiteSpace(Search.Text))
|
|
|
+ {
|
|
|
+ var searches = Search.Text.Split();
|
|
|
+ filtered = filtered.Where(x => x.Search(searches));
|
|
|
+ }
|
|
|
+
|
|
|
+ var categories = new Dictionary<string, TasksByUserCategory>();
|
|
|
|
|
|
- var privateFilter = new Filter<KanbanSubscriber>(x => x.Kanban.Private).IsEqualTo(false);
|
|
|
- if (App.EmployeeID != Guid.Empty)
|
|
|
+ foreach (var task in filtered)
|
|
|
+ {
|
|
|
+ if(!categories.TryGetValue(task.Category, out var category))
|
|
|
{
|
|
|
- privateFilter = privateFilter.Or(x => x.Employee.ID).IsEqualTo(App.EmployeeID);
|
|
|
+ category = new TasksByUserCategory(task.Category);
|
|
|
+ categories.Add(task.Category, category);
|
|
|
}
|
|
|
- filter.And(privateFilter);
|
|
|
|
|
|
- if (Host.Job != null)
|
|
|
+ if(!category.EmployeeCategoryDictionary.TryGetValue(task.EmployeeCategory, out var employeeCategory))
|
|
|
{
|
|
|
- if (Host.Job.ID != Guid.Empty)
|
|
|
- filter = filter.And(c => c.Kanban.JobLink.ID).IsEqualTo(Host.Job.ID);
|
|
|
- else
|
|
|
- filter = filter.And(c => c.Kanban.JobLink.ID).None();
|
|
|
+ employeeCategory = new TasksByUserEmployeeCategory(task.EmployeeCategory);
|
|
|
+ category.EmployeeCategoryDictionary.Add(task.EmployeeCategory, employeeCategory);
|
|
|
}
|
|
|
|
|
|
- if (!Host.KanbanSettings.UserSettings.IncludeCompleted)
|
|
|
- filter = filter.And(new Filter<KanbanSubscriber>(x => x.Kanban.Completed).IsEqualTo(DateTime.MinValue));
|
|
|
+ employeeCategory.Tasks.Add(task);
|
|
|
+ if (task.Checked)
|
|
|
+ {
|
|
|
+ SelectedTasks.Add(task);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- var emps = _employees.Where(x => Host.KanbanSettings.UserSettings.SelectedEmployees.Contains(x.Key));
|
|
|
- //if (Host.Settings.UserSettings.IncludeObserved)
|
|
|
- // filter = filter.And(x => x.Manager).IsEqualTo(false);
|
|
|
- //else
|
|
|
- // filter = filter.And(x => x.Assignee).IsEqualTo(true);
|
|
|
- filter = filter.And(c => c.Employee.ID).InList(emps.Select(x => x.Key).ToArray());
|
|
|
- if (!Host.KanbanSettings.UserSettings.IncludeObserved)
|
|
|
+ Model.Categories.AddRange(categories.Values.OrderBy(x => categoryOrder[x.Category]));
|
|
|
+ }
|
|
|
+
|
|
|
+ private IEnumerable<TaskModel> CreateModels(IEnumerable<KanbanSubscriber> subscribers)
|
|
|
+ {
|
|
|
+ foreach(var subscriber in subscribers)
|
|
|
+ {
|
|
|
+ var kanban = subscriber.Kanban;
|
|
|
+
|
|
|
+ var empValid = Entity.IsEntityLinkValid<KanbanSubscriber, EmployeeLink>(x => x.Kanban.EmployeeLink, row);
|
|
|
+ var mgrValid = Entity.IsEntityLinkValid<KanbanSubscriber, EmployeeLink>(x => x.Kanban.ManagerLink, row);
|
|
|
+
|
|
|
+ var completed = row.Get<KanbanSubscriber, DateTime>(e => e.Kanban.Completed);
|
|
|
+ var locked = row.Get<KanbanSubscriber, bool>(e => e.Kanban.Locked);
|
|
|
+ var typeID = row.Get<KanbanSubscriber, Guid>(e => e.Kanban.Type.ID);
|
|
|
+ var typeCode = row.Get<KanbanSubscriber, string>(e => e.Kanban.Type.Code);
|
|
|
+ var job = row.Get<KanbanSubscriber, string>(x => x.Kanban.JobLink.JobNumber);
|
|
|
+
|
|
|
+ var model = new TaskModel();
|
|
|
+
|
|
|
+ model.Title = kanban.Title;
|
|
|
+ model.ID = kanban.ID;
|
|
|
+ model.Description = kanban.Summary ?? "";
|
|
|
+ model.EmployeeCategory = subscriber.Employee.ID;
|
|
|
+ model.Category = kanban.Category;
|
|
|
+
|
|
|
+ if (model.Category.IsNullOrWhiteSpace())
|
|
|
+ model.Category = "Open";
|
|
|
+
|
|
|
+ var colour = subscriber.Employee.ID == kanban.EmployeeLink.ID
|
|
|
+ ? TaskModel.KanbanColor(
|
|
|
+ kanban.DueDate,
|
|
|
+ kanban.Completed)
|
|
|
+ : subscriber.Employee.ID == kanban.ManagerLink.ID
|
|
|
+ ? Color.Silver
|
|
|
+ : Color.Plum;
|
|
|
+ if (kanban.Locked)
|
|
|
{
|
|
|
- if (Host.KanbanSettings.UserSettings.IncludeManaged)
|
|
|
- filter = filter.And(new Filter<KanbanSubscriber>(x => x.Manager).IsEqualTo(true).Or(x => x.Assignee).IsEqualTo(true));
|
|
|
- else
|
|
|
- filter = filter.And(x => x.Assignee).IsEqualTo(true);
|
|
|
+ colour = colour.MixColors(0.5F, Color.White);
|
|
|
}
|
|
|
+ model.Color = System.Windows.Media.Color.FromArgb(colour.A, colour.R, colour.G, colour.B);
|
|
|
+
|
|
|
+ model.Attachments = kanban.Attachments > 0;
|
|
|
+ model.DueDate = kanban.DueDate;
|
|
|
+ model.CompletedDate = kanban.Completed;
|
|
|
+ model.Locked = kanban.Locked;
|
|
|
+ model.EstimatedTime = kanban.EstimatedTime;
|
|
|
|
|
|
- using (new WaitCursor())
|
|
|
+ var notes = new List<List<string>> { new() };
|
|
|
+ var kanbanNotes = kanban.Notes;
|
|
|
+ if (kanbanNotes != null)
|
|
|
{
|
|
|
- var kanbans = new Client<KanbanSubscriber>().Query(
|
|
|
- filter,
|
|
|
- new Columns<KanbanSubscriber>
|
|
|
- (
|
|
|
- x => x.Kanban.ID,
|
|
|
- x => x.Kanban.DueDate,
|
|
|
- x => x.Kanban.Completed,
|
|
|
- //x => x.Kanban.Description,
|
|
|
- x => x.Kanban.Summary,
|
|
|
- x => x.Kanban.Category,
|
|
|
- x => x.Kanban.EmployeeLink.ID,
|
|
|
- x => x.Kanban.EmployeeLink.Name,
|
|
|
- x => x.Kanban.ManagerLink.ID,
|
|
|
- x => x.Kanban.ManagerLink.Name,
|
|
|
- x => x.Kanban.Notes,
|
|
|
- x => x.Kanban.Title,
|
|
|
- x => x.Kanban.JobLink.ID,
|
|
|
- x => x.Kanban.JobLink.JobNumber,
|
|
|
- x => x.Kanban.JobLink.Name,
|
|
|
- x => x.Kanban.Type.ID,
|
|
|
- x => x.Kanban.Type.Code,
|
|
|
- x => x.Kanban.Number,
|
|
|
- x => x.Kanban.Attachments,
|
|
|
- x => x.Kanban.Locked,
|
|
|
- x => x.Employee.ID,
|
|
|
- x => x.Kanban.EstimatedTime
|
|
|
- ),
|
|
|
- new SortOrder<KanbanSubscriber>(x => x.Kanban.DueDate) { Direction = SortDirection.Ascending }
|
|
|
- );
|
|
|
- var models = new List<TaskModel>();
|
|
|
- foreach (var row in kanbans.Rows)
|
|
|
+ foreach (var line in kanbanNotes)
|
|
|
{
|
|
|
- var empid = row.Get<KanbanSubscriber, Guid>(e => e.Kanban.EmployeeLink.ID);
|
|
|
- var mgrid = row.Get<KanbanSubscriber, Guid>(e => e.Kanban.ManagerLink.ID);
|
|
|
- var subid = row.Get<KanbanSubscriber, Guid>(e => e.Employee.ID);
|
|
|
- var empValid = Entity.IsEntityLinkValid<KanbanSubscriber, EmployeeLink>(x => x.Kanban.EmployeeLink, row);
|
|
|
- var mgrValid = Entity.IsEntityLinkValid<KanbanSubscriber, EmployeeLink>(x => x.Kanban.ManagerLink, row);
|
|
|
-
|
|
|
- var completed = row.Get<KanbanSubscriber, DateTime>(e => e.Kanban.Completed);
|
|
|
- var locked = row.Get<KanbanSubscriber, bool>(e => e.Kanban.Locked);
|
|
|
- var typeID = row.Get<KanbanSubscriber, Guid>(e => e.Kanban.Type.ID);
|
|
|
- var typeCode = row.Get<KanbanSubscriber, string>(e => e.Kanban.Type.Code);
|
|
|
- var job = row.Get<KanbanSubscriber, string>(x => x.Kanban.JobLink.JobNumber);
|
|
|
-
|
|
|
- var model = new TaskModel();
|
|
|
-
|
|
|
- model.Title = row.Get<KanbanSubscriber, string>(x => x.Kanban.Title);
|
|
|
- model.ID = row.Get<KanbanSubscriber, Guid>(x => x.Kanban.ID).ToString();
|
|
|
- model.Description = row.Get<KanbanSubscriber, string>(x => x.Kanban.Summary) ?? "";
|
|
|
- model.Category = row.Get<KanbanSubscriber, Guid>(c => c.Employee.ID).ToString();
|
|
|
- model.Assignee = row.Get<KanbanSubscriber, string>(c => c.Kanban.Category);
|
|
|
-
|
|
|
- if (string.IsNullOrWhiteSpace(model.Assignee) || !_swimlanes.ContainsKey(model.Assignee))
|
|
|
- model.Assignee = "Open";
|
|
|
-
|
|
|
- var kanbancolor = subid == empid
|
|
|
- ? TaskModel.KanbanColor(
|
|
|
- row.Get<KanbanSubscriber, DateTime>(x => x.Kanban.DueDate),
|
|
|
- row.Get<KanbanSubscriber, DateTime>(x => x.Kanban.Completed))
|
|
|
- : subid == mgrid
|
|
|
- ? Color.Silver
|
|
|
- : Color.Plum;
|
|
|
- if (row.Get<KanbanSubscriber, bool>(x => x.Kanban.Locked))
|
|
|
- kanbancolor = kanbancolor.MixColors(0.5F, Color.White);
|
|
|
- model.ColorKey = ImageUtils.ColorToString(kanbancolor);
|
|
|
-
|
|
|
- model.Image = null;
|
|
|
- model.ImageURL = null;
|
|
|
- model.Attachments =
|
|
|
- row.Get<KanbanSubscriber, int>(x => x.Kanban.Attachments) > 0; // ? PRSDesktop.Resources.attachment.AsBitmapImage() : null;
|
|
|
- model.DueDate = row.Get<KanbanSubscriber, DateTime>(x => x.Kanban.DueDate);
|
|
|
- model.CompletedDate = row.Get<KanbanSubscriber, DateTime>(x => x.Kanban.Completed);
|
|
|
- model.Locked = row.Get<KanbanSubscriber, bool>(x => x.Kanban.Locked); // ? PRSDesktop.Resources.locked.AsBitmapImage() : null;
|
|
|
- model.EstimatedTime = row.Get<KanbanSubscriber, TimeSpan>(x => x.Kanban.EstimatedTime);
|
|
|
-
|
|
|
- var notes = new List<List<string>> { new() };
|
|
|
- var kanbanNotes = row.Get<KanbanSubscriber, string[]>(x => x.Kanban.Notes);
|
|
|
- if(kanbanNotes != null)
|
|
|
+ if (line == "===================================")
|
|
|
{
|
|
|
- foreach (var line in kanbanNotes)
|
|
|
- {
|
|
|
- if (line == "===================================")
|
|
|
- {
|
|
|
- notes.Add(new());
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- notes.Last().Add(line);
|
|
|
- }
|
|
|
- }
|
|
|
+ notes.Add(new());
|
|
|
}
|
|
|
- model.Notes = string.Join("\n===================================\n", notes.Reverse<List<string>>().Select(x => string.Join('\n', x)));
|
|
|
-
|
|
|
- model.EmployeeID = empid;
|
|
|
- model.ManagerID = mgrid;
|
|
|
-
|
|
|
- var sEmp = empid == row.Get<KanbanSubscriber, Guid>(c => c.Employee.ID)
|
|
|
- ? ""
|
|
|
- : !empValid
|
|
|
- ? " to (Unallocated)"
|
|
|
- : " to " + row.Get<KanbanSubscriber, string>(x => x.Kanban.EmployeeLink.Name);
|
|
|
-
|
|
|
- var sMgr = !mgrValid || mgrid == empid
|
|
|
- ? ""
|
|
|
- : " by " + row.Get<KanbanSubscriber, string>(x => x.Kanban.ManagerLink.Name);
|
|
|
-
|
|
|
- model.AssignedTo = !string.IsNullOrEmpty(sEmp) || !string.IsNullOrWhiteSpace(sMgr)
|
|
|
- ? string.Format("Assigned{0}{1}", sEmp, sMgr)
|
|
|
- : "";
|
|
|
-
|
|
|
- model.JobID = row.Get<KanbanSubscriber, Guid>(x => x.Kanban.JobLink.ID);
|
|
|
- model.JobNumber = row.Get<KanbanSubscriber, string>(x => x.Kanban.JobLink.JobNumber)?.Trim() ?? "";
|
|
|
- model.JobName = row.Get<KanbanSubscriber, string>(x => x.Kanban.JobLink.Name);
|
|
|
- model.Checked = false; //ischecked?.Invoke() == true;
|
|
|
- model.Type = new KanbanType
|
|
|
+ else
|
|
|
{
|
|
|
- ID = typeID,
|
|
|
- Code = typeCode
|
|
|
- };
|
|
|
- model.Number = row.Get<KanbanSubscriber, int>(x => x.Kanban.Number);
|
|
|
-
|
|
|
- model.PropertyChanged += Model_PropertyChanged;
|
|
|
-
|
|
|
- models.Add(model);
|
|
|
+ notes.Last().Add(line);
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
- UserTasksHeaderTimeConverter.Kanbans = models;
|
|
|
-
|
|
|
- Kanban.Columns.Clear();
|
|
|
- foreach (var employee in emps)
|
|
|
- Kanban.Columns.Add(new KanbanColumn
|
|
|
- {
|
|
|
- Categories = employee.Key.ToString(),
|
|
|
- Title = employee.Value,
|
|
|
- Width = Math.Max(150, Kanban.ActualWidth / emps.ToArray().Length - 1.0F)
|
|
|
- });
|
|
|
- //var template = Resources["SimpleHeader"] as DataTemplate;
|
|
|
- //var boundary = template.FindName("Boundary", null);
|
|
|
-
|
|
|
- if (Kanban.Columns.Count > 0)
|
|
|
- Kanban.ColumnWidth = Math.Max(150, (Kanban.ActualWidth - 20F) / Kanban.Columns.Count - 1.0F);
|
|
|
-
|
|
|
- _models = models.OrderBy(x => _swimlanes[x.Assignee]).ThenBy(x => x.DueDate).ToList();
|
|
|
- FilterKanbans();
|
|
|
-
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- private void Model_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
|
|
|
- {
|
|
|
- if(e.PropertyName == nameof(TaskModel.Assignee))
|
|
|
+ model.Notes = string.Join("\n===================================\n", notes.Reverse<List<string>>().Select(x => string.Join('\n', x)));
|
|
|
+
|
|
|
+ model.EmployeeID = kanban.EmployeeLink.ID;
|
|
|
+ model.ManagerID = kanban.ManagerLink.ID;
|
|
|
+
|
|
|
+ var employeeString = kanban.EmployeeLink.ID == subscriber.Employee.ID
|
|
|
+ ? ""
|
|
|
+ : kanban.EmployeeLink.ID == Guid.Empty
|
|
|
+ ? " to (Unallocated)"
|
|
|
+ : " to " + kanban.EmployeeLink.Name;
|
|
|
+
|
|
|
+ var managerString = kanban.ManagerLink.ID == Guid.Empty || kanban.ManagerLink.ID == subscriber.Employee.ID
|
|
|
+ ? ""
|
|
|
+ : " by " + kanban.ManagerLink.Name;
|
|
|
+
|
|
|
+ model.AssignedTo = !string.IsNullOrEmpty(employeeString) || !managerString.IsNullOrWhiteSpace()
|
|
|
+ ? $"Assigned{employeeString}{managerString}"
|
|
|
+ : "";
|
|
|
+
|
|
|
+ model.JobID = kanban.JobLink.ID;
|
|
|
+ model.JobNumber = kanban.JobLink.JobNumber?.Trim() ?? "";
|
|
|
+ model.JobName = kanban.JobLink.Name;
|
|
|
+ model.Checked = SelectedTasks.Any(x => x.ID == model.ID);
|
|
|
+ model.Type = new KanbanType
|
|
|
{
|
|
|
- using (new WaitCursor())
|
|
|
- {
|
|
|
- var model = sender as TaskModel;
|
|
|
- var models = new TaskModel[] { model };
|
|
|
- var kanban = Host.LoadKanbans(models, new Columns<Kanban>(x => x.ID, x => x.Category)).First();
|
|
|
- kanban.Category = model.Assignee;
|
|
|
-
|
|
|
- new Client<Kanban>().Save(kanban, string.Format("Task Category Updated to {0}", model.Assignee), (o, err) => { });
|
|
|
- model.Checked = false;
|
|
|
+ ID = typeID,
|
|
|
+ Code = typeCode
|
|
|
+ };
|
|
|
+ model.Number = kanban.Number;
|
|
|
|
|
|
- FilterKanbans();
|
|
|
- }
|
|
|
- }
|
|
|
+ yield return model;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- private void SaveSettings()
|
|
|
- {
|
|
|
- Host.KanbanSettings.UserSettings.AnchorWidth = SplitPanel.AnchorWidth;
|
|
|
-
|
|
|
- Host.KanbanSettings.UserSettings.TeamsHeight = SelectedTeams.ActualHeight;
|
|
|
-
|
|
|
- var teams = SelectedTeams.SelectedItems.Select(x => ((KeyValuePair<Guid, string>)x).Key);
|
|
|
- Host.KanbanSettings.UserSettings.SelectedTeams = teams.ToArray();
|
|
|
-
|
|
|
- var emps = SelectedEmployees.SelectedItems.Select(x => ((KeyValuePair<Guid, string>)x).Key);
|
|
|
- emps = emps.Where(e => _teamemployees.Any(t => t.Contains(e)));
|
|
|
- Host.KanbanSettings.UserSettings.SelectedEmployees = emps.ToArray();
|
|
|
+ #endregion
|
|
|
|
|
|
- Host.KanbanSettings.UserSettings.IncludeCompleted = IncludeCompleted.IsChecked == true;
|
|
|
- Host.KanbanSettings.UserSettings.IncludeObserved = IncludeObserved.IsChecked == true;
|
|
|
- Host.KanbanSettings.UserSettings.IncludeManaged = IncludeManaged.IsChecked == true;
|
|
|
+ #region Kanban
|
|
|
|
|
|
- Host.SaveSettings();
|
|
|
- }
|
|
|
+ private readonly List<TaskModel> SelectedTasks = new();
|
|
|
+ private List<TaskModel> AllTasks { get; set; } = new();
|
|
|
|
|
|
- private void Kanban_SizeChanged(object sender, SizeChangedEventArgs e)
|
|
|
+ private void DoEdit(TaskModel task)
|
|
|
+ {
|
|
|
+ var result = Host.EditReferences(new[] { task });
|
|
|
+ if (result)
|
|
|
{
|
|
|
- Kanban.ColumnWidth = Kanban.ActualWidth / Kanban.Columns.Count - 1.0F;
|
|
|
+ Refresh();
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- private void SplitPanel_OnChanged(object sender, DynamicSplitPanelSettings e)
|
|
|
- {
|
|
|
- if (!IsReady || Equals(Host.KanbanSettings.UserSettings.AnchorWidth, e.AnchorWidth))
|
|
|
- return;
|
|
|
- SaveSettings();
|
|
|
- }
|
|
|
+ private void EditTask_Executed(object sender, ExecutedRoutedEventArgs e)
|
|
|
+ {
|
|
|
+ if (e.Parameter is not TaskModel model) return;
|
|
|
|
|
|
- private void LoadEmployees()
|
|
|
- {
|
|
|
- var empfilter = LookupFactory.DefineFilter<Employee>();
|
|
|
+ DoEdit(model);
|
|
|
+ }
|
|
|
|
|
|
- UserTasksHeaderImageConverter.Images = new Client<Document>().Query(
|
|
|
- new Filter<Document>(x => x.ID).InQuery(empfilter, x => x.Thumbnail.ID),
|
|
|
- new Columns<Document>(x => x.ID).Add(x => x.Data)).ToDictionary<Document, Guid, byte[]>(x => x.ID, x => x.Data);
|
|
|
+ private void OpenTaskMenu_Executed(object sender, ExecutedRoutedEventArgs e)
|
|
|
+ {
|
|
|
+ if (e.Parameter is not KanbanResources.OpenTaskMenuCommandArgs args) return;
|
|
|
|
|
|
- var query = new MultiQuery();
|
|
|
- query.Add(
|
|
|
- LookupFactory.DefineFilter<Employee>(),
|
|
|
- new Columns<Employee>(x => x.ID)
|
|
|
- .Add(x => x.Name)
|
|
|
- .Add(x => x.Thumbnail.ID),
|
|
|
- new SortOrder<Employee>(x => x.Name)
|
|
|
- );
|
|
|
- query.Add(
|
|
|
- LookupFactory.DefineFilter<Team>(),
|
|
|
- new Columns<Team>(x => x.ID)
|
|
|
- .Add(x => x.Name),
|
|
|
- new SortOrder<Team>(x => x.Name)
|
|
|
- );
|
|
|
- query.Add(
|
|
|
- LookupFactory.DefineFilter<EmployeeTeam>(),
|
|
|
- new Columns<EmployeeTeam>(x => x.EmployeeLink.ID)
|
|
|
- .Add(x => x.TeamLink.ID)
|
|
|
- );
|
|
|
+ Host.PopulateMenu(this, args.Model, args.Menu);
|
|
|
+ }
|
|
|
|
|
|
- query.Query();
|
|
|
+ private void SelectTask_Executed(object sender, ExecutedRoutedEventArgs e)
|
|
|
+ {
|
|
|
+ if (e.Parameter is not TaskModel model) return;
|
|
|
|
|
|
- _teams = query.Get<Team>().ToDictionary<Team, Guid, string>(x => x.ID, x => x.Name);
|
|
|
+ if (!SelectedTasks.Remove(model))
|
|
|
+ {
|
|
|
+ SelectedTasks.Add(model);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- _employees = query.Get<Employee>().ToDictionary<Employee, Guid, string>(x => x.ID, x => x.Name, x => x.Name);
|
|
|
+ private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
|
|
|
+ {
|
|
|
+ e.CanExecute = true;
|
|
|
+ }
|
|
|
|
|
|
- UserTasksHeaderImageConverter.Employees = query.Get<Employee>().ToDictionary<Employee, Guid, Guid>(x => x.ID, x => x.Thumbnail.ID);
|
|
|
+ #endregion
|
|
|
|
|
|
- _teamemployees = query.Get<EmployeeTeam>().ToLookup<EmployeeTeam, Guid, Guid>(x => x.TeamLink.ID, x => x.EmployeeLink.ID);
|
|
|
+ #region ITaskControl
|
|
|
|
|
|
- SelectedTeams.ItemsSource = _teams;
|
|
|
- }
|
|
|
+ public ITaskHost Host { get; set; }
|
|
|
|
|
|
- private void PopulateEmployees()
|
|
|
- {
|
|
|
- bPopulating = true;
|
|
|
- try
|
|
|
- {
|
|
|
- var availableemployees = new List<Guid>();
|
|
|
- foreach (KeyValuePair<Guid, string> team in SelectedTeams.SelectedItems)
|
|
|
- availableemployees.AddRange(_teamemployees[team.Key].Where(x => !availableemployees.Contains(x)));
|
|
|
-
|
|
|
- SelectedEmployees.ItemsSource = _employees.Where(x => availableemployees.Contains(x.Key));
|
|
|
- SelectedEmployees.SelectedItems.Clear();
|
|
|
- foreach (var employee in Host.KanbanSettings.UserSettings.SelectedEmployees.Where(x => availableemployees.Contains(x)))
|
|
|
- SelectedEmployees.SelectedItems.Add(_employees.FirstOrDefault(x => Equals(x.Key, employee)));
|
|
|
- }
|
|
|
- catch (Exception e)
|
|
|
- {
|
|
|
- }
|
|
|
+ public KanbanViewType KanbanViewType => KanbanViewType.User;
|
|
|
|
|
|
- bPopulating = false;
|
|
|
- }
|
|
|
+ public bool IsReady { get; set; }
|
|
|
|
|
|
+ public string SectionName => "Tasks By User";
|
|
|
|
|
|
- private bool FilterKanban(TaskModel model, string searches, params Func<TaskModel, string>[] properties)
|
|
|
- {
|
|
|
- foreach (var search in searches.Split(' '))
|
|
|
- foreach (var property in properties)
|
|
|
- if (!property(model).Contains(search))
|
|
|
- return false;
|
|
|
- return true;
|
|
|
- }
|
|
|
+ public DataModel DataModel(Selection selection)
|
|
|
+ {
|
|
|
+ var ids = SelectedModels().Select(x => x.ID).ToArray();
|
|
|
+ return new AutoDataModel<Kanban>(new Filter<Kanban>(x => x.ID).InList(ids));
|
|
|
+ }
|
|
|
|
|
|
- private void FilterKanbans()
|
|
|
+ public IEnumerable<TaskModel> SelectedModels(TaskModel? sender = null)
|
|
|
+ {
|
|
|
+ if (sender is null)
|
|
|
{
|
|
|
- IEnumerable<TaskModel> Items = _models;
|
|
|
- if (TaskType.SelectedItem is KanbanType kanbanType)
|
|
|
- {
|
|
|
- Items = Items.Where(x => x.Type.ID == kanbanType.ID);
|
|
|
- }
|
|
|
- if (!string.IsNullOrWhiteSpace(Search.Text))
|
|
|
- {
|
|
|
- var searches = Search.Text.Split();
|
|
|
- Items = Items.Where(x => x.Search(searches));
|
|
|
- }
|
|
|
-
|
|
|
- if(object.Equals(Kanban.ItemsSource, Items))
|
|
|
- {
|
|
|
- // Triggers a refresh.
|
|
|
- Kanban.ItemsSource = null;
|
|
|
- }
|
|
|
- Kanban.ItemsSource = Items;
|
|
|
+ return SelectedTasks;
|
|
|
}
|
|
|
-
|
|
|
- private void ViewType_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
|
|
+ else
|
|
|
{
|
|
|
- if (Kanban != null)
|
|
|
- Kanban.CardTemplate = ViewType.SelectedIndex > 0
|
|
|
- ? Resources["CompactKanban"] as DataTemplate
|
|
|
- : Resources["FullKanban"] as DataTemplate;
|
|
|
- if (IsReady)
|
|
|
+ var result = SelectedTasks.ToList();
|
|
|
+ if (!result.Contains(sender))
|
|
|
{
|
|
|
- Host.KanbanSettings.StatusSettings.CompactView = ViewType.SelectedIndex > 0;
|
|
|
- Host.SaveSettings();
|
|
|
+ result.Add(sender);
|
|
|
}
|
|
|
+ return result;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- private void TaskType_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
|
|
- {
|
|
|
- FilterKanbans();
|
|
|
- }
|
|
|
-
|
|
|
- private void IncludeLocked_Checked(object sender, RoutedEventArgs e)
|
|
|
- {
|
|
|
- if (!IsReady)
|
|
|
- return;
|
|
|
-
|
|
|
- SaveSettings();
|
|
|
- Refresh(true);
|
|
|
- }
|
|
|
+ #endregion
|
|
|
|
|
|
- private void IncludeManaged_Checked(object sender, RoutedEventArgs e)
|
|
|
- {
|
|
|
- if (!IsReady)
|
|
|
- return;
|
|
|
+ #region Settings
|
|
|
|
|
|
- SaveSettings();
|
|
|
- Refresh(true);
|
|
|
- }
|
|
|
- private void IncludeObserved_Checked(object sender, RoutedEventArgs e)
|
|
|
- {
|
|
|
- if (!IsReady)
|
|
|
- return;
|
|
|
+ private void SaveSettings()
|
|
|
+ {
|
|
|
+ Host.KanbanSettings.UserSettings.AnchorWidth = SplitPanel.AnchorWidth;
|
|
|
|
|
|
- SaveSettings();
|
|
|
- Refresh(true);
|
|
|
- }
|
|
|
+ Host.KanbanSettings.UserSettings.TeamsHeight = SelectedTeams.ActualHeight;
|
|
|
|
|
|
- private void IncludeCompleted_Checked(object sender, RoutedEventArgs e)
|
|
|
- {
|
|
|
- if (!IsReady)
|
|
|
- return;
|
|
|
+ var teams = SelectedTeams.SelectedItems.Select(x => ((KeyValuePair<Guid, string>)x).Key);
|
|
|
+ Host.KanbanSettings.UserSettings.SelectedTeams = teams.ToArray();
|
|
|
|
|
|
- SaveSettings();
|
|
|
- Refresh(true);
|
|
|
- }
|
|
|
+ var emps = SelectedEmployees.SelectedItems.Select(x => ((KeyValuePair<Guid, string>)x).Key);
|
|
|
+ emps = emps.Where(e => TeamEmployees.Any(t => t.Contains(e)));
|
|
|
+ Host.KanbanSettings.UserSettings.SelectedEmployees = emps.ToArray();
|
|
|
|
|
|
- private void Search_KeyUp(object sender, KeyEventArgs e)
|
|
|
- {
|
|
|
- FilterKanbans();
|
|
|
- }
|
|
|
-
|
|
|
- private void Export_Click(object sender, RoutedEventArgs e)
|
|
|
- {
|
|
|
- }
|
|
|
-
|
|
|
- private void Kanban_CardDragStart(object sender, KanbanDragStartEventArgs e)
|
|
|
- {
|
|
|
- var models = SelectedModels(e.SelectedCard.Content as TaskModel).ToList();
|
|
|
- if (models.Any(x => x.Locked || x.EmployeeID != Guid.Parse(x.Category.ToString())) || !Host.CanChangeTasks(models))
|
|
|
- e.IsCancel = true;
|
|
|
- }
|
|
|
+ Host.KanbanSettings.UserSettings.IncludeCompleted = IncludeCompleted.IsChecked == true;
|
|
|
+ Host.KanbanSettings.UserSettings.IncludeObserved = IncludeObserved.IsChecked == true;
|
|
|
+ Host.KanbanSettings.UserSettings.IncludeManaged = IncludeManaged.IsChecked == true;
|
|
|
|
|
|
+ Host.SaveSettings();
|
|
|
+ }
|
|
|
|
|
|
- private void Kanban_CardDragEnd(object sender, KanbanDragEndEventArgs e)
|
|
|
- {
|
|
|
- using (new WaitCursor())
|
|
|
- {
|
|
|
- var target = e.TargetColumn.Categories;
|
|
|
- var targetCategory = e.TargetKey;
|
|
|
- var models = SelectedModels(e.SelectedCard.Content as TaskModel).Where(x => !Equals(x.Category, target)).ToList();
|
|
|
- if (!models.Any())
|
|
|
- return;
|
|
|
- var kanbans = Host.LoadKanbans(models, new Columns<Kanban>(x => x.ID, x => x.EmployeeLink.ID, x => x.Private, x => x.Number));
|
|
|
- var subscribers = new ClientKanbanSubscriberSet(kanbans.Select(x => x.ID));
|
|
|
- var targetID = Guid.Parse(target);
|
|
|
-
|
|
|
- var updated = new List<Kanban>();
|
|
|
- foreach (var kanban in kanbans)
|
|
|
- {
|
|
|
- if (!kanban.Private)
|
|
|
- {
|
|
|
- kanban.EmployeeLink.ID = targetID;
|
|
|
- subscribers.EnsureAssignee(kanban.ID, kanban.EmployeeLink.ID);
|
|
|
- updated.Add(kanban);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- MessageBox.Show($"Cannot change assignee for task {kanban.Number} because it is private.");
|
|
|
- models.RemoveAll(x => x.ID == kanban.ID.ToString());
|
|
|
- }
|
|
|
- }
|
|
|
+ private void SplitPanel_OnChanged(object sender, DynamicSplitPanelSettings e)
|
|
|
+ {
|
|
|
+ if (!IsReady || Equals(Host.KanbanSettings.UserSettings.AnchorWidth, e.AnchorWidth))
|
|
|
+ return;
|
|
|
+ SaveSettings();
|
|
|
+ }
|
|
|
|
|
|
- new Client<Kanban>().Save(updated, string.Format("Task Employee Updated to {0}", target), (o, err) => { });
|
|
|
- subscribers.Save(false);
|
|
|
- foreach (var model in models)
|
|
|
- {
|
|
|
- model.Checked = false;
|
|
|
- model.Category = target;
|
|
|
- model.EmployeeID = targetID;
|
|
|
- }
|
|
|
+ private void SelectedTeams_ItemChecked(object sender, ItemCheckedEventArgs e)
|
|
|
+ {
|
|
|
+ if (!IsReady)
|
|
|
+ return;
|
|
|
+ PopulateEmployees();
|
|
|
+ SaveSettings();
|
|
|
+ Refresh();
|
|
|
+ }
|
|
|
|
|
|
- FilterKanbans();
|
|
|
- }
|
|
|
- }
|
|
|
+ private void SelectedTeams_SizeChanged(object sender, SizeChangedEventArgs e)
|
|
|
+ {
|
|
|
+ if (!IsReady || Equals(Host.KanbanSettings.UserSettings.TeamsHeight, SelectedTeams.ActualHeight))
|
|
|
+ return;
|
|
|
+ SaveSettings();
|
|
|
+ }
|
|
|
|
|
|
- #region ITaskControl Support
|
|
|
+ private void EmployeesSelectionChanged(object sender, SelectionChangedEventArgs e)
|
|
|
+ {
|
|
|
+ if (!IsReady || bPopulating)
|
|
|
+ return;
|
|
|
+ SaveSettings();
|
|
|
+ Refresh();
|
|
|
+ }
|
|
|
|
|
|
- public ITaskHost Host { get; set; }
|
|
|
+ #endregion
|
|
|
|
|
|
- public KanbanViewType KanbanViewType => KanbanViewType.User;
|
|
|
+ private void Export_Click(object sender, RoutedEventArgs e)
|
|
|
+ {
|
|
|
|
|
|
- public IEnumerable<TaskModel> SelectedModels(TaskModel? sender = null)
|
|
|
- {
|
|
|
- var result = _models.Where(x => x.Checked).ToList();
|
|
|
- if (sender != null && !result.Contains(sender))
|
|
|
- result.Add(sender);
|
|
|
- return result;
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
- #endregion
|
|
|
+ private void IncludeCompleted_Checked(object sender, RoutedEventArgs e)
|
|
|
+ {
|
|
|
|
|
|
- #region Kanban Actions
|
|
|
+ }
|
|
|
|
|
|
- private void DoEdit(TaskModel task)
|
|
|
- {
|
|
|
- if (task == null)
|
|
|
- return;
|
|
|
+ private void IncludeObserved_Checked(object sender, RoutedEventArgs e)
|
|
|
+ {
|
|
|
|
|
|
- var result = Host.EditReferences(new[] { task });
|
|
|
- if (result)
|
|
|
- Refresh(true);
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
- private void TaskMenu_Opened(object sender, RoutedEventArgs e)
|
|
|
- {
|
|
|
- Host.PopulateMenu(this, (sender as ContextMenu)!);
|
|
|
- }
|
|
|
+ private void IncludeManaged_Checked(object sender, RoutedEventArgs e)
|
|
|
+ {
|
|
|
|
|
|
- private void Border_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
|
|
- {
|
|
|
- if (e.ClickCount > 1)
|
|
|
- {
|
|
|
- var task = ((Border)sender).Tag as TaskModel;
|
|
|
- DoEdit(task);
|
|
|
- e.Handled = true;
|
|
|
- }
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
- private void CheckBox_Checked(object sender, RoutedEventArgs e)
|
|
|
- {
|
|
|
- }
|
|
|
+ private void ViewType_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
|
|
+ {
|
|
|
|
|
|
- #endregion
|
|
|
+ }
|
|
|
|
|
|
- #region Employee List Actions
|
|
|
+ private void TaskType_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
|
|
+ {
|
|
|
|
|
|
- private void SelectedTeams_ItemChecked(object sender, ItemCheckedEventArgs e)
|
|
|
- {
|
|
|
- if (!IsReady)
|
|
|
- return;
|
|
|
- PopulateEmployees();
|
|
|
- SaveSettings();
|
|
|
- Refresh(true);
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
- private void SelectedTeams_SizeChanged(object sender, SizeChangedEventArgs e)
|
|
|
- {
|
|
|
- if (!IsReady || Equals(Host.KanbanSettings.UserSettings.TeamsHeight, SelectedTeams.ActualHeight))
|
|
|
- return;
|
|
|
- SaveSettings();
|
|
|
- }
|
|
|
+ private void Search_KeyUp(object sender, KeyEventArgs e)
|
|
|
+ {
|
|
|
|
|
|
- private void EmployeesSelectionChanged(object sender, SelectionChangedEventArgs e)
|
|
|
- {
|
|
|
- if (!IsReady || bPopulating)
|
|
|
- return;
|
|
|
- SaveSettings();
|
|
|
- Refresh(true);
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
- public string SectionName => "Tasks By User";
|
|
|
+ private void ItemsControl_DragOver(object sender, DragEventArgs e)
|
|
|
+ {
|
|
|
|
|
|
- public DataModel DataModel(Selection selection)
|
|
|
- {
|
|
|
- return new AutoDataModel<Kanban>(new Filter<Kanban>(x => x.ID).IsEqualTo(Guid.Empty));
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
- #endregion
|
|
|
+ private void ItemsControl_Drop(object sender, DragEventArgs e)
|
|
|
+ {
|
|
|
|
|
|
- private void Kanban_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
|
|
|
- {
|
|
|
- e.Handled = true;
|
|
|
- }
|
|
|
- }*/
|
|
|
+ }
|
|
|
}
|