using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Globalization; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using Comal.Classes; using InABox.Clients; using InABox.Core; using InABox.DynamicGrid; using InABox.Wpf; using InABox.WPF; using org.omg.CORBA; using Syncfusion.UI.Xaml.Kanban; using Color = System.Drawing.Color; namespace PRSDesktop { public class EmployeeModel { public EmployeeModel(Guid id, string name, Guid thumbnail, BitmapImage image) { ID = id; Name = name; Image = image; ThumbnailID = thumbnail; } public Guid ID { get; set; } public string Name { get; set; } public BitmapImage Image { get; set; } public Guid ThumbnailID { get; set; } } public class StatusTasksHeaderTimeConverter : IValueConverter { public static IEnumerable Tasks { get; set; } public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (Tasks == null) return "0:00"; var dataContext = value as ColumnTag; if (dataContext == null) return "0:00"; var getter = dataContext.GetType().GetProperty("Column", BindingFlags.NonPublic | BindingFlags.Instance); if (getter == null) return "0:00"; var column = (KanbanColumn)getter.GetValue(dataContext); if (column == null) return "0:00"; double result = 0.0F; foreach (var kanban in Tasks.Where(x => Equals(x.Category, column.Categories))) result += kanban.EstimatedTime.TotalHours; return string.Format("{0:F2}", result); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } public class BoolToVisibilityConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (Equals(value, true)) return Visibility.Visible; return Visibility.Collapsed; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } /// /// Interaction logic for KanbanPanel.xaml /// public partial class TasksByStatusControl : UserControl, ITaskControl { private enum Suppress { This } private BitmapImage _attachimg = PRSDesktop.Resources.attachment.AsBitmapImage(); private readonly ObservableCollection _employeelist = new(); private CoreTable _employees; public CoreTable _kanbans; private BitmapImage _lockimg = PRSDesktop.Resources.lock_sml.AsBitmapImage(); private ObservableCollection _models = new(); private CoreTable _types; public List CheckedKanbans = new(); // CoreUtils.FullGuid => All Staff // Guid.Empty => Unallocated // Anything Else => Actual Staff Member private Guid EmployeeID = Guid.Empty; private Guid? MyID; private string MyName = ""; private string searchtext = ""; private Guid selectedtype = CoreUtils.FullGuid; public TasksByStatusControl() { using (new EventSuppressor(Suppress.This)) InitializeComponent(); } public string SectionName => "Tasks By Status"; public DataModel DataModel(Selection selection) { var ids = SelectedModels().Select(x => Guid.Parse(x.ID)).ToArray(); return new AutoDataModel(new Filter(x => x.ID).InList(ids)); } private void ResizeColumns() { //if (!bResizeRequired) // return; using (var d = Dispatcher.DisableProcessing()) { var CollapsedWidth = 50; var CollapsedColumns = 0; Array.ForEach(Kanban.Columns.ToArray(), x => { CollapsedColumns += x.IsExpanded ? 0 : 1; }); if (Kanban.Columns.Count > 0 && CollapsedColumns != Kanban.Columns.Count) { var ColumnWidth = (Kanban.ActualWidth - CollapsedColumns * CollapsedWidth) / (Kanban.Columns.Count - CollapsedColumns) - 2; if (ColumnWidth != Kanban.ColumnWidth) Kanban.ColumnWidth = ColumnWidth; //bResizeRequired = false; } } } private void TaskMenu_Opened(object sender, RoutedEventArgs e) { Host.PopulateMenu(this, sender as ContextMenu); } private void Kanban_SizeChanged(object sender, SizeChangedEventArgs e) { Kanban.ColumnWidth = Kanban.ActualWidth / Kanban.Columns.Count - 1.0F; } private void Kanban_CardDragStart(object sender, KanbanDragStartEventArgs e) { var models = SelectedModels(e.SelectedCard.Content as TaskModel); if (models.Any(x => x.Locked)) e.IsCancel = true; } private void Kanban_CardDragEnd(object sender, KanbanDragEndEventArgs e) { using (new WaitCursor()) { var target = e.TargetColumn.Categories; var models = SelectedModels(e.SelectedCard.Content as TaskModel).Where(x => !Equals(x.Category, target)).ToArray(); if (!models.Any()) return; var kanbans = Host.LoadKanbans(models, new Columns(x => x.ID, x => x.Category)); foreach (var kanban in kanbans) kanban.Category = target; new Client().Save(kanbans, string.Format("Task Status Updated to {0}", target), (o, err) => { }); foreach (var model in models) { model.Checked = false; model.Category = target; } FilterKanbans(); } } private void Search_KeyUp(object sender, KeyEventArgs e) { if (string.IsNullOrWhiteSpace(Search.Text) || e.Key == Key.Return) { searchtext = Search.Text; Refresh(true); } } private void TaskTypes_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (!IsReady || EventSuppressor.IsSet(Suppress.This)) return; if (e.AddedItems.Count > 0) { var item = (KeyValuePair)e.AddedItems[0]; selectedtype = item.Key; } else { selectedtype = CoreUtils.FullGuid; } Host.Settings.StatusSettings.SelectedType = selectedtype; Host.SaveSettings(); ReloadKanbans(); } private void IncludeCompleted_Checked(object sender, RoutedEventArgs e) { if (!IsReady) return; Host.Settings.StatusSettings.IncludeCompleted = IncludeCompleted.IsChecked.Value; Host.SaveSettings(); SetupColumns(); ReloadKanbans(); } private void IncludeObserved_Checked(object sender, RoutedEventArgs e) { if (!IsReady) return; Host.Settings.StatusSettings.IncludeObserved = IncludeObserved.IsChecked.Value; Host.SaveSettings(); ReloadKanbans(); } private void IncludeLocked_Checked(object sender, RoutedEventArgs e) { if (!IsReady) return; Host.Settings.StatusSettings.IncludeLocked = IncludeLocked.IsChecked.Value; Host.SaveSettings(); ReloadKanbans(); } private void ViewType_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (Kanban != null) Kanban.CardTemplate = ViewType.SelectedIndex > 0 ? Resources["CompactKanban"] as DataTemplate : Resources["FullKanban"] as DataTemplate; if (!IsReady || EventSuppressor.IsSet(Suppress.This)) return; Host.Settings.StatusSettings.CompactView = ViewType.SelectedIndex > 0; Host.SaveSettings(); } private static bool UpdatingEmployees = false; private void Employees_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (UpdatingEmployees || EventSuppressor.IsSet(Suppress.This)) return; if (e.AddedItems.Count == 0) { EmployeeID = Guid.Empty; } else { var model = _employeelist[Employees.SelectedIndex]; EmployeeID = model.ID; } CheckedKanbans.Clear(); if (IsReady) Refresh(true); } private void Export_Click(object sender, RoutedEventArgs e) { var form = new DynamicExportForm(typeof(Kanban), _kanbans.Columns.Select(x => x.ColumnName)); if (form.ShowDialog() != true) return; var export = new Client().Query( GetKanbanFilter(), new Columns(form.Fields), LookupFactory.DefineSort() ); var employee = "Tasks for All Staff"; if (EmployeeID != CoreUtils.FullGuid) { if (EmployeeID == Guid.Empty) { employee = "Unallocated Tasks"; } else { var model = _employeelist.FirstOrDefault(x => x.ID.Equals(EmployeeID)); employee = model == null ? "Tasks for (Unknown)" : "Tasks for " + (model.ID == MyID ? MyName : model.Name); } } ExcelExporter.DoExport( export, string.Format( "{0} ({1:dd-MMM-yy})", employee, DateTime.Today ) ); } #region ITaskControl Support public bool IsReady { get; set; } public ITaskHost Host { get; set; } public KanbanView KanbanView => KanbanView.Status; public IEnumerable SelectedModels(TaskModel sender = null) { var result = _models.Where(x => x.Checked).ToList(); if (sender != null && !result.Contains(sender)) result.Add(sender); return result; } #endregion #region Setup public void Setup() { using (new EventSuppressor(Suppress.This)) { SetupToolbar(); SetupColumns(); SetupData(); SetupKanbanTypesLookup(false); SetupMyEmployee(); SetupEmployeeList(); } } private void SetupMyEmployee() { var row = _employees.Rows.FirstOrDefault(r => r.Get(c => c.UserLink.ID) == ClientFactory.UserGuid); if (row != null) { MyID = row.Get(c => c.ID); MyName = row.Get(x => x.Name); } } private void SetupEmployeeList() { IEnumerable active = null; var anonymous = PRSDesktop.Resources.anonymous.AsBitmapImage(); if (Security.IsAllowed()) { active = _employees.Rows.Where(r => r.Get(x => x.CanAllocateTasks) && (r.Get(x => x.FinishDate).IsEmpty() || r.Get(x => x.FinishDate) > DateTime.Today)); _employeelist.Add(new EmployeeModel(CoreUtils.FullGuid, "All Staff", Guid.Empty, PRSDesktop.Resources.everyone.AsBitmapImage())); _employeelist.Add(new EmployeeModel(Guid.Empty, "Unallocated", Guid.Empty, null)); } else { active = _employees.Rows.Where(r => r.Get(c => c.UserLink.ID).Equals(ClientFactory.UserGuid)); } EmployeeModel selected = null; foreach (var row in active) { var id = row.Get(x => x.ID); var userid = row.Get(x => x.UserLink.ID); var thumbnailid = row.Get(x => x.Thumbnail.ID); var name = userid.Equals(ClientFactory.UserGuid) ? "My Tasks" : row.Get(x => x.Name); var model = new EmployeeModel(id, name, thumbnailid, anonymous); if (userid.Equals(ClientFactory.UserGuid)) { _employeelist.Insert(0, model); selected = model; } else { _employeelist.Add(model); } } if (Security.IsAllowed()) { EmployeeListColumn.Width = new GridLength(1.0F, GridUnitType.Auto); var thumbnails = active .Select(r => r.EntityLinkID(x => x.Thumbnail) ?? Guid.Empty) .Where(x => x != Guid.Empty).ToArray(); Employees.ItemsSource = _employeelist; Employees.SelectedItem = _employeelist.First(); EmployeeID = _employeelist.First().ID; if (thumbnails.Any()) new Client().Query( new Filter(x => x.ID).InList(thumbnails), new Columns(x => x.ID, x => x.Data), null, (data, error) => { if (data != null) ProcessThumbnails(data); } ); } else { EmployeeListColumn.Width = new GridLength(0.0F, GridUnitType.Pixel); Employees.ItemsSource = _employeelist; Employees.SelectedItem = _employeelist.First(); EmployeeID = _employeelist.First().ID; } } private void ProcessThumbnails(CoreTable data) { Dispatcher.Invoke(() => { foreach (var row in data.Rows) { var id = row.Get(x => x.ID); var model = _employeelist.FirstOrDefault(x => x.ThumbnailID.Equals(id)); if (model != null) { model.Image = new BitmapImage(); model.Image.LoadImage(row.Get(x => x.Data)); } } UpdatingEmployees = true; Employees.ItemsSource = null; Employees.ItemsSource = _employeelist; Employees.SelectedItem = _employeelist.First(); EmployeeID = _employeelist.First().ID; UpdatingEmployees = false; }); } private void SetupKanbanTypesLookup(bool reload) { if (ClientFactory.IsSupported()) { if (reload) { _types = new Client().Query( new Filter(x => x.Hidden).IsEqualTo(false), new Columns(x => x.ID, x => x.Description), new SortOrder(x => x.Description) ); } var tasktypes = new Dictionary { { CoreUtils.FullGuid, "All Types" }, { Guid.Empty, "Unallocated Types" } }; _types.IntoDictionary(tasktypes, x => x.ID, row => row.Get(x => x.Description)); TaskTypes.ItemsSource = tasktypes; if (tasktypes.ContainsKey(Host.Settings.StatusSettings.SelectedType)) TaskTypes.SelectedValue = Host.Settings.StatusSettings.SelectedType; else TaskTypes.SelectedValue = CoreUtils.FullGuid; TaskTypesLabel.Visibility = Visibility.Visible; TaskTypes.Visibility = Visibility.Visible; } else { TaskTypesLabel.Visibility = Visibility.Collapsed; TaskTypes.Visibility = Visibility.Collapsed; } } private void SetupToolbar() { IncludeCompleted.Visibility = Security.IsAllowed() ? Visibility.Visible : Visibility.Collapsed; IncludeCompleted.IsChecked = IncludeCompleted.Visibility == Visibility.Visible ? Host.Settings.StatusSettings.IncludeCompleted : true; IncludeObserved.IsChecked = Host.Settings.StatusSettings.IncludeObserved; ViewType.SelectedIndex = Host.Settings.StatusSettings.CompactView ? 1 : 0; } private void SetupColumns() { Kanban.Columns.Clear(); var indicatorColorPalette = new IndicatorColorPalette(); indicatorColorPalette.Add(new ColorMapping { Key = "Red", Color = Colors.LightSalmon }); indicatorColorPalette.Add(new ColorMapping { Key = "Orange", Color = Colors.Orange }); indicatorColorPalette.Add(new ColorMapping { Key = "Yellow", Color = Colors.LightYellow }); indicatorColorPalette.Add(new ColorMapping { Key = "Green", Color = Colors.LightGreen }); Kanban.IndicatorColorPalette = indicatorColorPalette; Kanban.Columns.Add(new KanbanColumn { Categories = "Open", Title = "To Do" }); Kanban.Columns.Add(new KanbanColumn { Categories = "In Progress", Title = "In Progress" }); Kanban.Columns.Add(new KanbanColumn { Categories = "Waiting", Title = "Waiting for Others" }); if (Host.Settings.StatusSettings.IncludeCompleted) Kanban.Columns.Add(new KanbanColumn { Categories = "Complete", Title = "Completed" }); Kanban.InvalidateVisual(); foreach (var column in Kanban.Columns) { var menu = new ContextMenu(); menu.Tag = column; var item = new MenuItem { Header = "New Task" }; item.Click += CreateTask; menu.Items.Add(item); menu.Items.Add(new Separator()); item = new MenuItem { Header = "Select All " + column.Title + " Tasks", Tag = column }; item.Click += SelectAll_Click; menu.Items.Add(item); item = new MenuItem { Header = "Unselect All " + column.Title + " Tasks", Tag = column }; item.Click += UnSelectAll_Click; menu.Items.Add(item); column.ContextMenu = menu; } Kanban.ColumnWidth = Kanban.ActualWidth / Kanban.Columns.Count - 1.0F; } private void SetupData() { var query = new MultiQuery(); query.Add( null, new Columns(x => x.ID, x => x.Name, x => x.Thumbnail.ID, x => x.CanAllocateTasks, x => x.Email, x => x.Mobile, x => x.FinishDate, x => x.UserLink.ID), new SortOrder(x => x.Name) ); if (ClientFactory.IsSupported()) query.Add( new Filter(x => x.Hidden).IsEqualTo(false), new Columns(x => x.ID, x => x.Description), new SortOrder(x => x.Description) ); query.Query(); _employees = query.Get(); _types = ClientFactory.IsSupported() ? query.Get() : null; } #endregion #region Refresh / Reload private Filter GetSearchFilter(Expression> expression) where T : Entity, new() { Filter result = null; var comps = searchtext.Trim().Split(' '); foreach (var comp in comps) result = result == null ? new Filter(expression).Contains(comp) : result.And(expression).Contains(comp); return result; } private Filter GetKanbanSubscriberFilter() { var filter = new Filter(x => x.Kanban.Closed).IsEqualTo(DateTime.MinValue); if (Host.ParentID != Guid.Empty) filter = filter.And(x => x.Kanban.JobLink.ID).IsEqualTo(Host.ParentID); // All Tasks (EmployeeID.HasValue == false) or Unallocated (EmployeeID = Guid.Empty) are retrieved directly from the Kanban Table // so if we are here, we can assume that we are pulling subscriber data var empfilter = new Filter(x => x.Employee.ID).IsEqualTo(EmployeeID); filter.Ands.Add(empfilter); if (EmployeeID != MyID) filter = filter.And(x => x.Kanban.Private).IsEqualTo(false); //if (!includeobserved) // filter = filter.And(new Filter(x => x.Assignee).IsEqualTo(true).Or(x => x.Manager).IsEqualTo(true)); //if (!includecompleted) // filter = filter.And(x => x.Kanban.Completed).IsEqualTo(DateTime.MinValue); //if (selectedtype != CoreUtils.FullGuid) // filter = filter.And(x => x.Kanban.Type.ID).IsEqualTo(selectedtype); if (!string.IsNullOrWhiteSpace(searchtext)) { var search = GetSearchFilter(x => x.Kanban.JobLink.Name); search.Ors.Add(GetSearchFilter(x => x.Kanban.JobLink.JobNumber)); search.Ors.Add(GetSearchFilter(x => x.Kanban.Summary)); search.Ors.Add(GetSearchFilter(x => x.Kanban.Title)); search.Ors.Add(GetSearchFilter(x => x.Kanban.ManagerLink.Name)); search.Ors.Add(GetSearchFilter(x => x.Kanban.EmployeeLink.Name)); if (int.TryParse(searchtext.Trim(), out var tasknumber)) search.Ors.Add(new Filter(x => x.Kanban.Number).IsEqualTo(tasknumber)); filter.Ands.Add(search); } return filter; } private Filter GetKanbanFilter() { var filter = new Filter(x => x.Closed).IsEqualTo(DateTime.MinValue); if (Host.ParentID != Guid.Empty) filter = filter.And(x => x.JobLink.ID).IsEqualTo(Host.ParentID); if (EmployeeID != CoreUtils.FullGuid) { if (EmployeeID != Guid.Empty) { var empfilter = new Filter(x => x.EmployeeLink.ID).IsEqualTo(EmployeeID).Or(x => x.ManagerLink.ID).IsEqualTo(EmployeeID); filter.Ands.Add(empfilter); } else { filter = filter.And(x => x.EmployeeLink.ID).IsEqualTo(EmployeeID); } } if (EmployeeID != MyID) filter = filter.And(x => x.Private).IsEqualTo(false); //if (!includecompleted) // filter = filter.And(x => x.Completed).IsEqualTo(DateTime.MinValue); //if (selectedtype != CoreUtils.FullGuid) // filter = filter.And(x => x.Type.ID).IsEqualTo(selectedtype); return filter; } public void Refresh(bool resetselection) { Application.Current.Dispatcher.Invoke(() => { Mouse.OverrideCursor = Cursors.Wait; }); if (EmployeeID != CoreUtils.FullGuid && EmployeeID != Guid.Empty) { _kanbans = new Client().Query( GetKanbanSubscriberFilter(), new Columns ( 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.ManagerLink.ID, 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 ), new SortOrder(x => x.Kanban.DueDate) { Direction = SortDirection.Ascending } ); foreach (var column in _kanbans.Columns) column.ColumnName = column.ColumnName.Replace("Kanban.", ""); } else { _kanbans = new Client().Query( GetKanbanFilter(), new Columns ( x => x.ID, x => x.DueDate, x => x.Completed, //x => x.Description, x => x.Summary, x => x.Category, x => x.EmployeeLink.ID, x => x.ManagerLink.ID, x => x.Notes, x => x.Title, x => x.JobLink.ID, x => x.JobLink.JobNumber, x => x.JobLink.Name, x => x.Type.ID, x => x.Type.Code, x => x.Number, x => x.Attachments, x => x.Locked ), new SortOrder(x => x.DueDate) { Direction = SortDirection.Ascending } ); } ReloadKanbans(); Application.Current.Dispatcher.Invoke(() => { Mouse.OverrideCursor = null; }); } private void ReloadKanbans() { //SetupColumns(); //ResizeColumns(); _models = new ObservableCollection(); foreach (var row in _kanbans.Rows) try { var empid = row.Get(e => e.EmployeeLink.ID); var mgrid = row.EntityLinkID(x => x.ManagerLink) ?? Guid.Empty; var completed = row.Get(e => e.Completed); var locked = row.Get(e => e.Locked); var type = row.Get(e => e.Type.ID); var category = row.Get(x => x.Category); if (string.IsNullOrWhiteSpace(category)) category = "Open"; var bLockedOK = Host.Settings.StatusSettings.IncludeLocked || locked == false; var bObserveOK = EmployeeID == CoreUtils.FullGuid || Host.Settings.StatusSettings.IncludeObserved || empid == EmployeeID || mgrid == EmployeeID; var bCompleteOK = Host.Settings.StatusSettings.IncludeCompleted || completed.IsEmpty(); var bTypeOK = selectedtype == CoreUtils.FullGuid || type == selectedtype; if (bLockedOK && bCompleteOK && bObserveOK && bTypeOK) { var model = new TaskModel(); var EmployeeEntry = _employeelist.Where(x => x.ID.Equals(empid)).FirstOrDefault(); var empimg = EmployeeEntry?.Image; var ManagerEntry = _employeelist.Where(x => x.ID.Equals(mgrid)).FirstOrDefault(); //var description = row.Get(x => x.Summary); //if (String.IsNullOrWhiteSpace(description)) // description = String.Join("\r\n", row.Get(x => x.Notes)).Split(new String[] { "===============" }, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault(); //if (String.IsNullOrWhiteSpace(description)) // description = CoreUtils.StripHTML(row.Get(x => x.Description)); //if (String.IsNullOrWhiteSpace(description)) // description = ""; var job = row.Get(x => x.JobLink.JobNumber); model.Title = row.Get(x => x.Title); model.ID = row.Get(x => x.ID).ToString(); model.Description = row.Get(x => x.Summary) ?? ""; model.Category = category; var color = EmployeeID == Guid.Empty || empid == EmployeeID || EmployeeID == CoreUtils.FullGuid ? TaskModel.KanbanColor( row.Get(x => x.DueDate), row.Get(x => x.Completed)) : mgrid == EmployeeID ? Color.Silver : Color.Plum; if (row.Get(x => x.Locked)) color = color.MixColors(0.5F, Color.White); model.ColorKey = ImageUtils.ColorToString(color); model.Image = empimg; model.ImageURL = null; model.Attachments = row.Get(x => x.Attachments) > 0; // ? _attachimg : null; model.DueDate = row.Get(x => x.DueDate); model.CompletedDate = row.Get(x => x.Completed); model.Locked = row.Get(x => x.Locked); // ? _lockimg : null; var notes = new List> { new() }; if ((row.Get(x => x.Notes) != null)) { foreach (var line in row.Get(x => x.Notes)) { if (line == "===================================") { notes.Add(new()); } else { notes.Last().Add(line); } } model.Notes = string.Join("\n===================================\n", notes.Reverse>().Select(x => string.Join('\n', x))); } model.EmployeeID = empid; model.ManagerID = mgrid; var sEmp = ""; if (empid != EmployeeID) { if (!Entity.IsEntityLinkValid(x => x.EmployeeLink, row)) { sEmp = "Unallocated"; } else { var tuple = _employeelist.FirstOrDefault(x => x.ID.Equals(empid)); sEmp = tuple != null ? tuple.ID == MyID ? MyName : tuple.Name : ""; } } var sMgr = ""; if (mgrid != EmployeeID) if (mgrid != Guid.Empty) { var tuple = _employeelist.FirstOrDefault(x => x.ID.Equals(mgrid)); sMgr = tuple != null ? tuple.ID == MyID ? MyName : tuple.Name : ""; } if (!string.IsNullOrEmpty(sEmp)) { if (!string.IsNullOrWhiteSpace(sMgr) && !string.Equals(sMgr, sEmp)) model.AssignedTo = string.Format("Assigned to {0} by {1}", sEmp, sMgr); else model.AssignedTo = string.Format("Assigned to {0} ", sEmp); } else { if (!string.IsNullOrWhiteSpace(sMgr)) model.AssignedTo = string.Format("Allocated by {0} ", sMgr); } //model.AssignedTo = String.Format("M: {0} / E: {1}", sMgr, sEmp); model.JobID = row.Get(x => x.JobLink.ID); model.JobNumber = row.Get(x => x.JobLink.JobNumber); if (string.IsNullOrWhiteSpace(model.JobNumber)) model.JobNumber = ""; model.JobName = row.Get(x => x.JobLink.Name); model.Checked = CheckedKanbans.Contains(row.Get(x => x.ID).ToString()); model.Type = new KanbanType { ID = row.Get(x => x.Type.ID), Code = row.Get(x => x.Type.Code) }; model.Number = row.Get(x => x.Number); _models.Add(model); } } catch (Exception e) { Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace)); } StatusTasksHeaderTimeConverter.Tasks = _models; FilterKanbans(); } private void FilterKanbans() { Progress.ShowModal("Loading", (progress) => { Dispatcher.BeginInvoke(() => { Progress.Show("Loading"); }); if (JobFilterID == Guid.Empty) { var list = _models .Where(x => x.Search(Search.Text.Split())) .OrderBy(x => x.EmployeeID == EmployeeID ? 0 : 1).ThenBy(x => x.DueDate); Dispatcher.BeginInvoke(() => { Kanban.ItemsSource = list; }); } else { var list = _models .Where(x => x.Search(Search.Text.Split()) && x.JobSearch(JobFilterID)) .OrderBy(x => x.EmployeeID == EmployeeID ? 0 : 1).ThenBy(x => x.DueDate); Dispatcher.BeginInvoke(() => { Kanban.ItemsSource = list; }); } Task.Run(() => { Thread.Sleep(500); Dispatcher.BeginInvoke(() => { Progress.Close(); }); }); }); } #endregion #region Kanban Selection Stuff private void SelectColumn(KanbanColumn column, bool selected) { CheckedKanbans.Clear(); if (selected) { CheckedKanbans.AddRange(_models.Where(x => Equals(x.Category, column.Categories)).Select(x => x.ID)); foreach (var model in _models) model.Checked = Equals(model.Category, column.Categories); } FilterKanbans(); } private void UnSelectAll_Click(object sender, RoutedEventArgs e) { var column = ((MenuItem)sender).Tag as KanbanColumn; SelectColumn(column, false); } private void SelectAll_Click(object sender, RoutedEventArgs e) { var column = ((MenuItem)sender).Tag as KanbanColumn; SelectColumn(column, true); } //private IEnumerable GetSelectedKanbanIDs(String currentid) //{ // List result = new List(); // if (!CheckedKanbans.Contains(currentid)) // result.Add(Guid.Parse(currentid)); // CheckedKanbans.ForEach((id) => result.Add(Guid.Parse(id))); // return result; //} //private Kanban[] GetSelectedKanbans(String currentid) //{ // var ids = GetSelectedKanbanIDs(currentid); // return Host.LoadKanbans(ids).ToArray(); //} private void CheckBox_Checked(object sender, RoutedEventArgs e) { var task = ((CheckBox)sender).Tag as TaskModel; if (task == null) return; if (CheckedKanbans.Contains(task.ID)) CheckedKanbans.Remove(task.ID); else CheckedKanbans.Add(task.ID); } #endregion #region Context Menu Actions private void CreateTask(object sender, RoutedEventArgs e) { CreateKanban(); } 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 EditTask_Click(object sender, RoutedEventArgs e) { var task = ((MenuItem)e.Source).Tag as TaskModel; DoEdit(task); e.Handled = true; } //private void CreateSetout_Click(object sender, RoutedEventArgs e) //{ // MenuItem menu = sender as MenuItem; // TaskModel task = menu.Tag as TaskModel; // if (task.JobID.Equals(Guid.Empty)) // { // MessageBox.Show("Please link this task to a job before creating a setout!"); // return; // } // if (MessageBox.Show("This will convert this task into a Setout.\n\nDo you wish to continue?", "Confirmation", MessageBoxButton.YesNo) != MessageBoxResult.Yes) // return; // ManufacturingTemplate template = new Client().Load(new Filter(x => x.Code).IsEqualTo("PRS")).FirstOrDefault(); // if (template == null) // { // MessageBox.Show("[Pressing] Template does not exist!"); // return; // } // String setoutnumber = ""; // Progress.ShowModal("Creating Setout", (progress) => // { // MultiQuery query = new MultiQuery(); // query.Add( // new Filter(x => x.Template.ID).IsEqualTo(template.ID), // null, // new SortOrder(x => x.Sequence) // ); // query.Add( // new Filter(x => x.ID).IsEqualTo(task.ID), // null, // null // ); // query.Query(); // ManufacturingTemplateStage[] tstages = query.Get().Rows.Select(x => x.ToObject()).ToArray(); // Kanban kanban = query.Get().Rows.FirstOrDefault()?.ToObject(); // progress.Report("Creating Setouts"); // CoreTable setouts = new Client().Query( // new Filter(x => x.JobLink.ID).IsEqualTo(kanban.JobLink.ID), // new Columns(x => x.JobLink.JobNumber, x => x.Number), // null // ); // int ireq = 0; // String sreq = ""; // while (true) // { // ireq++; // sreq = String.Format("{0}-{1:yyMMdd}-{2}", kanban.JobLink.JobNumber, DateTime.Now, ireq); // if (!setouts.Rows.Any(r => sreq.Equals(r.Get(c => c.Number)))) // break; // } // Setout setout = new Setout(); // setout.Number = sreq; // setout.JobLink.ID = kanban.JobLink.ID; // = new Client().Load(new Filter(x => x.ID).IsEqualTo(kanban.JobLink.ID)).FirstOrDefault(); // setout.Reference = kanban.Title; // var notes = kanban.Notes.ToList(); // var description = kanban.Summary; // if (String.IsNullOrWhiteSpace(description)) // description = CoreUtils.StripHTML(kanban.Description); // if (!String.IsNullOrWhiteSpace(description)) // notes.Insert(0, description); // setout.Description = String.Join("\n==========================================\n", notes); // new Client().Save(setout, "Created from Task"); // setoutnumber = setout.Number; // progress.Report("Creating Manufacturing Packet"); // ManufacturingPacket packet = new ManufacturingPacket() // { // Group = template.Factory.Name, // Serial = template.Code, // Title = kanban.Title, // Quantity = 1, // BarcodeQty = 1, // DueDate = kanban.DueDate // }; // packet.SetoutLink.ID = setout.ID; // //packet.JobLink.ID = setout.JobLink.ID; // packet.ManufacturingTemplateLink.ID = template.ID; // packet.ManufacturingTemplateLink.Code = template.Code; // new Client().Save(packet, "Created from Task"); // List pstages = new List(); // foreach (var tstage in tstages) // { // var pstage = new ManufacturingPacketStage() // { // Time = tstage.Time, // Sequence = tstage.Sequence, // SequenceType = tstage.SequenceType, // Started = DateTime.MinValue, // PercentageComplete = 0.0F, // Completed = DateTime.MinValue, // QualityChecks = tstage.QualityChecks, // QualityStatus = QualityStatus.NotChecked, // QualityNotes = "", // }; // pstage.Parent.ID = packet.ID; // pstage.ManufacturingSectionLink.ID = tstage.Section.ID; // pstage.ManufacturingSectionLink.Name = tstage.Section.Name; // pstages.Add(pstage); // } // new Client().Save(pstages, "Created from Task", (_, __) => { }); // progress.Report("Processing Documents"); // List _setoutdocuments = new List(); // List _kanbandocuments = new List(); // KanbanDocument[] docrefs = new Client().Load(new Filter(x => x.EntityLink.ID).IsEqualTo(kanban.ID)); // foreach (var docref in docrefs) // { // Guid docid = ProcessSetoutDocument(docref); // var newdoc = new SetoutDocument(); // newdoc.EntityLink.ID = setout.ID; // newdoc.DocumentLink.ID = docid; // _setoutdocuments.Add(newdoc); // if (docid != docref.DocumentLink.ID) // { // docref.DocumentLink.ID = docid; // _kanbandocuments.Add(docref); // } // } // new Client().Save(_setoutdocuments, "Converted from Task", (_, __) => { }); // new Client().Save(_kanbandocuments, "Converted to PDF", (_, __) => { }); // SetoutKanban link = new SetoutKanban(); // link.Entity.ID = setout.ID; // link.Kanban.ID = kanban.ID; // new Client().Save(link, "Converting Task -> Setout", (_, __) => { }); // progress.Report("Updating Task"); // kanban.Title = kanban.Title + " (" + setoutnumber + ")"; // kanban.Locked = true; // new Client().Save(kanban, "Converting Kanban to Setout"); // }); // MessageBox.Show(String.Format("Created Setout {0}", setoutnumber)); // Refresh(); //} //private Guid ProcessSetoutDocument(KanbanDocument docref) //{ // Guid result = docref.DocumentLink.ID; // String ext = System.IO.Path.GetExtension(docref.DocumentLink.FileName).ToLower(); // if (ext.EndsWith("txt")) // { // var doc = new Client().Load(new Filter(x => x.ID).IsEqualTo(docref.DocumentLink.ID)).FirstOrDefault(); // PdfDocument pdf = new PdfDocument(); // PdfPage page = pdf.Pages.Add(); // PdfGraphics graphics = page.Graphics; // PdfFont font = new PdfStandardFont(PdfFontFamily.Courier, 12); // String text = System.Text.Encoding.UTF8.GetString(doc.Data); // graphics.DrawString(text, font, PdfBrushes.Black, new PointF(0, 0)); // MemoryStream ms = new MemoryStream(); // pdf.Save(ms); // pdf.Close(true); // byte[] data = ms.ToArray(); // var newdoc = new Document() // { // Data = data, // FileName = System.IO.Path.ChangeExtension(docref.DocumentLink.FileName, "pdf"), // CRC = CoreUtils.CalculateCRC(data), // TimeStamp = DateTime.Now, // }; // new Client().Save(newdoc, "Converted from Text"); // return newdoc.ID; // } // else if (ext.EndsWith("png") || ext.EndsWith("bmp") || ext.EndsWith("jpg") || ext.EndsWith("jpeg")) // { // var doc = new Client().Load(new Filter(x => x.ID).IsEqualTo(docref.DocumentLink.ID)).FirstOrDefault(); // PdfBitmap image = new PdfBitmap(new MemoryStream(doc.Data)); // PdfDocument pdf = new PdfDocument(); // pdf.PageSettings.Orientation = image.Height > image.Width ? PdfPageOrientation.Portrait : PdfPageOrientation.Landscape; // pdf.PageSettings.Size = new SizeF(image.Width, image.Height); // PdfPage page = pdf.Pages.Add(); // PdfGraphics graphics = page.Graphics; // graphics.DrawImage(image, 0.0F, 0.0F); // MemoryStream ms = new MemoryStream(); // pdf.Save(ms); // pdf.Close(true); // byte[] data = ms.ToArray(); // var newdoc = new Document() // { // Data = data, // FileName = System.IO.Path.ChangeExtension(docref.DocumentLink.FileName, "pdf"), // CRC = CoreUtils.CalculateCRC(data), // TimeStamp = DateTime.Now, // }; // new Client().Save(newdoc, "Converted from Image"); // return newdoc.ID; // } // return result; //} //private void CreateRequisition_Click(object sender, RoutedEventArgs e) //{ // MenuItem menu = sender as MenuItem; // TaskModel task = menu.Tag as TaskModel; // if (task.JobID.Equals(Guid.Empty)) // { // MessageBox.Show("Please link this task to a job before creating a requisition!"); // return; // } // if (MessageBox.Show("This will convert this task into a Requisition.\n\nDo you wish to continue?", "Confirmation", MessageBoxButton.YesNo) != MessageBoxResult.Yes) // return; // int requinumber = 0; // Progress.ShowModal("Creating Requisition", (progress) => // { // Kanban kanban = new Client().Load(new Filter(x => x.ID).IsEqualTo(task.ID)).FirstOrDefault(); // Requisition requi = new Requisition(); // requi.JobLink.ID = kanban.JobLink.ID; // requi.RequestedBy.ID = kanban.ManagerLink.ID; // requi.Employee.ID = Guid.Empty; // requi.Title = kanban.Title; // requi.Request = String.IsNullOrWhiteSpace(kanban.Summary) // ? String.IsNullOrWhiteSpace(kanban.Summary) // ? String.Join("\n", kanban.Notes) // : CoreUtils.StripHTML(kanban.Description) // : kanban.Summary; // requi.Notes = kanban.Notes; // requi.Due = kanban.DueDate; // new Client().Save(requi, "Created from Task"); // requinumber = requi.Number; // progress.Report("Updating Documents"); // List _documents = new List(); // KanbanDocument[] documents = new Client().Load(new Filter(x => x.EntityLink.ID).IsEqualTo(kanban.ID)); // foreach (var document in documents) // { // var newdoc = new RequisitionDocument(); // newdoc.EntityLink.ID = requi.ID; // newdoc.DocumentLink.ID = document.DocumentLink.ID; // _documents.Add(newdoc); // } // new Client().Save(_documents, "Converted from Task", (_, __) => { }); // RequisitionKanban link = new RequisitionKanban(); // link.Entity.ID = requi.ID; // link.Kanban.ID = kanban.ID; // new Client().Save(link, "Converting Task -> Requisition", (_, __) => { }); // progress.Report("Updating Task"); // kanban.Category = "Open"; // kanban.Completed = DateTime.MinValue; // kanban.Locked = true; // kanban.Title = kanban.Title + " (Requi #" + requi.Number.ToString() + ")"; // new Client().Save(kanban, "Converted to Requisition", (_, __) => { }); // }); // MessageBox.Show(String.Format("Created Requisition {0}", requinumber)); // Refresh(); //} //private void CreatePurchaseOrder_Click(object sender, RoutedEventArgs e) //{ // MenuItem menu = sender as MenuItem; // TaskModel task = menu.Tag as TaskModel; // if (MessageBox.Show("This will convert this task into a Purchase Order.\n\nDo you wish to continue?", "Confirmation", MessageBoxButton.YesNo) == MessageBoxResult.Yes) // { // String ponumber = ""; // Progress.ShowModal("Creating Purchase Order", (progress) => // { // Kanban kanban = new Client().Load(new Filter(x => x.ID).IsEqualTo(task.ID)).FirstOrDefault(); // PurchaseOrder order = new PurchaseOrder(); // order.Notes = kanban.Summary; // order.RaisedBy.ID = kanban.EmployeeLink.ID; // new Client().Save(order, "Created from Task Screen"); // ponumber = order.PONumber; // progress.Report("Updating Documents"); // List docs = new List(); // var taskdocs = new Client().Load(new Filter(x => x.EntityLink.ID).IsEqualTo(Guid.Parse(task.ID))); // foreach (var taskdoc in taskdocs) // { // PurchaseOrderDocument doc = new PurchaseOrderDocument(); // doc.DocumentLink.ID = taskdoc.DocumentLink.ID; // doc.EntityLink.ID = order.ID; // docs.Add(doc); // } // new Client().Save(docs, "", (_, __) => { }); // progress.Report("Creating Links"); // PurchaseOrderKanban link = new PurchaseOrderKanban(); // link.Entity.ID = order.ID; // link.Kanban.ID = kanban.ID; // new Client().Save(link, "Converting Task -> Purchase Order", (_, __) => { }); // progress.Report("Updating Task"); // kanban.Category = "Open"; // kanban.Completed = DateTime.MinValue; // kanban.Locked = true; // kanban.Title = "(PO#" + order.PONumber.ToString() + ") " + kanban.Title; // new Client().Save(kanban, "Converted to Purchase Order", (_, __) => { }); // }); // MessageBox.Show(String.Format("Created Purchase Order {0}", ponumber)); // Refresh(); // } //} //private void CreateDelivery_Click(object sender, RoutedEventArgs e) //{ // MenuItem menu = sender as MenuItem; // TaskModel task = menu.Tag as TaskModel; // if (MessageBox.Show("This will convert this task into a Delivery.\n\nDo you wish to continue?", "Confirmation", MessageBoxButton.YesNo) != MessageBoxResult.Yes) // return; // int deliverynumber = 0; // Progress.ShowModal("Creating Delivery", (progress) => // { // Kanban kanban = new Client().Query(new Filter(x => x.ID).IsEqualTo(task.ID)).Rows.FirstOrDefault()?.ToObject(); // Delivery delivery = new Delivery(); // delivery.Due = kanban.DueDate; // delivery.Job.ID = kanban.JobLink.ID; // delivery.Job.Synchronise(kanban.JobLink); // delivery.Notes = kanban.Summary; // delivery.Employee.ID = kanban.ManagerLink.ID; // delivery.Employee.Synchronise(kanban.ManagerLink); // new Client().Save(delivery, "Created From Task"); // deliverynumber = delivery.Number; // progress.Report("Updating Documents"); // List docs = new List(); // var taskdocs = new Client().Load(new Filter(x => x.EntityLink.ID).IsEqualTo(Guid.Parse(task.ID))); // foreach (var taskdoc in taskdocs) // { // DeliveryDocument doc = new DeliveryDocument(); // doc.DocumentLink.ID = taskdoc.DocumentLink.ID; // doc.EntityLink.ID = delivery.ID; // docs.Add(doc); // } // new Client().Save(docs, "", (_, __) => { }); // progress.Report("Creating Links"); // DeliveryKanban link = new DeliveryKanban(); // link.Entity.ID = delivery.ID; // link.Kanban.ID = kanban.ID; // new Client().Save(link, "Converting Task -> Delivery", (_, __) => { }); // progress.Report("Updating Task"); // kanban.Category = "Open"; // kanban.Completed = DateTime.MinValue; // kanban.Locked = true; // kanban.Title = "(Del#" + delivery.Number.ToString() + ") " + kanban.Title; // new Client().Save(kanban, "Converted to Delivery", (_, __) => { }); // }); // MessageBox.Show(String.Format("Created Delivery {0}", deliverynumber)); // Refresh(); //} //private void CloseTask_Click(object sender, RoutedEventArgs e) //{ // if (MessageBox.Show("Are you sure you want to remove the selected tasks from the list?", "Confirm removal", MessageBoxButton.YesNo) != MessageBoxResult.Yes) // return; // Progress.ShowModal("Closing Kanbans", (progress) => // { // TaskModel task = ((MenuItem)e.Source).Tag as TaskModel; // Kanban[] kanbans = GetSelectedKanbans(task.ID); // for (int i = 0; i < kanbans.Length; i++) // { // Kanban kanban = kanbans[i]; // kanban.Closed = DateTime.Now; // } // new Client().Save(kanbans, "Kanban Marked as Closed"); // CheckedKanbans.Clear(); // }); // Refresh(); //} //private void EmailTask_Click(object sender, RoutedEventArgs e) //{ // MenuItem menu = sender as MenuItem; // TaskModel task = menu.Tag as TaskModel; // Kanban kanban = new Client().Load(new Filter(x => x.ID).IsEqualTo(task.ID)).FirstOrDefault(); // List to = new List(); // String from = ""; // String salutation = ""; // if (MyID.HasValue) // { // CoreRow me = _employees.Rows.FirstOrDefault(r => r.Get(c => c.ID).Equals(MyID)); // if (me != null) // from = me.Get(c => c.Name).Split(' ').FirstOrDefault(); // if (kanban.EmployeeLink.ID != MyID.Value) // { // CoreRow emp = _employees.Rows.FirstOrDefault(r => r.Get(c => c.ID).Equals(kanban.EmployeeLink.ID)); // if (emp != null) // { // String email = emp.Get(c => c.Email); // if (!string.IsNullOrEmpty(email)) // { // to.Add(email); // String name = emp.Get(c => c.Name).Split(' ').FirstOrDefault(); // salutation = salutation + (String.IsNullOrEmpty(salutation) ? "Hi " : " and ") + name; // } // } // } // if (kanban.ManagerLink.ID != MyID.Value) // { // CoreRow emp = _employees.Rows.FirstOrDefault(r => r.Get(c => c.ID).Equals(kanban.ManagerLink.ID)); // if (emp != null) // { // String email = emp.Get(c => c.Email); // if (!string.IsNullOrEmpty(email)) // { // to.Add(email); // String name = emp.Get(c => c.Name).Split(' ').FirstOrDefault(); // salutation = salutation + (String.IsNullOrEmpty(salutation) ? "Hi " : " and ") + name; // } // } // } // } // Outlook.Application outlookApp = new Outlook.Application(); // Outlook.MailItem mailItem = (Outlook.MailItem)outlookApp.CreateItem(Outlook.OlItemType.olMailItem); // mailItem.Subject = "PRS Task: " + kanban.Title; // mailItem.To = String.Join("; ", to); // mailItem.HTMLBody = String.Format("{0},

