TasksByUserControl.xaml.cs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Drawing;
  4. using System.Globalization;
  5. using System.Linq;
  6. using System.Reflection;
  7. using System.Windows;
  8. using System.Windows.Controls;
  9. using System.Windows.Data;
  10. using System.Windows.Input;
  11. using Comal.Classes;
  12. using InABox.Clients;
  13. using InABox.Core;
  14. using InABox.DynamicGrid;
  15. using InABox.WPF;
  16. using Syncfusion.UI.Xaml.Kanban;
  17. using Syncfusion.Windows.Tools.Controls;
  18. namespace PRSDesktop
  19. {
  20. public class UserTasksHeaderImageConverter : IValueConverter
  21. {
  22. public static Dictionary<Guid, byte[]> Images { get; set; }
  23. public static Dictionary<Guid, Guid> Employees { get; set; }
  24. public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
  25. {
  26. var anonymous = Resources.anonymous.AsBitmapImage();
  27. if (Images == null)
  28. return anonymous;
  29. if (Employees == null)
  30. return anonymous;
  31. var dataContext = value as ColumnTag;
  32. if (dataContext == null)
  33. return anonymous;
  34. var getter = dataContext.GetType().GetProperty("Column", BindingFlags.NonPublic | BindingFlags.Instance);
  35. if (getter == null)
  36. return anonymous;
  37. var column = (KanbanColumn)getter.GetValue(dataContext);
  38. if (column == null)
  39. return anonymous;
  40. if (!Guid.TryParse(column.Categories, out var empid))
  41. return anonymous;
  42. if (!Employees.TryGetValue(empid, out var imageid))
  43. return anonymous;
  44. if (!Images.TryGetValue(imageid, out var data))
  45. return anonymous;
  46. return ImageUtils.LoadImage(data);
  47. }
  48. public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  49. {
  50. throw new NotImplementedException();
  51. }
  52. }
  53. public class UserTasksHeaderTimeConverter : IValueConverter
  54. {
  55. public static IEnumerable<TaskModel> Kanbans { get; set; }
  56. public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
  57. {
  58. if (Kanbans == null)
  59. return "0:00";
  60. var dataContext = value as ColumnTag;
  61. if (dataContext == null)
  62. return "0:00";
  63. var getter = dataContext.GetType().GetProperty("Column", BindingFlags.NonPublic | BindingFlags.Instance);
  64. if (getter == null)
  65. return "0:00";
  66. var column = (KanbanColumn)getter.GetValue(dataContext);
  67. if (column == null)
  68. return "0:00";
  69. double result = 0.0F;
  70. foreach (var kanban in Kanbans.Where(x => Equals(x.Category, column.Categories)))
  71. result += kanban.EstimatedTime.TotalHours;
  72. return string.Format("{0:F2}", result);
  73. }
  74. public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  75. {
  76. throw new NotImplementedException();
  77. }
  78. }
  79. //public class TaskHeaderWidthConverter : IValueConverter
  80. //{
  81. // public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
  82. // {
  83. // var dataContext = (value as ColumnTag);
  84. // if (dataContext == null)
  85. // return 150;
  86. // PropertyInfo getter = dataContext.GetType().GetProperty("Column", BindingFlags.NonPublic | BindingFlags.Instance);
  87. // if (getter == null)
  88. // return 150;
  89. // KanbanColumn column = (KanbanColumn)getter.GetValue(dataContext);
  90. // if (column == null)
  91. // return 150;
  92. // return Math.Max(150, column.Width) - 20 ;
  93. // }
  94. // public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  95. // {
  96. // throw new NotImplementedException();
  97. // }
  98. //}
  99. /// <summary>
  100. /// Interaction logic for TaskListPanel.xaml
  101. /// </summary>
  102. public partial class TasksByUserControl : UserControl, ITaskControl
  103. {
  104. private Dictionary<Guid, string> _employees;
  105. private List<TaskModel> _models = new();
  106. private ILookup<Guid, Guid> _teamemployees;
  107. private Dictionary<Guid, string> _teams;
  108. private bool bPopulating;
  109. public TasksByUserControl()
  110. {
  111. InitializeComponent();
  112. }
  113. public bool IsReady { get; set; }
  114. #region Setup
  115. public void Setup()
  116. {
  117. SetupToolbar();
  118. SplitPanel.AnchorWidth = Host.KanbanSettings.UserSettings.AnchorWidth;
  119. TeamsRow.Height = new GridLength(Host.KanbanSettings.UserSettings.TeamsHeight);
  120. LoadEmployees();
  121. foreach (var team in Host.KanbanSettings.UserSettings.SelectedTeams)
  122. SelectedTeams.SelectedItems.Add(_teams.FirstOrDefault(x => Equals(x.Key, team)));
  123. PopulateEmployees();
  124. PopulateKanbanTypes();
  125. }
  126. private void PopulateKanbanTypes()
  127. {
  128. TaskType.Items.Add("");
  129. foreach(var kanbanType in Host.KanbanTypes)
  130. {
  131. TaskType.Items.Add(kanbanType);
  132. }
  133. }
  134. #endregion
  135. private void SetupToolbar()
  136. {
  137. IncludeCompleted.Visibility = Security.IsAllowed<CanHideTaskCompletedColumn>() ? Visibility.Visible : Visibility.Collapsed;
  138. IncludeCompleted.IsChecked = IncludeCompleted.Visibility == Visibility.Visible ? Host.KanbanSettings.UserSettings.IncludeCompleted : true;
  139. IncludeObserved.IsChecked = Host.KanbanSettings.UserSettings.IncludeObserved;
  140. IncludeManaged.IsChecked = Host.KanbanSettings.UserSettings.IncludeManaged;
  141. ViewType.SelectedIndex = Host.KanbanSettings.UserSettings.CompactView ? 1 : 0;
  142. }
  143. public void Refresh(bool resetselection)
  144. {
  145. var _swimlanes = new Dictionary<string, int>
  146. {
  147. { "Open", 0 },
  148. { "In Progress", 1 },
  149. { "Waiting", 2 },
  150. { "Complete", 3 }
  151. };
  152. var filter = new Filter<KanbanSubscriber>(c => c.Kanban.Closed).IsEqualTo(DateTime.MinValue)
  153. .And(x => x.Kanban.Locked).IsEqualTo(false);
  154. var privateFilter = new Filter<KanbanSubscriber>(x => x.Kanban.Private).IsEqualTo(false);
  155. if (App.EmployeeID != Guid.Empty)
  156. {
  157. privateFilter = privateFilter.Or(x => x.Employee.ID).IsEqualTo(App.EmployeeID);
  158. }
  159. filter.And(privateFilter);
  160. if (Host.Job != null)
  161. {
  162. if (Host.Job.ID != Guid.Empty)
  163. filter = filter.And(c => c.Kanban.JobLink.ID).IsEqualTo(Host.Job.ID);
  164. else
  165. filter = filter.And(c => c.Kanban.JobLink.ID).None();
  166. }
  167. if (!Host.KanbanSettings.UserSettings.IncludeCompleted)
  168. filter = filter.And(new Filter<KanbanSubscriber>(x => x.Kanban.Completed).IsEqualTo(DateTime.MinValue));
  169. var emps = _employees.Where(x => Host.KanbanSettings.UserSettings.SelectedEmployees.Contains(x.Key));
  170. //if (Host.Settings.UserSettings.IncludeObserved)
  171. // filter = filter.And(x => x.Manager).IsEqualTo(false);
  172. //else
  173. // filter = filter.And(x => x.Assignee).IsEqualTo(true);
  174. filter = filter.And(c => c.Employee.ID).InList(emps.Select(x => x.Key).ToArray());
  175. if (!Host.KanbanSettings.UserSettings.IncludeObserved)
  176. {
  177. if (Host.KanbanSettings.UserSettings.IncludeManaged)
  178. filter = filter.And(new Filter<KanbanSubscriber>(x => x.Manager).IsEqualTo(true).Or(x => x.Assignee).IsEqualTo(true));
  179. else
  180. filter = filter.And(x => x.Assignee).IsEqualTo(true);
  181. }
  182. using (new WaitCursor())
  183. {
  184. var kanbans = new Client<KanbanSubscriber>().Query(
  185. filter,
  186. new Columns<KanbanSubscriber>
  187. (
  188. x => x.Kanban.ID,
  189. x => x.Kanban.DueDate,
  190. x => x.Kanban.Completed,
  191. //x => x.Kanban.Description,
  192. x => x.Kanban.Summary,
  193. x => x.Kanban.Category,
  194. x => x.Kanban.EmployeeLink.ID,
  195. x => x.Kanban.EmployeeLink.Name,
  196. x => x.Kanban.ManagerLink.ID,
  197. x => x.Kanban.ManagerLink.Name,
  198. x => x.Kanban.Notes,
  199. x => x.Kanban.Title,
  200. x => x.Kanban.JobLink.ID,
  201. x => x.Kanban.JobLink.JobNumber,
  202. x => x.Kanban.JobLink.Name,
  203. x => x.Kanban.Type.ID,
  204. x => x.Kanban.Type.Code,
  205. x => x.Kanban.Number,
  206. x => x.Kanban.Attachments,
  207. x => x.Kanban.Locked,
  208. x => x.Employee.ID,
  209. x => x.Kanban.EstimatedTime
  210. ),
  211. new SortOrder<KanbanSubscriber>(x => x.Kanban.DueDate) { Direction = SortDirection.Ascending }
  212. );
  213. var models = new List<TaskModel>();
  214. foreach (var row in kanbans.Rows)
  215. {
  216. var empid = row.Get<KanbanSubscriber, Guid>(e => e.Kanban.EmployeeLink.ID);
  217. var mgrid = row.Get<KanbanSubscriber, Guid>(e => e.Kanban.ManagerLink.ID);
  218. var subid = row.Get<KanbanSubscriber, Guid>(e => e.Employee.ID);
  219. var empValid = Entity.IsEntityLinkValid<KanbanSubscriber, EmployeeLink>(x => x.Kanban.EmployeeLink, row);
  220. var mgrValid = Entity.IsEntityLinkValid<KanbanSubscriber, EmployeeLink>(x => x.Kanban.ManagerLink, row);
  221. var completed = row.Get<KanbanSubscriber, DateTime>(e => e.Kanban.Completed);
  222. var locked = row.Get<KanbanSubscriber, bool>(e => e.Kanban.Locked);
  223. var typeID = row.Get<KanbanSubscriber, Guid>(e => e.Kanban.Type.ID);
  224. var typeCode = row.Get<KanbanSubscriber, string>(e => e.Kanban.Type.Code);
  225. var job = row.Get<KanbanSubscriber, string>(x => x.Kanban.JobLink.JobNumber);
  226. var model = new TaskModel();
  227. model.Title = row.Get<KanbanSubscriber, string>(x => x.Kanban.Title);
  228. model.ID = row.Get<KanbanSubscriber, Guid>(x => x.Kanban.ID).ToString();
  229. model.Description = row.Get<KanbanSubscriber, string>(x => x.Kanban.Summary) ?? "";
  230. model.Category = row.Get<KanbanSubscriber, Guid>(c => c.Employee.ID).ToString();
  231. model.Assignee = row.Get<KanbanSubscriber, string>(c => c.Kanban.Category);
  232. if (string.IsNullOrWhiteSpace(model.Assignee) || !_swimlanes.ContainsKey(model.Assignee))
  233. model.Assignee = "Open";
  234. var kanbancolor = subid == empid
  235. ? TaskModel.KanbanColor(
  236. row.Get<KanbanSubscriber, DateTime>(x => x.Kanban.DueDate),
  237. row.Get<KanbanSubscriber, DateTime>(x => x.Kanban.Completed))
  238. : subid == mgrid
  239. ? Color.Silver
  240. : Color.Plum;
  241. if (row.Get<KanbanSubscriber, bool>(x => x.Kanban.Locked))
  242. kanbancolor = kanbancolor.MixColors(0.5F, Color.White);
  243. model.ColorKey = ImageUtils.ColorToString(kanbancolor);
  244. model.Image = null;
  245. model.ImageURL = null;
  246. model.Attachments =
  247. row.Get<KanbanSubscriber, int>(x => x.Kanban.Attachments) > 0; // ? PRSDesktop.Resources.attachment.AsBitmapImage() : null;
  248. model.DueDate = row.Get<KanbanSubscriber, DateTime>(x => x.Kanban.DueDate);
  249. model.CompletedDate = row.Get<KanbanSubscriber, DateTime>(x => x.Kanban.Completed);
  250. model.Locked = row.Get<KanbanSubscriber, bool>(x => x.Kanban.Locked); // ? PRSDesktop.Resources.locked.AsBitmapImage() : null;
  251. model.EstimatedTime = row.Get<KanbanSubscriber, TimeSpan>(x => x.Kanban.EstimatedTime);
  252. var notes = new List<List<string>> { new() };
  253. var kanbanNotes = row.Get<KanbanSubscriber, string[]>(x => x.Kanban.Notes);
  254. if(kanbanNotes != null)
  255. {
  256. foreach (var line in kanbanNotes)
  257. {
  258. if (line == "===================================")
  259. {
  260. notes.Add(new());
  261. }
  262. else
  263. {
  264. notes.Last().Add(line);
  265. }
  266. }
  267. }
  268. model.Notes = string.Join("\n===================================\n", notes.Reverse<List<string>>().Select(x => string.Join('\n', x)));
  269. model.EmployeeID = empid;
  270. model.ManagerID = mgrid;
  271. var sEmp = empid == row.Get<KanbanSubscriber, Guid>(c => c.Employee.ID)
  272. ? ""
  273. : !empValid
  274. ? " to (Unallocated)"
  275. : " to " + row.Get<KanbanSubscriber, string>(x => x.Kanban.EmployeeLink.Name);
  276. var sMgr = !mgrValid || mgrid == empid
  277. ? ""
  278. : " by " + row.Get<KanbanSubscriber, string>(x => x.Kanban.ManagerLink.Name);
  279. model.AssignedTo = !string.IsNullOrEmpty(sEmp) || !string.IsNullOrWhiteSpace(sMgr)
  280. ? string.Format("Assigned{0}{1}", sEmp, sMgr)
  281. : "";
  282. model.JobID = row.Get<KanbanSubscriber, Guid>(x => x.Kanban.JobLink.ID);
  283. model.JobNumber = row.Get<KanbanSubscriber, string>(x => x.Kanban.JobLink.JobNumber)?.Trim() ?? "";
  284. model.JobName = row.Get<KanbanSubscriber, string>(x => x.Kanban.JobLink.Name);
  285. model.Checked = false; //ischecked?.Invoke() == true;
  286. model.Type = new KanbanType
  287. {
  288. ID = typeID,
  289. Code = typeCode
  290. };
  291. model.Number = row.Get<KanbanSubscriber, int>(x => x.Kanban.Number);
  292. model.PropertyChanged += Model_PropertyChanged;
  293. models.Add(model);
  294. }
  295. UserTasksHeaderTimeConverter.Kanbans = models;
  296. Kanban.Columns.Clear();
  297. foreach (var employee in emps)
  298. Kanban.Columns.Add(new KanbanColumn
  299. {
  300. Categories = employee.Key.ToString(),
  301. Title = employee.Value,
  302. Width = Math.Max(150, Kanban.ActualWidth / emps.ToArray().Length - 1.0F)
  303. });
  304. //var template = Resources["SimpleHeader"] as DataTemplate;
  305. //var boundary = template.FindName("Boundary", null);
  306. if (Kanban.Columns.Count > 0)
  307. Kanban.ColumnWidth = Math.Max(150, (Kanban.ActualWidth - 20F) / Kanban.Columns.Count - 1.0F);
  308. _models = models.OrderBy(x => _swimlanes[x.Assignee]).ThenBy(x => x.DueDate).ToList();
  309. FilterKanbans();
  310. }
  311. }
  312. private void Model_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
  313. {
  314. if(e.PropertyName == nameof(TaskModel.Assignee))
  315. {
  316. using (new WaitCursor())
  317. {
  318. var model = sender as TaskModel;
  319. var models = new TaskModel[] { model };
  320. var kanban = Host.LoadKanbans(models, new Columns<Kanban>(x => x.ID, x => x.Category)).First();
  321. kanban.Category = model.Assignee;
  322. new Client<Kanban>().Save(kanban, string.Format("Task Category Updated to {0}", model.Assignee), (o, err) => { });
  323. model.Checked = false;
  324. FilterKanbans();
  325. }
  326. }
  327. }
  328. private void SaveSettings()
  329. {
  330. Host.KanbanSettings.UserSettings.AnchorWidth = SplitPanel.AnchorWidth;
  331. Host.KanbanSettings.UserSettings.TeamsHeight = SelectedTeams.ActualHeight;
  332. var teams = SelectedTeams.SelectedItems.Select(x => ((KeyValuePair<Guid, string>)x).Key);
  333. Host.KanbanSettings.UserSettings.SelectedTeams = teams.ToArray();
  334. var emps = SelectedEmployees.SelectedItems.Select(x => ((KeyValuePair<Guid, string>)x).Key);
  335. emps = emps.Where(e => _teamemployees.Any(t => t.Contains(e)));
  336. Host.KanbanSettings.UserSettings.SelectedEmployees = emps.ToArray();
  337. Host.KanbanSettings.UserSettings.IncludeCompleted = IncludeCompleted.IsChecked == true;
  338. Host.KanbanSettings.UserSettings.IncludeObserved = IncludeObserved.IsChecked == true;
  339. Host.KanbanSettings.UserSettings.IncludeManaged = IncludeManaged.IsChecked == true;
  340. Host.SaveSettings();
  341. }
  342. private void Kanban_SizeChanged(object sender, SizeChangedEventArgs e)
  343. {
  344. Kanban.ColumnWidth = Kanban.ActualWidth / Kanban.Columns.Count - 1.0F;
  345. }
  346. private void SplitPanel_OnChanged(object sender, DynamicSplitPanelSettings e)
  347. {
  348. if (!IsReady || Equals(Host.KanbanSettings.UserSettings.AnchorWidth, e.AnchorWidth))
  349. return;
  350. SaveSettings();
  351. }
  352. private void LoadEmployees()
  353. {
  354. var empfilter = LookupFactory.DefineFilter<Employee>();
  355. UserTasksHeaderImageConverter.Images = new Client<Document>().Query(
  356. new Filter<Document>(x => x.ID).InQuery(empfilter, x => x.Thumbnail.ID),
  357. new Columns<Document>(x => x.ID).Add(x => x.Data)).ToDictionary<Document, Guid, byte[]>(x => x.ID, x => x.Data);
  358. var query = new MultiQuery();
  359. query.Add(
  360. LookupFactory.DefineFilter<Employee>(),
  361. new Columns<Employee>(x => x.ID)
  362. .Add(x => x.Name)
  363. .Add(x => x.Thumbnail.ID),
  364. new SortOrder<Employee>(x => x.Name)
  365. );
  366. query.Add(
  367. LookupFactory.DefineFilter<Team>(),
  368. new Columns<Team>(x => x.ID)
  369. .Add(x => x.Name),
  370. new SortOrder<Team>(x => x.Name)
  371. );
  372. query.Add(
  373. LookupFactory.DefineFilter<EmployeeTeam>(),
  374. new Columns<EmployeeTeam>(x => x.EmployeeLink.ID)
  375. .Add(x => x.TeamLink.ID)
  376. );
  377. query.Query();
  378. _teams = query.Get<Team>().ToDictionary<Team, Guid, string>(x => x.ID, x => x.Name);
  379. _employees = query.Get<Employee>().ToDictionary<Employee, Guid, string>(x => x.ID, x => x.Name, x => x.Name);
  380. UserTasksHeaderImageConverter.Employees = query.Get<Employee>().ToDictionary<Employee, Guid, Guid>(x => x.ID, x => x.Thumbnail.ID);
  381. _teamemployees = query.Get<EmployeeTeam>().ToLookup<EmployeeTeam, Guid, Guid>(x => x.TeamLink.ID, x => x.EmployeeLink.ID);
  382. SelectedTeams.ItemsSource = _teams;
  383. }
  384. private void PopulateEmployees()
  385. {
  386. bPopulating = true;
  387. try
  388. {
  389. var availableemployees = new List<Guid>();
  390. foreach (KeyValuePair<Guid, string> team in SelectedTeams.SelectedItems)
  391. availableemployees.AddRange(_teamemployees[team.Key].Where(x => !availableemployees.Contains(x)));
  392. SelectedEmployees.ItemsSource = _employees.Where(x => availableemployees.Contains(x.Key));
  393. SelectedEmployees.SelectedItems.Clear();
  394. foreach (var employee in Host.KanbanSettings.UserSettings.SelectedEmployees.Where(x => availableemployees.Contains(x)))
  395. SelectedEmployees.SelectedItems.Add(_employees.FirstOrDefault(x => Equals(x.Key, employee)));
  396. }
  397. catch (Exception e)
  398. {
  399. }
  400. bPopulating = false;
  401. }
  402. private bool FilterKanban(TaskModel model, string searches, params Func<TaskModel, string>[] properties)
  403. {
  404. foreach (var search in searches.Split(' '))
  405. foreach (var property in properties)
  406. if (!property(model).Contains(search))
  407. return false;
  408. return true;
  409. }
  410. private void FilterKanbans()
  411. {
  412. IEnumerable<TaskModel> Items = _models;
  413. if (TaskType.SelectedItem is KanbanType kanbanType)
  414. {
  415. Items = Items.Where(x => x.Type.ID == kanbanType.ID);
  416. }
  417. if (!string.IsNullOrWhiteSpace(Search.Text))
  418. {
  419. var searches = Search.Text.Split();
  420. Items = Items.Where(x => x.Search(searches));
  421. }
  422. if(object.Equals(Kanban.ItemsSource, Items))
  423. {
  424. // Triggers a refresh.
  425. Kanban.ItemsSource = null;
  426. }
  427. Kanban.ItemsSource = Items;
  428. }
  429. private void ViewType_SelectionChanged(object sender, SelectionChangedEventArgs e)
  430. {
  431. if (Kanban != null)
  432. Kanban.CardTemplate = ViewType.SelectedIndex > 0
  433. ? Resources["CompactKanban"] as DataTemplate
  434. : Resources["FullKanban"] as DataTemplate;
  435. if (IsReady)
  436. {
  437. Host.KanbanSettings.StatusSettings.CompactView = ViewType.SelectedIndex > 0;
  438. Host.SaveSettings();
  439. }
  440. }
  441. private void TaskType_SelectionChanged(object sender, SelectionChangedEventArgs e)
  442. {
  443. FilterKanbans();
  444. }
  445. private void IncludeLocked_Checked(object sender, RoutedEventArgs e)
  446. {
  447. if (!IsReady)
  448. return;
  449. SaveSettings();
  450. Refresh(true);
  451. }
  452. private void IncludeManaged_Checked(object sender, RoutedEventArgs e)
  453. {
  454. if (!IsReady)
  455. return;
  456. SaveSettings();
  457. Refresh(true);
  458. }
  459. private void IncludeObserved_Checked(object sender, RoutedEventArgs e)
  460. {
  461. if (!IsReady)
  462. return;
  463. SaveSettings();
  464. Refresh(true);
  465. }
  466. private void IncludeCompleted_Checked(object sender, RoutedEventArgs e)
  467. {
  468. if (!IsReady)
  469. return;
  470. SaveSettings();
  471. Refresh(true);
  472. }
  473. private void Search_KeyUp(object sender, KeyEventArgs e)
  474. {
  475. FilterKanbans();
  476. }
  477. private void Export_Click(object sender, RoutedEventArgs e)
  478. {
  479. }
  480. private void Kanban_CardDragStart(object sender, KanbanDragStartEventArgs e)
  481. {
  482. var models = SelectedModels(e.SelectedCard.Content as TaskModel).ToList();
  483. if (models.Any(x => x.Locked || x.EmployeeID != Guid.Parse(x.Category.ToString())) || !Host.CanChangeTasks(models))
  484. e.IsCancel = true;
  485. }
  486. private void Kanban_CardDragEnd(object sender, KanbanDragEndEventArgs e)
  487. {
  488. using (new WaitCursor())
  489. {
  490. var target = e.TargetColumn.Categories;
  491. var targetCategory = e.TargetKey;
  492. var models = SelectedModels(e.SelectedCard.Content as TaskModel).Where(x => !Equals(x.Category, target)).ToList();
  493. if (!models.Any())
  494. return;
  495. var kanbans = Host.LoadKanbans(models, new Columns<Kanban>(x => x.ID, x => x.EmployeeLink.ID, x => x.Private, x => x.Number));
  496. var subscribers = new ClientKanbanSubscriberSet(kanbans.Select(x => x.ID));
  497. var targetID = Guid.Parse(target);
  498. var updated = new List<Kanban>();
  499. foreach (var kanban in kanbans)
  500. {
  501. if (!kanban.Private)
  502. {
  503. kanban.EmployeeLink.ID = targetID;
  504. subscribers.EnsureAssignee(kanban.ID, kanban.EmployeeLink.ID);
  505. updated.Add(kanban);
  506. }
  507. else
  508. {
  509. MessageBox.Show($"Cannot change assignee for task {kanban.Number} because it is private.");
  510. models.RemoveAll(x => x.ID == kanban.ID.ToString());
  511. }
  512. }
  513. new Client<Kanban>().Save(updated, string.Format("Task Employee Updated to {0}", target), (o, err) => { });
  514. subscribers.Save(false);
  515. foreach (var model in models)
  516. {
  517. model.Checked = false;
  518. model.Category = target;
  519. model.EmployeeID = targetID;
  520. }
  521. FilterKanbans();
  522. }
  523. }
  524. #region ITaskControl Support
  525. public ITaskHost Host { get; set; }
  526. public KanbanViewType KanbanViewType => KanbanViewType.User;
  527. public IEnumerable<TaskModel> SelectedModels(TaskModel? sender = null)
  528. {
  529. var result = _models.Where(x => x.Checked).ToList();
  530. if (sender != null && !result.Contains(sender))
  531. result.Add(sender);
  532. return result;
  533. }
  534. #endregion
  535. #region Kanban Actions
  536. private void DoEdit(TaskModel task)
  537. {
  538. if (task == null)
  539. return;
  540. var result = Host.EditReferences(new[] { task });
  541. if (result)
  542. Refresh(true);
  543. }
  544. private void TaskMenu_Opened(object sender, RoutedEventArgs e)
  545. {
  546. Host.PopulateMenu(this, (sender as ContextMenu)!);
  547. }
  548. private void Border_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
  549. {
  550. if (e.ClickCount > 1)
  551. {
  552. var task = ((Border)sender).Tag as TaskModel;
  553. DoEdit(task);
  554. e.Handled = true;
  555. }
  556. }
  557. private void CheckBox_Checked(object sender, RoutedEventArgs e)
  558. {
  559. }
  560. #endregion
  561. #region Employee List Actions
  562. private void SelectedTeams_ItemChecked(object sender, ItemCheckedEventArgs e)
  563. {
  564. if (!IsReady)
  565. return;
  566. PopulateEmployees();
  567. SaveSettings();
  568. Refresh(true);
  569. }
  570. private void SelectedTeams_SizeChanged(object sender, SizeChangedEventArgs e)
  571. {
  572. if (!IsReady || Equals(Host.KanbanSettings.UserSettings.TeamsHeight, SelectedTeams.ActualHeight))
  573. return;
  574. SaveSettings();
  575. }
  576. private void EmployeesSelectionChanged(object sender, SelectionChangedEventArgs e)
  577. {
  578. if (!IsReady || bPopulating)
  579. return;
  580. SaveSettings();
  581. Refresh(true);
  582. }
  583. public string SectionName => "Tasks By User";
  584. public DataModel DataModel(Selection selection)
  585. {
  586. return new AutoDataModel<Kanban>(new Filter<Kanban>(x => x.ID).IsEqualTo(Guid.Empty));
  587. }
  588. #endregion
  589. private void Kanban_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
  590. {
  591. e.Handled = true;
  592. }
  593. }
  594. }