Walk Case.contactsIds for the first contact with a non-empty emailAddress
(falling back to the Account's emailAddress) instead of blindly using
contactsIds[0] and giving up if it has no email — Outlook was opening
the new mail with no To recipient when the first linked contact was
e.g. opposing counsel or a witness without a stored address.
Also hydrate the "כתוב מתיק" picker rows with number/status/court#
through GetCaseAsync (same pattern as SaveAttachmentsViewModel) and
switch the dialog to the DataGrid layout so it matches the file-
attachments picker the user expected.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1. New WPF converters (UI.Converters/EntityTypeToHebrewConverter.cs):
- EntityTypeToHebrewConverter maps Case/Contact/Account/Lead/... →
תיק / איש קשר / לקוח / ליד / ...
- EntityTypeToBrushConverter per-type accent brushes
- EntityTypeToIconConverter per-type emoji glyph
2. FileToCaseDialog redesigned:
- Soft slate background (#F8FAFC) with card-style borders + 6px
rounded corners
- Search row turned into a card with a 🔍 leading icon (DockPanel.Dock
respects RTL so it's on the visual right)
- Group headers now show: emoji + Hebrew label (תיק / איש קשר / ...)
+ result count, with a colored stripe per entity type
- Custom ResultItem template: hover + selected backgrounds, rounded
selection
- Recents pane has a header strip and per-row colored chip showing
the Hebrew entity type
- Primary action ("תייק") in solid blue with hover state; secondary
("ביטול") in white with border; tertiary ("+ צור איש קשר") as a
muted link button
3. ComposeFromCaseDialog gets the same card + button styling for
visual consistency.
Builds clean, 39 tests still green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1. FileToCaseDialog + ComposeFromCaseDialog: under FlowDirection=RTL,
DockPanel flips Dock="Right" to render at visual left. Switch the
search label to Dock="Left" so it renders on the right (start of
Hebrew reading order), matching where the eye expects it.
2. Replace imageMso values that were either off-topic or rare:
- FileToEspoCrm: MeetingForwardToManager → MoveToFolder
- OpenEspoCrmSettings: ServerPropertiesDialog → FileOptions
- ComposeFromCase: MailMergeStartLetters → NewMailMessage
All three are present in every Outlook version ≥ 2010 and convey the
action better.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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 <caseId>" 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=<id>, connects to named pipe,
writes "COMPOSE <id>\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) <noreply@anthropic.com>