Please see the above task in PRS.

Regards,

{1}

Task Description:
{2}

Additional Notes:
{3}", salutation, from, CoreUtils.StripHTML(kanban.Description), String.Join("\r\n", kanban.Notes)); // //mailItem.Attachments.Add(filename, Outlook.OlAttachmentType.olByValue, Type.Missing, Type.Missing); // mailItem.Display(false); //} //private void CompleteTask_Click(object sender, RoutedEventArgs e) //{ // if (MessageBox.Show("Are you sure you want to mark the selected tasks as complete?", "Confirm Completion", MessageBoxButton.YesNo) != MessageBoxResult.Yes) // return; // TaskModel task = ((MenuItem)e.Source).Tag as TaskModel; // Progress.ShowModal("Completing Task", (progress) => // { // Kanban[] kanbans = GetSelectedKanbans(task.ID); // for (int i = 0; i < kanbans.Length; i++) // { // Kanban kanban = kanbans[i]; // kanban.Completed = DateTime.Now; // kanban.Category = "Complete"; // } // new Client().Save(kanbans, "Kanban Marked as Completed"); // CheckedKanbans.Clear(); // }); // Refresh(); //} #endregion #region Kanban Creation / Editing public void CreateKanban() { var result = Host.CreateKanban( kanban => { kanban.EmployeeLink.ID = EmployeeID != CoreUtils.FullGuid ? EmployeeID : MyID.Value; kanban.ManagerLink.ID = MyID.Value; kanban.ManagerLink.UserLink.ID = ClientFactory.UserGuid; }); if (result != null) Refresh(true); } private void DoEdit(TaskModel task) { if (task == null) return; var result = Host.EditReferences(new[] { task }); if (result) Refresh(true); } #endregion private void TaskTypesLabel_OnClick(object sender, RoutedEventArgs e) { var list = new MasterList(typeof(KanbanType)); list.ShowDialog(); SetupKanbanTypesLookup(true); } private void JobFilterBtn_OnClick(object sender, RoutedEventArgs e) { if (JobFilterID != Guid.Empty) { JobFilterBtn.Content = "Filter Job"; JobFilterID = Guid.Empty; FilterKanbans(); return; } var window = new ThemableWindow(); var grid = new JobGrid(); grid.Options.Remove(DynamicGridOption.EditRows); grid.Options.Remove(DynamicGridOption.DeleteRows); grid.Options.Remove(DynamicGridOption.AddRows); grid.Options.Remove(DynamicGridOption.MultiSelect); grid.Options.Remove(DynamicGridOption.ExportData); grid.Options.Remove(DynamicGridOption.ImportData); grid.OnSelectItem += (object sender, DynamicGridSelectionEventArgs e) => { if ((sender as JobGrid).SelectedRows.Count() == 0) return; else { var item = (sender as JobGrid).SelectedRows[0]; AddJobFilter(item); window.Close(); } }; grid.Refresh(true, true); window.Content = grid; window.ShowDialog(); } Guid JobFilterID = Guid.Empty; private void AddJobFilter(CoreRow item) { JobFilterID = item.Get(x => x.ID); JobFilterBtn.Content = item.Get(x => x.JobNumber) + " (click to cancel)"; FilterKanbans(); } } }