using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using Comal.Classes; using InABox.Clients; using InABox.Core; using InABox.WPF; using PRSDesktop.WidgetGroups; using Syncfusion.UI.Xaml.Charts; namespace PRSDesktop { public class UserActivityDashboardProperties : IDashboardProperties { } public class UserActivityDashboardElement : DashboardElement { } /// /// Interaction logic for DatabaseActivityDashboard.xaml /// public partial class UserActivity : UserControl, IPanel, IDashboardWidget { public enum HistoryView { Day, Week, Month, Year } private CoreTable _employees; private int _selected = -1; private readonly BitmapImage back = PRSDesktop.Resources.back.AsBitmapImage(32, 32); private HistoryViewModel history; private readonly BitmapImage next = PRSDesktop.Resources.next.AsBitmapImage(32, 32); public UserActivity() { InitializeComponent(); PrevDay.Content = new Image { Source = back }; NextDay.Content = new Image { Source = next }; } public bool IsReady { get; set; } public void CreateToolbarButtons(IPanelHost host) { } public string SectionName => "User Activity"; public UserActivityDashboardProperties Properties { get; set; } public DataModel DataModel(Selection selection) { return new UserActivityDataModel(history.Summary); } public void Refresh() { if (history.To == DateTime.MinValue) history.To = DateTime.Today; if (history.View == HistoryView.Day) CurrentDate.Text = string.Format("{0:ddd, dd MMMM yyyy}", history.To); else CurrentDate.Text = string.Format("{0:dd MMM yy} - {1:dd MMM yy}", history.From, history.To); // Only creating two series active & inactive var colortable = typeof(Colors).GetProperties(BindingFlags.Static | BindingFlags.Public).Where(x => x.PropertyType == typeof(Color)) .ToArray(); Hours.Series.Clear(); var series = new StackingColumnSeries(); series.ItemsSource = history.Summary; series.XBindingPath = "Name"; series.YBindingPath = "Active"; series.Label = "Active"; series.Interior = new SolidColorBrush(Colors.LightSalmon); series.SeriesSelectionBrush = new SolidColorBrush(Colors.Salmon); Hours.Series.Add(series); series = new StackingColumnSeries(); series.ItemsSource = history.Summary; series.XBindingPath = "Name"; series.YBindingPath = "Idle"; series.Label = "Idle"; series.Interior = new SolidColorBrush(Colors.LightSteelBlue); series.SeriesSelectionBrush = new SolidColorBrush(Colors.SteelBlue); Hours.Series.Add(series); var axis = Hours.SecondaryAxis as NumericalAxis; axis.Maximum = history.MaxMalue(5.0F); } public Dictionary Selected() { return new Dictionary(); } public void Setup() { history = new HistoryViewModel(); DataContext = history; var grplookups = new Dictionary(); //Dictionary emplookups = new Dictionary() { { Guid.Empty, "All Staff" } }; _employees = new Client().Query( LookupFactory.DefineFilter(), new Columns( x => x.ID, x => x.UserLink.ID, x => x.Name, x => x.Group.ID, x => x.Group.Description ), new SortOrder(x => x.Name) ); foreach (var row in _employees.Rows) { var grpid = row.Get(x => x.Group.ID); var grpname = row.Get(x => x.Group.Description); if (string.IsNullOrEmpty(grpname)) grpname = "(No Group Assigned)"; if (!grplookups.ContainsKey(grpid)) grplookups[grpid] = grpname; //emplookups[row.Get(x => x.UserLink.ID)] = row.Get(x => x.Name); } var groups = grplookups.ToList(); groups.Sort((pair1, pair2) => pair1.Value.CompareTo(pair2.Value)); groups.Insert(0, new KeyValuePair(CoreUtils.FullGuid, "All Groups")); GroupView.ItemsSource = groups; //StaffView.ItemsSource = emplookups; //LoadCategories(Guid.Empty); Hours.Legend = new ChartLegend { LegendPosition = LegendPosition.Outside, DockPosition = ChartDock.Right, FontSize = 11, Width = 100 //ItemsPanel = Hours.Resources["itemPanelTemplate"] as ItemsPanelTemplate }; } public void Shutdown() { } public event DataModelUpdateEvent OnUpdateDataModel; public void Heartbeat(TimeSpan time) { // Nothing to do here } private bool HasData(List history) { foreach (var record in history) { var hasdata = record.Active + record.Idle > 0.0F; if (hasdata) return true; } return false; } private void LoadCategories(Guid userid) { history.Categories.Clear(); if (userid.Equals(Guid.Empty)) { foreach (var row in _employees.Rows) if (GroupView.SelectedValue.Equals(CoreUtils.FullGuid) || row.Get(x => x.Group.ID).Equals(GroupView.SelectedValue)) history.Categories[row.Get(x => x.UserLink.ID).ToString()] = row.Get(x => x.Name); } else { foreach (var module in Modules.All.OrderBy(x => x)) history.Categories[module] = module; } } private void GroupView_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (history == null) return; if (e.AddedItems.Count > 0) { var id = ((KeyValuePair)e.AddedItems[0]).Key; var curhistory = history; history = null; var emplookups = new Dictionary { { Guid.Empty, "All Staff" } }; foreach (var row in _employees.Rows) { var grpid = row.Get(x => x.Group.ID); if (id.Equals(CoreUtils.FullGuid) || grpid.Equals(id)) emplookups[row.Get(x => x.UserLink.ID)] = row.Get(x => x.Name); } StaffView.ItemsSource = null; history = curhistory; StaffView.ItemsSource = emplookups; if (!Guid.Empty.Equals(StaffView.SelectedValue)) StaffView.SelectedValue = Guid.Empty; } } private void StaffView_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (history == null) return; if (e.AddedItems.Count > 0) { var id = ((KeyValuePair)e.AddedItems[0]).Key; LoadCategories(id); history.UserID = id; Refresh(); ShowAll.Width = id != Guid.Empty ? new GridLength(70) : new GridLength(0); } } private void ViewStyle_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (history == null) return; history.View = ViewStyle.SelectedIndex == 0 ? HistoryView.Day : ViewStyle.SelectedIndex == 1 ? HistoryView.Week : ViewStyle.SelectedIndex == 2 ? HistoryView.Month : HistoryView.Year; Refresh(); } private void Search_KeyUp(object sender, KeyEventArgs e) { if (string.IsNullOrWhiteSpace(Search.Text) || e.Key == Key.Return) { history.Search = Search.Text; Refresh(); } } private void PrevDay_Click(object sender, RoutedEventArgs e) { history.Back(); Refresh(); } private void CurrentDate_MouseDoubleClick(object sender, MouseButtonEventArgs e) { history.To = DateTime.Today; Refresh(); } private void NextDay_Click(object sender, RoutedEventArgs e) { history.Forward(); Refresh(); } private void Export_Click(object sender, RoutedEventArgs e) { } private void Hours_SelectionChanged(object sender, ChartSelectionChangedEventArgs e) { if (e.IsDataPointSelection) { if (history.UserID == Guid.Empty && e.SelectedIndex == -1 && _selected > -1) { var emps = StaffView.ItemsSource as Dictionary; var id = emps.Keys.ElementAt(_selected + 1); LoadCategories(id); StaffView.SelectedValue = id; } _selected = e.SelectedIndex; } } private void ShowAll_Click(object sender, RoutedEventArgs e) { StaffView.SelectedValue = Guid.Empty; } // Either: // - Person + Time Spent on any module // - Module + Time Spent in Specific Module public class History { public string Key { get; set; } public string Name { get; set; } public double Active { get; set; } public double Idle { get; set; } } public class HistoryViewModel { private string _search = ""; private DateTime _to = DateTime.MinValue; private Guid _userid = Guid.Empty; private HistoryView _view = HistoryView.Day; public HistoryViewModel() { Categories = new Dictionary(); Summary = new List(); To = DateTime.Today; } public Guid UserID { get => _userid; set { _userid = value; Refresh(); } } public HistoryView View { get => _view; set { _view = value; Refresh(); } } public DateTime To { get => _to.Date; set { _to = value; Refresh(); } } public DateTime From => _view.Equals(HistoryView.Day) ? _to : _view.Equals(HistoryView.Week) ? _to.AddDays(-6) : _view.Equals(HistoryView.Month) ? _to.AddMonths(-1).AddDays(1) : _to.AddYears(-1).AddDays(1); public Dictionary Categories { get; } public List Summary { get; set; } public string Search { get => _search; set { _search = value; Refresh(); } } public void Forward() { To = _view.Equals(HistoryView.Day) ? _to.AddDays(1) : _view.Equals(HistoryView.Week) ? _to.AddDays(7) : _view.Equals(HistoryView.Month) ? _to.AddMonths(1) : _to.AddYears(1); } public void Back() { To = _view.Equals(HistoryView.Day) ? _to.AddDays(-1) : _view.Equals(HistoryView.Week) ? _to.AddDays(-7) : _view.Equals(HistoryView.Month) ? _to.AddMonths(-1) : _to.AddYears(-1); } private void AddSearchCriteria(Filter filter, string search, params Expression>[] expressions) { var comps = search.Trim().Split(' '); foreach (var comp in comps) { Filter result = null; foreach (var expression in expressions) result = result == null ? new Filter(expression).Contains(comp) : result.Or(expression).Contains(comp); filter.Ands.Add(result); } } private void UpdateHistory(CoreRow row) { var category = ""; if (_userid.Equals(Guid.Empty)) category = row.Get(x => x.User.ID).ToString(); else category = row.Get(x => x.Module); var record = Summary.FirstOrDefault(x => x.Key.Equals(category)); if (record != null) { record.Active += row.Get(x => x.ActiveTime).TotalHours; record.Idle += row.Get(x => x.IdleTime).TotalHours; } } public Filter GetFilter() { var from = _view.Equals(HistoryView.Day) ? _to.AddDays(-1) : _view.Equals(HistoryView.Week) ? _to.AddDays(-7) : _view.Equals(HistoryView.Month) ? _to.AddMonths(-1) : _to.AddYears(-1); var criteria = new Filter(x => x.Date).IsGreaterThan(from).And(x => x.Date).IsLessThanOrEqualTo(_to); if (!_userid.Equals(Guid.Empty)) criteria = criteria.And(x => x.User.ID).IsEqualTo(_userid); if (!string.IsNullOrWhiteSpace(_search)) criteria = criteria.TextSearch( Search, x => x.User.UserID, x => x.Module ); return criteria; } private void Refresh() { var criteria = GetFilter(); var data = new Client().Query( criteria, null, new SortOrder(x => x.User.UserID) ); Summary.Clear(); foreach (var key in Categories.Keys) Summary.Add(new History { Key = key, Name = Categories[key] }); foreach (var row in data.Rows) UpdateHistory(row); } public double MaxMalue(double min) { var result = min; foreach (var history in Summary) if (history.Active + history.Idle > result) result = history.Active + history.Idle; return Math.Truncate(result + 1.0F); } } } }