TasksByStatusControlOld.xaml.cs 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.ObjectModel;
  4. using System.Globalization;
  5. using System.Linq;
  6. using System.Linq.Expressions;
  7. using System.Reflection;
  8. using System.Threading;
  9. using System.Threading.Tasks;
  10. using System.Windows;
  11. using System.Windows.Controls;
  12. using System.Windows.Data;
  13. using System.Windows.Input;
  14. using System.Windows.Media;
  15. using System.Windows.Media.Imaging;
  16. using Comal.Classes;
  17. using InABox.Clients;
  18. using InABox.Core;
  19. using InABox.DynamicGrid;
  20. using InABox.Wpf;
  21. using InABox.WPF;
  22. using org.omg.CORBA;
  23. using Syncfusion.UI.Xaml.Kanban;
  24. using Color = System.Drawing.Color;
  25. namespace PRSDesktop
  26. {
  27. public class StatusTasksHeaderTimeConverter : IValueConverter
  28. {
  29. public static IEnumerable<TaskModel> Tasks { get; set; }
  30. public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
  31. {
  32. if (Tasks == null)
  33. return "0:00";
  34. var dataContext = value as ColumnTag;
  35. if (dataContext == null)
  36. return "0:00";
  37. var getter = dataContext.GetType().GetProperty("Column", BindingFlags.NonPublic | BindingFlags.Instance);
  38. if (getter == null)
  39. return "0:00";
  40. var column = (KanbanColumn)getter.GetValue(dataContext);
  41. if (column == null)
  42. return "0:00";
  43. double result = 0.0F;
  44. foreach (var kanban in Tasks.Where(x => Equals(x.Category, column.Categories)))
  45. result += kanban.EstimatedTime.TotalHours;
  46. return string.Format("{0:F2}", result);
  47. }
  48. public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  49. {
  50. throw new NotImplementedException();
  51. }
  52. }
  53. /// <summary>
  54. /// Interaction logic for KanbanPanel.xaml
  55. /// </summary>
  56. public partial class TasksByStatusControlOld : UserControl, ITaskControl
  57. {
  58. private enum Suppress
  59. {
  60. This
  61. }
  62. private BitmapImage _attachimg = PRSDesktop.Resources.attachment.AsBitmapImage();
  63. private readonly ObservableCollection<EmployeeModel> _employeelist = new();
  64. private CoreTable _employees;
  65. public CoreTable _kanbans;
  66. private BitmapImage _lockimg = PRSDesktop.Resources.lock_sml.AsBitmapImage();
  67. private ObservableCollection<TaskModel> _models = new();
  68. private CoreTable _types;
  69. public List<string> CheckedKanbans = new();
  70. // CoreUtils.FullGuid => All Staff
  71. // Guid.Empty => Unallocated
  72. // Anything Else => Actual Staff Member
  73. private Guid EmployeeID = Guid.Empty;
  74. private Guid? MyID;
  75. private string MyName = "";
  76. private string searchtext = "";
  77. private Guid selectedtype = CoreUtils.FullGuid;
  78. public TasksByStatusControlOld()
  79. {
  80. using (new EventSuppressor(Suppress.This))
  81. InitializeComponent();
  82. }
  83. public string SectionName => "Tasks By Status";
  84. public DataModel DataModel(Selection selection)
  85. {
  86. var ids = SelectedModels().Select(x => Guid.Parse(x.ID)).ToArray();
  87. return new AutoDataModel<Kanban>(new Filter<Kanban>(x => x.ID).InList(ids));
  88. }
  89. private void ResizeColumns()
  90. {
  91. //if (!bResizeRequired)
  92. // return;
  93. using (var d = Dispatcher.DisableProcessing())
  94. {
  95. var CollapsedWidth = 50;
  96. var CollapsedColumns = 0;
  97. Array.ForEach(Kanban.Columns.ToArray(), x => { CollapsedColumns += x.IsExpanded ? 0 : 1; });
  98. if (Kanban.Columns.Count > 0 && CollapsedColumns != Kanban.Columns.Count)
  99. {
  100. var ColumnWidth = (Kanban.ActualWidth - CollapsedColumns * CollapsedWidth) / (Kanban.Columns.Count - CollapsedColumns) - 2;
  101. if (ColumnWidth != Kanban.ColumnWidth) Kanban.ColumnWidth = ColumnWidth;
  102. //bResizeRequired = false;
  103. }
  104. }
  105. }
  106. private void TaskMenu_Opened(object sender, RoutedEventArgs e)
  107. {
  108. Host.PopulateMenu(this, sender as ContextMenu);
  109. }
  110. private void Kanban_SizeChanged(object sender, SizeChangedEventArgs e)
  111. {
  112. Kanban.ColumnWidth = Kanban.ActualWidth / Kanban.Columns.Count - 1.0F;
  113. }
  114. private void Kanban_CardDragStart(object sender, KanbanDragStartEventArgs e)
  115. {
  116. var models = SelectedModels(e.SelectedCard.Content as TaskModel);
  117. if (models.Any(x => x.Locked))
  118. e.IsCancel = true;
  119. }
  120. private void Kanban_CardDragEnd(object sender, KanbanDragEndEventArgs e)
  121. {
  122. using (new WaitCursor())
  123. {
  124. var target = e.TargetColumn.Categories;
  125. var models = SelectedModels(e.SelectedCard.Content as TaskModel).Where(x => !Equals(x.Category, target)).ToArray();
  126. if (!models.Any())
  127. return;
  128. var kanbans = Host.LoadKanbans(models, new Columns<Kanban>(x => x.ID, x => x.Category));
  129. foreach (var kanban in kanbans)
  130. kanban.Category = target;
  131. new Client<Kanban>().Save(kanbans, string.Format("Task Status Updated to {0}", target), (o, err) => { });
  132. foreach (var model in models)
  133. {
  134. model.Checked = false;
  135. model.Category = target;
  136. }
  137. FilterKanbans();
  138. }
  139. }
  140. private void Search_KeyUp(object sender, KeyEventArgs e)
  141. {
  142. if (string.IsNullOrWhiteSpace(Search.Text) || e.Key == Key.Return)
  143. {
  144. searchtext = Search.Text;
  145. Refresh(true);
  146. }
  147. }
  148. private void TaskTypes_SelectionChanged(object sender, SelectionChangedEventArgs e)
  149. {
  150. if (!IsReady || EventSuppressor.IsSet(Suppress.This))
  151. return;
  152. if (e.AddedItems.Count > 0)
  153. {
  154. var item = (KeyValuePair<Guid, string>)e.AddedItems[0];
  155. selectedtype = item.Key;
  156. }
  157. else
  158. {
  159. selectedtype = CoreUtils.FullGuid;
  160. }
  161. Host.KanbanSettings.StatusSettings.SelectedType = selectedtype;
  162. Host.SaveSettings();
  163. ReloadKanbans();
  164. }
  165. private void IncludeCompleted_Checked(object sender, RoutedEventArgs e)
  166. {
  167. if (!IsReady)
  168. return;
  169. Host.KanbanSettings.StatusSettings.IncludeCompleted = IncludeCompleted.IsChecked.Value;
  170. Host.SaveSettings();
  171. SetupColumns();
  172. ReloadKanbans();
  173. }
  174. private void IncludeObserved_Checked(object sender, RoutedEventArgs e)
  175. {
  176. if (!IsReady)
  177. return;
  178. Host.KanbanSettings.StatusSettings.IncludeObserved = IncludeObserved.IsChecked.Value;
  179. Host.SaveSettings();
  180. ReloadKanbans();
  181. }
  182. private void IncludeLocked_Checked(object sender, RoutedEventArgs e)
  183. {
  184. if (!IsReady)
  185. return;
  186. Host.KanbanSettings.StatusSettings.IncludeLocked = IncludeLocked.IsChecked.Value;
  187. Host.SaveSettings();
  188. ReloadKanbans();
  189. }
  190. private void ViewType_SelectionChanged(object sender, SelectionChangedEventArgs e)
  191. {
  192. if (Kanban != null)
  193. Kanban.CardTemplate = ViewType.SelectedIndex > 0
  194. ? Resources["CompactKanban"] as DataTemplate
  195. : Resources["FullKanban"] as DataTemplate;
  196. if (!IsReady || EventSuppressor.IsSet(Suppress.This))
  197. return;
  198. Host.KanbanSettings.StatusSettings.CompactView = ViewType.SelectedIndex > 0;
  199. Host.SaveSettings();
  200. }
  201. private static bool UpdatingEmployees = false;
  202. private void Employees_SelectionChanged(object sender, SelectionChangedEventArgs e)
  203. {
  204. if (UpdatingEmployees || EventSuppressor.IsSet(Suppress.This))
  205. return;
  206. if (e.AddedItems.Count == 0)
  207. {
  208. EmployeeID = Guid.Empty;
  209. }
  210. else
  211. {
  212. var model = _employeelist[Employees.SelectedIndex];
  213. EmployeeID = model.ID;
  214. }
  215. CheckedKanbans.Clear();
  216. if (IsReady)
  217. Refresh(true);
  218. }
  219. private void Export_Click(object sender, RoutedEventArgs e)
  220. {
  221. var form = new DynamicExportForm(typeof(Kanban), _kanbans.Columns.Select(x => x.ColumnName));
  222. if (form.ShowDialog() != true)
  223. return;
  224. var export = new Client<Kanban>().Query(
  225. GetKanbanFilter(),
  226. new Columns<Kanban>(form.Fields),
  227. LookupFactory.DefineSort<Kanban>()
  228. );
  229. var employee = "Tasks for All Staff";
  230. if (EmployeeID != CoreUtils.FullGuid)
  231. {
  232. if (EmployeeID == Guid.Empty)
  233. {
  234. employee = "Unallocated Tasks";
  235. }
  236. else
  237. {
  238. var model = _employeelist.FirstOrDefault(x => x.ID.Equals(EmployeeID));
  239. employee = model == null ? "Tasks for (Unknown)" : "Tasks for " + (model.ID == MyID ? MyName : model.Name);
  240. }
  241. }
  242. ExcelExporter.DoExport<Kanban>(
  243. export,
  244. string.Format(
  245. "{0} ({1:dd-MMM-yy})",
  246. employee,
  247. DateTime.Today
  248. )
  249. );
  250. }
  251. #region ITaskControl Support
  252. public bool IsReady { get; set; }
  253. public ITaskHost Host { get; set; }
  254. public KanbanViewType KanbanViewType => KanbanViewType.Status;
  255. public IEnumerable<TaskModel> SelectedModels(TaskModel sender = null)
  256. {
  257. var result = _models.Where(x => x.Checked).ToList();
  258. if (sender != null && !result.Contains(sender))
  259. result.Add(sender);
  260. return result;
  261. }
  262. #endregion
  263. #region Setup
  264. public void Setup()
  265. {
  266. using (new EventSuppressor(Suppress.This))
  267. {
  268. SetupToolbar();
  269. SetupColumns();
  270. SetupData();
  271. SetupKanbanTypesLookup(false);
  272. SetupMyEmployee();
  273. SetupEmployeeList();
  274. }
  275. }
  276. private void SetupMyEmployee()
  277. {
  278. var row = _employees.Rows.FirstOrDefault(r => r.Get<Employee, Guid>(c => c.UserLink.ID) == ClientFactory.UserGuid);
  279. if (row != null)
  280. {
  281. MyID = row.Get<Employee, Guid>(c => c.ID);
  282. MyName = row.Get<Employee, string>(x => x.Name);
  283. }
  284. }
  285. private void SetupEmployeeList()
  286. {
  287. IEnumerable<CoreRow> active = null;
  288. var anonymous = PRSDesktop.Resources.anonymous.AsBitmapImage();
  289. if (Security.IsAllowed<CanViewOthersTasks>())
  290. {
  291. active = _employees.Rows.Where(r =>
  292. r.Get<Employee, bool>(x => x.CanAllocateTasks) && (r.Get<Employee, DateTime>(x => x.FinishDate).IsEmpty() ||
  293. r.Get<Employee, DateTime>(x => x.FinishDate) > DateTime.Today));
  294. _employeelist.Add(new EmployeeModel(CoreUtils.FullGuid, "All Staff", Guid.Empty, PRSDesktop.Resources.everyone.AsBitmapImage()));
  295. _employeelist.Add(new EmployeeModel(Guid.Empty, "Unallocated", Guid.Empty, null));
  296. }
  297. else
  298. {
  299. active = _employees.Rows.Where(r => r.Get<Employee, Guid>(c => c.UserLink.ID).Equals(ClientFactory.UserGuid));
  300. }
  301. EmployeeModel selected = null;
  302. foreach (var row in active)
  303. {
  304. var id = row.Get<Employee, Guid>(x => x.ID);
  305. var userid = row.Get<Employee, Guid>(x => x.UserLink.ID);
  306. var thumbnailid = row.Get<Employee, Guid>(x => x.Thumbnail.ID);
  307. var name = userid.Equals(ClientFactory.UserGuid) ? "My Tasks" : row.Get<Employee, string>(x => x.Name);
  308. var model = new EmployeeModel(id, name, thumbnailid, anonymous);
  309. if (userid.Equals(ClientFactory.UserGuid))
  310. {
  311. _employeelist.Insert(0, model);
  312. selected = model;
  313. }
  314. else
  315. {
  316. _employeelist.Add(model);
  317. }
  318. }
  319. if (Security.IsAllowed<CanViewOthersTasks>())
  320. {
  321. EmployeeListColumn.Width = new GridLength(1.0F, GridUnitType.Auto);
  322. var thumbnails = active
  323. .Select(r => r.EntityLinkID<Employee, ImageDocumentLink>(x => x.Thumbnail) ?? Guid.Empty)
  324. .Where(x => x != Guid.Empty).ToArray();
  325. Employees.ItemsSource = _employeelist;
  326. Employees.SelectedItem = _employeelist.First();
  327. EmployeeID = _employeelist.First().ID;
  328. if (thumbnails.Any())
  329. new Client<Document>().Query(
  330. new Filter<Document>(x => x.ID).InList(thumbnails),
  331. new Columns<Document>(x => x.ID, x => x.Data),
  332. null,
  333. (data, error) =>
  334. {
  335. if (data != null)
  336. ProcessThumbnails(data);
  337. }
  338. );
  339. }
  340. else
  341. {
  342. EmployeeListColumn.Width = new GridLength(0.0F, GridUnitType.Pixel);
  343. Employees.ItemsSource = _employeelist;
  344. Employees.SelectedItem = _employeelist.First();
  345. EmployeeID = _employeelist.First().ID;
  346. }
  347. }
  348. private void ProcessThumbnails(CoreTable data)
  349. {
  350. Dispatcher.Invoke(() =>
  351. {
  352. foreach (var row in data.Rows)
  353. {
  354. var id = row.Get<Document, Guid>(x => x.ID);
  355. var model = _employeelist.FirstOrDefault(x => x.ThumbnailID.Equals(id));
  356. if (model != null)
  357. {
  358. model.Image = new BitmapImage();
  359. model.Image.LoadImage(row.Get<Document, byte[]>(x => x.Data));
  360. }
  361. }
  362. UpdatingEmployees = true;
  363. Employees.ItemsSource = null;
  364. Employees.ItemsSource = _employeelist;
  365. Employees.SelectedItem = _employeelist.First();
  366. EmployeeID = _employeelist.First().ID;
  367. UpdatingEmployees = false;
  368. });
  369. }
  370. private void SetupKanbanTypesLookup(bool reload)
  371. {
  372. if (ClientFactory.IsSupported<KanbanType>())
  373. {
  374. if (reload)
  375. {
  376. _types = new Client<KanbanType>().Query(
  377. new Filter<KanbanType>(x => x.Hidden).IsEqualTo(false),
  378. new Columns<KanbanType>(x => x.ID, x => x.Description),
  379. new SortOrder<KanbanType>(x => x.Description)
  380. );
  381. }
  382. var tasktypes = new Dictionary<Guid, string>
  383. {
  384. { CoreUtils.FullGuid, "All Types" },
  385. { Guid.Empty, "Unallocated Types" }
  386. };
  387. _types.IntoDictionary<KanbanType, Guid, string>(tasktypes, x => x.ID, row => row.Get<KanbanType, string>(x => x.Description));
  388. TaskTypes.ItemsSource = tasktypes;
  389. if (tasktypes.ContainsKey(Host.KanbanSettings.StatusSettings.SelectedType))
  390. TaskTypes.SelectedValue = Host.KanbanSettings.StatusSettings.SelectedType;
  391. else
  392. TaskTypes.SelectedValue = CoreUtils.FullGuid;
  393. TaskTypesLabel.Visibility = Visibility.Visible;
  394. TaskTypes.Visibility = Visibility.Visible;
  395. }
  396. else
  397. {
  398. TaskTypesLabel.Visibility = Visibility.Collapsed;
  399. TaskTypes.Visibility = Visibility.Collapsed;
  400. }
  401. }
  402. private void SetupToolbar()
  403. {
  404. IncludeCompleted.Visibility = Security.IsAllowed<CanHideTaskCompletedColumn>() ? Visibility.Visible : Visibility.Collapsed;
  405. IncludeCompleted.IsChecked = IncludeCompleted.Visibility == Visibility.Visible ? Host.KanbanSettings.StatusSettings.IncludeCompleted : true;
  406. IncludeObserved.IsChecked = Host.KanbanSettings.StatusSettings.IncludeObserved;
  407. ViewType.SelectedIndex = Host.KanbanSettings.StatusSettings.CompactView ? 1 : 0;
  408. }
  409. private void SetupColumns()
  410. {
  411. Kanban.Columns.Clear();
  412. var indicatorColorPalette = new IndicatorColorPalette();
  413. indicatorColorPalette.Add(new ColorMapping { Key = "Red", Color = Colors.LightSalmon });
  414. indicatorColorPalette.Add(new ColorMapping { Key = "Orange", Color = Colors.Orange });
  415. indicatorColorPalette.Add(new ColorMapping { Key = "Yellow", Color = Colors.LightYellow });
  416. indicatorColorPalette.Add(new ColorMapping { Key = "Green", Color = Colors.LightGreen });
  417. Kanban.IndicatorColorPalette = indicatorColorPalette;
  418. Kanban.Columns.Add(new KanbanColumn
  419. {
  420. Categories = "Open",
  421. Title = "To Do"
  422. });
  423. Kanban.Columns.Add(new KanbanColumn
  424. {
  425. Categories = "In Progress",
  426. Title = "In Progress"
  427. });
  428. Kanban.Columns.Add(new KanbanColumn
  429. {
  430. Categories = "Waiting",
  431. Title = "Waiting for Others"
  432. });
  433. if (Host.KanbanSettings.StatusSettings.IncludeCompleted)
  434. Kanban.Columns.Add(new KanbanColumn
  435. {
  436. Categories = "Complete",
  437. Title = "Completed"
  438. });
  439. Kanban.InvalidateVisual();
  440. foreach (var column in Kanban.Columns)
  441. {
  442. var menu = new ContextMenu();
  443. menu.Tag = column;
  444. var item = new MenuItem { Header = "New Task" };
  445. item.Click += CreateTask;
  446. menu.Items.Add(item);
  447. menu.Items.Add(new Separator());
  448. item = new MenuItem { Header = "Select All " + column.Title + " Tasks", Tag = column };
  449. item.Click += SelectAll_Click;
  450. menu.Items.Add(item);
  451. item = new MenuItem { Header = "Unselect All " + column.Title + " Tasks", Tag = column };
  452. item.Click += UnSelectAll_Click;
  453. menu.Items.Add(item);
  454. column.ContextMenu = menu;
  455. }
  456. Kanban.ColumnWidth = Kanban.ActualWidth / Kanban.Columns.Count - 1.0F;
  457. }
  458. private void SetupData()
  459. {
  460. var query = new MultiQuery();
  461. query.Add(
  462. null,
  463. new Columns<Employee>(x => x.ID, x => x.Name, x => x.Thumbnail.ID, x => x.CanAllocateTasks, x => x.Email, x => x.Mobile,
  464. x => x.FinishDate, x => x.UserLink.ID),
  465. new SortOrder<Employee>(x => x.Name)
  466. );
  467. if (ClientFactory.IsSupported<KanbanType>())
  468. query.Add(
  469. new Filter<KanbanType>(x => x.Hidden).IsEqualTo(false),
  470. new Columns<KanbanType>(x => x.ID, x => x.Description),
  471. new SortOrder<KanbanType>(x => x.Description)
  472. );
  473. query.Query();
  474. _employees = query.Get<Employee>();
  475. _types = ClientFactory.IsSupported<KanbanType>()
  476. ? query.Get<KanbanType>()
  477. : null;
  478. }
  479. #endregion
  480. #region Refresh / Reload
  481. private Filter<T> GetSearchFilter<T>(Expression<Func<T, object>> expression) where T : Entity, new()
  482. {
  483. Filter<T> result = null;
  484. var comps = searchtext.Trim().Split(' ');
  485. foreach (var comp in comps)
  486. result = result == null ? new Filter<T>(expression).Contains(comp) : result.And(expression).Contains(comp);
  487. return result;
  488. }
  489. private Filter<KanbanSubscriber> GetKanbanSubscriberFilter()
  490. {
  491. var filter = new Filter<KanbanSubscriber>(x => x.Kanban.Closed).IsEqualTo(DateTime.MinValue);
  492. if (Host.Job != null)
  493. {
  494. if (Host.Job.ID != Guid.Empty)
  495. filter = filter.And(x => x.Kanban.JobLink.ID).IsEqualTo(Host.Job.ID);
  496. else
  497. filter = filter.And(x => x.Kanban.JobLink.ID).None();
  498. }
  499. // All Tasks (EmployeeID.HasValue == false) or Unallocated (EmployeeID = Guid.Empty) are retrieved directly from the Kanban Table
  500. // so if we are here, we can assume that we are pulling subscriber data
  501. var empfilter = new Filter<KanbanSubscriber>(x => x.Employee.ID).IsEqualTo(EmployeeID);
  502. filter.Ands.Add(empfilter);
  503. if (EmployeeID != MyID)
  504. filter = filter.And(x => x.Kanban.Private).IsEqualTo(false);
  505. //if (!includeobserved)
  506. // filter = filter.And(new Filter<KanbanSubscriber>(x => x.Assignee).IsEqualTo(true).Or(x => x.Manager).IsEqualTo(true));
  507. //if (!includecompleted)
  508. // filter = filter.And(x => x.Kanban.Completed).IsEqualTo(DateTime.MinValue);
  509. //if (selectedtype != CoreUtils.FullGuid)
  510. // filter = filter.And(x => x.Kanban.Type.ID).IsEqualTo(selectedtype);
  511. if (!string.IsNullOrWhiteSpace(searchtext))
  512. {
  513. var search = GetSearchFilter<KanbanSubscriber>(x => x.Kanban.JobLink.Name);
  514. search.Ors.Add(GetSearchFilter<KanbanSubscriber>(x => x.Kanban.JobLink.JobNumber));
  515. search.Ors.Add(GetSearchFilter<KanbanSubscriber>(x => x.Kanban.Summary));
  516. search.Ors.Add(GetSearchFilter<KanbanSubscriber>(x => x.Kanban.Title));
  517. search.Ors.Add(GetSearchFilter<KanbanSubscriber>(x => x.Kanban.ManagerLink.Name));
  518. search.Ors.Add(GetSearchFilter<KanbanSubscriber>(x => x.Kanban.EmployeeLink.Name));
  519. if (int.TryParse(searchtext.Trim(), out var tasknumber))
  520. search.Ors.Add(new Filter<KanbanSubscriber>(x => x.Kanban.Number).IsEqualTo(tasknumber));
  521. filter.Ands.Add(search);
  522. }
  523. return filter;
  524. }
  525. private Filter<Kanban> GetKanbanFilter()
  526. {
  527. var filter = new Filter<Kanban>(x => x.Closed).IsEqualTo(DateTime.MinValue);
  528. if (Host.Job != null)
  529. {
  530. if (Host.Job.ID != Guid.Empty)
  531. filter = filter.And(x => x.JobLink.ID).IsEqualTo(Host.Job.ID);
  532. else
  533. filter = filter.And(x => x.JobLink.ID).None();
  534. }
  535. if (EmployeeID != CoreUtils.FullGuid)
  536. {
  537. if (EmployeeID != Guid.Empty)
  538. {
  539. var empfilter = new Filter<Kanban>(x => x.EmployeeLink.ID).IsEqualTo(EmployeeID).Or(x => x.ManagerLink.ID).IsEqualTo(EmployeeID);
  540. filter.Ands.Add(empfilter);
  541. }
  542. else
  543. {
  544. filter = filter.And(x => x.EmployeeLink.ID).IsEqualTo(EmployeeID);
  545. }
  546. }
  547. if (EmployeeID != MyID)
  548. filter = filter.And(x => x.Private).IsEqualTo(false);
  549. //if (!includecompleted)
  550. // filter = filter.And(x => x.Completed).IsEqualTo(DateTime.MinValue);
  551. //if (selectedtype != CoreUtils.FullGuid)
  552. // filter = filter.And(x => x.Type.ID).IsEqualTo(selectedtype);
  553. return filter;
  554. }
  555. public void Refresh(bool resetselection)
  556. {
  557. Application.Current.Dispatcher.Invoke(() => { Mouse.OverrideCursor = Cursors.Wait; });
  558. if (EmployeeID != CoreUtils.FullGuid && EmployeeID != Guid.Empty)
  559. {
  560. _kanbans = new Client<KanbanSubscriber>().Query(
  561. GetKanbanSubscriberFilter(),
  562. new Columns<KanbanSubscriber>
  563. (
  564. x => x.Kanban.ID,
  565. x => x.Kanban.DueDate,
  566. x => x.Kanban.Completed,
  567. //x => x.Kanban.Description,
  568. x => x.Kanban.Summary,
  569. x => x.Kanban.Category,
  570. x => x.Kanban.EmployeeLink.ID,
  571. x => x.Kanban.ManagerLink.ID,
  572. x => x.Kanban.Notes,
  573. x => x.Kanban.Title,
  574. x => x.Kanban.JobLink.ID,
  575. x => x.Kanban.JobLink.JobNumber,
  576. x => x.Kanban.JobLink.Name,
  577. x => x.Kanban.Type.ID,
  578. x => x.Kanban.Type.Code,
  579. x => x.Kanban.Number,
  580. x => x.Kanban.Attachments,
  581. x => x.Kanban.Locked
  582. ),
  583. new SortOrder<KanbanSubscriber>(x => x.Kanban.DueDate) { Direction = SortDirection.Ascending }
  584. );
  585. foreach (var column in _kanbans.Columns)
  586. column.ColumnName = column.ColumnName.Replace("Kanban.", "");
  587. }
  588. else
  589. {
  590. _kanbans = new Client<Kanban>().Query(
  591. GetKanbanFilter(),
  592. new Columns<Kanban>
  593. (
  594. x => x.ID,
  595. x => x.DueDate,
  596. x => x.Completed,
  597. //x => x.Description,
  598. x => x.Summary,
  599. x => x.Category,
  600. x => x.EmployeeLink.ID,
  601. x => x.ManagerLink.ID,
  602. x => x.Notes,
  603. x => x.Title,
  604. x => x.JobLink.ID,
  605. x => x.JobLink.JobNumber,
  606. x => x.JobLink.Name,
  607. x => x.Type.ID,
  608. x => x.Type.Code,
  609. x => x.Number,
  610. x => x.Attachments,
  611. x => x.Locked
  612. ),
  613. new SortOrder<Kanban>(x => x.DueDate) { Direction = SortDirection.Ascending }
  614. );
  615. }
  616. ReloadKanbans();
  617. Application.Current.Dispatcher.Invoke(() => { Mouse.OverrideCursor = null; });
  618. }
  619. private void ReloadKanbans()
  620. {
  621. //SetupColumns();
  622. //ResizeColumns();
  623. _models = new ObservableCollection<TaskModel>();
  624. foreach (var row in _kanbans.Rows)
  625. try
  626. {
  627. var empid = row.Get<IKanban, Guid>(e => e.EmployeeLink.ID);
  628. var mgrid = row.EntityLinkID<IKanban, EmployeeLink>(x => x.ManagerLink) ?? Guid.Empty;
  629. var completed = row.Get<IKanban, DateTime>(e => e.Completed);
  630. var locked = row.Get<IKanban, bool>(e => e.Locked);
  631. var type = row.Get<IKanban, Guid>(e => e.Type.ID);
  632. var category = row.Get<IKanban, string>(x => x.Category);
  633. if (string.IsNullOrWhiteSpace(category))
  634. category = "Open";
  635. var bLockedOK = Host.KanbanSettings.StatusSettings.IncludeLocked || locked == false;
  636. var bObserveOK = EmployeeID == CoreUtils.FullGuid || Host.KanbanSettings.StatusSettings.IncludeObserved || empid == EmployeeID || mgrid == EmployeeID;
  637. var bCompleteOK = Host.KanbanSettings.StatusSettings.IncludeCompleted || completed.IsEmpty();
  638. var bTypeOK = selectedtype == CoreUtils.FullGuid || type == selectedtype;
  639. if (bLockedOK && bCompleteOK && bObserveOK && bTypeOK)
  640. {
  641. var model = new TaskModel();
  642. var EmployeeEntry = _employeelist.Where(x => x.ID.Equals(empid)).FirstOrDefault();
  643. var empimg = EmployeeEntry?.Image;
  644. var ManagerEntry = _employeelist.Where(x => x.ID.Equals(mgrid)).FirstOrDefault();
  645. //var description = row.Get<IKanban, String>(x => x.Summary);
  646. //if (String.IsNullOrWhiteSpace(description))
  647. // description = String.Join("\r\n", row.Get<IKanban, String[]>(x => x.Notes)).Split(new String[] { "===============" }, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault();
  648. //if (String.IsNullOrWhiteSpace(description))
  649. // description = CoreUtils.StripHTML(row.Get<IKanban, String>(x => x.Description));
  650. //if (String.IsNullOrWhiteSpace(description))
  651. // description = "";
  652. var job = row.Get<IKanban, string>(x => x.JobLink.JobNumber);
  653. model.Title = row.Get<IKanban, string>(x => x.Title);
  654. model.ID = row.Get<IKanban, Guid>(x => x.ID).ToString();
  655. model.Description = row.Get<IKanban, string>(x => x.Summary) ?? "";
  656. model.Category = category;
  657. var color = EmployeeID == Guid.Empty || empid == EmployeeID || EmployeeID == CoreUtils.FullGuid
  658. ? TaskModel.KanbanColor(
  659. row.Get<IKanban, DateTime>(x => x.DueDate),
  660. row.Get<IKanban, DateTime>(x => x.Completed))
  661. : mgrid == EmployeeID
  662. ? Color.Silver
  663. : Color.Plum;
  664. if (row.Get<IKanban, bool>(x => x.Locked))
  665. color = color.MixColors(0.5F, Color.White);
  666. model.ColorKey = ImageUtils.ColorToString(color);
  667. model.Image = empimg;
  668. model.ImageURL = null;
  669. model.Attachments = row.Get<IKanban, int>(x => x.Attachments) > 0; // ? _attachimg : null;
  670. model.DueDate = row.Get<IKanban, DateTime>(x => x.DueDate);
  671. model.CompletedDate = row.Get<IKanban, DateTime>(x => x.Completed);
  672. model.Locked = row.Get<IKanban, bool>(x => x.Locked); // ? _lockimg : null;
  673. var notes = new List<List<string>> { new() };
  674. if ((row.Get<IKanban, string[]>(x => x.Notes) != null))
  675. {
  676. foreach (var line in row.Get<IKanban, string[]>(x => x.Notes))
  677. {
  678. if (line == "===================================")
  679. {
  680. notes.Add(new());
  681. }
  682. else
  683. {
  684. notes.Last().Add(line);
  685. }
  686. }
  687. model.Notes = string.Join("\n===================================\n", notes.Reverse<List<string>>().Select(x => string.Join('\n', x)));
  688. }
  689. model.EmployeeID = empid;
  690. model.ManagerID = mgrid;
  691. var sEmp = "";
  692. if (empid != EmployeeID)
  693. {
  694. if (!Entity.IsEntityLinkValid<IKanban, EmployeeLink>(x => x.EmployeeLink, row))
  695. {
  696. sEmp = "Unallocated";
  697. }
  698. else
  699. {
  700. var tuple = _employeelist.FirstOrDefault(x => x.ID.Equals(empid));
  701. sEmp = tuple != null ? tuple.ID == MyID ? MyName : tuple.Name : "";
  702. }
  703. }
  704. var sMgr = "";
  705. if (mgrid != EmployeeID)
  706. if (mgrid != Guid.Empty)
  707. {
  708. var tuple = _employeelist.FirstOrDefault(x => x.ID.Equals(mgrid));
  709. sMgr = tuple != null ? tuple.ID == MyID ? MyName : tuple.Name : "";
  710. }
  711. if (!string.IsNullOrEmpty(sEmp))
  712. {
  713. if (!string.IsNullOrWhiteSpace(sMgr) && !string.Equals(sMgr, sEmp))
  714. model.AssignedTo = string.Format("Assigned to {0} by {1}", sEmp, sMgr);
  715. else
  716. model.AssignedTo = string.Format("Assigned to {0} ", sEmp);
  717. }
  718. else
  719. {
  720. if (!string.IsNullOrWhiteSpace(sMgr))
  721. model.AssignedTo = string.Format("Allocated by {0} ", sMgr);
  722. }
  723. //model.AssignedTo = String.Format("M: {0} / E: {1}", sMgr, sEmp);
  724. model.JobID = row.Get<IKanban, Guid>(x => x.JobLink.ID);
  725. model.JobNumber = row.Get<IKanban, string>(x => x.JobLink.JobNumber);
  726. if (string.IsNullOrWhiteSpace(model.JobNumber))
  727. model.JobNumber = "";
  728. model.JobName = row.Get<IKanban, string>(x => x.JobLink.Name);
  729. model.Checked = CheckedKanbans.Contains(row.Get<IKanban, Guid>(x => x.ID).ToString());
  730. model.Type = new KanbanType
  731. {
  732. ID = row.Get<IKanban, Guid>(x => x.Type.ID),
  733. Code = row.Get<IKanban, string>(x => x.Type.Code)
  734. };
  735. model.Number = row.Get<IKanban, int>(x => x.Number);
  736. _models.Add(model);
  737. }
  738. }
  739. catch (Exception e)
  740. {
  741. Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
  742. }
  743. StatusTasksHeaderTimeConverter.Tasks = _models;
  744. FilterKanbans();
  745. }
  746. private void FilterKanbans()
  747. {
  748. Progress.ShowModal("Loading", (progress) =>
  749. {
  750. Dispatcher.BeginInvoke(() => { Progress.Show("Loading"); });
  751. if (JobFilterID == Guid.Empty)
  752. {
  753. var list = _models
  754. .Where(x => x.Search(Search.Text.Split()))
  755. .OrderBy(x => x.EmployeeID == EmployeeID ? 0 : 1).ThenBy(x => x.DueDate);
  756. Dispatcher.BeginInvoke(() => { Kanban.ItemsSource = list; });
  757. }
  758. else
  759. {
  760. var list = _models
  761. .Where(x => x.Search(Search.Text.Split()) && x.JobSearch(JobFilterID))
  762. .OrderBy(x => x.EmployeeID == EmployeeID ? 0 : 1).ThenBy(x => x.DueDate);
  763. Dispatcher.BeginInvoke(() => { Kanban.ItemsSource = list; });
  764. }
  765. Task.Run(() =>
  766. {
  767. Thread.Sleep(500);
  768. Dispatcher.BeginInvoke(() =>
  769. {
  770. Progress.Close();
  771. });
  772. });
  773. });
  774. }
  775. #endregion
  776. private void TaskTypesLabel_OnClick(object sender, RoutedEventArgs e)
  777. {
  778. var list = new MasterList(typeof(KanbanType));
  779. list.ShowDialog();
  780. SetupKanbanTypesLookup(true);
  781. }
  782. private void JobFilterBtn_OnClick(object sender, RoutedEventArgs e)
  783. {
  784. if (JobFilterID != Guid.Empty)
  785. {
  786. JobFilterBtn.Content = "Filter Job";
  787. JobFilterID = Guid.Empty;
  788. FilterKanbans();
  789. return;
  790. }
  791. var window = new ThemableWindow();
  792. var grid = new JobGrid();
  793. grid.Reconfigure(options =>
  794. {
  795. options.Remove(DynamicGridOption.EditRows);
  796. options.Remove(DynamicGridOption.DeleteRows);
  797. options.Remove(DynamicGridOption.AddRows);
  798. options.Remove(DynamicGridOption.MultiSelect);
  799. options.Remove(DynamicGridOption.ExportData);
  800. options.Remove(DynamicGridOption.ImportData);
  801. });
  802. grid.OnSelectItem += (object sender, DynamicGridSelectionEventArgs e) =>
  803. {
  804. if ((sender as JobGrid).SelectedRows.Count() == 0)
  805. return;
  806. else
  807. {
  808. var item = (sender as JobGrid).SelectedRows[0];
  809. AddJobFilter(item);
  810. window.Close();
  811. }
  812. };
  813. grid.Refresh(true, true);
  814. window.Content = grid;
  815. window.ShowDialog();
  816. }
  817. Guid JobFilterID = Guid.Empty;
  818. private void AddJobFilter(CoreRow item)
  819. {
  820. JobFilterID = item.Get<Job, Guid>(x => x.ID);
  821. JobFilterBtn.Content = item.Get<Job, string>(x => x.JobNumber) + " (click to cancel)";
  822. FilterKanbans();
  823. }
  824. }
  825. }