From 0964439441298c5d483fe4592e000e8759654284 Mon Sep 17 00:00:00 2001 From: PointStar Date: Mon, 11 May 2026 15:47:36 +0300 Subject: [PATCH] =?UTF-8?q?feat(compose):=20Task=20#5=20=E2=80=94=20Compos?= =?UTF-8?q?e=20from=20Case=20+=20URL=20protocol=20+=20auto-file?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit UI: - ComposeFromCaseDialog (RTL, search-then-pick a single Case via GlobalSearch + entityType=Case filter) - ComposeFromCaseViewModel — debounced GlobalSearch, returns chosen EspoEntityRef Host: - ComposeService.ApplyCaseToMailAsync: * fetches Case + primary Contact * stamps UserProperties EspoCaseId, EspoCaseName, OutlookAddinGuid * pre-fills To/Subject and appends an RTL footer with a CRM deep link - ItemSend hook (in AddInHost.HookItemSend): when the user sends a tagged compose, register guid → target with SentItemsWatcher - SentItemsWatcher: rooted Items reference (prevents GC), 30s expiry sweep, 2-min default timeout per pending tag, MailMatched event - AddInHost.OnSentMailMatched: extracts the sent MailItem, files via FilingService, stamps "Filed: {name}" category - LaunchComposeFromCaseAsync (Inspector ribbon) and LaunchComposeFromCaseByIdAsync (URL protocol) entry points - NamedPipeListener (\.\pipe\MarcusLaw.OutlookAddin) — listens for "COMPOSE " lines, dispatches on WPF Dispatcher Ribbon: - InspectorRibbon.xml — "כתוב מתיק" button on Mail Compose ribbon, hidden for received/read mail via getVisible - ExplorerRibbon class now serves both Explorer and Inspector ribbons (single IRibbonExtensibility, dispatches by ribbonID) URL protocol: - New OutlookAddinProtocolHandler console project (net48 WinExe): parses outlookaddin://compose?caseId=, connects to named pipe, writes "COMPOSE \n" - tools/install-protocol.ps1 + uninstall-protocol.ps1 register the scheme under HKCU\Software\Classes\outlookaddin Core/UI/Tests + protocol handler all build; 38 unit tests still green. Co-Authored-By: Claude Opus 4.7 (1M context) --- OutlookAddin.sln | 6 + .../Dialogs/ComposeFromCaseDialog.xaml | 62 +++++ .../Dialogs/ComposeFromCaseDialog.xaml.cs | 36 +++ .../ViewModels/ComposeFromCaseViewModel.cs | 127 +++++++++++ src/OutlookAddin/OutlookAddin.csproj | 12 + src/OutlookAddin/Ribbon/ExplorerRibbon.cs | 80 ++++++- src/OutlookAddin/Ribbon/InspectorRibbon.xml | 19 ++ src/OutlookAddin/Services/AddInHost.cs | 215 ++++++++++++++++++ src/OutlookAddin/Services/ComposeService.cs | 162 +++++++++++++ .../Services/NamedPipeListener.cs | 87 +++++++ src/OutlookAddin/Services/SentItemsWatcher.cs | 179 +++++++++++++++ .../OutlookAddinProtocolHandler.csproj | 17 ++ src/OutlookAddinProtocolHandler/Program.cs | 89 ++++++++ tools/install-protocol.ps1 | 41 ++++ tools/uninstall-protocol.ps1 | 3 + 15 files changed, 1123 insertions(+), 12 deletions(-) create mode 100644 src/OutlookAddin.UI/Dialogs/ComposeFromCaseDialog.xaml create mode 100644 src/OutlookAddin.UI/Dialogs/ComposeFromCaseDialog.xaml.cs create mode 100644 src/OutlookAddin.UI/ViewModels/ComposeFromCaseViewModel.cs create mode 100644 src/OutlookAddin/Ribbon/InspectorRibbon.xml create mode 100644 src/OutlookAddin/Services/ComposeService.cs create mode 100644 src/OutlookAddin/Services/NamedPipeListener.cs create mode 100644 src/OutlookAddin/Services/SentItemsWatcher.cs create mode 100644 src/OutlookAddinProtocolHandler/OutlookAddinProtocolHandler.csproj create mode 100644 src/OutlookAddinProtocolHandler/Program.cs create mode 100644 tools/install-protocol.ps1 create mode 100644 tools/uninstall-protocol.ps1 diff --git a/OutlookAddin.sln b/OutlookAddin.sln index 6f7681d..8d7a47c 100644 --- a/OutlookAddin.sln +++ b/OutlookAddin.sln @@ -10,6 +10,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OutlookAddin.Tests", "src\O EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OutlookAddin", "src\OutlookAddin\OutlookAddin.csproj", "{7A8B6509-CB21-42BD-A42C-2735170AFFD2}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OutlookAddinProtocolHandler", "src\OutlookAddinProtocolHandler\OutlookAddinProtocolHandler.csproj", "{A0000000-0000-0000-0000-000000000005}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -32,6 +34,10 @@ Global {7A8B6509-CB21-42BD-A42C-2735170AFFD2}.Debug|Any CPU.Build.0 = Debug|Any CPU {7A8B6509-CB21-42BD-A42C-2735170AFFD2}.Release|Any CPU.ActiveCfg = Release|Any CPU {7A8B6509-CB21-42BD-A42C-2735170AFFD2}.Release|Any CPU.Build.0 = Release|Any CPU + {A0000000-0000-0000-0000-000000000005}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A0000000-0000-0000-0000-000000000005}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A0000000-0000-0000-0000-000000000005}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A0000000-0000-0000-0000-000000000005}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/OutlookAddin.UI/Dialogs/ComposeFromCaseDialog.xaml b/src/OutlookAddin.UI/Dialogs/ComposeFromCaseDialog.xaml new file mode 100644 index 0000000..c551fb8 --- /dev/null +++ b/src/OutlookAddin.UI/Dialogs/ComposeFromCaseDialog.xaml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +