From ee1f54675e542ea4734ffc7eed6c6df80d8063c3 Mon Sep 17 00:00:00 2001 From: Meik Date: Wed, 28 Jan 2026 12:08:39 +0100 Subject: [PATCH] aktueller Stand --- 2026-01-28 10_49_55-.png | Bin 0 -> 6511 bytes F4SD-PhoneMonitor/F4SD-PhoneMonitor.csproj | 2 +- F4SD-PhoneMonitor/packages.config | 2 +- .../Sevices/SupportCase/SupportCaseTest.cs | 87 + .../F4SD.Cockpit.Client.Test.csproj | 2 +- .../F4SD-Cockpit-Client-Base.csproj | 49 +- .../FasdCockpitCommunicationBase.cs | 5 +- FasdCockpitBase/app.config | 11 + FasdCockpitBase/packages.config | 13 +- .../F4SD-Cockpit-Client-Communication.csproj | 16 +- .../FasdCockpitCommunicationWeb.cs | 120 +- .../TicketOverviewCountsResponse.cs | 48 + FasdCockpitCommunication/app.config | 11 + FasdCockpitCommunication/packages.config | 2 +- .../Config/F4SD-HealthCard-Configuration.xml | 12 +- .../Config/F4SD-HealthCard-Configuration.xsd | 10 +- .../F4SD-Cockpit-Client-Demo.csproj | 3 +- .../F4SDCockpitCommunicationDemo.cs | 322 +- FasdCockpitCommunicationDemo/app.config | 11 + .../cF4SDHealthCardJsonRawData.cs | 31 +- FasdCockpitCommunicationDemo/packages.config | 2 +- FasdDesktopUi/App.config | 6 +- FasdDesktopUi/App.xaml.cs | 162 +- .../CustomEvents/HeadingDataEventArgs.cs | 16 + .../RelationEventArgs.cs | 5 +- .../CustomEvents/SupportCaseDataEventArgs.cs | 12 + .../Basics/Helper/HealthCardDataHelper.cs | 701 +++-- .../Basics/Helper/MenuItemDataProvider.cs | 2 +- .../Basics/Models/ConnectionStatusHelper.cs | 5 +- .../Basics/Models/HeadingDataModel.cs | 1 + .../Basics/Models/NamedParameterEntry.cs | 2 + .../Basics/Models/TicketOverviewModel.cs | 232 +- FasdDesktopUi/Basics/SearchHistoryManager.cs | 2 +- .../TicketOverviewCountsChangedEventArgs.cs | 7 +- .../ProtocollService/F4SDProtocoll.cs | 33 +- .../ProtocollService/IProtocollEntry.cs | 15 - .../QuickActionProtocollEntry.cs | 110 +- .../QuickTipStepProtocollEntry.cs | 29 +- .../ProtocollService/TextualProtocollEntry.cs | 18 - .../RelationService/RelationService.cs | 4 +- .../Controllers/SupportCaseController.cs | 255 ++ .../SupportCaseHeadingController.cs | 93 + .../Services/SupportCase/ISupportCase.cs | 12 +- .../Services/SupportCase/SupportCase.cs | 177 +- .../SupportCase/SupportCaseFactory.cs | 3 - .../SupportCase/SupportCaseProcessor.cs | 274 ++ .../SupportCaseProcessorFactory.cs | 18 + .../Services/TicketOverviewUpdateService.cs | 559 +++- .../Basics/SupportCaseDataProvider.cs | 187 +- .../UiActions/ChangeHealthCardAction.cs | 22 +- .../UiActions/ShowDetailedDataAction.cs | 54 +- .../Basics/UiActions/UiDemoQuickAction.cs | 7 +- .../Basics/UiActions/UiLocalQuickAction.cs | 12 +- .../UiActions/UiLocalWebRequestQuickAction.cs | 13 +- .../UiActions/UiProcessSearchHistoryEntry.cs | 2 +- .../UiProcessSearchRelationAction.cs | 34 +- .../UiActions/UiProcessSearchResultAction.cs | 7 +- .../Basics/UiActions/UiQuickAction.cs | 1 + .../Basics/UiActions/UiQuickTipAction.cs | 8 +- .../Basics/UiActions/UiRemoteQuickAction.cs | 15 +- .../Basics/UiActions/UiServerQuickAction.cs | 13 +- .../UiActions/UiShowRawHealthcardValues.cs | 41 + FasdDesktopUi/Basics/UserControls/Badge.xaml | 27 + .../Basics/UserControls/Badge.xaml.cs | 27 + .../UserControls/DataCanvas/DataCanvas.xaml | 6 - .../DataCanvas/DataCanvas.xaml.cs | 12 +- .../DataCanvas/DynamicChart.xaml.cs | 51 +- .../QuickActionStatusMonitor.xaml.cs | 9 +- .../QuickTip/QuickTipStatusMonitor.xaml | 215 +- .../QuickTip/QuickTipStatusMonitor.xaml.cs | 7 +- .../Basics/UserControls/SearchBar.xaml.cs | 2 +- .../CloseCaseDialogWithTicket.merged.xaml.cs | 2707 +++++++++++++++++ .../Ticket/CloseCaseDialogWithTicket.xaml.cs | 2 +- .../UserControls/TicketOverview.xaml.cs | 76 +- FasdDesktopUi/Basics/cUtility.cs | 64 +- FasdDesktopUi/Config/LanguageDefinitions.xml | 73 +- FasdDesktopUi/F4SD-Cockpit-Client.csproj | 114 +- .../Pages/DetailsPage/DetailsPageView.xaml | 6 +- .../Pages/DetailsPage/DetailsPageView.xaml.cs | 326 +- .../Pages/DetailsPage/DetailsPageViewModel.cs | 109 - .../DetailsPageDataHistoryCollection.xaml | 2 +- .../DetailsPageDataHistoryCollection.xaml.cs | 8 +- .../DetailsPageNavigationHeading.xaml.cs | 12 +- .../DetailsPageWidgetCollection.xaml | 2 +- .../DetailsPageWindowStateBar.xaml | 11 +- .../DetailsPageWindowStateBar.xaml.cs | 19 +- .../RawHealthCardValuesPage.xaml | 109 + .../RawHealthCardValuesPage.xaml.cs | 64 + .../Pages/SearchPage/SearchPageView.xaml | 50 +- .../Pages/SearchPage/SearchPageView.xaml.cs | 536 +++- .../SettingsPage/M42SettingsPageView.xaml | 2 +- .../Pages/SlimPage/SlimPageView.xaml.cs | 14 +- .../SupportCasePageBase.cs | 22 +- .../CheckBoxResources.xaml | 9 +- .../LightModeResources.xaml | 2 +- FasdDesktopUi/cFasdCockpitConfig.cs | 3 + FasdDesktopUi/packages.config | 17 +- FasdExcelToJsonConverter/App.config | 4 + .../ExcelHealthcardParser.cs | 2 +- .../F4SD-ExcelToJson-Converter.csproj | 2 +- FasdExcelToJsonConverter/packages.config | 2 +- Setup_Client/Product.wxs | 3 +- Setup_Client/SignSourceFiles.cmd | 2 +- Shared/SharedAssemblyInfo.cs | 6 +- 104 files changed, 6797 insertions(+), 1867 deletions(-) create mode 100644 2026-01-28 10_49_55-.png create mode 100644 FasdCockpitBase/app.config create mode 100644 FasdCockpitCommunication/TicketOverview/TicketOverviewCountsResponse.cs create mode 100644 FasdCockpitCommunication/app.config create mode 100644 FasdCockpitCommunicationDemo/app.config create mode 100644 FasdDesktopUi/Basics/CustomEvents/HeadingDataEventArgs.cs rename FasdDesktopUi/Basics/{Services/RelationService => CustomEvents}/RelationEventArgs.cs (59%) create mode 100644 FasdDesktopUi/Basics/CustomEvents/SupportCaseDataEventArgs.cs delete mode 100644 FasdDesktopUi/Basics/Services/ProtocollService/IProtocollEntry.cs delete mode 100644 FasdDesktopUi/Basics/Services/ProtocollService/TextualProtocollEntry.cs create mode 100644 FasdDesktopUi/Basics/Services/SupportCase/Controllers/SupportCaseController.cs create mode 100644 FasdDesktopUi/Basics/Services/SupportCase/Controllers/SupportCaseHeadingController.cs create mode 100644 FasdDesktopUi/Basics/Services/SupportCase/SupportCaseProcessor.cs create mode 100644 FasdDesktopUi/Basics/Services/SupportCase/SupportCaseProcessorFactory.cs create mode 100644 FasdDesktopUi/Basics/UiActions/UiShowRawHealthcardValues.cs create mode 100644 FasdDesktopUi/Basics/UserControls/Badge.xaml create mode 100644 FasdDesktopUi/Basics/UserControls/Badge.xaml.cs create mode 100644 FasdDesktopUi/Basics/UserControls/Ticket/CloseCaseDialogWithTicket.merged.xaml.cs create mode 100644 FasdDesktopUi/Pages/RawHealthCardValuesPage/RawHealthCardValuesPage.xaml create mode 100644 FasdDesktopUi/Pages/RawHealthCardValuesPage/RawHealthCardValuesPage.xaml.cs diff --git a/2026-01-28 10_49_55-.png b/2026-01-28 10_49_55-.png new file mode 100644 index 0000000000000000000000000000000000000000..62b9c9e3d162c3bd36deffafec9fdbc9bcd38387 GIT binary patch literal 6511 zcmbVRXIN9+mOcxfe;8~;+>g0^E~(dm}h>RvesE^J!|iC*4pp8Pm-0z6#+gl9{>OX zS509y0KjI%x+m~(vCgRqoc*i|8^Y$wMWCWvYK|pvco|#r8+9sp0GI{0>FMv=<)Q^IShT-YBgdc5CK{11l=3 zD&2OoveHPDwHA3`EXsMw*g9s?;Oyzsq|BJc&1>*GHrxKu-3&iGZR4!I{>IXVPOi*t zO;k56Yrs!-<-WyMuNTR1e@#eEK3Re5Nut{$HpTp5Hz4VFourX`vKmXp_fj7jW{h{g z$NTWB?`qTohPhQS-YHkb}umQdnf<5aJAC z^ZOa*ySX;Ji8J@~q;_%VyRLoh)r@+ys{UKpc-5xtQ;V;$TQcc->6XtN({C#g;CuYu z{u6WA5KmNgcJ&^2hS|V%!_AZ{x@Tc|y&GHI{z&{w5x;>%7f>`d{-iDP0Qwy$)j`Z~$+cUO zi`lZY{6;GqD+YKe$!V%_)YSp)+W~hf@Fyf%$8W;NC1dYy{p2qPm}lom^xZA!-^?MB zfv?4nO{jt5nEFA^ViWz!8ox^uoGTqJ2Qnu}5CHLo5cb59%bFPRQwhZt4Nd;`7;!fS z1#*L0%YLo6aC012xVbgpxw3(ClW6_M6zXiH9Z{?a61Qi)gX+GT)KI6?KAK9_Kn^IR zA^_g9%2`=MP>tw0v?4?=m}jCKJ_(f(;OYdkFsR=~cTzsJ4D2yhcto)eeIbnPnhg1Z zXiNI^vu#Sxp}hDm=UP`8_L7WRU3gCtZ8$PwF^8YIM7mGq5>_S5z2CjIzdEWu?P5Px z*|^EIhV{A5t)k#o`1-MQa;3Y8lRir9Dwu7#D0sIj&Bm$c94z=wpeXT@aeKA zD3aB_kGto~lXprF8KBeci`IBoG-@$*59Kks@wrXO1AgHK4Qw3F#`BGfyOlL;Q9%pv zX>9?+bbaaT{rB^A0vnhv;~JZJYpck%_v_^WD7CGLYC{}frOacPE&R$AVcpu9?lF%o z%lA*0^}j#6Mn|S5J@&8+Ovy?aWpBCJl?Ydh1F#t>W&y;RK(|e!tfL zWdt$rjxyMC!t7C&h0a1+uT12K>~?2O;|(3u?G_`nRtVEM8SkH`2=C?Q{WZmqOPo5k zn!r34oA0=(OdxNOg@w^wilYYrO(2TaM~UM;RlzK)&+ zI#;=ru>Az$u(j)-!sT>$yFFzqn2I;th04QjN`1hxm9uj_IUe;7dr71GRpT+qRuvZ@ z=_B`_;CWU6|3W70-W!>2yH3uH zm@$~M5Zsf#XZfMaeIZ)nF}W)0*||lhtnjE7y}GDO-^O2EZF`0<(QAk~{Rmm@!Ld5{ zOaEqr@aQL0Rr^DFT4sUpCo!KT1jzgzf z37JHq_Y2i9_r)KpjbBi1nBbLf^c@=rUZ_@;4}JBmLVC=TmeKv(ga*y%R(s_^6gyBu zu57O!Ffug7_ouP_HSaZDsFIo>AOEM{iU^0uM?A;@9;-=~W=)Zq;r{RP{El&2 zQN0NC@x9UedPOviD}?>=aCmCT8s}>Hm8OCgbp`%9`V3ZWB<)ZN^Xu+wc<#th+S72s z!u8+A!|aK;(Gfoq$YXAByUm>>y0@=c&zUM>N>XMlEt<7;zxU#v=}z~XVA}aJdv_zN zw^dEHirca~F;^*aYuLq_0mUyVJnocS7ueN1L}l@_TeWqr0gPu{ zYa86BJR6seo2{S?AcUT;tzFNLiG6&v`^N7Wx0Ux3V2ppGkn!VP93)}Xd~#Xv3in5ofc?ukQC@cbdiR7I$wPbR zBS^Z4rgP-onj7xXy985i;aqkhgP=N(!Gx`x!Mlzl>^xd#V6cE4>w8A&F273f`|n%= zOOzGVMtUc!B~+WcJuY{n@>Ll{899r5tH13JukX#=FHpm=f8v%q*fHJL`6zA_)vrhW z2`QLkq)_4n&yOM$C7JC$H)6#oRXJ~}tCqgIa56~gL|V6X{TXkawQjCCfA4g60d>w? z9vMgcImv-8szS7*Xw*g0`N@3Q*vOg0#2B$7o|M9_Sj!mO`E~-gYYgk9%O!I02=lj6 z``CZSf5D2oID+2N9`WWuPD!`d;RRbIXMIY-0Cjl30(VmazJESKUZK7mx-%#lb+P#b z1XeDr5ich9yNPJR8m?_No>&}`mS9f3^?pKyz?yWu*l04tXnC*gxM`71KLh(HR!9d- zpifgwg!RxKYac1$93mYp;n%Ut${$h6o`I8$*Ar~#&Oq)kW`=l1?ScVKC9^mVuyAYL zWrIuq1M^s2zs|vleFzLP6*c(B>M(JC@POA}=R#xS z1TzbEQm2mepOwQu4CNcFv- zzsz~Y4=+X9e%yZKP3;{Vt|0QOK%4z!!1jDbFg(?A5>uBZWyGw#K`$#N1>7zAc*Z9n zt?d&0?~S#kXSbpQ0!=bEUWd0J-Wq)9ZcuK}yfZZ`;*Dg)P|8-3Led-Eh4ZYLIczks zwd4(u_kKM!`$CCT=a}TLL#A@oANkgdgzr0*@;6Ly`(q;``eI%5f_7i{?oUblnte92 z{@cbc&rghBR!kkm&_9~BHAfNLX$o-ZtoNk+yispmuoJ6Cn9ONap3tjJo>*%?c)BM< zGW3Q16dbin6U#%J)GQ-X*T_y+1JJ)x=Fm*rtuUvaIkf6I#%(Xj2oPf`{AjE0Z+;4^ zdwKyT9Db@yBnEsO4upOi_q%TLo6E9ZO<$1Mu(i`mT|F`u_KnM-M@-3y?Xr+PW-_79 zHk7j@sJg13_##e2J24Eu{_sXFXl$9rR@V-0B_Yu(-=y&0w}6Fo{7m?-My~`vntto5 z(bz>9qYGS%^#}#A*76uz!=pQ*jM+P#<+(Wm6rE=VeT&)Vo3FRiU$H6$DfHp$SbOxd z4ql0?(c$&sr)*_L?P$Pg;E0AV?rFQFZ>qSF^uSP|yQ`o}X_;EXqIA^mku!{q#`aSQ zZw)5xZ-?CuedyanK~yjG^9E04Z;nUags|Gg1c+l%T?;cjSQ!JIx!jY26*po^(HpF| zpCp#@`Kjt)ri)w$&Zj@ZDu{@T+T8@6&wbe9NXskJe9)_n)(sI$vds_3N}S@nZZek4 z=K?=7r+>9k*1}F_s#wnUv5d%xa{_*Dh|ga9-r^{ zo~1LOX9N=srFI)IeZBAAT@^ema%rR?HR_kb8T4+%WZ`L%&)0>GUYvG~J?YfYtCy5` zJUN){!P)Nf3XFBD3a+H%g7KVIs6}^~=ROsUmw$I>tExAz#+Lt8o1A#uCjFH2ybvn^ zsnaZu=J*F+ii22%`I!YVegDulM@~@0;4QDt$eCD*9&8wM==(I^Q)5Mfv2HvKX(NNTma5R)!YBtqIWkU-V32qMlSG z%bb(W&d%e;^7+Rh_1*(YD}adgkF_G!!+(>4x4yo9|M>VRCVlDo;GmsO*rLO-HvA8H z{qS7bl55S!+nbl7L3e%3BDSUrv$J15Te`}0l!9CNyA9z*7TGH5YL4O;IxHtHfL|%+ zMx9|yAgCSK@in(4QkBB_9_jiCs4x6%WOWpE0iL0cr2qO}`*m{{mS$B2-23wPzKtf@ z4N_G@3x)pxl^6pMPLApIu2T@Lda1=oO*cCYk+=Z?N=%(r^#fv^d?>xBpYp z_#WMfG3R)!sV4#93Uwi5FCb5?wg^Jz`nqqO6v#73tzajc4qJ`(QgRB1>peQ3xsHK# z%zIuV$cZtK>N&!m-{~vZkaA=eUeMFNen&Ur=rz|HePXi1iNhK=_?!GOF!zPQhLIo^ zUG4XS80n=DhZBfkn+tf;GFgbj#g9=fM-6N*CRz?o_wbhrwLE z&;|ZHX>}#c&crV_;6%B~VWS6MxVo_1(6QbIYS@^Bk+z*KVHlXIDwGRNt>Mc?oFoDF z9E_-M5a)u^)nUWX6BtQEu6gRuS*++8obz$a8_tT}Xd!DgTVKvZ!fLv-NlA#ITRaLZ z8ID)SxR_|Ai{*9PAd(s*e8mvmRe>NLFc`PfkGfY-RXo!pB>($SDg>(ShSyo9rHERF zr=~~<_)qC6|dr#jm7Y!e2~_xO-T*- zdG(Jb@AfH2e5AGYLYL+3eVZ4bPhnuN5+Hs^o5`av`fo3G^(f4FU!0hMa1aK zKo`(V-9_|;gk^5BP=p0Jl^FJTevEG7yuNlqAd;Co(yNp~sy`JF{dO50l(6f&e`iJV z@kaA~soN_@ht$&ixN$0Uu&P=*+f5!ULQ_X zk*b?4(be*DOx-eCTQa2iseHld6v|!F-$-byOjC!seVD>`&aJFct6!IqEjOb{t;3bF zN(UjdWXcNPaKz+!aw?S^==!sW+C+E(G`ZFghllRXOlstCBT(<{iD?x|n^6%<4Ieu2 zW@VAUb5L{!(O@~st z?LbiCObAH3f4l6p5?fTHrEbHION{0=GVMS@o=R zbP32#B@EB=iAWj|Z#X_{Gc!a z2BrA2;A%p-yH>%l7qw*aN8?v$0C92cynlhI%?FCjk?3W5f9MBu7o>MG!AnN0I601q%J$@hu!FAwYPzN3d#Bd&}qO-k|(wD}Q8*`uVU>pKZI? z#7FAK8K8CR4lbKh^y7Sd`8Gnhq7`E128okRr^pF=>{N7ZW= z9YPFK25iMT&OHf}V)_9Z6BQ&U$#DBjJTQ-D?gW;TJ81JhY>;JB?m%+PYha(4RpH_} z^NJeR1#gx~bSDN&Sv!pgsU}Z4@_aJ31r7H;G&g`piT^guH$|^IC5&j^Mopo3^2eQ5=FeO<~g?{|S5!x$u%ErfJ{h@>fgm0ge_a zyK<>1Ahp8EDzSUW@YX$1@*imS+h4vZaQ$0}IEWY3u`Jto0`Cs8BTZLqp;{=+s zxCEc9JqEUUtd0%#rLvla;>njA&=YLHS@;a}0xT&jUuynOQ_WxiIeoyE)N*g=(R;_stp6dv N)k_wzii<9>{{g>dqs;&S literal 0 HcmV?d00001 diff --git a/F4SD-PhoneMonitor/F4SD-PhoneMonitor.csproj b/F4SD-PhoneMonitor/F4SD-PhoneMonitor.csproj index 78f9499..15eac1a 100644 --- a/F4SD-PhoneMonitor/F4SD-PhoneMonitor.csproj +++ b/F4SD-PhoneMonitor/F4SD-PhoneMonitor.csproj @@ -67,7 +67,7 @@ .\Interop.CLMgr.dll - ..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + ..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll diff --git a/F4SD-PhoneMonitor/packages.config b/F4SD-PhoneMonitor/packages.config index fef83be..17ab3be 100644 --- a/F4SD-PhoneMonitor/packages.config +++ b/F4SD-PhoneMonitor/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/F4SD.Cockpit.Client.Test/Basics/Sevices/SupportCase/SupportCaseTest.cs b/F4SD.Cockpit.Client.Test/Basics/Sevices/SupportCase/SupportCaseTest.cs index fdf7c48..f7a23d3 100644 --- a/F4SD.Cockpit.Client.Test/Basics/Sevices/SupportCase/SupportCaseTest.cs +++ b/F4SD.Cockpit.Client.Test/Basics/Sevices/SupportCase/SupportCaseTest.cs @@ -1,4 +1,5 @@ using C4IT.FASD.Base; +using FasdDesktopUi.Basics.CustomEvents; using FasdDesktopUi.Basics.Services.RelationService; using FasdDesktopUi.Basics.Services.SupportCase; using NSubstitute; @@ -62,4 +63,90 @@ public class SupportCaseTest Assert.Equal(_supportCase, raisedEvent.Sender); Assert.Equal(relations, raisedEvent.Arguments.Relations); } + + [Fact] + public void UpdateSupportCaseDataCache_Raise_SupportCaseDataCacheHasChanged() + { + cF4sdApiSearchResultRelation relation = new() + { + Type = enumF4sdSearchResultClass.Computer, + Name = "My computer", + Identities = + [ + new() { Id = Guid.NewGuid(), Class = enumFasdInformationClass.Computer } + ] + }; + + List tables = + [ + new() { Name = "TestTable1", Columns = [], TableType = eDataHistoryTableType.History }, + ]; + + var raisedEvent = Assert.Raises( + h => _supportCase.SupportCaseDataCacheHasChanged += h, + h => _supportCase.SupportCaseDataCacheHasChanged -= h, + () => _supportCase.UpdateSupportCaseDataCache(relation, tables)); + Assert.NotNull(raisedEvent); + Assert.Equal(_supportCase, raisedEvent.Sender); + Assert.Equal(relation, raisedEvent.Arguments.Relation); + Assert.Equal(tables, raisedEvent.Arguments.DataTables); + } + + [Fact] + public void GetSupportCaseData_Contains_UpdateSupportCaseDataCacheData() + { + // Arrange + const string columnValue = "Hello world"; + const string tableName = "TestTable1"; + const string columnName = "TestColumn1"; + List expected = [columnValue]; + + + cF4sdApiSearchResultRelation relation = new() + { + Type = enumF4sdSearchResultClass.Computer, + Name = "My computer", + Identities = + [ + new() { Id = Guid.NewGuid(), Class = enumFasdInformationClass.Computer } + ] + }; + + cF4SDHealthCardRawData.cHealthCardTable dataTable = new() + { + Name = tableName, + TableType = eDataHistoryTableType.History + }; + dataTable.Columns = new() + { + [columnName] = new(dataTable) { Values = expected } + }; + + // Act + _supportCase.UpdateSupportCaseDataCache(relation, [dataTable]); + + // Assert + var actual = _supportCase.GetSupportCaseHealthcardData(relation, new cValueAddress() { ValueTable = tableName, ValueColumn = columnName }); + + Assert.Equal(expected, actual); + } + + [Fact] + public void GetSupportCaseData_ReturnsNull_When_NoDataExists() + { + // Arrange + cF4sdApiSearchResultRelation relation = new() + { + Type = enumF4sdSearchResultClass.Computer, + Name = "My computer", + Identities = + [ + new() { Id = Guid.NewGuid(), Class = enumFasdInformationClass.Computer } + ] + }; + // Act + var actual = _supportCase.GetSupportCaseHealthcardData(relation, new cValueAddress() { ValueTable = "NonExistentTable", ValueColumn = "NonExistentColumn" }); + // Assert + Assert.Null(actual); + } } diff --git a/F4SD.Cockpit.Client.Test/F4SD.Cockpit.Client.Test.csproj b/F4SD.Cockpit.Client.Test/F4SD.Cockpit.Client.Test.csproj index 6d7ec82..4d0cc30 100644 --- a/F4SD.Cockpit.Client.Test/F4SD.Cockpit.Client.Test.csproj +++ b/F4SD.Cockpit.Client.Test/F4SD.Cockpit.Client.Test.csproj @@ -29,7 +29,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/FasdCockpitBase/F4SD-Cockpit-Client-Base.csproj b/FasdCockpitBase/F4SD-Cockpit-Client-Base.csproj index 62bc38c..106eb2f 100644 --- a/FasdCockpitBase/F4SD-Cockpit-Client-Base.csproj +++ b/FasdCockpitBase/F4SD-Cockpit-Client-Base.csproj @@ -53,15 +53,49 @@ prompt + + ..\packages\C4IT.F4SD.DisplayFormatting.1.0.0\lib\netstandard2.0\C4IT.F4SD.DisplayFormatting.dll + + + ..\packages\C4IT.F4SD.SupportCaseProtocoll.1.0.0\lib\netstandard2.0\C4IT.F4SD.SupportCaseProtocoll.dll + ..\packages\MaterialIcons.1.0.3\lib\MaterialIcons.dll + + ..\packages\Microsoft.Bcl.AsyncInterfaces.10.0.2\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll + + + ..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.10.0.2\lib\net462\Microsoft.Extensions.DependencyInjection.Abstractions.dll + + + ..\packages\Microsoft.Extensions.Logging.Abstractions.10.0.2\lib\net462\Microsoft.Extensions.Logging.Abstractions.dll + - ..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + ..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll + + ..\packages\System.Buffers.4.6.1\lib\net462\System.Buffers.dll + + + ..\packages\System.Diagnostics.DiagnosticSource.10.0.2\lib\net462\System.Diagnostics.DiagnosticSource.dll + + + ..\packages\System.Memory.4.6.3\lib\net462\System.Memory.dll + + + + ..\packages\System.Numerics.Vectors.4.6.1\lib\net462\System.Numerics.Vectors.dll + + + ..\packages\System.Runtime.CompilerServices.Unsafe.6.1.2\lib\net462\System.Runtime.CompilerServices.Unsafe.dll + + + ..\packages\System.Threading.Tasks.Extensions.4.6.3\lib\net462\System.Threading.Tasks.Extensions.dll + @@ -125,12 +159,13 @@ Properties\SharedAssemblyInfo.cs - - - - - + + + + + + @@ -140,4 +175,4 @@ - + \ No newline at end of file diff --git a/FasdCockpitBase/FasdCockpitCommunicationBase.cs b/FasdCockpitBase/FasdCockpitCommunicationBase.cs index 7b28df7..5897a90 100644 --- a/FasdCockpitBase/FasdCockpitCommunicationBase.cs +++ b/FasdCockpitBase/FasdCockpitCommunicationBase.cs @@ -64,8 +64,9 @@ namespace C4IT.FASD.Cockpit.Communication public abstract Task StartGatheringRelations(IEnumerable relatedTo, CancellationToken token); public abstract Task GetStagedRelations(Guid id, CancellationToken token); - public abstract Task> GetSearchResultRelations(enumF4sdSearchResultClass resultType, List searchResults); - public abstract Task> GetTicketOverviewRelations(string key, bool useRoleScope, int count); + public abstract Task> GetSearchResultRelations(enumF4sdSearchResultClass resultType, List searchResults); + public abstract Task> GetTicketOverviewRelations(string key, bool useRoleScope, int count); + public abstract Task> GetTicketOverviewCounts(IEnumerable keys, bool useRoleScope); public abstract Task GetHealthCardData(cF4sdHealthCardRawDataRequest requestData); diff --git a/FasdCockpitBase/app.config b/FasdCockpitBase/app.config new file mode 100644 index 0000000..db5dd16 --- /dev/null +++ b/FasdCockpitBase/app.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/FasdCockpitBase/packages.config b/FasdCockpitBase/packages.config index 89fe9c4..635d9d9 100644 --- a/FasdCockpitBase/packages.config +++ b/FasdCockpitBase/packages.config @@ -1,5 +1,16 @@  + + - + + + + + + + + + + \ No newline at end of file diff --git a/FasdCockpitCommunication/F4SD-Cockpit-Client-Communication.csproj b/FasdCockpitCommunication/F4SD-Cockpit-Client-Communication.csproj index b8a7c7c..54720fc 100644 --- a/FasdCockpitCommunication/F4SD-Cockpit-Client-Communication.csproj +++ b/FasdCockpitCommunication/F4SD-Cockpit-Client-Communication.csproj @@ -56,7 +56,7 @@ - ..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + ..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll @@ -95,11 +95,12 @@ Properties\SharedAssemblyInfo.cs - - - - - + + + + + + {7793f281-b226-4e20-b6f6-5d53d70f1dc1} @@ -115,6 +116,7 @@ + @@ -123,4 +125,4 @@ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - \ No newline at end of file + diff --git a/FasdCockpitCommunication/FasdCockpitCommunicationWeb.cs b/FasdCockpitCommunication/FasdCockpitCommunicationWeb.cs index fcc9117..6c75dd3 100644 --- a/FasdCockpitCommunication/FasdCockpitCommunicationWeb.cs +++ b/FasdCockpitCommunication/FasdCockpitCommunicationWeb.cs @@ -17,7 +17,8 @@ using C4IT.Security; using C4IT.FASD.Communication.Agent; using FasdCockpitBase.Models; -using FasdCockpitCommunication; +using FasdCockpitCommunication; +using FasdCockpitCommunication.TicketOverview; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -1095,10 +1096,119 @@ namespace C4IT.FASD.Cockpit.Communication return output; } - public override Task> GetTicketOverviewRelations(string key, bool useRoleScope, int count) - { - return Task.FromResult(new List()); - } + public override async Task> GetTicketOverviewCounts(IEnumerable keys, bool useRoleScope) + { + var CM = MethodBase.GetCurrentMethod(); + LogMethodBegin(CM); + + var apiError = 0; + var timeStart = DateTime.UtcNow; + + try + { + var normalizedKeys = (keys ?? Enumerable.Empty()) + .Where(k => !string.IsNullOrWhiteSpace(k)) + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToList(); + + var http = GetHttpHelper(true); + var scope = useRoleScope ? "role" : "personal"; + var urlBuilder = new StringBuilder($"api/TicketOverview/GetCounts?scope={scope}"); + + if (normalizedKeys.Count > 0) + { + var joinedKeys = HttpUtility.UrlEncode(string.Join(",", normalizedKeys)); + urlBuilder.Append($"&keys={joinedKeys}"); + } + + var url = urlBuilder.ToString(); + var result = await http.GetHttpJson(url, 15000, CancellationToken.None); + + if (!result.IsOk) + { + apiError = (int)result.Status; + if (CheckConnectionStatus != null) + await CheckConnectionStatus.Invoke(); + + LogEntry($"Error on requesting ticket overview counts ({scope}). Status: {result.Status}", LogLevels.Warning); + return new Dictionary(StringComparer.OrdinalIgnoreCase); + } + + if (Debug_apiValues) SaveApiResultValueJson("TicketOverview.GetCounts", result.Result, url); + + var response = JsonConvert.DeserializeObject(result.Result); + return response?.ToDictionary(normalizedKeys) ?? new Dictionary(StringComparer.OrdinalIgnoreCase); + } + catch (Exception E) + { + apiError = E.HResult; + if (CheckConnectionStatus != null) + await CheckConnectionStatus.Invoke(); + + LogException(E); + } + finally + { + if (Debug_apiTiming) SaveApiTimingEntry("TicketOverview.GetCounts", timeStart, apiError); + LogMethodEnd(CM); + } + + return new Dictionary(StringComparer.OrdinalIgnoreCase); + } + + public override async Task> GetTicketOverviewRelations(string key, bool useRoleScope, int count) + { + var CM = MethodBase.GetCurrentMethod(); + LogMethodBegin(CM); + + var apiError = 0; + var timeStart = DateTime.UtcNow; + var output = new List(); + + try + { + if (string.IsNullOrWhiteSpace(key)) + return output; + + var http = GetHttpHelper(true); + var scope = useRoleScope ? "role" : "personal"; + var safeKey = HttpUtility.UrlEncode(key); + var url = $"api/TicketOverview/GetRelations?key={safeKey}&scope={scope}&count={Math.Max(0, count)}"; + + var result = await http.GetHttpJson(url, 20000, CancellationToken.None); + + if (!result.IsOk) + { + apiError = (int)result.Status; + if (CheckConnectionStatus != null) + await CheckConnectionStatus.Invoke(); + + LogEntry($"Error on requesting ticket overview relations for '{key}' ({scope}). Status: {result.Status}", LogLevels.Warning); + return output; + } + + if (Debug_apiValues) SaveApiResultValueJson("TicketOverview.GetRelations", result.Result, url); + + var relations = JsonConvert.DeserializeObject>(result.Result); + if (relations != null) + output = relations; + } + catch (Exception E) + { + apiError = E.HResult; + if (CheckConnectionStatus != null) + await CheckConnectionStatus.Invoke(); + + LogException(E); + } + finally + { + if (Debug_apiTiming) SaveApiTimingEntry("TicketOverview.GetRelations", timeStart, apiError); + LogMethodEnd(CM); + } + + return output; + } public override async Task GetHealthCardData(cF4sdHealthCardRawDataRequest requestData) { var CM = MethodBase.GetCurrentMethod(); diff --git a/FasdCockpitCommunication/TicketOverview/TicketOverviewCountsResponse.cs b/FasdCockpitCommunication/TicketOverview/TicketOverviewCountsResponse.cs new file mode 100644 index 0000000..5dd3c83 --- /dev/null +++ b/FasdCockpitCommunication/TicketOverview/TicketOverviewCountsResponse.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; + +using Newtonsoft.Json; + +namespace FasdCockpitCommunication.TicketOverview +{ + internal sealed class TicketOverviewCountsResponse + { + [JsonProperty("counts")] + public Dictionary Counts { get; set; } = new Dictionary(StringComparer.OrdinalIgnoreCase); + + public Dictionary ToDictionary(IEnumerable expectedKeys) + { + var comparer = StringComparer.OrdinalIgnoreCase; + var output = new Dictionary(comparer); + + if (expectedKeys != null) + { + foreach (var key in expectedKeys) + { + if (string.IsNullOrWhiteSpace(key)) + continue; + + if (Counts != null && Counts.TryGetValue(key, out var count)) + output[key] = count; + else + output[key] = 0; + } + + return output; + } + + if (Counts != null) + { + foreach (var kvp in Counts) + { + if (string.IsNullOrWhiteSpace(kvp.Key)) + continue; + + output[kvp.Key] = kvp.Value; + } + } + + return output; + } + } +} diff --git a/FasdCockpitCommunication/app.config b/FasdCockpitCommunication/app.config new file mode 100644 index 0000000..db5dd16 --- /dev/null +++ b/FasdCockpitCommunication/app.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/FasdCockpitCommunication/packages.config b/FasdCockpitCommunication/packages.config index fef83be..17ab3be 100644 --- a/FasdCockpitCommunication/packages.config +++ b/FasdCockpitCommunication/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/FasdCockpitCommunicationDemo/Config/F4SD-HealthCard-Configuration.xml b/FasdCockpitCommunicationDemo/Config/F4SD-HealthCard-Configuration.xml index 5e49ff6..e97b810 100644 --- a/FasdCockpitCommunicationDemo/Config/F4SD-HealthCard-Configuration.xml +++ b/FasdCockpitCommunicationDemo/Config/F4SD-HealthCard-Configuration.xml @@ -205,9 +205,6 @@ Distinguished Name User - - Distinguished Name computer - IP Adresse @@ -282,8 +279,8 @@ IBM - - + @@ -470,7 +467,7 @@ - + Freier Speicher @@ -1065,9 +1062,6 @@ Distinguished Name User - - Distinguished Name computer - Anwender diff --git a/FasdCockpitCommunicationDemo/Config/F4SD-HealthCard-Configuration.xsd b/FasdCockpitCommunicationDemo/Config/F4SD-HealthCard-Configuration.xsd index ef9e2d1..981decd 100644 --- a/FasdCockpitCommunicationDemo/Config/F4SD-HealthCard-Configuration.xsd +++ b/FasdCockpitCommunicationDemo/Config/F4SD-HealthCard-Configuration.xsd @@ -102,6 +102,13 @@ + + + + + + + @@ -543,7 +550,8 @@ - + + diff --git a/FasdCockpitCommunicationDemo/F4SD-Cockpit-Client-Demo.csproj b/FasdCockpitCommunicationDemo/F4SD-Cockpit-Client-Demo.csproj index 84457aa..967e2f5 100644 --- a/FasdCockpitCommunicationDemo/F4SD-Cockpit-Client-Demo.csproj +++ b/FasdCockpitCommunicationDemo/F4SD-Cockpit-Client-Demo.csproj @@ -54,7 +54,7 @@ - ..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + ..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll @@ -122,6 +122,7 @@ Always + Designer diff --git a/FasdCockpitCommunicationDemo/F4SDCockpitCommunicationDemo.cs b/FasdCockpitCommunicationDemo/F4SDCockpitCommunicationDemo.cs index a9fe5f9..edf5cc9 100644 --- a/FasdCockpitCommunicationDemo/F4SDCockpitCommunicationDemo.cs +++ b/FasdCockpitCommunicationDemo/F4SDCockpitCommunicationDemo.cs @@ -268,7 +268,41 @@ namespace C4IT.FASD.Cockpit.Communication return ticket; } - public override async Task> GetTicketOverviewRelations(string key, bool useRoleScope, int count) + public override Task> GetTicketOverviewCounts(IEnumerable keys, bool useRoleScope) + { + var scopeKey = useRoleScope ? "Role" : "Personal"; + var comparer = StringComparer.OrdinalIgnoreCase; + var result = new Dictionary(comparer); + + var requestedKeys = keys == null + ? TicketOverviewRelations.Keys.ToList() + : keys.Where(k => !string.IsNullOrWhiteSpace(k)).Distinct(comparer).ToList(); + + if (requestedKeys.Count == 0) + requestedKeys.AddRange(TicketOverviewRelations.Keys); + + foreach (var key in requestedKeys) + { + if (string.IsNullOrWhiteSpace(key)) + continue; + + if (TicketOverviewRelations.TryGetValue(key, out var scopeDictionary) && + scopeDictionary != null && + scopeDictionary.TryGetValue(scopeKey, out var definitions) && + definitions != null) + { + result[key] = definitions.Count; + } + else + { + result[key] = 0; + } + } + + return Task.FromResult(result); + } + + public override async Task> GetTicketOverviewRelations(string key, bool useRoleScope, int count) { var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); @@ -821,14 +855,14 @@ namespace C4IT.FASD.Cockpit.Communication output.Add(new cF4sdApiSearchResultRelation() { id = Guid.NewGuid(), Name = "C4-CK007", DisplayName = "C4-CK007", LastUsed = DateTime.UtcNow, Type = enumF4sdSearchResultClass.Computer, UsingLevel = 1, Identities = new cF4sdIdentityList() { new cF4sdIdentityEntry() { Class = enumFasdInformationClass.User, Id = resultIds.First() }, new cF4sdIdentityEntry() { Class = enumFasdInformationClass.Computer, Id = Guid.NewGuid() } } }); break; case constGuidTimoTicket: - output.Add(new cF4sdApiSearchResultRelation() { id = Guid.Parse(constGuidTimoTicketComputer), Name = "C4-TT007", DisplayName = "C4-TT007", LastUsed = DateTime.UtcNow.AddSeconds(-31), Type = enumF4sdSearchResultClass.Computer, UsingLevel = 1, Identities = new cF4sdIdentityList() { new cF4sdIdentityEntry() { Class = enumFasdInformationClass.User, Id = Guid.Parse(constGuidTimoTicket) }, new cF4sdIdentityEntry() { Class = enumFasdInformationClass.Computer, Id = Guid.Parse(constGuidTimoTicketComputer) } } }); - output.Add(new cF4sdApiSearchResultRelation() { id = Guid.NewGuid(), Name = "C4-NB00015", DisplayName = "C4-NB00015", LastUsed = DateTime.UtcNow.AddHours(-10), Type = enumF4sdSearchResultClass.Computer, UsingLevel = 0.6, Identities = new cF4sdIdentityList() { new cF4sdIdentityEntry() { Class = enumFasdInformationClass.User, Id = Guid.Parse(constGuidTimoTicket) }, new cF4sdIdentityEntry() { Class = enumFasdInformationClass.Computer, Id = Guid.NewGuid() } } }); + output.Add(new cF4sdApiSearchResultRelation() { id = Guid.Parse(constGuidTimoTicketComputer), Name = "C4-TT007", DisplayName = "C4-TT007", LastUsed = DateTime.UtcNow.AddSeconds(-31), Type = enumF4sdSearchResultClass.Computer, UsingLevel = 1, Identities = new cF4sdIdentityList() { new cF4sdIdentityEntry() { Class = enumFasdInformationClass.User, Id = Guid.Parse(constGuidTimoTicket) }, new cF4sdIdentityEntry() { Class = enumFasdInformationClass.Computer, Id = Guid.Parse(constGuidTimoTicketComputer) } }, Infos = new Dictionary() }); + output.Add(new cF4sdApiSearchResultRelation() { id = Guid.NewGuid(), Name = "C4-NB00015", DisplayName = "C4-NB00015", LastUsed = DateTime.UtcNow.AddHours(-10), Type = enumF4sdSearchResultClass.Computer, UsingLevel = 0.6, Identities = new cF4sdIdentityList() { new cF4sdIdentityEntry() { Class = enumFasdInformationClass.User, Id = Guid.Parse(constGuidTimoTicket) }, new cF4sdIdentityEntry() { Class = enumFasdInformationClass.Computer, Id = Guid.NewGuid() } }, Infos = new Dictionary() }); var demoTickets = await GetDemoTicketData(new cF4sdHealthCardRawDataRequest() { Identities = new cF4sdIdentityList() { new cF4sdIdentityEntry() { Class = enumFasdInformationClass.User, Id = Guid.Parse(constGuidTimoTicket) }, new cF4sdIdentityEntry() { Class = enumFasdInformationClass.Computer, Id = Guid.NewGuid() } } }); foreach (var demoTicket in demoTickets) { - output.Add(new cF4sdApiSearchResultRelation() { id = demoTicket.Id, Name = demoTicket.Name, DisplayName = demoTicket.Name, Infos = new Dictionary() { ["Summary"] = demoTicket.Summary, ["StatusId"] = ((int)demoTicket.Status).ToString(), ["Asset"] = demoTicket.Asset }, Type = enumF4sdSearchResultClass.Ticket, Identities = new cF4sdIdentityList() { new cF4sdIdentityEntry() { Class = enumFasdInformationClass.User, Id = Guid.Parse(constGuidTimoTicket) }, new cF4sdIdentityEntry() { Class = enumFasdInformationClass.Ticket, Id = demoTicket.Id } } }); + output.Add(new cF4sdApiSearchResultRelation() { id = demoTicket.Id, Name = demoTicket.Name, DisplayName = demoTicket.Name, Infos = new Dictionary() { ["Summary"] = demoTicket.Summary, ["Status"] = demoTicket.Status.ToString(), ["StatusId"] = ((int)demoTicket.Status).ToString(), ["Asset"] = demoTicket.Asset }, Type = enumF4sdSearchResultClass.Ticket, Identities = new cF4sdIdentityList() { new cF4sdIdentityEntry() { Class = enumFasdInformationClass.User, Id = Guid.Parse(constGuidTimoTicket) }, new cF4sdIdentityEntry() { Class = enumFasdInformationClass.Ticket, Id = demoTicket.Id } } }); } break; @@ -855,6 +889,7 @@ namespace C4IT.FASD.Cockpit.Communication LogMethodBegin(CM); var output = new cF4SDHealthCardRawData(); + cF4SDHealthCardRawData.cHealthCardTable outputTable; try { @@ -890,47 +925,52 @@ namespace C4IT.FASD.Cockpit.Communication } - output.Tables["M42Wpm-Tickets"] = new cF4SDHealthCardRawData.cHealthCardTable() + outputTable = new cF4SDHealthCardRawData.cHealthCardTable() { Name = "M42Wpm-Tickets", InformationClass = enumFasdInformationClass.Ticket, IsStatic = true, - Columns = new Dictionary() - { - ["name"] = new cF4SDHealthCardRawData.cHealthCardTableColumn() { Values = new List() { selectedTicket.Name } }, - ["Status"] = new cF4SDHealthCardRawData.cHealthCardTableColumn() { Values = new List() { ticketStatusString } }, - ["Priority"] = new cF4SDHealthCardRawData.cHealthCardTableColumn() { Values = new List() { selectedTicket.Priority } }, - ["AffectedUser"] = new cF4SDHealthCardRawData.cHealthCardTableColumn() { Values = new List() { selectedTicket.AffectedUser } }, - ["AssetName"] = new cF4SDHealthCardRawData.cHealthCardTableColumn() { Values = new List() { selectedTicket.Asset } }, - ["CreationDaysSinceNow"] = new cF4SDHealthCardRawData.cHealthCardTableColumn() { Values = new List() { selectedTicket.CreationDaysSinceNow } }, - ["CreationDate"] = new cF4SDHealthCardRawData.cHealthCardTableColumn() { Values = new List() { selectedTicket.CreationDate.ToUniversalTime() } }, - ["ClosingDaysSinceNow"] = new cF4SDHealthCardRawData.cHealthCardTableColumn() { Values = new List() { selectedTicket.ClosingDaysSinceNow } }, - ["ClosingDate"] = new cF4SDHealthCardRawData.cHealthCardTableColumn() { Values = new List() { selectedTicket.ClosingDate } }, - ["Category"] = new cF4SDHealthCardRawData.cHealthCardTableColumn() { Values = new List() { selectedTicket.Category } }, - ["CreationSource"] = new cF4SDHealthCardRawData.cHealthCardTableColumn() { Values = new List() { selectedTicket.CreationSource.ToString() } }, - ["Description"] = new cF4SDHealthCardRawData.cHealthCardTableColumn() { Values = new List() { selectedTicket.Description?.ToString() } }, - ["DescriptionHtml"] = new cF4SDHealthCardRawData.cHealthCardTableColumn() { Values = new List() { selectedTicket.DescriptionHtml?.ToString() } }, - ["Summary"] = new cF4SDHealthCardRawData.cHealthCardTableColumn() { Values = new List() { selectedTicket.Summary.ToString() } }, - ["Solution"] = new cF4SDHealthCardRawData.cHealthCardTableColumn() { Values = new List() { selectedTicket.Solution?.ToString() } }, - ["SolutionHtml"] = new cF4SDHealthCardRawData.cHealthCardTableColumn() { Values = new List() { selectedTicket.SolutionHtml?.ToString() } }, - } }; - output.Tables["M42Wpm-Ticket-History"] = new cF4SDHealthCardRawData.cHealthCardTable() + outputTable.Columns = new Dictionary() + { + ["name"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(outputTable) { Values = new List() { selectedTicket.Name } }, + ["Status"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(outputTable) { Values = new List() { ticketStatusString } }, + ["Priority"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(outputTable) { Values = new List() { selectedTicket.Priority } }, + ["AffectedUser"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(outputTable) { Values = new List() { selectedTicket.AffectedUser } }, + ["AssetName"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(outputTable) { Values = new List() { selectedTicket.Asset } }, + ["CreationDaysSinceNow"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(outputTable) { Values = new List() { selectedTicket.CreationDaysSinceNow } }, + ["CreationDate"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(outputTable) { Values = new List() { selectedTicket.CreationDate.ToUniversalTime() } }, + ["ClosingDaysSinceNow"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(outputTable) { Values = new List() { selectedTicket.ClosingDaysSinceNow } }, + ["ClosingDate"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(outputTable) { Values = new List() { selectedTicket.ClosingDate } }, + ["Category"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(outputTable) { Values = new List() { selectedTicket.Category } }, + ["CreationSource"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(outputTable) { Values = new List() { selectedTicket.CreationSource.ToString() } }, + ["Description"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(outputTable) { Values = new List() { selectedTicket.Description?.ToString() } }, + ["DescriptionHtml"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(outputTable) { Values = new List() { selectedTicket.DescriptionHtml?.ToString() } }, + ["Summary"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(outputTable) { Values = new List() { selectedTicket.Summary.ToString() } }, + ["Solution"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(outputTable) { Values = new List() { selectedTicket.Solution?.ToString() } }, + ["SolutionHtml"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(outputTable) { Values = new List() { selectedTicket.SolutionHtml?.ToString() } }, + }; + + output.Tables["M42Wpm-Tickets"] = outputTable; + + outputTable = new cF4SDHealthCardRawData.cHealthCardTable() { Name = "M42Wpm-Ticket-History", InformationClass = enumFasdInformationClass.Ticket, - IsStatic = false, - Columns = new Dictionary() - { - ["Header"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(), - ["IsVisibleForUser"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(), - ["CreationDaysSinceNow"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(), - ["time"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(), - ["Description"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(), - ["DescriptionHtml"] = new cF4SDHealthCardRawData.cHealthCardTableColumn() - } + IsStatic = false }; + outputTable.Columns = new Dictionary() + { + ["Header"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(outputTable), + ["IsVisibleForUser"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(outputTable), + ["CreationDaysSinceNow"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(outputTable), + ["time"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(outputTable), + ["Description"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(outputTable), + ["DescriptionHtml"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(outputTable) + }; + + output.Tables["M42Wpm-Ticket-History"] = outputTable; foreach (var journalItem in selectedTicket.JournalItems) { @@ -944,55 +984,63 @@ namespace C4IT.FASD.Cockpit.Communication foreach (var directLink in selectedTicket.DirectLinks) { - output.Tables["M42Wpm-Tickets"].Columns[directLink.Key] = new cF4SDHealthCardRawData.cHealthCardTableColumn() { ColumnName = directLink.Key, IsIncomplete = false, Values = new List() { directLink.Value } }; + outputTable = output.Tables["M42Wpm-Tickets"]; + if (outputTable?.Columns != null) + outputTable.Columns[directLink.Key] = new cF4SDHealthCardRawData.cHealthCardTableColumn(outputTable) { ColumnName = directLink.Key, IsIncomplete = false, Values = new List() { directLink.Value } }; } } } - output.Tables.Add("sequenceTable", new cF4SDHealthCardRawData.cHealthCardTable() + outputTable = new cF4SDHealthCardRawData.cHealthCardTable() { IsIncomplete = true, IsStatic = false, - StartingIndex = 7, - Columns = new Dictionary() + StartingIndex = 7 + }; + outputTable.Columns = new Dictionary() + { + ["sequenceColumn"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(outputTable) { - ["sequenceColumn"] = new cF4SDHealthCardRawData.cHealthCardTableColumn() - { - ColumnName = "sequenceColumn", - Values = new List() { 1, 0 } - } + ColumnName = "sequenceColumn", + Values = new List() { 1, 0 } } - }); + }; - output.Tables.Add("sequenceTable2", new cF4SDHealthCardRawData.cHealthCardTable() + output.Tables.Add("sequenceTable", outputTable); + + outputTable = new cF4SDHealthCardRawData.cHealthCardTable() { IsIncomplete = true, IsStatic = false, - StartingIndex = 7, - Columns = new Dictionary() + StartingIndex = 7 + }; + outputTable.Columns = new Dictionary() + { + ["sequenceColumn"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(outputTable) { - ["sequenceColumn"] = new cF4SDHealthCardRawData.cHealthCardTableColumn() - { - ColumnName = "sequenceColumn", - Values = new List() { 8, 1, 0 } - } + ColumnName = "sequenceColumn", + Values = new List() { 8, 1, 0 } } - }); + }; - output.Tables.Add("sequenceTable3", new cF4SDHealthCardRawData.cHealthCardTable() + output.Tables.Add("sequenceTable2", outputTable); + + outputTable = new cF4SDHealthCardRawData.cHealthCardTable() { IsIncomplete = false, StartingIndex = 0, - IsStatic = true, - Columns = new Dictionary() + IsStatic = true + }; + outputTable.Columns = new Dictionary() + { + ["sequenceColumn"] = new cF4SDHealthCardRawData.cHealthCardTableColumn(outputTable) { - ["sequenceColumn"] = new cF4SDHealthCardRawData.cHealthCardTableColumn() - { - ColumnName = "sequenceColumn", - Values = new List() { "Static" } - } + ColumnName = "sequenceColumn", + Values = new List() { "Static" } } - }); + }; + + output.Tables.Add("sequenceTable3", outputTable); output.Id = Guid.NewGuid(); @@ -1041,49 +1089,61 @@ namespace C4IT.FASD.Cockpit.Communication await Task.Delay(250); lock (CachedHealthCardRawData) { - if (!CachedHealthCardRawData.ContainsKey(Id)) - CachedHealthCardRawData[Id] = new cF4SDHealthCardRawData() { Id = Id, Tables = new Dictionary() }; + if (!CachedHealthCardRawData.TryGetValue(Id, out var _rawData)) + { + _rawData = new cF4SDHealthCardRawData() { Id = Id, Tables = new Dictionary() }; + CachedHealthCardRawData[Id] = _rawData; + } - if (CachedHealthCardRawData[Id].Tables is null) - CachedHealthCardRawData[Id].Tables = new Dictionary(); + if (_rawData.Tables is null) + _rawData.Tables = new Dictionary(); - if (!CachedHealthCardRawData[Id].Tables.ContainsKey(tableOne)) - CachedHealthCardRawData[Id].Tables[tableOne] = new cF4SDHealthCardRawData.cHealthCardTable() { Columns = new Dictionary() }; + if (!_rawData.Tables.TryGetValue(tableOne, out var _table)) + { + _table = new cF4SDHealthCardRawData.cHealthCardTable() { Name = tableOne, Columns = new Dictionary() }; + _rawData.Tables[tableOne] = _table; + } - if (!CachedHealthCardRawData[Id].Tables[tableOne].Columns.ContainsKey(columnName)) - CachedHealthCardRawData[Id].Tables[tableOne].Columns[columnName] = new cF4SDHealthCardRawData.cHealthCardTableColumn(); + if (!_table.Columns.ContainsKey(columnName)) + _table.Columns[columnName] = new cF4SDHealthCardRawData.cHealthCardTableColumn(_table); - CachedHealthCardRawData[Id].Tables[tableOne].StartingIndex = 3; - CachedHealthCardRawData[Id].Tables[tableOne].IsIncomplete = true; + _table.StartingIndex = 3; + _table.IsIncomplete = true; - if (CachedHealthCardRawData[Id].Tables[tableOne].Columns[columnName].Values.Count < 3) - CachedHealthCardRawData[Id].Tables[tableOne].Columns[columnName].Values.AddRange(new List() { 5, 4, 3, 2, 1, 0 }); + if (_table.Columns[columnName].Values.Count < 3) + _table.Columns[columnName].Values.AddRange(new List() { 5, 4, 3, 2, 1, 0 }); else - CachedHealthCardRawData[Id].Tables[tableOne].Columns[columnName].Values.InsertRange(3, new List() { 5, 4, 3, 2, 1, 0 }); + _table.Columns[columnName].Values.InsertRange(3, new List() { 5, 4, 3, 2, 1, 0 }); } await Task.Delay(250); lock (CachedHealthCardRawData) { - if (!CachedHealthCardRawData.ContainsKey(Id)) - CachedHealthCardRawData[Id] = new cF4SDHealthCardRawData() { Id = Id, Tables = new Dictionary() }; + if (!CachedHealthCardRawData.TryGetValue(Id, out var _rawData)) + { + _rawData = new cF4SDHealthCardRawData() { Id = Id, Tables = new Dictionary() }; + CachedHealthCardRawData[Id] = _rawData; + } - if (CachedHealthCardRawData[Id].Tables is null) - CachedHealthCardRawData[Id].Tables = new Dictionary(); + if (_rawData.Tables is null) + _rawData.Tables = new Dictionary(); - if (!CachedHealthCardRawData[Id].Tables.ContainsKey(tableTwo)) - CachedHealthCardRawData[Id].Tables[tableTwo] = new cF4SDHealthCardRawData.cHealthCardTable() { Columns = new Dictionary() }; + if (!_rawData.Tables.TryGetValue(tableTwo, out var _table)) + { + _table = new cF4SDHealthCardRawData.cHealthCardTable() { Name = tableTwo, Columns = new Dictionary() }; + _rawData.Tables[tableTwo] = _table; + } - if (!CachedHealthCardRawData[Id].Tables[tableTwo].Columns.ContainsKey(columnName)) - CachedHealthCardRawData[Id].Tables[tableTwo].Columns[columnName] = new cF4SDHealthCardRawData.cHealthCardTableColumn(); + if (!_table.Columns.ContainsKey(columnName)) + _table.Columns[columnName] = new cF4SDHealthCardRawData.cHealthCardTableColumn(_table); - CachedHealthCardRawData[Id].Tables[tableTwo].StartingIndex = 2; - CachedHealthCardRawData[Id].Tables[tableTwo].IsIncomplete = true; + _table.StartingIndex = 2; + _table.IsIncomplete = true; - if (CachedHealthCardRawData[Id].Tables[tableTwo].Columns[columnName].Values.Count < 2) - CachedHealthCardRawData[Id].Tables[tableTwo].Columns[columnName].Values.AddRange(new List() { 0, 3, 1, 2, 3, 8, 1, 0 }); + if (_table.Columns[columnName].Values.Count < 2) + _table.Columns[columnName].Values.AddRange(new List() { 0, 3, 1, 2, 3, 8, 1, 0 }); else - CachedHealthCardRawData[Id].Tables[tableTwo].Columns[columnName].Values.InsertRange(2, new List() { 0, 3, 1, 2, 3, 8, 1, 0 }); + _table.Columns[columnName].Values.InsertRange(2, new List() { 0, 3, 1, 2, 3, 8, 1, 0 }); } await Task.Delay(500); @@ -1092,61 +1152,79 @@ namespace C4IT.FASD.Cockpit.Communication const string numericalTable = "agnt-computer-event-numerical"; const string processorColumn = "ProcessorUsage"; - if (!CachedHealthCardRawData.ContainsKey(Id)) - CachedHealthCardRawData[Id] = new cF4SDHealthCardRawData() { Id = Id, Tables = new Dictionary() }; + if (!CachedHealthCardRawData.TryGetValue(Id, out var _rawData)) + { + _rawData = new cF4SDHealthCardRawData() { Id = Id, Tables = new Dictionary() }; + CachedHealthCardRawData[Id] = _rawData; + } - if (CachedHealthCardRawData[Id].Tables is null) - CachedHealthCardRawData[Id].Tables = new Dictionary(); + if (_rawData.Tables is null) + _rawData.Tables = new Dictionary(); - if (!CachedHealthCardRawData[Id].Tables.ContainsKey(numericalTable)) - CachedHealthCardRawData[Id].Tables[numericalTable] = new cF4SDHealthCardRawData.cHealthCardTable() { Columns = new Dictionary() }; + if (!_rawData.Tables.TryGetValue(numericalTable, out var _table)) + { + _table = new cF4SDHealthCardRawData.cHealthCardTable() { Name = numericalTable, Columns = new Dictionary() }; + _rawData.Tables[numericalTable] = _table; + } - if (!CachedHealthCardRawData[Id].Tables[numericalTable].Columns.ContainsKey(processorColumn)) - CachedHealthCardRawData[Id].Tables[numericalTable].Columns[processorColumn] = new cF4SDHealthCardRawData.cHealthCardTableColumn(); + if (!_table.Columns.ContainsKey(processorColumn)) + _table.Columns[processorColumn] = new cF4SDHealthCardRawData.cHealthCardTableColumn(_table); - CachedHealthCardRawData[Id].Tables[numericalTable].IsIncomplete = false; - CachedHealthCardRawData[Id].Tables[numericalTable].Columns[processorColumn].IsIncomplete = false; - CachedHealthCardRawData[Id].Tables[numericalTable].Columns[processorColumn].Values = new List() { 12.0, 20.0, 18.0, 15.0, 18.0, 19.0, 20.0, 26.0, 17.0, 11.0, 18.0, 16.0, 16.0, 14.0, 15.0 }; + _table.IsIncomplete = false; + _table.Columns[processorColumn].IsIncomplete = false; + _table.Columns[processorColumn].Values = new List() { 12.0, 20.0, 18.0, 15.0, 18.0, 19.0, 20.0, 26.0, 17.0, 11.0, 18.0, 16.0, 16.0, 14.0, 15.0 }; } await Task.Delay(250); lock (CachedHealthCardRawData) { - if (!CachedHealthCardRawData.ContainsKey(Id)) - CachedHealthCardRawData[Id] = new cF4SDHealthCardRawData() { Id = Id, Tables = new Dictionary() }; + if (!CachedHealthCardRawData.TryGetValue(Id, out var _rawData)) + { + _rawData = new cF4SDHealthCardRawData() { Id = Id, Tables = new Dictionary() }; + CachedHealthCardRawData[Id] = _rawData; + } - if (CachedHealthCardRawData[Id].Tables is null) - CachedHealthCardRawData[Id].Tables = new Dictionary(); + if (_rawData.Tables is null) + _rawData.Tables = new Dictionary(); - if (!CachedHealthCardRawData[Id].Tables.ContainsKey(tableOne)) - CachedHealthCardRawData[Id].Tables[tableOne] = new cF4SDHealthCardRawData.cHealthCardTable() { Columns = new Dictionary() }; + if (!_rawData.Tables.TryGetValue(tableOne, out var _table)) + { + _table = new cF4SDHealthCardRawData.cHealthCardTable() { Name = tableOne, Columns = new Dictionary() }; + _rawData.Tables[tableOne] = _table; + } - if (!CachedHealthCardRawData[Id].Tables[tableOne].Columns.ContainsKey(columnName)) - CachedHealthCardRawData[Id].Tables[tableOne].Columns[columnName] = new cF4SDHealthCardRawData.cHealthCardTableColumn(); + if (!_table.Columns.TryGetValue(columnName, out var _column)) + { + _column = new cF4SDHealthCardRawData.cHealthCardTableColumn(_table); + _table.Columns[columnName] = _column; + } - CachedHealthCardRawData[Id].Tables[tableOne].StartingIndex = 0; - CachedHealthCardRawData[Id].Tables[tableOne].IsIncomplete = false; + _table.StartingIndex = 0; + _table.IsIncomplete = false; - if (CachedHealthCardRawData[Id].Tables[tableOne].Columns[columnName].Values.Count < 0) - CachedHealthCardRawData[Id].Tables[tableOne].Columns[columnName].Values.AddRange(new List() { 8, 7, 6 }); + if (_column.Values.Count < 0) + _column.Values.AddRange(new List() { 8, 7, 6 }); else - CachedHealthCardRawData[Id].Tables[tableOne].Columns[columnName].Values.InsertRange(0, new List() { 8, 7, 6 }); + _column.Values.InsertRange(0, new List() { 8, 7, 6 }); - if (!CachedHealthCardRawData[Id].Tables.ContainsKey(tableTwo)) - CachedHealthCardRawData[Id].Tables[tableTwo] = new cF4SDHealthCardRawData.cHealthCardTable() { Columns = new Dictionary() }; + if (!_rawData.Tables.TryGetValue(tableTwo, out var _table2)) + { + _table2 = new cF4SDHealthCardRawData.cHealthCardTable() { Name = tableTwo, Columns = new Dictionary() }; + _rawData.Tables[tableTwo] = _table2; + } - if (!CachedHealthCardRawData[Id].Tables[tableTwo].Columns.ContainsKey(columnName)) - CachedHealthCardRawData[Id].Tables[tableTwo].Columns[columnName] = new cF4SDHealthCardRawData.cHealthCardTableColumn(); + if (!_rawData.Tables[tableTwo].Columns.ContainsKey(columnName)) + CachedHealthCardRawData[Id].Tables[tableTwo].Columns[columnName] = new cF4SDHealthCardRawData.cHealthCardTableColumn(_table2); - CachedHealthCardRawData[Id].Tables[tableTwo].StartingIndex = 1; - CachedHealthCardRawData[Id].Tables[tableTwo].IsIncomplete = false; + _table2.StartingIndex = 1; + _table2.IsIncomplete = false; - if (CachedHealthCardRawData[Id].Tables[tableTwo].Columns[columnName].Values.Count < 1) - CachedHealthCardRawData[Id].Tables[tableTwo].Columns[columnName].Values.AddRange(new List() { 1 }); + if (_table2.Columns[columnName].Values.Count < 1) + _table2.Columns[columnName].Values.AddRange(new List() { 1 }); else - CachedHealthCardRawData[Id].Tables[tableTwo].Columns[columnName].Values.InsertRange(1, new List() { 1 }); + _table2.Columns[columnName].Values.InsertRange(1, new List() { 1 }); } diff --git a/FasdCockpitCommunicationDemo/app.config b/FasdCockpitCommunicationDemo/app.config new file mode 100644 index 0000000..db5dd16 --- /dev/null +++ b/FasdCockpitCommunicationDemo/app.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/FasdCockpitCommunicationDemo/cF4SDHealthCardJsonRawData.cs b/FasdCockpitCommunicationDemo/cF4SDHealthCardJsonRawData.cs index fcc9708..e54f6ea 100644 --- a/FasdCockpitCommunicationDemo/cF4SDHealthCardJsonRawData.cs +++ b/FasdCockpitCommunicationDemo/cF4SDHealthCardJsonRawData.cs @@ -43,25 +43,26 @@ namespace C4IT.FASD.Base if (output.Tables.ContainsKey(table.Name)) continue; - var tableColumns = new Dictionary(); - - foreach (var column in table.Columns) - { - if (tableColumns.ContainsKey(column.ColumnName)) - continue; - - var values = new List(); - values.AddRange(column.Values); - tableColumns.Add(column.ColumnName, new cF4SDHealthCardRawData.cHealthCardTableColumn() { ColumnName = column.ColumnName, Values = values }); - } - - output.Tables.Add(table.Name, new cF4SDHealthCardRawData.cHealthCardTable() + var outputTable = new cF4SDHealthCardRawData.cHealthCardTable() { Name = table.Name, IsStatic = table.IsStatic, TimeFrames = table.TimeFrames, - Columns = tableColumns - }); + }; + + outputTable.Columns = new Dictionary(); + + foreach (var column in table.Columns) + { + if (outputTable.Columns.ContainsKey(column.ColumnName)) + continue; + + var values = new List(); + values.AddRange(column.Values); + outputTable.Columns.Add(column.ColumnName, new cF4SDHealthCardRawData.cHealthCardTableColumn(outputTable) { ColumnName = column.ColumnName, Values = values }); + } + + output.Tables.Add(table.Name, outputTable); } } catch (Exception E) diff --git a/FasdCockpitCommunicationDemo/packages.config b/FasdCockpitCommunicationDemo/packages.config index fef83be..17ab3be 100644 --- a/FasdCockpitCommunicationDemo/packages.config +++ b/FasdCockpitCommunicationDemo/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/FasdDesktopUi/App.config b/FasdDesktopUi/App.config index 64336ea..cb4dfb7 100644 --- a/FasdDesktopUi/App.config +++ b/FasdDesktopUi/App.config @@ -25,7 +25,11 @@ - + + + + + diff --git a/FasdDesktopUi/App.xaml.cs b/FasdDesktopUi/App.xaml.cs index 0f204c4..1a7a220 100644 --- a/FasdDesktopUi/App.xaml.cs +++ b/FasdDesktopUi/App.xaml.cs @@ -3,10 +3,11 @@ using C4IT.FASD.Cockpit.Communication; using C4IT.FASD.Security; using C4IT.Graphics; using C4IT.Logging; -using C4IT.MultiLanguage; -using FasdDesktopUi.Basics; -using FasdDesktopUi.Basics.Helper; -using FasdDesktopUi.Basics.Models; +using C4IT.MultiLanguage; +using FasdDesktopUi.Basics; +using FasdDesktopUi.Basics.Helper; +using FasdDesktopUi.Basics.Models; +using FasdDesktopUi.Basics.Services.Models; using FasdDesktopUi.Pages.CustomMessageBox; using FasdDesktopUi.Pages.PhoneSettingsPage; using FasdDesktopUi.Pages.SearchPage; @@ -35,10 +36,11 @@ namespace FasdDesktopUi static public System.Windows.Forms.ToolStripItem M42OptionMenuItem = null; - public System.Windows.Forms.NotifyIcon notifyIcon = new System.Windows.Forms.NotifyIcon() { Text = $"First Aid Service Desk" }; - public bool UseOsLanguage = string.IsNullOrEmpty(cFasdCockpitConfig.Instance.SelectedLanguage); - - private TrayTicketNotificationManager _ticketTrayNotification; + public System.Windows.Forms.NotifyIcon notifyIcon = new System.Windows.Forms.NotifyIcon() { Text = $"First Aid Service Desk" }; + public bool UseOsLanguage = string.IsNullOrEmpty(cFasdCockpitConfig.Instance.SelectedLanguage); + + private TrayTicketNotificationManager _ticketTrayNotification; + private TileScope? _pendingTicketOverviewScope; private async void Application_Startup(object sender, StartupEventArgs e) { @@ -166,42 +168,50 @@ namespace FasdDesktopUi } - private void NotifyIcon_Click(object sender, EventArgs e) - { - try - { - if (e is System.Windows.Forms.MouseEventArgs mouseEventArgs) - if (mouseEventArgs.Button == System.Windows.Forms.MouseButtons.Right) - return; + private void NotifyIcon_Click(object sender, EventArgs e) + { + try + { + if (e is System.Windows.Forms.MouseEventArgs mouseEventArgs) + if (mouseEventArgs.Button == System.Windows.Forms.MouseButtons.Right) + return; - var searchView = SearchPageView.Instance; - if (searchView == null) - return; - -#if isDemo - var hasNotification = HasPendingTicketOverviewNotification(); - - if (searchView.IsVisible && !hasNotification) - { - searchView.Hide(); - return; - } - - if (!searchView.IsVisible) - searchView.ActivateSearchView(); - else - searchView.BringToFrontPreserveState(); - - searchView.ShowTicketOverviewPane(); - - if (hasNotification) - ClearTicketOverviewTrayNotification(); -#else - if (SearchPageView.Instance.IsVisible) - SearchPageView.Instance.Hide(); - else - SearchPageView.Instance.ActivateSearchView(); + var searchView = SearchPageView.Instance; + if (searchView == null) + return; + + var hasNotification = HasPendingTicketOverviewNotification(); + if (hasNotification) + { + if (!searchView.IsVisible) + searchView.ActivateSearchView(); + else + searchView.BringToFrontPreserveState(); + + searchView.ShowTicketOverviewPaneForScope(PendingTicketOverviewScope); + ClearTicketOverviewTrayNotification(); + return; + } + +#if isDemo + if (searchView.IsVisible) + { + searchView.Hide(); + return; + } + + if (!searchView.IsVisible) + searchView.ActivateSearchView(); + else + searchView.BringToFrontPreserveState(); + + searchView.ShowTicketOverviewPane(); +#else + if (SearchPageView.Instance.IsVisible) + SearchPageView.Instance.Hide(); + else + SearchPageView.Instance.ActivateSearchView(); #endif } catch (Exception E) @@ -271,48 +281,56 @@ namespace FasdDesktopUi } } - private void NotifyIcon_BalloonTipClicked(object sender, EventArgs e) - { - try - { - SearchPageView.Instance?.BringToFrontPreserveState(); - SearchPageView.Instance?.ShowTicketOverviewPane(); - ClearTicketOverviewTrayNotification(); - } - catch (Exception E) - { - LogException(E); - } - } + private void NotifyIcon_BalloonTipClicked(object sender, EventArgs e) + { + try + { + SearchPageView.Instance?.BringToFrontPreserveState(); + SearchPageView.Instance?.ShowTicketOverviewPaneForScope(PendingTicketOverviewScope); + ClearTicketOverviewTrayNotification(); + } + catch (Exception E) + { + LogException(E); + } + } private bool HasPendingTicketOverviewNotification() { return _ticketTrayNotification?.HasNotification ?? false; } - public void ShowTicketOverviewTrayNotification(string message) - { - try - { - _ticketTrayNotification?.Show(message); - } + public void ShowTicketOverviewTrayNotification(string message) + { + try + { + _ticketTrayNotification?.Show(message); + } catch (Exception ex) { LogException(ex); } } - public void ClearTicketOverviewTrayNotification() - { - try - { - _ticketTrayNotification?.Clear(); - } - catch (Exception ex) - { - LogException(ex); - } - } + public void ClearTicketOverviewTrayNotification() + { + try + { + _pendingTicketOverviewScope = null; + _ticketTrayNotification?.Clear(); + } + catch (Exception ex) + { + LogException(ex); + } + } + + public void SetTicketOverviewNotificationScope(TileScope? scope) + { + _pendingTicketOverviewScope = scope; + } + + public TileScope? PendingTicketOverviewScope => _pendingTicketOverviewScope; private System.Windows.Forms.ToolStripItem SetUpNotifyIconLanguageOption() { diff --git a/FasdDesktopUi/Basics/CustomEvents/HeadingDataEventArgs.cs b/FasdDesktopUi/Basics/CustomEvents/HeadingDataEventArgs.cs new file mode 100644 index 0000000..bd21880 --- /dev/null +++ b/FasdDesktopUi/Basics/CustomEvents/HeadingDataEventArgs.cs @@ -0,0 +1,16 @@ +using FasdDesktopUi.Basics.Models; +using System; +using System.Collections.Generic; + +namespace FasdDesktopUi.Basics.CustomEvents +{ + public class HeadingDataEventArgs : EventArgs + { + public IEnumerable NewValue { get; } + + public HeadingDataEventArgs(IEnumerable headingData) : base() + { + NewValue = headingData; + } + } +} diff --git a/FasdDesktopUi/Basics/Services/RelationService/RelationEventArgs.cs b/FasdDesktopUi/Basics/CustomEvents/RelationEventArgs.cs similarity index 59% rename from FasdDesktopUi/Basics/Services/RelationService/RelationEventArgs.cs rename to FasdDesktopUi/Basics/CustomEvents/RelationEventArgs.cs index eb30d3d..6acbea3 100644 --- a/FasdDesktopUi/Basics/Services/RelationService/RelationEventArgs.cs +++ b/FasdDesktopUi/Basics/CustomEvents/RelationEventArgs.cs @@ -1,11 +1,8 @@ using C4IT.FASD.Base; using System; -using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace FasdDesktopUi.Basics.Services.RelationService +namespace FasdDesktopUi.Basics.CustomEvents { public class RelationEventArgs : EventArgs { diff --git a/FasdDesktopUi/Basics/CustomEvents/SupportCaseDataEventArgs.cs b/FasdDesktopUi/Basics/CustomEvents/SupportCaseDataEventArgs.cs new file mode 100644 index 0000000..ba5f22d --- /dev/null +++ b/FasdDesktopUi/Basics/CustomEvents/SupportCaseDataEventArgs.cs @@ -0,0 +1,12 @@ +using C4IT.FASD.Base; +using System; +using System.Collections.Generic; + +namespace FasdDesktopUi.Basics.CustomEvents +{ + public class SupportCaseDataEventArgs : EventArgs + { + public cF4sdApiSearchResultRelation Relation { get; set; } + public IEnumerable DataTables { get; set; } + } +} diff --git a/FasdDesktopUi/Basics/Helper/HealthCardDataHelper.cs b/FasdDesktopUi/Basics/Helper/HealthCardDataHelper.cs index b5a6293..ad284b4 100644 --- a/FasdDesktopUi/Basics/Helper/HealthCardDataHelper.cs +++ b/FasdDesktopUi/Basics/Helper/HealthCardDataHelper.cs @@ -15,7 +15,6 @@ using C4IT.FASD.Base; using C4IT.FASD.Cockpit.Communication; using C4IT.Logging; using C4IT.MultiLanguage; -using C4IT.XML; using F4SD_AdaptableIcon.Enums; @@ -26,6 +25,10 @@ using FasdDesktopUi.Basics.UiActions; using FasdDesktopUi.Pages.DetailsPage.Models; using FasdDesktopUi.Pages.SlimPage.Models; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Serialization; + using static C4IT.FASD.Base.cF4SDHealthCardRawData; using static C4IT.Logging.cLogManager; @@ -78,6 +81,7 @@ namespace FasdDesktopUi.Basics.Helper this.dataProvider = dataProvider; _menuDataProvider = new MenuItemDataProvider(dataProvider); cUtility.RawValueFormatter.SetDefaultCulture(new CultureInfo(cFasdCockpitConfig.Instance.SelectedLanguage)); + cUtility.RawValueFormatter.SetDefaultTimeZone(TimeZoneInfo.Local); HistoryData = new cHealthCardHistoryDataHelper(this); SlimCard = new cHealthCardSlimPageHelper(this); @@ -246,6 +250,9 @@ namespace FasdDesktopUi.Basics.Helper { List output = new List(); + if (healthCardColumn?.Values == null) + return output; + try { for (int i = 0; i < startingIndex; i++) @@ -263,6 +270,13 @@ namespace FasdDesktopUi.Basics.Helper return output; } + private List GetStateValues(cHealthCardTableColumn tableColumn) + { + if (tableColumn == null) + return new List(); + else return GetValuesOfHealthCardTableColumn(tableColumn.Table.StartingIndex, tableColumn); + } + private List GetStateValues(cValueAddress DatabaseInfo, bool isStatic) { List output = new List(); @@ -313,9 +327,7 @@ namespace FasdDesktopUi.Basics.Helper rawValueLeveling = GetStateValueAt(referencedStateDefinition.DatabaseInfo, 0, true); } - var _color = stateDefinitionForLeveling is cHealthCardStateAggregation aggregation ? - GetSummaryStatusColor(aggregation.States, true) : GetHighlightColor(rawValueLeveling, stateDefinitionForLeveling); - + var _color = GetHighlightColor(rawValueLeveling, stateDefinitionForLeveling, 0, true); return _color; } catch (Exception ex) @@ -325,63 +337,64 @@ namespace FasdDesktopUi.Basics.Helper return enumHighlightColor.none; } - private enumHighlightColor GetHighlightColor(object value, cHealthCardStateBase stateDefinition, int referenceDays = 0) + private enumHighlightColor GetHighlightColor(object value, cHealthCardStateBase stateDefinition, int referenceDays, bool isStatic) { - return GetHighlightColor(new cStateThresholdValues() { Value = value, StateDefinition = stateDefinition, ReferenceDays = referenceDays }); - } + if (stateDefinition == null) + return enumHighlightColor.none; - private enumHighlightColor GetHighlightColor(cStateThresholdValues thresholdValues) - { enumHighlightColor output = enumHighlightColor.none; + if (stateDefinition is cHealthCardStateAggregation _stateAggregation) + return GetSummaryStatusColor(_stateAggregation.States, isStatic, referenceDays) ?? enumHighlightColor.none; + try { - if (thresholdValues.Value == null) + if (value == null) return output; - if (thresholdValues.StateDefinition is cHealthCardStateLevel stateLevel) + if (stateDefinition is cHealthCardStateLevel stateLevel) { - var valueDouble = cF4SDHealthCardRawData.GetDouble(thresholdValues.Value); + var valueDouble = cF4SDHealthCardRawData.GetDouble(value); if (valueDouble != null) { if (stateLevel.IsDirectionUp) - output = valueDouble >= stateLevel.Error ? enumHighlightColor.red : valueDouble >= stateLevel.Warning ? enumHighlightColor.orange : thresholdValues.StateDefinition.IsNotTransparent ? enumHighlightColor.green : enumHighlightColor.none; + output = valueDouble >= stateLevel.Error ? enumHighlightColor.red : valueDouble >= stateLevel.Warning ? enumHighlightColor.orange : stateDefinition.IsNotTransparent ? enumHighlightColor.green : enumHighlightColor.none; else - output = valueDouble <= stateLevel.Error ? enumHighlightColor.red : valueDouble <= stateLevel.Warning ? enumHighlightColor.orange : thresholdValues.StateDefinition.IsNotTransparent ? enumHighlightColor.green : enumHighlightColor.none; + output = valueDouble <= stateLevel.Error ? enumHighlightColor.red : valueDouble <= stateLevel.Warning ? enumHighlightColor.orange : stateDefinition.IsNotTransparent ? enumHighlightColor.green : enumHighlightColor.none; } } - else if (thresholdValues.StateDefinition is cHealthCardStateVersion stateVersion) + else if (stateDefinition is cHealthCardStateVersion stateVersion) { - var valueVersion = cF4SDHealthCardRawData.GetVersion(thresholdValues.Value); + var valueVersion = cF4SDHealthCardRawData.GetVersion(value); if (valueVersion != null) { if (stateVersion.IsDirectionUp) - output = valueVersion >= stateVersion.Error ? enumHighlightColor.red : valueVersion >= stateVersion.Warning ? enumHighlightColor.orange : thresholdValues.StateDefinition.IsNotTransparent ? enumHighlightColor.green : enumHighlightColor.none; + output = valueVersion >= stateVersion.Error ? enumHighlightColor.red : valueVersion >= stateVersion.Warning ? enumHighlightColor.orange : stateDefinition.IsNotTransparent ? enumHighlightColor.green : enumHighlightColor.none; else - output = valueVersion <= stateVersion.Error ? enumHighlightColor.red : valueVersion <= stateVersion.Warning ? enumHighlightColor.orange : thresholdValues.StateDefinition.IsNotTransparent ? enumHighlightColor.green : enumHighlightColor.none; + output = valueVersion <= stateVersion.Error ? enumHighlightColor.red : valueVersion <= stateVersion.Warning ? enumHighlightColor.orange : stateDefinition.IsNotTransparent ? enumHighlightColor.green : enumHighlightColor.none; } } - else if (thresholdValues.StateDefinition is cHealthCardStateDateTime stateDateTime) + else if (stateDefinition is cHealthCardStateDateTime stateDateTime) { - var valueDateTime = cF4SDHealthCardRawData.GetDateTime(thresholdValues.Value); + var valueDateTime = cF4SDHealthCardRawData.GetDateTime(value); if (valueDateTime != null) { var tempDateTime = valueDateTime ?? DateTime.Now; - var differenceHours = Math.Floor((DateTime.UtcNow.AddDays(-thresholdValues.ReferenceDays) - tempDateTime).TotalHours); + var differenceHours = Math.Floor((DateTime.UtcNow.AddDays(-referenceDays) - tempDateTime).TotalHours); if (stateDateTime.IsDirectionUp) - output = differenceHours >= stateDateTime.ErrorHours ? enumHighlightColor.red : differenceHours >= stateDateTime.WarningHours ? enumHighlightColor.orange : thresholdValues.StateDefinition.IsNotTransparent ? enumHighlightColor.green : enumHighlightColor.none; + output = differenceHours >= stateDateTime.ErrorHours ? enumHighlightColor.red : differenceHours >= stateDateTime.WarningHours ? enumHighlightColor.orange : stateDefinition.IsNotTransparent ? enumHighlightColor.green : enumHighlightColor.none; else - output = differenceHours <= stateDateTime.ErrorHours ? enumHighlightColor.red : differenceHours <= stateDateTime.WarningHours ? enumHighlightColor.orange : thresholdValues.StateDefinition.IsNotTransparent ? enumHighlightColor.green : enumHighlightColor.none; + output = differenceHours <= stateDateTime.ErrorHours ? enumHighlightColor.red : differenceHours <= stateDateTime.WarningHours ? enumHighlightColor.orange : stateDefinition.IsNotTransparent ? enumHighlightColor.green : enumHighlightColor.none; } } - else if (thresholdValues.StateDefinition is cHealthCardStateInfo) + else if (stateDefinition is cHealthCardStateInfo) { - output = thresholdValues.StateDefinition.IsNotTransparent ? enumHighlightColor.blue : enumHighlightColor.none; + output = stateDefinition.IsNotTransparent ? enumHighlightColor.blue : enumHighlightColor.none; } - else if (thresholdValues.StateDefinition is cHealthCardStateTranslation stateTranslation) + else if (stateDefinition is cHealthCardStateTranslation stateTranslation) { var abstractTranslation = cF4SDHealthCardConfig.GetTranslationsWithName(stateTranslation, stateTranslation.Translation); if (abstractTranslation == null || !(abstractTranslation is cHealthCardTranslator translation)) @@ -390,7 +403,7 @@ namespace FasdDesktopUi.Basics.Helper enumHealthCardStateLevel translationStateLevel = translation.DefaultTranslation?.StateLevel ?? enumHealthCardStateLevel.Info; foreach (var translationEntry in translation.Translations) { - if (translationEntry.Values.Any(translationValue => thresholdValues.Value.ToString().Equals(translationValue, StringComparison.InvariantCultureIgnoreCase))) + if (translationEntry.Values.Any(translationValue => value.ToString().Equals(translationValue, StringComparison.InvariantCultureIgnoreCase))) translationStateLevel = translationEntry.StateLevel; } @@ -400,7 +413,7 @@ namespace FasdDesktopUi.Basics.Helper output = enumHighlightColor.none; break; case enumHealthCardStateLevel.Ok: - if (thresholdValues.StateDefinition.IsNotTransparent) + if (stateDefinition.IsNotTransparent) output = enumHighlightColor.green; break; case enumHealthCardStateLevel.Warning: @@ -410,12 +423,12 @@ namespace FasdDesktopUi.Basics.Helper output = enumHighlightColor.red; break; case enumHealthCardStateLevel.Info: - if (thresholdValues.StateDefinition.IsNotTransparent) + if (stateDefinition.IsNotTransparent) output = enumHighlightColor.blue; break; } } - else if (thresholdValues.StateDefinition is cHealthCardStateRefLink stateRefLink) + else if (stateDefinition is cHealthCardStateRefLink stateRefLink) { //if (cHealthCardPrerequisites.GetReferencableStates(SelectedHealthCard).TryGetValue(stateRefLink.Reference, out var referencedState)) // output = GetHighlightColor(thresholdValues); @@ -428,9 +441,9 @@ namespace FasdDesktopUi.Basics.Helper return output; } - private enumHighlightColor GetSummaryStatusColor(List stateDefinitions, bool isStatic, int dayIndex = 0) + private enumHighlightColor? GetSummaryStatusColor(List stateDefinitions, bool isStatic, int dayIndex = 0) { - enumHighlightColor output = enumHighlightColor.none; + enumHighlightColor? output = null; try { foreach (var stateDefinition in stateDefinitions) @@ -438,20 +451,20 @@ namespace FasdDesktopUi.Basics.Helper if (!IsUiVisible(stateDefinition, dataProvider.NamedParameterEntries)) continue; - var tempColor = enumHighlightColor.none; var stateValue = GetStateValueAt(stateDefinition.DatabaseInfo, dayIndex, isStatic); + enumHighlightColor? tempColor = null; + if (stateValue != null) + { + tempColor = GetHighlightColor(stateValue, stateDefinition, dayIndex, isStatic); + if (tempColor == enumHighlightColor.none && stateValue != null) + tempColor = enumHighlightColor.green; + } - if (stateDefinition is cHealthCardStateAggregation aggregationState) - tempColor = GetSummaryStatusColor(aggregationState.States, isStatic, dayIndex); - else - tempColor = GetHighlightColor(stateValue, stateDefinition, referenceDays: dayIndex); - - - if (tempColor == enumHighlightColor.none && stateValue != null) - tempColor = enumHighlightColor.green; - - output = (enumHighlightColor)Math.Max((int)tempColor, (int)output); + if (output == null) + output = tempColor; + else if (tempColor != null) + output = (enumHighlightColor)Math.Max((int)tempColor, (int)output); } } catch (Exception E) @@ -461,6 +474,134 @@ namespace FasdDesktopUi.Basics.Helper return output; } + private cDataHistoryValueModel ProcessSingleStateValue(cProcessStateRequirements Requirements, object value, object thresholdValue, int columnIndex) + { + try + { + var cellContent = new cDataHistoryValueModel() { Content = null, HighlightColor = enumHighlightColor.none, IsLoading = Requirements.valueTableColumn?.IsIncomplete ?? false }; + + if (Requirements.valueState is cHealthCardStateAggregation stateAggregation) + { + cellContent.Content = "Ø"; + cellContent.HighlightColor = GetSummaryStatusColor(stateAggregation.States, Requirements.isStatic, columnIndex); + if (cellContent.HighlightColor == null) + { + cellContent.Content = "-"; + cellContent.HighlightColor = enumHighlightColor.none; + } + } + else + { + FormattingOptions options = new FormattingOptions() { ReferenceDate = DateTime.UtcNow.Date.AddDays(columnIndex), TimeZone = TimeZoneInfo.Local }; + var _c = cUtility.RawValueFormatter.GetDisplayValue(value, Requirements.valueState.DisplayType, options); + if (!string.IsNullOrWhiteSpace(_c)) + cellContent.Content = _c; + + cellContent.ThresholdValues = new cStateThresholdValues() { Value = thresholdValue, StateDefinition = Requirements.valueState.StateProcessingRequirements.tresholdState, ReferenceDays = columnIndex }; + cellContent.HighlightColor = GetHighlightColor(cellContent.ThresholdValues.Value, Requirements.valueState.StateProcessingRequirements.tresholdState, columnIndex, Requirements.isStatic); + + if (Requirements.valueState.StateProcessingRequirements.translation != null && cellContent.Content != null) + { + var translationValue = Requirements.valueState.StateProcessingRequirements.translation.DefaultTranslation?.Translation.GetValue() ?? cellContent.Content; + foreach (var translationEntry in Requirements.valueState.StateProcessingRequirements.translation.Translations) + { + if (translationEntry.Values.Any(_val => cellContent.Content.Equals(_val, StringComparison.CurrentCultureIgnoreCase))) + translationValue = translationEntry.Translation.GetValue(); + } + cellContent.Content = translationValue; + } + + if (cellContent.Content == null) + cellContent.Content = "-"; + + if (!cellContent.IsLoading && Requirements.valueTableColumn?.Table != null) + { + int maxColumnCount = 0; + if (Requirements.valueTableColumn.Table.Columns?.Count > 0) + maxColumnCount = Requirements.valueTableColumn.Table.Columns.Max(column => column.Value?.Values?.Count ?? 1); + + if (columnIndex < Requirements.valueTableColumn.Table.StartingIndex || columnIndex >= Requirements.valueTableColumn.Table.StartingIndex + maxColumnCount) + cellContent.IsLoading = Requirements.valueTableColumn.Table.IsIncomplete; + } + } + + if (Requirements.valueState.Details != null && value != null) + cellContent.UiAction = new cShowDetailedDataAction(Requirements.valueState, columnIndex); + + return cellContent; + } + catch (Exception E) + { + LogException(E); + } + + return null; + } + + private cProcessStateRequirements CreateProcessStateRequirements(cHealthCardStateBase stateDefinition, bool isStatic) + { + var ProcessRequirements = new cProcessStateRequirements() + { + valueState = stateDefinition, + valueTableColumn = null, + isStatic = isStatic, + Values = new List(), + ThresholdValues = new List() + }; + + try + { + // get the global requirements one which are not support case dependent + if (stateDefinition.StateProcessingRequirements == null) + { + stateDefinition.StateProcessingRequirements = new cHealthCardStateBase.cStateProcessingRequirements() { tresholdState = stateDefinition, translation = null }; + + // if we have a ref link, get the referenced stateDefinition and state values + ProcessRequirements.ThresholdValues = ProcessRequirements.Values; + if (stateDefinition is cHealthCardStateRefLink ReferencedLinkState) + { + var refState = cF4SDHealthCardConfig.GetReferencableStateWithName(ReferencedLinkState.ParentNode, ReferencedLinkState.Reference); + if (refState != null) + { + stateDefinition.StateProcessingRequirements.tresholdState = refState; + } + } + + //in state is translation state, get the translation + if (stateDefinition is cHealthCardStateTranslation _StateTranslation) + { + var abstractTranslation = cF4SDHealthCardConfig.GetTranslationsWithName(_StateTranslation, _StateTranslation.Translation); + if (abstractTranslation is cHealthCardTranslator castedTranslation) + stateDefinition.StateProcessingRequirements.translation = castedTranslation; + } + + } + + // get the state values + if (stateDefinition.DatabaseInfo != null) + { + var _table = HealthCardRawData.GetTableByName(stateDefinition.DatabaseInfo.ValueTable, isStatic); + if (_table != null) + { + _table.Columns.TryGetValue(stateDefinition.DatabaseInfo.ValueColumn, out ProcessRequirements.valueTableColumn); + ProcessRequirements.Values = GetValuesOfHealthCardTableColumn(_table.StartingIndex, ProcessRequirements.valueTableColumn); + } + } + + // get the treshold values + if (stateDefinition == stateDefinition.StateProcessingRequirements.tresholdState) + ProcessRequirements.ThresholdValues = ProcessRequirements.Values; + else + ProcessRequirements.ThresholdValues = GetStateValues(stateDefinition.StateProcessingRequirements.tresholdState.DatabaseInfo, isStatic); + } + catch (Exception E) + { + LogException(E); + } + + return ProcessRequirements; + } + private cUiActionBase GetUiActionByQuickActionNames(List names, string uiActionName, string uiActionDescription) { try @@ -961,10 +1102,10 @@ namespace FasdDesktopUi.Basics.Helper string namedParameterTitle = namedParameter.Value.Names.GetValue(); var parameterValue = GetStateValueAt(namedParameter.Value.DatabaseInfo, 0, true); - string namedParameterValue = cUtility.RawValueFormatter.GetDisplayValue(parameterValue, cUtility.GetRawValueType(namedParameter.Value.Display)); + string namedParameterValue = cUtility.RawValueFormatter.GetDisplayValue(parameterValue, namedParameter.Value.Display); if (!dataProvider.NamedParameterEntries.ContainsKey(namedParameter.Value.ParameterName)) - dataProvider.NamedParameterEntries.Add(namedParameter.Value.ParameterName, new cNamedParameterEntryPointer(dataProvider, namedParameter.Value.DatabaseInfo, cUtility.GetRawValueType(namedParameter.Value.Display)) { Title = namedParameterTitle }); + dataProvider.NamedParameterEntries.Add(namedParameter.Value.ParameterName, new cNamedParameterEntryPointer(dataProvider, namedParameter.Value.DatabaseInfo, namedParameter.Value.Display) { Title = namedParameterTitle }); } catch (Exception ex) { @@ -997,6 +1138,15 @@ namespace FasdDesktopUi.Basics.Helper #endregion + private class cProcessStateRequirements + { + internal cHealthCardStateBase valueState; + internal bool isStatic; + internal cHealthCardTableColumn valueTableColumn; + internal List Values; + internal List ThresholdValues; + } + public abstract class cHealthCardStateSubHelper { protected readonly cHealthCardDataHelper parent; @@ -1055,7 +1205,7 @@ namespace FasdDesktopUi.Basics.Helper CultureInfo culture = new CultureInfo(cMultiLanguageSupport.CurrentLanguage); var valueColumnHeader = i != 0 ? DateTime.Today.AddDays(-i).ToString(cMultiLanguageSupport.GetItem("Global.Date.Format.ShortDateWithDay", "ddd. dd.MM."), culture) : cMultiLanguageSupport.GetItem("Global.Date.Today"); var summaryStatusColor = parent.GetSummaryStatusColor(stateCategoryDefinition.States, false, i); - var valueColumn = new DetailsPageDataHistoryColumnModel() { ColumnValues = new List(), Content = valueColumnHeader, HighlightColor = summaryStatusColor }; + var valueColumn = new DetailsPageDataHistoryColumnModel() { ColumnValues = new List(), Content = valueColumnHeader, HighlightColor = summaryStatusColor ?? enumHighlightColor.none }; historySectionValueColumns.Add(valueColumn); } @@ -1115,88 +1265,15 @@ namespace FasdDesktopUi.Basics.Helper private void ProcessState(cHealthCardStateBase stateDefinition, int valueColumnCount, bool isStatic, List historySectionValueColumns) { - var stateValues = parent.GetStateValues(stateDefinition.DatabaseInfo, isStatic); - //in case state is translationstate, get translation to avoid calling GetTranslationWithName method for every column - cHealthCardStateTranslation stateTranslation = null; - cHealthCardTranslator translation = null; - if (stateDefinition is cHealthCardStateTranslation tempStateTranslation) - { - stateTranslation = tempStateTranslation; - var abstractTranslation = cF4SDHealthCardConfig.GetTranslationsWithName(tempStateTranslation, stateTranslation.Translation); - - if (abstractTranslation is cHealthCardTranslator castedTranslation) - translation = castedTranslation; - } - else - tempStateTranslation = null; + var ProcessRequirements = parent.CreateProcessStateRequirements(stateDefinition, isStatic); for (int i = 0; i < valueColumnCount; i++) { - string cellContentString = stateDefinition is cHealthCardStateAggregation ? "Ø" : "-"; - enumHighlightColor cellContentColor = enumHighlightColor.none; - cStateThresholdValues thresholdValues = null; + var Value = ProcessRequirements.Values?.Count > i ? ProcessRequirements.Values[i] : null; + var thresholdValue = ProcessRequirements.ThresholdValues?.Count > i ? ProcessRequirements.ThresholdValues[i] : null; - if (stateValues.Count > i) - { - FormattingOptions options = new FormattingOptions() { ReferenceDate = DateTime.UtcNow.Date.AddDays(i) }; - thresholdValues = new cStateThresholdValues() { Value = stateValues[i], StateDefinition = stateDefinition, ReferenceDays = i }; - cellContentString = cUtility.RawValueFormatter.GetDisplayValue(stateValues[i], cUtility.GetRawValueType(stateDefinition.DisplayType), options); - if (string.IsNullOrWhiteSpace(cellContentString)) - cellContentString = "-"; - cellContentColor = parent.GetHighlightColor(thresholdValues); - } - - if (stateDefinition is cHealthCardStateAggregation stateAggregation) - { - cellContentColor = parent.GetSummaryStatusColor(stateAggregation.States, isStatic, i); - } - - if (stateTranslation != null) - { - if (translation != null && cellContentString != "-") - { - var translationValue = translation.DefaultTranslation?.Translation.GetValue() ?? cellContentString; - foreach (var translationEntry in translation.Translations) - { - if (cellContentString != null) - if (translationEntry.Values.Any(value => cellContentString.Equals(value, StringComparison.CurrentCultureIgnoreCase))) - translationValue = translationEntry.Translation.GetValue(); - } - cellContentString = translationValue; - } - } - - bool isStateRowLoading = false; - if (stateDefinition.DatabaseInfo != null) - { - var stateTable = HealthCardRawData.GetTableByName(stateDefinition.DatabaseInfo.ValueTable, isStatic); - - if (stateTable != null) - { - int maxColumnCount = 0; - if (stateTable?.Columns?.Count > 0) - maxColumnCount = stateTable.Columns.Max(column => column.Value?.Values?.Count ?? 1); - - if (i < stateTable.StartingIndex || i >= stateTable.StartingIndex + maxColumnCount) - isStateRowLoading = stateTable.IsIncomplete; - } - } - - - if (stateDefinition.DatabaseInfo != null) - { - var stateTable = HealthCardRawData.GetTableByName(stateDefinition.DatabaseInfo.ValueTable, isStatic); - - if (stateTable != null) - if (stateTable.Columns.TryGetValue(stateDefinition.DatabaseInfo.ValueColumn, out var stateColumn)) - isStateRowLoading = stateColumn.IsIncomplete; - } - - var cellContent = new cDataHistoryValueModel() { Content = cellContentString, HighlightColor = cellContentColor, IsLoading = isStateRowLoading, ThresholdValues = thresholdValues }; - - if (stateDefinition.Details != null && stateValues?.Count > i && stateValues[i] != null) - cellContent.UiAction = new cShowDetailedDataAction(stateDefinition, i); + var cellContent = parent.ProcessSingleStateValue(ProcessRequirements, Value, thresholdValue, i); historySectionValueColumns[i].ColumnValues.Add(cellContent); } @@ -1272,15 +1349,16 @@ namespace FasdDesktopUi.Basics.Helper if (stateDefinition.DatabaseInfo != null) { object widgetValue = parent.GetStateValueAt(stateDefinition.DatabaseInfo, 0, true); - widgetValueToAdd.Value = cUtility.RawValueFormatter.GetDisplayValue(widgetValue, cUtility.GetRawValueType(stateDefinition.DisplayType)); + widgetValueToAdd.Value = cUtility.RawValueFormatter.GetDisplayValue(widgetValue, stateDefinition.DisplayType); + object stateValue = widgetValue; if (stateDefinition is cHealthCardStateRefLink refLinkState) { stateModel = cF4SDHealthCardConfig.GetReferencableStateWithName(stateDefinition.ParentNode, refLinkState.Reference); - widgetValue = parent.GetStateValueAt(stateModel.DatabaseInfo, 0, true); + stateValue = parent.GetStateValueAt(stateModel.DatabaseInfo, 0, true); } - var widgetHighlightColor = parent.GetHighlightColor(widgetValue, stateModel); + var widgetHighlightColor = parent.GetHighlightColor(stateValue, stateModel, 0, true); widgetValueToAdd.HighlightIn = widgetHighlightColor; widgetValues.Add(widgetValueToAdd); @@ -1360,7 +1438,7 @@ namespace FasdDesktopUi.Basics.Helper var tempContent = i != 0 ? DateTime.Today.AddDays(-i).ToString("dd.MM") : cMultiLanguageSupport.GetItem("Global.Date.Today"); var tempHighlightColor = parent.GetSummaryStatusColor(categoryDefinition.States, false, i); - slimPageData.ValueColumns.Add(new cDataHistoryValueModel() { Content = tempContent, HighlightColor = tempHighlightColor, IsLoading = isLoading }); + slimPageData.ValueColumns.Add(new cDataHistoryValueModel() { Content = tempContent, HighlightColor = tempHighlightColor ?? enumHighlightColor.none, IsLoading = isLoading }); } //SummaryValueColumn @@ -1398,7 +1476,7 @@ namespace FasdDesktopUi.Basics.Helper } - summaryValueColumnColor = (enumHighlightColor)Math.Max((int)summaryValueColumnColor, (int)parent.GetSummaryStatusColor(categoryDefinition.States, false, i)); + summaryValueColumnColor = (enumHighlightColor)Math.Max((int)summaryValueColumnColor, (int)(parent.GetSummaryStatusColor(categoryDefinition.States, false, i) ?? enumHighlightColor.none)); } var summaryValueColumn = new cDataHistoryValueModel() { Content = summaryValueColumnContent, HighlightColor = summaryValueColumnColor, IsLoading = isSummaryLoading }; @@ -1476,24 +1554,15 @@ namespace FasdDesktopUi.Basics.Helper internal cHealthCardDetailPageHelper(cHealthCardDataHelper parent) : base(parent) { } - private cHealthCardDetailsTable GetDetailTableValued(object _value, cHealthCardDetailsValued StateDetailsValued) + private List getDetailsValuesCsv(string Data, cHealthCardDetailsValued StateDetailsValued) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } + var _values = new List(); + try { - if (_value == null) - return null; - var _strData = cUtility.RawValueFormatter.GetDisplayValue(_value, RawValueType.STRING); - if (_strData == null) - return null; - - var _cols = new List(); - foreach (var _colConfig in StateDetailsValued) - _cols.Add(_colConfig.Names.GetValue()); - - var _arrRow = _strData.Split(StateDetailsValued.RowSeparator); - var _values = new List(); + var _arrRow = Data.Split(StateDetailsValued.RowSeparator); foreach (var _row in _arrRow) { if (string.IsNullOrEmpty(_row)) @@ -1504,21 +1573,109 @@ namespace FasdDesktopUi.Basics.Helper _entry.Add(_row.Trim()); else { - var _arrCol = _strData.Split((char)StateDetailsValued.ColSeparator); + var _arrCol = Data.Split((char)StateDetailsValued.ColSeparator); foreach (var _col in _arrCol) _entry.Add(_col.Trim()); } - while (_entry.Count < _cols.Count) + while (_entry.Count < StateDetailsValued.Count) _entry.Add(null); _values.Add(_entry.ToArray()); } + } + catch (Exception E) + { + LogException(E); + } + finally + { + if (CM != null) LogMethodEnd(CM); + } + + return _values; + } + + private List getDetailsValuesJson(string Data, cHealthCardDetailsValued StateDetailsValued) + { + MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } + + + try + { + var _rawVals = JsonConvert.DeserializeObject>(Data); + if (_rawVals?.Count > 0) + { + var _values = new List(); + foreach (JObject _row in _rawVals) + { + var _props = _row.Children(); + + var _valRow = new object[StateDetailsValued.Count]; + for (int i = 0; i < StateDetailsValued.Count; i++) _valRow[i] = null; + + foreach (var _token in _props) + { + if (!(_token is JProperty jProp)) + continue; + + var _name = jProp.Name; + var _i = StateDetailsValued.FindIndex(v => v.Column.Equals(_name, StringComparison.InvariantCultureIgnoreCase)); + if (_i < 0) + continue; + + var _col = StateDetailsValued[_i]; + if (jProp.Value is JValue jValue) + { + var _value = jValue.Value; + var _displayString = cUtility.RawValueFormatter.GetDisplayValue(_value, _col.DisplayType); + _valRow[_i] = _displayString; + } + + } + _values.Add(_valRow); + } + + return _values; + + } + + } + catch (Exception E) + { + LogException(E); + } + finally + { + if (CM != null) LogMethodEnd(CM); + } + + return null; + } + + private cHealthCardDetailsTable GetDetailTableValued(object _value, cHealthCardDetailsValued StateDetailsValued) + { + MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } + + try + { + if (_value == null) + return null; + + var _strData = cUtility.RawValueFormatter.GetDisplayValue(_value, RawValueType.STRING); + if (_strData == null) + return null; + + List _values = new List(); + if (StateDetailsValued.Format == cHealthCardDetailsValued.ValuedFormat.json) + _values = getDetailsValuesJson(_strData, StateDetailsValued); + else + _values = getDetailsValuesCsv(_strData, StateDetailsValued); var Result = new cHealthCardDetailsTable() { Name = "Details-" + StateDetailsValued.ParentState.Name, - Columns = _cols, + Columns = StateDetailsValued.Select(v => v.Names.GetValue()).ToList(), Values = new Dictionary>() { { 0, _values } } }; @@ -1563,13 +1720,16 @@ namespace FasdDesktopUi.Basics.Helper widgetRowData.EditValueInformation = GetEditInfo(rawValueDisplay); bool shouldShowValueDetails = - (TryGetValuedDetails(rawValueDisplay, out var valuedDetails) && valuedDetails?.Values?.Values?.FirstOrDefault()?.Count > 1) + (TryGetValuedDetails(rawValueDisplay, out var valuedDetails) + && (valuedDetails?.Values?.Values?.FirstOrDefault()?.Count > 1) + || (valuedDetails?.Values?.Values?.FirstOrDefault()?.FirstOrDefault()?.Length > 1) + ) || (stateDefinition.Details is cHealthCardDetails && rawValueDisplay != null && rawValueDisplay.ToString() != "0"); if (shouldShowValueDetails) { widgetRowData.ValuedDetails = valuedDetails; - widgetRowData.UiActionValue = new cShowDetailedDataAction(stateDefinition, ValuedDetailsData: valuedDetails) + widgetRowData.UiActionValue = new cShowDetailedDataAction(stateDefinition, valuedDetailsData: valuedDetails) { DisplayType = enumActionDisplayType.enabled }; @@ -1615,7 +1775,7 @@ namespace FasdDesktopUi.Basics.Helper if (detailTable != null) displayValue = GetDetailStringValue(rawValue, detailTable); - return displayValue ?? cUtility.RawValueFormatter.GetDisplayValue(rawValue, cUtility.GetRawValueType(stateDefinition.DisplayType)); + return displayValue ?? cUtility.RawValueFormatter.GetDisplayValue(rawValue, stateDefinition.DisplayType); } string GetTranslationValue(cHealthCardStateTranslation translationDefinition, object rawValue) @@ -1644,8 +1804,8 @@ namespace FasdDesktopUi.Basics.Helper return null; var tableValues = detailTableValueTable.Values.First().Value; - if (detailTableValueTable.Columns.Count == 1 && tableValues.Count == 1) - return cUtility.RawValueFormatter.GetDisplayValue(detailTableValueTable.Values.First().Value.First()?.First(), cUtility.GetRawValueType(stateDefinition.Details.First().DisplayType)); + if (detailTableValueTable.Columns.Count >= 1 && tableValues.Count == 1) + return cUtility.RawValueFormatter.GetDisplayValue(detailTableValueTable.Values.First().Value.First()?.First(), stateDefinition.Details.First().DisplayType); else return cUtility.RawValueFormatter.GetDisplayValue(detailTableValueTable.Values.First().Value.Count, RawValueType.STRING); } @@ -1807,57 +1967,24 @@ namespace FasdDesktopUi.Basics.Helper } } - public async Task GetHealthCardRawDataAsync(cF4sdHealthCardRawDataRequest requestData) + public async Task SetHealthCardRawData(cF4SDHealthCardRawData newHealthCardRawData, cF4sdIdentityList identities) { var CM = MethodBase.GetCurrentMethod(); - var IsDataIncomplete = true; LogMethodBegin(CM); try { - if (SelectedHealthCard == null) - { - LogEntry("No valid healthcard was found."); - return false; - } - - dataProvider.Identities = requestData.Identities; - var requestedTables = requestData.Tables; - - HealthCardRawData.RemoveEmptyTables(); - var requiredTables = requestedTables.Where(value => HealthCardRawData.Tables.ContainsKey(value) == false && value.StartsWith("Computation_") == false).ToList(); - - Mouse.OverrideCursor = Cursors.Wait; - - cF4SDHealthCardRawData newHealthCardRawData = null; - await LoadingRawDataCriticalSection.EnterAsync(); - IsDataIncomplete = false; - - if (requiredTables?.Count > 0) - { - requestData.Tables = requiredTables; - - - newHealthCardRawData = await cFasdCockpitCommunicationBase.Instance.GetHealthCardData(requestData); - if (newHealthCardRawData == null) - return false; - } + parent.dataProvider.Identities = identities; if (newHealthCardRawData != null) parent.HealthCardRawData = HealthCardRawData.Combine(newHealthCardRawData); parent.UpdateNamedParameterEntries(); - IsDataIncomplete = HealthCardRawData.Tables.Where(table => table.Key.StartsWith("Computation_") == false) - .ToList() - .Any(table => table.Value.IsIncomplete); - - - if (IsDataIncomplete) - { - var _ = Task.Run(ContinueHealthCardDataLoadingAsync); - } + bool isDataIncomplete = HealthCardRawData.Tables + .Where(table => table.Key.StartsWith("Computation_") == false) + .Any(table => table.Value.IsIncomplete); lock (HealthCardRawData) { @@ -1865,29 +1992,21 @@ namespace FasdDesktopUi.Basics.Helper } LogEntry("DataChanged - Finished getting Healthcard rawdata."); - DataChanged?.Invoke(this, new BooleanEventArgs() { BooleanArg = true }); + DataChanged?.Invoke(this, new BooleanEventArgs(true)); parent.UpdateNamedParameterEntries(); - - if (IsDataIncomplete is false) - DataFullyLoaded?.Invoke(this, new EventArgs()); - - return true; + if (!isDataIncomplete) + DataFullyLoaded?.Invoke(this, EventArgs.Empty); } - catch (Exception E) + catch (Exception ex) { - LogException(E); + LogException(ex); } finally { - if (IsDataIncomplete is false) - LoadingRawDataCriticalSection.Leave(); - - Mouse.OverrideCursor = null; + LoadingRawDataCriticalSection.Leave(); LogMethodEnd(CM); } - - return false; } internal cHealthCardDataLoadingHelper(cHealthCardDataHelper parent) : base(parent) { } @@ -1980,7 +2099,7 @@ namespace FasdDesktopUi.Basics.Helper { try { - if (newRawData is null) + if (newRawData?.Tables is null) return; foreach (var tableName in newRawData.Tables.Keys) @@ -2035,129 +2154,115 @@ namespace FasdDesktopUi.Basics.Helper } } - private bool CheckUpdatedTable(KeyValuePair table, cF4SDHealthCardRawData updatedHealthCardRawData) + public async Task UpdateHealthcardRawData(cF4SDHealthCardRawData updatedHealthCardRawData) { - if (!(updatedHealthCardRawData?.Tables?.ContainsKey(table.Key) is true)) - return false; - - var _res = WasTableUpdated(table.Value, updatedHealthCardRawData.Tables[table.Key]); - return _res; - } - - private async Task ContinueHealthCardDataLoadingAsync() - { - var CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); try { - var IsDataIncomplete = true; - do + if (updatedHealthCardRawData is null) + return; + + bool isDataIncomplete = true; + await LoadingRawDataCriticalSection.EnterAsync(); + try { - try + lock (HealthCardRawData) { - var updatedHealthCardRawData = await cFasdCockpitCommunicationBase.Instance.GetHealthCardData(HealthCardRawData.Id); + var incompleteRawTables = HealthCardRawData.Tables.Where(table => table.Value.IsIncomplete + && table.Key.StartsWith("Computation_") == false) + .ToDictionary(table => table.Key, table => table.Value); - lock (HealthCardRawData) + if (updatedHealthCardRawData is null) { - - var incompleteRawTables = HealthCardRawData.Tables.Where(table => table.Value.IsIncomplete - && table.Key.StartsWith("Computation_") == false) - .ToDictionary(table => table.Key, table => table.Value); - - if (updatedHealthCardRawData is null) - { - var _msg = new List + var _msg = new List { $"Couldn't recieve complete healthcard raw data with id {HealthCardRawData?.Id}.", " Incomplete health cards:" }; - foreach (var incompleteTable in HealthCardRawData.Tables.Where(table => table.Value.IsIncomplete)) - { - _msg.Add($" {incompleteTable.Value.Name}"); - foreach (var incompleteColumn in incompleteTable.Value.Columns.Values.Where(column => column.IsIncomplete)) - { - incompleteColumn.IsIncomplete = false; - } - - incompleteTable.Value.IsIncomplete = false; - } - - cLogManager.DefaultLogger.LogList(LogLevels.Error, _msg); - - SelectedHealthCard.DoComputations(HealthCardRawData); - LogEntry("DataChanged - Couldn't complete healthcard raw data."); - DataChanged?.Invoke(this, EventArgs.Empty); - break; - } - - var rawTablesToUpdate = incompleteRawTables.Where(table => CheckUpdatedTable(table, updatedHealthCardRawData)).ToDictionary(table => table.Key, table => table.Value); - - foreach (var oldTable in rawTablesToUpdate) + foreach (var incompleteTable in HealthCardRawData.Tables.Where(table => table.Value.IsIncomplete)) { - if (oldTable.Key.ToLowerInvariant() == "nxt-user") + _msg.Add($" {incompleteTable.Value.Name}"); + foreach (var incompleteColumn in incompleteTable.Value.Columns.Values.Where(column => column.IsIncomplete)) { - + incompleteColumn.IsIncomplete = false; } - - var newTable = updatedHealthCardRawData.Tables[oldTable.Key]; - var oldTableValues = HealthCardRawData.Tables[oldTable.Key]; - - cF4SDHealthCardRawData.cHealthCardTable mergedTable = oldTableValues; - - foreach (var newTableColumnKeys in newTable.Columns.Keys) - { - if (mergedTable.Columns.ContainsKey(newTableColumnKeys) == false) - mergedTable.Columns[newTableColumnKeys] = new cF4SDHealthCardRawData.cHealthCardTableColumn(); - - int mergedTableColumnValueCount = mergedTable.Columns[newTableColumnKeys].Values.Count; - int mergedTableColumnLength = Math.Max(mergedTable.StartingIndex + mergedTableColumnValueCount, newTable.StartingIndex + newTable.Columns[newTableColumnKeys].Values.Count); //mergedTable.Columns[newTableColumnKeys].Values.Count + newTable.Columns.Count; - object[] mergedTableColumnValues = new object[mergedTableColumnLength]; - - for (int i = mergedTable.StartingIndex; i < mergedTable.StartingIndex + mergedTableColumnValueCount; i++) - { - mergedTableColumnValues[i] = mergedTable.Columns[newTableColumnKeys].Values[i - mergedTable.StartingIndex]; - } - - for (int i = newTable.StartingIndex; i < newTable.StartingIndex + newTable.Columns[newTableColumnKeys].Values.Count; i++) - { - mergedTableColumnValues[i] = newTable.Columns[newTableColumnKeys].Values[i - newTable.StartingIndex]; - } - - int newStartingIndex = Math.Min(mergedTable.StartingIndex, newTable.StartingIndex); - mergedTable.Columns[newTableColumnKeys].Values = mergedTableColumnValues.Skip(newStartingIndex).ToList(); - mergedTable.Columns[newTableColumnKeys].IsIncomplete = newTable.Columns[newTableColumnKeys].IsIncomplete; - mergedTable.StartingIndex = newStartingIndex; - mergedTable.IsIncomplete = newTable.IsIncomplete; - } - - HealthCardRawData.Tables[oldTable.Key] = mergedTable; + incompleteTable.Value.IsIncomplete = false; } - IsDataIncomplete = HealthCardRawData.Tables.Where(table => table.Key.StartsWith("Computation_") == false) - .Any(table => table.Value.IsIncomplete); + cLogManager.DefaultLogger.LogList(LogLevels.Error, _msg); - if (rawTablesToUpdate?.Count > 0) + SelectedHealthCard.DoComputations(HealthCardRawData); + LogEntry("DataChanged - Couldn't complete healthcard raw data."); + DataChanged?.Invoke(this, EventArgs.Empty); + return; + } + + Dictionary rawTablesToUpdate = updatedHealthCardRawData.Tables + .Where(table => HealthCardRawData.Tables.TryGetValue(table.Key, out var oldTable) && WasTableUpdated(oldTable, table.Value)) + .ToDictionary(table => table.Key, table => table.Value); + + foreach (var oldTable in rawTablesToUpdate) + { + cHealthCardTable newTable = updatedHealthCardRawData.Tables[oldTable.Key]; + cHealthCardTable oldTableValues = HealthCardRawData.Tables[oldTable.Key]; + + cHealthCardTable mergedTable = oldTableValues; + + foreach (var newTableColumnKeys in newTable.Columns.Keys) { - SelectedHealthCard.DoComputations(HealthCardRawData); - LogEntry($"DataChanged - {rawTablesToUpdate.Count} Tables where updated with last GetHealthcardData-Request."); - DataChanged?.Invoke(this, EventArgs.Empty); + if (mergedTable.Columns.ContainsKey(newTableColumnKeys) == false) + mergedTable.Columns[newTableColumnKeys] = new cHealthCardTableColumn(mergedTable); + + int mergedTableColumnValueCount = mergedTable.Columns[newTableColumnKeys].Values.Count; + int mergedTableColumnLength = Math.Max(mergedTable.StartingIndex + mergedTableColumnValueCount, newTable.StartingIndex + newTable.Columns[newTableColumnKeys].Values.Count); //mergedTable.Columns[newTableColumnKeys].Values.Count + newTable.Columns.Count; + object[] mergedTableColumnValues = new object[mergedTableColumnLength]; + + for (int i = mergedTable.StartingIndex; i < mergedTable.StartingIndex + mergedTableColumnValueCount; i++) + { + mergedTableColumnValues[i] = mergedTable.Columns[newTableColumnKeys].Values[i - mergedTable.StartingIndex]; + } + + for (int i = newTable.StartingIndex; i < newTable.StartingIndex + newTable.Columns[newTableColumnKeys].Values.Count; i++) + { + mergedTableColumnValues[i] = newTable.Columns[newTableColumnKeys].Values[i - newTable.StartingIndex]; + } + + int newStartingIndex = Math.Min(mergedTable.StartingIndex, newTable.StartingIndex); + mergedTable.Columns[newTableColumnKeys].Values = mergedTableColumnValues.Skip(newStartingIndex).ToList(); + mergedTable.Columns[newTableColumnKeys].IsIncomplete = newTable.Columns[newTableColumnKeys].IsIncomplete; + mergedTable.StartingIndex = newStartingIndex; + mergedTable.IsIncomplete = newTable.IsIncomplete; } + + HealthCardRawData.Tables[oldTable.Key] = mergedTable; + } + + isDataIncomplete = HealthCardRawData.Tables + .Where(table => table.Key.StartsWith("Computation_") == false) + .Any(table => table.Value.IsIncomplete); + + if (rawTablesToUpdate?.Count > 0) + { + SelectedHealthCard.DoComputations(HealthCardRawData); + LogEntry($"DataChanged - {rawTablesToUpdate.Count} Tables where updated with last GetHealthcardData-Request."); + DataChanged?.Invoke(this, EventArgs.Empty); } } - catch (Exception E) - { - LogException(E); - } - } while (IsDataIncomplete); + } + catch (Exception E) + { + LogException(E); + } - DataFullyLoaded?.Invoke(this, new EventArgs()); + if (!isDataIncomplete) + DataFullyLoaded?.Invoke(this, EventArgs.Empty); } - catch (Exception E) + catch (Exception ex) { - LogException(E); + LogException(ex); } finally { @@ -2529,7 +2634,7 @@ namespace FasdDesktopUi.Basics.Helper { RawValues = values, RawMaximizeValues = maximingValues, - DisplayType = cUtility.GetRawValueType(display), + DisplayType = display, Description = parent.GetTitleColumnOfHealthCardState(stylableStateConfig).ContentDescription, FontSize = stylableStateConfig.FontSize, FontWeight = fontWeight, diff --git a/FasdDesktopUi/Basics/Helper/MenuItemDataProvider.cs b/FasdDesktopUi/Basics/Helper/MenuItemDataProvider.cs index 4e905c3..605b3cb 100644 --- a/FasdDesktopUi/Basics/Helper/MenuItemDataProvider.cs +++ b/FasdDesktopUi/Basics/Helper/MenuItemDataProvider.cs @@ -125,7 +125,7 @@ namespace FasdDesktopUi.Basics.Helper private bool HasRequiredInformationClasses(List required) { - return !(required.Any(informationClass => _dataProvider.Identities.Any(identity => identity.Class == informationClass) == false)); + return !(required.Any(informationClass => _dataProvider?.Identities?.Any(identity => identity.Class == informationClass) == false)); } diff --git a/FasdDesktopUi/Basics/Models/ConnectionStatusHelper.cs b/FasdDesktopUi/Basics/Models/ConnectionStatusHelper.cs index e076461..1b39616 100644 --- a/FasdDesktopUi/Basics/Models/ConnectionStatusHelper.cs +++ b/FasdDesktopUi/Basics/Models/ConnectionStatusHelper.cs @@ -280,7 +280,10 @@ namespace FasdDesktopUi.Basics.Models } if (App.M42OptionMenuItem != null) - App.M42OptionMenuItem.Enabled = userInfo != null; + App.Current.MainWindow.Dispatcher.Invoke(() => + { + App.M42OptionMenuItem.Enabled = userInfo != null; + }); // check, if the are logons needed bool m42Valid = await CheckAndRefreshM42LogonAsync(); diff --git a/FasdDesktopUi/Basics/Models/HeadingDataModel.cs b/FasdDesktopUi/Basics/Models/HeadingDataModel.cs index 13d02e7..4308388 100644 --- a/FasdDesktopUi/Basics/Models/HeadingDataModel.cs +++ b/FasdDesktopUi/Basics/Models/HeadingDataModel.cs @@ -9,6 +9,7 @@ namespace FasdDesktopUi.Basics.Models public enumFasdInformationClass InformationClass { get; set; } public bool IsOnline { get; set; } public cF4sdIdentityList Identities { get; set; } + public cF4sdApiSearchResultRelation Realtion { get; set; } } public class cSwapCaseInfo diff --git a/FasdDesktopUi/Basics/Models/NamedParameterEntry.cs b/FasdDesktopUi/Basics/Models/NamedParameterEntry.cs index 56e9d97..ac4d5c5 100644 --- a/FasdDesktopUi/Basics/Models/NamedParameterEntry.cs +++ b/FasdDesktopUi/Basics/Models/NamedParameterEntry.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Windows; using C4IT.F4SD.DisplayFormatting; +using C4IT.F4SD.SupportCaseProtocoll.Models; using C4IT.FASD.Base; using FasdCockpitBase; @@ -49,6 +50,7 @@ namespace FasdDesktopUi.Basics.Models try { cUtility.RawValueFormatter.SetDefaultCulture(new System.Globalization.CultureInfo(cFasdCockpitConfig.Instance.SelectedLanguage)); + cUtility.RawValueFormatter.SetDefaultTimeZone(TimeZoneInfo.Local); var outputTable = dataProvider.HealthCardDataHelper.HealthCardRawData.GetTableByName(valueAdress.ValueTable, true); if (outputTable != null) diff --git a/FasdDesktopUi/Basics/Models/TicketOverviewModel.cs b/FasdDesktopUi/Basics/Models/TicketOverviewModel.cs index 1dc6f3b..f30bdfc 100644 --- a/FasdDesktopUi/Basics/Models/TicketOverviewModel.cs +++ b/FasdDesktopUi/Basics/Models/TicketOverviewModel.cs @@ -69,79 +69,79 @@ namespace FasdDesktopUi.Basics.Models set { if (_unassignedTicketsSelected != value) { _unassignedTicketsSelected = value; OnPropertyChanged(nameof(UnassignedTicketsSelected)); } } } - private bool _unassignedTicketsCriticalSelected; - public bool UnassignedTicketsCriticalSelected - { - get => _unassignedTicketsCriticalSelected; - set { if (_unassignedTicketsCriticalSelected != value) { _unassignedTicketsCriticalSelected = value; OnPropertyChanged(nameof(UnassignedTicketsCriticalSelected)); } } - } - #endregion - - #region Highlight-Properties - private bool _ticketsNewHighlighted; - public bool TicketsNewHighlighted { get => _ticketsNewHighlighted; set { if (_ticketsNewHighlighted != value) { _ticketsNewHighlighted = value; OnPropertyChanged(nameof(TicketsNewHighlighted)); } } } - - private bool _ticketsActiveHighlighted; - public bool TicketsActiveHighlighted { get => _ticketsActiveHighlighted; set { if (_ticketsActiveHighlighted != value) { _ticketsActiveHighlighted = value; OnPropertyChanged(nameof(TicketsActiveHighlighted)); } } } - - private bool _ticketsCriticalHighlighted; - public bool TicketsCriticalHighlighted { get => _ticketsCriticalHighlighted; set { if (_ticketsCriticalHighlighted != value) { _ticketsCriticalHighlighted = value; OnPropertyChanged(nameof(TicketsCriticalHighlighted)); } } } - - private bool _ticketsNewInfoHighlighted; - public bool TicketsNewInfoHighlighted { get => _ticketsNewInfoHighlighted; set { if (_ticketsNewInfoHighlighted != value) { _ticketsNewInfoHighlighted = value; OnPropertyChanged(nameof(TicketsNewInfoHighlighted)); } } } - - private bool _incidentNewHighlighted; - public bool IncidentNewHighlighted { get => _incidentNewHighlighted; set { if (_incidentNewHighlighted != value) { _incidentNewHighlighted = value; OnPropertyChanged(nameof(IncidentNewHighlighted)); } } } - - private bool _incidentActiveHighlighted; - public bool IncidentActiveHighlighted { get => _incidentActiveHighlighted; set { if (_incidentActiveHighlighted != value) { _incidentActiveHighlighted = value; OnPropertyChanged(nameof(IncidentActiveHighlighted)); } } } - - private bool _incidentCriticalHighlighted; - public bool IncidentCriticalHighlighted { get => _incidentCriticalHighlighted; set { if (_incidentCriticalHighlighted != value) { _incidentCriticalHighlighted = value; OnPropertyChanged(nameof(IncidentCriticalHighlighted)); } } } - - private bool _incidentNewInfoHighlighted; - public bool IncidentNewInfoHighlighted { get => _incidentNewInfoHighlighted; set { if (_incidentNewInfoHighlighted != value) { _incidentNewInfoHighlighted = value; OnPropertyChanged(nameof(IncidentNewInfoHighlighted)); } } } - - private bool _unassignedTicketsHighlighted; - public bool UnassignedTicketsHighlighted { get => _unassignedTicketsHighlighted; set { if (_unassignedTicketsHighlighted != value) { _unassignedTicketsHighlighted = value; OnPropertyChanged(nameof(UnassignedTicketsHighlighted)); } } } - - private bool _unassignedTicketsCriticalHighlighted; - public bool UnassignedTicketsCriticalHighlighted { get => _unassignedTicketsCriticalHighlighted; set { if (_unassignedTicketsCriticalHighlighted != value) { _unassignedTicketsCriticalHighlighted = value; OnPropertyChanged(nameof(UnassignedTicketsCriticalHighlighted)); } } } - #endregion - - #region Change Hint Properties - private string _ticketsNewChangeHint; - public string TicketsNewChangeHint { get => _ticketsNewChangeHint; set { if (_ticketsNewChangeHint != value) { _ticketsNewChangeHint = value; OnPropertyChanged(nameof(TicketsNewChangeHint)); } } } - - private string _ticketsActiveChangeHint; - public string TicketsActiveChangeHint { get => _ticketsActiveChangeHint; set { if (_ticketsActiveChangeHint != value) { _ticketsActiveChangeHint = value; OnPropertyChanged(nameof(TicketsActiveChangeHint)); } } } - - private string _ticketsCriticalChangeHint; - public string TicketsCriticalChangeHint { get => _ticketsCriticalChangeHint; set { if (_ticketsCriticalChangeHint != value) { _ticketsCriticalChangeHint = value; OnPropertyChanged(nameof(TicketsCriticalChangeHint)); } } } - - private string _ticketsNewInfoChangeHint; - public string TicketsNewInfoChangeHint { get => _ticketsNewInfoChangeHint; set { if (_ticketsNewInfoChangeHint != value) { _ticketsNewInfoChangeHint = value; OnPropertyChanged(nameof(TicketsNewInfoChangeHint)); } } } - - private string _incidentNewChangeHint; - public string IncidentNewChangeHint { get => _incidentNewChangeHint; set { if (_incidentNewChangeHint != value) { _incidentNewChangeHint = value; OnPropertyChanged(nameof(IncidentNewChangeHint)); } } } - - private string _incidentActiveChangeHint; - public string IncidentActiveChangeHint { get => _incidentActiveChangeHint; set { if (_incidentActiveChangeHint != value) { _incidentActiveChangeHint = value; OnPropertyChanged(nameof(IncidentActiveChangeHint)); } } } - - private string _incidentCriticalChangeHint; - public string IncidentCriticalChangeHint { get => _incidentCriticalChangeHint; set { if (_incidentCriticalChangeHint != value) { _incidentCriticalChangeHint = value; OnPropertyChanged(nameof(IncidentCriticalChangeHint)); } } } - - private string _incidentNewInfoChangeHint; - public string IncidentNewInfoChangeHint { get => _incidentNewInfoChangeHint; set { if (_incidentNewInfoChangeHint != value) { _incidentNewInfoChangeHint = value; OnPropertyChanged(nameof(IncidentNewInfoChangeHint)); } } } - - private string _unassignedTicketsChangeHint; - public string UnassignedTicketsChangeHint { get => _unassignedTicketsChangeHint; set { if (_unassignedTicketsChangeHint != value) { _unassignedTicketsChangeHint = value; OnPropertyChanged(nameof(UnassignedTicketsChangeHint)); } } } - - private string _unassignedTicketsCriticalChangeHint; - public string UnassignedTicketsCriticalChangeHint { get => _unassignedTicketsCriticalChangeHint; set { if (_unassignedTicketsCriticalChangeHint != value) { _unassignedTicketsCriticalChangeHint = value; OnPropertyChanged(nameof(UnassignedTicketsCriticalChangeHint)); } } } - #endregion - - #region Ticket & Incident-Properties + private bool _unassignedTicketsCriticalSelected; + public bool UnassignedTicketsCriticalSelected + { + get => _unassignedTicketsCriticalSelected; + set { if (_unassignedTicketsCriticalSelected != value) { _unassignedTicketsCriticalSelected = value; OnPropertyChanged(nameof(UnassignedTicketsCriticalSelected)); } } + } + #endregion + + #region Highlight-Properties + private bool _ticketsNewHighlighted; + public bool TicketsNewHighlighted { get => _ticketsNewHighlighted; set { if (_ticketsNewHighlighted != value) { _ticketsNewHighlighted = value; OnPropertyChanged(nameof(TicketsNewHighlighted)); } } } + + private bool _ticketsActiveHighlighted; + public bool TicketsActiveHighlighted { get => _ticketsActiveHighlighted; set { if (_ticketsActiveHighlighted != value) { _ticketsActiveHighlighted = value; OnPropertyChanged(nameof(TicketsActiveHighlighted)); } } } + + private bool _ticketsCriticalHighlighted; + public bool TicketsCriticalHighlighted { get => _ticketsCriticalHighlighted; set { if (_ticketsCriticalHighlighted != value) { _ticketsCriticalHighlighted = value; OnPropertyChanged(nameof(TicketsCriticalHighlighted)); } } } + + private bool _ticketsNewInfoHighlighted; + public bool TicketsNewInfoHighlighted { get => _ticketsNewInfoHighlighted; set { if (_ticketsNewInfoHighlighted != value) { _ticketsNewInfoHighlighted = value; OnPropertyChanged(nameof(TicketsNewInfoHighlighted)); } } } + + private bool _incidentNewHighlighted; + public bool IncidentNewHighlighted { get => _incidentNewHighlighted; set { if (_incidentNewHighlighted != value) { _incidentNewHighlighted = value; OnPropertyChanged(nameof(IncidentNewHighlighted)); } } } + + private bool _incidentActiveHighlighted; + public bool IncidentActiveHighlighted { get => _incidentActiveHighlighted; set { if (_incidentActiveHighlighted != value) { _incidentActiveHighlighted = value; OnPropertyChanged(nameof(IncidentActiveHighlighted)); } } } + + private bool _incidentCriticalHighlighted; + public bool IncidentCriticalHighlighted { get => _incidentCriticalHighlighted; set { if (_incidentCriticalHighlighted != value) { _incidentCriticalHighlighted = value; OnPropertyChanged(nameof(IncidentCriticalHighlighted)); } } } + + private bool _incidentNewInfoHighlighted; + public bool IncidentNewInfoHighlighted { get => _incidentNewInfoHighlighted; set { if (_incidentNewInfoHighlighted != value) { _incidentNewInfoHighlighted = value; OnPropertyChanged(nameof(IncidentNewInfoHighlighted)); } } } + + private bool _unassignedTicketsHighlighted; + public bool UnassignedTicketsHighlighted { get => _unassignedTicketsHighlighted; set { if (_unassignedTicketsHighlighted != value) { _unassignedTicketsHighlighted = value; OnPropertyChanged(nameof(UnassignedTicketsHighlighted)); } } } + + private bool _unassignedTicketsCriticalHighlighted; + public bool UnassignedTicketsCriticalHighlighted { get => _unassignedTicketsCriticalHighlighted; set { if (_unassignedTicketsCriticalHighlighted != value) { _unassignedTicketsCriticalHighlighted = value; OnPropertyChanged(nameof(UnassignedTicketsCriticalHighlighted)); } } } + #endregion + + #region Change Hint Properties + private string _ticketsNewChangeHint; + public string TicketsNewChangeHint { get => _ticketsNewChangeHint; set { if (_ticketsNewChangeHint != value) { _ticketsNewChangeHint = value; OnPropertyChanged(nameof(TicketsNewChangeHint)); } } } + + private string _ticketsActiveChangeHint; + public string TicketsActiveChangeHint { get => _ticketsActiveChangeHint; set { if (_ticketsActiveChangeHint != value) { _ticketsActiveChangeHint = value; OnPropertyChanged(nameof(TicketsActiveChangeHint)); } } } + + private string _ticketsCriticalChangeHint; + public string TicketsCriticalChangeHint { get => _ticketsCriticalChangeHint; set { if (_ticketsCriticalChangeHint != value) { _ticketsCriticalChangeHint = value; OnPropertyChanged(nameof(TicketsCriticalChangeHint)); } } } + + private string _ticketsNewInfoChangeHint; + public string TicketsNewInfoChangeHint { get => _ticketsNewInfoChangeHint; set { if (_ticketsNewInfoChangeHint != value) { _ticketsNewInfoChangeHint = value; OnPropertyChanged(nameof(TicketsNewInfoChangeHint)); } } } + + private string _incidentNewChangeHint; + public string IncidentNewChangeHint { get => _incidentNewChangeHint; set { if (_incidentNewChangeHint != value) { _incidentNewChangeHint = value; OnPropertyChanged(nameof(IncidentNewChangeHint)); } } } + + private string _incidentActiveChangeHint; + public string IncidentActiveChangeHint { get => _incidentActiveChangeHint; set { if (_incidentActiveChangeHint != value) { _incidentActiveChangeHint = value; OnPropertyChanged(nameof(IncidentActiveChangeHint)); } } } + + private string _incidentCriticalChangeHint; + public string IncidentCriticalChangeHint { get => _incidentCriticalChangeHint; set { if (_incidentCriticalChangeHint != value) { _incidentCriticalChangeHint = value; OnPropertyChanged(nameof(IncidentCriticalChangeHint)); } } } + + private string _incidentNewInfoChangeHint; + public string IncidentNewInfoChangeHint { get => _incidentNewInfoChangeHint; set { if (_incidentNewInfoChangeHint != value) { _incidentNewInfoChangeHint = value; OnPropertyChanged(nameof(IncidentNewInfoChangeHint)); } } } + + private string _unassignedTicketsChangeHint; + public string UnassignedTicketsChangeHint { get => _unassignedTicketsChangeHint; set { if (_unassignedTicketsChangeHint != value) { _unassignedTicketsChangeHint = value; OnPropertyChanged(nameof(UnassignedTicketsChangeHint)); } } } + + private string _unassignedTicketsCriticalChangeHint; + public string UnassignedTicketsCriticalChangeHint { get => _unassignedTicketsCriticalChangeHint; set { if (_unassignedTicketsCriticalChangeHint != value) { _unassignedTicketsCriticalChangeHint = value; OnPropertyChanged(nameof(UnassignedTicketsCriticalChangeHint)); } } } + #endregion + + #region Ticket & Incident-Properties // Ticket Properties private int _ticketsNew; @@ -184,11 +184,11 @@ namespace FasdDesktopUi.Basics.Models #region Helper-Methods - public void ResetSelection() - { - TicketsNewSelected = false; - TicketsActiveSelected = false; - TicketsCriticalSelected = false; + public void ResetSelection() + { + TicketsNewSelected = false; + TicketsActiveSelected = false; + TicketsCriticalSelected = false; TicketsNewInfoSelected = false; IncidentNewSelected = false; @@ -196,38 +196,44 @@ namespace FasdDesktopUi.Basics.Models IncidentCriticalSelected = false; IncidentNewInfoSelected = false; - UnassignedTicketsSelected = false; - UnassignedTicketsCriticalSelected = false; - } - - public void ResetHighlights() - { - TicketsNewHighlighted = false; - TicketsActiveHighlighted = false; - TicketsCriticalHighlighted = false; - TicketsNewInfoHighlighted = false; - - IncidentNewHighlighted = false; - IncidentActiveHighlighted = false; - IncidentCriticalHighlighted = false; - IncidentNewInfoHighlighted = false; - - UnassignedTicketsHighlighted = false; - UnassignedTicketsCriticalHighlighted = false; - - TicketsNewChangeHint = null; - TicketsActiveChangeHint = null; - TicketsCriticalChangeHint = null; - TicketsNewInfoChangeHint = null; - - IncidentNewChangeHint = null; - IncidentActiveChangeHint = null; - IncidentCriticalChangeHint = null; - IncidentNewInfoChangeHint = null; - - UnassignedTicketsChangeHint = null; - UnassignedTicketsCriticalChangeHint = null; - } - #endregion - } -} + UnassignedTicketsSelected = false; + UnassignedTicketsCriticalSelected = false; + } + + public void ResetHighlights() + { + TicketsNewHighlighted = false; + TicketsActiveHighlighted = false; + TicketsCriticalHighlighted = false; + TicketsNewInfoHighlighted = false; + + IncidentNewHighlighted = false; + IncidentActiveHighlighted = false; + IncidentCriticalHighlighted = false; + IncidentNewInfoHighlighted = false; + + UnassignedTicketsHighlighted = false; + UnassignedTicketsCriticalHighlighted = false; + + TicketsNewChangeHint = null; + TicketsActiveChangeHint = null; + TicketsCriticalChangeHint = null; + TicketsNewInfoChangeHint = null; + + IncidentNewChangeHint = null; + IncidentActiveChangeHint = null; + IncidentCriticalChangeHint = null; + IncidentNewInfoChangeHint = null; + + UnassignedTicketsChangeHint = null; + UnassignedTicketsCriticalChangeHint = null; + } + #endregion + + public TicketOverviewModel() + { + + } + } + +} diff --git a/FasdDesktopUi/Basics/SearchHistoryManager.cs b/FasdDesktopUi/Basics/SearchHistoryManager.cs index a64ba84..8eccf13 100644 --- a/FasdDesktopUi/Basics/SearchHistoryManager.cs +++ b/FasdDesktopUi/Basics/SearchHistoryManager.cs @@ -242,7 +242,7 @@ namespace FasdDesktopUi.Basics if (addRelation) foreach (var _caseRelation in CaseRelations) { - if (_caseRelation.isEqual(CaseRelation)) + if (_caseRelation.Equals(CaseRelation)) { addRelation = false; break; diff --git a/FasdDesktopUi/Basics/Services/Models/TicketOverviewCountsChangedEventArgs.cs b/FasdDesktopUi/Basics/Services/Models/TicketOverviewCountsChangedEventArgs.cs index 365bbc4..6ed1040 100644 --- a/FasdDesktopUi/Basics/Services/Models/TicketOverviewCountsChangedEventArgs.cs +++ b/FasdDesktopUi/Basics/Services/Models/TicketOverviewCountsChangedEventArgs.cs @@ -5,15 +5,18 @@ namespace FasdDesktopUi.Basics.Services.Models { public sealed class TicketOverviewCountsChangedEventArgs : EventArgs { - public TicketOverviewCountsChangedEventArgs(IReadOnlyList changes, IReadOnlyDictionary currentCounts) + public TicketOverviewCountsChangedEventArgs(IReadOnlyList changes, IReadOnlyDictionary currentCounts, TileScope? initializedScope = null) { - Changes = changes; + Changes = changes ?? Array.Empty(); CurrentCounts = currentCounts; + InitializedScope = initializedScope; } public IReadOnlyList Changes { get; } public IReadOnlyDictionary CurrentCounts { get; } + + public TileScope? InitializedScope { get; } } public readonly struct TileCountChange diff --git a/FasdDesktopUi/Basics/Services/ProtocollService/F4SDProtocoll.cs b/FasdDesktopUi/Basics/Services/ProtocollService/F4SDProtocoll.cs index 25e5af2..c0bbda9 100644 --- a/FasdDesktopUi/Basics/Services/ProtocollService/F4SDProtocoll.cs +++ b/FasdDesktopUi/Basics/Services/ProtocollService/F4SDProtocoll.cs @@ -1,4 +1,5 @@ -using System; +using C4IT.F4SD.SupportCaseProtocoll.Models; +using System; using System.Collections.Generic; using System.Linq; using System.Windows; @@ -8,14 +9,14 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService { internal class F4SDProtocoll { - private readonly ICollection _protocollEntries = new List(); + private readonly ICollection _protocollEntries = new List(); public static F4SDProtocoll Instance { get; private set; } = new F4SDProtocoll(); private F4SDProtocoll() { } - internal void Add(IProtocollEntry entry) => _protocollEntries.Add(entry); - internal void Add(IEnumerable entries) + internal void Add(ProtocollEntryBase entry) => _protocollEntries.Add(entry); + internal void Add(IEnumerable entries) { foreach (var entry in entries) { @@ -25,34 +26,34 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService internal void Clear() => _protocollEntries.Clear(); - internal T GetLatestOfType() where T : IProtocollEntry => _protocollEntries.OfType().LastOrDefault(); + internal T GetLatestOfType() where T : ProtocollEntryBase => _protocollEntries.OfType().LastOrDefault(); - internal IEnumerable GetOfType(int? count = null) where T : IProtocollEntry + internal IEnumerable GetOfType(int? count = null) where T : ProtocollEntryBase { if(count.HasValue) return _protocollEntries.OfType().Reverse().Take(count.Value).Reverse(); return _protocollEntries.OfType(); } - internal IEnumerable GetAll() => _protocollEntries; + internal IEnumerable GetAll() => _protocollEntries; - internal DataObject GetLatestOfTypeAsDataObject(bool skipHtmlFrame) where T : IProtocollEntry + internal DataObject GetLatestOfTypeAsDataObject(bool skipHtmlFrame) where T : ProtocollEntryBase { - IProtocollEntry entry = _protocollEntries.OfType().LastOrDefault(); + ProtocollEntryBase entry = _protocollEntries.OfType().LastOrDefault(); if (entry is null) return new DataObject(); - return GetDataObjectOf(new IProtocollEntry[] { entry }, skipHtmlFrame); + return GetDataObjectOf(new ProtocollEntryBase[] { entry }, skipHtmlFrame); } - internal DataObject GetOfTypeAsDataObject(bool skipHtmlFrame, int? count = null) where T : IProtocollEntry - => GetDataObjectOf(GetOfType(count).Cast(), skipHtmlFrame); + internal DataObject GetOfTypeAsDataObject(bool skipHtmlFrame, int? count = null) where T : ProtocollEntryBase + => GetDataObjectOf(GetOfType(count).Cast(), skipHtmlFrame); internal DataObject GetAllAsDataObject(bool skipHtmlFrame) => GetDataObjectOf(_protocollEntries, skipHtmlFrame); - private DataObject GetDataObjectOf(IEnumerable entries, bool skipHtmlFrame, int? count = null) + private DataObject GetDataObjectOf(IEnumerable entries, bool skipHtmlFrame, int? count = null) { DataObject dataObject = new DataObject(); @@ -67,16 +68,16 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService if (count.HasValue) entries = entries.Reverse().Take(count.Value).Reverse(); - foreach (IProtocollEntry entry in entries) + foreach (ProtocollEntryBase entry in entries) { - string entryAscii = entry.GetAscii(); + string entryAscii = entry.AsciiContent; if (!string.IsNullOrEmpty(entryAscii)) { ascii += entryAscii; ascii += asciiSeparator; } - string entryHtml = entry.GetHtml(); + string entryHtml = entry.HtmlContent; if (!string.IsNullOrEmpty(entryHtml)) { html += entryHtml; diff --git a/FasdDesktopUi/Basics/Services/ProtocollService/IProtocollEntry.cs b/FasdDesktopUi/Basics/Services/ProtocollService/IProtocollEntry.cs deleted file mode 100644 index f5f5d7e..0000000 --- a/FasdDesktopUi/Basics/Services/ProtocollService/IProtocollEntry.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; - -namespace FasdDesktopUi.Basics.Services.ProtocollService -{ - internal interface IProtocollEntry - { - string GetAscii(); - string GetHtml(); - } -} diff --git a/FasdDesktopUi/Basics/Services/ProtocollService/QuickActionProtocollEntry.cs b/FasdDesktopUi/Basics/Services/ProtocollService/QuickActionProtocollEntry.cs index 211bb1f..f8633ba 100644 --- a/FasdDesktopUi/Basics/Services/ProtocollService/QuickActionProtocollEntry.cs +++ b/FasdDesktopUi/Basics/Services/ProtocollService/QuickActionProtocollEntry.cs @@ -1,4 +1,4 @@ -using C4IT.F4SD.DisplayFormatting; +using C4IT.F4SD.SupportCaseProtocoll.Models; using C4IT.FASD.Base; using C4IT.MultiLanguage; using FasdDesktopUi.Basics.Models; @@ -11,17 +11,26 @@ using static FasdDesktopUi.Basics.UserControls.QuickActionStatusMonitor; namespace FasdDesktopUi.Basics.Services.ProtocollService { - internal class QuickActionProtocollEntry : IProtocollEntry + internal static class QuickActionProtocollEntryOutput { - private readonly cFasdQuickAction _quickActionDefinition; - private readonly cQuickActionCopyData _quickActionCopyData; - const string AsciiSeperator = "\n\n"; - public QuickActionProtocollEntry(cFasdQuickAction quickActionDefinition, cQuickActionCopyData quickActionCopyData) + public static QuickActionProtocollEntry GetQuickActionProtocollEntry(cFasdQuickAction quickActionDefinition, cQuickActionCopyData quickActionCopyData) { - _quickActionDefinition = quickActionDefinition; - _quickActionCopyData = quickActionCopyData; + string ascii = GetAscii(quickActionDefinition, quickActionCopyData); + string html = GetHtml(quickActionDefinition, quickActionCopyData); + + return new QuickActionProtocollEntry(ascii, html) + { + Id = quickActionDefinition.Id, + Name = quickActionDefinition.Name, + ExecutionTypeId = (int)quickActionDefinition.ExecutionType, + WasRunningOnAffectedDevice = quickActionCopyData.WasRunningOnAffectedDevice, + AffectedDeviceName = quickActionCopyData.AffectedDeviceName, + ResultCode = (int?)quickActionCopyData.QuickActionOutput?.ResultCode, + ErrorMessage = quickActionCopyData.QuickActionOutput?.ErrorDescription, + MeasureValues = GetQuickActionHtmlValueComparison(quickActionCopyData.MeasureValues) + }; } internal static cQuickActionCopyData GetCopyData(cFasdQuickAction quickActionDefinition, cSupportCaseDataProvider dataProvider, bool wasRunningOnAffectedDevice, cQuickActionOutput quickActionOutput, List measureValues) @@ -51,38 +60,21 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService return quickActionCopyData; } - internal cQuickActionResult GetResult() - { - return new cQuickActionResult() - { - QuickActionId = _quickActionDefinition.Id, - QuickActionName = _quickActionDefinition.Name, - QuickActionExecutionType = (int)_quickActionDefinition.ExecutionType, - wasRunningOnAffectedDevice = _quickActionCopyData.WasRunningOnAffectedDevice, - AffectedDeviceName = _quickActionCopyData.AffectedDeviceName, - ExecutionTime = DateTime.UtcNow, - ResultCode = (int?)(_quickActionCopyData.QuickActionOutput?.ResultCode), - ErrorMessage = _quickActionCopyData.QuickActionOutput?.ErrorDescription, - Output = GetQuickActionHtmlOutput(_quickActionCopyData.QuickActionOutput), - MeasureValues = GetQuickActionHtmlValueComparison(_quickActionCopyData.MeasureValues) - }; - } + private static string GetAscii(cFasdQuickAction quickActionDefinition, cQuickActionCopyData quickActionCopyData) => GetQuickActionAscii(quickActionDefinition, quickActionCopyData); - public string GetAscii() => GetQuickActionAscii(_quickActionCopyData); + private static string GetHtml(cFasdQuickAction quickActionDefinition, cQuickActionCopyData quickActionCopyData) => GetQuickActionHtml(quickActionDefinition, quickActionCopyData); - public string GetHtml() => GetQuickActionHtml(_quickActionCopyData); - - private bool ShouldHideQuickActionOutput(string outputValueKey) + private static bool ShouldHideQuickActionOutput(cFasdQuickAction quickActionDefinition, string outputValueKey) { try { - if (_quickActionDefinition.ColumnOutputFormattings is null) + if (quickActionDefinition.ColumnOutputFormattings is null) return false; - if (!_quickActionDefinition.ShowAllOutputContent && !_quickActionDefinition.ColumnOutputFormattings.ContainsKey(outputValueKey)) + if (!quickActionDefinition.ShowAllOutputContent && !quickActionDefinition.ColumnOutputFormattings.ContainsKey(outputValueKey)) return true; - if (_quickActionDefinition.ColumnOutputFormattings.TryGetValue(outputValueKey, out var columnFormatting)) + if (quickActionDefinition.ColumnOutputFormattings.TryGetValue(outputValueKey, out var columnFormatting)) return columnFormatting.Hidden; } catch (Exception ex) @@ -95,19 +87,19 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService #region Ascii - private string GetQuickActionAscii(cQuickActionCopyData copyData) + private static string GetQuickActionAscii(cFasdQuickAction quickActionDefinition, cQuickActionCopyData copyData) { string ascii = string.Empty; ascii += GetQuickActionAsciiDescription(copyData.Name, copyData.AffectedDeviceName, copyData.WasRunningOnAffectedDevice, copyData.ExecutionTime, copyData.QuickActionOutput?.ResultCode); ascii += GetQuickActionAsciiError(copyData.QuickActionOutput?.ErrorDescription); - ascii += GetQuickActionAsciiOutput(copyData.QuickActionOutput); + ascii += GetQuickActionAsciiOutput(quickActionDefinition, copyData.QuickActionOutput); ascii += GetQuickActionAsciiValueComparisonString(copyData.MeasureValues); return ascii; } - private string GetQuickActionAsciiDescription(string quickActionName, string deviceName, bool wasRunningOnAffectedDevice, DateTime executionTime, enumQuickActionSuccess? quickActionStatus) + private static string GetQuickActionAsciiDescription(string quickActionName, string deviceName, bool wasRunningOnAffectedDevice, DateTime executionTime, enumQuickActionSuccess? quickActionStatus) { string asciiDescription = string.Empty; try @@ -136,7 +128,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService return asciiDescription; } - private string GetQuickActionAsciiError(string errorMessage) + private static string GetQuickActionAsciiError(string errorMessage) { if (!string.IsNullOrEmpty(errorMessage)) errorMessage.Insert(0, AsciiSeperator); @@ -144,7 +136,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService return errorMessage; } - private string GetQuickActionAsciiOutput(QuickActionStatusMonitor.cQuickActionOutput quickActionOutput) + private static string GetQuickActionAsciiOutput(cFasdQuickAction quickActionDefinition, QuickActionStatusMonitor.cQuickActionOutput quickActionOutput) { string output = string.Empty; @@ -162,7 +154,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService output += AsciiSeperator; output += cMultiLanguageSupport.GetItem("QuickAction.Copy.Output") + " "; - output += singleOutput.GetDisplayValue(_quickActionDefinition.ColumnOutputFormattings); + output += singleOutput.GetDisplayValue(quickActionDefinition.ColumnOutputFormattings); break; } @@ -174,10 +166,10 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService foreach (var value in listOutput.Values[0]) { - if (ShouldHideQuickActionOutput(value.Key)) + if (ShouldHideQuickActionOutput(quickActionDefinition, value.Key)) continue; - if (_quickActionDefinition.ColumnOutputFormattings?.TryGetValue(value.Key, out var outputFormatting) ?? false) + if (quickActionDefinition.ColumnOutputFormattings?.TryGetValue(value.Key, out var outputFormatting) ?? false) output += outputFormatting.Names.GetValue(); else output += value.Key; @@ -193,10 +185,10 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService { string valueKey = listOutput.Values[0][j].Key; - if (ShouldHideQuickActionOutput(valueKey)) + if (ShouldHideQuickActionOutput(quickActionDefinition, valueKey)) continue; - string displayValue = listOutput.GetDisplayValue(i, j, _quickActionDefinition.ColumnOutputFormattings); + string displayValue = listOutput.GetDisplayValue(i, j, quickActionDefinition.ColumnOutputFormattings); if (string.IsNullOrWhiteSpace(displayValue)) continue; @@ -217,12 +209,12 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService { var value = objectOutput.Values[i]; - if (ShouldHideQuickActionOutput(value.Key)) + if (ShouldHideQuickActionOutput(quickActionDefinition, value.Key)) continue; string columnTitle = string.Empty; - if (_quickActionDefinition.ColumnOutputFormattings?.TryGetValue(value.Key, out var outputFormatting) ?? false) + if (quickActionDefinition.ColumnOutputFormattings?.TryGetValue(value.Key, out var outputFormatting) ?? false) columnTitle = outputFormatting.Names.GetValue(); else columnTitle = value.Key; @@ -230,7 +222,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService if (!string.IsNullOrEmpty(columnTitle)) output += $"{columnTitle}: "; - string displayValue = objectOutput.GetDisplayValue(i, _quickActionDefinition.ColumnOutputFormattings); + string displayValue = objectOutput.GetDisplayValue(i, quickActionDefinition.ColumnOutputFormattings); output += !string.IsNullOrWhiteSpace(displayValue) ? displayValue : null; output += "\n"; @@ -248,7 +240,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService return output; } - private string GetQuickActionAsciiValueComparisonString(List measureValues) + private static string GetQuickActionAsciiValueComparisonString(List measureValues) { string output = string.Empty; @@ -260,6 +252,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService output += AsciiSeperator + cMultiLanguageSupport.GetItem("QuickAction.Copy.Measure"); cUtility.RawValueFormatter.SetDefaultCulture(new System.Globalization.CultureInfo(cFasdCockpitConfig.Instance.SelectedLanguage)); + cUtility.RawValueFormatter.SetDefaultTimeZone(TimeZoneInfo.Local); foreach (var measureValue in measureValues) { @@ -292,7 +285,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService #region Html - private string GetQuickActionHtml(cQuickActionCopyData copyData) + private static string GetQuickActionHtml(cFasdQuickAction quickActionDefinition, cQuickActionCopyData copyData) { string output = string.Empty; @@ -300,7 +293,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService { output += GetQuickActionHtmlDescription(copyData.Name, copyData.AffectedDeviceName, copyData.WasRunningOnAffectedDevice, copyData.ExecutionTime, copyData.QuickActionOutput?.ResultCode); output += GetQuickActionHtmlError(copyData.QuickActionOutput?.ErrorDescription); - output += GetQuickActionHtmlOutput(copyData.QuickActionOutput); + output += GetQuickActionHtmlOutput(quickActionDefinition, copyData.QuickActionOutput); output += GetQuickActionHtmlValueComparison(copyData.MeasureValues); } catch (Exception E) @@ -311,7 +304,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService return output; } - private string GetQuickActionHtmlDescription(string quickActionName, string deviceName, bool wasRunningOnAffectedDevice, DateTime executionTime, enumQuickActionSuccess? quickActionStatus) + private static string GetQuickActionHtmlDescription(string quickActionName, string deviceName, bool wasRunningOnAffectedDevice, DateTime executionTime, enumQuickActionSuccess? quickActionStatus) { string output = string.Empty; try @@ -348,7 +341,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService return errorMessage; } - private string GetQuickActionHtmlOutput(QuickActionStatusMonitor.cQuickActionOutput quickActionOutput) + private static string GetQuickActionHtmlOutput(cFasdQuickAction quickActionDefinition, QuickActionStatusMonitor.cQuickActionOutput quickActionOutput) { string output = string.Empty; @@ -366,7 +359,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService if (singleOutput.Value is null) return output; - var displayValue = singleOutput.GetDisplayValue(_quickActionDefinition?.ColumnOutputFormattings); + var displayValue = singleOutput.GetDisplayValue(quickActionDefinition?.ColumnOutputFormattings); output += "

" + cMultiLanguageSupport.GetItem("QuickAction.Copy.Output.Html") + " " + displayValue + "

"; break; } @@ -379,11 +372,11 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService foreach (var value in listOutput.Values[0]) { - if (ShouldHideQuickActionOutput(value.Key)) + if (ShouldHideQuickActionOutput(quickActionDefinition, value.Key)) continue; string headingValue = value.Key; - if (_quickActionDefinition.ColumnOutputFormattings?.TryGetValue(value.Key, out var outputFormatting) ?? false) + if (quickActionDefinition.ColumnOutputFormattings?.TryGetValue(value.Key, out var outputFormatting) ?? false) headingValue = outputFormatting.Names.GetValue(); output += ""; @@ -400,10 +393,10 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService for (int j = 0; j < listOutput.Values[i].Count; j++) { string valueKey = listOutput.Values[0][j].Key; - if (ShouldHideQuickActionOutput(valueKey)) + if (ShouldHideQuickActionOutput(quickActionDefinition, valueKey)) continue; - string displayValue = listOutput.GetDisplayValue(i, j, _quickActionDefinition.ColumnOutputFormattings); + string displayValue = listOutput.GetDisplayValue(i, j, quickActionDefinition.ColumnOutputFormattings); if (string.IsNullOrWhiteSpace(displayValue)) continue; @@ -429,11 +422,11 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService { var value = objectOutput.Values[i]; - if (ShouldHideQuickActionOutput(value.Key)) + if (ShouldHideQuickActionOutput(quickActionDefinition, value.Key)) continue; string headingValue = value.Key; - if (_quickActionDefinition.ColumnOutputFormattings?.TryGetValue(value.Key, out var outputFormatting) ?? false) + if (quickActionDefinition.ColumnOutputFormattings?.TryGetValue(value.Key, out var outputFormatting) ?? false) headingValue = outputFormatting.Names.GetValue(); output += ""; @@ -442,7 +435,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService output += ""; output += ""; - string displayValue = objectOutput.GetDisplayValue(i, _quickActionDefinition.ColumnOutputFormattings); + string displayValue = objectOutput.GetDisplayValue(i, quickActionDefinition.ColumnOutputFormattings); output += !string.IsNullOrWhiteSpace(displayValue) ? displayValue : null; output += ""; @@ -462,7 +455,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService return output; } - private string GetQuickActionHtmlValueComparison(List measureValues) + private static string GetQuickActionHtmlValueComparison(List measureValues) { string output = string.Empty; @@ -474,6 +467,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService output += "

" + cMultiLanguageSupport.GetItem("QuickAction.Copy.Measure.Html") + "

"; cUtility.RawValueFormatter.SetDefaultCulture(new System.Globalization.CultureInfo(cFasdCockpitConfig.Instance.SelectedLanguage)); + cUtility.RawValueFormatter.SetDefaultTimeZone(TimeZoneInfo.Local); foreach (var measureValue in measureValues) { diff --git a/FasdDesktopUi/Basics/Services/ProtocollService/QuickTipStepProtocollEntry.cs b/FasdDesktopUi/Basics/Services/ProtocollService/QuickTipStepProtocollEntry.cs index d83f688..c3a8694 100644 --- a/FasdDesktopUi/Basics/Services/ProtocollService/QuickTipStepProtocollEntry.cs +++ b/FasdDesktopUi/Basics/Services/ProtocollService/QuickTipStepProtocollEntry.cs @@ -1,27 +1,30 @@ -using C4IT.FASD.Base; +using C4IT.F4SD.SupportCaseProtocoll.Models; +using C4IT.FASD.Base; using C4IT.MultiLanguage; namespace FasdDesktopUi.Basics.Services.ProtocollService { - internal class QuickTipStepProtocollEntry : IProtocollEntry + internal static class QuickTipStepProtocollEntryOutput { - private readonly cQuickTipElement _quickTipElementDefinition; - private readonly bool _wasSuccessfull; - - public QuickTipStepProtocollEntry(cQuickTipElement quickTipElementDefinition, bool wasSuccessfull) + public static QuickTipStepProtocollEntry GetQuickTipStepProtocollEntry(cQuickTipElement quickTipElementDefinition, bool wasSuccessfull) { - _quickTipElementDefinition = quickTipElementDefinition; - _wasSuccessfull = wasSuccessfull; + string ascii = GetAsciiOutput(quickTipElementDefinition, wasSuccessfull); + string html = GetHtmlOutput(quickTipElementDefinition, wasSuccessfull); + return new QuickTipStepProtocollEntry(ascii, html) + { + Name = quickTipElementDefinition.Name, + WasSuccessfull = wasSuccessfull + }; } - public string GetAscii() + private static string GetAsciiOutput(cQuickTipElement quickTipElementDefinition, bool wasSuccessfull) { string currentLanguage = cMultiLanguageSupport.CurrentLanguage; try { cMultiLanguageSupport.CurrentLanguage = cF4SDCockpitXmlConfig.Instance.HealthCardConfig.ProtocollLanguage ?? currentLanguage; - string ascii = _wasSuccessfull ? cMultiLanguageSupport.GetItem("QuickTips.Copy.ManualStep.Successfull") : cMultiLanguageSupport.GetItem("QuickTips.Copy.ManualStep.Unsuccessfull"); - return string.Format(ascii, _quickTipElementDefinition?.Names?.GetValue()); + string ascii = wasSuccessfull ? cMultiLanguageSupport.GetItem("QuickTips.Copy.ManualStep.Successfull") : cMultiLanguageSupport.GetItem("QuickTips.Copy.ManualStep.Unsuccessfull"); + return string.Format(ascii, quickTipElementDefinition?.Names?.GetValue()); } finally { @@ -29,7 +32,7 @@ namespace FasdDesktopUi.Basics.Services.ProtocollService } } - public string GetHtml() - => GetAscii(); + private static string GetHtmlOutput(cQuickTipElement quickTipElementDefinition, bool wasSuccessfull) + => GetAsciiOutput(quickTipElementDefinition, wasSuccessfull); } } diff --git a/FasdDesktopUi/Basics/Services/ProtocollService/TextualProtocollEntry.cs b/FasdDesktopUi/Basics/Services/ProtocollService/TextualProtocollEntry.cs deleted file mode 100644 index 150341d..0000000 --- a/FasdDesktopUi/Basics/Services/ProtocollService/TextualProtocollEntry.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace FasdDesktopUi.Basics.Services.ProtocollService -{ - internal class TextualProtocollEntry : IProtocollEntry - { - private readonly string _asciiText; - private readonly string _htmlText; - - public TextualProtocollEntry(string asciiText, string htmlText) - { - _asciiText = asciiText; - _htmlText = htmlText; - } - - public string GetAscii() => _asciiText; - - public string GetHtml() => _htmlText; - } -} diff --git a/FasdDesktopUi/Basics/Services/RelationService/RelationService.cs b/FasdDesktopUi/Basics/Services/RelationService/RelationService.cs index ca81a80..b8f4a1b 100644 --- a/FasdDesktopUi/Basics/Services/RelationService/RelationService.cs +++ b/FasdDesktopUi/Basics/Services/RelationService/RelationService.cs @@ -4,10 +4,8 @@ using System; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; -using System.Text; using System.Threading; using System.Threading.Tasks; -using System.Windows.Forms; using static C4IT.Logging.cLogManager; [assembly: InternalsVisibleTo("F4SD.Cockpit.Client.Test")] @@ -29,7 +27,7 @@ namespace FasdDesktopUi.Basics.Services.RelationService { try { - _relations = new List(); + _relations = relatedTo?.Select(searchResult => new cF4sdApiSearchResultRelation(searchResult)).ToList() ?? new List(); cF4sdStagedSearchResultRelationTaskId gatherRelationTask = await cFasdCockpitCommunicationBase.Instance.StartGatheringRelations(relatedTo, token); _ = Task.Run(async () => diff --git a/FasdDesktopUi/Basics/Services/SupportCase/Controllers/SupportCaseController.cs b/FasdDesktopUi/Basics/Services/SupportCase/Controllers/SupportCaseController.cs new file mode 100644 index 0000000..29cad06 --- /dev/null +++ b/FasdDesktopUi/Basics/Services/SupportCase/Controllers/SupportCaseController.cs @@ -0,0 +1,255 @@ +using C4IT.FASD.Base; +using C4IT.FASD.Cockpit.Communication; +using FasdDesktopUi.Basics.CustomEvents; +using FasdDesktopUi.Basics.Models; +using FasdDesktopUi.Pages.DetailsPage.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using static C4IT.Logging.cLogManager; + +namespace FasdDesktopUi.Basics.Services.SupportCase.Controllers +{ + /// + /// Used to manage the for the UI via the " + /// + public class SupportCaseController + { + private SupportCaseProcessor _supportCaseProcessor; + private cF4sdApiSearchResultRelation _focusedRelation; + private readonly Dictionary _selectedRelations = new Dictionary(); + private cHealthCard _selectedHealthcard = null; + private bool _hasDirectionConnection = false; + public cSupportCaseDataProvider SupportCaseDataProviderArtifact { get => _supportCaseProcessor?.SupportCaseDataProviderArtifact; } + + internal void SetSupportCaseProcessor(SupportCaseProcessor supportCaseProcessor, IEnumerable preselectedIdentities) + { + IEnumerable preselectedRelations = GetPreselectedRelations(supportCaseProcessor.GetCaseRelations(), preselectedIdentities); + + ResetSelectedRelations(preselectedRelations); + _hasDirectionConnection = false; + + if (_supportCaseProcessor != null) + { + _supportCaseProcessor.AvailableCaseRelationsAdded -= HandleAvailableCaseRelationsAdded; + _supportCaseProcessor.CaseDataChanged -= HandleCaseDataChanged; + _supportCaseProcessor.SupportCaseDataProviderArtifact.DirectConnectionHelper.DirectConnectionChanged -= HandleDirectConnectionChanged; + } + + _supportCaseProcessor = supportCaseProcessor; + + _supportCaseProcessor.AvailableCaseRelationsAdded += HandleAvailableCaseRelationsAdded; + _supportCaseProcessor.CaseDataChanged += HandleCaseDataChanged; + _supportCaseProcessor.SupportCaseDataProviderArtifact.DirectConnectionHelper.DirectConnectionChanged += HandleDirectConnectionChanged; + } + + private IEnumerable GetPreselectedRelations + (ILookup loadedRelations, IEnumerable preselectedIdentities) + { + List preselectedRelations = new List(); + + foreach (var relationType in loadedRelations) + { + foreach (var relation in relationType) + { + if (relation.Identities.All(ri => preselectedIdentities.Any(i => i.Id == ri.Id))) + preselectedRelations.Add(relation); + } + } + + return preselectedRelations; + } + + private void ResetSelectedRelations(IEnumerable preselectedRelations) + { + try + { + _selectedRelations.Clear(); + + if (preselectedRelations is null) + return; + + foreach (var relation in preselectedRelations) + { + _selectedRelations[cF4sdIdentityEntry.GetFromSearchResult(relation.Type)] = relation; + } + } + catch (Exception ex) + { + LogException(ex); + } + } + + private void HandleAvailableCaseRelationsAdded(object sender, RelationEventArgs e) + => AvailableCaseRelationsAdded?.Invoke(this, e); + + private void HandleCaseDataChanged(object sender, SupportCaseDataEventArgs e) + { + CaseDataChanged?.Invoke(this, e); + + _ = Task.Run(async () => + { + await UpdateStatusOfSelectedRelations(); + + if (!_hasDirectionConnection) + await SupportCaseDataProviderArtifact.DirectConnectionHelper.DirectConnectionStartAsync(); + }); + } + + private void HandleDirectConnectionChanged(object sender, EventArgs e) + { + _hasDirectionConnection = SupportCaseDataProviderArtifact.DirectConnectionHelper.IsDirectConnectionActive; + } + + /// + /// Updates the currently for a support case relevant and shown relation. + /// + /// Raises + internal void UpdateFocusedCaseRelation(cF4sdApiSearchResultRelation relation) + { + try + { + _selectedHealthcard = _supportCaseProcessor.GetHealthcardFor(relation); + HashSet requiredTables = cHealthCard.GetRequiredTables(_selectedHealthcard); + _ = Task.Run(async () => await _supportCaseProcessor.LoadSupportCaseDataAsync(relation, requiredTables)); + + List requiredInformationClasses = relation.Identities + .Where(i => i.Class != enumFasdInformationClass.User) + .Select(i => i.Class) + .ToList(); + + if (relation.Type == enumF4sdSearchResultClass.User) + requiredInformationClasses = new List() { enumFasdInformationClass.User }; + + if (requiredInformationClasses.Count == 0) + requiredInformationClasses.Add(enumFasdInformationClass.User); + + SupportCaseDataProviderArtifact.HealthCardDataHelper.TrySetSelectedHealthcard(requiredInformationClasses); + + _focusedRelation = relation; + + if (!_selectedRelations.Values.Contains(relation)) + _hasDirectionConnection = false; + + _selectedRelations[cF4sdIdentityEntry.GetFromSearchResult(relation.Type)] = relation; + _ = Task.Run(async () => await UpdateStatusOfSelectedRelations()); + + var focusedRelations = new cF4sdApiSearchResultRelation[1] { _focusedRelation }; + FocusedRelationsChanged?.Invoke(this, new RelationEventArgs() + { + Relations = focusedRelations.ToLookup(r => cF4sdIdentityEntry.GetFromSearchResult(r.Type), r => r) + }); + } + catch (Exception ex) + { + LogException(ex); + } + } + + private async Task UpdateStatusOfSelectedRelations() + { + const string StatusString = "Status"; + + try + { + int? agentUserId = null; + int? agentDeviceId = null; + + // todo these values should not be recieved from the NamedParameters, instead from the relation it self + if (SupportCaseDataProviderArtifact.NamedParameterEntries.TryGetValue("AgentUserId", out var userNamedParameter)) + { + var value = userNamedParameter.GetValue(); + if (!string.IsNullOrWhiteSpace(value)) + agentUserId = int.Parse(value); + } + + + // todo these values should not be recieved from the NamedParameters, instead from the relation it self + if (SupportCaseDataProviderArtifact.NamedParameterEntries.TryGetValue("AgentDeviceId", out var deviceNamedParameter)) + { + var value = deviceNamedParameter.GetValue(); + if (!string.IsNullOrWhiteSpace(value)) + agentDeviceId = int.Parse(deviceNamedParameter.GetValue()); + } + + foreach (var relationEntry in _selectedRelations) + { + if (relationEntry.Value is null) + continue; + + string statusValue = "Unknown"; + + switch (relationEntry.Key) + { + case enumFasdInformationClass.Computer: + if (!agentDeviceId.HasValue) + continue; + + bool isDeviceOnline = await cFasdCockpitCommunicationBase.Instance.GetAgentOnlineStatus(agentDeviceId.Value); + statusValue = isDeviceOnline ? "Online" : "Offline"; + break; + case enumFasdInformationClass.User: + if (!agentDeviceId.HasValue || !agentUserId.HasValue) + continue; + + bool isUserOnline = await cFasdCockpitCommunicationBase.Instance.GetAgentOnlineStatus(agentDeviceId.Value, agentUserId.Value); + statusValue = isUserOnline ? "Online" : "Offline"; + break; + case enumFasdInformationClass.Ticket: + case enumFasdInformationClass.VirtualSession: + case enumFasdInformationClass.MobileDevice: + default: + continue; + } + + if (relationEntry.Value.Infos is null) + relationEntry.Value.Infos = new Dictionary(); + + relationEntry.Value.Infos[StatusString] = statusValue; + } + + IEnumerable newHeadingData = SupportCaseHeadingController.GetHeadingData(_selectedRelations); + HeadingDataChanged?.Invoke(this, new HeadingDataEventArgs(newHeadingData)); + } + catch (Exception ex) + { + LogException(ex); + } + } + + public async Task RefreshDataForCurrentlyFocusedRelationAsync() + { + await _supportCaseProcessor.UpdateLatestCaseDataFor(_focusedRelation); + } + + public List> GetWidgetData() + => _supportCaseProcessor.GetWidgetData(_focusedRelation); + + public cDetailsPageDataHistoryDataModel GetHistoryData() + => _supportCaseProcessor.GetHistoryData(_focusedRelation); + + public List GetContainerData() + => _supportCaseProcessor.GetContainerData(_focusedRelation); + + public List GetMenuBarData() + => _supportCaseProcessor.GetMenuBarData(_focusedRelation); + + /// + /// Raised when the currently for a support case relevant and shown relations have been updated. + /// + public event EventHandler FocusedRelationsChanged; + + /// + /// Raised when newly available relations for a support case were added. + /// + public event EventHandler AvailableCaseRelationsAdded; + + /// + /// Raised when the data set of a support case has changed. + /// + public event EventHandler CaseDataChanged; + + public event EventHandler HeadingDataChanged; + } +} diff --git a/FasdDesktopUi/Basics/Services/SupportCase/Controllers/SupportCaseHeadingController.cs b/FasdDesktopUi/Basics/Services/SupportCase/Controllers/SupportCaseHeadingController.cs new file mode 100644 index 0000000..8c266e9 --- /dev/null +++ b/FasdDesktopUi/Basics/Services/SupportCase/Controllers/SupportCaseHeadingController.cs @@ -0,0 +1,93 @@ +using C4IT.FASD.Base; +using C4IT.MultiLanguage; +using FasdDesktopUi.Basics.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using static C4IT.Logging.cLogManager; + +namespace FasdDesktopUi.Basics.Services.SupportCase.Controllers +{ + internal class SupportCaseHeadingController + { + internal static IEnumerable GetHeadingData(Dictionary relations) + { + try + { + return Enum.GetValues(typeof(enumFasdInformationClass)) + .Cast() + .Select(informationClass => + { + if (relations.TryGetValue(informationClass, out var relation) && relation != null) + return GetHeadingDataFor(relation); + else + return GetEmptyHeadingDataFor(informationClass); + }); + } + catch (Exception ex) + { + LogException(ex); + } + + return Enumerable.Empty(); + } + + private static cHeadingDataModel GetEmptyHeadingDataFor(enumFasdInformationClass informationClass) + { + string headingText = string.Empty; + + switch (informationClass) + { + case enumFasdInformationClass.Computer: + headingText = cMultiLanguageSupport.GetItem("Header.Select.Computer"); + break; + case enumFasdInformationClass.Ticket: + headingText = cMultiLanguageSupport.GetItem("Header.Select.Ticket"); + break; + case enumFasdInformationClass.VirtualSession: + headingText = cMultiLanguageSupport.GetItem("Header.Select.VirtualSession"); + break; + case enumFasdInformationClass.MobileDevice: + headingText = cMultiLanguageSupport.GetItem("Header.Select.MobileDevice"); + break; + } + + return new cHeadingDataModel() { InformationClass = informationClass, HeadingText = headingText }; + } + + private static cHeadingDataModel GetHeadingDataFor(cF4sdApiSearchResultRelation relation) + { + const string StatusString = "Status"; + bool isOnline = false; + + string statusValue = "Unknown"; + if (relation?.Infos?.TryGetValue(StatusString, out var statusValueFromDictionary) ?? false) + statusValue = statusValueFromDictionary; + + switch (relation.Type) + { + case enumF4sdSearchResultClass.Computer: + case enumF4sdSearchResultClass.User: + isOnline = string.Equals(statusValue, "Online", StringComparison.InvariantCultureIgnoreCase); + break; + case enumF4sdSearchResultClass.Ticket: + isOnline = !string.Equals(statusValue, nameof(enumTicketStatus.Closed)); + break; + case enumF4sdSearchResultClass.VirtualSession: + isOnline = string.Equals(statusValue, nameof(enumCitrixSessionStatus.Active)); + break; + case enumF4sdSearchResultClass.MobileDevice: + break; + } + + return new cHeadingDataModel() + { + HeadingText = string.IsNullOrEmpty(relation.Name) ? relation.DisplayName : relation.Name, + InformationClass = cF4sdIdentityEntry.GetFromSearchResult(relation.Type), + IsOnline = isOnline, + Identities = relation.Identities, + Realtion = relation + }; + } + } +} diff --git a/FasdDesktopUi/Basics/Services/SupportCase/ISupportCase.cs b/FasdDesktopUi/Basics/Services/SupportCase/ISupportCase.cs index c6ded8f..4e5acd8 100644 --- a/FasdDesktopUi/Basics/Services/SupportCase/ISupportCase.cs +++ b/FasdDesktopUi/Basics/Services/SupportCase/ISupportCase.cs @@ -1,8 +1,9 @@ using C4IT.FASD.Base; -using FasdDesktopUi.Basics.Services.RelationService; +using FasdDesktopUi.Basics.CustomEvents; using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; namespace FasdDesktopUi.Basics.Services.SupportCase { @@ -12,10 +13,13 @@ namespace FasdDesktopUi.Basics.Services.SupportCase void Initialize(); void AddCaseRelations(ILookup relations); ILookup GetCaseRelations(); - IEnumerable GetSupportCaseHealthcardData(object identities, object valueAddress); - void UpdateSupportCaseDataCache(); + Task LoadSupportCaseDataAsync(cF4sdApiSearchResultRelation relation, IEnumerable tablesToLoad); + IEnumerable GetSupportCaseHealthcardData(cF4sdApiSearchResultRelation relation, cValueAddress valueAddress); + void UpdateSupportCaseDataCache(cF4sdApiSearchResultRelation relation, IEnumerable tables); + void InvalidateCaseDataCacheFor(cF4sdApiSearchResultRelation relation); + void InvalidateLatestCaseDataCacheFor(cF4sdApiSearchResultRelation relation, out ICollection invalidatedTables); event EventHandler CaseRelationsAdded; - event EventHandler SupportCaseDataCacheHasChanged; + event EventHandler SupportCaseDataCacheHasChanged; } } \ No newline at end of file diff --git a/FasdDesktopUi/Basics/Services/SupportCase/SupportCase.cs b/FasdDesktopUi/Basics/Services/SupportCase/SupportCase.cs index e67e929..3dde9b5 100644 --- a/FasdDesktopUi/Basics/Services/SupportCase/SupportCase.cs +++ b/FasdDesktopUi/Basics/Services/SupportCase/SupportCase.cs @@ -1,10 +1,10 @@ using C4IT.FASD.Base; +using C4IT.FASD.Cockpit.Communication; +using FasdDesktopUi.Basics.CustomEvents; using FasdDesktopUi.Basics.Services.RelationService; using System; using System.Collections.Generic; using System.Linq; -using System.Reflection; -using System.Text; using System.Threading.Tasks; using static C4IT.Logging.cLogManager; @@ -13,7 +13,7 @@ namespace FasdDesktopUi.Basics.Services.SupportCase public class SupportCase : ISupportCase { private readonly Dictionary> _caseRelations = new Dictionary>(); - //private readonly Lookup _supportCaseDataCache; + private readonly Dictionary> _supportCaseDataCache = new Dictionary>(); internal readonly Guid Id; private readonly IRelationService _relationService; @@ -67,12 +67,12 @@ namespace FasdDesktopUi.Basics.Services.SupportCase foreach (var relationType in relations) { if (_caseRelations.TryGetValue(relationType.Key, out var caseRelation)) - caseRelation = caseRelation.Union(relationType, new SearchResultRelationEqualityComparer()).ToList(); + caseRelation = caseRelation.Union(relationType).ToList(); else _caseRelations.Add(relationType.Key, relationType.ToList()); if (SupportCaseDataProviderArtifact?.CaseRelations?.TryGetValue(relationType.Key, out var caseRelations) ?? false) - caseRelations = caseRelations.Union(relationType, new SearchResultRelationEqualityComparer()).ToList(); + caseRelations = caseRelations.Union(relationType).ToList(); else SupportCaseDataProviderArtifact?.CaseRelations?.Add(relationType.Key, relationType.ToList()); } @@ -85,14 +85,158 @@ namespace FasdDesktopUi.Basics.Services.SupportCase } } - public void UpdateSupportCaseDataCache() + public async Task LoadSupportCaseDataAsync(cF4sdApiSearchResultRelation relation, IEnumerable tablesToLoad) { - throw new NotImplementedException(); + try + { + cF4SDHealthCardRawData rawData = null; + + // todo this is only a temporary fix. Currently the tablesToLoad contain also detail tables + // and tables won't be loaded e.g. the QuickActionHistory + bool isDataComplete = tablesToLoad.Any(t => + _supportCaseDataCache.TryGetValue(t, out var cachedTables) + && cachedTables.TryGetValue(relation, out var table) + && !table.IsIncomplete && !table.Columns.Values.Any(c => c.IsIncomplete) + ); + + var rawDataRequest = new cF4sdHealthCardRawDataRequest() + { + Identities = relation.Identities, + Tables = tablesToLoad.ToList(), + MaxAge = cF4SDCockpitXmlConfig.Instance?.HealthCardConfig?.SearchResultAge ?? 14 + }; + + while (!isDataComplete) + { + if (rawData is null) + { + rawData = await cFasdCockpitCommunicationBase.Instance.GetHealthCardData(rawDataRequest); + await SupportCaseDataProviderArtifact.HealthCardDataHelper.LoadingHelper.SetHealthCardRawData(rawData, rawDataRequest.Identities); + } + else + { + rawData = await cFasdCockpitCommunicationBase.Instance.GetHealthCardData(rawData.Id); + await SupportCaseDataProviderArtifact.HealthCardDataHelper.LoadingHelper.UpdateHealthcardRawData(rawData); + } + + UpdateSupportCaseDataCache(relation, rawData?.Tables?.Values); + + isDataComplete = rawData?.Tables? + .Where(table => table.Key.StartsWith("Computation_") == false) + .All(table => !table.Value.IsIncomplete && !table.Value.Columns.Values.Any(c => c.IsIncomplete)) ?? false; + } + } + catch (Exception ex) + { + LogException(ex); + } } - public IEnumerable GetSupportCaseHealthcardData(object identities, object valueAddress) + public void UpdateSupportCaseDataCache(cF4sdApiSearchResultRelation relation, IEnumerable tables) { - throw new NotImplementedException(); + try + { + if (tables is null) + return; + + List dataTables = tables?.ToList(); + + foreach (var table in dataTables) + { + if (string.IsNullOrEmpty(table.Name)) + continue; + + if (!_supportCaseDataCache.ContainsKey(table.Name)) + _supportCaseDataCache.Add(table.Name, new Dictionary()); + + if (!_supportCaseDataCache[table.Name].ContainsKey(relation)) + _supportCaseDataCache[table.Name][relation] = table; + else + MergeTable(_supportCaseDataCache[table.Name][relation], table); + } + + SupportCaseDataCacheHasChanged?.Invoke(this, new SupportCaseDataEventArgs() { Relation = relation, DataTables = dataTables }); + } + catch (Exception ex) + { + LogException(ex); + } + + void MergeTable(cF4SDHealthCardRawData.cHealthCardTable existingTable, cF4SDHealthCardRawData.cHealthCardTable newTable) + { + foreach (var newColumn in newTable.Columns) + { + existingTable.Columns[newColumn.Key] = newColumn.Value; + } + } + } + + public void InvalidateCaseDataCacheFor(cF4sdApiSearchResultRelation relation) + { + try + { + foreach (var tableCache in _supportCaseDataCache.Values) + { + tableCache.Remove(relation); + } + + // todo: invoke SupportCaseDataChache with empty tables + // SupportCaseDataCacheHasChanged?.Invoke(this, new SupportCaseDataEventArgs() { Relation = relation }); + } + catch (Exception ex) + { + LogException(ex); + } + } + + public void InvalidateLatestCaseDataCacheFor(cF4sdApiSearchResultRelation relation, out ICollection invalidatedTables) + { + invalidatedTables = new HashSet(); + try + { + foreach (var tableCache in _supportCaseDataCache.Values) + { + if (!tableCache.TryGetValue(relation, out cF4SDHealthCardRawData.cHealthCardTable table)) + continue; + + table.IsIncomplete = true; + + foreach (var column in table.Columns.Values) + { + column.Values[0] = null; + column.IsIncomplete = true; + } + + invalidatedTables.Add(table); + } + } + catch (Exception ex) + { + LogException(ex); + } + } + + public IEnumerable GetSupportCaseHealthcardData(cF4sdApiSearchResultRelation relation, cValueAddress valueAddress) + { + try + { + if (!_supportCaseDataCache.TryGetValue(valueAddress.ValueTable, out var tables)) + return null; + + if (!tables.TryGetValue(relation, out var table)) + return null; + + if (!table.Columns.TryGetValue(valueAddress.ValueColumn, out var column)) + return null; + + return column.Values; + } + catch (Exception ex) + { + LogException(ex); + } + + return null; } private void HandleRelationsFound(object sender, StagedSearchResultRelationsEventArgs e) @@ -107,19 +251,6 @@ namespace FasdDesktopUi.Basics.Services.SupportCase => AddCaseRelations(relations?.ToLookup(r => cF4sdIdentityEntry.GetFromSearchResult(r.Type), r => r)); public event EventHandler CaseRelationsAdded; - public event EventHandler SupportCaseDataCacheHasChanged; // Lookup for IdentitySet and tables which has been updated - - private class SearchResultRelationEqualityComparer : IEqualityComparer - { - public bool Equals(cF4sdApiSearchResultRelation x, cF4sdApiSearchResultRelation y) - { - return x.isEqual(y); - } - - public int GetHashCode(cF4sdApiSearchResultRelation obj) - { - return obj.GetHashCode(); - } - } + public event EventHandler SupportCaseDataCacheHasChanged; } } diff --git a/FasdDesktopUi/Basics/Services/SupportCase/SupportCaseFactory.cs b/FasdDesktopUi/Basics/Services/SupportCase/SupportCaseFactory.cs index 87089e0..3d46210 100644 --- a/FasdDesktopUi/Basics/Services/SupportCase/SupportCaseFactory.cs +++ b/FasdDesktopUi/Basics/Services/SupportCase/SupportCaseFactory.cs @@ -23,9 +23,6 @@ namespace FasdDesktopUi.Basics.Services.SupportCase if (primaryIdentity is null) throw new InvalidEnumArgumentException($"{nameof(primaryIdentity)} must not be null."); - if (primaryIdentity.Class != enumFasdInformationClass.User) - throw new InvalidEnumArgumentException($"{nameof(primaryIdentity)} must be of class {nameof(enumFasdInformationClass.User)}."); - if (_supportCases.TryGetValue(primaryIdentity.Id, out var supportCase)) { supportCase.Initialize(); diff --git a/FasdDesktopUi/Basics/Services/SupportCase/SupportCaseProcessor.cs b/FasdDesktopUi/Basics/Services/SupportCase/SupportCaseProcessor.cs new file mode 100644 index 0000000..8f8a8c3 --- /dev/null +++ b/FasdDesktopUi/Basics/Services/SupportCase/SupportCaseProcessor.cs @@ -0,0 +1,274 @@ +using C4IT.FASD.Base; +using C4IT.FASD.Cockpit.Communication; +using C4IT.Logging; +using FasdDesktopUi.Basics.CustomEvents; +using FasdDesktopUi.Basics.Models; +using FasdDesktopUi.Pages.DetailsPage.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using static C4IT.Logging.cLogManager; + +namespace FasdDesktopUi.Basics.Services.SupportCase +{ + /// + /// Used for processing raw data of a for the UI in a certain way. + /// + internal class SupportCaseProcessor + { + private ISupportCase _supportCase; + public cSupportCaseDataProvider SupportCaseDataProviderArtifact { get => _supportCase?.SupportCaseDataProviderArtifact; } + + private readonly Dictionary _detailsPageDataCache = new Dictionary(); + + private readonly Dictionary> _namedParameterCache = new Dictionary>(); + + internal void SetSupportCase(ISupportCase supportCase) + { + if (_supportCase != null) + { + _supportCase.CaseRelationsAdded -= HandleSupportCaseRelationsAdded; + _supportCase.SupportCaseDataCacheHasChanged -= HandleSupportCaseDataCacheHasChanged; + } + + _supportCase = supportCase; + + _supportCase.CaseRelationsAdded += HandleSupportCaseRelationsAdded; + _supportCase.SupportCaseDataCacheHasChanged += HandleSupportCaseDataCacheHasChanged; + } + + private void HandleSupportCaseRelationsAdded(object sender, RelationEventArgs e) + => AvailableCaseRelationsAdded?.Invoke(this, e); + + private async void HandleSupportCaseDataCacheHasChanged(object sender, SupportCaseDataEventArgs e) + { + bool isArtifactShowingCorrectHealthCard + = SupportCaseDataProviderArtifact.HealthCardDataHelper.SelectedHealthCard == GetHealthcardFor(e.Relation); + + if (!isArtifactShowingCorrectHealthCard) + { + // todo this can probably be removed, as soon as the last dependency of the SupportCaseDataProviderArtifact is gone. + // till then the detailspageData gets overriden with the detailspageData of the new relation. + // However, the removal shouldn't be much of a problem, due to the fact the Artifact also stores the raw data + _detailsPageDataCache.Remove(e.Relation); + return; + } + + if (_detailsPageDataCache.TryGetValue(e.Relation, out var cachedData)) + { + cDetailsPageData detailData = _supportCase.SupportCaseDataProviderArtifact.HealthCardDataHelper.DetailPage.GetDataWithoutHeading(); + cachedData.WidgetData = detailData.WidgetData; + cachedData.DataHistoryList = detailData.DataHistoryList; + cachedData.MenuBarData = detailData.MenuBarData; + cachedData.DataContainerCollectionList = detailData.DataContainerCollectionList; + } + else + { + _detailsPageDataCache[e.Relation] = await _supportCase.SupportCaseDataProviderArtifact.HealthCardDataHelper.DetailPage.GetDataAsync(); + } + + UpdateNamedParameters(e.Relation, e.DataTables); + CaseDataChanged?.Invoke(this, e); + } + + private void UpdateNamedParameters(cF4sdApiSearchResultRelation relation, IEnumerable dataTables) + { + try + { + if (!_namedParameterCache.ContainsKey(relation)) + _namedParameterCache.Add(relation, new Dictionary()); + + var healthcard = GetHealthcardFor(relation); + + foreach (var namedParameter in cHealthCardPrerequisites.GetNamedParameters(healthcard).Values) + { + var table = dataTables.FirstOrDefault(t => t.Name == namedParameter.DatabaseInfo.ValueTable); + + if (table is null) + continue; + + if (!table.Columns.TryGetValue(namedParameter.DatabaseInfo.ValueColumn, out var column)) + continue; + + string value = cUtility.RawValueFormatter.GetDisplayValue(column.Values.FirstOrDefault(), namedParameter.Display); + _namedParameterCache[relation][namedParameter.ParameterName] = value; + } + } + catch (Exception ex) + { + LogException(ex); + } + } + + public async Task LoadSupportCaseDataAsync(cF4sdApiSearchResultRelation relation, IEnumerable tablesToLoad) + { + _ = Task.Run(async () => await _supportCase.LoadSupportCaseDataAsync(relation, tablesToLoad.Where(t => !t.Contains("-details-")))); + + if (!_detailsPageDataCache.TryGetValue(relation, out var detailsData)) + { + detailsData = await _supportCase.SupportCaseDataProviderArtifact.HealthCardDataHelper.DetailPage.GetDataAsync(); + _detailsPageDataCache.Add(relation, detailsData); + } + + CaseDataChanged?.Invoke(this, new SupportCaseDataEventArgs()); + } + + public async Task UpdateLatestCaseDataFor(cF4sdApiSearchResultRelation relation) + { + try + { + int? agentUserId = relation.Identities.FirstOrDefault(i => i.Class == enumFasdInformationClass.User)?.agentId; + int? agentDeviceId = relation.Identities.FirstOrDefault(i => i.Class == enumFasdInformationClass.Computer)?.agentId; + + await ActualizeDataAsync(agentUserId, agentDeviceId); + _supportCase.InvalidateLatestCaseDataCacheFor(relation, out var invalidatedTables); + _detailsPageDataCache.Remove(relation); + await _supportCase.LoadSupportCaseDataAsync(relation, invalidatedTables.Select(t => t.Name)); + } + catch (Exception ex) + { + LogException(ex); + } + } + + private async Task ActualizeDataAsync(int? agentUserId, int? agentDeviceId) + { + var status = enumActualizeStatus.unknown; + + try + { + TimeSpan refreshDelay = TimeSpan.FromMilliseconds(500); + const int maxPollCount = 20; + + if (!agentDeviceId.HasValue) + { + LogEntry("Coudldn't acutalize data. There was no valid AgentDeviceId found.", LogLevels.Error); + return status; + } + + var taskId = await cFasdCockpitCommunicationBase.Instance.ActualizeAgentData(agentDeviceId.Value, agentUserId); + + if (taskId == Guid.Empty) + return enumActualizeStatus.failed; + + enumFasdInformationClass informationClass = agentUserId != null ? enumFasdInformationClass.User : enumFasdInformationClass.Computer; + int pollCount = 0; + + do + { + status = await cFasdCockpitCommunicationBase.Instance.GetActualizeAgentDataStatus(taskId, informationClass); + + if (status == enumActualizeStatus.unknown) + { + pollCount++; + if (pollCount >= maxPollCount) + return status; + + await Task.Delay(refreshDelay); + } + } while (status == enumActualizeStatus.unknown); + } + catch (Exception E) + { + LogException(E); + } + + return status; + } + + internal ILookup GetCaseRelations() + => _supportCase.GetCaseRelations(); + + internal cHealthCard GetHealthcardFor(cF4sdApiSearchResultRelation relation) + { + var availableHealthCards = cF4SDCockpitXmlConfig.Instance?.HealthCardConfig?.HealthCards?.Values; + + if (availableHealthCards is null || availableHealthCards.Count == 0) + return null; + + return availableHealthCards + .FirstOrDefault(hc => + hc.InformationClasses.All(i => i == cF4sdIdentityEntry.GetFromSearchResult(relation.Type)) + && HasCockpitUserRequiredRoles(hc.RequiredRoles)); + } + + private static bool HasCockpitUserRequiredRoles(List requiredRoles) + { + try + { + if (requiredRoles is null || requiredRoles.Count == 0) + return true; + + List roles = null; + lock (cFasdCockpitCommunicationBase.CockpitUserInfoLock) + { + roles = cFasdCockpitCommunicationBase.CockpitUserInfo?.Roles; + } + if (roles is null || roles.Count == 0) + return false; + + foreach (var requiredRole in requiredRoles) + { + if (roles.Contains(requiredRole, StringComparer.InvariantCultureIgnoreCase)) + return true; + } + } + catch (Exception E) + { + LogException(E); + } + return false; + } + + public List> GetWidgetData(cF4sdApiSearchResultRelation relation) + { + List> widgetData = null; + + if (_detailsPageDataCache.TryGetValue(relation, out var detailsData)) + widgetData = detailsData?.WidgetData; + + return widgetData ?? new List>(); + } + + public cDetailsPageDataHistoryDataModel GetHistoryData(cF4sdApiSearchResultRelation relation) + { + cDetailsPageDataHistoryDataModel historyData = null; + + if (_detailsPageDataCache.TryGetValue(relation, out var detailsData)) + historyData = detailsData?.DataHistoryList; + + return historyData ?? new cDetailsPageDataHistoryDataModel(); + } + + public List GetContainerData(cF4sdApiSearchResultRelation relation) + { + List containerData = null; + + if (_detailsPageDataCache.TryGetValue(relation, out var detailsData)) + containerData = detailsData?.DataContainerCollectionList; + + return containerData ?? new List(); + } + + public List GetMenuBarData(cF4sdApiSearchResultRelation relation) + { + List menuData = null; + + if (_detailsPageDataCache.TryGetValue(relation, out var detailsData)) + menuData = detailsData?.MenuBarData; + + return menuData ?? new List(); + } + + /// + /// Raised when newly available relations for a support case were added. + /// + public event EventHandler AvailableCaseRelationsAdded; + + /// + /// Raised when the data set of a support case has changed. + /// + public event EventHandler CaseDataChanged; + } +} diff --git a/FasdDesktopUi/Basics/Services/SupportCase/SupportCaseProcessorFactory.cs b/FasdDesktopUi/Basics/Services/SupportCase/SupportCaseProcessorFactory.cs new file mode 100644 index 0000000..15ade05 --- /dev/null +++ b/FasdDesktopUi/Basics/Services/SupportCase/SupportCaseProcessorFactory.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; + +namespace FasdDesktopUi.Basics.Services.SupportCase +{ + internal class SupportCaseProcessorFactory + { + private readonly static Dictionary _supportCaseProccesors = new Dictionary(); + + internal static SupportCaseProcessor Get(Guid id) + { + if (!_supportCaseProccesors.ContainsKey(id)) + _supportCaseProccesors.Add(id, new SupportCaseProcessor()); + + return _supportCaseProccesors[id]; + } + } +} diff --git a/FasdDesktopUi/Basics/Services/TicketOverviewUpdateService.cs b/FasdDesktopUi/Basics/Services/TicketOverviewUpdateService.cs index 87582d2..68d9c2b 100644 --- a/FasdDesktopUi/Basics/Services/TicketOverviewUpdateService.cs +++ b/FasdDesktopUi/Basics/Services/TicketOverviewUpdateService.cs @@ -7,8 +7,9 @@ using System.Windows.Threading; using C4IT.FASD.Base; using C4IT.FASD.Cockpit.Communication; -using FasdDesktopUi.Basics.Models; -using FasdDesktopUi.Basics.Services.Models; +using FasdDesktopUi; +using FasdDesktopUi.Basics.Models; +using FasdDesktopUi.Basics.Services.Models; #if isDemo using System.Net; using FasdCockpitCommunicationDemo; @@ -19,11 +20,10 @@ namespace FasdDesktopUi.Basics.Services { public sealed class TicketOverviewUpdateService { - private static readonly TimeSpan RefreshInterval = TimeSpan.FromMinutes(5); - private static readonly string[] OverviewKeys = new[] - { - "TicketsNew", - "TicketsActive", + private static readonly string[] OverviewKeys = new[] + { + "TicketsNew", + "TicketsActive", "TicketsCritical", "TicketsNewInfo", "IncidentNew", @@ -33,16 +33,22 @@ namespace FasdDesktopUi.Basics.Services "UnassignedTickets", "UnassignedTicketsCritical" }; - private const string DemoTicketDetailsKey = "Demo.HasTicketDetails"; - private readonly Dispatcher _dispatcher; - private readonly Dictionary _currentCounts = new Dictionary(StringComparer.OrdinalIgnoreCase); - private readonly Dictionary<(string Key, bool UseRoleScope), List> _demoRelations = new Dictionary<(string, bool), List>(); - private DispatcherTimer _timer; - private bool _isFetching; - private bool _fetchRetryPending; - private bool _isDemo; - private bool _initialized; - private readonly Random _random = new Random(); + private const string DemoTicketDetailsKey = "Demo.HasTicketDetails"; + private readonly Dispatcher _dispatcher; + private readonly Dictionary _currentCounts = new Dictionary(StringComparer.OrdinalIgnoreCase); + private readonly Dictionary<(string Key, bool UseRoleScope), List> _demoRelations = new Dictionary<(string, bool), List>(); + private readonly HashSet _pendingScopes = new HashSet(); + private readonly HashSet _initializedScopes = new HashSet(); + private readonly object _fetchLock = new object(); + private readonly HashSet _retryScopes = new HashSet(); + private DispatcherTimer _personalTimer; + private DispatcherTimer _roleTimer; + private Task _fetchWorker; + private bool _retryScheduled; + private bool _isDemo; + private bool _initialized; + private bool _isEnabled; + private readonly Random _random = new Random(); #if isDemo private readonly List _persistedDemoTickets = new List(); private readonly List _demoTemplates = new List(); @@ -67,138 +73,338 @@ namespace FasdDesktopUi.Basics.Services #endif } - static TicketOverviewUpdateService() - { -#if isDemo - Instance = new TicketOverviewUpdateService(); -#endif - } - - public static TicketOverviewUpdateService Instance { get; } = null; + static TicketOverviewUpdateService() + { + Instance = new TicketOverviewUpdateService(); + } + + public static TicketOverviewUpdateService Instance { get; } public event EventHandler OverviewCountsChanged; - public IReadOnlyDictionary CurrentCounts => _currentCounts; + public IReadOnlyDictionary CurrentCounts => _currentCounts; + + public bool IsScopeInitialized(TileScope scope) + { + lock (_fetchLock) + { + return _initializedScopes.Contains(scope); + } + } + + public bool AreAllScopesInitialized + { + get + { + lock (_fetchLock) + { + return _initializedScopes.Contains(TileScope.Personal) + && _initializedScopes.Contains(TileScope.Role); + } + } + } - public void Start() - { - if (_initialized) - return; + public void Start() + { + UpdateAvailability(true); + } + + public void Stop() + { + UpdateAvailability(false); + } + + public void UpdateAvailability(bool isEnabled) + { + if (isEnabled) + { + if (!_isEnabled) + { + _isEnabled = true; + StartInternal(); + } + else + { + RefreshTimerIntervals(); + } + } + else + { + if (_isEnabled) + StopInternal(); + + _isEnabled = false; + } + } + + private void StartInternal() + { + if (_initialized) + return; + + _initialized = true; +#if isDemo + _isDemo = true; + LoadPersistedDemoTickets(); +#else + _isDemo = cFasdCockpitCommunicationBase.Instance?.IsDemo() == true; +#endif + + InitializeTimers(); + _ = FetchAsync(); + } + + private void StopInternal() + { + if (!_initialized) + return; + + _initialized = false; + lock (_fetchLock) + { + _pendingScopes.Clear(); + _initializedScopes.Clear(); + } + + lock (_retryScopes) + { + _retryScheduled = false; + _retryScopes.Clear(); + } + + _dispatcher.InvokeAsync(() => + { + _personalTimer?.Stop(); + _roleTimer?.Stop(); + _personalTimer = null; + _roleTimer = null; + + foreach (var key in OverviewKeys) + { + _currentCounts[key] = TileCounts.Empty; + } + }); + } + + private void InitializeTimers() + { + _personalTimer = CreateScopeTimer(TileScope.Personal); + _roleTimer = CreateScopeTimer(TileScope.Role); + + _personalTimer?.Start(); + _roleTimer?.Start(); + } + + private DispatcherTimer CreateScopeTimer(TileScope scope) + { + var interval = GetPollingInterval(scope); + var timer = new DispatcherTimer(interval, DispatcherPriority.Background, async (s, e) => await FetchAsync(scope).ConfigureAwait(false), _dispatcher) + { + IsEnabled = false + }; + return timer; + } + + private TimeSpan GetPollingInterval(TileScope scope) + { + var ticketConfig = cFasdCockpitConfig.Instance?.Global?.TicketConfiguration; + int minutes = scope == TileScope.Role + ? cF4sdTicketConfig.DefaultOverviewPollingRole + : cF4sdTicketConfig.DefaultOverviewPollingPersonal; + + if (ticketConfig != null) + { + minutes = scope == TileScope.Role + ? ticketConfig.OverviewPollingRole + : ticketConfig.OverviewPollingPersonal; + } + + if (minutes < 1) + minutes = 1; + + return TimeSpan.FromMinutes(minutes); + } - _initialized = true; -#if isDemo - _isDemo = true; - LoadPersistedDemoTickets(); -#else - _isDemo = cFasdCockpitCommunicationBase.Instance?.IsDemo() == true; -#endif - - if (!_isDemo) - { - _timer = new DispatcherTimer(RefreshInterval, DispatcherPriority.Background, async (s, e) => await FetchAsync().ConfigureAwait(false), _dispatcher); - _timer.Start(); - _ = FetchAsync(); - } - else - { - _ = FetchAsync(); - } - } - - public async Task FetchAsync() - { - if (_isFetching) - return; - - var communication = cFasdCockpitCommunicationBase.Instance; - if (communication == null) - { - ScheduleFetchRetry(); - return; - } - - _isFetching = true; - try - { - _isDemo = communication?.IsDemo() == true; - if (_isDemo && _timer != null) - { - _timer.Stop(); - _timer = null; - } - var counts = await Task.Run(() => RetrieveCountsAsync()).ConfigureAwait(false); - if (counts != null) - { - await _dispatcher.InvokeAsync(() => ProcessCounts(counts)); - } - } - finally - { - _isFetching = false; - } - } - - private Dictionary RetrieveCountsAsync() - { - var communication = cFasdCockpitCommunicationBase.Instance; - if (communication == null) - return null; - - var result = new Dictionary(StringComparer.OrdinalIgnoreCase); - - foreach (var key in OverviewKeys) - { - var personalTask = communication.GetTicketOverviewRelations(key, useRoleScope: false, count: 0); - var roleTask = communication.GetTicketOverviewRelations(key, useRoleScope: true, count: 0); - Task.WaitAll(personalTask, roleTask); - - int personalCount = personalTask.Result?.Count ?? 0; - int roleCount = roleTask.Result?.Count ?? 0; - - if (_isDemo) - { - personalCount += GetDemoRelationCount(key, useRoleScope: false); - roleCount += GetDemoRelationCount(key, useRoleScope: true); - } - - result[key] = new TileCounts(personalCount, roleCount); - } - - return result; - } - - private void ProcessCounts(Dictionary newCounts) - { - var changes = new List(); - bool hasPrevious = _currentCounts.Values.Any(tc => tc.Personal > 0 || tc.Role > 0); - - foreach (var key in OverviewKeys) - { - var previous = _currentCounts[key]; - var current = newCounts.TryGetValue(key, out var value) ? value : TileCounts.Empty; - - if (previous.Personal != current.Personal) - { - changes.Add(new TileCountChange(key, TileScope.Personal, previous.Personal, current.Personal)); - } - - if (previous.Role != current.Role) - { - changes.Add(new TileCountChange(key, TileScope.Role, previous.Role, current.Role)); - } - - _currentCounts[key] = current; - } - - if (!hasPrevious) - return; - - if (changes.Count == 0) - return; - - var args = new TicketOverviewCountsChangedEventArgs(changes, new Dictionary(_currentCounts)); - OverviewCountsChanged?.Invoke(this, args); - } + public Task FetchAsync() + { + if (!_isEnabled) + return Task.CompletedTask; + + return QueueFetchAsync(new[] { TileScope.Personal, TileScope.Role }); + } + + public Task FetchAsync(TileScope scope) + { + if (!_isEnabled) + return Task.CompletedTask; + + return QueueFetchAsync(new[] { scope }); + } + + private Task QueueFetchAsync(IEnumerable scopes) + { + if (!_isEnabled) + return Task.CompletedTask; + + if (scopes == null) + return Task.CompletedTask; + + lock (_fetchLock) + { + foreach (var scope in scopes) + { + _pendingScopes.Add(scope); + } + + if (_fetchWorker == null || _fetchWorker.IsCompleted) + { + _fetchWorker = Task.Run(ProcessFetchQueueAsync); + } + + return _fetchWorker; + } + } + + private async Task ProcessFetchQueueAsync() + { + while (true) + { + TileScope scope; + + lock (_fetchLock) + { + if (_pendingScopes.Count == 0) + { + _fetchWorker = null; + return; + } + + scope = _pendingScopes.First(); + _pendingScopes.Remove(scope); + } + + await FetchScopeAsync(scope).ConfigureAwait(false); + } + } + + private async Task FetchScopeAsync(TileScope scope) + { + if (!_isEnabled) + return; + + var communication = cFasdCockpitCommunicationBase.Instance; + if (communication == null) + { + ScheduleFetchRetry(scope); + return; + } + + try + { + _isDemo = communication.IsDemo(); + + var rawCounts = await communication.GetTicketOverviewCounts(OverviewKeys, scope == TileScope.Role).ConfigureAwait(false); + var counts = new Dictionary(StringComparer.OrdinalIgnoreCase); + + if (rawCounts != null) + { + foreach (var kvp in rawCounts) + { + if (string.IsNullOrWhiteSpace(kvp.Key)) + continue; + + counts[kvp.Key] = Math.Max(0, kvp.Value); + } + } + + if (_isDemo) + { + foreach (var key in OverviewKeys) + { + var extras = GetDemoRelationCount(key, scope == TileScope.Role); + if (counts.ContainsKey(key)) + counts[key] += extras; + else + counts[key] = extras; + } + } + + if (!_isEnabled) + return; + + await _dispatcher.InvokeAsync(() => ProcessScopeCounts(scope, counts)); + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"[TicketOverview] Fetch {scope} failed: {ex}"); + ScheduleFetchRetry(scope); + } + } + + private void RefreshTimerIntervals() + { + _dispatcher.InvokeAsync(() => + { + if (_personalTimer != null) + _personalTimer.Interval = GetPollingInterval(TileScope.Personal); + + if (_roleTimer != null) + _roleTimer.Interval = GetPollingInterval(TileScope.Role); + }); + } + + private void ProcessScopeCounts(TileScope scope, IDictionary newCounts) + { + if (newCounts == null) + return; + + var hasInitializedScope = _initializedScopes.Contains(scope); + var changes = new List(); + + foreach (var key in OverviewKeys) + { + var previous = _currentCounts.TryGetValue(key, out var counts) ? counts : TileCounts.Empty; + var incoming = newCounts.TryGetValue(key, out var value) ? value : 0; + + TileCounts updated; + int oldValue; + + if (scope == TileScope.Role) + { + updated = new TileCounts(previous.Personal, incoming); + oldValue = previous.Role; + } + else + { + updated = new TileCounts(incoming, previous.Role); + oldValue = previous.Personal; + } + + _currentCounts[key] = updated; + + if (hasInitializedScope && oldValue != incoming) + { + changes.Add(new TileCountChange(key, scope, oldValue, incoming)); + } + } + + if (!hasInitializedScope) + { + _initializedScopes.Add(scope); + var initArgs = new TicketOverviewCountsChangedEventArgs( + Array.Empty(), + new Dictionary(_currentCounts, StringComparer.OrdinalIgnoreCase), + scope); + OverviewCountsChanged?.Invoke(this, initArgs); + return; + } + + if (changes.Count == 0) + return; + + var args = new TicketOverviewCountsChangedEventArgs(changes, new Dictionary(_currentCounts, StringComparer.OrdinalIgnoreCase)); + OverviewCountsChanged?.Invoke(this, args); + } public void SimulateDemoTicket() { @@ -318,9 +524,9 @@ namespace FasdDesktopUi.Basics.Services if (appliedChanges.Count == 0) return; - var args = new TicketOverviewCountsChangedEventArgs(appliedChanges, new Dictionary(_currentCounts)); - OverviewCountsChanged?.Invoke(this, args); - } + var args = new TicketOverviewCountsChangedEventArgs(appliedChanges, new Dictionary(_currentCounts)); + OverviewCountsChanged?.Invoke(this, args); + } private void AddRelationForRecord(DemoTicketRecord record) { @@ -577,24 +783,43 @@ namespace FasdDesktopUi.Basics.Services return 0; } - private void ScheduleFetchRetry() - { - if (_fetchRetryPending) - return; - - _fetchRetryPending = true; - _ = _dispatcher.InvokeAsync(async () => - { - try - { - await Task.Delay(250).ConfigureAwait(false); - await FetchAsync().ConfigureAwait(false); - } - finally - { - _fetchRetryPending = false; - } - }, DispatcherPriority.Background); - } + private void ScheduleFetchRetry(TileScope scope) + { + if (!_isEnabled) + return; + + lock (_retryScopes) + { + _retryScopes.Add(scope); + if (_retryScheduled) + return; + + _retryScheduled = true; + } + + _ = _dispatcher.InvokeAsync(async () => + { + try + { + await Task.Delay(TimeSpan.FromSeconds(5)).ConfigureAwait(false); + TileScope[] scopes; + lock (_retryScopes) + { + scopes = _retryScopes.ToArray(); + _retryScopes.Clear(); + _retryScheduled = false; + } + + foreach (var pendingScope in scopes) + { + await FetchAsync(pendingScope).ConfigureAwait(false); + } + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"[TicketOverview] Retry scheduling failed: {ex}"); + } + }, DispatcherPriority.Background); + } } -} \ No newline at end of file +} diff --git a/FasdDesktopUi/Basics/SupportCaseDataProvider.cs b/FasdDesktopUi/Basics/SupportCaseDataProvider.cs index 8702a06..70b4bb5 100644 --- a/FasdDesktopUi/Basics/SupportCaseDataProvider.cs +++ b/FasdDesktopUi/Basics/SupportCaseDataProvider.cs @@ -6,7 +6,8 @@ using System.Windows; using System.Windows.Documents; using System.Linq; using System.Windows.Input; -using System.Diagnostics; +using System.Diagnostics; +using System.Windows.Threading; using C4IT.FASD.Base; using C4IT.Logging; @@ -26,6 +27,8 @@ using Newtonsoft.Json; using FasdDesktopUi.Basics.Services.ProtocollService; using FasdDesktopUi.Basics.Services.SupportCase; using FasdDesktopUi.Basics.Services.RelationService; +using FasdDesktopUi.Basics.Services.SupportCase.Controllers; +using C4IT.F4SD.SupportCaseProtocoll.Models; namespace FasdDesktopUi.Basics @@ -100,10 +103,10 @@ namespace FasdDesktopUi.Basics QuickActionProtocollHelper = new cQuickActionProtocollHelper(this); } - public static async Task GetDataProviderForAsync(List storedRelations, cF4sdApiSearchResultRelation selectedRelation, IRelationService relationService) - { - try - { + public static async Task GetDataProviderForAsync(cF4sdApiSearchResultRelation selectedRelation, IRelationService relationService) + { + try + { if (selectedRelation == null) { Debug.Assert(true, "The selected relation must not be null here!"); @@ -147,43 +150,68 @@ namespace FasdDesktopUi.Basics cSupportCaseDataProvider.CurrentProvider = null; } - if (!DataProviders.TryGetValue(MainIdentity.Id, out var _result)) - { - _result = new cSupportCaseDataProvider(); - DataProviders.Add(MainIdentity.Id, _result); - } - - _result.NamedParameterEntries = new cNamedParameterList(_result); - - _result.StartCase(MainIdentity.Id); + if (!DataProviders.TryGetValue(MainIdentity.Id, out var _result)) + { + _result = new cSupportCaseDataProvider(); + DataProviders.Add(MainIdentity.Id, _result); + } + + await EnsureSupportCasePagesAsync(); + + _result.NamedParameterEntries = new cNamedParameterList(_result); + + _result.StartCase(MainIdentity.Id); var supportCase = SupportCaseFactory.Get(MainIdentity, relationService, _result); - cSupportCaseDataProvider.detailsPage.SetSupportCase(supportCase); - cSupportCaseDataProvider.slimPage.SetSupportCase(supportCase); + var supportCaseProcessor = SupportCaseProcessorFactory.Get(MainIdentity.Id); + var supportCaseController = new SupportCaseController(); + + supportCaseProcessor.SetSupportCase(supportCase); + supportCaseController.SetSupportCaseProcessor(supportCaseProcessor, Identities); + + if (cSupportCaseDataProvider.detailsPage == null || cSupportCaseDataProvider.slimPage == null) + { + LogEntry("Support case pages are not initialized; aborting case start.", LogLevels.Error); + return null; + } + + cSupportCaseDataProvider.detailsPage.SetSupportCaseController(supportCaseController); + cSupportCaseDataProvider.slimPage.SetSupportCaseController(supportCaseController); var Status = await _result.SetViewDataAsync(requiredInformationClasses, Identities, true); + + cF4sdApiSearchResultRelation relationToFocus = GetRelationToFocus(selectedRelation, relationService.GetLoadedRelations()); + // relation to focus may not have all identities + supportCaseController.UpdateFocusedCaseRelation(relationToFocus); if (!Status) return null; + var selectedHealthCard = _result.HealthCardDataHelper?.SelectedHealthCard; + if (selectedHealthCard != null) + _ = cHealthCard.GetRequiredTables(selectedHealthCard); // todo the healthcard is not selected at this point + + if (detailsPage?.WidgetCollection != null) + detailsPage.WidgetCollection.WidgetDataList = supportCaseController.GetWidgetData(); + if (detailsPage?.DataHistoryCollectionUserControl != null) + detailsPage.DataHistoryCollectionUserControl.HistoryDataList = supportCaseController.GetHistoryData(); + if (detailsPage?.CustomizableSectionUc != null) + detailsPage.CustomizableSectionUc.ContainerCollections = supportCaseController.GetContainerData(); + CurrentProvider = _result; - // start the direct connection - if (_result.DirectConnectionHelper.IsDirectConnectionActive is false) - _ = Task.Run(async () => - { - try - { - await _result.DirectConnectionHelper.DirectConnectionStartAsync(); - } - catch { } - }); - // start the slim or detaild page - bool shouldSkipSlimView = Identities.Any(identity => identity.Class is enumFasdInformationClass.Ticket) || cFasdCockpitConfig.Instance.Global.ShouldSkipSlimView; - if (shouldSkipSlimView) - cSupportCaseDataProvider.detailsPage?.Show(); - else - cSupportCaseDataProvider.slimPage.Show(); + bool shouldSkipSlimView = (Identities?.Any(identity => identity.Class is enumFasdInformationClass.Ticket) ?? false) + || (cFasdCockpitConfig.Instance?.Global?.ShouldSkipSlimView ?? false); + if (shouldSkipSlimView) + { + cSupportCaseDataProvider.detailsPage?.Show(); + cSupportCaseDataProvider.slimPage?.Hide(); + } + else + { + cSupportCaseDataProvider.slimPage?.Show(); + cSupportCaseDataProvider.detailsPage?.Hide(); + } return _result; } @@ -194,11 +222,35 @@ namespace FasdDesktopUi.Basics return null; } - public void StartCase(Guid userId) + private static cF4sdApiSearchResultRelation GetRelationToFocus(cF4sdApiSearchResultRelation selectedRelation, IEnumerable loadedRelations) { - var CM = MethodBase.GetCurrentMethod(); - LogMethodBegin(CM); try + { + if (selectedRelation.Type != enumF4sdSearchResultClass.User) + return selectedRelation; + + cF4sdIdentityEntry alternativeIdentity = selectedRelation.Identities.FirstOrDefault(i => i.Class != enumFasdInformationClass.User); + cF4sdApiSearchResultRelation relationToFocus = loadedRelations.FirstOrDefault(r => r.id == alternativeIdentity?.Id && cF4sdIdentityEntry.GetFromSearchResult(r.Type) == alternativeIdentity.Class); + + if (relationToFocus is null) + return selectedRelation; + + relationToFocus.Identities = selectedRelation.Identities; + return relationToFocus; + } + catch (Exception ex) + { + LogException(ex); + } + + return selectedRelation; + } + + public void StartCase(Guid userId) + { + var CM = MethodBase.GetCurrentMethod(); + LogMethodBegin(CM); + try { lock (caseIdLockObject) { @@ -238,11 +290,28 @@ namespace FasdDesktopUi.Basics { LogException(E); } - finally - { - LogMethodEnd(CM); - } - } + finally + { + LogMethodEnd(CM); + } + } + + private static async Task EnsureSupportCasePagesAsync() + { + if (detailsPage != null && slimPage != null) + return; + + if (Application.Current == null) + return; + + await Application.Current.Dispatcher.InvokeAsync(() => + { + if (slimPage == null) + slimPage = new Pages.SlimPage.SlimPageView(); + if (detailsPage == null) + detailsPage = new Pages.DetailsPage.DetailsPageView(); + }, DispatcherPriority.Normal); + } public async Task CloseCaseAsync() { @@ -452,35 +521,12 @@ namespace FasdDesktopUi.Basics } } - var isOk = await HealthCardDataHelper.LoadingHelper.GetHealthCardRawDataAsync(new cF4sdHealthCardRawDataRequest() - { - Identities = Identities, - Tables = requiredTables.ToList(), - MaxAge = cF4SDCockpitXmlConfig.Instance?.HealthCardConfig?.SearchResultAge ?? 14 - }); if (isNewCase) HealthCardDataHelper.LoadingHelper.LastDataRequest = DateTime.Now; - if (isOk == false) - { - string identityString = ""; - - foreach (var identity in Identities) - { - identityString += "\n" + identity.Id + " (Type: " + identity.Class + ")"; - } - - LogEntry($"Error trying to receive healthcard data for following identities: {identityString}", LogLevels.Error); - CustomMessageBox.Show($"Error trying to receive healthcard data for following identities: {identityString}", "Data Error", enumHealthCardStateLevel.Error); - return false; - } - var slimPageData = await HealthCardDataHelper.SlimCard.GetDataAsync(); - var detailsPageData = await HealthCardDataHelper.DetailPage.GetDataAsync(); - slimPage?.SetPropertyValues(slimPageData); - detailsPage?.SetPropertyValues(detailsPageData); return true; } @@ -545,11 +591,6 @@ namespace FasdDesktopUi.Basics } relationIdentity.CopyTo(existingIdentity); } - else - { - Identities.Add(relationIdentity.CreateCopy()); - ComputerAdded |= relationIdentity.Class == enumFasdInformationClass.Computer; - } } @@ -561,16 +602,6 @@ namespace FasdDesktopUi.Basics var searchResultInfoClass = cF4sdIdentityEntry.GetFromSearchResult(searchResultRelation.Type); await SetViewDataAsync(new List() { searchResultInfoClass }, Identities, false); - if (ComputerAdded) - _ = Task.Run(async () => - { - try - { - await DirectConnectionHelper.DirectConnectionStartAsync(); - } - catch { } - }); - } catch (Exception E) { diff --git a/FasdDesktopUi/Basics/UiActions/ChangeHealthCardAction.cs b/FasdDesktopUi/Basics/UiActions/ChangeHealthCardAction.cs index f5f3850..fc558d3 100644 --- a/FasdDesktopUi/Basics/UiActions/ChangeHealthCardAction.cs +++ b/FasdDesktopUi/Basics/UiActions/ChangeHealthCardAction.cs @@ -1,24 +1,11 @@ using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; using System.Reflection; -using System.Security.Cryptography.X509Certificates; -using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Input; - using C4IT.FASD.Base; -using C4IT.FASD.Cockpit.Communication; -using C4IT.Logging; -using C4IT.MultiLanguage; - -using FasdDesktopUi.Basics.Models; - -using FasdDesktopUi.Basics.UserControls; +using FasdDesktopUi.Basics.Services.SupportCase.Controllers; using FasdDesktopUi.Pages.DetailsPage; -using FasdDesktopUi.Pages.DetailsPage.UserControls; using static C4IT.Logging.cLogManager; @@ -26,11 +13,14 @@ namespace FasdDesktopUi.Basics.UiActions { public class cChangeHealthCardAction : cUiActionBase { + private readonly SupportCaseController _supportCaseController; + public cF4sdApiSearchResultRelation ResultRelation { get; private set; } = null; - public cChangeHealthCardAction(cF4sdApiSearchResultRelation resultRelation) + public cChangeHealthCardAction(cF4sdApiSearchResultRelation resultRelation, SupportCaseController supportCaseController) { ResultRelation = resultRelation; + _supportCaseController = supportCaseController; } public override async Task RunUiActionAsync(object sender, UIElement UiLocation, bool isDetailedLayout, cSupportCaseDataProvider dataProvider) @@ -52,6 +42,8 @@ namespace FasdDesktopUi.Basics.UiActions detailsPage.NavigationHeadingUc.ResetSelectors(); await dataProvider.ExchangeCaseIdentitiesAsync(ResultRelation); + _supportCaseController.UpdateFocusedCaseRelation(ResultRelation); + detailsPage.UpdateHealthcardSectionVisibilities(); return true; } diff --git a/FasdDesktopUi/Basics/UiActions/ShowDetailedDataAction.cs b/FasdDesktopUi/Basics/UiActions/ShowDetailedDataAction.cs index 643c0cc..c1de10d 100644 --- a/FasdDesktopUi/Basics/UiActions/ShowDetailedDataAction.cs +++ b/FasdDesktopUi/Basics/UiActions/ShowDetailedDataAction.cs @@ -34,17 +34,17 @@ namespace FasdDesktopUi.Basics.UiActions private string Recommendation { get; set; } - private cHealthCardDetailsTable ValuedDetailsData = null; + private readonly cHealthCardDetailsTable _valuedDetailsData = null; - public cShowDetailedDataAction(cHealthCardStateBase StateDefinition, int DayIndex = 0, cHealthCardDetailsTable ValuedDetailsData = null) + public cShowDetailedDataAction(cHealthCardStateBase stateDefinition, int dayIndex = 0, cHealthCardDetailsTable valuedDetailsData = null) { - this.StateDefinition = StateDefinition; - this.DayIndex = DayIndex; - this.DetailsTitle = StateDefinition.Names.GetValue(); - this.Recommendation = StateDefinition.Descriptions.GetValue(); - if (this.Recommendation == String.Empty) - this.Recommendation = null; - this.ValuedDetailsData = ValuedDetailsData; + StateDefinition = stateDefinition; + DayIndex = dayIndex; + DetailsTitle = stateDefinition.Names.GetValue(); + Recommendation = stateDefinition.Descriptions.GetValue(); + if (Recommendation == string.Empty) + Recommendation = null; + _valuedDetailsData = valuedDetailsData; } public override async Task RunUiActionAsync(object sender, UIElement UiLocation, bool isDetailedLayout, cSupportCaseDataProvider dataProvider) @@ -61,7 +61,7 @@ namespace FasdDesktopUi.Basics.UiActions if (StateDefinition.Details is cHealthCardDetailsValued) { - if (ValuedDetailsData == null) + if (_valuedDetailsData == null) return false; } else @@ -240,26 +240,37 @@ namespace FasdDesktopUi.Basics.UiActions private cDetailedDataModel GetValuedDataModel() { - if (!(StateDefinition.Details is cHealthCardDetailsValued _details) || ValuedDetailsData == null) + if (!(StateDefinition.Details is cHealthCardDetailsValued details) || _valuedDetailsData == null) return null; - if (ValuedDetailsData.Columns.Count > 1) + var _colCount = details.Count; + + if (_colCount == 0) return null; - var _rowHeadings = _details.Select(v => v.Names.GetValue() as object).ToList(); + var rowHeadings = details.Select(v => (object)v.Names.GetValue()).ToList(); cDetailedDataModel output = new cDetailedDataModel() { Heading = StateDefinition.Names.GetValue(), FullDetailedData = new List(), - HasColumnHeaders = _rowHeadings.Count > 1 + HasColumnHeaders = _colCount > 1 }; - if (_rowHeadings.Count > 1) - output.FullDetailedData.Add(_rowHeadings); + if (rowHeadings.Count > 1) + output.FullDetailedData.Add(rowHeadings); - var _data = ValuedDetailsData.Values[0]; + var _data = _valuedDetailsData.Values[0]; foreach (var _row in _data) - output.FullDetailedData.Add(new List() { _row[0] }); + { + var _rowValues = new List(); + for (int i = 0; i < _colCount; i++) + { + _rowValues.Add(_row[i]); + } + output.FullDetailedData.Add(_rowValues); + } + + var _json = Newtonsoft.Json.JsonConvert.SerializeObject(output); return output; } @@ -307,7 +318,7 @@ namespace FasdDesktopUi.Basics.UiActions var valueProcessing = splitColumnName.Length > 1 ? splitColumnName[1] : null; rawColumnIndexes.Add(rawColumnIndex); - displayTypes.Add(cUtility.GetRawValueType(displayType)); + displayTypes.Add(displayType); valueProcessings.Add(valueProcessing); } @@ -326,7 +337,8 @@ namespace FasdDesktopUi.Basics.UiActions shouldHideRow = true; } - cUtility.RawValueFormatter.SetDefaultCulture(new System.Globalization.CultureInfo(cFasdCockpitConfig.Instance.SelectedLanguage)); + cUtility.RawValueFormatter.SetDefaultCulture(new CultureInfo(cFasdCockpitConfig.Instance.SelectedLanguage)); + cUtility.RawValueFormatter.SetDefaultTimeZone(TimeZoneInfo.Local); foreach (var index in rawColumnIndexes) { @@ -366,6 +378,8 @@ namespace FasdDesktopUi.Basics.UiActions output.FullDetailedData.Add(displayValuesOfRow); } + var _json = Newtonsoft.Json.JsonConvert.SerializeObject(output); + return output; } catch (Exception E) diff --git a/FasdDesktopUi/Basics/UiActions/UiDemoQuickAction.cs b/FasdDesktopUi/Basics/UiActions/UiDemoQuickAction.cs index eba4b54..4390c8c 100644 --- a/FasdDesktopUi/Basics/UiActions/UiDemoQuickAction.cs +++ b/FasdDesktopUi/Basics/UiActions/UiDemoQuickAction.cs @@ -5,6 +5,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using C4IT.F4SD.DisplayFormatting; +using C4IT.F4SD.SupportCaseProtocoll.Models; using C4IT.FASD.Base; using C4IT.Logging; using C4IT.MultiLanguage; @@ -135,8 +136,10 @@ namespace FasdDesktopUi.Basics.UiActions StatusMonitor.QuickActionOutputs.Add(_ref.Output); quickActionOutput = QuickActionStatusMonitor.cQuickActionOutput.GetQuickActionOutput(_ref.Output, DataProvider); - cQuickActionCopyData copyData = QuickActionProtocollEntry.GetCopyData(quickActionDemo, DataProvider, true, quickActionOutput, StatusMonitor.MeasureValues); - F4SDProtocoll.Instance.Add(new QuickActionProtocollEntry(quickActionDemo, copyData)); + cQuickActionCopyData copyData = QuickActionProtocollEntryOutput.GetCopyData(quickActionDemo, DataProvider, true, quickActionOutput, StatusMonitor.MeasureValues); + QuickActionProtocollEntry protocollEntry = QuickActionProtocollEntryOutput.GetQuickActionProtocollEntry(quickActionDemo, copyData); + + F4SDProtocoll.Instance.Add(protocollEntry); _msg = cMultiLanguageSupport.GetItem("QuickAction.Revision.Status.FinishedSuccessfull"); } diff --git a/FasdDesktopUi/Basics/UiActions/UiLocalQuickAction.cs b/FasdDesktopUi/Basics/UiActions/UiLocalQuickAction.cs index ecacfda..ba79246 100644 --- a/FasdDesktopUi/Basics/UiActions/UiLocalQuickAction.cs +++ b/FasdDesktopUi/Basics/UiActions/UiLocalQuickAction.cs @@ -6,6 +6,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using C4IT.F4SD.DisplayFormatting; +using C4IT.F4SD.SupportCaseProtocoll.Models; using C4IT.FASD.Base; using C4IT.FASD.Cockpit.Communication; using C4IT.Logging; @@ -154,9 +155,10 @@ namespace FasdDesktopUi.Basics.UiActions cMultiLanguageSupport.CurrentLanguage = tempLang; } - cQuickActionCopyData copyData = QuickActionProtocollEntry.GetCopyData(LocalQuickAction, DataProvider, false, protocollOutput, StatusMonitor.MeasureValues); - F4SDProtocoll.Instance.Add(new QuickActionProtocollEntry(LocalQuickAction, copyData)); + cQuickActionCopyData copyData = QuickActionProtocollEntryOutput.GetCopyData(LocalQuickAction, DataProvider, false, protocollOutput, StatusMonitor.MeasureValues); + QuickActionProtocollEntry protocollEntry = QuickActionProtocollEntryOutput.GetQuickActionProtocollEntry(LocalQuickAction, copyData); + F4SDProtocoll.Instance.Add(protocollEntry); string quickActionStatus; switch (ResultRevision.Status) @@ -193,8 +195,10 @@ namespace FasdDesktopUi.Basics.UiActions cMultiLanguageSupport.CurrentLanguage = tempLang; } - cQuickActionCopyData copyData = QuickActionProtocollEntry.GetCopyData(LocalQuickAction, DataProvider, false, protocollOutput, StatusMonitor.MeasureValues); - F4SDProtocoll.Instance.Add(new QuickActionProtocollEntry(LocalQuickAction, copyData)); + cQuickActionCopyData copyData = QuickActionProtocollEntryOutput.GetCopyData(LocalQuickAction, DataProvider, false, protocollOutput, StatusMonitor.MeasureValues); + QuickActionProtocollEntry protocollEntry = QuickActionProtocollEntryOutput.GetQuickActionProtocollEntry(LocalQuickAction, copyData); + + F4SDProtocoll.Instance.Add(protocollEntry); output = new List() { cMultiLanguageSupport.GetItem("QuickAction.Revision.Status.Canceled"), cUtility.RawValueFormatter.GetDisplayValue(DateTime.UtcNow, RawValueType.DATETIME) }; } diff --git a/FasdDesktopUi/Basics/UiActions/UiLocalWebRequestQuickAction.cs b/FasdDesktopUi/Basics/UiActions/UiLocalWebRequestQuickAction.cs index 235a0d8..c8aa111 100644 --- a/FasdDesktopUi/Basics/UiActions/UiLocalWebRequestQuickAction.cs +++ b/FasdDesktopUi/Basics/UiActions/UiLocalWebRequestQuickAction.cs @@ -1,4 +1,5 @@ using C4IT.F4SD.DisplayFormatting; +using C4IT.F4SD.SupportCaseProtocoll.Models; using C4IT.FASD.Base; using C4IT.Logging; using C4IT.MultiLanguage; @@ -124,8 +125,10 @@ namespace FasdDesktopUi.Basics.UiActions cMultiLanguageSupport.CurrentLanguage = tempLang; } - cQuickActionCopyData copyData = QuickActionProtocollEntry.GetCopyData(LocalQuickAction, DataProvider, false, protocollOutput, StatusMonitor.MeasureValues); - F4SDProtocoll.Instance.Add(new QuickActionProtocollEntry(LocalQuickAction, copyData)); + cQuickActionCopyData copyData = QuickActionProtocollEntryOutput.GetCopyData(LocalQuickAction, DataProvider, false, protocollOutput, StatusMonitor.MeasureValues); + QuickActionProtocollEntry protocollEntry = QuickActionProtocollEntryOutput.GetQuickActionProtocollEntry(LocalQuickAction, copyData); + + F4SDProtocoll.Instance.Add(protocollEntry); return new List() { cMultiLanguageSupport.GetItem("QuickAction.Revision.Status.FinishedSuccessfull"), cUtility.RawValueFormatter.GetDisplayValue(DateTime.UtcNow, RawValueType.DATETIME) }; } @@ -141,8 +144,10 @@ namespace FasdDesktopUi.Basics.UiActions cMultiLanguageSupport.CurrentLanguage = cF4SDCockpitXmlConfig.Instance.HealthCardConfig.ProtocollLanguage; protocollOutput = new cQuickActionOutputSingle(new cF4sdQuickActionRevision.cOutput() { ResultCode = enumQuickActionSuccess.error, ErrorDescription = cMultiLanguageSupport.GetItem("QuickAction.Copy.Output.Cancel") }); - cQuickActionCopyData copyData = QuickActionProtocollEntry.GetCopyData(LocalQuickAction, DataProvider, false, protocollOutput, StatusMonitor.MeasureValues); - F4SDProtocoll.Instance.Add(new QuickActionProtocollEntry(LocalQuickAction, copyData)); + cQuickActionCopyData copyData = QuickActionProtocollEntryOutput.GetCopyData(LocalQuickAction, DataProvider, false, protocollOutput, StatusMonitor.MeasureValues); + QuickActionProtocollEntry protocollEntry = QuickActionProtocollEntryOutput.GetQuickActionProtocollEntry(LocalQuickAction, copyData); + + F4SDProtocoll.Instance.Add(protocollEntry); cMultiLanguageSupport.CurrentLanguage = tempLang; return new List() { cMultiLanguageSupport.GetItem("QuickAction.Revision.Status.Canceled"), cUtility.RawValueFormatter.GetDisplayValue(DateTime.UtcNow, RawValueType.DATETIME) }; diff --git a/FasdDesktopUi/Basics/UiActions/UiProcessSearchHistoryEntry.cs b/FasdDesktopUi/Basics/UiActions/UiProcessSearchHistoryEntry.cs index cc60e4c..db7c975 100644 --- a/FasdDesktopUi/Basics/UiActions/UiProcessSearchHistoryEntry.cs +++ b/FasdDesktopUi/Basics/UiActions/UiProcessSearchHistoryEntry.cs @@ -58,7 +58,7 @@ namespace FasdDesktopUi.Basics.UiActions } } HistoryEntry.isSeen = true; - dataProvider = await cSupportCaseDataProvider.GetDataProviderForAsync(RelationEntry.Relations, RelationEntry.SelectedRelation, relationService); + dataProvider = await cSupportCaseDataProvider.GetDataProviderForAsync(RelationEntry.SelectedRelation, relationService); if (dataProvider is null) { Debug.Assert(true, "Could not start a data provider for the selected criterias."); diff --git a/FasdDesktopUi/Basics/UiActions/UiProcessSearchRelationAction.cs b/FasdDesktopUi/Basics/UiActions/UiProcessSearchRelationAction.cs index d981d48..62b0ff8 100644 --- a/FasdDesktopUi/Basics/UiActions/UiProcessSearchRelationAction.cs +++ b/FasdDesktopUi/Basics/UiActions/UiProcessSearchRelationAction.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; +using System.Threading; using System.Threading.Tasks; using System.Windows; using static C4IT.Logging.cLogManager; @@ -23,7 +24,7 @@ namespace FasdDesktopUi.Basics.UiActions public cUiProcessSearchRelationAction(cSearchHistorySearchResultEntry searchHistoryEntry, cF4sdApiSearchResultRelation selectedRelation, IRelationService relationService, ISearchUiProvider searchUiProvider) { - Name = $"{searchHistoryEntry.HeaderText} → {selectedRelation.DisplayName}"; + Name = !string.IsNullOrWhiteSpace(selectedRelation.DisplayName) ? $"{searchHistoryEntry.HeaderText} → {selectedRelation.DisplayName}" : searchHistoryEntry.HeaderText; _selectedSearchResult = searchHistoryEntry.SelectedSearchResult; _relations = searchHistoryEntry.Relations; _selectedRelation = selectedRelation; @@ -32,7 +33,7 @@ namespace FasdDesktopUi.Basics.UiActions _searchHistoryEntry = searchHistoryEntry; } - public cUiProcessSearchRelationAction(string name, List selectedSearchResult, List relations, cF4sdApiSearchResultRelation selectedRelation, ISearchUiProvider searchUiProvider, cSearchHistoryEntryBase searchHistoryEntry) + public cUiProcessSearchRelationAction(string name, List selectedSearchResult, List relations, cF4sdApiSearchResultRelation selectedRelation, ISearchUiProvider searchUiProvider, cSearchHistoryEntryBase searchHistoryEntry, IRelationService relationService) { Name = name; _selectedSearchResult = selectedSearchResult; @@ -40,6 +41,7 @@ namespace FasdDesktopUi.Basics.UiActions _selectedRelation = selectedRelation; _searchUiProvider = searchUiProvider; _searchHistoryEntry = searchHistoryEntry; + _relationService = relationService; } public override async Task RunUiActionAsync(object sender, UIElement UiLocation, bool isDetailedLayout, cSupportCaseDataProvider dataProvider) @@ -84,10 +86,15 @@ namespace FasdDesktopUi.Basics.UiActions return false; } + // set the new result menu properies for loading .... _seachHistoryEntry.isSeen = true; // get the new data provider for the support call informations (get it from the cache or create a new one) - dataProvider = await cSupportCaseDataProvider.GetDataProviderForAsync(_relations, _selectedRelation, _relationService); + dataProvider = await cSupportCaseDataProvider.GetDataProviderForAsync(_selectedRelation, _relationService); + + bool shouldLoadRelationsForSelectedRelation = _selectedRelation.Type == enumF4sdSearchResultClass.User; + if (shouldLoadRelationsForSelectedRelation) + StartLoadingRelationsFor(_selectedRelation); if (dataProvider is null) { @@ -106,5 +113,26 @@ namespace FasdDesktopUi.Basics.UiActions return false; } + + private void StartLoadingRelationsFor(cF4sdApiSearchResultRelation selectedRelation) + { + try + { + var relationsToReload = new List() { new cFasdApiSearchResultEntry() + { + DisplayName = selectedRelation.DisplayName, + id = selectedRelation.id, + Infos = selectedRelation.Infos, + Name = selectedRelation.Name, + Status = selectedRelation.Status, + Type = selectedRelation.Type + } }; + _ = Task.Run(async () => _relationService.LoadRelationsAsync(relationsToReload), CancellationToken.None); + } + catch (Exception ex) + { + LogException(ex); + } + } } } diff --git a/FasdDesktopUi/Basics/UiActions/UiProcessSearchResultAction.cs b/FasdDesktopUi/Basics/UiActions/UiProcessSearchResultAction.cs index 3e0cb7b..aaf555d 100644 --- a/FasdDesktopUi/Basics/UiActions/UiProcessSearchResultAction.cs +++ b/FasdDesktopUi/Basics/UiActions/UiProcessSearchResultAction.cs @@ -24,6 +24,8 @@ namespace FasdDesktopUi.Basics.UiActions private readonly List _loadedRelations = new List(); private readonly TaskCompletionSource _isSearchUnambigous = new TaskCompletionSource(); + private IRelationService _relationService = null; + public cF4sdApiSearchResultRelation PreSelectedSearchRelation { get; set; } = null; public cUiProcessSearchResultAction(string name, ISearchUiProvider searchUiProvider, List searchResults) @@ -115,10 +117,10 @@ namespace FasdDesktopUi.Basics.UiActions private async Task ProcessSearchResultRelationAsync(string name, List caseRelations, cF4sdApiSearchResultRelation selectedRelation) { var relationSearchResult = new cSearchHistorySearchResultEntry(_searchResults.FirstOrDefault().DisplayName, _searchResults.FirstOrDefault().DisplayName, _searchResults, caseRelations, _searchUiProvider); - string displayName = selectedRelation != null ? $"{name} → {selectedRelation.Name}" : name; + string displayName = !string.IsNullOrWhiteSpace(selectedRelation?.Name) ? $"{name} → {selectedRelation.Name}" : name; cUiProcessSearchRelationAction action - = new cUiProcessSearchRelationAction(displayName, _searchResults, caseRelations, caseRelations.FirstOrDefault(), _searchUiProvider, relationSearchResult) + = new cUiProcessSearchRelationAction(displayName, _searchResults, caseRelations, selectedRelation, _searchUiProvider, relationSearchResult, _relationService) { DisplayType = enumActionDisplayType.enabled, }; @@ -155,6 +157,7 @@ namespace FasdDesktopUi.Basics.UiActions try { _loadedRelations.AddRange(e.StagedResultRelations.Relations); + _relationService = e.RelationService; if (!e.StagedResultRelations.IsComplete) return; diff --git a/FasdDesktopUi/Basics/UiActions/UiQuickAction.cs b/FasdDesktopUi/Basics/UiActions/UiQuickAction.cs index 98f5f49..360902d 100644 --- a/FasdDesktopUi/Basics/UiActions/UiQuickAction.cs +++ b/FasdDesktopUi/Basics/UiActions/UiQuickAction.cs @@ -45,6 +45,7 @@ namespace FasdDesktopUi.Basics.UiActions return; cUtility.RawValueFormatter.SetDefaultCulture(new System.Globalization.CultureInfo(cFasdCockpitConfig.Instance.SelectedLanguage)); + cUtility.RawValueFormatter.SetDefaultTimeZone(TimeZoneInfo.Local); shouldRunImmidiate = QuickActionConfig.RunImmediate; Description = QuickActionConfig.Descriptions?.GetValue(Default: null); diff --git a/FasdDesktopUi/Basics/UiActions/UiQuickTipAction.cs b/FasdDesktopUi/Basics/UiActions/UiQuickTipAction.cs index 9acbce1..e1df907 100644 --- a/FasdDesktopUi/Basics/UiActions/UiQuickTipAction.cs +++ b/FasdDesktopUi/Basics/UiActions/UiQuickTipAction.cs @@ -27,12 +27,12 @@ namespace FasdDesktopUi.Basics.UiActions _quickTip = quickTip; } - public override Task RunUiActionAsync(object sender, UIElement UiLocation, bool isDetailedLayout, cSupportCaseDataProvider dataProvider) + public override async Task RunUiActionAsync(object sender, UIElement UiLocation, bool isDetailedLayout, cSupportCaseDataProvider dataProvider) { try { if (!(UiLocation is QuickTipStatusMonitor quickTipStatusMonitor)) - return Task.FromResult(false); + return false; DataProvider = dataProvider; @@ -49,13 +49,13 @@ namespace FasdDesktopUi.Basics.UiActions quickTipStatusMonitor.Visibility = Visibility.Visible; - return Task.FromResult(true); + return true; } catch (Exception E) { LogException(E); } - return Task.FromResult(false); + return false; } private void CreateElementData() diff --git a/FasdDesktopUi/Basics/UiActions/UiRemoteQuickAction.cs b/FasdDesktopUi/Basics/UiActions/UiRemoteQuickAction.cs index 7b7d2c4..3f4caac 100644 --- a/FasdDesktopUi/Basics/UiActions/UiRemoteQuickAction.cs +++ b/FasdDesktopUi/Basics/UiActions/UiRemoteQuickAction.cs @@ -1,4 +1,5 @@ using C4IT.F4SD.DisplayFormatting; +using C4IT.F4SD.SupportCaseProtocoll.Models; using C4IT.FASD.Base; using C4IT.FASD.Cockpit.Communication; using C4IT.Logging; @@ -137,9 +138,10 @@ namespace FasdDesktopUi.Basics.UiActions cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor.QuickActionData.ActionSteps, RemoteQuickAction.Name, enumActionStepType.running, status); cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor.QuickActionData.ActionSteps, RemoteQuickAction.Name, enumActionStepType.main, status); - cQuickActionCopyData copyData = QuickActionProtocollEntry.GetCopyData(RemoteQuickAction, DataProvider, true, protocollOutput, StatusMonitor.MeasureValues); - F4SDProtocoll.Instance.Add(new QuickActionProtocollEntry(RemoteQuickAction, copyData)); + cQuickActionCopyData copyData = QuickActionProtocollEntryOutput.GetCopyData(RemoteQuickAction, DataProvider, true, protocollOutput, StatusMonitor.MeasureValues); + QuickActionProtocollEntry protocollEntry = QuickActionProtocollEntryOutput.GetQuickActionProtocollEntry(RemoteQuickAction, copyData); + F4SDProtocoll.Instance.Add(protocollEntry); } else { @@ -155,8 +157,11 @@ namespace FasdDesktopUi.Basics.UiActions cMultiLanguageSupport.CurrentLanguage = tempLang; } - cQuickActionCopyData copyData = QuickActionProtocollEntry.GetCopyData(RemoteQuickAction, DataProvider, true, protocollOutput, StatusMonitor.MeasureValues); - F4SDProtocoll.Instance.Add(new QuickActionProtocollEntry(RemoteQuickAction, copyData)); + cQuickActionCopyData copyData = QuickActionProtocollEntryOutput.GetCopyData(RemoteQuickAction, DataProvider, true, protocollOutput, StatusMonitor.MeasureValues); + QuickActionProtocollEntry protocollEntry = QuickActionProtocollEntryOutput.GetQuickActionProtocollEntry(RemoteQuickAction, copyData); + + + F4SDProtocoll.Instance.Add(protocollEntry); return new List() { cMultiLanguageSupport.GetItem("QuickAction.Revision.Status.Canceled"), cUtility.RawValueFormatter.GetDisplayValue(DateTime.UtcNow, RawValueType.DATETIME) }; } @@ -241,7 +246,7 @@ namespace FasdDesktopUi.Basics.UiActions { Id = measure.Id, Names = measureDefinition.Names, - Display = cUtility.GetRawValueType(measureDefinition.Display), + Display = measureDefinition.Display, Value = measure.Value, PostValue = measure.PostValue }); diff --git a/FasdDesktopUi/Basics/UiActions/UiServerQuickAction.cs b/FasdDesktopUi/Basics/UiActions/UiServerQuickAction.cs index 487d73a..8bc9d71 100644 --- a/FasdDesktopUi/Basics/UiActions/UiServerQuickAction.cs +++ b/FasdDesktopUi/Basics/UiActions/UiServerQuickAction.cs @@ -1,4 +1,5 @@ using C4IT.F4SD.DisplayFormatting; +using C4IT.F4SD.SupportCaseProtocoll.Models; using C4IT.FASD.Base; using C4IT.FASD.Cockpit.Communication; using C4IT.Logging; @@ -170,8 +171,10 @@ namespace FasdDesktopUi.Basics.UiActions cMultiLanguageSupport.CurrentLanguage = tempLang; } - cQuickActionCopyData copyData = QuickActionProtocollEntry.GetCopyData(ServerQuickAction, DataProvider, false, protocollOutput, StatusMonitor.MeasureValues); - F4SDProtocoll.Instance.Add(new QuickActionProtocollEntry(ServerQuickAction, copyData)); + cQuickActionCopyData copyData = QuickActionProtocollEntryOutput.GetCopyData(ServerQuickAction, DataProvider, false, protocollOutput, StatusMonitor.MeasureValues); + QuickActionProtocollEntry protocollEntry = QuickActionProtocollEntryOutput.GetQuickActionProtocollEntry(ServerQuickAction, copyData); + + F4SDProtocoll.Instance.Add(protocollEntry); string quickActionStatus; switch (ResultRevision.Status) @@ -208,8 +211,10 @@ namespace FasdDesktopUi.Basics.UiActions cMultiLanguageSupport.CurrentLanguage = tempLang; } - cQuickActionCopyData copyData = QuickActionProtocollEntry.GetCopyData(ServerQuickAction, DataProvider, false, protocollOutput, StatusMonitor.MeasureValues); - F4SDProtocoll.Instance.Add(new QuickActionProtocollEntry(ServerQuickAction, copyData)); + cQuickActionCopyData copyData = QuickActionProtocollEntryOutput.GetCopyData(ServerQuickAction, DataProvider, false, protocollOutput, StatusMonitor.MeasureValues); + QuickActionProtocollEntry protocollEntry = QuickActionProtocollEntryOutput.GetQuickActionProtocollEntry(ServerQuickAction, copyData); + + F4SDProtocoll.Instance.Add(protocollEntry); output = new List() { cMultiLanguageSupport.GetItem("QuickAction.Revision.Status.Canceled"), cUtility.RawValueFormatter.GetDisplayValue(DateTime.UtcNow, RawValueType.DATETIME) }; } diff --git a/FasdDesktopUi/Basics/UiActions/UiShowRawHealthcardValues.cs b/FasdDesktopUi/Basics/UiActions/UiShowRawHealthcardValues.cs new file mode 100644 index 0000000..44741f3 --- /dev/null +++ b/FasdDesktopUi/Basics/UiActions/UiShowRawHealthcardValues.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +using C4IT.Logging; + +using FasdDesktopUi.Pages.RawHealthCardValuesPage; + +using static C4IT.Logging.cLogManager; + +namespace FasdDesktopUi.Basics.UiActions +{ + public class UiShowRawHealthcardValues : cUiActionBase + { + public override async Task RunUiActionAsync(object sender, UIElement UiLocation, bool isDetailedLayout, cSupportCaseDataProvider dataProvider) + { + MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } + + try + { + var _rawValueWindow = new RawHealthCardValuesPage(); + _rawValueWindow.Show(); + return true; + } + catch (Exception E) + { + LogException(E); + } + finally + { + if (CM != null) LogMethodEnd(CM); + } + return false; + } + + } +} diff --git a/FasdDesktopUi/Basics/UserControls/Badge.xaml b/FasdDesktopUi/Basics/UserControls/Badge.xaml new file mode 100644 index 0000000..d726782 --- /dev/null +++ b/FasdDesktopUi/Basics/UserControls/Badge.xaml @@ -0,0 +1,27 @@ + + + + + + + + + + diff --git a/FasdDesktopUi/Basics/UserControls/Badge.xaml.cs b/FasdDesktopUi/Basics/UserControls/Badge.xaml.cs new file mode 100644 index 0000000..0146113 --- /dev/null +++ b/FasdDesktopUi/Basics/UserControls/Badge.xaml.cs @@ -0,0 +1,27 @@ +using F4SD_AdaptableIcon; +using FasdDesktopUi.Basics.Helper; +using System; +using System.Windows; +using System.Windows.Controls; +using static C4IT.Logging.cLogManager; + +namespace FasdDesktopUi.Basics.UserControls +{ + public partial class Badge : UserControl + { + public string Text + { + get { return (string)GetValue(TextProperty); } + set { SetValue(TextProperty, value); } + } + + public static readonly DependencyProperty TextProperty = + DependencyProperty.Register(nameof(Text), typeof(string), typeof(Badge), new PropertyMetadata("Beta")); + + + public Badge() + { + InitializeComponent(); + } + } +} diff --git a/FasdDesktopUi/Basics/UserControls/DataCanvas/DataCanvas.xaml b/FasdDesktopUi/Basics/UserControls/DataCanvas/DataCanvas.xaml index a96f2db..4e24f09 100644 --- a/FasdDesktopUi/Basics/UserControls/DataCanvas/DataCanvas.xaml +++ b/FasdDesktopUi/Basics/UserControls/DataCanvas/DataCanvas.xaml @@ -23,12 +23,6 @@ Visibility="{Binding ElementName=DataCanvasUc, Path=IsDetailedLayout, Converter={StaticResource BoolToVisibility}}" IsCloseButtonVisible="{Binding ElementName=DataCanvasUc, Path=DataCanvasData, Converter={StaticResource IsCloseButtonVisible}, ConverterParameter={x:Static converter:enumDataCanvasTypes.detailedData} }" /> - - = chartEndMs || endMs <= chartStartMs) + continue; + + if (startMs < chartStartMs) + startMs = chartStartMs; + + if (endMs > chartEndMs) + endMs = chartEndMs; + + double xLeft = xCoordinate.GetCoordinate(startMs); + double xRight = xCoordinate.GetCoordinate(endMs); double y = 0; @@ -585,19 +598,19 @@ namespace FasdDesktopUi.Basics.UserControls { y = yCoordinate.GetCoordinate(dataValue); } - - + + Border border = new Border() { Height = 6.0, - Width = xRight - xLeft, + Width = xRight - xLeft, CornerRadius = new CornerRadius(4.0), ToolTip = dataTime.ToShortTimeString() + " - " + dataTime.AddMilliseconds(dataDuration).ToShortTimeString() + " | " + dataValue, }; if (border.Width < 6) { - border.Width = 6; - } + border.Width = 6; + } if (ChartData.IsThresholdActive == false) { border.Background = new SolidColorBrush(Color.FromRgb(0, 157, 221)); @@ -652,16 +665,30 @@ namespace FasdDesktopUi.Basics.UserControls { try { + double oneDayMs = TimeSpan.FromDays(1).TotalMilliseconds; + double chartStartMs = 0; + double chartEndMs = oneDayMs; + foreach (var data in GraphicDataProperty) { DateTime dataTime = data.Time; double dataValue = data.Value; int dataDuration = data.Duration; - double time = dataTime.TimeOfDay.TotalMilliseconds; + double startMs = dataTime.TimeOfDay.TotalMilliseconds; + double endMs = startMs + dataDuration; - double xLeft = xCoordinate.GetCoordinate(time); - double xRight = xCoordinate.GetCoordinate(time + dataDuration); + if (startMs >= chartEndMs || endMs <= chartStartMs) + continue; + + if (startMs < chartStartMs) + startMs = chartStartMs; + + if (endMs > chartEndMs) + endMs = chartEndMs; + + double xLeft = xCoordinate.GetCoordinate(startMs); + double xRight = xCoordinate.GetCoordinate(endMs); double y = 0; diff --git a/FasdDesktopUi/Basics/UserControls/DataCanvas/QuickActionStatusMonitor.xaml.cs b/FasdDesktopUi/Basics/UserControls/DataCanvas/QuickActionStatusMonitor.xaml.cs index bf8af3c..4d06518 100644 --- a/FasdDesktopUi/Basics/UserControls/DataCanvas/QuickActionStatusMonitor.xaml.cs +++ b/FasdDesktopUi/Basics/UserControls/DataCanvas/QuickActionStatusMonitor.xaml.cs @@ -1,4 +1,5 @@ using C4IT.F4SD.DisplayFormatting; +using C4IT.F4SD.SupportCaseProtocoll.Models; using C4IT.FASD.Base; using C4IT.MultiLanguage; using F4SD_AdaptableIcon.Enums; @@ -38,6 +39,7 @@ namespace FasdDesktopUi.Basics.UserControls public cQuickActionOutput(cF4sdQuickActionRevision.cOutput scriptOutput) { _rawValueFormatter.SetDefaultCulture(new System.Globalization.CultureInfo(cFasdCockpitConfig.Instance.SelectedLanguage)); + _rawValueFormatter.SetDefaultTimeZone(TimeZoneInfo.Local); ErrorCode = scriptOutput.ErrorCode; ErrorDescription = scriptOutput.ErrorDescription; ResultCode = scriptOutput.ResultCode.GetValueOrDefault(); @@ -246,7 +248,7 @@ namespace FasdDesktopUi.Basics.UserControls return veiledText; if (outputFormatting.DisplayType != null) - output = _rawValueFormatter.GetDisplayValue(Value, cUtility.GetRawValueType(outputFormatting.DisplayType.Value)); + output = _rawValueFormatter.GetDisplayValue(Value, outputFormatting.DisplayType.Value); if (outputFormatting.Translation != null) { @@ -372,7 +374,7 @@ namespace FasdDesktopUi.Basics.UserControls return veiledText; if (outputFormatting.DisplayType != null) - output = _rawValueFormatter.GetDisplayValue(selectedItem.Value, cUtility.GetRawValueType(outputFormatting.DisplayType.Value)); + output = _rawValueFormatter.GetDisplayValue(selectedItem.Value, outputFormatting.DisplayType.Value); if (outputFormatting.Translation != null) { @@ -464,7 +466,7 @@ namespace FasdDesktopUi.Basics.UserControls return veiledText; if (outputFormatting.DisplayType != null) - output = _rawValueFormatter.GetDisplayValue(Values[row][column].Value, cUtility.GetRawValueType(outputFormatting.DisplayType.Value)); + output = _rawValueFormatter.GetDisplayValue(Values[row][column].Value, outputFormatting.DisplayType.Value); if (outputFormatting.Translation != null) { @@ -803,6 +805,7 @@ namespace FasdDesktopUi.Basics.UserControls return; _rawValueFormatter.SetDefaultCulture(new System.Globalization.CultureInfo(cFasdCockpitConfig.Instance.SelectedLanguage)); + _rawValueFormatter.SetDefaultTimeZone(TimeZoneInfo.Local); for (int i = 0; i < measureValues.Count; i++) { diff --git a/FasdDesktopUi/Basics/UserControls/QuickTip/QuickTipStatusMonitor.xaml b/FasdDesktopUi/Basics/UserControls/QuickTip/QuickTipStatusMonitor.xaml index 142309f..ef3f0e3 100644 --- a/FasdDesktopUi/Basics/UserControls/QuickTip/QuickTipStatusMonitor.xaml +++ b/FasdDesktopUi/Basics/UserControls/QuickTip/QuickTipStatusMonitor.xaml @@ -1,14 +1,17 @@  - - + + - - + - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + diff --git a/FasdDesktopUi/Basics/UserControls/QuickTip/QuickTipStatusMonitor.xaml.cs b/FasdDesktopUi/Basics/UserControls/QuickTip/QuickTipStatusMonitor.xaml.cs index dc3a6a4..4725d89 100644 --- a/FasdDesktopUi/Basics/UserControls/QuickTip/QuickTipStatusMonitor.xaml.cs +++ b/FasdDesktopUi/Basics/UserControls/QuickTip/QuickTipStatusMonitor.xaml.cs @@ -1,4 +1,5 @@ -using C4IT.FASD.Base; +using C4IT.F4SD.SupportCaseProtocoll.Models; +using C4IT.FASD.Base; using C4IT.MultiLanguage; using F4SD_AdaptableIcon; using F4SD_AdaptableIcon.Enums; @@ -254,7 +255,9 @@ namespace FasdDesktopUi.Basics.UserControls.QuickTip return; bool wasSuccessfull = step.SuccessState == enumQuickActionSuccess.finished || step.SuccessState == enumQuickActionSuccess.successfull; - F4SDProtocoll.Instance.Add(new QuickTipStepProtocollEntry(step.StepData.QuickTipElementDefinition, wasSuccessfull)); + ProtocollEntryBase protocollEntry = QuickTipStepProtocollEntryOutput.GetQuickTipStepProtocollEntry(step.StepData.QuickTipElementDefinition, wasSuccessfull); + + F4SDProtocoll.Instance.Add(protocollEntry); } catch (Exception ex) { diff --git a/FasdDesktopUi/Basics/UserControls/SearchBar.xaml.cs b/FasdDesktopUi/Basics/UserControls/SearchBar.xaml.cs index 1ecaf4c..c3de5d1 100644 --- a/FasdDesktopUi/Basics/UserControls/SearchBar.xaml.cs +++ b/FasdDesktopUi/Basics/UserControls/SearchBar.xaml.cs @@ -173,7 +173,7 @@ namespace FasdDesktopUi.Basics.UserControls } SearchTextBox.Text = search; - await ChangedSearchValue.Invoke(_result); + await ChangedSearchValue?.Invoke(_result); } diff --git a/FasdDesktopUi/Basics/UserControls/Ticket/CloseCaseDialogWithTicket.merged.xaml.cs b/FasdDesktopUi/Basics/UserControls/Ticket/CloseCaseDialogWithTicket.merged.xaml.cs new file mode 100644 index 0000000..bdcaa4c --- /dev/null +++ b/FasdDesktopUi/Basics/UserControls/Ticket/CloseCaseDialogWithTicket.merged.xaml.cs @@ -0,0 +1,2707 @@ +using C4IT.FASD.Base; +using C4IT.FASD.Cockpit.Communication; +using C4IT.MultiLanguage; +using F4SD_AdaptableIcon.Enums; +using FasdDesktopUi.Basics.Helper; +using FasdDesktopUi.Basics.Models; +using FasdDesktopUi.Basics.Services.ProtocollService; +using FasdDesktopUi.Pages.TicketCompletion; +using MaterialIcons; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Input; +using System.Windows.Media; +using static C4IT.Logging.cLogManager; + +namespace FasdDesktopUi.Basics.UserControls +{ + public partial class CloseCaseDialogWithTicket : UserControl + { + #region Fields & Properties + private readonly Dictionary _errors = new Dictionary(); + + private readonly IValueConverter _languageConverter = new Converter.LanguageDefinitionsConverter(); + + private readonly List _openedWindows = new List(); + + private readonly cF4sdApiSearchResultRelation _newTicketRelation = new cF4sdApiSearchResultRelation() + { + id = Guid.NewGuid(), + DisplayName = cMultiLanguageSupport.GetItem("Header.Create.Ticket"), + Type = enumF4sdSearchResultClass.Ticket, + Identities = null, + Infos = new Dictionary { [TicketInfoKeys.Special] = TicketSpecialValues.TicketCreation } + }; + + private readonly cF4sdApiSearchResultRelation _selectTicketRelation = new cF4sdApiSearchResultRelation() + { + id = Guid.NewGuid(), + DisplayName = cMultiLanguageSupport.GetItem("Header.Select.Ticket"), + Type = enumF4sdSearchResultClass.Ticket, + Identities = null, + Infos = new Dictionary { [TicketInfoKeys.Special] = TicketSpecialValues.TicketSelect } + }; + + private readonly cF4sdApiSearchResultRelation _noTicketRelation = new cF4sdApiSearchResultRelation() + { + DisplayName = cMultiLanguageSupport.GetItem("Header.Skip.Ticket"), + Type = enumF4sdSearchResultClass.Ticket, + Identities = null, + Infos = new Dictionary { [TicketInfoKeys.Special] = TicketSpecialValues.NoTicket } + }; + + private readonly cF4sdApiSearchResultRelation _removeAffectedAssetEntry = new cF4sdApiSearchResultRelation() + { + DisplayName = cMultiLanguageSupport.GetItem("Dialog.CloseCase.RemoveAffectedAssetEntry"), + Type = enumF4sdSearchResultClass.Computer, + Identities = null, + Infos = new Dictionary { [TicketInfoKeys.Special] = TicketSpecialValues.RemoveAffectedAssetEntry } + }; + + private const string CategoryTableNamePrimary = "M42Wpm-Ticket-Categories"; + private const string CategoryTableNameLegacy = "M42Wpm-Ticket-CloseCase-Categories"; + private string activeCategoryTableName = CategoryTableNamePrimary; + + private static readonly Brush SharedValidationBorderBrush = CreateValidationBrush(); + private static readonly Brush DefaultTextBoxBorderBrush = CreateDefaultTextBoxBorderBrush(); + private static Brush CreateValidationBrush() + { + var brush = new SolidColorBrush(Color.FromRgb(0xF5, 0x7C, 0x73)); + if (brush.CanFreeze) + brush.Freeze(); + return brush; + } + private static Brush CreateDefaultTextBoxBorderBrush() + { + var brush = new SolidColorBrush(Color.FromRgb(0xDE, 0xE2, 0xE6)); + if (brush.CanFreeze) + brush.Freeze(); + return brush; + } + + private ObservableCollection categoryHierarchy = new ObservableCollection(); + private readonly Dictionary categoryLookup = new Dictionary(StringComparer.OrdinalIgnoreCase); + private bool isCategoryLoading; + private Brush defaultCategoryBorderBrush; + private Brush defaultQuickTicketBorderBrush; + private readonly Brush validationErrorBrush = SharedValidationBorderBrush; + private Brush defaultTicketStatusBorderBrush; + private Thickness? defaultCategoryBorderThickness; + private Thickness? defaultQuickTicketBorderThickness; + private Thickness? defaultTicketStatusBorderThickness; + + public bool AreCaseNotesMandatory => + cFasdCockpitConfig.Instance?.Global?.TicketConfiguration?.NotesMandatory ?? false; + + private static class TicketInfoKeys + { + public const string ActivityType = "ActivityType"; + public const string Asset = "Asset"; + public const string ServiceId = "ServiceId"; + public const string ServiceName = "ServiceName"; + public const string StatusId = "StatusId"; + public const string Category = "Category"; + public const string Summary = "Summary"; + public const string Special = "Special"; + } + + private static class TicketInfoValues + { + public const string ActivityTypeTicket = "SPSActivityTypeTicket"; + } + + private static class TicketSpecialValues + { + public const string TicketCreation = "TicketCreation"; + public const string TicketSelect = "TicketSelect"; + public const string NoTicket = "NoTicket"; + public const string RemoveAffectedAssetEntry = "RemoveAffectedAssetEntry"; + public const string RemoveAffectedServiceEntry = "RemoveAffectedServiceEntry"; + } + + private static class ValidationPropertyNames + { + public const string SelectedTicket = nameof(SelectedTicket); + public const string SelectedCategory = nameof(SelectedCategory); + public const string QuickTicketSelection = nameof(QuickTicketSelection); + public const string TicketSummaryTextBox = nameof(TicketSummaryTextBox); + public const string TicketStatusCombobox = nameof(TicketStatusCombobox); + public const string CaseNotesPreview = nameof(CaseNotesPreview); + public const string SolutionTextbox = "SolutionTextbox"; + public const string ErrorTypeValue = "ErrorTypeValue"; + public const string ReminderDate = "ReminderDate"; + public const string HoldComment = "HoldComment"; + public const string SelectedRoleAndPerson = "SelectedRoleAndPerson"; + public const string ForwardComment = "ForwardComment"; + } + + private bool TryGetSelectedTicketInfo(string key, out string value) + { + value = null; + return SelectedTicket?.Infos != null && SelectedTicket.Infos.TryGetValue(key, out value); + } + + private string GetSelectedTicketInfoOrDefault(string key) => + TryGetSelectedTicketInfo(key, out var value) ? value : null; + + private static bool TryGetSpecialValue(cF4sdApiSearchResultRelation relation, out string specialValue) + { + specialValue = null; + return relation?.Infos != null && relation.Infos.TryGetValue(TicketInfoKeys.Special, out specialValue); + } + + private static bool RelationHasSpecialInfo(cF4sdApiSearchResultRelation relation, string expectedSpecialValue) => + TryGetSpecialValue(relation, out var specialValue) && + string.Equals(specialValue, expectedSpecialValue, StringComparison.OrdinalIgnoreCase); + + public bool IsTicket + { + get + { + return TryGetSelectedTicketInfo(TicketInfoKeys.ActivityType, out var activityType) + && string.Equals(activityType, TicketInfoValues.ActivityTypeTicket, StringComparison.OrdinalIgnoreCase); + } + } + + private bool _isTicketIntegrationActive; + public bool IsTicketIntegrationActive + { + get => _isTicketIntegrationActive; + private set => _isTicketIntegrationActive = value; + } + + public bool EnableHoldTicketAction + { + get { return (bool)GetValue(EnableHoldTicketActionProperty); } + set { SetValue(EnableHoldTicketActionProperty, value); } + } + + public static readonly DependencyProperty EnableHoldTicketActionProperty = + DependencyProperty.Register("EnableHoldTicketAction", typeof(bool), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(true)); + + public bool EnableCloseTicketAction + { + get { return (bool)GetValue(EnableCloseTicketActionProperty); } + set { SetValue(EnableCloseTicketActionProperty, value); } + } + + public static readonly DependencyProperty EnableCloseTicketActionProperty = + DependencyProperty.Register("EnableCloseTicketAction", typeof(bool), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(true)); + + public bool EnableSaveTicketAction + { + get { return (bool)GetValue(EnableSaveTicketActionProperty); } + set { SetValue(EnableSaveTicketActionProperty, value); } + } + + public static readonly DependencyProperty EnableSaveTicketActionProperty = + DependencyProperty.Register("EnableSaveTicketAction", typeof(bool), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(true)); + + public bool EnableForwardTicketAction + { + get { return (bool)GetValue(EnableForwardTicketActionProperty); } + set { SetValue(EnableForwardTicketActionProperty, value); } + } + + public static readonly DependencyProperty EnableForwardTicketActionProperty = + DependencyProperty.Register("EnableForwardTicketAction", typeof(bool), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(true)); + + private cF4sdApiSearchResultRelation _selectedTicket; + + public cF4sdApiSearchResultRelation SelectedTicket + { + get => _selectedTicket; + set + { + _selectedTicket = value; + //SelectedComputer = null; + + UpdateSelectedTicketControl(); + CheckAffectedAssetIsCurrentAsset(); + CheckAffectedServiceIsCurrentService(); + UpdateAffectedAssetLabel(); + UpdateAffectedServiceLabel(); + UpdateAffectedAssetComboBox(); + ShowAssetWarningTicketAction = IsTicket; + ValidateProperty(ValidationPropertyNames.SelectedTicket); + EnableHoldTicketAction = _selectedTicket == null || SelectedTicket == _selectTicketRelation || selectedTicketIsNewTicket; + if (TryGetSelectedTicketInfo(TicketInfoKeys.StatusId, out var statusIdString) && + Enum.TryParse(statusIdString, true, out enumTicketStatus statusId)) + { + EnableHoldTicketAction = statusId != enumTicketStatus.OnHold; + } + TrySelectTicketCategoryFromTicketInfos(); + } + } + + private bool selectedTicketIsNewTicket + { + get => SelectedTicket == _newTicketRelation; + } + + #region SelectedComputer DependencyProperty + public static readonly DependencyProperty SelectedComputerProperty = + DependencyProperty.Register("SelectedComputer", typeof(cF4sdApiSearchResultRelation), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(null)); + + public cF4sdApiSearchResultRelation SelectedComputer + { + get { return (cF4sdApiSearchResultRelation)GetValue(SelectedComputerProperty); } + set + { + SetValue(SelectedComputerProperty, value); + CheckAffectedAssetIsCurrentAsset(); + } + } + #endregion + + public bool ShowAssetWarningTicketAction + { + get { return (bool)GetValue(ShowAssetWarningTicketActionProperty); } + set { SetValue(ShowAssetWarningTicketActionProperty, value); } + } + + public static readonly DependencyProperty ShowAssetWarningTicketActionProperty = + DependencyProperty.Register("ShowAssetWarningTicketAction", typeof(bool), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(false)); + + #region SelectedService DependencyProperty + + public static readonly DependencyProperty SelectedServiceProperty = DependencyProperty.Register( + "SelectedService", + typeof(KeyValuePair), + typeof(CloseCaseDialogWithTicket), + new PropertyMetadata(default(KeyValuePair), OnSelectedServiceChanged)); + + public KeyValuePair SelectedService + { + get { return (KeyValuePair)GetValue(SelectedServiceProperty); } + set + { + SetValue(SelectedServiceProperty, value); + CheckAffectedServiceIsCurrentService(); + } + } + private static void OnSelectedServiceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var control = (CloseCaseDialogWithTicket)d; + var newValue = (KeyValuePair)e.NewValue; + control.CheckAffectedServiceIsCurrentService(); + } + #endregion + + #region SelectedCategory DependencyProperty + + public static readonly DependencyProperty SelectedCategoryProperty = DependencyProperty.Register( + "SelectedCategory", + typeof(HierarchicalSelectionItem), + typeof(CloseCaseDialogWithTicket), + new PropertyMetadata(null, OnSelectedCategoryChanged)); + + public HierarchicalSelectionItem SelectedCategory + { + get { return (HierarchicalSelectionItem)GetValue(SelectedCategoryProperty); } + set { SetValue(SelectedCategoryProperty, value); } + } + + private static void OnSelectedCategoryChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is CloseCaseDialogWithTicket instance) + { + instance.LogSelectedCategoryChanged(e.NewValue as HierarchicalSelectionItem); + instance.ValidateProperty(ValidationPropertyNames.SelectedCategory); + } + } + + #endregion + + private void LogSelectedCategoryChanged(HierarchicalSelectionItem category) + { + try + { + var fullPath = category == null + ? "" + : string.IsNullOrWhiteSpace(category.FullPath) ? category.DisplayName : category.FullPath; + var id = category == null || string.IsNullOrWhiteSpace(category.Id) ? "" : category.Id; + LogEntry($"[CloseCaseDialog] SelectedCategory updated -> {fullPath} (Id={id})"); + } + catch (Exception ex) + { + LogException(ex); + } + } + + public bool ShowServiceHasBeenChangedWarning + { + get { return ServiceHasBeenChanged && SetOrUpdateServiceInTicket; } + } + public bool ShowAssetHasBeenChangedWarning + { + get { return AssetHasBeenChanged && SetOrUpdateComputerInTicket; } + } + + #region AssetHasBeenChanged DependencyProperty + + public static readonly DependencyProperty AssetHasBeenChangedProperty = + DependencyProperty.Register("AssetHasBeenChanged", typeof(bool), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(false)); + + public bool AssetHasBeenChanged + { + get { return (bool)GetValue(AssetHasBeenChangedProperty); } + set { SetValue(AssetHasBeenChangedProperty, value); } + } + + #endregion + + #region SetOrUpdateComputerInTicket DependencyProperty + + public static readonly DependencyProperty SetOrUpdateComputerInTicketProperty = + DependencyProperty.Register("SetOrUpdateComputerInTicket", typeof(bool), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(true, OnSetOrUpdateComputerInTicketChanged)); + + private static void OnSetOrUpdateComputerInTicketChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is CloseCaseDialogWithTicket instance) + instance.CheckAffectedAssetIsCurrentAsset(); + } + + public bool SetOrUpdateComputerInTicket + { + get { return (bool)GetValue(SetOrUpdateComputerInTicketProperty); } + set { SetValue(SetOrUpdateComputerInTicketProperty, value); } + } + + #endregion + + private bool _skipTicketPillSelected; + + public bool SkipTicketPillSelected + { + get { return _skipTicketPillSelected; } + set { _skipTicketPillSelected = value; } + } + + private bool _newTicketPillSelected; + + public bool NewTicketPillSelected + { + get { return _newTicketPillSelected; } + set + { + _newTicketPillSelected = value; + ValidateProperty(ValidationPropertyNames.SelectedTicket); + + } + } + + #region SetOrUpdateServiceInTicket DependencyProperty + + public static readonly DependencyProperty SetOrUpdateServiceInTicketProperty = + DependencyProperty.Register("SetOrUpdateServiceInTicket", typeof(bool), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(false, OnSetOrUpdateServiceInTicketChanged)); + + private static void OnSetOrUpdateServiceInTicketChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is CloseCaseDialogWithTicket instance) + instance.CheckAffectedServiceIsCurrentService(); + } + + public bool SetOrUpdateServiceInTicket + { + get { return (bool)GetValue(SetOrUpdateServiceInTicketProperty); } + set { SetValue(SetOrUpdateServiceInTicketProperty, value); } + } + #endregion + + #region ServiceHasBeenChanged DependencyProperty + + public static readonly DependencyProperty ServiceHasBeenChangedProperty = + DependencyProperty.Register("ServiceHasBeenChanged", typeof(bool), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(false)); + + public bool ServiceHasBeenChanged + { + get { return (bool)GetValue(ServiceHasBeenChangedProperty); } + set { SetValue(ServiceHasBeenChangedProperty, value); } + } + + #endregion + + public static readonly DependencyProperty ComputerRelationsProperty = + DependencyProperty.Register("ComputerRelations", typeof(List), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(new List(), OnComputerRelationsChanged)); + + private static void OnComputerRelationsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is CloseCaseDialogWithTicket instance) + { + //instance.CheckAffectedAssetIsCurrentAsset(); + } + } + + public List ComputerRelations + { + get { return (List)GetValue(ComputerRelationsProperty); } + set { SetValue(ComputerRelationsProperty, value); } + } + + public bool SupportNotepad { get; private set; } = false; + + public static EventHandler TicketNotepadChanged { get; set; } + + #region DataProvider + + public cSupportCaseDataProvider DataProvider + { + get { return (cSupportCaseDataProvider)GetValue(DataProviderProperty); } + set { SetValue(DataProviderProperty, value); } + } + + public static readonly DependencyProperty DataProviderProperty = + DependencyProperty.Register("DataProvider", typeof(cSupportCaseDataProvider), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(null, DataProviderChanged)); + + private static async void DataProviderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + try + { + if (!(d is CloseCaseDialogWithTicket me)) + return; + + + me.SelectedTicket = me.SelectedTicket ?? me._selectTicketRelation; + + me.UpdateSelectedTicketControl(); + me.UpdateTicketSelection(); + + me.AddCopyTemplates(); + me.UpdateAffectedAssetLabel(); + me.UpdateAffectedServiceLabel(); + me.UpdateAffectedAssetComboBox(); + + me.ServiceSelectionControl.SearchDataChanged = me.HandleServiceSearchDataChanged; + me.ServiceSelectionControl.ParentElement = me.MainStack; + me.ServiceSelectionControl.ParentIndex = me.MainStack.Children.IndexOf(me.ServiceSelectionControl); + + me.AddNewOrExistingOrNoneTicketSelection(); + me.UpdateCaseNotesPreview(); + me.UpdateTicketComponentVisibility(); + await me.InitializeCategorySelectionAsync(); + await me.UpdateQuickCallsComboBoxAsync(); + me.ValidateProperty(ValidationPropertyNames.SelectedCategory); + me.ValidateProperty(ValidationPropertyNames.QuickTicketSelection); + } + catch (Exception E) + { + LogException(E); + } + + } + + #endregion + + #endregion + string lastServiceSearch = string.Empty; + + private TicketCompletion parentWindow; + + public CloseCaseDialogWithTicket() + { + InitializeComponent(); + this.Unloaded += CloseCaseDialogWithTicket_Unloaded; + this.Loaded += CloseCaseDialogWithTicket_Loaded; + defaultCategoryBorderBrush = CategoryValidationBorder?.BorderBrush?.CloneCurrentValue(); + defaultQuickTicketBorderBrush = QuickTicketValidationBorder?.BorderBrush?.CloneCurrentValue(); + defaultTicketStatusBorderBrush = TicketStatusValidationBorder?.BorderBrush?.CloneCurrentValue(); + if (validationErrorBrush is Freezable freezableBrush && freezableBrush.CanFreeze) + freezableBrush.Freeze(); + + DependencyPropertyDescriptor dpd = + DependencyPropertyDescriptor.FromProperty(TextBlock.TextProperty, typeof(TextBlock)); + + dpd?.AddValueChanged(CaseNotesPreview, TicketCaseNotesTextBlock_TextChanged); + + SupportNotepad = true; + } + + private void CloseCaseDialogWithTicket_Loaded(object sender, RoutedEventArgs e) + { + Window _parentWindow = Window.GetWindow(this); + + if (!(_parentWindow is TicketCompletion _msgBox)) + return; + + _parentWindow.Closing += ParentWindow_Closing; + parentWindow = _msgBox; + parentWindow.SetButtonStateYes(false, "Initial gesperrt."); + parentWindow.SetButtonStateNo(true, cMultiLanguageSupport.GetItem("Dialog.CloseCase.Cancel")); + + ValidateProperty(ValidationPropertyNames.TicketSummaryTextBox); + ValidateProperty(ValidationPropertyNames.TicketStatusCombobox); + ValidateProperty(ValidationPropertyNames.CaseNotesPreview); + ValidateProperty(ValidationPropertyNames.SelectedCategory); + ValidateProperty(ValidationPropertyNames.QuickTicketSelection); + } + private void CloseCaseDialogWithTicket_Unloaded(object sender, RoutedEventArgs e) + { + Window parentWindow = Window.GetWindow(this); + if (parentWindow != null) + { + parentWindow.Closing -= ParentWindow_Closing; + } + } + private void ParentWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) + { + foreach (SelectionPill pill in NewOrExistingOrNoneTicketWrap.Children.OfType()) + { + SelectionPill.RemovePill(pill); + } + foreach (SelectionPill pill in CopyTemplateWrap.Children.OfType()) + { + SelectionPill.RemovePill(pill); + } + } + protected override void OnInitialized(EventArgs e) + { + try + { + base.OnInitialized(e); + IsTicketIntegrationActive = cFasdCockpitCommunicationBase.CockpitUserInfo?.Roles?.Any(role => string.Equals(role, "Cockpit.TicketAgent", StringComparison.OrdinalIgnoreCase)) ?? false; + cSupportCaseDataProvider.CaseNotesChanged += (sender, args) => UpdateCaseNotesPreview(); + } + catch (Exception E) + { + LogException(E); + } + } + + + + private void UpdateAffectedAssetLabel() + { + var computerName = GetSelectedTicketInfoOrDefault(TicketInfoKeys.Asset); + + var binding = new Binding + { + Converter = _languageConverter, + ConverterParameter = NewTicketPillSelected || string.IsNullOrEmpty(computerName) ? "Dialog.CloseCase.SetAffectedAssetLabel" : "Dialog.CloseCase.UpdateAffectedAssetLabel" + }; + + SetOrUpdateComputerInTicketLabel.SetBinding(TextBlock.TextProperty, binding); + } + private void UpdateAffectedServiceLabel() + { + var serviceId = GetSelectedTicketInfoOrDefault(TicketInfoKeys.ServiceId); + + var binding = new Binding + { + Converter = _languageConverter, + ConverterParameter = NewTicketPillSelected || string.IsNullOrEmpty(serviceId) || serviceId == Guid.Empty.ToString() ? "Dialog.CloseCase.SetAffectedServiceLabel" : "Dialog.CloseCase.UpdateAffectedServiceLabel" + }; + + SetOrUpdateServiceInTicketLabel.SetBinding(TextBlock.TextProperty, binding); + } + + private bool checkTicketActive() + { + var _retVal = IsTicketIntegrationActive; + if (cFasdCockpitCommunicationBase.Instance.IsDemo()) + _retVal = DataProvider.HealthCardDataHelper?.HealthCardRawData?.Tables?.ContainsKey("M42Wpm-User-NewTicket") ?? false; + return _retVal; + } + + private void UpdateTicketComponentVisibility() + { + try + { + if (DataProvider is null) + return; + + var _isVisible = checkTicketActive() && !_skipTicketPillSelected; + + TicketSelectionCategory.Visibility = _isVisible ? Visibility.Visible : Visibility.Collapsed; + StatusSelectionBorder.Visibility = _isVisible ? Visibility.Visible : Visibility.Collapsed; + CopyDisclaimerTextBox.Visibility = _isVisible ? Visibility.Collapsed : Visibility.Visible; + } + catch (Exception E) + { + LogException(E); + } + } + + private UIElement GetTicketUiElement(cF4sdApiSearchResultRelation ticketRelation) + { + try + { + Border outputBorder = new Border(); + outputBorder.MouseLeftButtonUp += TicketRelation_MouseLeftButtonUp; + outputBorder.TouchDown += TicketRelation_TouchDown; + + outputBorder.SetResourceReference(StyleProperty, "Menu.SubCategory"); + outputBorder.Tag = ticketRelation; + + Grid contentGrid = new Grid(); + outputBorder.Child = contentGrid; + contentGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Auto) }); + contentGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) }); + + AdaptableIcon.AdaptableIcon ticketIcon = new AdaptableIcon.AdaptableIcon() { SelectedInternIcon = enumInternIcons.f4sd_outline }; + + if (RelationHasSpecialInfo(ticketRelation, TicketSpecialValues.TicketCreation)) + { + ticketIcon.SelectedInternIcon = enumInternIcons.misc_plus; + } + else if (RelationHasSpecialInfo(ticketRelation, TicketSpecialValues.NoTicket)) + { + ticketIcon.SelectedMaterialIcon = MaterialIconType.ic_block; + } + else if (ticketRelation.Infos.TryGetValue(TicketInfoKeys.StatusId, out string ticketStatusId)) + { + Enum.TryParse(ticketStatusId, true, out enumTicketStatus ticketStatus); + + switch (ticketStatus) + { + case enumTicketStatus.New: + case enumTicketStatus.InProgress: + case enumTicketStatus.OnHold: + ticketIcon.SelectedMaterialIcon = MaterialIconType.ic_drafts; + break; + case enumTicketStatus.Closed: + ticketIcon.SelectedMaterialIcon = MaterialIconType.ic_mail; + break; + } + } + else + { + ticketIcon.SelectedMaterialIcon = MaterialIconType.ic_mail; + } + + contentGrid.Children.Add(ticketIcon); + StackPanel ticketTextStack = new StackPanel() { Margin = new Thickness(15, 0, 15, 0), VerticalAlignment = VerticalAlignment.Center, IsHitTestVisible = false }; + Grid.SetColumn(ticketTextStack, 1); + contentGrid.Children.Add(ticketTextStack); + + Border ticketNameBorder = new Border() { ClipToBounds = true }; + ticketTextStack.Children.Add(ticketNameBorder); + + TextBlock ticketNameTextBlock = new TextBlock() { Text = ticketRelation.DisplayName, TextTrimming = TextTrimming.CharacterEllipsis }; + ticketNameBorder.Child = ticketNameTextBlock; + + Border ticketDescriptionBorder = new Border() { ClipToBounds = true }; + ticketTextStack.Children.Add(ticketDescriptionBorder); + + TextBlock ticketDescriptionTextBlock = null; + if (ticketRelation.Infos.TryGetValue(TicketInfoKeys.Summary, out string ticketSummary)) + { + ticketDescriptionTextBlock = new TextBlock() { Text = ticketSummary, TextTrimming = TextTrimming.CharacterEllipsis, FontWeight = FontWeights.UltraLight }; + ticketDescriptionBorder.Child = ticketDescriptionTextBlock; + } + + outputBorder.MouseEnter += (sender, e) => + { + try + { + cUtility.SetTickerTextAnimation(ticketNameTextBlock, ticketNameBorder); + + if (ticketDescriptionTextBlock != null) + cUtility.SetTickerTextAnimation(ticketDescriptionTextBlock, ticketDescriptionBorder); + } + catch (Exception E) + { + LogException(E); + } + }; + outputBorder.MouseLeave += (sender, e) => + { + try + { + ticketNameTextBlock.TextTrimming = TextTrimming.CharacterEllipsis; + ticketNameTextBlock.BeginAnimation(MarginProperty, null); + + ticketNameBorder.ClearValue(WidthProperty); + ticketNameTextBlock.ClearValue(WidthProperty); + + if (ticketDescriptionTextBlock != null) + { + ticketDescriptionTextBlock.TextTrimming = TextTrimming.CharacterEllipsis; + ticketDescriptionTextBlock.BeginAnimation(MarginProperty, null); + } + } + catch (Exception E) + { + LogException(E); + } + }; + + + return outputBorder; + } + catch (Exception E) + { + LogException(E); + } + + return null; + } + + private void UpdateSelectedTicketControl() + { + try + { + if (SelectedTicket is null) + return; + + TicketIcon.SelectedInternIcon = null; + TicketIcon.SelectedMaterialIcon = null; + TicketTextBlock.Text = SelectedTicket.DisplayName; + + if (SelectedTicket.Infos.TryGetValue(TicketInfoKeys.Summary, out var ticketSummary)) + TicketSummaryTextBox.Text = ticketSummary; + else + TicketSummaryTextBox.Text = string.Empty; + + if (RelationHasSpecialInfo(SelectedTicket, TicketSpecialValues.TicketCreation)) + { + TicketIcon.SelectedInternIcon = enumInternIcons.misc_plus; + } + else if (RelationHasSpecialInfo(SelectedTicket, TicketSpecialValues.NoTicket)) + { + TicketIcon.SelectedMaterialIcon = MaterialIconType.ic_block; + } + else if (SelectedTicket.Infos.TryGetValue(TicketInfoKeys.StatusId, out string ticketStatusId)) + { + Enum.TryParse(ticketStatusId, true, out enumTicketStatus ticketStatus); + + switch (ticketStatus) + { + case enumTicketStatus.New: + case enumTicketStatus.InProgress: + case enumTicketStatus.OnHold: + TicketIcon.SelectedMaterialIcon = MaterialIconType.ic_drafts; + break; + case enumTicketStatus.Closed: + TicketIcon.SelectedMaterialIcon = MaterialIconType.ic_mail; + break; + } + } + else + { + TicketIcon.SelectedMaterialIcon = MaterialIconType.ic_mail; + } + } + catch (Exception E) + { + LogException(E); + } + } + + private void CheckAffectedAssetIsCurrentAsset() + { + + try + { + WarningAssetHasBeenChanged.DataContext = this; + Binding visibilityBinding = new Binding(nameof(ShowAssetHasBeenChangedWarning)) + { + Converter = new BooleanToVisibilityConverter(), + }; + if (DataProvider == null) return; + + var computerName = GetSelectedTicketInfoOrDefault(TicketInfoKeys.Asset); + if (string.IsNullOrEmpty(computerName) || SelectedComputer == null) + { + AssetHasBeenChanged = false; + } + else + { + AssetHasBeenChanged = !SelectedComputer.DisplayName.Equals(computerName, StringComparison.OrdinalIgnoreCase); + } + WarningAssetHasBeenChanged.SetBinding(VisibilityProperty, visibilityBinding); + } + catch (Exception e) + { + LogException(e); + } + } + + private void CheckAffectedServiceIsCurrentService() + { + + try + { + WarningServiceHasBeenChanged.DataContext = this; + Binding visibilityBinding = new Binding(nameof(ShowServiceHasBeenChangedWarning)) + { + Converter = new BooleanToVisibilityConverter(), + }; + if (DataProvider == null) return; + + var service = GetSelectedTicketInfoOrDefault(TicketInfoKeys.ServiceId); + if (string.IsNullOrEmpty(service) || service == Guid.Empty.ToString() || SelectedService.Value == null) + { + ServiceHasBeenChanged = false; + } + else + { + ServiceHasBeenChanged = !SelectedService.Value.ToString().Equals(service, StringComparison.OrdinalIgnoreCase); + } + WarningServiceHasBeenChanged.SetBinding(VisibilityProperty, visibilityBinding); + } + catch (Exception e) + { + LogException(e); + } + } + + private void UpdateAffectedAssetComboBox() + { + try + { + if (DataProvider?.CaseRelations.TryGetValue(enumFasdInformationClass.Computer, out var computerRelationsTemp) != true) + return; + ComputerRelations = new List(computerRelationsTemp); + var currentlySelectedId = DataProvider.Identities.FirstOrDefault(identity => identity.Class == enumFasdInformationClass.Computer)?.Id; + var computerName = GetSelectedTicketInfoOrDefault(TicketInfoKeys.Asset); + + + // Direktes Hinzufügen von Standardoptionen + var defaultOptions = new List(); + + // Hinzufügen basierend auf der Verfügbarkeit eines ausgewählten Elements + if (SelectedTicket != _newTicketRelation && !string.IsNullOrEmpty(computerName)) + { + var stringTemplate = cMultiLanguageSupport.GetItem("Dialog.CloseCase.RemoveAffectedAssetEntry"); + _removeAffectedAssetEntry.DisplayName = string.Format(stringTemplate, computerName); + defaultOptions.AddRange(new[] { _removeAffectedAssetEntry }); + } + else + { + ComputerRelations.Remove(_removeAffectedAssetEntry); + } + var matchingRelation = ComputerRelations.FirstOrDefault(relation => relation.DisplayName == computerName); + + if (matchingRelation != null && !selectedTicketIsNewTicket) + { + ComputerRelations.Remove(matchingRelation); + } + ComputerRelations = ComputerRelations.Concat(defaultOptions).ToList(); + + var currentlySelectedComputer = DataProvider.Identities.FirstOrDefault(identity => identity.Class == enumFasdInformationClass.Computer); + if (currentlySelectedComputer != null) + SelectedComputer = ComputerRelations.FirstOrDefault(c => c.id == currentlySelectedComputer.Id); + else if (ComputerSelection.Items.Count > 0) + ComputerSelection.SelectedIndex = 0; + + if (currentlySelectedComputer == null || ComputerRelations.Any(x => RelationHasSpecialInfo(x, TicketSpecialValues.RemoveAffectedAssetEntry))) + SetOrUpdateComputerInTicket = false; + if (NewTicketPillSelected) + SetOrUpdateComputerInTicket = true; + + + } + catch (Exception e) + { + LogException(e); + } + } + + + private async void HandleServiceSearchDataChanged(object sender, cF4sdHealthSelectionDataRequest e) => await UpdateServiceSelectionControlAsync(e); + + private async Task UpdateServiceSelectionControlAsync(cF4sdHealthSelectionDataRequest requestData) + { + + try + { + string adDnUser = string.Empty; + + if (!cFasdCockpitCommunicationBase.Instance.IsDemo()) + { + if (DataProvider.NamedParameterEntries.TryGetValue("ad-dn-User", out var adDnUserParameter) && + !string.IsNullOrEmpty(adDnUserParameter.GetValue())) + { + adDnUser = adDnUserParameter.GetValue(); + } + else + { + return; + } + } + + requestData.Identities = DataProvider.Identities; + requestData.Table = "M42Wpm-Ticket-CloseCase-Services"; + requestData.FilterParams = new List { adDnUser }; + requestData.ResetFilter = ServiceSelectionControl.ResetFilter; + + if (string.IsNullOrEmpty(lastServiceSearch) || !lastServiceSearch.Equals(requestData.Search, StringComparison.OrdinalIgnoreCase)) + { + var resServiceCount = await cFasdCockpitCommunicationBase.Instance.GetPagedDataCount(requestData); + ServiceSelectionControl.TotalItemCount = resServiceCount; + lastServiceSearch = requestData.Search; + } + + var serviceData = await cFasdCockpitCommunicationBase.Instance.GetPagedData(requestData); + var servicesList = GetServiceSelectionData(serviceData); + + var service = GetSelectedTicketInfoOrDefault(TicketInfoKeys.ServiceId); + var serviceName = GetSelectedTicketInfoOrDefault(TicketInfoKeys.ServiceName); + if (!string.IsNullOrEmpty(service) && Guid.Empty.ToString() != service) + { + + servicesList.Add(new KeyValuePair(string.Format(cMultiLanguageSupport.GetItem("Dialog.CloseCase.RemoveAffectedServiceEntry"), serviceName), TicketSpecialValues.RemoveAffectedServiceEntry)); + var itemToRemove = servicesList.FirstOrDefault(item => item.Value is string && (string)item.Value == service); + if (!itemToRemove.Equals(default(KeyValuePair))) + { + servicesList.Remove(itemToRemove); + } + } + else + { + var itemToRemove = servicesList.FirstOrDefault(x => string.Equals(x.Value.ToString(), TicketSpecialValues.RemoveAffectedServiceEntry, StringComparison.OrdinalIgnoreCase)); + if (itemToRemove.Key != null) + { + servicesList.Remove(itemToRemove); + } + } + ServiceSelectionControl.ItemData = servicesList; + } + catch (Exception E) + { + LogException(E); + } + } + + private ObservableCollection> GetServiceSelectionData(cF4SDHealthCardRawData.cHealthCardTable dataTable) + { + try + { + if (dataTable is null || dataTable.Name != "M42Wpm-Ticket-CloseCase-Services") + return null; + + if (!dataTable.Columns.TryGetValue("id", out var idColumn)) + return null; + + dataTable.Columns.TryGetValue("Name", out var nameColumn); + + var zippedKeyValuePairs = idColumn.Values.Zip(nameColumn.Values, (id, display) => new KeyValuePair(display.ToString(), id)); + + return new ObservableCollection>(zippedKeyValuePairs); + } + catch (Exception E) + { + LogException(E); + } + + return null; + } + + private async Task InitializeCategorySelectionAsync() + { + if (isCategoryLoading) + return; + + try + { + if (DataProvider == null || CategorySelectionControl == null) + return; + + isCategoryLoading = true; + + var tableCandidates = new[] { CategoryTableNamePrimary, CategoryTableNameLegacy }; + bool initialized = false; + + foreach (var tableName in tableCandidates) + { + if (await TryPopulateCategoryHierarchyAsync(tableName)) + { + activeCategoryTableName = tableName; + initialized = true; + break; + } + } + + if (initialized) + { + CategorySelectionControl.ItemsSource = categoryHierarchy; + TrySelectTicketCategoryFromTicketInfos(); + } + } + catch (Exception E) + { + LogException(E); + } + finally + { + isCategoryLoading = false; + ValidateProperty(ValidationPropertyNames.SelectedCategory); + } + } + + private async Task TryPopulateCategoryHierarchyAsync(string tableName) + { + try + { + const int defaultPageSize = 250; + + var requestData = new cF4sdHealthSelectionDataRequest + { + Identities = DataProvider.Identities, + Table = tableName, + Page = 0, + PageSize = defaultPageSize, + Search = string.Empty + }; + + var totalCount = await cFasdCockpitCommunicationBase.Instance.GetPagedDataCount(requestData); + var effectivePageSize = requestData.PageSize > 0 ? requestData.PageSize : defaultPageSize; + var pageCount = Math.Max(1, (int)Math.Ceiling((double)totalCount / Math.Max(1, effectivePageSize))); + + var flatItems = new Dictionary(StringComparer.OrdinalIgnoreCase); + + for (int pageIndex = 0; pageIndex < pageCount; pageIndex++) + { + requestData.Page = pageIndex; + requestData.PageSize = effectivePageSize; + + var categoryTable = await cFasdCockpitCommunicationBase.Instance.GetPagedData(requestData); + bool rowAdded = false; + + foreach (var item in ConvertCategoryTable(categoryTable)) + { + if (string.IsNullOrWhiteSpace(item.Id)) + continue; + + flatItems[item.Id] = item; + rowAdded = true; + } + + if (!rowAdded && categoryTable == null) + return false; + } + + var hierarchy = HierarchicalSelectionItem.BuildTree(flatItems.Values); + if (hierarchy == null || hierarchy.Count == 0) + return false; + + categoryHierarchy = hierarchy; + UpdateCategoryLookup(); + return true; + } + catch (Exception E) + { + LogException(E); + return false; + } + } + + private IEnumerable ConvertCategoryTable(cF4SDHealthCardRawData.cHealthCardTable dataTable) + { + if (dataTable == null || dataTable.Columns == null) + yield break; + + if (!dataTable.Columns.TryGetValue("id", out var idColumn)) + yield break; + + if (!dataTable.Columns.TryGetValue("Name", out var nameColumn)) + yield break; + + cF4SDHealthCardRawData.cHealthCardTableColumn parentIdColumn = null; + cF4SDHealthCardRawData.cHealthCardTableColumn parentNameColumn = null; + if (!dataTable.Columns.TryGetValue("parentValue", out parentIdColumn)) + dataTable.Columns.TryGetValue("Parent_Value", out parentIdColumn); + if (!dataTable.Columns.TryGetValue("parent", out parentNameColumn)) + dataTable.Columns.TryGetValue("Parent", out parentNameColumn); + + for (int index = 0; index < idColumn.Values.Count; index++) + { + var id = idColumn.Values[index]?.ToString(); + if (string.IsNullOrWhiteSpace(id)) + continue; + + var displayName = index < nameColumn.Values.Count ? nameColumn.Values[index]?.ToString() : string.Empty; + + string parentId = null; + if (parentIdColumn != null && index < parentIdColumn.Values.Count) + parentId = parentIdColumn.Values[index]?.ToString(); + + if (Guid.TryParse(parentId, out var parsedParentId) && parsedParentId == Guid.Empty) + parentId = null; + + var parentDisplayName = parentNameColumn != null && index < parentNameColumn.Values.Count + ? parentNameColumn.Values[index]?.ToString() + : null; + + yield return new HierarchicalSelectionItem + { + Id = id, + DisplayName = string.IsNullOrWhiteSpace(displayName) ? parentDisplayName ?? id : displayName, + ParentId = parentId, + ParentDisplayName = parentDisplayName + }; + } + } + + private void UpdateCategoryLookup() + { + categoryLookup.Clear(); + + if (categoryHierarchy == null) + return; + + foreach (var node in categoryHierarchy.SelectMany(item => item.SelfAndDescendants())) + { + if (!string.IsNullOrWhiteSpace(node.Id)) + categoryLookup[node.Id] = node; + } + } + + private void TrySelectTicketCategoryFromTicketInfos() + { + try + { + if (SelectedTicket?.Infos == null) + { + SelectedCategory = null; + return; + } + + if (!SelectedTicket.Infos.TryGetValue(TicketInfoKeys.Category, out var categoryId) || string.IsNullOrWhiteSpace(categoryId)) + { + SelectedCategory = null; + return; + } + + if (categoryLookup.TryGetValue(categoryId, out var categoryNode)) + SelectedCategory = categoryNode; + } + catch (Exception E) + { + LogException(E); + } + } + + private Guid? GetSelectedCategoryGuid() + { + if (SelectedCategory == null || string.IsNullOrWhiteSpace(SelectedCategory.Id)) + return null; + + if (Guid.TryParse(SelectedCategory.Id, out var categoryGuid)) + return categoryGuid; + + return null; + } + + private async Task UpdateQuickCallsComboBoxAsync() + { + try + { + cF4sdHealthSelectionDataRequest requestData = new cF4sdHealthSelectionDataRequest + { + Identities = DataProvider.Identities, + Table = "M42Wpm-Ticket-QuickCalls" + }; + + var resultCount = await cFasdCockpitCommunicationBase.Instance.GetPagedDataCount(requestData); + var quickCallsTable = await cFasdCockpitCommunicationBase.Instance.GetPagedData(requestData); + + if (quickCallsTable == null) return; + + if (!quickCallsTable.Columns.TryGetValue("Name", out var namesColumn) || + !quickCallsTable.Columns.TryGetValue("id", out var idsColumn) || + !quickCallsTable.Columns.TryGetValue("Classification", out var classificationColumn)) + { + return; + } + + var quickCallListe = new List(); + + for (int i = 0; i < idsColumn.Values.Count; i++) + { + var id = idsColumn.Values[i].ToString(); + var name = namesColumn.Values[i].ToString(); + + Guid? classification = null; + var classificationValue = classificationColumn.Values[i]?.ToString(); + if (Guid.TryParse(classificationValue, out var parsedClassification)) + classification = parsedClassification; + + + quickCallListe.Add(new QuickCallEntry + { + ID = id, + DisplayName = name, + Classification = classification + }); + } + + QuickTicketSelection.ItemsSource = quickCallListe; + + QuickTicketSelection.SelectedItem = quickCallListe + .FirstOrDefault(x => x.ID == "7bbe64e2-94d0-ee11-4285-00155d010a04"); + ValidateProperty(ValidationPropertyNames.QuickTicketSelection); + } + catch (Exception e) + { + LogException(e); + } + } + + public class QuickCallEntry + { + public string ID { get; set; } + public string DisplayName { get; set; } + public Guid? Classification { get; set; } + public override string ToString() + { + return DisplayName.ToString(); + } + } + + + private void UpdateTicketSelection() + { + + try + { + TicketSelectionContainer.Children.Clear(); + + if (DataProvider is null) + return; + + if (!DataProvider.CaseRelations.TryGetValue(enumFasdInformationClass.Ticket, out var tempTicketRelations)) + return; + + var ticketRelations = new List(tempTicketRelations); + //ticketRelations.Insert(0, newTicketRelation); + //ticketRelations.Add(noTicketRelation); + + foreach (var ticketRelation in ticketRelations) + { + var tempTicketElement = GetTicketUiElement(ticketRelation); + + if (tempTicketElement is Border ticketBorder) + { + if (ticketRelations.FirstOrDefault() == ticketRelation) + ticketBorder.CornerRadius = new CornerRadius(7.5, 7.5, 0, 0); + else if (ticketRelations.LastOrDefault() == ticketRelation) + ticketBorder.CornerRadius = new CornerRadius(0, 0, 7.5, 7.5); + } + + if (tempTicketElement is null) + continue; + + TicketSelectionContainer.Children.Add(tempTicketElement); + } + + var currentlySelectedTicket = DataProvider.Identities.FirstOrDefault(identity => identity.Class == enumFasdInformationClass.Ticket); + if (currentlySelectedTicket != null && !NewTicketPillSelected) + SelectedTicket = ticketRelations.FirstOrDefault(ticket => ticket.id == currentlySelectedTicket.Id); + } + catch (Exception E) + { + LogException(E); + } + } + + private void UpdateCaseNotesPreview() + { + try + { + if (DataProvider is null) + return; + + var caseNotesFlowDocument = DataProvider.CaseNotes; + StringBuilder caseNotes = new StringBuilder(); + cRichTextBoxHelper.TraverseBlockAsUnicode(caseNotesFlowDocument.Blocks, caseNotes); + CaseNotesPreview.Text = caseNotes.ToString(); + } + catch (Exception E) + { + LogException(E); + } + + } + private void AddNewOrExistingOrNoneTicketSelection() + { + try + { + bool createTicket = _selectedTicket == null || SelectedTicket == _selectTicketRelation || selectedTicketIsNewTicket; + if (TryGetSelectedTicketInfo(TicketInfoKeys.StatusId, out var statusIdString) && + Enum.TryParse(statusIdString, true, out enumTicketStatus statusId)) + { + createTicket = statusId == enumTicketStatus.Closed; + SelectedTicket = SelectedTicket ?? _selectTicketRelation; + } + + TicketSelectionBorder.IsEnabled = !createTicket; + + var pillInfos = new (string, string, string, bool, bool)[] + { + ("Header.Create.Ticket", "CreateTicket", "misc_plus", false, createTicket), + ("Header.Select.Ticket", "SelectTicket", "ic_drafts", true, !createTicket), + ("Header.Skip.Ticket", "SkipTicket", "ic_block", true, false) + }; + NewTicketPillSelected = createTicket; + + foreach (var (textKey, tag, icon, isMaterialIcon, isSelected) in pillInfos) + { + var pillText = cMultiLanguageSupport.GetItem(textKey); + var selectionPill = new SelectionPill + { + PillText = pillText, + Tag = tag, + SelectOne = true, + GroupName = "NewUpdateNoTicketSelection", + IsSelected = isSelected + }; + + if (isMaterialIcon) + { + selectionPill.SelectedMaterialIcon = (MaterialIconType)Enum.Parse(typeof(MaterialIconType), icon); + } + else + { + selectionPill.SelectedInternIcon = (enumInternIcons)Enum.Parse(typeof(enumInternIcons), icon); + } + if (checkTicketActive()) + { + if (string.Equals(tag, "SelectTicket", StringComparison.OrdinalIgnoreCase)) + { + selectionPill.IsSelectedChanged += (s, e) => + { + TicketSelectionBorder.IsEnabled = selectionPill.IsSelected; + + + if (!DataProvider.CaseRelations.TryGetValue(enumFasdInformationClass.Ticket, out var tempTicketRelations)) + return; + + var ticketRelations = new List(tempTicketRelations); + var currentlySelectedTicket = DataProvider.Identities.FirstOrDefault(identity => identity.Class == enumFasdInformationClass.Ticket); + SelectedTicket = SelectedTicket ?? ticketRelations.FirstOrDefault(ticket => ticket.id == currentlySelectedTicket.Id); + ValidateProperty(ValidationPropertyNames.SelectedTicket); + ValidateProperty(ValidationPropertyNames.TicketSummaryTextBox); + ValidateProperty(ValidationPropertyNames.TicketStatusCombobox); + }; + } + else if (string.Equals(tag, "CreateTicket", StringComparison.OrdinalIgnoreCase)) + { + selectionPill.IsSelectedChanged += (s, e) => + { + NewTicketPillSelected = selectionPill.IsSelected; + SelectedTicket = selectionPill.IsSelected ? SelectedTicket : _selectTicketRelation; + if (selectionPill.IsSelected) + { + SelectedTicket = _selectTicketRelation; + } + ValidateProperty(ValidationPropertyNames.SelectedTicket); + ValidateProperty(ValidationPropertyNames.TicketSummaryTextBox); + ValidateProperty(ValidationPropertyNames.TicketStatusCombobox); + }; + } + else if (string.Equals(tag, "SkipTicket", StringComparison.OrdinalIgnoreCase)) + { + selectionPill.IsSelectedChanged += (s, e) => + { + _skipTicketPillSelected = selectionPill.IsSelected; + _errors.Clear(); + UpdateTicketComponentVisibility(); + ValidateProperty(ValidationPropertyNames.SelectedTicket); + ValidateProperty(ValidationPropertyNames.TicketSummaryTextBox); + ValidateProperty(ValidationPropertyNames.TicketStatusCombobox); + if (selectionPill.IsSelected) + { + TicketStatusCombobox.SelectedIndex = 0; + } + }; + } + NewOrExistingOrNoneTicketWrap.Children.Add(selectionPill); + } + } + } + catch (Exception E) + { + LogException(E); + } + } + private void AddCopyTemplates() + { + try + { + foreach (var copyTemplate in cF4SDCockpitXmlConfig.Instance.CopyTemplateConfig.CopyTemplates.CopyTemplates) + { + if (copyTemplate.Value.HiddenInTicketDialog) + continue; + + var selectionPill = new SelectionPill() { PillText = copyTemplate.Value.Names.GetValue(), Tag = copyTemplate.Value }; + + if (!string.IsNullOrWhiteSpace(copyTemplate.Value.Descriptions.GetValue())) + selectionPill.ToolTip = copyTemplate.Value.Descriptions.GetValue(); + + switch (copyTemplate.Value.Icon.IconType) + { + case enumIconType.intern: + if (Enum.TryParse(copyTemplate.Value.Icon.Name, out enumInternIcons internIcon)) + selectionPill.SelectedInternIcon = internIcon; + break; + case enumIconType.material: + if (Enum.TryParse(copyTemplate.Value.Icon.Name, out MaterialIcons.MaterialIconType materialIcon)) + selectionPill.SelectedMaterialIcon = materialIcon; + break; + case enumIconType.gif: + if (Enum.TryParse(copyTemplate.Value.Icon.Name, out enumInternGif internGif)) + selectionPill.SelectedGif = internGif; + break; + } + + CopyTemplateWrap.Children.Add(selectionPill); + } + } + catch (Exception E) + { + LogException(E); + } + } + + private string GetCopyText(enumCopyContentFormat format) + { + string output = string.Empty; + + try + { + if (CopyTemplateWrap.Children?.Count <= 0) + return string.Empty; + + foreach (var child in CopyTemplateWrap.Children) + { + if (!(child is SelectionPill selectionPill)) + continue; + + if (selectionPill.IsSelected == false) + continue; + + if (!(selectionPill.Tag is cCopyTemplate selectedCopyTemplate)) + continue; + + if (!selectedCopyTemplate.CopyContentList.TryGetValue(format, out cCopyContent copyContent)) + if (!selectedCopyTemplate.CopyContentList.TryGetValue(enumCopyContentFormat.UNICODE, out copyContent)) + continue; + + if (copyContent is null) + continue; + + if (!string.IsNullOrEmpty(output)) + output += format == enumCopyContentFormat.HTML ? "

" : "\n\n"; + + string copyText = copyContent.Content; + copyText = DataProvider.HealthCardDataHelper.ReplaceNamedParameters(copyText, format == enumCopyContentFormat.HTML); + + if (format == enumCopyContentFormat.HTML) + output += "
" + copyText + "
"; + else + output += copyText; + } + } + catch (Exception E) + { + LogException(E); + } + + return output; + } + + #region CloseCaseWithTicket + + private bool CloseCaseWithCopy() + { + try + { + StringBuilder asciiStringBuilder = new StringBuilder(); + StringBuilder htmlStringBuilder = new StringBuilder(); + + if (TransferCaseNotesCheck.IsChecked ?? false) + { + + var caseNotes = DataProvider.CaseNotes; + + var unicodeCaseNotes = new StringBuilder(); + cRichTextBoxHelper.TraverseBlockAsUnicode(DataProvider.CaseNotes.Blocks, unicodeCaseNotes); + if (!string.IsNullOrWhiteSpace(unicodeCaseNotes.ToString())) + { + asciiStringBuilder.AppendLine(cMultiLanguageSupport.GetItem("Dialog.CloseCase.Summary") + ": \n"); + htmlStringBuilder.AppendLine("" + cMultiLanguageSupport.GetItem("Dialog.CloseCase.Summary") + ":
"); + asciiStringBuilder.Append(unicodeCaseNotes); + } + + var htmlCaseNotes = new StringBuilder(); + cRichTextBoxHelper.TraverseBlockAsHtml(DataProvider.CaseNotes.Blocks, htmlCaseNotes); + if (!string.IsNullOrWhiteSpace(htmlCaseNotes.ToString())) + htmlStringBuilder.Append(htmlCaseNotes); + else + htmlStringBuilder.Append(unicodeCaseNotes); + } + + if (string.IsNullOrEmpty(asciiStringBuilder.ToString()) is false) + asciiStringBuilder.AppendLine(); + + if (string.IsNullOrEmpty(htmlStringBuilder.ToString()) is false) + htmlStringBuilder.AppendLine("

"); + + + var copyText = GetCopyText(enumCopyContentFormat.UNICODE); + if (!string.IsNullOrEmpty(copyText)) + { + asciiStringBuilder.AppendLine(cMultiLanguageSupport.GetItem("Dialog.CloseCase.Heading.CopyTemplates") + ": \n"); + htmlStringBuilder.AppendLine("" + cMultiLanguageSupport.GetItem("Dialog.CloseCase.Heading.CopyTemplates") + ":
"); + + asciiStringBuilder.AppendLine(copyText); + htmlStringBuilder.AppendLine(GetCopyText(enumCopyContentFormat.HTML)); + } + + if (TransferQuickActionHistoryCheck.IsChecked ?? false) + { + var quickActionProtocoll = F4SDProtocoll.Instance.GetAllAsDataObject(true); + var actionText = quickActionProtocoll.GetText(); + + if (!string.IsNullOrEmpty(actionText)) + { + + if (string.IsNullOrEmpty(asciiStringBuilder.ToString()) is false) + asciiStringBuilder.AppendLine(); + + if (string.IsNullOrEmpty(htmlStringBuilder.ToString()) is false) + htmlStringBuilder.AppendLine("

"); + + asciiStringBuilder.AppendLine(cMultiLanguageSupport.GetItem("Dialog.CloseCase.Heading.QuickActions") + ": \n"); + htmlStringBuilder.AppendLine("" + cMultiLanguageSupport.GetItem("Dialog.CloseCase.Heading.QuickActions") + ":

"); + + asciiStringBuilder.AppendLine(quickActionProtocoll.GetText()); + htmlStringBuilder.AppendLine("
" + quickActionProtocoll.GetText(TextDataFormat.Html)); + } + } + + + DataObject tempDataObj = new DataObject(); + tempDataObj.SetText(asciiStringBuilder.ToString()); + tempDataObj.SetText(cUtility.GetHtmlFrame(htmlStringBuilder.ToString()), TextDataFormat.Html); + + System.Windows.Forms.Clipboard.SetDataObject(tempDataObj, true); + + return true; + } + catch (Exception E) + { + LogException(E); + } + + + return false; + } + + private async Task CloseCaseWithTicketAsync(Guid? userId = null) + { + var cm = MethodBase.GetCurrentMethod(); + LogMethodBegin(cm); + + try + { + if (SelectedTicket.Equals(_noTicketRelation)) + return false; + // Update Ticket Tables + const string ticketTable = "M42Wpm-Tickets"; + Dictionary ticketValues = new Dictionary() + { + ["UserId"] = userId, + + ["id"] = SelectedTicket.id, + [TicketInfoKeys.Summary] = TicketSummaryTextBox.Text, + ["CreationSource"] = 3, + ["Status"] = enumTicketStatus.Unknown, + ["time"] = DateTime.UtcNow, + ["Priority"] = 2, + }; + Guid quickcallId = Guid.Empty; + Guid? quickCallClassificationId = null; + if (QuickTicketSelection.SelectedItem is QuickCallEntry selectedQuickTicketItem) + { + //ticketValues.Add("Category", selectedQuickTicketItem.DisplayName); + ticketValues.Add("QuickCallId", selectedQuickTicketItem.ID); + Guid.TryParse(selectedQuickTicketItem.ID?.ToString(), out quickcallId); + if (selectedQuickTicketItem.Classification.HasValue) + { + quickCallClassificationId = selectedQuickTicketItem.Classification; + ticketValues["Classification"] = quickCallClassificationId.Value; + } + } + var selectedCategoryId = GetSelectedCategoryGuid(); + if (selectedCategoryId.HasValue) + ticketValues[TicketInfoKeys.Category] = selectedCategoryId.Value; + enumCloseCaseTicketStatus? closeCaseTicketStatus = null; + int errorType = -1; + var comment = string.Empty; + DateTime? reminderDate = null; + Guid? selectedRole = null; + Guid? selectedPerson = null; + if (TicketStatusCombobox.SelectedItem is ComboBoxItem selectedItem + && Enum.TryParse(selectedItem.Tag?.ToString(), out enumCloseCaseTicketStatus result)) + { + closeCaseTicketStatus = result; + switch (closeCaseTicketStatus) + { + case enumCloseCaseTicketStatus.Close: + ticketValues.Add("ClosingDate", DateTime.UtcNow); + ticketValues["Status"] = enumTicketStatus.Closed; + + if (DynamicStatusAdditionBorder.Child is CloseTicketDialog closeTicket) + { + ticketValues.Add("Solution", closeTicket.Solution); + if (closeTicket.ErrorTypeComboBox.SelectedItem is ComboBoxItem closeTicketComboBox) + { + int.TryParse(closeTicketComboBox.Tag?.ToString(), out errorType); + ticketValues.Add("ErrorType", closeTicketComboBox.Tag); + } + } + break; + case enumCloseCaseTicketStatus.OnHold: + { + if (DynamicStatusAdditionBorder.Child is HoldTicketDialog holdTicket) + { + comment = holdTicket.Comment; + } + } + ticketValues["Status"] = enumTicketStatus.OnHold; + break; + case enumCloseCaseTicketStatus.Forward: + if (DynamicStatusAdditionBorder.Child is ForwardTicketDialog forwardTicket) + { + var roleSelection = forwardTicket.RoleSelectionControl.GetSelectedValue(); + if (roleSelection.HasValue) + { + var roleSelectionval = roleSelection.Value.Value.ToString(); + if (Guid.TryParse(roleSelectionval, out var roleResult)) + { + selectedRole = roleResult; + } + } + var personSelection = forwardTicket.PersonSelectionControl.GetSelectedValue(); + if (personSelection.HasValue) + { + var personSelectionval = personSelection.Value.Value.ToString(); + if (Guid.TryParse(personSelectionval, out var personResult)) + { + selectedPerson = personResult; + } + } + comment = forwardTicket.Comment; + } + ticketValues["Status"] = enumTicketStatus.InProgress; + break; + default: + ticketValues["Status"] = enumTicketStatus.New; + break; + } + } + + string user = string.Empty; + if (DataProvider.NamedParameterEntries.TryGetValue("UserFullName", out var userNameParameter)) + user = userNameParameter.GetValue(); + ticketValues.Add("AffectedUser", user); + string asset = string.Empty; + if (SelectedComputer == _removeAffectedAssetEntry) + { + asset = TicketSpecialValues.RemoveAffectedAssetEntry; + } + else if (SetOrUpdateComputerInTicket) + { + asset = SelectedComputer?.DisplayName; + } + + ticketValues.Add("Asset", asset); + + Guid? service = null; + if (SetOrUpdateServiceInTicket && SelectedService.Value != null) + { + if (string.Equals(SelectedService.Value.ToString(), TicketSpecialValues.RemoveAffectedServiceEntry, StringComparison.OrdinalIgnoreCase)) + service = Guid.Empty; + else if (Guid.TryParse(SelectedService.Value.ToString(), out Guid parsedGuid)) + { + service = parsedGuid; + } + } + + + string adDnComputer = string.Empty; + string userFullName = string.Empty; + string userAccount = string.Empty; + string adDnUser = string.Empty; + string userMail = string.Empty; + + // Abrufen der Variablenwerte aus den NamedParameterEntries + if (DataProvider.NamedParameterEntries.TryGetValue("ad-dn-computer", out var adDnComputerParameter)) + { + adDnComputer = adDnComputerParameter.GetValue(); + } + + if (DataProvider.NamedParameterEntries.TryGetValue("UserFullName", out var userFullNameParameter)) + { + userFullName = userFullNameParameter.GetValue(); + } + + if (DataProvider.NamedParameterEntries.TryGetValue("UserAccount", out var userAccountParameter)) + { + userAccount = userAccountParameter.GetValue(); + } + + if (DataProvider.NamedParameterEntries.TryGetValue("ad-dn-User", out var adDnUserParameter)) + { + adDnUser = adDnUserParameter.GetValue(); + } + + if (DataProvider.NamedParameterEntries.TryGetValue("UserMail", out var userMailParameter)) + { + userMail = userMailParameter.GetValue(); + } + + var htmlCaseNotes = new StringBuilder(); + if (TransferCaseNotesCheck.IsChecked ?? false) + { + var caseNotes = DataProvider.CaseNotes; + + var unicodeCaseNotes = new StringBuilder(); + cRichTextBoxHelper.TraverseBlockAsUnicode(DataProvider.CaseNotes.Blocks, unicodeCaseNotes); + if (!string.IsNullOrWhiteSpace(unicodeCaseNotes.ToString())) + ticketValues.Add("Description", unicodeCaseNotes.ToString()); + + cRichTextBoxHelper.TraverseBlockAsHtml(DataProvider.CaseNotes.Blocks, htmlCaseNotes); + if (!string.IsNullOrWhiteSpace(htmlCaseNotes.ToString())) + ticketValues.Add("DescriptionHtml", htmlCaseNotes.ToString()); + } + + const string journalTable = "M42Wpm-Tickets-History"; + + //Update QuickAction History + string solutionHtmlString = string.Empty; + Dictionary quickActionValues = null; + + if (ticketValues.TryGetValue("Solution", out var solutionValue)) + { + if (solutionValue is string solutionString) + { + if (!string.IsNullOrWhiteSpace(solutionString)) + { + solutionString += "\n\n\n"; + solutionHtmlString = solutionString + "


"; + } + else + { + solutionHtmlString = "


"; + } + + ticketValues["Solution"] = solutionString; + ticketValues["SolutionHtml"] = solutionHtmlString; + } + } + + if (TransferQuickActionHistoryCheck.IsChecked ?? false) + { + var quickActionProtocoll = F4SDProtocoll.Instance.GetAllAsDataObject(true); + + if (ticketValues.TryGetValue("Solution", out solutionValue)) + { + if (solutionValue is string solutionString) + { + solutionString += quickActionProtocoll.GetText(); + solutionHtmlString += quickActionProtocoll.GetText(TextDataFormat.Html); + + ticketValues["Solution"] = solutionString; + ticketValues["SolutionHtml"] = solutionHtmlString; + } + } + else + { + var tempQuickActionValues = new Dictionary() + { + ["UserId"] = userId, + ["id"] = SelectedTicket.id, + ["Header"] = "Commented by F4SD", + ["IsVisibleForUser"] = false, + ["time"] = DateTime.UtcNow, + ["Description"] = quickActionProtocoll.GetText(), + ["DescriptionHtml"] = string.IsNullOrWhiteSpace(quickActionProtocoll.GetText(TextDataFormat.Html)) + ? quickActionProtocoll.GetText() + : quickActionProtocoll.GetText(TextDataFormat.Html) + }; + + if (!string.IsNullOrWhiteSpace(quickActionProtocoll.GetText())) + quickActionValues = tempQuickActionValues; + } + } + + await cFasdCockpitCommunicationBase.Instance.UpdateHealthcardTableData(new cF4SDWriteParameters() { id = SelectedTicket.id, TableName = ticketTable, Values = ticketValues }); + + if (quickActionValues != null) + await cFasdCockpitCommunicationBase.Instance.UpdateHealthcardTableData(new cF4SDWriteParameters() { id = SelectedTicket.id, TableName = journalTable, Values = quickActionValues }); + + string copyString = GetCopyText(enumCopyContentFormat.UNICODE); + string copyStringHtml = GetCopyText(enumCopyContentFormat.HTML); + if (!string.IsNullOrWhiteSpace(copyString)) + { + Dictionary copyValues = new Dictionary() + { + ["UserId"] = userId, + + ["id"] = SelectedTicket.id, + ["Header"] = "Commented by F4SD", + ["IsVisibleForUser"] = false, + ["time"] = DateTime.UtcNow, + ["Description"] = copyString, + ["DescriptionHtml"] = string.IsNullOrWhiteSpace(copyStringHtml) ? copyString : copyStringHtml + }; + await cFasdCockpitCommunicationBase.Instance.UpdateHealthcardTableData(new cF4SDWriteParameters() { id = SelectedTicket.id, TableName = journalTable, Values = copyValues }); + } + + string statusIdValue = null; + if (TryGetSelectedTicketInfo(TicketInfoKeys.StatusId, out var value)) + { + statusIdValue = value; + } + + + var workingTimes = TimerView.GetWorkTimes(); + workingTimes.Add("Description", cMultiLanguageSupport.GetItem("Dialog.CloseCase.WorkingTimeEntryDescription")); + var doNotEscalate = false; + var holdTicketReason = 0; + if (this.DynamicStatusAdditionBorder.Child is HoldTicketDialog holdTicketDialog) + { + reminderDate = new DateTime( + holdTicketDialog.SelectedDate.Year, + holdTicketDialog.SelectedDate.Month, + holdTicketDialog.SelectedDate.Day, + holdTicketDialog.SelectedHour, + holdTicketDialog.SelectedMinute, + 0); + doNotEscalate = (bool)holdTicketDialog.DoNotEscalate.IsChecked; + if (holdTicketDialog.ReasonSelection.SelectedItem is ComboBoxItem sel) + { + if (int.TryParse(sel.Tag.ToString(), out int tmpReasonTag)) + { + holdTicketReason = tmpReasonTag; + } + } + } + cApiM42Ticket ticketData = new cApiM42Ticket() + { + Ticket = _selectedTicket.Identities == null ? Guid.Empty : SelectedTicket.id, + Action = closeCaseTicketStatus.HasValue ? closeCaseTicketStatus : null, + User = adDnUser, + AffectedAsset = asset, + AffectedService = service, + Category = selectedCategoryId, + Summary = TicketSummaryTextBox.Text, + DescriptionHtml = htmlCaseNotes.ToString(), + Quickcall = quickcallId, + Classification = quickCallClassificationId, + CopyTemplates = string.IsNullOrWhiteSpace(copyStringHtml) ? copyString : copyStringHtml, + SolutionHtml = solutionHtmlString, + ErrorType = errorType, + ReminderDate = reminderDate, + DoNotEscalateWhilePaused = doNotEscalate, + Reason = holdTicketReason, + ResponsibleRole = selectedRole, + ResponsiblePerson = selectedPerson, + Comment = comment, + QuickActionHistory = TransferQuickActionHistoryCheck.IsChecked ?? false ? F4SDProtocoll.Instance.GetOfType().Select(e => e.GetResult()).ToList() : null, + workTimes = workingTimes, + StatusIdValue = statusIdValue, + CaseId = DataProvider.CaseId + }; + ticketData.AdditionalValues.Add("IsTicket", IsTicket); + ticketData.AdditionalValues.Add(TicketInfoKeys.ActivityType, GetSelectedTicketInfoOrDefault(TicketInfoKeys.ActivityType)); + ticketData.AdditionalValues.Add("Dialog.CloseCase.AssetNotFoundInMatrix42", cMultiLanguageSupport.GetItem("Dialog.CloseCase.AssetNotFoundInMatrix42")); + ticketData.AdditionalValues.Add("Dialog.CloseCase.ReopenReasonText", cMultiLanguageSupport.GetItem("Dialog.CloseCase.ReopenReasonText")); + ticketData.AdditionalValues.Add("Dialog.CloseCase.ReopenReasonTextHtml", cMultiLanguageSupport.GetItem("Dialog.CloseCase.ReopenReasonTextHtml")); + var _res = await cFasdCockpitCommunicationBase.Instance.Matrix42TicketFinalization(ticketData); + return true; + } + catch (Exception e) + { + LogException(e); + } + finally + { + LogMethodEnd(cm); + } + return false; + } + + public async Task CloseCaseAsync(Guid? userId = null) + { + try + { + + if (checkTicketActive() && !_skipTicketPillSelected) + return await CloseCaseWithTicketAsync(userId); + else + return CloseCaseWithCopy(); + } + catch (Exception E) + { + LogException(E); + } + + return false; + } + + #endregion + + + public List GetErrors(string propertyName) + { + switch (propertyName) + { + case ValidationPropertyNames.SelectedTicket: + if (SelectedTicket == _selectTicketRelation && !NewTicketPillSelected && !SkipTicketPillSelected) + { + if (!_errors.ContainsKey(propertyName)) + _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Header.Select.Ticket")); + } + else + { + if (_errors.ContainsKey(propertyName)) + _errors.Remove(propertyName); + } + break; + case ValidationPropertyNames.TicketSummaryTextBox: + validateTextboxNotEmpty(TicketSummaryTextBox); + if (!string.IsNullOrEmpty(TicketSummaryTextBox.Text) || !TicketSummaryTextBox.IsVisible) + { + if (_errors.ContainsKey(propertyName)) + _errors.Remove(propertyName); + } + else + { + if (!_errors.ContainsKey(propertyName)) + _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorSummaryEmpty")); + } + break; + case ValidationPropertyNames.CaseNotesPreview: + var errorNotEmpty = CheckTextBlockNotEmpty(CaseNotesPreview, cFasdCockpitConfig.Instance.Global.TicketConfiguration.NotesMandatory); + if (errorNotEmpty && CaseNotesPreview.IsVisible) + { + if (!_errors.ContainsKey(propertyName)) + _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorCaseNoteEmpty")); + } + else + { + if (_errors.ContainsKey(propertyName)) + _errors.Remove(propertyName); + } + break; + case ValidationPropertyNames.SolutionTextbox: + if (DynamicStatusAdditionBorder.Child is CloseTicketDialog closeTicketDialog) + { + if (string.IsNullOrEmpty(closeTicketDialog.Solution)) + { + setTextboxErrorState(closeTicketDialog.SolutionTextbox, true); + if (!_errors.ContainsKey(propertyName)) + _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorSolutionEmpty")); + } + else + { + setTextboxErrorState(closeTicketDialog.SolutionTextbox, false); + if (_errors.ContainsKey(propertyName)) + _errors.Remove(propertyName); + } + } + break; + case ValidationPropertyNames.ReminderDate: + if (DynamicStatusAdditionBorder.Child is HoldTicketDialog holdTicketDialog) + { + if (holdTicketDialog.SelectedReminderDate <= DateTime.UtcNow.AddMinutes(-2)) + { + if (!_errors.ContainsKey(propertyName)) + _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorReminderDate")); + } + else + { + if (_errors.ContainsKey(propertyName)) + _errors.Remove(propertyName); + } + } + break; + + case ValidationPropertyNames.ErrorTypeValue: + if (DynamicStatusAdditionBorder.Child is CloseTicketDialog closeTicketDialog2) + { + if (closeTicketDialog2.SelectedErrorType == null || closeTicketDialog2.SelectedErrorType is ComboBoxItem b && b.Tag == null) + { + closeTicketDialog2.UpdateErrorTypeValidationState(true); + if (!_errors.ContainsKey(propertyName)) + _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorTypeEmpty")); + } + else + { + closeTicketDialog2.UpdateErrorTypeValidationState(false); + if (_errors.ContainsKey(propertyName)) + _errors.Remove(propertyName); + } + } + break; + + case ValidationPropertyNames.SelectedRoleAndPerson: + if (DynamicStatusAdditionBorder.Child is ForwardTicketDialog forwardTicketDialog) + { + bool hasError = (forwardTicketDialog.SelectedPerson.Key == null || forwardTicketDialog.SelectedPerson.Value == null) && + (forwardTicketDialog.SelectedRole.Key == null || forwardTicketDialog.SelectedRole.Value == null); + + forwardTicketDialog.UpdateResponsibleSelectionValidationState(hasError); + + if (hasError) + { + if (!_errors.ContainsKey(propertyName)) + _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorRoleAndPersonEmpty")); + } + else + { + if (_errors.ContainsKey(propertyName)) + _errors.Remove(propertyName); + } + } + break; + + case ValidationPropertyNames.ForwardComment: + if (DynamicStatusAdditionBorder.Child is ForwardTicketDialog forwardTicketDialog2) + { + if (string.IsNullOrEmpty(forwardTicketDialog2.Comment)) + { + setTextboxErrorState(forwardTicketDialog2.CommentTextbox, true); + if (!_errors.ContainsKey(propertyName)) + _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ForwardTicket.ValidationErrorCommentEmpty")); + } + else + { + setTextboxErrorState(forwardTicketDialog2.CommentTextbox, false); + if (_errors.ContainsKey(propertyName)) + _errors.Remove(propertyName); + } + } + break; + case ValidationPropertyNames.HoldComment: + if (DynamicStatusAdditionBorder.Child is HoldTicketDialog holdTicketDialog1) + { + if (string.IsNullOrEmpty(holdTicketDialog1.Comment)) + { + setTextboxErrorState(holdTicketDialog1.CommentTextBox, true); + if (!_errors.ContainsKey(propertyName)) + _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.HoldTicket.ValidationErrorCommentEmpty")); + } + else + { + setTextboxErrorState(holdTicketDialog1.CommentTextBox, false); + if (_errors.ContainsKey(propertyName)) + _errors.Remove(propertyName); + } + } + break; + + case ValidationPropertyNames.TicketStatusCombobox: + validateComboboxNotEmpty(TicketStatusCombobox); + if (!(TicketStatusCombobox.SelectedItem is ComboBoxItem a)) + break; + + enumTicketStatus currentTicketStatus = enumTicketStatus.Unknown; + if (TryGetSelectedTicketInfo(TicketInfoKeys.StatusId, out var statusIdString) && + Enum.TryParse(statusIdString, true, out enumTicketStatus parsedStatus)) + { + currentTicketStatus = parsedStatus; + } + + bool ticketActionHasError = TicketStatusCombobox.IsVisible && a.Tag == null; + if (!ticketActionHasError) + { + if (_errors.ContainsKey(propertyName)) + _errors.Remove(propertyName); + } + else if (!_errors.ContainsKey(propertyName)) + { + _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorTicketActionEmpty")); + } + UpdateTicketStatusValidationVisualState(ticketActionHasError); + + if (a.Tag == null) + { + ShowAssetWarningTicketAction = false; + break; + } + + enumCloseCaseTicketStatus? selectedStatus = null; + if (Enum.TryParse(a.Tag.ToString(), true, out enumCloseCaseTicketStatus parsedStatusAction)) + { + selectedStatus = parsedStatusAction; + } + + bool hasTicketActivity = TryGetSelectedTicketInfo(TicketInfoKeys.ActivityType, out var currentTicketActivityType) && + string.Equals(currentTicketActivityType, TicketInfoValues.ActivityTypeTicket, StringComparison.OrdinalIgnoreCase); + + if (selectedStatus.HasValue && selectedStatus != enumCloseCaseTicketStatus.Forward && selectedStatus != enumCloseCaseTicketStatus.Save && hasTicketActivity) + { + ShowAssetWarningTicketAction = true; + var binding = new Binding + { + Converter = _languageConverter, + ConverterParameter = "Dialog.CloseCase.ValidationErrorTicketToIncident" + }; + + WarningTicketAction.SetBinding(ToolTipProperty, binding); + } + else if (currentTicketStatus == enumTicketStatus.Closed) + { + ShowAssetWarningTicketAction = true; + var binding = new Binding + { + Converter = _languageConverter, + ConverterParameter = "Dialog.CloseCase.ValidationErrorTicketWillBeReopened" + }; + + WarningTicketAction.SetBinding(ToolTipProperty, binding); + } + else + { + ShowAssetWarningTicketAction = false; + } + + break; + case ValidationPropertyNames.SelectedCategory: + bool categoryIsVisible = CategorySelectionControl?.IsVisible ?? false; + bool categoryHasError = categoryIsVisible && SelectedCategory == null; + UpdateCategoryValidationVisualState(categoryHasError); + + if (categoryHasError) + { + if (!_errors.ContainsKey(propertyName)) + _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorCategoryEmpty")); + } + else + { + if (_errors.ContainsKey(propertyName)) + _errors.Remove(propertyName); + } + + break; + case ValidationPropertyNames.QuickTicketSelection: + bool quickCallIsVisible = QuickTicketSelection?.IsVisible ?? false; + bool quickCallSelected = QuickTicketSelection?.SelectedItem is QuickCallEntry selectedQuickCall && !string.IsNullOrWhiteSpace(selectedQuickCall.ID); + bool quickCallHasError = quickCallIsVisible && !quickCallSelected; + UpdateQuickTicketValidationVisualState(quickCallHasError); + + if (quickCallHasError) + { + if (!_errors.ContainsKey(propertyName)) + _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorQuickCallEmpty")); + } + else + { + if (_errors.ContainsKey(propertyName)) + _errors.Remove(propertyName); + } + + break; + } + + return new List(_errors.Values); + } + + + private void ValidateProperty(string propertyName) + { + var errors = GetErrors(propertyName); + if (errors != null && errors.Count > 0) + { + // Speichern-Button deaktivieren + if (Window.GetWindow(this) is TicketCompletion msgBox) + { + this.parentWindow = msgBox; + this.parentWindow.SetButtonStateYes(false, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorsList") + "\r\n• " + string.Join("\r\n• ", errors)); + } + } + else + { + // Speichern-Button aktivieren + Window parentWindow = Window.GetWindow(this); + + if (parentWindow is TicketCompletion _msgBox) + { + this.parentWindow = _msgBox; + this.parentWindow.SetButtonStateYes(true, ""); + } + } + } + + #region TicketRelation_Click + + private void TicketRelation_Click(object sender) + { + try + { + if (!(sender is FrameworkElement senderElement)) + return; + + if (!(senderElement.Tag is cF4sdApiSearchResultRelation selectedSearchResult)) + return; + + SelectedTicket = selectedSearchResult; + UpdateSelectedTicketControl(); + TicketSelectionPopUp.IsOpen = false; + } + catch (Exception E) + { + LogException(E); + } + } + + private void TicketRelation_TouchDown(object sender, TouchEventArgs e) + { + TicketRelation_Click(sender); + } + + private void TicketRelation_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) + { + TicketRelation_Click(sender); + } + + #endregion + + #region EditCaseNotesButton_Click + + private void EditCaseNotesButton_Click() + { + try + { + if (SupportNotepad == false) + { + return; + } + + + TicketNotepadChanged?.Invoke(this, true); + + //TODO + //var notepad = new Notepad(true, DataProvider.caseNotes) { DataProvider = DataProvider }; + //openedWindows.Add(Window.GetWindow(notepad)); + } + catch (Exception E) + { + LogException(E); + } + + } + + private void EditCaseNotesButton_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) + { + EditCaseNotesButton_Click(); + + if (!string.IsNullOrWhiteSpace(CaseNotesPreview.Text)) + { + CaseNotesPreviewBorder.BorderBrush = (SolidColorBrush)new BrushConverter().ConvertFromString("#DEE2E6"); + ValidateProperty(ValidationPropertyNames.CaseNotesPreview); + } + else + { + CaseNotesPreviewBorder.BorderBrush = SharedValidationBorderBrush; + } + } + + private void EditCaseNotesButton_TouchDown(object sender, TouchEventArgs e) + { + EditCaseNotesButton_Click(); + } + + #endregion + + private void TicketStatusCombobox_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + + if (DynamicStatusAdditionBorder is null) + return; + + if (!(sender is ComboBox comboBox)) + return; + + // Die Werte aus 'errors' entfernen + Array.ForEach( + new[] + { + ValidationPropertyNames.SolutionTextbox, + ValidationPropertyNames.ErrorTypeValue, + ValidationPropertyNames.ReminderDate, + ValidationPropertyNames.SelectedRoleAndPerson, + ValidationPropertyNames.ForwardComment, + ValidationPropertyNames.HoldComment + }, + key => _errors.Remove(key)); + ValidateProperty(ValidationPropertyNames.TicketStatusCombobox); + + if (!(comboBox.SelectedItem is ComboBoxItem selectedItem)) + return; + if (!(Enum.TryParse(selectedItem.Tag?.ToString(), out enumCloseCaseTicketStatus closeCaseTicketStatus))) + { + DynamicStatusAdditionBorder.Visibility = Visibility.Collapsed; + return; + } + + FrameworkElement dynamicStatusChild = null; + switch (closeCaseTicketStatus) + { + case enumCloseCaseTicketStatus.Close: + var dialog = new CloseTicketDialog() { DataProvider = DataProvider }; + dialog.ErrorTypeValueChanged += Dialog_ErrorTypeValueChanged; + dialog.SolutionValueChanged += SolutionTextboxValueChanged; + var _h = Dispatcher.BeginInvoke((Action)(() => + { + if (dialog.IsLoaded) + { + ValidateProperty(ValidationPropertyNames.SolutionTextbox); + ValidateProperty(ValidationPropertyNames.ErrorTypeValue); + } + }), System.Windows.Threading.DispatcherPriority.Loaded); + + + dynamicStatusChild = dialog; + break; + case enumCloseCaseTicketStatus.OnHold: + var holdTicketDialog = new HoldTicketDialog(DataProvider = DataProvider); + dynamicStatusChild = holdTicketDialog; + holdTicketDialog.SelectedReminderDateChanged += ReminderDateValueChanged; + holdTicketDialog.CommentChanged += HoldCommentChanged; + _h = Dispatcher.BeginInvoke((Action)(() => + { + if (holdTicketDialog.IsLoaded) + { + ValidateProperty(ValidationPropertyNames.ReminderDate); + ValidateProperty(ValidationPropertyNames.HoldComment); + } + }), System.Windows.Threading.DispatcherPriority.Loaded); + break; + case enumCloseCaseTicketStatus.Forward: + var forwardTicketDialog = new ForwardTicketDialog(DataProvider); + dynamicStatusChild = forwardTicketDialog; + forwardTicketDialog.SelectedPersonChanged += SelectedPersonChanged; + forwardTicketDialog.SelectedRoleChanged += SelectedRoleChanged; + forwardTicketDialog.CommentChanged += ForwardCommentChanged; + _h = Dispatcher.BeginInvoke((Action)(() => + { + if (forwardTicketDialog.IsLoaded) + { + ValidateProperty(ValidationPropertyNames.SelectedRoleAndPerson); + ValidateProperty(ValidationPropertyNames.ForwardComment); + } + }), System.Windows.Threading.DispatcherPriority.Loaded); + break; + case enumCloseCaseTicketStatus.Save: + break; + } + if (dynamicStatusChild != null) + { + DynamicStatusAdditionBorder.Visibility = Visibility.Visible; + DynamicStatusAdditionBorder.Child = dynamicStatusChild; + } + else + DynamicStatusAdditionBorder.Visibility = Visibility.Collapsed; + this.VerticalAlignment = VerticalAlignment.Center; + } + private void ForwardCommentChanged(object sender, EventArgs e) + { + ValidateProperty(ValidationPropertyNames.ForwardComment); + } + private void HoldCommentChanged(object sender, EventArgs e) + { + ValidateProperty(ValidationPropertyNames.HoldComment); + } + private void SelectedRoleChanged(object sender, EventArgs e) + { + ValidateProperty(ValidationPropertyNames.SelectedRoleAndPerson); + } + + private void SelectedPersonChanged(object sender, EventArgs e) + { + ValidateProperty(ValidationPropertyNames.SelectedRoleAndPerson); + } + + private void ReminderDateValueChanged(object sender, EventArgs e) + { + ValidateProperty(ValidationPropertyNames.ReminderDate); + } + private void SolutionTextboxValueChanged(object sender, EventArgs e) + { + ValidateProperty(ValidationPropertyNames.SolutionTextbox); + } + + private void Dialog_ErrorTypeValueChanged(object sender, EventArgs e) + { + ValidateProperty(ValidationPropertyNames.ErrorTypeValue); + } + + private static void validateComboboxNotEmpty(object sender) + { + //var comboBox = sender as ComboBox; + //if (comboBox != null) + //{ + // if (!(comboBox.SelectedItem is ComboBoxItem selectedItem)) + // return; + + + + // // Überprüfe den Inhalt und setze die Hintergrundfarbe entsprechend + // if (selectedItem.Tag == null) + // { + // // Setze die Hintergrundfarbe auf Rot, um einen Validierungsfehler anzuzeigen + // comboBox.BorderBrush = SharedValidationBorderBrush; + // } + // else + // { + // // Setze die ursprüngliche Hintergrundfarbe zurück, wenn die Validierung erfolgreich ist + // comboBox.BorderBrush = (SolidColorBrush)new BrushConverter().ConvertFromString("#DEE2E6"); + // } + //} + } + + private void TicketSelectionBorder_Click() + { + var _h = Dispatcher.Invoke(async () => + { + await Task.Delay(50); + + if (!TicketSelectionPopUp.IsOpen) + DropDownOpened(TicketSelectionBorder, EventArgs.Empty); + + TicketSelectionPopUp.IsOpen = !TicketSelectionPopUp.IsOpen; + }); + } + + private void TicketSelectionBorder_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) + { + TicketSelectionBorder_Click(); + } + + private void TicketSelectionBorder_TouchDown(object sender, TouchEventArgs e) + { + TicketSelectionBorder_Click(); + } + + private void TicketSummaryTextBox_TextChanged(object sender, TextChangedEventArgs e) + { + try + { + if (SelectedTicket?.Infos is null) + return; + + SelectedTicket.Infos[TicketInfoKeys.Summary] = TicketSummaryTextBox.Text; + ValidateProperty(ValidationPropertyNames.TicketSummaryTextBox); + } + catch (Exception E) + { + LogException(E); + } + + } + + private void TicketCaseNotesTextBlock_TextChanged(object sender, EventArgs e) + { + try + { + if (SelectedTicket?.Infos is null) + return; + + if (string.IsNullOrWhiteSpace(CaseNotesPreview.Text)) + CaseNotesPreview.Text = string.Empty; + + SelectedTicket.Infos[TicketInfoKeys.Summary] = CaseNotesPreview.Text; + ValidateProperty(ValidationPropertyNames.CaseNotesPreview); + } + catch (Exception E) + { + LogException(E); + } + } + + private static void validateTextboxNotEmpty(object sender) + { + if (sender is TextBox textBox) + { + // Text aus der TextBox holen + string text = textBox.Text; + + // Überprüfe den Inhalt und setze die Hintergrundfarbe entsprechend + if (string.IsNullOrWhiteSpace(text)) + { + // Setze die Hintergrundfarbe auf Rot, um einen Validierungsfehler anzuzeigen + textBox.BorderBrush = SharedValidationBorderBrush; + } + else + { + // Setze die ursprüngliche Hintergrundfarbe zurück, wenn die Validierung erfolgreich ist + textBox.BorderBrush = (SolidColorBrush)new BrushConverter().ConvertFromString("#DEE2E6"); + } + } + } + + + private bool CheckTextBlockNotEmpty(TextBlock _textBlock, bool notEmpty) + { + var _retVal = false; + Brush _borderCaseNores = DefaultTextBoxBorderBrush; + if (notEmpty && string.IsNullOrWhiteSpace(_textBlock.Text)) + { + _retVal = true; + _borderCaseNores = SharedValidationBorderBrush; + } + CaseNotesPreviewBorder.BorderBrush = _borderCaseNores; + return _retVal; + } + + + private static void setTextboxErrorState(object sender, bool hasError) + { + var textBox = sender as TextBox; + if (textBox == null) + return; + + textBox.BorderBrush = hasError + ? SharedValidationBorderBrush + : DefaultTextBoxBorderBrush; + } + + private void UpdateCategoryValidationVisualState(bool hasError) => + UpdateValidationBorderState(CategoryValidationBorder, ref defaultCategoryBorderBrush, ref defaultCategoryBorderThickness, hasError); + + private void UpdateQuickTicketValidationVisualState(bool hasError) => + UpdateValidationBorderState(QuickTicketValidationBorder, ref defaultQuickTicketBorderBrush, ref defaultQuickTicketBorderThickness, hasError); + + private void UpdateTicketStatusValidationVisualState(bool hasError) => + UpdateValidationBorderState(TicketStatusValidationBorder, ref defaultTicketStatusBorderBrush, ref defaultTicketStatusBorderThickness, hasError); + + private void UpdateValidationBorderState(Border border, ref Brush defaultBrush, ref Thickness? defaultThickness, bool hasError) + { + if (border == null) + return; + + if (defaultBrush == null) + { + var borderBrush = border.BorderBrush; + defaultBrush = borderBrush != null ? borderBrush.CloneCurrentValue() : null; + } + + if (!defaultThickness.HasValue) + defaultThickness = border.BorderThickness; + + border.BorderBrush = hasError ? validationErrorBrush : defaultBrush; + border.BorderThickness = hasError ? new Thickness(1) : defaultThickness ?? new Thickness(0); + } + + + + #region DropDown + private static bool IsInsidePageable(FrameworkElement fe) => cUiElementHelper.GetFirstParentOfType(fe) != null; + + private void DropDownOpened(object sender, EventArgs e) + { + if (!(sender is FrameworkElement fe)) return; + if (IsInsidePageable(fe)) return; // ComboBoxPageable fired itself + + var parentBorder = cUiElementHelper.GetFirstParentOfType(fe); + if (parentBorder != null) + cFocusInvoker.InvokeGotFocus(parentBorder, e); + } + + private void DropDownClosed(object sender, EventArgs e) + { + if (!(sender is FrameworkElement fe)) return; + if (IsInsidePageable(fe)) return; + + var parentBorder = cUiElementHelper.GetFirstParentOfType(fe); + if (parentBorder != null) + cFocusInvoker.InvokeLostFocus(parentBorder, e); + + DynamicStatusAdditionBorder?.Focus(); + } + + #endregion + + private void TicketSelectionPopUp_Closed(object sender, EventArgs e) + { + DropDownClosed(TicketSelectionBorder, e); + } + + private void TransferCaseNotesCheck_Checked(object sender, RoutedEventArgs e) + { + try + { + CaseNotesPreview?.ClearValue(OpacityProperty); + CaseNotesPreviewBorder?.ClearValue(IsHitTestVisibleProperty); + } + catch (Exception E) + { + LogException(E); + } + + } + private void ComputerSelection_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + SelectedComputer = (cF4sdApiSearchResultRelation)ComputerSelection.SelectedItem; + } + + private void QuickTicketSelection_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + ValidateProperty(ValidationPropertyNames.QuickTicketSelection); + } + + private void TransferCaseNotesCheck_Unchecked(object sender, RoutedEventArgs e) + { + try + { + if (CaseNotesPreview != null) + CaseNotesPreview.Opacity = 0.7; + + if (CaseNotesPreviewBorder != null) + CaseNotesPreviewBorder.IsHitTestVisible = false; + } + catch (Exception E) + { + LogException(E); + } + + } + + private void CloseCaseDialogUc_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) + { + try + { + if (!(e.NewValue is bool isVisible && !isVisible)) + return; + + foreach (Window window in _openedWindows) + { + if (window is null) + continue; + + window.Close(); + } + } + catch (Exception E) + { + LogException(E); + } + + } + + private void Combobox_PreviewKeyDown(object sender, KeyEventArgs e) + { + if (e.Key == Key.Escape) + { + if (sender is FrameworkElement fe && IsInsidePageable(fe)) return; + DropDownClosed(sender, e); + } + } + } +} diff --git a/FasdDesktopUi/Basics/UserControls/Ticket/CloseCaseDialogWithTicket.xaml.cs b/FasdDesktopUi/Basics/UserControls/Ticket/CloseCaseDialogWithTicket.xaml.cs index feb750b..bee7782 100644 --- a/FasdDesktopUi/Basics/UserControls/Ticket/CloseCaseDialogWithTicket.xaml.cs +++ b/FasdDesktopUi/Basics/UserControls/Ticket/CloseCaseDialogWithTicket.xaml.cs @@ -1911,7 +1911,7 @@ namespace FasdDesktopUi.Basics.UserControls ResponsibleRole = selectedRole, ResponsiblePerson = selectedPerson, Comment = comment, - QuickActionHistory = TransferQuickActionHistoryCheck.IsChecked ?? false ? F4SDProtocoll.Instance.GetOfType().Select(e => e.GetResult()).ToList() : null, + SupportCaseProtocollEntries = TransferQuickActionHistoryCheck.IsChecked ?? false ? F4SDProtocoll.Instance.GetAll().ToList() : null, workTimes = workingTimes, StatusIdValue = statusIdValue, CaseId = DataProvider.CaseId diff --git a/FasdDesktopUi/Basics/UserControls/TicketOverview.xaml.cs b/FasdDesktopUi/Basics/UserControls/TicketOverview.xaml.cs index 6a771fc..5d0d0ce 100644 --- a/FasdDesktopUi/Basics/UserControls/TicketOverview.xaml.cs +++ b/FasdDesktopUi/Basics/UserControls/TicketOverview.xaml.cs @@ -10,6 +10,7 @@ using System.Windows.Threading; using C4IT.FASD.Cockpit.Communication; using FasdDesktopUi.Basics.Models; +using FasdDesktopUi.Basics.Services; using FasdDesktopUi.Basics.Services.Models; using FasdDesktopUi.Pages.SearchPage; namespace FasdDesktopUi.Basics.UserControls @@ -217,36 +218,33 @@ namespace FasdDesktopUi.Basics.UserControls private async Task RefreshCountsAsync(bool useRoleTickets) { - var communication = cFasdCockpitCommunicationBase.Instance; + Dictionary counts = null; + var service = TicketOverviewUpdateService.Instance; - var counts = CategorySetters.ToDictionary(item => item.Key, _ => 0); - - if (communication != null) + if (service != null) { - var tasks = CategorySetters.ToDictionary( - item => item.Key, - item => communication.GetTicketOverviewRelations(item.Key, useRoleTickets, 0)); - - foreach (var kvp in tasks) + try { - try - { - var relations = await kvp.Value.ConfigureAwait(false); - counts[kvp.Key] = relations?.Count ?? 0; - } - catch (Exception ex) - { - Debug.WriteLine($"[TicketOverview] Failed to load count for '{kvp.Key}': {ex}"); - counts[kvp.Key] = 0; - } + var scope = useRoleTickets ? TileScope.Role : TileScope.Personal; + await service.FetchAsync(scope).ConfigureAwait(false); + counts = service.GetCountsForScope(useRoleTickets); + } + catch (Exception ex) + { + Debug.WriteLine($"[TicketOverview] Service refresh failed: {ex}"); + counts = null; } } + if (counts == null || counts.Count == 0) + counts = await LoadCountsFallbackAsync(useRoleTickets).ConfigureAwait(false); + await Dispatcher.InvokeAsync(() => { foreach (var (key, setter) in CategorySetters) { - setter(_viewModel, counts[key]); + counts.TryGetValue(key, out var value); + setter(_viewModel, value); } _viewModel.ResetSelection(); @@ -255,6 +253,34 @@ namespace FasdDesktopUi.Basics.UserControls }, DispatcherPriority.Background); } + private async Task> LoadCountsFallbackAsync(bool useRoleTickets) + { + var counts = CategorySetters.ToDictionary(item => item.Key, _ => 0); + var communication = cFasdCockpitCommunicationBase.Instance; + if (communication == null) + return counts; + + var tasks = CategorySetters.ToDictionary( + item => item.Key, + item => communication.GetTicketOverviewRelations(item.Key, useRoleTickets, 0)); + + foreach (var kvp in tasks) + { + try + { + var relations = await kvp.Value.ConfigureAwait(false); + counts[kvp.Key] = relations?.Count ?? 0; + } + catch (Exception ex) + { + Debug.WriteLine($"[TicketOverview] Fallback load failed for '{kvp.Key}': {ex}"); + counts[kvp.Key] = 0; + } + } + + return counts; + } + public void UpdateCounts(IDictionary counts, bool useRoleTickets) { if (counts == null) @@ -272,6 +298,16 @@ namespace FasdDesktopUi.Basics.UserControls }, DispatcherPriority.Background); } + public void ClearHighlightsForScope(TileScope scope) + { + var highlightStates = scope == TileScope.Role ? _roleHighlightStates : _personalHighlightStates; + if (highlightStates.Count == 0) + return; + + highlightStates.Clear(); + UpdateHighlightState(scope == TileScope.Role); + } + public void SetHighlights(IEnumerable changes, bool useRoleTickets) { if (changes != null) diff --git a/FasdDesktopUi/Basics/cUtility.cs b/FasdDesktopUi/Basics/cUtility.cs index 6df7766..2252060 100644 --- a/FasdDesktopUi/Basics/cUtility.cs +++ b/FasdDesktopUi/Basics/cUtility.cs @@ -26,55 +26,6 @@ namespace FasdDesktopUi.Basics { public static readonly IRawValueFormatter RawValueFormatter = new RawValueFormatter(); - internal static RawValueType GetRawValueType(enumHealthCardDisplayTypes displayType) - { - switch (displayType) - { - case enumHealthCardDisplayTypes.STRING: - return RawValueType.STRING; - case enumHealthCardDisplayTypes.INTEGER: - return RawValueType.INTEGER; - case enumHealthCardDisplayTypes.PERCENT: - return RawValueType.PERCENT; - case enumHealthCardDisplayTypes.PERCENT100: - return RawValueType.PERCENT100; - case enumHealthCardDisplayTypes.PERCENT1000: - return RawValueType.PERCENT1000; - case enumHealthCardDisplayTypes.TIME: - return RawValueType.TIME; - case enumHealthCardDisplayTypes.DATE: - return RawValueType.DATE; - case enumHealthCardDisplayTypes.DATE_CALC: - return RawValueType.DATE_CALC; - case enumHealthCardDisplayTypes.DATETIME: - return RawValueType.DATETIME; - case enumHealthCardDisplayTypes.DURATION_DAY: - return RawValueType.DURATION_DAY; - case enumHealthCardDisplayTypes.DURATION_HOUR: - return RawValueType.DURATION_HOUR; - case enumHealthCardDisplayTypes.DURATION_MINUTE: - return RawValueType.DURATION_MINUTE; - case enumHealthCardDisplayTypes.DURATION_SECOND: - return RawValueType.DURATION_SECOND; - case enumHealthCardDisplayTypes.DURATION_MILLI: - return RawValueType.DURATION_MILLI; - case enumHealthCardDisplayTypes.DURATION_MICRO: - return RawValueType.DURATION_MICRO; - case enumHealthCardDisplayTypes.DURATION_DAY_SINCE_NOW: - return RawValueType.DURATION_DAY_SINCE_NOW; - case enumHealthCardDisplayTypes.BITS_PERSECOND: - return RawValueType.BITS_PERSECOND; - case enumHealthCardDisplayTypes.BYTES: - return RawValueType.BYTES; - case enumHealthCardDisplayTypes.HERTZ: - return RawValueType.HERTZ; - case enumHealthCardDisplayTypes.MEGA_HERTZ: - return RawValueType.MEGA_HERTZ; - default: - return RawValueType.STRING; - } - } - public static int SmoothedInt(int oldValue, int newValue) { if (oldValue < newValue) @@ -410,24 +361,25 @@ namespace FasdDesktopUi.Basics { try { - FormattingOptions options = new FormattingOptions() { ReferenceDate = DateTime.UtcNow.AddDays(_v.ReferenceDays) }; - + FormattingOptions options = new FormattingOptions() { ReferenceDate = DateTime.UtcNow.AddDays(_v.ReferenceDays), TimeZone = TimeZoneInfo.Local }; RawValueFormatter.SetDefaultCulture(new System.Globalization.CultureInfo(cFasdCockpitConfig.Instance.SelectedLanguage)); - var _strVal = RawValueFormatter.GetDisplayValue(_v.Value, GetRawValueType(_v.StateDefinition.DisplayType), options); + RawValueFormatter.SetDefaultTimeZone(TimeZoneInfo.Local); + + var _strVal = RawValueFormatter.GetDisplayValue(_v.Value, _v.StateDefinition.DisplayType, options); _t.rawValue.Text = _strVal; if (_v.StateDefinition is cHealthCardStateLevel _sl) { - _strVal = RawValueFormatter.GetDisplayValue(_sl.Warning, GetRawValueType(_v.StateDefinition.DisplayType), options); + _strVal = RawValueFormatter.GetDisplayValue(_sl.Warning, _v.StateDefinition.DisplayType, options); _t.tresholdWarning.Text = _strVal; - _strVal = RawValueFormatter.GetDisplayValue(_sl.Error, GetRawValueType(_v.StateDefinition.DisplayType), options); + _strVal = RawValueFormatter.GetDisplayValue(_sl.Error, _v.StateDefinition.DisplayType, options); _t.tresholdError.Text = _strVal; } else if (_v.StateDefinition is cHealthCardStateVersion _sv) { - _strVal = RawValueFormatter.GetDisplayValue(_sv.Warning, GetRawValueType(_v.StateDefinition.DisplayType), options); + _strVal = RawValueFormatter.GetDisplayValue(_sv.Warning, _v.StateDefinition.DisplayType, options); _t.tresholdWarning.Text = _strVal; - _strVal = RawValueFormatter.GetDisplayValue(_sv.Error, GetRawValueType(_v.StateDefinition.DisplayType), options); + _strVal = RawValueFormatter.GetDisplayValue(_sv.Error, _v.StateDefinition.DisplayType, options); _t.tresholdError.Text = _strVal; } else if (_v.StateDefinition is cHealthCardStateDateTime _sd) diff --git a/FasdDesktopUi/Config/LanguageDefinitions.xml b/FasdDesktopUi/Config/LanguageDefinitions.xml index cdf502c..4056781 100644 --- a/FasdDesktopUi/Config/LanguageDefinitions.xml +++ b/FasdDesktopUi/Config/LanguageDefinitions.xml @@ -71,6 +71,11 @@ Als angedocktes Fenster anzeigen + + Show raw values of healthcard + Rohwerte der Healthcard anzeigen + + Uhr @@ -96,7 +101,35 @@ Nicht erneut anzeigen - + + All + Alle + + + Main Information + + + F4SD Agent + + + Nexthink NXQL + + + Active Directory + + + Azure AD + + + Matrix42 WPM + + + MS Intune + + + Citrix + + The RSA encryption could not be initialised correctly. The cockpit will be closed. Die RSA Verschlüsselung konnte nicht korrekt initialisiert werden. Das Cockpit wird beendet. @@ -1355,10 +1388,10 @@ Kategorie - - Save - Speichern - + + Save + Speichern + Cancel @@ -1578,21 +1611,21 @@ Fehler: - - Fill summary - Zusammenfassung angeben - - - Select a category - Kategorie auswählen - - - Select a quickcall template - Quickcall auswählen - - - - Fill solution + + Fill summary + Zusammenfassung angeben + + + Select a category + Kategorie auswählen + + + Select a quickcall template + Quickcall auswählen + + + + Fill solution Lösung angeben diff --git a/FasdDesktopUi/F4SD-Cockpit-Client.csproj b/FasdDesktopUi/F4SD-Cockpit-Client.csproj index 06dfab3..7933e7b 100644 --- a/FasdDesktopUi/F4SD-Cockpit-Client.csproj +++ b/FasdDesktopUi/F4SD-Cockpit-Client.csproj @@ -91,32 +91,58 @@ prompt - - ..\packages\C4IT.F4SD.DisplayFormatting.0.0.1-preview-0.0.2\lib\netstandard2.0\C4IT.F4SD.DisplayFormatting.dll + + ..\packages\C4IT.F4SD.DisplayFormatting.1.0.0\lib\netstandard2.0\C4IT.F4SD.DisplayFormatting.dll + + + ..\packages\C4IT.F4SD.SupportCaseProtocoll.1.0.0\lib\netstandard2.0\C4IT.F4SD.SupportCaseProtocoll.dll ..\packages\MaterialIcons.1.0.3\lib\MaterialIcons.dll - - ..\packages\Microsoft.Extensions.Logging.Abstractions.3.1.32\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll + + ..\packages\Microsoft.Bcl.AsyncInterfaces.10.0.2\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll - - - ..\packages\Microsoft.Web.WebView2.1.0.3240.44\lib\net462\Microsoft.Web.WebView2.Core.dll + + ..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.10.0.2\lib\net462\Microsoft.Extensions.DependencyInjection.Abstractions.dll - - ..\packages\Microsoft.Web.WebView2.1.0.3240.44\lib\net462\Microsoft.Web.WebView2.WinForms.dll + + ..\packages\Microsoft.Extensions.Logging.Abstractions.10.0.2\lib\net462\Microsoft.Extensions.Logging.Abstractions.dll - - ..\packages\Microsoft.Web.WebView2.1.0.3240.44\lib\net462\Microsoft.Web.WebView2.Wpf.dll + + ..\packages\Microsoft.Web.WebView2.1.0.3650.58\lib\net462\Microsoft.Web.WebView2.Core.dll + + + ..\packages\Microsoft.Web.WebView2.1.0.3650.58\lib\net462\Microsoft.Web.WebView2.WinForms.dll + + + ..\packages\Microsoft.Web.WebView2.1.0.3650.58\lib\net462\Microsoft.Web.WebView2.Wpf.dll - ..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + ..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll + + ..\packages\System.Buffers.4.6.1\lib\net462\System.Buffers.dll + + + ..\packages\System.Diagnostics.DiagnosticSource.10.0.2\lib\net462\System.Diagnostics.DiagnosticSource.dll + + + ..\packages\System.Memory.4.6.3\lib\net462\System.Memory.dll + + + ..\packages\System.Numerics.Vectors.4.6.1\lib\net462\System.Numerics.Vectors.dll + + + ..\packages\System.Runtime.CompilerServices.Unsafe.6.1.2\lib\net462\System.Runtime.CompilerServices.Unsafe.dll + + + ..\packages\System.Threading.Tasks.Extensions.4.6.3\lib\net462\System.Threading.Tasks.Extensions.dll + @@ -151,6 +177,9 @@ + + + @@ -173,18 +202,19 @@ - - - + + + + @@ -234,13 +264,18 @@ + - - BlurInvokerContainer.xaml - - - ComboBoxPageAble.xaml - + + Badge.xaml + + + BlurInvokerContainer.xaml + + + ComboBoxPageAble.xaml + + HierarchicalSelectionControl.xaml @@ -340,6 +375,12 @@ CustomMessageBox.xaml + + RawHealthCardValuesPage.xaml + + + SearchPageView.xaml + IntroView.xaml @@ -398,9 +439,6 @@ PhoneSettingsPage.xaml - - SearchPageView.xaml - M42SettingsPageView.xaml @@ -443,6 +481,10 @@ SlimPageWidgetCollection.xaml + + Designer + MSBuild:Compile + MSBuild:Compile Designer @@ -701,13 +743,17 @@ MSBuild:Compile Designer - + + Designer + MSBuild:Compile + + MSBuild:Compile Designer - - Designer + MSBuild:Compile + Designer Designer @@ -854,15 +900,6 @@ Code - - True - True - Resources.resx - - - ResXFileCodeGenerator - Resources.Designer.cs - Config\LanguageDefinitions.xsd Designer @@ -993,6 +1030,7 @@ + if $(ConfigurationName) == BuildToTeams powershell.exe -ExecutionPolicy remotesigned -file "$(SolutionDir)BuildToTeams.ps1" -DirectoryToZip "$(SolutionDir)\FasdDesktopUi\bin\Release" @@ -1008,11 +1046,11 @@ taskkill -im "F4SD-Cockpit-Client.exe" -f -FI "STATUS eq RUNNING" copy "$(ProjectDir)..\..\C4IT FASD\_Common\XmlSchemas\LanguageDefinitions.xsd" "$(ProjectDir)Config" - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + diff --git a/FasdDesktopUi/Pages/DetailsPage/DetailsPageView.xaml b/FasdDesktopUi/Pages/DetailsPage/DetailsPageView.xaml index 580f0f1..d585357 100644 --- a/FasdDesktopUi/Pages/DetailsPage/DetailsPageView.xaml +++ b/FasdDesktopUi/Pages/DetailsPage/DetailsPageView.xaml @@ -90,12 +90,11 @@ @@ -220,8 +219,7 @@ + WidgetGeometryList="{Binding WidgetGeometryList}" /> UpdateBlurStatus(obj); } - public override void SetSupportCase(ISupportCase supportCase) + internal override void SetSupportCaseController(SupportCaseController supportCaseController) { - if (_supportCase != null) - _supportCase.CaseRelationsAdded -= HandleCaseRelationsAdded; + if (_supportCaseController != null) + UnsubscribeEventsOf(_supportCaseController); - supportCase.CaseRelationsAdded += HandleCaseRelationsAdded; - base.SetSupportCase(supportCase); + ResetPageToDefaultState(); + SubscribeEventsOf(supportCaseController); + base.SetSupportCaseController(supportCaseController); + NavigationHeadingUc.SupportCaseController = supportCaseController; IsBlurred = true; - RefreshControl.DataProvider = supportCase.SupportCaseDataProviderArtifact; - NavigationHeadingUc.DataProvider = supportCase.SupportCaseDataProviderArtifact; + RefreshControl.DataProvider = supportCaseController.SupportCaseDataProviderArtifact; + NavigationHeadingUc.DataProvider = supportCaseController.SupportCaseDataProviderArtifact; cSupportCaseDataProvider.CaseChanged += DataProvider_CaseChanged; RefreshControl.IsDataIncomplete = true; RefreshControl.LoadingDataIndicatorUc.LoadingText = cMultiLanguageSupport.GetItem("DetailsPage.Loading"); CustomizableSectionUc.IsDataIncomplete = true; - supportCase.SupportCaseDataProviderArtifact.NotepadDocumentUpdated += ResetNotepadNotification; + supportCaseController.SupportCaseDataProviderArtifact.NotepadDocumentUpdated += ResetNotepadNotification; + + void SubscribeEventsOf(SupportCaseController controller) + { + controller.AvailableCaseRelationsAdded += HandleAvailableRelationsAdded; + controller.FocusedRelationsChanged += HandleFocusedRelationsChanged; + controller.CaseDataChanged += HandleCaseDataChanged; + controller.HeadingDataChanged += HandleHeadingDataChanged; + } + + void UnsubscribeEventsOf(SupportCaseController controller) + { + controller.AvailableCaseRelationsAdded -= HandleAvailableRelationsAdded; + controller.FocusedRelationsChanged -= HandleFocusedRelationsChanged; + controller.CaseDataChanged -= HandleCaseDataChanged; + controller.HeadingDataChanged -= HandleHeadingDataChanged; + } } - private async void HandleCaseRelationsAdded(object sender, RelationEventArgs e) + private void HandleAvailableRelationsAdded(object sender, RelationEventArgs e) { - await Dispatcher.Invoke(async () => + } + + private void HandleFocusedRelationsChanged(object sender, RelationEventArgs e) + { + IsBlurred = false; + _supportCaseController.SupportCaseDataProviderArtifact.Identities = e.Relations.FirstOrDefault()?.FirstOrDefault()?.Identities; // todo remove when ShowDetailedDataAction is not dependent on Artifact anymore + Dispatcher.Invoke(() => { - NavigationHeadingUc.HeadingData = _supportCase?.SupportCaseDataProviderArtifact.HealthCardDataHelper.GetHeadingDataWithoutOnlineStatus(); - NavigationHeadingUc.HeadingData = await _supportCase?.SupportCaseDataProviderArtifact.HealthCardDataHelper.UpdateOnlineStatusAsync(); + ResetPageToDefaultState(); + UpdateHealthcardSectionVisibilities(); + HandleCaseDataChanged(null, null); }); } + private void HandleHeadingDataChanged(object sender, HeadingDataEventArgs e) + { + Dispatcher.Invoke(() => NavigationHeadingUc.HeadingData = e.NewValue.ToList()); + } + + // todo update NavigationHeadingUc_HeadingIconClickedEvent as soon as EventArgs are taken into account + private void HandleCaseDataChanged(object sender, SupportCaseDataEventArgs e) + { + try + { + if (isDataChangedEventRunning) + { + shouldReRunDataChangedEvent = true; + return; + } + + isDataChangedEventRunning = true; + + Dispatcher.Invoke(() => + { + if (QuickActionDecorator.Child is DataCanvas dataCanvas) + Dispatcher.Invoke(async () => await dataCanvas.UpdateDataAsync()); + + if (WidgetCollection.WidgetDataList is null || WidgetCollection.WidgetDataList.Count == 0) + WidgetCollection.WidgetDataList = _supportCaseController?.GetWidgetData(); + + WidgetCollection.UpdateWidgetData(_supportCaseController?.GetWidgetData()); + + if (DataHistoryCollectionUserControl.HistoryDataList is null || DataHistoryCollectionUserControl.HistoryDataList.Count == 0) + DataHistoryCollectionUserControl.HistoryDataList = _supportCaseController?.GetHistoryData(); + + DataHistoryCollectionUserControl.UpdateHistory(_supportCaseController?.GetHistoryData()); + + if (CustomizableSectionUc.ContainerCollections is null || CustomizableSectionUc.ContainerCollections.Count == 0) + CustomizableSectionUc.ContainerCollections = _supportCaseController?.GetContainerData(); + + CustomizableSectionUc.UpdateContainerCollection(_supportCaseController?.GetContainerData()); + + if (this.DataContext is DetailsPageViewModel viewModel) + viewModel.MenuBarData = _supportCaseController?.GetMenuBarData(); + + if (_lastDesiredHeightOfWidgetCollection != WidgetCollection.DesiredSize.Height) + { + _lastDesiredHeightOfWidgetCollection = WidgetCollection.DesiredSize.Height; + MainGrid.InvalidateMeasure(); + MainGrid.UpdateLayout(); + } + }); + + if (shouldReRunDataChangedEvent) + HandleCaseDataChanged(sender, e); + } + finally + { + isDataChangedEventRunning = false; + shouldReRunDataChangedEvent = false; + } + } + + /// + /// Sets the visibility of History and Customizable Section based on the currently selected Healthcard. + /// + internal void UpdateHealthcardSectionVisibilities() + { + try + { + cHealthCard selectedHealthcard = _supportCaseController.SupportCaseDataProviderArtifact.HealthCardDataHelper.SelectedHealthCard; + bool showHistorySection = selectedHealthcard.CategoriesHistory?.StateCategories != null && selectedHealthcard.CategoriesHistory.StateCategories.Count > 0; + + Dispatcher.Invoke(() => + { + DataHistoryCollectionUserControl.Visibility = showHistorySection ? Visibility.Visible : Visibility.Collapsed; + CustomizableSectionUc.Visibility = showHistorySection ? Visibility.Collapsed : Visibility.Visible; + }); + } + catch (Exception ex) + { + LogException(ex); + } + } + private void ReinitializeNotepad() { if (SupportNotepad == true) { - notepad = new Notepad(_supportCase?.SupportCaseDataProviderArtifact); + notepad = new Notepad(_supportCaseController?.SupportCaseDataProviderArtifact); ChangeNotepadNotification(); NotepadDecorator.Child = notepad; NotepadDecorator.Visibility = Visibility.Collapsed; @@ -319,31 +426,34 @@ namespace FasdDesktopUi.Pages.DetailsPage { try { - Panel.SetZIndex(NavigationHeadingUc, 1); - NavigationHeadingUc.ResetSelectors(); - - if (cConnectionStatusHelper.Instance?.ApiConnectionStatus == cConnectionStatusHelper.enumOnlineStatus.online) + Dispatcher.Invoke(() => { - SearchBarUserControl.Visibility = Visibility.Collapsed; - SearchBarUserControl.Clear(); - MenuBarUserControl.Visibility = Visibility.Visible; - } + Panel.SetZIndex(NavigationHeadingUc, 1); + NavigationHeadingUc.ResetSelectors(); - SearchResultBorder.Visibility = Visibility.Collapsed; - - OverlayBorder.Child = null; - OverlayBorder.Visibility = Visibility.Collapsed; - - if (BlurInvokers?.Count > 0) - { - foreach (var blurInvoker in BlurInvokers.ToArray()) + if (cConnectionStatusHelper.Instance?.ApiConnectionStatus == cConnectionStatusHelper.enumOnlineStatus.online) { - if (blurInvoker is Window blurInvokerWindow) - blurInvokerWindow.Hide(); + SearchBarUserControl.Visibility = Visibility.Collapsed; + SearchBarUserControl.Clear(); + MenuBarUserControl.Visibility = Visibility.Visible; } - } - IsBlurred = BlurInvokers?.Count > 0; + SearchResultBorder.Visibility = Visibility.Collapsed; + + OverlayBorder.Child = null; + OverlayBorder.Visibility = Visibility.Collapsed; + + if (BlurInvokers?.Count > 0) + { + foreach (var blurInvoker in BlurInvokers.ToArray()) + { + if (blurInvoker is Window blurInvokerWindow) + blurInvokerWindow.Hide(); + } + } + + IsBlurred = BlurInvokers?.Count > 0; + }); } catch (Exception E) { @@ -450,21 +560,8 @@ namespace FasdDesktopUi.Pages.DetailsPage { try { - Dispatcher.Invoke(() => - { - NavigationHeadingUc.IsHitTestVisible = false; - NavigationHeadingUc.Opacity = 0.7; - }); - RefreshControl.IsDataIncomplete = true; - - List tasks = new List - { - _supportCase?.SupportCaseDataProviderArtifact?.HealthCardDataHelper?.UpdateOnlineStatusAsync(), - _supportCase?.SupportCaseDataProviderArtifact?.HealthCardDataHelper?.LoadingHelper?.RefreshLatestDataAsync() - }; - - await Task.WhenAll(tasks); + await _supportCaseController.RefreshDataForCurrentlyFocusedRelationAsync(); RefreshControl.UpdateLastDataRequestTime(); RefreshControl.IsDataIncomplete = false; } @@ -495,6 +592,7 @@ namespace FasdDesktopUi.Pages.DetailsPage { case cChangeHealthCardAction _: case cShowHeadingSelectionMenuAction _: + case UiShowRawHealthcardValues _: break; case cUiQuickAction _: case cShowRecommendationAction _: @@ -515,7 +613,7 @@ namespace FasdDesktopUi.Pages.DetailsPage break; } - await e.UiAction.RunUiActionAsync(e.OriginalSource, drawingArea, true, _supportCase?.SupportCaseDataProviderArtifact); + await e.UiAction.RunUiActionAsync(e.OriginalSource, drawingArea, true, _supportCaseController?.SupportCaseDataProviderArtifact); UpdateHistoryWidth(); } catch (Exception E) @@ -545,21 +643,13 @@ namespace FasdDesktopUi.Pages.DetailsPage { try { - if (isDataProviderLoading) - return; - if (!(sender is FrameworkElement senderElement)) return; - if (!(senderElement.Tag is enumFasdInformationClass informationClassTag)) + if (!(senderElement.Tag is cF4sdApiSearchResultRelation selectedRelation)) return; - if (_supportCase?.SupportCaseDataProviderArtifact is null || !_supportCase.SupportCaseDataProviderArtifact.Identities.Any(identity => identity.Class == informationClassTag)) - return; - - Mouse.OverrideCursor = Cursors.Wait; - - await _supportCase?.SupportCaseDataProviderArtifact.ChangeHealthCardAsync(informationClassTag); + _supportCaseController.UpdateFocusedCaseRelation(selectedRelation); } catch (Exception E) { @@ -654,7 +744,7 @@ namespace FasdDesktopUi.Pages.DetailsPage private void F4SDIcon_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { CustomMessageBox.CustomMessageBox.Show("1. Have you tried turning it off and on again?\n2. Are you sure it is plugged in?", "How to solve (almost) any computer problem", enumHealthCardStateLevel.Info, this); - _supportCase.SupportCaseDataProviderArtifact.HealthCardDataHelper.IsInEditMode = true; + _supportCaseController.SupportCaseDataProviderArtifact.HealthCardDataHelper.IsInEditMode = true; } #region CloseCaseWithTicketIcon_Click @@ -701,17 +791,14 @@ namespace FasdDesktopUi.Pages.DetailsPage { try { - if (!(e.NewValue is bool isVisible)) + if (!(e.NewValue is bool isVisible && isVisible)) return; - if (isVisible) - { - Show(); - Activate(); - Focus(); - if (IsWindowLoaded) - WindowState = WindowState.Maximized; - } + Show(); + Activate(); + Focus(); + if (IsWindowLoaded) + WindowState = WindowState.Maximized; } catch (Exception E) { @@ -936,7 +1023,7 @@ namespace FasdDesktopUi.Pages.DetailsPage LogMethodBegin(CM); try { - LogEntry($"DataChanged - DataProvider for Class: {_supportCase?.SupportCaseDataProviderArtifact.Identities[0].Class} - Id: {_supportCase?.SupportCaseDataProviderArtifact.Identities[0].Id}"); + LogEntry($"DataChanged - DataProvider for Class: {_supportCaseController?.SupportCaseDataProviderArtifact.Identities[0].Class} - Id: {_supportCaseController?.SupportCaseDataProviderArtifact.Identities[0].Id}"); if (isDataChangedEventRunning) { @@ -949,21 +1036,6 @@ namespace FasdDesktopUi.Pages.DetailsPage if (!(e is BooleanEventArgs booleanArg) || booleanArg.BooleanArg == false) isDataProviderLoading = true; - var data = _supportCase?.SupportCaseDataProviderArtifact.HealthCardDataHelper.DetailPage.GetDataWithoutHeading(); - await Dispatcher.Invoke(async () => - { - NavigationHeadingUc.HeadingData = _supportCase?.SupportCaseDataProviderArtifact.HealthCardDataHelper.GetHeadingDataWithoutOnlineStatus(); - NavigationHeadingUc.HeadingData = await _supportCase?.SupportCaseDataProviderArtifact.HealthCardDataHelper.UpdateOnlineStatusAsync(); - }); - Dispatcher.Invoke(() => { WidgetCollection.UpdateWidgetData(data.WidgetData); }); - Dispatcher.Invoke(() => DataHistoryCollectionUserControl.UpdateHistory(data.DataHistoryList)); - Dispatcher.Invoke(() => CustomizableSectionUc.UpdateContainerCollection(data.DataContainerCollectionList)); - - Dispatcher.Invoke(() => - { - if (DataContext is DetailsPageViewModel viewModel) - viewModel.SetPropertyValues(data); - }); Dispatcher.Invoke(UpdateHistoryWidth); @@ -1023,7 +1095,7 @@ namespace FasdDesktopUi.Pages.DetailsPage { Dispatcher.Invoke(() => { - bool hasDirectConnection = _supportCase?.SupportCaseDataProviderArtifact?.DirectConnectionHelper?.IsDirectConnectionActive ?? false; + bool hasDirectConnection = _supportCaseController?.SupportCaseDataProviderArtifact?.DirectConnectionHelper?.IsDirectConnectionActive ?? false; NavigationHeadingUc.HasDirectConnection = hasDirectConnection; if (hasDirectConnection) @@ -1295,7 +1367,7 @@ namespace FasdDesktopUi.Pages.DetailsPage private void ChangeNotepadNotification() { - FlowDocument document = _supportCase?.SupportCaseDataProviderArtifact.CaseNotes; + FlowDocument document = _supportCaseController?.SupportCaseDataProviderArtifact.CaseNotes; bool isFlowDocumentEmpty = !document.Blocks.Any(block => { if (block is Paragraph paragraph) @@ -1358,22 +1430,16 @@ namespace FasdDesktopUi.Pages.DetailsPage BlurBorder_Click(); MenuBarUserControl.Visibility = Visibility.Visible; SearchBarUserControl.Visibility = Visibility.Collapsed; - QuickActionSelectorUc.QuickActionList = null; QuickActionSelectorUc.Visibility = Visibility.Collapsed; QuickActionDecorator.Child.Visibility = Visibility.Collapsed; - NotepadDecorator.Visibility = Visibility.Collapsed; NotepadDecorator.Child = null; notepad = null; - isQuickActionDecoratorVisible = false; - isQuickActionSelectorVisible = false; - if (IsLoaded) ReinitializeNotepad(); - DataHistoryCollectionUserControl.ToggleVerticalCollapseDetails(true); UpdateHistoryWidth(); } @@ -1383,64 +1449,6 @@ namespace FasdDesktopUi.Pages.DetailsPage } } - public void SetPropertyValues(cDetailsPageData detailPageData) - { - var CM = MethodBase.GetCurrentMethod(); - LogMethodBegin(CM); - try - { - if (DataContext is DetailsPageViewModel viewModel) - { - viewModel.SetPropertyValues(detailPageData); - - NavigationHeadingUc.HeadingData = detailPageData.HeadingData; - - ResetPageToDefaultState(); - - if (detailPageData.DataHistoryList?.Count > 0) - { - CustomizableSectionUc.Visibility = Visibility.Collapsed; - DataHistoryCollectionUserControl.Visibility = Visibility.Visible; - DataHistoryCollectionUserControl.HistoryDataList = detailPageData.DataHistoryList; - DataHistoryCollectionUserControl.DataProvider = _supportCase?.SupportCaseDataProviderArtifact; - - QuickActionSelectorUc.IsLocked = cFasdCockpitConfig.Instance.IsHistoryQuickActionSelectorVisible; - - if (cFasdCockpitConfig.Instance.IsHistoryQuickActionSelectorVisible) - MoreButtonClickedAction(); - } - else if (detailPageData.DataContainerCollectionList?.Count > 0) - { - DataHistoryCollectionUserControl.Visibility = Visibility.Collapsed; - CustomizableSectionUc.Visibility = Visibility.Visible; - CustomizableSectionUc.ContainerCollections = detailPageData.DataContainerCollectionList; - - var ticketMenuData = detailPageData.MenuBarData.FirstOrDefault(menuData => menuData.MenuText == "Ticket"); - - if (ticketMenuData != null) - if (ticketMenuData is cMenuDataContainer containerMenuData) - { - QuickActionSelectorUc.QuickActionSelectorHeading = containerMenuData.MenuText; - QuickActionSelectorUc.QuickActionList = containerMenuData.SubMenuData; - } - - QuickActionSelectorUc.IsLocked = cFasdCockpitConfig.Instance.IsCustomizableQuickActionSelectorVisible; - - if (cFasdCockpitConfig.Instance.IsCustomizableQuickActionSelectorVisible) - QuickActionSelectorUc.Visibility = Visibility.Visible; - } - } - } - catch (Exception E) - { - LogException(E); - } - finally - { - LogMethodEnd(CM); - } - } - #endregion #region DataHistoryCollection @@ -1589,9 +1597,9 @@ namespace FasdDesktopUi.Pages.DetailsPage try { - midnightTimer.Stop(); + _midnightTimer.Stop(); - var from = _supportCase?.SupportCaseDataProviderArtifact?.HealthCardDataHelper?.LoadingHelper?.LastDataRequest; + var from = _supportCaseController?.SupportCaseDataProviderArtifact?.HealthCardDataHelper?.LoadingHelper?.LastDataRequest; if (from == null) { @@ -1618,7 +1626,7 @@ namespace FasdDesktopUi.Pages.DetailsPage } finally { - midnightTimer.Start(); + _midnightTimer.Start(); } diff --git a/FasdDesktopUi/Pages/DetailsPage/DetailsPageViewModel.cs b/FasdDesktopUi/Pages/DetailsPage/DetailsPageViewModel.cs index a1585df..4c6a9dc 100644 --- a/FasdDesktopUi/Pages/DetailsPage/DetailsPageViewModel.cs +++ b/FasdDesktopUi/Pages/DetailsPage/DetailsPageViewModel.cs @@ -1,19 +1,10 @@ using System; using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Diagnostics; using System.Linq; using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Input; -using System.Windows.Threading; - using FasdDesktopUi.Basics.Models; using FasdDesktopUi.Pages.DetailsPage.Models; using FasdDesktopUi.Basics; - using static C4IT.Logging.cLogManager; namespace FasdDesktopUi.Pages.DetailsPage.ViewModels @@ -48,56 +39,6 @@ namespace FasdDesktopUi.Pages.DetailsPage.ViewModels #endregion - #region Header Properties - - #region PageTitle Property - - private string pageTitle; - public string PageTitle - { - get { return pageTitle; } - set - { - pageTitle = value; - OnPropertyChanged(); - } - } - - #endregion - - #region HeadingData Property - - private List headingData; - - public List HeadingData - { - get { return headingData; } - set - { - headingData = value; - OnPropertyChanged(); - } - } - - #endregion - - #endregion - - #region Widget Properties - - #region WidgetData Property - private List> widgetDataList; - public List> WidgetDataList - { - get { return widgetDataList; } - set - { - widgetDataList = value; - OnPropertyChanged(); - } - } - #endregion - #region WidgetGeometry Property private List widgetGeometryList; public List WidgetGeometryList @@ -112,8 +53,6 @@ namespace FasdDesktopUi.Pages.DetailsPage.ViewModels #endregion - #endregion - #region Details Properties #region TimeSinceLastRefresh property @@ -145,21 +84,6 @@ namespace FasdDesktopUi.Pages.DetailsPage.ViewModels #endregion - #region DetailsData property - - private cDetailsPageDataHistoryDataModel detailsDataList; - public cDetailsPageDataHistoryDataModel DetailsDataList - { - get { return detailsDataList; } - set - { - detailsDataList = value; - OnPropertyChanged(); - } - } - - #endregion - #region ShownValueColumnsCount public int ShownValueColumnsCount { @@ -245,39 +169,6 @@ namespace FasdDesktopUi.Pages.DetailsPage.ViewModels } } - public void SetPropertyValues(cDetailsPageData propertyValues) - { - var CM = MethodBase.GetCurrentMethod(); - LogMethodBegin(CM); - try - { - DataProvider = propertyValues.DataProvider; - - //Heading Properties - HeadingData = propertyValues.HeadingData; - - //Widget Properties - WidgetDataList = propertyValues.WidgetData; - - //Details Properties - TimeSinceLastRefresh = propertyValues.TimeSinceLastRefresh; - ShownValueColumnsCount = propertyValues.ShownValueColumnsCount; - DetailsDataList = propertyValues.DataHistoryList; - - //Menu Properties - MenuBarData = propertyValues.MenuBarData; - } - catch (Exception E) - { - LogEntry($"Passed history values: {propertyValues}"); - LogException(E); - } - finally - { - LogMethodEnd(CM); - } - } - #endregion #endregion diff --git a/FasdDesktopUi/Pages/DetailsPage/UserControls/DataHistory/DetailsPageDataHistoryCollection.xaml b/FasdDesktopUi/Pages/DetailsPage/UserControls/DataHistory/DetailsPageDataHistoryCollection.xaml index e577ed9..5153aec 100644 --- a/FasdDesktopUi/Pages/DetailsPage/UserControls/DataHistory/DetailsPageDataHistoryCollection.xaml +++ b/FasdDesktopUi/Pages/DetailsPage/UserControls/DataHistory/DetailsPageDataHistoryCollection.xaml @@ -4,7 +4,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:FasdDesktopUi.Pages.DetailsPage.UserControls" - xmlns:ico="clr-namespace:FasdDesktopUi.Basics.UserControls.AdaptableIcon" + xmlns:ico="clr-namespace:FasdDesktopUi.Basics.UserControls.AdaptableIcon;assembly=F4SD-AdaptableIcon" xmlns:config="clr-namespace:C4IT.FASD.Base;assembly=F4SD-Cockpit-Client-Base" xmlns:vc="clr-namespace:FasdDesktopUi.Basics.Converter" mc:Ignorable="d" diff --git a/FasdDesktopUi/Pages/DetailsPage/UserControls/DataHistory/DetailsPageDataHistoryCollection.xaml.cs b/FasdDesktopUi/Pages/DetailsPage/UserControls/DataHistory/DetailsPageDataHistoryCollection.xaml.cs index 5406dee..ed38b70 100644 --- a/FasdDesktopUi/Pages/DetailsPage/UserControls/DataHistory/DetailsPageDataHistoryCollection.xaml.cs +++ b/FasdDesktopUi/Pages/DetailsPage/UserControls/DataHistory/DetailsPageDataHistoryCollection.xaml.cs @@ -1,21 +1,15 @@ using System; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.ComponentModel; using System.Globalization; using System.Linq; using System.Reflection; -using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Threading; -using C4IT.Logging; -using C4IT.MultiLanguage; using FasdDesktopUi.Basics; using FasdDesktopUi.Basics.Enums; using FasdDesktopUi.Pages.DetailsPage.Models; @@ -509,7 +503,7 @@ namespace FasdDesktopUi.Pages.DetailsPage.UserControls default: subtitleStyle = titleColumnMainTitleStyle; break; - }; + } double subtitleLength = MeasureStringSize(subtitle.Content, new TextBox { Style = subtitleStyle }).Width; maxTitleLength = maxTitleLength < subtitleLength ? subtitleLength + 70 : maxTitleLength; diff --git a/FasdDesktopUi/Pages/DetailsPage/UserControls/DetailsPageNavigationHeading.xaml.cs b/FasdDesktopUi/Pages/DetailsPage/UserControls/DetailsPageNavigationHeading.xaml.cs index 2ebde4c..1094b8d 100644 --- a/FasdDesktopUi/Pages/DetailsPage/UserControls/DetailsPageNavigationHeading.xaml.cs +++ b/FasdDesktopUi/Pages/DetailsPage/UserControls/DetailsPageNavigationHeading.xaml.cs @@ -19,6 +19,7 @@ using C4IT.FASD.Base; using static C4IT.Logging.cLogManager; using C4IT.FASD.Cockpit.Communication; +using FasdDesktopUi.Basics.Services.SupportCase.Controllers; namespace FasdDesktopUi.Pages.DetailsPage.UserControls { @@ -41,6 +42,8 @@ namespace FasdDesktopUi.Pages.DetailsPage.UserControls } } + public SupportCaseController SupportCaseController { get; set; } + private List _highlightBorders; private void UpdateHeaderHighlights() @@ -457,6 +460,8 @@ namespace FasdDesktopUi.Pages.DetailsPage.UserControls if (headingIcon != null) { + headingIcon.Tag = heading.Realtion; + if (heading.IsOnline) { headingIcon.SetResourceReference(AdaptableIcon.PrimaryIconColorProperty, "Color.Green"); @@ -471,6 +476,7 @@ namespace FasdDesktopUi.Pages.DetailsPage.UserControls if (headingTextBlock != null && string.IsNullOrWhiteSpace(heading.HeadingText) is false) { + headingTextBlock.Tag = heading.Realtion; headingTextBlock.Text = heading.HeadingText; } @@ -632,7 +638,7 @@ namespace FasdDesktopUi.Pages.DetailsPage.UserControls var action = new cShowHeadingSelectionMenuAction(); ShowsRelations = true; cUiActionBase.RaiseEvent(new cShowHeadingSelectionMenuAction(), this, sender); - DoShowRelations(swapCaseData, location); + DoShowRelations(swapCaseData, location, SupportCaseController); //Dispatcher.Invoke(async () => await action.RunUiActionAsync(sender, location, false, DataProvider)); } catch (Exception E) @@ -642,7 +648,7 @@ namespace FasdDesktopUi.Pages.DetailsPage.UserControls } - private void DoShowRelations(cSwapCaseInfo swapCaseData, CustomMenu customMenu) + private void DoShowRelations(cSwapCaseInfo swapCaseData, CustomMenu customMenu, SupportCaseController supportCaseController) { var CM = MethodBase.GetCurrentMethod(); @@ -669,7 +675,7 @@ namespace FasdDesktopUi.Pages.DetailsPage.UserControls { IsMatchingRelation = isMatchingRelation, IsUsedForCaseEnrichment = true, - UiAction = new cChangeHealthCardAction(storedRelation) + UiAction = new cChangeHealthCardAction(storedRelation, supportCaseController) }); } } diff --git a/FasdDesktopUi/Pages/DetailsPage/UserControls/DetailsPageWidgetCollection.xaml b/FasdDesktopUi/Pages/DetailsPage/UserControls/DetailsPageWidgetCollection.xaml index 7ff928f..3f6d643 100644 --- a/FasdDesktopUi/Pages/DetailsPage/UserControls/DetailsPageWidgetCollection.xaml +++ b/FasdDesktopUi/Pages/DetailsPage/UserControls/DetailsPageWidgetCollection.xaml @@ -5,7 +5,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:FasdDesktopUi.Pages.DetailsPage.UserControls" xmlns:uc="clr-namespace:FasdDesktopUi.Pages.DetailsPage.UserControls" - xmlns:ico="clr-namespace:FasdDesktopUi.Basics.UserControls.AdaptableIcon" + xmlns:ico="clr-namespace:FasdDesktopUi.Basics.UserControls.AdaptableIcon;assembly=F4SD-AdaptableIcon" xmlns:config="clr-namespace:C4IT.FASD.Base;assembly=F4SD-Cockpit-Client-Base" x:Name="_this" mc:Ignorable="d" diff --git a/FasdDesktopUi/Pages/DetailsPage/UserControls/DetailsPageWindowStateBar.xaml b/FasdDesktopUi/Pages/DetailsPage/UserControls/DetailsPageWindowStateBar.xaml index 9927135..50ab9fc 100644 --- a/FasdDesktopUi/Pages/DetailsPage/UserControls/DetailsPageWindowStateBar.xaml +++ b/FasdDesktopUi/Pages/DetailsPage/UserControls/DetailsPageWindowStateBar.xaml @@ -10,7 +10,7 @@ d:DesignHeight="450" d:DesignWidth="800" d:Background="White" - DataContext="{Binding RelativeSource={RelativeSource Self}}"> + DataContext="{Binding RelativeSource={RelativeSource Self}}" Loaded="UserControl_Loaded"> @@ -50,6 +50,15 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/FasdDesktopUi/Pages/RawHealthCardValuesPage/RawHealthCardValuesPage.xaml.cs b/FasdDesktopUi/Pages/RawHealthCardValuesPage/RawHealthCardValuesPage.xaml.cs new file mode 100644 index 0000000..2be0bf3 --- /dev/null +++ b/FasdDesktopUi/Pages/RawHealthCardValuesPage/RawHealthCardValuesPage.xaml.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; + +using C4IT.FASD.Base; +using C4IT.MultiLanguage; + +namespace FasdDesktopUi.Pages.RawHealthCardValuesPage +{ + public partial class RawHealthCardValuesPage : Window + { + private enumDataHistoryOrigin originFilter = enumDataHistoryOrigin.Unknown; + + public RawHealthCardValuesPage() + { + InitializeComponent(); + } + + private void CloseButton_Click(object sender, InputEventArgs e) + { + Close(); + } + + private void MinimizeButton_Click(object sender, InputEventArgs e) + { + this.WindowState = WindowState.Minimized; + } + + private void WindowSizeButton_Click(object sender, InputEventArgs e) + { + this.WindowState = this.WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized; + } + + private void Window_Loaded(object sender, RoutedEventArgs e) + { + OriginFilterComboBox.Items.Clear(); + foreach (enumDataHistoryOrigin origin in Enum.GetValues(typeof(enumDataHistoryOrigin))) + { + string _name = cMultiLanguageSupport.GetItem("Global.Enumeration.DataHistoryOrigin." + origin.ToString()); + if (string.IsNullOrEmpty(_name)) + _name = origin.ToString(); + OriginFilterComboBox.Items.Add(new ComboBoxItem() { Content = _name, Tag = origin}); + } + OriginFilterComboBox.SelectedIndex = 0; + + } + + private void OriginFilterComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (OriginFilterComboBox.SelectedItem is ComboBoxItem selectedItem && selectedItem.Tag is enumDataHistoryOrigin selectedOrigin) + originFilter = selectedOrigin; + } + } +} diff --git a/FasdDesktopUi/Pages/SearchPage/SearchPageView.xaml b/FasdDesktopUi/Pages/SearchPage/SearchPageView.xaml index 6df916b..ca09a6b 100644 --- a/FasdDesktopUi/Pages/SearchPage/SearchPageView.xaml +++ b/FasdDesktopUi/Pages/SearchPage/SearchPageView.xaml @@ -75,13 +75,13 @@ - + @@ -107,16 +107,27 @@ Visibility="Visible" /> - - + + + + @@ -154,8 +165,11 @@ CornerRadius="10" VerticalAlignment="Bottom" Visibility="Collapsed"> + + x:FieldModifier="private" + PreviewMouseWheel="ResultMenu_PreviewMouseWheel"/> + diff --git a/FasdDesktopUi/Pages/SearchPage/SearchPageView.xaml.cs b/FasdDesktopUi/Pages/SearchPage/SearchPageView.xaml.cs index 3c6bc76..7b180e1 100644 --- a/FasdDesktopUi/Pages/SearchPage/SearchPageView.xaml.cs +++ b/FasdDesktopUi/Pages/SearchPage/SearchPageView.xaml.cs @@ -21,6 +21,7 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; using System.Windows; +using System.Windows.Controls; using System.Windows.Input; using System.Windows.Interop; using System.Windows.Media; @@ -32,9 +33,12 @@ namespace FasdDesktopUi.Pages.SearchPage { public partial class SearchPageView : Window, ISearchUiProvider { - private static SearchPageView _instance = null; - private const int WM_NCHITTEST = 0x0084; - private const int HTTRANSPARENT = -1; + private static SearchPageView _instance = null; + private const int WM_NCHITTEST = 0x0084; + private const int HTTRANSPARENT = -1; + private readonly HashSet _ticketOverviewNotificationScopesPrimed = new HashSet(); + private bool _ticketOverviewFirstEventHandled; + private readonly HashSet _ticketOverviewInitWasEmptyScopes = new HashSet(); public static SearchPageView Instance { get @@ -62,72 +66,155 @@ namespace FasdDesktopUi.Pages.SearchPage public SupportCaseSearchService SearchService { get; } = new SupportCaseSearchService(new RelationService()); - private SearchPageView() - { - try - { - InitializeComponent(); - Visibility = Visibility.Visible; - _instance = this; - - // FilterToggleCheckBox-Events registrieren - FilterCheckbox.Checked += (s, e) => FilterToggleCheckedChanged?.Invoke(this, true); - FilterCheckbox.Unchecked += (s, e) => FilterToggleCheckedChanged?.Invoke(this, false); - - Loaded += (s, e) => - { - Hide(); - SearchBarUc.ActivateManualSearch(); - }; - - AddCustomEventHandlers(); - - UiSettingsChanged(null, null); - - if (TicketOverviewUpdateService.Instance != null) - { - TicketOverviewUpdateService.Instance.Start(); - TicketOverviewUpdateService.Instance.OverviewCountsChanged += TicketOverviewUpdateService_OverviewCountsChanged; - } - } - catch (Exception E) - { - LogException(E); - } + private SearchPageView() + { + try + { + InitializeComponent(); + Visibility = Visibility.Visible; + _instance = this; + + GetPrimaryScreenSize(); + + // FilterToggleCheckBox-Events registrieren + FilterCheckbox.Checked += (s, e) => FilterToggleCheckedChanged?.Invoke(this, true); + FilterCheckbox.Unchecked += (s, e) => FilterToggleCheckedChanged?.Invoke(this, false); + + Loaded += (s, e) => + { + Hide(); + SearchBarUc.ActivateManualSearch(); + ScheduleSearchResultMaxHeightUpdate(); + }; + SizeChanged += (s, e) => ScheduleSearchResultMaxHeightUpdate(); + SearchBarUc.SizeChanged += (s, e) => ScheduleSearchResultMaxHeightUpdate(); + BodyStack_TicketOverview.SizeChanged += (s, e) => ScheduleSearchResultMaxHeightUpdate(); + SearchHistoryBorder.SizeChanged += (s, e) => ScheduleSearchResultMaxHeightUpdate(); + + AddCustomEventHandlers(); + + if (TicketOverviewUpdateService.Instance != null) + { + TicketOverviewUpdateService.Instance.OverviewCountsChanged += TicketOverviewUpdateService_OverviewCountsChanged; + } + + UiSettingsChanged(null, null); + } + catch (Exception E) + { + LogException(E); + } } - private void SetSearchResultVisibility(bool isVisible) - { - SearchResultBorder.Visibility = isVisible ? Visibility.Visible : Visibility.Collapsed; - BodyStack_SearchResults.Visibility = (isVisible || SearchResultBorder.IsVisible) ? Visibility.Visible : Visibility.Collapsed; - } + public void GetPrimaryScreenSize() + { + UpdateSearchResultMaxHeight(); + } + + private void ScheduleSearchResultMaxHeightUpdate() + { + if (Dispatcher == null || Dispatcher.HasShutdownStarted) + return; + + Dispatcher.BeginInvoke((Action)UpdateSearchResultMaxHeight, DispatcherPriority.Loaded); + } + + private void UpdateSearchResultMaxHeight() + { + if (SearchResultBorder == null) + return; + + var workAreaHeight = ActualHeight > 0 ? ActualHeight : SystemParameters.WorkArea.Height; + var reservedHeight = 0.0; + + reservedHeight += GetVisibleHeightWithMargin(SearchBarUc); + reservedHeight += GetVisibleHeightWithMargin(BodyStack_TicketOverview); + reservedHeight += GetVisibleHeightWithMargin(SearchHistoryBorder); + + if (MainBorder != null) + { + reservedHeight += MainBorder.Padding.Top + MainBorder.Padding.Bottom; + } + + var searchResultMargin = SearchResultBorder.Margin; + var availableHeight = workAreaHeight - reservedHeight - searchResultMargin.Top - searchResultMargin.Bottom; + availableHeight = Math.Max(0, availableHeight); + SearchResultBorder.MaxHeight = availableHeight; + } + + private static double GetVisibleHeightWithMargin(FrameworkElement element) + { + if (element == null || element.Visibility != Visibility.Visible) + return 0; + + var margin = element.Margin; + return element.ActualHeight + margin.Top + margin.Bottom; + } + + private void SetSearchResultVisibility(bool isVisible) + { + SearchResultBorder.Visibility = isVisible ? Visibility.Visible : Visibility.Collapsed; + BodyStack_SearchResults.Visibility = (isVisible || SearchResultBorder.IsVisible) ? Visibility.Visible : Visibility.Collapsed; + ScheduleSearchResultMaxHeightUpdate(); + } + + public void SetSearchHistoryVisibility(bool isVisible) + { + SearchHistoryBorder.Visibility = isVisible && !SearchHistory.IsEmpty() ? Visibility.Visible : Visibility.Collapsed; + BodyStack_SearchResults.Visibility = (isVisible || SearchResultBorder.IsVisible) ? Visibility.Visible : Visibility.Collapsed; + ScheduleSearchResultMaxHeightUpdate(); + } - public void SetSearchHistoryVisibility(bool isVisible) - { - SearchHistoryBorder.Visibility = isVisible && !SearchHistory.IsEmpty() ? Visibility.Visible : Visibility.Collapsed; - BodyStack_SearchResults.Visibility = (isVisible || SearchResultBorder.IsVisible) ? Visibility.Visible : Visibility.Collapsed; - } + private bool CheckTicketOverviewAvailability() + { + return cFasdCockpitConfig.Instance?.Global?.TicketConfiguration?.ShowOverview == true; + } + + private void UpdateTicketOverviewAvailability() + { + var enabled = CheckTicketOverviewAvailability(); + var service = TicketOverviewUpdateService.Instance; + service?.UpdateAvailability(enabled); + if (enabled) + _ = service?.FetchAsync(); + + if (!enabled) + { + if (Dispatcher.CheckAccess()) + { + ApplyTicketOverviewDisabledState(); + } + else + { + Dispatcher.Invoke(ApplyTicketOverviewDisabledState); + } + } + } + + private void ApplyTicketOverviewDisabledState() + { + _renderTicketOverviewUserNames = false; + _ticketOverviewNotificationScopesPrimed.Clear(); + _ticketOverviewFirstEventHandled = false; + _ticketOverviewInitWasEmptyScopes.Clear(); + SetTicketOverviewVisibility(false); + (Application.Current as App)?.ClearTicketOverviewTrayNotification(); + } - private bool CheckTicketOverviewAvailability() - { - if (cFasdCockpitCommunicationBase.Instance.IsDemo()) - return true; - return false; - } - - private void SetTicketOverviewVisibility(bool isVisible) - { - var b = isVisible; - if (!CheckTicketOverviewAvailability()) - b = false; + private void SetTicketOverviewVisibility(bool isVisible) + { + var b = isVisible; + if (!CheckTicketOverviewAvailability()) + b = false; BodyStack_TicketOverview.Visibility = b ? Visibility.Visible : Visibility.Collapsed; TicketOverviewBorder.Visibility = b ? Visibility.Visible : Visibility.Collapsed; FilterCheckbox.Visibility = b ? Visibility.Visible : Visibility.Collapsed; - RoleLabel.Visibility = b ? Visibility.Visible : Visibility.Collapsed; - OwnTicketsLabel.Visibility = b ? Visibility.Visible : Visibility.Collapsed; - TicketOverviewLabel.Visibility = b ? Visibility.Visible : Visibility.Collapsed; - } + RoleLabel.Visibility = b ? Visibility.Visible : Visibility.Collapsed; + OwnTicketsLabel.Visibility = b ? Visibility.Visible : Visibility.Collapsed; + TicketOverviewLabel.Visibility = b ? Visibility.Visible : Visibility.Collapsed; + ScheduleSearchResultMaxHeightUpdate(); + } public void ShowLoadingTextItem(string itemText) { @@ -135,10 +222,10 @@ namespace FasdDesktopUi.Pages.SearchPage ResultMenu.ShowLoadingTextItem(itemText); } - public void ShowTicketOverviewPane() - { - Dispatcher.Invoke(() => - { + public void ShowTicketOverviewPane() + { + Dispatcher.Invoke(() => + { bool overviewAlreadyVisible = TicketOverviewBorder.Visibility == Visibility.Visible; SetTicketOverviewVisibility(true); @@ -151,10 +238,28 @@ namespace FasdDesktopUi.Pages.SearchPage } TicketOverviewUc?.RefreshHighlightState(IsFilterChecked); - var app = Application.Current as FasdDesktopUi.App; - app?.ClearTicketOverviewTrayNotification(); - }); - } + var app = Application.Current as FasdDesktopUi.App; + app?.ClearTicketOverviewTrayNotification(); + }); + } + + public void ShowTicketOverviewPaneForScope(TileScope? scope) + { + if (scope.HasValue) + { + Dispatcher.Invoke(() => + { + if (TicketOverviewBorder.Visibility == Visibility.Visible) + return; + + var useRoleScope = scope.Value == TileScope.Role; + if (FilterCheckbox != null && FilterCheckbox.IsChecked != useRoleScope) + FilterCheckbox.IsChecked = useRoleScope; + }); + } + + ShowTicketOverviewPane(); + } internal void CloseTicketOverviewResults() { @@ -192,7 +297,7 @@ namespace FasdDesktopUi.Pages.SearchPage enumFasdInformationClass GetInformationClass(cF4sdApiSearchResultRelation relation) => cF4sdIdentityEntry.GetFromSearchResult(relation.Type); - cMenuDataBase GetMenuData(cF4sdApiSearchResultRelation relation, IRelationService trelationService) + cMenuDataBase GetMenuData(cF4sdApiSearchResultRelation relation, IRelationService subRelationService) { try { @@ -837,37 +942,178 @@ namespace FasdDesktopUi.Pages.SearchPage } } - private void TicketOverviewUpdateService_OverviewCountsChanged(object sender, TicketOverviewCountsChangedEventArgs e) - { - try - { - ApplyLatestCounts(); - var positiveChanges = e.Changes?.Where(change => change.Delta > 0).ToList(); - TicketOverviewUc?.SetHighlights(positiveChanges, IsFilterChecked); - - var app = Application.Current as FasdDesktopUi.App; - - if (positiveChanges == null || positiveChanges.Count == 0) - { - app?.ClearTicketOverviewTrayNotification(); - return; - } - - var message = BuildNotificationMessage(positiveChanges); - if (string.IsNullOrWhiteSpace(message)) - { - app?.ClearTicketOverviewTrayNotification(); - return; - } - - app?.ShowTicketOverviewTrayNotification(message); - ShowTicketOverviewNotification(message); - } - catch (Exception ex) - { - LogException(ex); - } - } + private void TicketOverviewUpdateService_OverviewCountsChanged(object sender, TicketOverviewCountsChangedEventArgs e) + { + try + { + ApplyLatestCounts(); + var positiveChanges = e.Changes?.Where(change => change.Delta > 0).ToList(); + var app = Application.Current as FasdDesktopUi.App; + var service = TicketOverviewUpdateService.Instance; + + if (!_ticketOverviewFirstEventHandled) + { + _ticketOverviewFirstEventHandled = true; + foreach (var scope in GetTicketOverviewEventScopes(e)) + { + PrimeTicketOverviewScope(scope); + TrackEmptyInitScope(scope, e?.CurrentCounts); + } + app?.ClearTicketOverviewTrayNotification(); + return; + } + + if (e.InitializedScope.HasValue) + { + PrimeTicketOverviewScope(e.InitializedScope.Value); + TrackEmptyInitScope(e.InitializedScope.Value, e?.CurrentCounts); + app?.ClearTicketOverviewTrayNotification(); + return; + } + + if (positiveChanges == null || positiveChanges.Count == 0) + { + app?.ClearTicketOverviewTrayNotification(); + return; + } + + if (service != null && !service.AreAllScopesInitialized) + { + app?.ClearTicketOverviewTrayNotification(); + return; + } + + var filteredChanges = FilterChangesForPrimedScopes(positiveChanges); + if (filteredChanges.Count == 0) + { + app?.ClearTicketOverviewTrayNotification(); + return; + } + + TicketOverviewUc?.SetHighlights(filteredChanges, IsFilterChecked); + + var pendingScope = ResolveSingleScope(filteredChanges); + app?.SetTicketOverviewNotificationScope(pendingScope); + + var message = BuildNotificationMessage(filteredChanges); + if (string.IsNullOrWhiteSpace(message)) + { + app?.ClearTicketOverviewTrayNotification(); + return; + } + + app?.ShowTicketOverviewTrayNotification(message); + ShowTicketOverviewNotification(message); + } + catch (Exception ex) + { + LogException(ex); + } + } + + private void PrimeTicketOverviewScope(TileScope scope) + { + if (_ticketOverviewNotificationScopesPrimed.Add(scope)) + { + TicketOverviewUc?.ClearHighlightsForScope(scope); + } + } + + private IReadOnlyList FilterChangesForPrimedScopes(IReadOnlyList changes) + { + if (changes == null || changes.Count == 0) + return Array.Empty(); + + var filteredChanges = new List(changes.Count); + var unprimedScopes = new HashSet(); + var silentInitScopes = new HashSet(); + + foreach (var change in changes) + { + if (_ticketOverviewInitWasEmptyScopes.Contains(change.Scope)) + { + silentInitScopes.Add(change.Scope); + continue; + } + + if (_ticketOverviewNotificationScopesPrimed.Contains(change.Scope)) + { + filteredChanges.Add(change); + } + else + { + unprimedScopes.Add(change.Scope); + } + } + + foreach (var scope in unprimedScopes) + { + PrimeTicketOverviewScope(scope); + } + + if (silentInitScopes.Count > 0) + { + foreach (var scope in silentInitScopes) + { + _ticketOverviewInitWasEmptyScopes.Remove(scope); + PrimeTicketOverviewScope(scope); + } + } + + return filteredChanges; + } + + private void TrackEmptyInitScope(TileScope scope, IReadOnlyDictionary counts) + { + if (IsScopeCountsEmpty(scope, counts)) + { + _ticketOverviewInitWasEmptyScopes.Add(scope); + } + } + + private static bool IsScopeCountsEmpty(TileScope scope, IReadOnlyDictionary counts) + { + if (counts == null || counts.Count == 0) + return true; + + foreach (var kvp in counts) + { + var value = scope == TileScope.Role ? kvp.Value.Role : kvp.Value.Personal; + if (value != 0) + return false; + } + + return true; + } + + private static IEnumerable GetTicketOverviewEventScopes(TicketOverviewCountsChangedEventArgs e) + { + if (e == null) + return Enumerable.Empty(); + + if (e.InitializedScope.HasValue) + return new[] { e.InitializedScope.Value }; + + if (e.Changes == null || e.Changes.Count == 0) + return Enumerable.Empty(); + + return e.Changes.Select(change => change.Scope).Distinct(); + } + + private static TileScope? ResolveSingleScope(IReadOnlyList changes) + { + if (changes == null || changes.Count == 0) + return null; + + var scope = changes[0].Scope; + for (int i = 1; i < changes.Count; i++) + { + if (changes[i].Scope != scope) + return null; + } + + return scope; + } private void ApplyLatestCounts() { @@ -1082,11 +1328,12 @@ namespace FasdDesktopUi.Pages.SearchPage SetPendingInformationClasses(new HashSet { enumFasdInformationClass.Ticket }); - var relations = await LoadRelationsForTileAsync(e.Key, e.UseRoleScope, Math.Max(0, e.Count)); - Debug.WriteLine($"[TicketOverview] Relations loaded: {relations?.Count ?? 0}"); - var firstRelation = relations.FirstOrDefault(); - string displayText = header; - if (firstRelation != null) + var relations = await LoadRelationsForTileAsync(e.Key, e.UseRoleScope, Math.Max(0, e.Count)); + Debug.WriteLine($"[TicketOverview] Relations loaded: {relations?.Count ?? 0}"); + var ticketOverviewRelationService = new RelationService(); + var firstRelation = relations.FirstOrDefault(); + string displayText = header; + if (firstRelation != null) { string firstSummary = null; if (firstRelation.Infos != null && firstRelation.Infos.TryGetValue("Summary", out var summaryValue)) @@ -1130,16 +1377,16 @@ namespace FasdDesktopUi.Pages.SearchPage { trailingUser = userDisplayName; } - return (cMenuDataBase)new cMenuDataSearchRelation(r) - { - MenuText = r.DisplayName, - TrailingText = trailingUser, - UiAction = new cUiProcessSearchRelationAction(entry, r, null, this) - { - DisplayType = isEnabled ? enumActionDisplayType.enabled : enumActionDisplayType.disabled, - Description = isEnabled ? string.Empty : disabledReason, - AlternativeDescription = isEnabled ? string.Empty : disabledReason - } + return (cMenuDataBase)new cMenuDataSearchRelation(r) + { + MenuText = r.DisplayName, + TrailingText = trailingUser, + UiAction = new cUiProcessSearchRelationAction(entry, r, ticketOverviewRelationService, this) + { + DisplayType = isEnabled ? enumActionDisplayType.enabled : enumActionDisplayType.disabled, + Description = isEnabled ? string.Empty : disabledReason, + AlternativeDescription = isEnabled ? string.Empty : disabledReason + } }; } ); @@ -1381,11 +1628,11 @@ namespace FasdDesktopUi.Pages.SearchPage } } - private void UiSettingsChanged(object sender, EventArgs e) - { - try - { - var positionAlignement = cFasdCockpitConfig.Instance.Global.SmallViewAlignment; + private void UiSettingsChanged(object sender, EventArgs e) + { + try + { + var positionAlignement = cFasdCockpitConfig.Instance.Global.SmallViewAlignment; switch (positionAlignement) { @@ -1396,18 +1643,49 @@ namespace FasdDesktopUi.Pages.SearchPage Dispatcher.Invoke(() => MainBorder.HorizontalAlignment = HorizontalAlignment.Right); break; default: - Dispatcher.Invoke(() => MainBorder.HorizontalAlignment = HorizontalAlignment.Left); - break; - } - } - catch (Exception E) - { - LogException(E); - } + Dispatcher.Invoke(() => MainBorder.HorizontalAlignment = HorizontalAlignment.Left); + break; + } + + UpdateTicketOverviewAvailability(); + } + catch (Exception E) + { + LogException(E); + } } public void SetPendingInformationClasses(HashSet informationClasses) => Dispatcher.Invoke(() => ResultMenu.SetPendingInformationClasses(informationClasses)); public void UpdatePendingInformationClasses(HashSet informationClasses) => Dispatcher.Invoke(() => ResultMenu.UpdatePendingInformationClasses(informationClasses)); + + private void ResultMenu_PreviewMouseWheel(object sender, MouseWheelEventArgs e) + { + var scrollViewer = FindParent((DependencyObject)sender); + + if (scrollViewer != null) + { + if (e.Delta > 0) + scrollViewer.LineUp(); + else + scrollViewer.LineDown(); + + e.Handled = true; + } + } + + private T FindParent(DependencyObject child) where T : DependencyObject + { + DependencyObject parent = VisualTreeHelper.GetParent(child); + + while (parent != null) + { + if (parent is T typed) + return typed; + + parent = VisualTreeHelper.GetParent(parent); + } + return null; + } } } diff --git a/FasdDesktopUi/Pages/SettingsPage/M42SettingsPageView.xaml b/FasdDesktopUi/Pages/SettingsPage/M42SettingsPageView.xaml index 3799f9a..770ae8d 100644 --- a/FasdDesktopUi/Pages/SettingsPage/M42SettingsPageView.xaml +++ b/FasdDesktopUi/Pages/SettingsPage/M42SettingsPageView.xaml @@ -9,7 +9,7 @@ xmlns:vc="clr-namespace:FasdDesktopUi.Basics.Converter" xmlns:sys="clr-namespace:System;assembly=mscorlib" mc:Ignorable="d" - Title="PhoneSettingsPage" + Title="M42SettingsPage" ResizeMode="NoResize" WindowStyle="None" AllowsTransparency="True" diff --git a/FasdDesktopUi/Pages/SlimPage/SlimPageView.xaml.cs b/FasdDesktopUi/Pages/SlimPage/SlimPageView.xaml.cs index 8896f31..7b307c4 100644 --- a/FasdDesktopUi/Pages/SlimPage/SlimPageView.xaml.cs +++ b/FasdDesktopUi/Pages/SlimPage/SlimPageView.xaml.cs @@ -310,7 +310,7 @@ namespace FasdDesktopUi.Pages.SlimPage return; } - var data = await _supportCase?.SupportCaseDataProviderArtifact.HealthCardDataHelper.SlimCard.GetDataAsync(); + var data = await _supportCaseController?.SupportCaseDataProviderArtifact.HealthCardDataHelper.SlimCard.GetDataAsync(); //todo: check if there is a more performant way solving this Dispatcher.Invoke(() => WidgetCollectionUc.HeadingData = data.HeadingData); Dispatcher.Invoke(() => WidgetCollectionUc.WidgetData = data.WidgetData); @@ -339,17 +339,17 @@ namespace FasdDesktopUi.Pages.SlimPage { try { - var data = await _supportCase?.SupportCaseDataProviderArtifact.HealthCardDataHelper.SlimCard.GetDataAsync(); + var data = await _supportCaseController?.SupportCaseDataProviderArtifact.HealthCardDataHelper.SlimCard.GetDataAsync(); //todo: check if there is a more performant way solving this Dispatcher.Invoke(() => WidgetCollectionUc.HeadingData = data.HeadingData); Dispatcher.Invoke(() => WidgetCollectionUc.WidgetData = data.WidgetData); Dispatcher.Invoke(() => MenuBarUc.MenuBarItemData = GetSlimpageMenuBarData(data.MenuBarData)); Dispatcher.Invoke(() => DataHistoryCollectionUc.UpdateHistory(data.DataHistoryList)); - if (_supportCase != null) + if (_supportCaseController != null) { - _supportCase.SupportCaseDataProviderArtifact.HealthCardDataHelper.LoadingHelper.DataChanged -= DataProvider_DataChanged; - _supportCase.SupportCaseDataProviderArtifact.HealthCardDataHelper.LoadingHelper.DataFullyLoaded -= DataProvider_DataFullyLoaded; + _supportCaseController.SupportCaseDataProviderArtifact.HealthCardDataHelper.LoadingHelper.DataChanged -= DataProvider_DataChanged; + _supportCaseController.SupportCaseDataProviderArtifact.HealthCardDataHelper.LoadingHelper.DataFullyLoaded -= DataProvider_DataFullyLoaded; } } catch (Exception E) @@ -364,7 +364,7 @@ namespace FasdDesktopUi.Pages.SlimPage { Dispatcher.Invoke(() => { - bool hasDirectConnection = _supportCase?.SupportCaseDataProviderArtifact?.DirectConnectionHelper?.IsDirectConnectionActive ?? false; + bool hasDirectConnection = _supportCaseController?.SupportCaseDataProviderArtifact?.DirectConnectionHelper?.IsDirectConnectionActive ?? false; WidgetCollectionUc.HasDirectConnection = hasDirectConnection; }); } @@ -495,7 +495,7 @@ namespace FasdDesktopUi.Pages.SlimPage break; } - await e.UiAction?.RunUiActionAsync(e.OriginalSource, drawingArea, false, _supportCase?.SupportCaseDataProviderArtifact); + await e.UiAction?.RunUiActionAsync(e.OriginalSource, drawingArea, false, _supportCaseController?.SupportCaseDataProviderArtifact); } catch (Exception E) diff --git a/FasdDesktopUi/Pages/SupportCasePageBase/SupportCasePageBase.cs b/FasdDesktopUi/Pages/SupportCasePageBase/SupportCasePageBase.cs index 8f2fb1f..061e111 100644 --- a/FasdDesktopUi/Pages/SupportCasePageBase/SupportCasePageBase.cs +++ b/FasdDesktopUi/Pages/SupportCasePageBase/SupportCasePageBase.cs @@ -4,30 +4,30 @@ using System.Windows; using FasdDesktopUi.Basics; using FasdDesktopUi.Basics.Models; -using FasdDesktopUi.Basics.Services.SupportCase; +using FasdDesktopUi.Basics.Services.SupportCase.Controllers; using static C4IT.Logging.cLogManager; namespace FasdDesktopUi.Pages { public class SupportCasePageBase : Window, IBlurrable { - protected ISupportCase _supportCase; + protected SupportCaseController _supportCaseController; internal bool isDataChangedEventRunning = false; - public virtual void SetSupportCase(ISupportCase supportCase) + internal virtual void SetSupportCaseController(SupportCaseController supportCase) { - if (_supportCase != null) + if (_supportCaseController != null) { - _supportCase.SupportCaseDataProviderArtifact.HealthCardDataHelper.LoadingHelper.DataChanged -= DataProvider_DataChanged; - _supportCase.SupportCaseDataProviderArtifact.HealthCardDataHelper.LoadingHelper.DataFullyLoaded -= DataProvider_DataFullyLoaded; - _supportCase.SupportCaseDataProviderArtifact.DirectConnectionHelper.DirectConnectionChanged -= DirectConnectionHelper_DirectConnectionChanged; + _supportCaseController.SupportCaseDataProviderArtifact.HealthCardDataHelper.LoadingHelper.DataChanged -= DataProvider_DataChanged; + _supportCaseController.SupportCaseDataProviderArtifact.HealthCardDataHelper.LoadingHelper.DataFullyLoaded -= DataProvider_DataFullyLoaded; + _supportCaseController.SupportCaseDataProviderArtifact.DirectConnectionHelper.DirectConnectionChanged -= DirectConnectionHelper_DirectConnectionChanged; } - _supportCase = supportCase; - _supportCase.SupportCaseDataProviderArtifact.HealthCardDataHelper.LoadingHelper.DataChanged += DataProvider_DataChanged; - _supportCase.SupportCaseDataProviderArtifact.HealthCardDataHelper.LoadingHelper.DataFullyLoaded += DataProvider_DataFullyLoaded; - _supportCase.SupportCaseDataProviderArtifact.DirectConnectionHelper.DirectConnectionChanged += DirectConnectionHelper_DirectConnectionChanged; + _supportCaseController = supportCase; + _supportCaseController.SupportCaseDataProviderArtifact.HealthCardDataHelper.LoadingHelper.DataChanged += DataProvider_DataChanged; + _supportCaseController.SupportCaseDataProviderArtifact.HealthCardDataHelper.LoadingHelper.DataFullyLoaded += DataProvider_DataFullyLoaded; + _supportCaseController.SupportCaseDataProviderArtifact.DirectConnectionHelper.DirectConnectionChanged += DirectConnectionHelper_DirectConnectionChanged; } internal async void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) diff --git a/FasdDesktopUi/ResourceDictionaries/CheckBoxResources.xaml b/FasdDesktopUi/ResourceDictionaries/CheckBoxResources.xaml index 66eeb2c..dde1183 100644 --- a/FasdDesktopUi/ResourceDictionaries/CheckBoxResources.xaml +++ b/FasdDesktopUi/ResourceDictionaries/CheckBoxResources.xaml @@ -1,8 +1,8 @@  - - \ No newline at end of file + + + diff --git a/FasdDesktopUi/ResourceDictionaries/LightModeResources.xaml b/FasdDesktopUi/ResourceDictionaries/LightModeResources.xaml index d43a566..ab4422f 100644 --- a/FasdDesktopUi/ResourceDictionaries/LightModeResources.xaml +++ b/FasdDesktopUi/ResourceDictionaries/LightModeResources.xaml @@ -8,7 +8,7 @@ ../Resources/Cursors/Hand_Clipboard_Light.cur - + - + + - - - + + + + + + + + + + + \ No newline at end of file diff --git a/FasdExcelToJsonConverter/App.config b/FasdExcelToJsonConverter/App.config index 008267a..7ab2079 100644 --- a/FasdExcelToJsonConverter/App.config +++ b/FasdExcelToJsonConverter/App.config @@ -21,6 +21,10 @@ + + + + \ No newline at end of file diff --git a/FasdExcelToJsonConverter/ExcelHealthcardParser.cs b/FasdExcelToJsonConverter/ExcelHealthcardParser.cs index 78c3bc5..e8717b0 100644 --- a/FasdExcelToJsonConverter/ExcelHealthcardParser.cs +++ b/FasdExcelToJsonConverter/ExcelHealthcardParser.cs @@ -96,7 +96,7 @@ namespace FasdExcelToJsonConverter if (tableDictionaryEntry.Columns.ContainsKey(columnName)) continue; - tableDictionaryEntry.Columns.Add(columnName, new cF4SDHealthCardRawData.cHealthCardTableColumn() { ColumnName = columnName, Values = values.ToList() }); + tableDictionaryEntry.Columns.Add(columnName, new cF4SDHealthCardRawData.cHealthCardTableColumn(tableDictionaryEntry) { ColumnName = columnName, Values = values.ToList() }); if (tableDictionaryEntry.TimeFrames == null) tableDictionaryEntry.TimeFrames = new DateTime[1, 2]; diff --git a/FasdExcelToJsonConverter/F4SD-ExcelToJson-Converter.csproj b/FasdExcelToJsonConverter/F4SD-ExcelToJson-Converter.csproj index bd396c8..7d32c32 100644 --- a/FasdExcelToJsonConverter/F4SD-ExcelToJson-Converter.csproj +++ b/FasdExcelToJsonConverter/F4SD-ExcelToJson-Converter.csproj @@ -79,7 +79,7 @@ - ..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + ..\packages\Newtonsoft.Json.13.0.4\lib\net45\Newtonsoft.Json.dll diff --git a/FasdExcelToJsonConverter/packages.config b/FasdExcelToJsonConverter/packages.config index fef83be..17ab3be 100644 --- a/FasdExcelToJsonConverter/packages.config +++ b/FasdExcelToJsonConverter/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/Setup_Client/Product.wxs b/Setup_Client/Product.wxs index f11cb89..fc4885f 100644 --- a/Setup_Client/Product.wxs +++ b/Setup_Client/Product.wxs @@ -4,7 +4,7 @@ @@ -98,6 +98,7 @@ + diff --git a/Setup_Client/SignSourceFiles.cmd b/Setup_Client/SignSourceFiles.cmd index edd81af..012dab6 100644 --- a/Setup_Client/SignSourceFiles.cmd +++ b/Setup_Client/SignSourceFiles.cmd @@ -3,7 +3,7 @@ set ProductName="C4IT First Aid Service Desk Cockpit" set SignTool=..\..\Common Code\Tools\signtool.exe set TimeStamp=http://rfc3161timestamp.globalsign.com/advanced -"%SignTool%" sign /a /tr %TimeStamp% /td SHA256 /fd SHA256 /d %ProductName% ".\Source\F4SD-Cockpit-Client.exe" ".\Source\F4SD-Cockpit-Client-Base.dll" ".\Source\F4SD-Cockpit-Client-Communication.dll" ".\Source\C4IT.F4SD.DisplayFormatting.dll" ".\Source\F4SD-AdaptableIcon.dll" ".\Source\F4SD-PhoneMonitor.exe" ".\Source\F4SD-Logging.dll" +"%SignTool%" sign /a /tr %TimeStamp% /td SHA256 /fd SHA256 /d %ProductName% ".\Source\F4SD-Cockpit-Client.exe" ".\Source\F4SD-Cockpit-Client-Base.dll" ".\Source\F4SD-Cockpit-Client-Communication.dll" ".\Source\C4IT.F4SD.DisplayFormatting.dll" ".\Source\C4IT.F4SD.SupportCaseProtocoll.dll" ".\Source\F4SD-AdaptableIcon.dll" ".\Source\F4SD-PhoneMonitor.exe" ".\Source\F4SD-Logging.dll" pause diff --git a/Shared/SharedAssemblyInfo.cs b/Shared/SharedAssemblyInfo.cs index e2bdea1..c3739c8 100644 --- a/Shared/SharedAssemblyInfo.cs +++ b/Shared/SharedAssemblyInfo.cs @@ -2,10 +2,10 @@ [assembly: AssemblyCompany("Consulting4IT GmbH, Germany")] [assembly: AssemblyProduct("C4IT First Aid Service Desk")] -[assembly: AssemblyCopyright("Copyright © 2025, Consulting4IT GmbH, Germany")] +[assembly: AssemblyCopyright("Copyright © 2026, Consulting4IT GmbH, Germany")] [assembly: AssemblyTrademark("")] [assembly: AssemblyVersion("2.6.*")] -[assembly: AssemblyInformationalVersion("2.6.0.5")] +[assembly: AssemblyInformationalVersion("2.6.1.2")] -[assembly: AssemblyMinServerVersion("2.5.0.0")] \ No newline at end of file +[assembly: AssemblyMinServerVersion("2.6.1.1")] \ No newline at end of file