Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6a51a58224 | |||
| 9b451c9cbe | |||
| 35ce8facff | |||
| c685f4f91d | |||
| 5eae3da213 | |||
| 8264c11b57 | |||
| 4556d2c1b3 | |||
| a8e947c825 | |||
| 32f6facb67 | |||
| 2228353c48 | |||
| eea0d92d85 | |||
| 655fefa822 | |||
| d2c54840ba | |||
| 870426ec08 | |||
| 137929b4ac | |||
| 95d7599cb1 | |||
| 62254fcd8c | |||
| 7aa96c99a3 | |||
| 35455c2ef6 | |||
| 025dab9b20 |
@@ -258,15 +258,21 @@ jobs:
|
|||||||
& msbuild @msbuildArgs
|
& msbuild @msbuildArgs
|
||||||
if ($LASTEXITCODE -ne 0) { throw "msbuild /t:Publish failed with $LASTEXITCODE" }
|
if ($LASTEXITCODE -ne 0) { throw "msbuild /t:Publish failed with $LASTEXITCODE" }
|
||||||
|
|
||||||
# Sanity check: did the VSTO publish target produce a .vsto file?
|
# Sanity check + rename to canonical OutlookAddin.vsto so the URL
|
||||||
$vsto = Get-ChildItem -Recurse -Filter '*.vsto' -Path publish | Select-Object -First 1
|
# matches PROVIDER_URL (hardcoded to .../OutlookAddin.vsto). Restrict
|
||||||
if (-not $vsto) { throw "msbuild /t:Publish completed but no .vsto file found under publish/" }
|
# to publish/ root -- there's a second .vsto inside Application Files
|
||||||
|
# that must keep its versioned name. Verify the renamed file exists
|
||||||
|
# before continuing; v1.2.11 shipped broken because a silent failure
|
||||||
|
# here left no OutlookAddin.vsto in the tar and 404'd the CDN.
|
||||||
|
$vsto = Get-ChildItem -File -Filter '*.vsto' -Path publish | Select-Object -First 1
|
||||||
|
if (-not $vsto) { throw "msbuild /t:Publish completed but no .vsto file found at publish/ root" }
|
||||||
Write-Host " produced $($vsto.FullName)"
|
Write-Host " produced $($vsto.FullName)"
|
||||||
|
|
||||||
# Rename to canonical OutlookAddin.vsto so the ClickOnce manifest
|
|
||||||
# URL matches PROVIDER_URL (which is hardcoded to .../OutlookAddin.vsto).
|
|
||||||
if ($vsto.Name -ne 'OutlookAddin.vsto') {
|
if ($vsto.Name -ne 'OutlookAddin.vsto') {
|
||||||
Rename-Item -LiteralPath $vsto.FullName -NewName 'OutlookAddin.vsto'
|
Rename-Item -LiteralPath $vsto.FullName -NewName 'OutlookAddin.vsto' -ErrorAction Stop
|
||||||
|
Write-Host " renamed -> OutlookAddin.vsto"
|
||||||
|
}
|
||||||
|
if (-not (Test-Path 'publish/OutlookAddin.vsto')) {
|
||||||
|
throw "post-rename: publish/OutlookAddin.vsto does not exist"
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Host "=== STEP F: stage protocol handler ==="
|
Write-Host "=== STEP F: stage protocol handler ==="
|
||||||
|
|||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
-35
@@ -1,35 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<configuration>
|
|
||||||
<runtime>
|
|
||||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
|
||||||
<dependentAssembly>
|
|
||||||
<assemblyIdentity name="Microsoft.Bcl.AsyncInterfaces" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
|
||||||
<bindingRedirect oldVersion="0.0.0.0-8.0.0.0" newVersion="8.0.0.0" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</assemblyBinding>
|
|
||||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
|
||||||
<dependentAssembly>
|
|
||||||
<assemblyIdentity name="Microsoft.Extensions.DependencyInjection.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
|
|
||||||
<bindingRedirect oldVersion="0.0.0.0-8.0.0.2" newVersion="8.0.0.2" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</assemblyBinding>
|
|
||||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
|
||||||
<dependentAssembly>
|
|
||||||
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
|
||||||
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</assemblyBinding>
|
|
||||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
|
||||||
<dependentAssembly>
|
|
||||||
<assemblyIdentity name="System.ComponentModel.Annotations" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
|
||||||
<bindingRedirect oldVersion="0.0.0.0-4.2.1.0" newVersion="4.2.1.0" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</assemblyBinding>
|
|
||||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
|
||||||
<dependentAssembly>
|
|
||||||
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
|
||||||
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</assemblyBinding>
|
|
||||||
</runtime>
|
|
||||||
</configuration>
|
|
||||||
BIN
Binary file not shown.
-588
@@ -1,588 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<asmv1:assembly xsi:schemaLocation="urn:schemas-microsoft-com:asm.v1 assembly.adaptive.xsd" manifestVersion="1.0" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns="urn:schemas-microsoft-com:asm.v2" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:co.v1="urn:schemas-microsoft-com:clickonce.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:co.v2="urn:schemas-microsoft-com:clickonce.v2">
|
|
||||||
<asmv1:assemblyIdentity name="MarcusLaw.OutlookAddin.dll" version="1.0.7.0" publicKeyToken="41d8d795775ea8cb" language="neutral" processorArchitecture="msil" type="win32" />
|
|
||||||
<description xmlns="urn:schemas-microsoft-com:asm.v1">MarcusLaw.OutlookAddin</description>
|
|
||||||
<application />
|
|
||||||
<entryPoint>
|
|
||||||
<co.v1:customHostSpecified />
|
|
||||||
</entryPoint>
|
|
||||||
<trustInfo>
|
|
||||||
<security>
|
|
||||||
<applicationRequestMinimum>
|
|
||||||
<PermissionSet Unrestricted="true" ID="Custom" SameSite="site" />
|
|
||||||
<defaultAssemblyRequest permissionSetReference="Custom" />
|
|
||||||
</applicationRequestMinimum>
|
|
||||||
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
|
|
||||||
<!--
|
|
||||||
UAC Manifest Options
|
|
||||||
If you want to change the Windows User Account Control level replace the
|
|
||||||
requestedExecutionLevel node with one of the following.
|
|
||||||
|
|
||||||
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
|
||||||
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
|
||||||
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
|
|
||||||
|
|
||||||
If you want to utilize File and Registry Virtualization for backward
|
|
||||||
compatibility then delete the requestedExecutionLevel node.
|
|
||||||
-->
|
|
||||||
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
|
||||||
</requestedPrivileges>
|
|
||||||
</security>
|
|
||||||
</trustInfo>
|
|
||||||
<dependency>
|
|
||||||
<dependentOS>
|
|
||||||
<osVersionInfo>
|
|
||||||
<os majorVersion="5" minorVersion="1" buildNumber="2600" servicePackMajor="0" />
|
|
||||||
</osVersionInfo>
|
|
||||||
</dependentOS>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
|
||||||
<assemblyIdentity name="Microsoft.Windows.CommonLanguageRuntime" version="4.0.30319.0" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
|
||||||
<assemblyIdentity name="Accessibility" version="4.0.0.0" publicKeyToken="B03F5F7F11D50A3A" language="neutral" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
|
||||||
<assemblyIdentity name="Microsoft.CSharp" version="4.0.0.0" publicKeyToken="B03F5F7F11D50A3A" language="neutral" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
|
||||||
<assemblyIdentity name="Microsoft.Office.Tools" version="10.0.0.0" publicKeyToken="B03F5F7F11D50A3A" language="neutral" processorArchitecture="msil" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
|
||||||
<assemblyIdentity name="Microsoft.Office.Tools.Common" version="10.0.0.0" publicKeyToken="B03F5F7F11D50A3A" language="neutral" processorArchitecture="msil" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
|
||||||
<assemblyIdentity name="Microsoft.Office.Tools.Outlook" version="10.0.0.0" publicKeyToken="B03F5F7F11D50A3A" language="neutral" processorArchitecture="msil" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
|
||||||
<assemblyIdentity name="Microsoft.Office.Tools.v4.0.Framework" version="10.0.0.0" publicKeyToken="B03F5F7F11D50A3A" language="neutral" processorArchitecture="msil" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
|
||||||
<assemblyIdentity name="Microsoft.VisualStudio.Tools.Applications.Runtime" version="10.0.0.0" publicKeyToken="B03F5F7F11D50A3A" language="neutral" processorArchitecture="msil" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
|
||||||
<assemblyIdentity name="mscorlib" version="4.0.0.0" publicKeyToken="B77A5C561934E089" language="neutral" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
|
||||||
<assemblyIdentity name="netstandard" version="2.0.0.0" publicKeyToken="CC7B13FFCD2DDD51" language="neutral" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
|
||||||
<assemblyIdentity name="PresentationCore" version="4.0.0.0" publicKeyToken="31BF3856AD364E35" language="neutral" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
|
||||||
<assemblyIdentity name="PresentationFramework" version="4.0.0.0" publicKeyToken="31BF3856AD364E35" language="neutral" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
|
||||||
<assemblyIdentity name="stdole" version="7.0.3300.0" publicKeyToken="B03F5F7F11D50A3A" language="neutral" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
|
||||||
<assemblyIdentity name="System" version="4.0.0.0" publicKeyToken="B77A5C561934E089" language="neutral" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
|
||||||
<assemblyIdentity name="System.ComponentModel.DataAnnotations" version="4.0.0.0" publicKeyToken="31BF3856AD364E35" language="neutral" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
|
||||||
<assemblyIdentity name="System.Core" version="4.0.0.0" publicKeyToken="B77A5C561934E089" language="neutral" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
|
||||||
<assemblyIdentity name="System.Data" version="4.0.0.0" publicKeyToken="B77A5C561934E089" language="neutral" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
|
||||||
<assemblyIdentity name="System.Data.DataSetExtensions" version="4.0.0.0" publicKeyToken="B77A5C561934E089" language="neutral" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
|
||||||
<assemblyIdentity name="System.Deployment" version="4.0.0.0" publicKeyToken="B03F5F7F11D50A3A" language="neutral" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
|
||||||
<assemblyIdentity name="System.Drawing" version="4.0.0.0" publicKeyToken="B03F5F7F11D50A3A" language="neutral" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
|
||||||
<assemblyIdentity name="System.Net.Http" version="4.2.0.0" publicKeyToken="B03F5F7F11D50A3A" language="neutral" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
|
||||||
<assemblyIdentity name="System.Numerics" version="4.0.0.0" publicKeyToken="B77A5C561934E089" language="neutral" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
|
||||||
<assemblyIdentity name="System.Security" version="4.0.0.0" publicKeyToken="B03F5F7F11D50A3A" language="neutral" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
|
||||||
<assemblyIdentity name="System.Windows.Forms" version="4.0.0.0" publicKeyToken="B77A5C561934E089" language="neutral" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
|
||||||
<assemblyIdentity name="System.Xaml" version="4.0.0.0" publicKeyToken="B77A5C561934E089" language="neutral" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
|
||||||
<assemblyIdentity name="System.Xml" version="4.0.0.0" publicKeyToken="B77A5C561934E089" language="neutral" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
|
||||||
<assemblyIdentity name="System.Xml.Linq" version="4.0.0.0" publicKeyToken="B77A5C561934E089" language="neutral" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
|
||||||
<assemblyIdentity name="WindowsBase" version="4.0.0.0" publicKeyToken="31BF3856AD364E35" language="neutral" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="preRequisite" allowDelayedBinding="true">
|
|
||||||
<assemblyIdentity name="WindowsFormsIntegration" version="4.0.0.0" publicKeyToken="31BF3856AD364E35" language="neutral" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="CommunityToolkit.Mvvm.dll" size="115496">
|
|
||||||
<assemblyIdentity name="CommunityToolkit.Mvvm" version="8.3.0.0" publicKeyToken="4AFF67A105548EE2" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>6Jm7PxxMSE5OkBu7iJrppKUcBydJn1dv4z/0D/2bhio=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="MarcusLaw.OutlookAddin.dll" size="104960">
|
|
||||||
<assemblyIdentity name="MarcusLaw.OutlookAddin" version="1.0.7.0" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>UFDuAUnK7LIuno/5e6mwDuBGdKJjD6uv4mhSODRsaLI=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="MarcusLaw.OutlookAddin.Core.dll" size="94208">
|
|
||||||
<assemblyIdentity name="MarcusLaw.OutlookAddin.Core" version="1.0.0.0" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>AycV+vLsh7n9HMhrJdeglo3VQIc0GxGLYzffJuzQEKI=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="MarcusLaw.OutlookAddin.UI.dll" size="98816">
|
|
||||||
<assemblyIdentity name="MarcusLaw.OutlookAddin.UI" version="1.0.0.0" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>QrrK6ct5D6PUeQW7tkvGmMXXafUw1y/cYMzlf05OkWk=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="en-US\MarcusLaw.OutlookAddin.UI.resources.dll" size="7168">
|
|
||||||
<assemblyIdentity name="MarcusLaw.OutlookAddin.UI.resources" version="1.0.0.0" language="en-US" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>bwKiIldXtJujP3A/5q5LqYQmTcq5rk3P1IKlRHPF5ks=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="Microsoft.Bcl.AsyncInterfaces.dll" size="26904">
|
|
||||||
<assemblyIdentity name="Microsoft.Bcl.AsyncInterfaces" version="8.0.0.0" publicKeyToken="CC7B13FFCD2DDD51" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>gGeCA70CA6ZZT04zCyJUPA3lBZOCuxyTNLeGi48xsbw=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="Microsoft.Bcl.TimeProvider.dll" size="32528">
|
|
||||||
<assemblyIdentity name="Microsoft.Bcl.TimeProvider" version="8.0.0.0" publicKeyToken="CC7B13FFCD2DDD51" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>aTJCtn2pGveN2kuR1gIOC4zaCNTJECF3oSUiAJ75uUA=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="Microsoft.Extensions.Caching.Abstractions.dll" size="34464">
|
|
||||||
<assemblyIdentity name="Microsoft.Extensions.Caching.Abstractions" version="8.0.0.0" publicKeyToken="ADB9793829DDAE60" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>9SqzavfWhbalT0vUMnzHXHpjwQOdET0vxf4gYix1WxM=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="Microsoft.Extensions.Caching.Memory.dll" size="50984">
|
|
||||||
<assemblyIdentity name="Microsoft.Extensions.Caching.Memory" version="8.0.0.1" publicKeyToken="ADB9793829DDAE60" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>wv358DZn4LYfOU9AvtIkha8QuSsRT8pHei2JPVvfUB8=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="Microsoft.Extensions.DependencyInjection.Abstractions.dll" size="63784">
|
|
||||||
<assemblyIdentity name="Microsoft.Extensions.DependencyInjection.Abstractions" version="8.0.0.2" publicKeyToken="ADB9793829DDAE60" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>Ge3U9eaaRYncMUkJtYVKIvicS5qwQFkXcTl7LLGhe6Y=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="Microsoft.Extensions.Logging.Abstractions.dll" size="67880">
|
|
||||||
<assemblyIdentity name="Microsoft.Extensions.Logging.Abstractions" version="8.0.0.2" publicKeyToken="ADB9793829DDAE60" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>QBBtlRffKDtnxOXKG4YRVpA7fmvyDMzbFmSVRDFdQu4=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="Microsoft.Extensions.Options.dll" size="68768">
|
|
||||||
<assemblyIdentity name="Microsoft.Extensions.Options" version="8.0.0.2" publicKeyToken="ADB9793829DDAE60" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>c3DHL4ddmRGH4ntasuwkQro05v8nlQFTxmlq7JBVPF0=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="Microsoft.Extensions.Primitives.dll" size="49936">
|
|
||||||
<assemblyIdentity name="Microsoft.Extensions.Primitives" version="8.0.0.0" publicKeyToken="ADB9793829DDAE60" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>PG6lVZRDPi8DQCJ70ViPurG6ihDJkxm1KMxVcyWTQMs=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="Microsoft.Office.Tools.Common.v4.0.Utilities.dll" size="32664">
|
|
||||||
<assemblyIdentity name="Microsoft.Office.Tools.Common.v4.0.Utilities" version="10.0.0.0" publicKeyToken="B03F5F7F11D50A3A" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>jLCTF8Mm6bD4PDN+rnzN6q0+ReXaNgPh68kMWgatFwI=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="Microsoft.Office.Tools.Outlook.v4.0.Utilities.dll" size="49048">
|
|
||||||
<assemblyIdentity name="Microsoft.Office.Tools.Outlook.v4.0.Utilities" version="10.0.0.0" publicKeyToken="B03F5F7F11D50A3A" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>AY9f4ogMVBnNqNKvGc0Ko8U3XsIDeLhU/c5jky7x2Zc=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="Polly.dll" size="294960">
|
|
||||||
<assemblyIdentity name="Polly" version="8.0.0.0" publicKeyToken="C8A3FFC3F8F825CC" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>01vtaLqFx2ZiynhO4GgatEAd0Y1XmUo1AMI+CSIy5Ag=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="Polly.Core.dll" size="241712">
|
|
||||||
<assemblyIdentity name="Polly.Core" version="8.0.0.0" publicKeyToken="C8A3FFC3F8F825CC" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>rxJ4TrxMsT8aI+YQY5A92tKKH4VDZnPLN6QPyHLgZsI=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="Serilog.dll" size="154112">
|
|
||||||
<assemblyIdentity name="Serilog" version="4.0.0.0" publicKeyToken="24C2F752A8E58A10" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>E2b/L9D/pZ/Wsjo3IVAHEvDqtyucnyzPiJ0rn4CBiOQ=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="Serilog.Sinks.File.dll" size="32768">
|
|
||||||
<assemblyIdentity name="Serilog.Sinks.File" version="6.0.0.0" publicKeyToken="24C2F752A8E58A10" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>yZtkok6s9F6xTZBKEpT9bm3EbA/+YcU+p7nFj1TNsOM=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="System.Buffers.dll" size="20856">
|
|
||||||
<assemblyIdentity name="System.Buffers" version="4.0.3.0" publicKeyToken="CC7B13FFCD2DDD51" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>rMzPvkXZ8I/+7ZkW43sz6YxlvgEs//bn+ntnIQzh/vs=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="System.ComponentModel.Annotations.dll" size="43152">
|
|
||||||
<assemblyIdentity name="System.ComponentModel.Annotations" version="4.2.1.0" publicKeyToken="B03F5F7F11D50A3A" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>BBE8hUkYVRnzICeQzrI99glkSHK5wkmlbSvPWVZhAsQ=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="System.Diagnostics.DiagnosticSource.dll" size="189104">
|
|
||||||
<assemblyIdentity name="System.Diagnostics.DiagnosticSource" version="8.0.0.1" publicKeyToken="CC7B13FFCD2DDD51" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>GIdZJhX8CLvJGtYjB8jBHfwUxFvxINJx1mvkoNGhSac=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="System.Memory.dll" size="142240">
|
|
||||||
<assemblyIdentity name="System.Memory" version="4.0.1.2" publicKeyToken="CC7B13FFCD2DDD51" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>vz+4RmT0CX8aipvHGlHc+M8akF1AgKTSkNoXMIZuhW8=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="System.Numerics.Vectors.dll" size="115856">
|
|
||||||
<assemblyIdentity name="System.Numerics.Vectors" version="4.1.4.0" publicKeyToken="B03F5F7F11D50A3A" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>HT74aYKB589zcdFVSv71hys5+Wwm2nciEKM9oEG6EYM=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="System.Runtime.CompilerServices.Unsafe.dll" size="18024">
|
|
||||||
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" version="6.0.0.0" publicKeyToken="B03F5F7F11D50A3A" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>N3aEiOjvRXKbx9miZ3YzxkUAQpdbuWUW4YbabLnNDc8=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="System.Security.Cryptography.ProtectedData.dll" size="21776">
|
|
||||||
<assemblyIdentity name="System.Security.Cryptography.ProtectedData" version="8.0.0.0" publicKeyToken="B03F5F7F11D50A3A" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>N/qb7rtPZhOmNTeKfhRfkYfgk0cboq7VzfmuFIdKX3s=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="System.Text.Encodings.Web.dll" size="79024">
|
|
||||||
<assemblyIdentity name="System.Text.Encodings.Web" version="8.0.0.0" publicKeyToken="CC7B13FFCD2DDD51" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>6cT17tGGyxKcUnxLjWfRY+ovI5bp2LluMLXnwSIDzoQ=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="System.Text.Json.dll" size="644888">
|
|
||||||
<assemblyIdentity name="System.Text.Json" version="8.0.0.5" publicKeyToken="CC7B13FFCD2DDD51" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>hsPyY66bRGmrEmbIBHEIcIJEfrSjjmuXv16E3hXAeh0=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="System.Threading.Channels.dll" size="74000">
|
|
||||||
<assemblyIdentity name="System.Threading.Channels" version="8.0.0.0" publicKeyToken="CC7B13FFCD2DDD51" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>pC5FobuOZSjSRPhhHPHj5zHKtIGmeSjBvoFeY1/+jsc=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="System.Threading.Tasks.Extensions.dll" size="25984">
|
|
||||||
<assemblyIdentity name="System.Threading.Tasks.Extensions" version="4.2.0.1" publicKeyToken="CC7B13FFCD2DDD51" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>T4H/0NxyBNt1r8NepCkXabB8RAWS8oiUJg7qdmJqI8Y=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="System.ValueTuple.dll" size="25232">
|
|
||||||
<assemblyIdentity name="System.ValueTuple" version="4.0.3.0" publicKeyToken="CC7B13FFCD2DDD51" language="neutral" processorArchitecture="msil" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>6QXRAlhbIsbfBPIZr1y9v6e8Fll56XiLYt9tzBZeEPQ=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<file name="MarcusLaw.OutlookAddin.dll.config" size="1827">
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>uMegIvfUIIUq0XcXNVowCSN4iTs7XAuPmHY2Gb/9AR4=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</file>
|
|
||||||
<vstav3:addIn xmlns:vstav3="urn:schemas-microsoft-com:vsta.v3">
|
|
||||||
<vstav3:entryPointsCollection>
|
|
||||||
<vstav3:entryPoints>
|
|
||||||
<vstav3:entryPoint class="OutlookAddin.ThisAddIn">
|
|
||||||
<assemblyIdentity name="MarcusLaw.OutlookAddin" version="1.0.7.0" language="neutral" processorArchitecture="msil" />
|
|
||||||
</vstav3:entryPoint>
|
|
||||||
</vstav3:entryPoints>
|
|
||||||
</vstav3:entryPointsCollection>
|
|
||||||
<vstav3:update enabled="true">
|
|
||||||
<vstav3:expiration maximumAge="7" unit="days" />
|
|
||||||
</vstav3:update>
|
|
||||||
<vstav3:application>
|
|
||||||
<vstov4:customizations xmlns:vstov4="urn:schemas-microsoft-com:vsto.v4">
|
|
||||||
<vstov4:customization>
|
|
||||||
<vstov4:appAddIn application="Outlook" loadBehavior="3" keyName="MarcusLaw.OutlookAddin">
|
|
||||||
<vstov4:friendlyName>MarcusLaw.OutlookAddin</vstov4:friendlyName>
|
|
||||||
<vstov4:description>MarcusLaw.OutlookAddin</vstov4:description>
|
|
||||||
<vstov4.1:ribbonTypes xmlns:vstov4.1="urn:schemas-microsoft-com:vsto.v4.1" />
|
|
||||||
</vstov4:appAddIn>
|
|
||||||
</vstov4:customization>
|
|
||||||
</vstov4:customizations>
|
|
||||||
</vstav3:application>
|
|
||||||
</vstav3:addIn>
|
|
||||||
<publisherIdentity name="CN=HP-OFFICE1\Chaim" issuerKeyHash="461191bb791c8dcf6417521bc4cc018623c19538" /><Signature Id="StrongNameSignature" xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha256" /><Reference URI=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" /><DigestValue>wM13VCTBORPvZvtVa3YF66dro2pCcN8pucJyy+jTfoA=</DigestValue></Reference></SignedInfo><SignatureValue>dsDElqrcVTLfCKtMxmY/j7UatomYO80a72g8QUQgqIe4KmJyTr3gQkmu18UjhT2+mTbTIahwj03kIVNnAiFQK0FkGcK7HI758be3Wo0Ib3RDJevFegV/uNH5U4SImdPk1mHFoV7RuqB08ioQtHKd1VWi/vaEc8EVFCgRnLANrL4=</SignatureValue><KeyInfo Id="StrongNameKeyInfo"><KeyValue><RSAKeyValue><Modulus>xREBVt621l5WQ3HNT3kMrcZSyVcrSzXGDKTMvBwbaOmt7ZSsM5F8hZ+AQTmTC2BoXM8LeiP+wZAVU0MYokbWdHIG9TSqT5Uaud77qpDIfgJKk24CMS0ptE1PI4usLdwO1KyfRESHW8gxgVt0hAWuDudgI/EnOiyM5YRZNEf8Di0=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue></KeyValue><msrel:RelData xmlns:msrel="http://schemas.microsoft.com/windows/rel/2005/reldata"><r:license xmlns:r="urn:mpeg:mpeg21:2003:01-REL-R-NS" xmlns:as="http://schemas.microsoft.com/windows/pki/2005/Authenticode"><r:grant><as:ManifestInformation Hash="807ed3e8cb72c2b929df70426aa36ba7eb05766b55fb66ef1339c1245477cdc0" Description="" Url=""><as:assemblyIdentity name="MarcusLaw.OutlookAddin.dll" version="1.0.7.0" publicKeyToken="41d8d795775ea8cb" language="neutral" processorArchitecture="msil" type="win32" /></as:ManifestInformation><as:SignedBy /><as:AuthenticodePublisher><as:X509SubjectName>CN=HP-OFFICE1\Chaim</as:X509SubjectName></as:AuthenticodePublisher></r:grant><r:issuer><Signature Id="AuthenticodeSignature" xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha256" /><Reference URI=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" /><DigestValue>UgZbGtjRWoDrCAiV0IY5v0u4waIeDBt21bIbnTo2Cmk=</DigestValue></Reference></SignedInfo><SignatureValue>rksSK/JiE2/Zsf1ESCzwLUilq+7Vv9kThYx7oxnWU7vzliAUhTRl/smA0NNZqJLlrQ0KmNP79OR0Z4c9o7hnGr+q6fUfjoevcSKdSSaHkrLMU70b799w+A2mP3Bn01znZjncPW5/WUGq5euehFDkfCaPU9IEGKx62XFjh8QIq7c=</SignatureValue><KeyInfo><KeyValue><RSAKeyValue><Modulus>xREBVt621l5WQ3HNT3kMrcZSyVcrSzXGDKTMvBwbaOmt7ZSsM5F8hZ+AQTmTC2BoXM8LeiP+wZAVU0MYokbWdHIG9TSqT5Uaud77qpDIfgJKk24CMS0ptE1PI4usLdwO1KyfRESHW8gxgVt0hAWuDudgI/EnOiyM5YRZNEf8Di0=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue></KeyValue><X509Data><X509Certificate>MIIB2TCCAUKgAwIBAgIQc4FF18qP9L1B37xzsUPl3jANBgkqhkiG9w0BAQsFADArMSkwJwYDVQQDHiAASABQAC0ATwBGAEYASQBDAEUAMQBcAEMAaABhAGkAbTAeFw0yNjA1MTExMTQ0MDlaFw0yNzA1MTExNzQ0MDlaMCsxKTAnBgNVBAMeIABIAFAALQBPAEYARgBJAEMARQAxAFwAQwBoAGEAaQBtMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDFEQFW3rbWXlZDcc1PeQytxlLJVytLNcYMpMy8HBto6a3tlKwzkXyFn4BBOZMLYGhczwt6I/7BkBVTQxiiRtZ0cgb1NKpPlRq53vuqkMh+AkqTbgIxLSm0TU8ji6wt3A7UrJ9ERIdbyDGBW3SEBa4O52Aj8Sc6LIzlhFk0R/wOLQIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAFqX6W2LgF51biJUxrAe0KCZRG1YJsBhXyKf3RUDIWbyMuYmiwfIGKSEi5SX1wOD+4dF6+tBclK9pGOgqqNsfro67Mhdoo2HUhnrRXPUeqjgo5NR0qbxVYszhFBBBCjCxrDVjh8j7/lutwWUWGnF9mc3Bcw5GIHMZ+3d9T4IUYpI</X509Certificate></X509Data></KeyInfo></Signature></r:issuer></r:license></msrel:RelData></KeyInfo></Signature></asmv1:assembly>
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<asmv1:assembly xsi:schemaLocation="urn:schemas-microsoft-com:asm.v1 assembly.adaptive.xsd" manifestVersion="1.0" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns="urn:schemas-microsoft-com:asm.v2" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xrml="urn:mpeg:mpeg21:2003:01-REL-R-NS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:co.v1="urn:schemas-microsoft-com:clickonce.v1" xmlns:co.v2="urn:schemas-microsoft-com:clickonce.v2">
|
|
||||||
<assemblyIdentity name="MarcusLaw.OutlookAddin.vsto" version="1.0.7.0" publicKeyToken="41d8d795775ea8cb" language="neutral" processorArchitecture="msil" xmlns="urn:schemas-microsoft-com:asm.v1" />
|
|
||||||
<description asmv2:publisher="MarcusLaw.OutlookAddin" asmv2:product="MarcusLaw.OutlookAddin" xmlns="urn:schemas-microsoft-com:asm.v1" />
|
|
||||||
<deployment install="false" mapFileExtensions="true" />
|
|
||||||
<compatibleFrameworks xmlns="urn:schemas-microsoft-com:clickonce.v2">
|
|
||||||
<framework targetVersion="4.8" profile="Full" supportedRuntime="4.0.30319" />
|
|
||||||
</compatibleFrameworks>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" codebase="Application Files\MarcusLaw.OutlookAddin_1_0_7_0\MarcusLaw.OutlookAddin.dll.manifest" size="36548">
|
|
||||||
<assemblyIdentity name="MarcusLaw.OutlookAddin.dll" version="1.0.7.0" publicKeyToken="41d8d795775ea8cb" language="neutral" processorArchitecture="msil" type="win32" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>oFrXd0JDtHBok3bcmFLDAa5KFf5jBZVRZPJUYiSPakQ=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<publisherIdentity name="CN=HP-OFFICE1\Chaim" issuerKeyHash="461191bb791c8dcf6417521bc4cc018623c19538" /><Signature Id="StrongNameSignature" xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha256" /><Reference URI=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" /><DigestValue>AoiIvEZEDw5NCrymwVAvIW1PN4f6L/G/2Jw2WXuAemM=</DigestValue></Reference></SignedInfo><SignatureValue>dllu0k2mVVdH4KTiz7PQJQO5ZO3uO7Yzi5EGrzcM+SlFppRxFcu35Xgm82GLJ5UbsgzugIiHcq69HYsbYgqQ5KRAV2W2jFSLMbqXyXFTpGR3ZP/mV8DF9Od1Ha+Ul61ZPfLHqSsK+TyStc+P5DkiXnLkhKLqkUyWpSpVFlHGkNE=</SignatureValue><KeyInfo Id="StrongNameKeyInfo"><KeyValue><RSAKeyValue><Modulus>xREBVt621l5WQ3HNT3kMrcZSyVcrSzXGDKTMvBwbaOmt7ZSsM5F8hZ+AQTmTC2BoXM8LeiP+wZAVU0MYokbWdHIG9TSqT5Uaud77qpDIfgJKk24CMS0ptE1PI4usLdwO1KyfRESHW8gxgVt0hAWuDudgI/EnOiyM5YRZNEf8Di0=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue></KeyValue><msrel:RelData xmlns:msrel="http://schemas.microsoft.com/windows/rel/2005/reldata"><r:license xmlns:r="urn:mpeg:mpeg21:2003:01-REL-R-NS" xmlns:as="http://schemas.microsoft.com/windows/pki/2005/Authenticode"><r:grant><as:ManifestInformation Hash="637a807b59369cd8bff12ffa87374f6d212f50c1a6bc0a4d0e0f4446bc888802" Description="" Url=""><as:assemblyIdentity name="MarcusLaw.OutlookAddin.vsto" version="1.0.7.0" publicKeyToken="41d8d795775ea8cb" language="neutral" processorArchitecture="msil" xmlns="urn:schemas-microsoft-com:asm.v1" /></as:ManifestInformation><as:SignedBy /><as:AuthenticodePublisher><as:X509SubjectName>CN=HP-OFFICE1\Chaim</as:X509SubjectName></as:AuthenticodePublisher></r:grant><r:issuer><Signature Id="AuthenticodeSignature" xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha256" /><Reference URI=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" /><DigestValue>a2ZfU5jaiU9/spzQ38LrO3Oh5H1amjxMKA+UDGIxk88=</DigestValue></Reference></SignedInfo><SignatureValue>ASngBgbaDxF8ymTll++oets2qBL0KP7cDJTN34zncwwk2+I+ToCM0Mg7z1cwvQZftfxnKgcwKD5b57mIHIqj6Aklgyf3Bh5ifXN9kUIyNjHxhe905AYjBWHyKLQm+ld6V3eb+N8HJ7jYUewbevols9Mm3pQVYr8eWHL3FOp0dyA=</SignatureValue><KeyInfo><KeyValue><RSAKeyValue><Modulus>xREBVt621l5WQ3HNT3kMrcZSyVcrSzXGDKTMvBwbaOmt7ZSsM5F8hZ+AQTmTC2BoXM8LeiP+wZAVU0MYokbWdHIG9TSqT5Uaud77qpDIfgJKk24CMS0ptE1PI4usLdwO1KyfRESHW8gxgVt0hAWuDudgI/EnOiyM5YRZNEf8Di0=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue></KeyValue><X509Data><X509Certificate>MIIB2TCCAUKgAwIBAgIQc4FF18qP9L1B37xzsUPl3jANBgkqhkiG9w0BAQsFADArMSkwJwYDVQQDHiAASABQAC0ATwBGAEYASQBDAEUAMQBcAEMAaABhAGkAbTAeFw0yNjA1MTExMTQ0MDlaFw0yNzA1MTExNzQ0MDlaMCsxKTAnBgNVBAMeIABIAFAALQBPAEYARgBJAEMARQAxAFwAQwBoAGEAaQBtMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDFEQFW3rbWXlZDcc1PeQytxlLJVytLNcYMpMy8HBto6a3tlKwzkXyFn4BBOZMLYGhczwt6I/7BkBVTQxiiRtZ0cgb1NKpPlRq53vuqkMh+AkqTbgIxLSm0TU8ji6wt3A7UrJ9ERIdbyDGBW3SEBa4O52Aj8Sc6LIzlhFk0R/wOLQIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAFqX6W2LgF51biJUxrAe0KCZRG1YJsBhXyKf3RUDIWbyMuYmiwfIGKSEi5SX1wOD+4dF6+tBclK9pGOgqqNsfro67Mhdoo2HUhnrRXPUeqjgo5NR0qbxVYszhFBBBCjCxrDVjh8j7/lutwWUWGnF9mc3Bcw5GIHMZ+3d9T4IUYpI</X509Certificate></X509Data></KeyInfo></Signature></r:issuer></r:license></msrel:RelData></KeyInfo></Signature></asmv1:assembly>
|
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
@@ -1,21 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<asmv1:assembly xsi:schemaLocation="urn:schemas-microsoft-com:asm.v1 assembly.adaptive.xsd" manifestVersion="1.0" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns="urn:schemas-microsoft-com:asm.v2" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xrml="urn:mpeg:mpeg21:2003:01-REL-R-NS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:co.v1="urn:schemas-microsoft-com:clickonce.v1" xmlns:co.v2="urn:schemas-microsoft-com:clickonce.v2">
|
|
||||||
<assemblyIdentity name="MarcusLaw.OutlookAddin.vsto" version="1.0.7.0" publicKeyToken="41d8d795775ea8cb" language="neutral" processorArchitecture="msil" xmlns="urn:schemas-microsoft-com:asm.v1" />
|
|
||||||
<description asmv2:publisher="MarcusLaw.OutlookAddin" asmv2:product="MarcusLaw.OutlookAddin" xmlns="urn:schemas-microsoft-com:asm.v1" />
|
|
||||||
<deployment install="false" mapFileExtensions="true" />
|
|
||||||
<compatibleFrameworks xmlns="urn:schemas-microsoft-com:clickonce.v2">
|
|
||||||
<framework targetVersion="4.8" profile="Full" supportedRuntime="4.0.30319" />
|
|
||||||
</compatibleFrameworks>
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly dependencyType="install" codebase="Application Files\MarcusLaw.OutlookAddin_1_0_7_0\MarcusLaw.OutlookAddin.dll.manifest" size="36548">
|
|
||||||
<assemblyIdentity name="MarcusLaw.OutlookAddin.dll" version="1.0.7.0" publicKeyToken="41d8d795775ea8cb" language="neutral" processorArchitecture="msil" type="win32" />
|
|
||||||
<hash>
|
|
||||||
<dsig:Transforms>
|
|
||||||
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
|
|
||||||
</dsig:Transforms>
|
|
||||||
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
|
|
||||||
<dsig:DigestValue>oFrXd0JDtHBok3bcmFLDAa5KFf5jBZVRZPJUYiSPakQ=</dsig:DigestValue>
|
|
||||||
</hash>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
<publisherIdentity name="CN=HP-OFFICE1\Chaim" issuerKeyHash="461191bb791c8dcf6417521bc4cc018623c19538" /><Signature Id="StrongNameSignature" xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha256" /><Reference URI=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" /><DigestValue>AoiIvEZEDw5NCrymwVAvIW1PN4f6L/G/2Jw2WXuAemM=</DigestValue></Reference></SignedInfo><SignatureValue>dllu0k2mVVdH4KTiz7PQJQO5ZO3uO7Yzi5EGrzcM+SlFppRxFcu35Xgm82GLJ5UbsgzugIiHcq69HYsbYgqQ5KRAV2W2jFSLMbqXyXFTpGR3ZP/mV8DF9Od1Ha+Ul61ZPfLHqSsK+TyStc+P5DkiXnLkhKLqkUyWpSpVFlHGkNE=</SignatureValue><KeyInfo Id="StrongNameKeyInfo"><KeyValue><RSAKeyValue><Modulus>xREBVt621l5WQ3HNT3kMrcZSyVcrSzXGDKTMvBwbaOmt7ZSsM5F8hZ+AQTmTC2BoXM8LeiP+wZAVU0MYokbWdHIG9TSqT5Uaud77qpDIfgJKk24CMS0ptE1PI4usLdwO1KyfRESHW8gxgVt0hAWuDudgI/EnOiyM5YRZNEf8Di0=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue></KeyValue><msrel:RelData xmlns:msrel="http://schemas.microsoft.com/windows/rel/2005/reldata"><r:license xmlns:r="urn:mpeg:mpeg21:2003:01-REL-R-NS" xmlns:as="http://schemas.microsoft.com/windows/pki/2005/Authenticode"><r:grant><as:ManifestInformation Hash="637a807b59369cd8bff12ffa87374f6d212f50c1a6bc0a4d0e0f4446bc888802" Description="" Url=""><as:assemblyIdentity name="MarcusLaw.OutlookAddin.vsto" version="1.0.7.0" publicKeyToken="41d8d795775ea8cb" language="neutral" processorArchitecture="msil" xmlns="urn:schemas-microsoft-com:asm.v1" /></as:ManifestInformation><as:SignedBy /><as:AuthenticodePublisher><as:X509SubjectName>CN=HP-OFFICE1\Chaim</as:X509SubjectName></as:AuthenticodePublisher></r:grant><r:issuer><Signature Id="AuthenticodeSignature" xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha256" /><Reference URI=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" /><DigestValue>a2ZfU5jaiU9/spzQ38LrO3Oh5H1amjxMKA+UDGIxk88=</DigestValue></Reference></SignedInfo><SignatureValue>ASngBgbaDxF8ymTll++oets2qBL0KP7cDJTN34zncwwk2+I+ToCM0Mg7z1cwvQZftfxnKgcwKD5b57mIHIqj6Aklgyf3Bh5ifXN9kUIyNjHxhe905AYjBWHyKLQm+ld6V3eb+N8HJ7jYUewbevols9Mm3pQVYr8eWHL3FOp0dyA=</SignatureValue><KeyInfo><KeyValue><RSAKeyValue><Modulus>xREBVt621l5WQ3HNT3kMrcZSyVcrSzXGDKTMvBwbaOmt7ZSsM5F8hZ+AQTmTC2BoXM8LeiP+wZAVU0MYokbWdHIG9TSqT5Uaud77qpDIfgJKk24CMS0ptE1PI4usLdwO1KyfRESHW8gxgVt0hAWuDudgI/EnOiyM5YRZNEf8Di0=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue></KeyValue><X509Data><X509Certificate>MIIB2TCCAUKgAwIBAgIQc4FF18qP9L1B37xzsUPl3jANBgkqhkiG9w0BAQsFADArMSkwJwYDVQQDHiAASABQAC0ATwBGAEYASQBDAEUAMQBcAEMAaABhAGkAbTAeFw0yNjA1MTExMTQ0MDlaFw0yNzA1MTExNzQ0MDlaMCsxKTAnBgNVBAMeIABIAFAALQBPAEYARgBJAEMARQAxAFwAQwBoAGEAaQBtMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDFEQFW3rbWXlZDcc1PeQytxlLJVytLNcYMpMy8HBto6a3tlKwzkXyFn4BBOZMLYGhczwt6I/7BkBVTQxiiRtZ0cgb1NKpPlRq53vuqkMh+AkqTbgIxLSm0TU8ji6wt3A7UrJ9ERIdbyDGBW3SEBa4O52Aj8Sc6LIzlhFk0R/wOLQIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAFqX6W2LgF51biJUxrAe0KCZRG1YJsBhXyKf3RUDIWbyMuYmiwfIGKSEi5SX1wOD+4dF6+tBclK9pGOgqqNsfro67Mhdoo2HUhnrRXPUeqjgo5NR0qbxVYszhFBBBCjCxrDVjh8j7/lutwWUWGnF9mc3Bcw5GIHMZ+3d9T4IUYpI</X509Certificate></X509Data></KeyInfo></Signature></r:issuer></r:license></msrel:RelData></KeyInfo></Signature></asmv1:assembly>
|
|
||||||
Binary file not shown.
@@ -315,16 +315,11 @@ git push origin v1.0.1
|
|||||||
ה-CI ירוץ אוטומטית כמו בשחרור הראשון.
|
ה-CI ירוץ אוטומטית כמו בשחרור הראשון.
|
||||||
|
|
||||||
**אצל הלקוחות:**
|
**אצל הלקוחות:**
|
||||||
- ClickOnce בודק עדכון אוטומטית **כל 7 ימים** (הגדרה ב-csproj: `UpdateInterval=7`).
|
- ה־VSTO runtime בודק את ה-`.vsto` manifest **בכל פתיחה של Outlook** (משוחזר מ-`<UpdatePeriodically>false</UpdatePeriodically>` ב-csproj החל מ-v1.2.9; קודם זה היה פעם ב-7 ימים). הבדיקה היא GET של ~6KB, ~100ms — בלתי מורגש בזמן הטעינה.
|
||||||
- כדי **להאיץ** עדכון אצל לקוח מסויים:
|
- ה-CI מציב `/p:MinimumRequiredVersion=<tag>` בכל build, אז מיד כשהבדיקה מזהה גרסה חדשה — ההתקנה נכפית בלי דיאלוג.
|
||||||
1. סגור את Outlook לגמרי.
|
- **תרגום מעשי**: 30 שניות אחרי `git push --tags` ה-CI מסיים → תוך 2-3 דקות החבילה נדחפת ל-CDN → בכניסה הבאה של כל אחד מהלקוחות ל-Outlook הוא רץ על הגרסה החדשה. **בלי שום פעולה ידנית מצידם**.
|
||||||
2. פתח את Outlook שוב.
|
- **הכפתור "בדוק עדכונים" בהגדרות** רק מודיע ("זמינה גרסה X — סגור ופתח Outlook"). הוא לא יכול להתקין מתוך תהליך Outlook רץ — `VSTOInstaller.exe` לא יכול לדרוס DLLs נעולים, וה-ApplicationDeployment API נכשל ב-`TrustNotGrantedException` בהקשר VSTO. ההתקנה תמיד קורית רק דרך ה-runtime בעלייה של Outlook. [פירוט בזיכרון: feedback_vsto_updater_api.md]
|
||||||
3. אם עברו לפחות 7 ימים מבדיקת ה-update הקודמת — יבדוק עכשיו ויעדכן.
|
- **תקלה נדירה — לקוח שהותקן ידנית עם dev cert** (`HP-OFFICE1\<user>`, publicKeyToken `41d8d795775ea8cb`) לא יכול לעבור auto-update לגרסת prod cert (`Marcus-Law OutlookAddin`, publicKeyToken `c68d2b4c25051c5b`) — ClickOnce מתייחס אליהן כשתי אפליקציות שונות. **פעם אחת**: Apps & Features → uninstall של MarcusLaw.OutlookAddin → התקנה חדשה מ-`https://platform.dev.marcus-law.co.il/outlook-addin/OutlookAddin.vsto`. אחרי זה auto-update עובד.
|
||||||
4. אם לא — אפשר לנקות את ה-ClickOnce cache:
|
|
||||||
```powershell
|
|
||||||
rundll32.exe dfshim.dll,CleanOnlineAppCache
|
|
||||||
```
|
|
||||||
ואז לפתוח שוב את `https://platform.dev.marcus-law.co.il/outlook-addin/OutlookAddin.vsto`.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -268,14 +268,47 @@ If the session is on the Linux dev server (`/home/chaim/espocrm-extensions/Outlo
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## How releases work (current, 2026-05-24)
|
||||||
|
|
||||||
|
**Production install URL:** `https://platform.dev.marcus-law.co.il/outlook-addin/OutlookAddin.vsto`
|
||||||
|
|
||||||
|
**Release flow:**
|
||||||
|
|
||||||
|
1. Code change merged to `main` (push or PR-merge — no CI fires yet)
|
||||||
|
2. Bump `<ApplicationVersion>` in `src/OutlookAddin/OutlookAddin.csproj` and `AssemblyVersion` + `AssemblyFileVersion` in `src/OutlookAddin/Properties/AssemblyInfo.cs` to the next 4-part version (e.g. `1.2.1.0`). CI overrides `ApplicationVersion` from the tag at build time, but leaves AssemblyInfo alone — keep them in sync manually so the bundled DLL's FileVersion matches the manifest.
|
||||||
|
3. `git tag -a v1.2.1 -m "..." && git push --tags`
|
||||||
|
4. Gitea Actions workflow (`.gitea/workflows/build.yml`) fires:
|
||||||
|
- Imports the **real** codesign cert from secrets `CODESIGN_CERT_PFX_BASE64` + `CODESIGN_THUMBPRINT` (publicKeyToken `c68d2b4c25051c5b`, `CN=Marcus-Law OutlookAddin`)
|
||||||
|
- Patches csproj to swap the dev self-signed thumbprint (`2399E9BF…`) for the real one
|
||||||
|
- `msbuild /t:Publish` with `/p:InstallUrl=https://platform.dev.marcus-law.co.il/outlook-addin/` and `/p:ApplicationVersion=<tag>.0`
|
||||||
|
- Uploads `publish.tar.gz` to Gitea generic registry (`outlook-addin-publish/<version>/publish.tar.gz`)
|
||||||
|
- Linux job downloads the tar.gz, builds a Docker image `outlook-addin-cdn:latest`, pushes to Gitea registry, calls Coolify to redeploy the CDN container
|
||||||
|
- Posts to Mattermost channel `git-verelasim` with the install URL on success / a failure link on failure
|
||||||
|
5. Lawyers' installed Add-in checks the deployment manifest at the install URL **on every Outlook startup** (csproj has `<UpdatePeriodically>false</UpdatePeriodically>` since v1.2.9 — earlier versions waited up to 7 days). The check is a single ~6 KB HTTP GET, ~100 ms. Combined with the CI setting `/p:MinimumRequiredVersion=<tag>` per build, this means every tagged release lands on every lawyer's PC the next time they open Outlook, silently and without prompts.
|
||||||
|
|
||||||
|
**Semver policy:** PATCH for bug fixes (unilateral), MINOR for visible features (unilateral when warranted), MAJOR only with Chaim's explicit approval.
|
||||||
|
|
||||||
|
**Branding (`KlearBranding` repo):** the product is presented to lawyers as **Klear** — title bars, MessageBox titles, ribbon group label, About header all say "Klear". The logo is mirrored from `espocrm-extensions/KlearBranding/files/client/custom/img/logo-klear.png` into `src/OutlookAddin.UI/Resources/logo-klear.png` and embedded as a WPF Resource. Brand accent color: `#121d2e` (dark navy).
|
||||||
|
|
||||||
|
**What stays MarcusLaw under the hood (deliberate — preserves auto-update across the rebrand):**
|
||||||
|
- ClickOnce app identity (`AssemblyName=MarcusLaw.OutlookAddin`)
|
||||||
|
- `%APPDATA%\MarcusLaw\OutlookAddin\settings.json` and `creds.dat`
|
||||||
|
- `%LOCALAPPDATA%\MarcusLaw\OutlookAddin\logs\`
|
||||||
|
- `DpapiCredentialStore.EntropySeed = "MarcusLaw.OutlookAddin.v1"`
|
||||||
|
- Code namespaces `MarcusLaw.OutlookAddin.*`
|
||||||
|
- Named pipe `MarcusLaw.OutlookAddin`
|
||||||
|
|
||||||
|
Changing any of these would orphan all existing installs and require a coordinated uninstall+reinstall on every lawyer's PC plus an entropy migration for DPAPI-encrypted credentials. See the LegalCRM rebrand misadventure in git history for what *not* to do.
|
||||||
|
|
||||||
|
**Known traps when releasing:**
|
||||||
|
- VS Publish wizard (Project Properties → Publish) **rewrites** csproj at every click — flips `<AutoIncrementApplicationRevision>` back to `true`, resets `<ApplicationVersion>` to whatever's in the UI, sometimes deletes prior `Application Files/<...>/` bundles. **Don't use it.** Tag and let CI do it.
|
||||||
|
- There's an old `Publish/` directory in git history that was a parallel manual-release channel via `gitea.../raw/branch/main/Publish/`. It's **not the production install URL** — that's platform.dev. The folder was dropped in v1.2.0.
|
||||||
|
|
||||||
## Things deliberately deferred
|
## Things deliberately deferred
|
||||||
|
|
||||||
| What | When | Why deferred |
|
| What | When | Why deferred |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| Windows CI runner on Coolify | Until ClickOnce publish becomes useful | Local builds on dev's VS 2022 suffice through week 5 |
|
| Identity-level rebrand to a pure Klear product (AssemblyName, namespaces, DPAPI entropy, AppData paths) | Until there's another reason to force-reinstall on all 10 PCs | Visible rebrand already done in v1.2.0 without disrupting users; full rename trades aesthetic cleanliness for a day of IT coordination + lost credentials |
|
||||||
| Code signing cert (self-signed) + GPO push to 10 PCs | Week 6 (before release) | IT task; cert isn't useful until we have something to sign |
|
|
||||||
| ClickOnce hosting setup at `platform.dev.marcus-law.co.il/outlook-addin/` | Week 6 | No build artifacts yet |
|
|
||||||
| Mattermost release notification webhook in CI | Week 6 | Coupled to CI runner |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -213,13 +213,29 @@ namespace MarcusLaw.OutlookAddin.Core.Services
|
|||||||
// is sent in the "file" field as a data-URI. The previous extra
|
// is sent in the "file" field as a data-URI. The previous extra
|
||||||
// "contents" alias was an undocumented legacy that strict tenants
|
// "contents" alias was an undocumented legacy that strict tenants
|
||||||
// reject with 400.
|
// reject with 400.
|
||||||
|
//
|
||||||
|
// We bind the upload to Note.attachments (parentType=Note,
|
||||||
|
// field=attachments). EspoCRM's attachment access checker now
|
||||||
|
// REJECTS a role=Attachment upload that carries neither `field`
|
||||||
|
// nor `parentType` ("No `field` and `parentType`." → 400) — the
|
||||||
|
// earlier "unbound blob" shape no longer passes. Note.attachments
|
||||||
|
// is the documented Attachment-Multiple example and a built-in
|
||||||
|
// field that carries NO "allowed file types" restriction, so every
|
||||||
|
// file type (PDF, JPEG, PNG, …) passes — unlike Document.file,
|
||||||
|
// which Marcus-Law limits to PDF/Word and which rejected images
|
||||||
|
// with 403 "Not allowed file type".
|
||||||
|
//
|
||||||
|
// We never set parentId / create a Note: the attachment stays a
|
||||||
|
// standalone blob whose id we immediately push to the network
|
||||||
|
// share. The (parentType, field) pair only satisfies the access
|
||||||
|
// checker and selects an unrestricted file-type policy.
|
||||||
var payload = new Dictionary<string, object?>
|
var payload = new Dictionary<string, object?>
|
||||||
{
|
{
|
||||||
["name"] = fileName,
|
["name"] = fileName,
|
||||||
["type"] = mime,
|
["type"] = mime,
|
||||||
["role"] = "Attachment",
|
["role"] = "Attachment",
|
||||||
["relatedType"] = "Document",
|
["parentType"] = "Note",
|
||||||
["field"] = "file",
|
["field"] = "attachments",
|
||||||
["file"] = dataUri
|
["file"] = dataUri
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
<Window x:Class="MarcusLaw.OutlookAddin.UI.Dialogs.ComposeFromCaseDialog"
|
<Window x:Class="MarcusLaw.OutlookAddin.UI.Dialogs.ComposeFromCaseDialog"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:conv="clr-namespace:MarcusLaw.OutlookAddin.UI.Converters"
|
||||||
Title="כתוב מייל מתיק"
|
Title="כתוב מייל מתיק"
|
||||||
Height="480" Width="600"
|
Height="520" Width="680"
|
||||||
MinHeight="320" MinWidth="500"
|
MinHeight="360" MinWidth="540"
|
||||||
FlowDirection="RightToLeft"
|
FlowDirection="RightToLeft"
|
||||||
WindowStartupLocation="CenterOwner"
|
WindowStartupLocation="CenterOwner"
|
||||||
ShowInTaskbar="False"
|
ShowInTaskbar="False"
|
||||||
@@ -11,6 +12,7 @@
|
|||||||
Background="#F8FAFC"
|
Background="#F8FAFC"
|
||||||
FontFamily="Segoe UI, David, Frank Ruehl, Arial">
|
FontFamily="Segoe UI, David, Frank Ruehl, Arial">
|
||||||
<Window.Resources>
|
<Window.Resources>
|
||||||
|
<conv:CaseStatusToHebrewConverter x:Key="CaseStatusHe" />
|
||||||
<SolidColorBrush x:Key="Primary" Color="#2563EB" />
|
<SolidColorBrush x:Key="Primary" Color="#2563EB" />
|
||||||
<SolidColorBrush x:Key="PrimaryHover" Color="#1D4ED8" />
|
<SolidColorBrush x:Key="PrimaryHover" Color="#1D4ED8" />
|
||||||
<SolidColorBrush x:Key="Border" Color="#E2E8F0" />
|
<SolidColorBrush x:Key="Border" Color="#E2E8F0" />
|
||||||
@@ -134,24 +136,30 @@
|
|||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<Border Grid.Row="1" Style="{StaticResource Card}">
|
<Border Grid.Row="1" Style="{StaticResource Card}">
|
||||||
<ListBox ItemsSource="{Binding Cases}"
|
<DataGrid ItemsSource="{Binding Cases}"
|
||||||
SelectedItem="{Binding SelectedCase}"
|
SelectedItem="{Binding SelectedCase}"
|
||||||
BorderThickness="0"
|
AutoGenerateColumns="False"
|
||||||
Background="Transparent"
|
HeadersVisibility="Column"
|
||||||
ItemContainerStyle="{StaticResource ResultItem}"
|
GridLinesVisibility="Horizontal"
|
||||||
Padding="4">
|
HorizontalGridLinesBrush="#E2E8F0"
|
||||||
<ListBox.ItemTemplate>
|
RowBackground="White"
|
||||||
<DataTemplate>
|
AlternatingRowBackground="#F8FAFC"
|
||||||
<StackPanel>
|
BorderThickness="0"
|
||||||
<TextBlock FontSize="13">
|
CanUserAddRows="False"
|
||||||
<Run Text="[" /><Run Text="{Binding Number, Mode=OneWay}" /><Run Text="] " />
|
CanUserDeleteRows="False"
|
||||||
<Run Text="{Binding Name, Mode=OneWay}" FontWeight="SemiBold" />
|
CanUserResizeRows="False"
|
||||||
</TextBlock>
|
CanUserReorderColumns="False"
|
||||||
<TextBlock Text="{Binding Status}" Foreground="{StaticResource Muted}" FontSize="11" />
|
SelectionMode="Single"
|
||||||
</StackPanel>
|
SelectionUnit="FullRow"
|
||||||
</DataTemplate>
|
IsReadOnly="True"
|
||||||
</ListBox.ItemTemplate>
|
RowHeight="30">
|
||||||
</ListBox>
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Header="מס׳ תיק" Binding="{Binding Number}" Width="80" />
|
||||||
|
<DataGridTextColumn Header="שם" Binding="{Binding Name}" Width="*" />
|
||||||
|
<DataGridTextColumn Header="מס׳ בבית משפט" Binding="{Binding CourtCaseNumber}" Width="140" />
|
||||||
|
<DataGridTextColumn Header="סטטוס" Binding="{Binding Status, Converter={StaticResource CaseStatusHe}}" Width="110" />
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<TextBlock Grid.Row="2" Text="{Binding StatusMessage}"
|
<TextBlock Grid.Row="2" Text="{Binding StatusMessage}"
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:conv="clr-namespace:MarcusLaw.OutlookAddin.UI.Converters"
|
xmlns:conv="clr-namespace:MarcusLaw.OutlookAddin.UI.Converters"
|
||||||
Title="שמור קבצים מצורפים ל-Klear"
|
Title="שמור קבצים מצורפים ל-Klear"
|
||||||
Height="560" Width="620"
|
Height="640" Width="620"
|
||||||
MinHeight="420" MinWidth="500"
|
MinHeight="480" MinWidth="500"
|
||||||
FlowDirection="RightToLeft"
|
FlowDirection="RightToLeft"
|
||||||
WindowStartupLocation="CenterOwner"
|
WindowStartupLocation="CenterOwner"
|
||||||
ShowInTaskbar="False"
|
ShowInTaskbar="False"
|
||||||
@@ -144,24 +144,38 @@
|
|||||||
|
|
||||||
<!-- Folder -->
|
<!-- Folder -->
|
||||||
<DockPanel Grid.Row="2" Margin="0,10,0,0" LastChildFill="True">
|
<DockPanel Grid.Row="2" Margin="0,10,0,0" LastChildFill="True">
|
||||||
<TextBlock DockPanel.Dock="Left" Text="תיקייה:" VerticalAlignment="Center"
|
<DockPanel DockPanel.Dock="Top" LastChildFill="True" Margin="0,0,0,4">
|
||||||
Margin="0,0,8,0" Foreground="{StaticResource Muted}" FontSize="12" />
|
<TextBlock DockPanel.Dock="Left" Text="תיקיית יעד:" VerticalAlignment="Center"
|
||||||
<TextBlock DockPanel.Dock="Right" Text="טוען…" VerticalAlignment="Center"
|
Margin="0,0,8,0" Foreground="{StaticResource Muted}" FontSize="12" />
|
||||||
Margin="8,0,0,0" Foreground="{StaticResource Muted}" FontSize="12"
|
<TextBlock DockPanel.Dock="Right" Text="טוען…" VerticalAlignment="Center"
|
||||||
Visibility="{Binding IsLoadingSubfolders, Converter={StaticResource BoolToVis}}" />
|
Margin="8,0,0,0" Foreground="{StaticResource Muted}" FontSize="12"
|
||||||
<ComboBox ItemsSource="{Binding Subfolders}"
|
Visibility="{Binding IsLoadingSubfolders, Converter={StaticResource BoolToVis}}" />
|
||||||
SelectedItem="{Binding SelectedSubfolder}"
|
<TextBlock Text="בחר/י תיקייה או תת-תיקייה לשמירה (ניתן להרחיב רמות)"
|
||||||
Padding="6,4">
|
VerticalAlignment="Center" Foreground="{StaticResource Muted}" FontSize="11"
|
||||||
<ComboBox.Style>
|
TextTrimming="CharacterEllipsis" />
|
||||||
<Style TargetType="ComboBox">
|
</DockPanel>
|
||||||
<Style.Triggers>
|
<Border Style="{StaticResource Card}" MaxHeight="150">
|
||||||
<DataTrigger Binding="{Binding IsLoadingSubfolders}" Value="True">
|
<TreeView x:Name="FolderTreeView"
|
||||||
<Setter Property="IsEnabled" Value="False" />
|
ItemsSource="{Binding FolderTree}"
|
||||||
</DataTrigger>
|
BorderThickness="0"
|
||||||
</Style.Triggers>
|
Background="Transparent"
|
||||||
</Style>
|
SelectedItemChanged="FolderTreeView_SelectedItemChanged">
|
||||||
</ComboBox.Style>
|
<TreeView.ItemContainerStyle>
|
||||||
</ComboBox>
|
<Style TargetType="TreeViewItem">
|
||||||
|
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
|
||||||
|
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
|
||||||
|
</Style>
|
||||||
|
</TreeView.ItemContainerStyle>
|
||||||
|
<TreeView.ItemTemplate>
|
||||||
|
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
|
||||||
|
<StackPanel Orientation="Horizontal" Margin="0,1">
|
||||||
|
<TextBlock Text="📁" Margin="0,0,4,0" FontSize="13" VerticalAlignment="Center" />
|
||||||
|
<TextBlock Text="{Binding Name}" VerticalAlignment="Center" FontSize="13" />
|
||||||
|
</StackPanel>
|
||||||
|
</HierarchicalDataTemplate>
|
||||||
|
</TreeView.ItemTemplate>
|
||||||
|
</TreeView>
|
||||||
|
</Border>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
|
|
||||||
<!-- Attachments header -->
|
<!-- Attachments header -->
|
||||||
|
|||||||
@@ -32,5 +32,15 @@ namespace MarcusLaw.OutlookAddin.UI.Dialogs
|
|||||||
DialogResult = _viewModel?.DialogResult;
|
DialogResult = _viewModel?.DialogResult;
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WPF's TreeView.SelectedItem is read-only, so we mirror the selection
|
||||||
|
// into the view-model here (the chosen node drives the save target).
|
||||||
|
private void FolderTreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
|
||||||
|
{
|
||||||
|
if (_viewModel != null)
|
||||||
|
{
|
||||||
|
_viewModel.SelectedFolder = e.NewValue as FolderNodeViewModel;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,8 +98,19 @@
|
|||||||
|
|
||||||
<TabItem Header="אודות">
|
<TabItem Header="אודות">
|
||||||
<StackPanel Margin="16">
|
<StackPanel Margin="16">
|
||||||
<TextBlock Text="Marcus-Law OutlookAddin" FontWeight="Bold" FontSize="16" />
|
<Border Background="#121d2e" CornerRadius="6" Padding="14,12" Margin="0,0,0,12">
|
||||||
<TextBlock Text="תוסף Klear ל-Microsoft Outlook" Margin="0,4,0,12" />
|
<DockPanel LastChildFill="True">
|
||||||
|
<Image DockPanel.Dock="Right"
|
||||||
|
Source="pack://application:,,,/MarcusLaw.OutlookAddin.UI;component/Resources/logo-klear.png"
|
||||||
|
Height="36"
|
||||||
|
Margin="12,0,0,0"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
<StackPanel VerticalAlignment="Center">
|
||||||
|
<TextBlock Text="Klear" Foreground="White" FontWeight="Bold" FontSize="18" />
|
||||||
|
<TextBlock Text="תוסף ל-Microsoft Outlook" Foreground="#CBD5E1" FontSize="12" />
|
||||||
|
</StackPanel>
|
||||||
|
</DockPanel>
|
||||||
|
</Border>
|
||||||
<DockPanel LastChildFill="False" Margin="0,0,0,4">
|
<DockPanel LastChildFill="False" Margin="0,0,0,4">
|
||||||
<TextBlock DockPanel.Dock="Left" Text="{Binding VersionLine}" Foreground="Gray" VerticalAlignment="Center" />
|
<TextBlock DockPanel.Dock="Left" Text="{Binding VersionLine}" Foreground="Gray" VerticalAlignment="Center" />
|
||||||
<Button DockPanel.Dock="Right"
|
<Button DockPanel.Dock="Right"
|
||||||
@@ -112,10 +123,22 @@
|
|||||||
Foreground="{Binding UpdateStatusBrush}"
|
Foreground="{Binding UpdateStatusBrush}"
|
||||||
TextWrapping="Wrap"
|
TextWrapping="Wrap"
|
||||||
Margin="0,4,0,0" />
|
Margin="0,4,0,0" />
|
||||||
<TextBlock Margin="0,16,0,0" TextWrapping="Wrap"
|
<TextBlock Margin="0,16,0,0" TextWrapping="Wrap">
|
||||||
Text="לוגים: %LOCALAPPDATA%\MarcusLaw\OutlookAddin\logs" />
|
<Run Text="לוגים: " />
|
||||||
<TextBlock TextWrapping="Wrap"
|
<Hyperlink Tag="%LOCALAPPDATA%\MarcusLaw\OutlookAddin\logs"
|
||||||
Text="הגדרות: %APPDATA%\MarcusLaw\OutlookAddin\settings.json" />
|
Click="OnOpenFolderHyperlink"
|
||||||
|
ToolTip="פתח את התיקייה ב-Explorer">
|
||||||
|
<Run Text="%LOCALAPPDATA%\MarcusLaw\OutlookAddin\logs" />
|
||||||
|
</Hyperlink>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock TextWrapping="Wrap">
|
||||||
|
<Run Text="הגדרות: " />
|
||||||
|
<Hyperlink Tag="%APPDATA%\MarcusLaw\OutlookAddin"
|
||||||
|
Click="OnOpenFolderHyperlink"
|
||||||
|
ToolTip="פתח את התיקייה ב-Explorer">
|
||||||
|
<Run Text="%APPDATA%\MarcusLaw\OutlookAddin\settings.json" />
|
||||||
|
</Hyperlink>
|
||||||
|
</TextBlock>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
</TabControl>
|
</TabControl>
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using System.Windows.Documents;
|
||||||
using MarcusLaw.OutlookAddin.UI.ViewModels;
|
using MarcusLaw.OutlookAddin.UI.ViewModels;
|
||||||
|
|
||||||
namespace MarcusLaw.OutlookAddin.UI.Dialogs
|
namespace MarcusLaw.OutlookAddin.UI.Dialogs
|
||||||
@@ -40,5 +43,23 @@ namespace MarcusLaw.OutlookAddin.UI.Dialogs
|
|||||||
DialogResult = _viewModel?.DialogResult;
|
DialogResult = _viewModel?.DialogResult;
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnOpenFolderHyperlink(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (!(sender is Hyperlink h) || !(h.Tag is string raw)) return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var path = Environment.ExpandEnvironmentVariables(raw);
|
||||||
|
// Create the folder lazily so the link works even on the very
|
||||||
|
// first run, before any log has been written.
|
||||||
|
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
||||||
|
Process.Start(new ProcessStartInfo("explorer.exe", "\"" + path + "\"") { UseShellExecute = true });
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show("פתיחת התיקייה נכשלה: " + ex.Message, "Klear",
|
||||||
|
MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,4 +25,8 @@
|
|||||||
<ProjectReference Include="..\OutlookAddin.Core\OutlookAddin.Core.csproj" />
|
<ProjectReference Include="..\OutlookAddin.Core\OutlookAddin.Core.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Resource Include="Resources\logo-klear.png" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -74,20 +75,36 @@ namespace MarcusLaw.OutlookAddin.UI.ViewModels
|
|||||||
ct.ThrowIfCancellationRequested();
|
ct.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
Cases.Clear();
|
Cases.Clear();
|
||||||
int kept = 0;
|
var caseHits = new List<EspoEntityRef>();
|
||||||
foreach (var hit in search.List)
|
foreach (var hit in search.List)
|
||||||
{
|
{
|
||||||
if (!string.Equals(hit.EntityType, "Case", StringComparison.OrdinalIgnoreCase)) continue;
|
if (string.Equals(hit.EntityType, "Case", StringComparison.OrdinalIgnoreCase))
|
||||||
Cases.Add(new CaseEntity
|
caseHits.Add(hit);
|
||||||
{
|
|
||||||
Id = hit.Id,
|
|
||||||
Name = hit.Name,
|
|
||||||
});
|
|
||||||
kept++;
|
|
||||||
}
|
}
|
||||||
StatusMessage = kept == 0
|
|
||||||
? "אין תוצאות מסוג תיק (Case)"
|
if (caseHits.Count == 0)
|
||||||
: $"נמצאו {kept} תיקים";
|
{
|
||||||
|
StatusMessage = "אין תוצאות מסוג תיק (Case)";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GlobalSearch only returns id+name. Hydrate each hit with
|
||||||
|
// number+status (and the Hebrew case name when present) so the
|
||||||
|
// picker shows the same columns the file-attachments picker
|
||||||
|
// does.
|
||||||
|
var detailTasks = new List<Task<CaseEntity?>>(caseHits.Count);
|
||||||
|
foreach (var hit in caseHits)
|
||||||
|
{
|
||||||
|
detailTasks.Add(LoadCaseRowAsync(hit, ct));
|
||||||
|
}
|
||||||
|
var details = await Task.WhenAll(detailTasks).ConfigureAwait(true);
|
||||||
|
ct.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
foreach (var row in details)
|
||||||
|
{
|
||||||
|
if (row != null) Cases.Add(row);
|
||||||
|
}
|
||||||
|
StatusMessage = $"נמצאו {Cases.Count} תיקים";
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException) { /* superseded */ }
|
catch (OperationCanceledException) { /* superseded */ }
|
||||||
catch (EspoCrmAuthorizationException)
|
catch (EspoCrmAuthorizationException)
|
||||||
@@ -101,6 +118,27 @@ namespace MarcusLaw.OutlookAddin.UI.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<CaseEntity?> LoadCaseRowAsync(EspoEntityRef hit, CancellationToken ct)
|
||||||
|
{
|
||||||
|
var row = new CaseEntity { Id = hit.Id, Name = hit.Name };
|
||||||
|
if (string.IsNullOrEmpty(hit.Id)) return row;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var detail = await _client.GetCaseAsync(
|
||||||
|
hit.Id, "id,name,number,status,cCourtCaseNumber", ct).ConfigureAwait(false);
|
||||||
|
row.Number = detail.Number;
|
||||||
|
row.Status = detail.Status;
|
||||||
|
row.CourtCaseNumber = detail.CourtCaseNumber;
|
||||||
|
if (!string.IsNullOrEmpty(detail.Name)) row.Name = detail.Name;
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException) { throw; }
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Warning(ex, "ComposeFromCase: hydrating case {CaseId} failed", hit.Id);
|
||||||
|
}
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
[RelayCommand(CanExecute = nameof(CanSubmit))]
|
[RelayCommand(CanExecute = nameof(CanSubmit))]
|
||||||
private void Submit()
|
private void Submit()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,168 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Threading;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using MarcusLaw.OutlookAddin.Core.Services;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace MarcusLaw.OutlookAddin.UI.ViewModels
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// One node in the network-storage folder tree shown by the
|
||||||
|
/// save-attachments dialog. Children are listed lazily the first time the
|
||||||
|
/// node is expanded, so the user can drill into nested subfolders to any
|
||||||
|
/// depth without us listing the whole tree up front.
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class FolderNodeViewModel : ObservableObject
|
||||||
|
{
|
||||||
|
private readonly IEspoCrmClient? _client;
|
||||||
|
private readonly ILogger? _logger;
|
||||||
|
private readonly Dispatcher? _dispatcher;
|
||||||
|
private bool _childrenLoaded;
|
||||||
|
private bool _loadingStarted;
|
||||||
|
|
||||||
|
/// <summary>Label shown in the tree.</summary>
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Path relative to the share root (e.g. "56-ליאור זייני/מסמכים").
|
||||||
|
/// Used to list this folder's children. Empty for placeholders.
|
||||||
|
/// </summary>
|
||||||
|
public string FullPath { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Path relative to the case-root folder (e.g. "מסמכים/רפואי"), or
|
||||||
|
/// null for the case-root node itself. This is what the save target
|
||||||
|
/// appends to the resolved case folder.
|
||||||
|
/// </summary>
|
||||||
|
public string? RelativePath { get; }
|
||||||
|
|
||||||
|
/// <summary>True for the transient "loading…" child placeholder.</summary>
|
||||||
|
public bool IsPlaceholder { get; }
|
||||||
|
|
||||||
|
public bool IsRoot => !IsPlaceholder && RelativePath == null;
|
||||||
|
|
||||||
|
public ObservableCollection<FolderNodeViewModel> Children { get; } =
|
||||||
|
new ObservableCollection<FolderNodeViewModel>();
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool isExpanded;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool isSelected;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool isLoading;
|
||||||
|
|
||||||
|
/// <summary>Real folder node.</summary>
|
||||||
|
public FolderNodeViewModel(
|
||||||
|
IEspoCrmClient client,
|
||||||
|
ILogger logger,
|
||||||
|
Dispatcher dispatcher,
|
||||||
|
string name,
|
||||||
|
string fullPath,
|
||||||
|
string? relativePath)
|
||||||
|
{
|
||||||
|
_client = client ?? throw new ArgumentNullException(nameof(client));
|
||||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
|
_dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
|
||||||
|
Name = name;
|
||||||
|
FullPath = fullPath;
|
||||||
|
RelativePath = relativePath;
|
||||||
|
// A placeholder child makes the expand chevron appear before we've
|
||||||
|
// listed; expanding swaps it for the real children (or, if there
|
||||||
|
// are none, the node becomes a leaf).
|
||||||
|
Children.Add(new FolderNodeViewModel());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Placeholder ("loading…") node constructor.</summary>
|
||||||
|
private FolderNodeViewModel()
|
||||||
|
{
|
||||||
|
Name = "טוען…";
|
||||||
|
FullPath = string.Empty;
|
||||||
|
RelativePath = string.Empty;
|
||||||
|
IsPlaceholder = true;
|
||||||
|
_childrenLoaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnIsExpandedChanged(bool value)
|
||||||
|
{
|
||||||
|
if (value && !_childrenLoaded && !_loadingStarted)
|
||||||
|
{
|
||||||
|
_loadingStarted = true;
|
||||||
|
_ = LoadChildrenAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Lists this folder's subfolders and replaces the placeholder with
|
||||||
|
/// real child nodes. <paramref name="seedNames"/> (used for the root)
|
||||||
|
/// guarantees the default case subfolders show even if the share
|
||||||
|
/// listing lags or omits a not-yet-created folder.
|
||||||
|
/// </summary>
|
||||||
|
public async Task LoadChildrenAsync(IEnumerable<string>? seedNames = null)
|
||||||
|
{
|
||||||
|
if (_client == null) return;
|
||||||
|
IsLoading = true;
|
||||||
|
|
||||||
|
// Build into a local list and swap once at the end. The seeds are
|
||||||
|
// added first so that even if the share listing fails the default
|
||||||
|
// subfolders still show; on failure for a non-seeded node the list
|
||||||
|
// is empty and the node reads as a leaf rather than "loading…".
|
||||||
|
var seen = new HashSet<string>(StringComparer.Ordinal);
|
||||||
|
var loaded = new List<FolderNodeViewModel>();
|
||||||
|
if (seedNames != null)
|
||||||
|
{
|
||||||
|
foreach (var n in seedNames)
|
||||||
|
{
|
||||||
|
if (seen.Add(n)) loaded.Add(MakeChild(n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var items = await _client.ListNetworkStorageFolderAsync(FullPath).ConfigureAwait(true);
|
||||||
|
foreach (var item in items)
|
||||||
|
{
|
||||||
|
if (!item.IsFolder) continue;
|
||||||
|
if (!seen.Add(item.Name)) continue;
|
||||||
|
loaded.Add(MakeChild(item.Name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger?.Warning(ex, "Listing subfolders under '{Path}' failed", FullPath);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// Marshal onto the Dispatcher: once this node's TreeViewItem
|
||||||
|
// exists, Children is bound and must only be mutated on the UI
|
||||||
|
// thread (the network await above can resume on a thread-pool
|
||||||
|
// thread in this VSTO host).
|
||||||
|
OnUi(() =>
|
||||||
|
{
|
||||||
|
Children.Clear();
|
||||||
|
foreach (var child in loaded) Children.Add(child);
|
||||||
|
});
|
||||||
|
_childrenLoaded = true;
|
||||||
|
IsLoading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private FolderNodeViewModel MakeChild(string name)
|
||||||
|
{
|
||||||
|
var fullPath = string.IsNullOrEmpty(FullPath) ? name : FullPath + "/" + name;
|
||||||
|
var relativePath = IsRoot ? name : RelativePath + "/" + name;
|
||||||
|
return new FolderNodeViewModel(_client!, _logger!, _dispatcher!, name, fullPath, relativePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUi(Action action)
|
||||||
|
{
|
||||||
|
var d = _dispatcher;
|
||||||
|
if (d == null || d.CheckAccess()) action();
|
||||||
|
else d.Invoke(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Threading;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using MarcusLaw.OutlookAddin.Core.Models;
|
using MarcusLaw.OutlookAddin.Core.Models;
|
||||||
@@ -31,6 +32,7 @@ namespace MarcusLaw.OutlookAddin.UI.ViewModels
|
|||||||
|
|
||||||
private readonly IEspoCrmClient _client;
|
private readonly IEspoCrmClient _client;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
private readonly Dispatcher _dispatcher;
|
||||||
private CancellationTokenSource? _searchCts;
|
private CancellationTokenSource? _searchCts;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
@@ -40,7 +42,7 @@ namespace MarcusLaw.OutlookAddin.UI.ViewModels
|
|||||||
private CaseEntity? selectedCase;
|
private CaseEntity? selectedCase;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string? selectedSubfolder;
|
private FolderNodeViewModel? selectedFolder;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string? statusMessage;
|
private string? statusMessage;
|
||||||
@@ -58,7 +60,12 @@ namespace MarcusLaw.OutlookAddin.UI.ViewModels
|
|||||||
|
|
||||||
public ObservableCollection<CaseEntity> Cases { get; } = new ObservableCollection<CaseEntity>();
|
public ObservableCollection<CaseEntity> Cases { get; } = new ObservableCollection<CaseEntity>();
|
||||||
|
|
||||||
public ObservableCollection<string> Subfolders { get; } = new ObservableCollection<string>();
|
/// <summary>
|
||||||
|
/// Folder tree for the selected case. Holds a single root node (the
|
||||||
|
/// case folder); its children are the subfolders, loaded lazily so the
|
||||||
|
/// user can drill into any nesting depth.
|
||||||
|
/// </summary>
|
||||||
|
public ObservableCollection<FolderNodeViewModel> FolderTree { get; } = new ObservableCollection<FolderNodeViewModel>();
|
||||||
|
|
||||||
public ObservableCollection<AttachmentRowViewModel> Attachments { get; } = new ObservableCollection<AttachmentRowViewModel>();
|
public ObservableCollection<AttachmentRowViewModel> Attachments { get; } = new ObservableCollection<AttachmentRowViewModel>();
|
||||||
|
|
||||||
@@ -78,14 +85,20 @@ namespace MarcusLaw.OutlookAddin.UI.ViewModels
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Subfolder string the user picked, or null to save to the case
|
/// Folder the user picked, as a path relative to the case folder
|
||||||
/// folder root.
|
/// (e.g. "מסמכים/רפואי"), or null to save to the case folder root.
|
||||||
|
/// Multi-segment paths are honoured by the save target, which appends
|
||||||
|
/// this to <see cref="ResolvedCaseFolderPath"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? ChosenSubfolderName =>
|
public string? ChosenSubfolderName
|
||||||
string.IsNullOrEmpty(SelectedSubfolder) ||
|
{
|
||||||
string.Equals(SelectedSubfolder, RootSentinel, StringComparison.Ordinal)
|
get
|
||||||
? null
|
{
|
||||||
: SelectedSubfolder;
|
var f = SelectedFolder;
|
||||||
|
if (f == null || f.IsPlaceholder || f.IsRoot) return null;
|
||||||
|
return string.IsNullOrEmpty(f.RelativePath) ? null : f.RelativePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public CaseEntity? PickedCase => SelectedCase;
|
public CaseEntity? PickedCase => SelectedCase;
|
||||||
|
|
||||||
@@ -98,8 +111,15 @@ namespace MarcusLaw.OutlookAddin.UI.ViewModels
|
|||||||
{
|
{
|
||||||
_client = client ?? throw new ArgumentNullException(nameof(client));
|
_client = client ?? throw new ArgumentNullException(nameof(client));
|
||||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
|
// Captured on the UI thread (the VM is constructed on the thread
|
||||||
|
// that shows the dialog). Used to marshal ObservableCollection
|
||||||
|
// mutations back onto the Dispatcher — in this VSTO host the WPF
|
||||||
|
// SynchronizationContext is not installed, so ConfigureAwait(true)
|
||||||
|
// resumes on a thread-pool thread and a bound-collection Add throws
|
||||||
|
// "changes ... from a thread different from the Dispatcher thread".
|
||||||
|
_dispatcher = Dispatcher.CurrentDispatcher;
|
||||||
|
|
||||||
ResetSubfolders();
|
ResetFolderTree();
|
||||||
|
|
||||||
foreach (var att in attachments)
|
foreach (var att in attachments)
|
||||||
{
|
{
|
||||||
@@ -107,12 +127,52 @@ namespace MarcusLaw.OutlookAddin.UI.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ResetSubfolders()
|
/// <summary>
|
||||||
|
/// Seeds the case list with the cases already resolved for the mail's
|
||||||
|
/// sender (from the sidebar match) so the user doesn't have to search
|
||||||
|
/// for a client we've already identified. When exactly one case is
|
||||||
|
/// known we auto-select it (which kicks the subfolder/folder-path
|
||||||
|
/// resolve); with several we just show them and let the user pick.
|
||||||
|
/// The user can still type in the search box to override — that
|
||||||
|
/// repopulates <see cref="Cases"/> from a fresh server search.
|
||||||
|
/// </summary>
|
||||||
|
public void PreselectCases(IReadOnlyList<CaseEntity> cases)
|
||||||
{
|
{
|
||||||
Subfolders.Clear();
|
if (cases == null || cases.Count == 0) return;
|
||||||
Subfolders.Add(RootSentinel);
|
|
||||||
foreach (var f in DefaultCaseSubfolders) Subfolders.Add(f);
|
Cases.Clear();
|
||||||
SelectedSubfolder = Subfolders[0];
|
foreach (var c in cases)
|
||||||
|
{
|
||||||
|
if (c == null || string.IsNullOrEmpty(c.Id)) continue;
|
||||||
|
Cases.Add(c);
|
||||||
|
}
|
||||||
|
if (Cases.Count == 0) return;
|
||||||
|
|
||||||
|
if (Cases.Count == 1)
|
||||||
|
{
|
||||||
|
SelectedCase = Cases[0];
|
||||||
|
StatusMessage = "התיק זוהה אוטומטית מהשולח";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
StatusMessage = $"{Cases.Count} תיקים מקושרים לשולח — בחר/י תיק";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Runs <paramref name="action"/> on the UI/Dispatcher thread.</summary>
|
||||||
|
private void OnUi(Action action)
|
||||||
|
{
|
||||||
|
if (_dispatcher.CheckAccess()) action();
|
||||||
|
else _dispatcher.Invoke(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ResetFolderTree()
|
||||||
|
{
|
||||||
|
OnUi(() =>
|
||||||
|
{
|
||||||
|
FolderTree.Clear();
|
||||||
|
SelectedFolder = null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void OnSearchTextChanged(string value)
|
partial void OnSearchTextChanged(string value)
|
||||||
@@ -137,7 +197,7 @@ namespace MarcusLaw.OutlookAddin.UI.ViewModels
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task RefreshSubfoldersForSelectedCaseAsync()
|
public async Task RefreshSubfoldersForSelectedCaseAsync()
|
||||||
{
|
{
|
||||||
ResetSubfolders();
|
ResetFolderTree();
|
||||||
ResolvedCaseFolderPath = null;
|
ResolvedCaseFolderPath = null;
|
||||||
|
|
||||||
var c = SelectedCase;
|
var c = SelectedCase;
|
||||||
@@ -188,21 +248,28 @@ namespace MarcusLaw.OutlookAddin.UI.ViewModels
|
|||||||
c.Id, c.Number ?? "(none)", primaryContactName ?? "(none)", c.NetworkStorageFolderPath ?? "(none)", folderPath);
|
c.Id, c.Number ?? "(none)", primaryContactName ?? "(none)", c.NetworkStorageFolderPath ?? "(none)", folderPath);
|
||||||
if (string.IsNullOrEmpty(folderPath)) return;
|
if (string.IsNullOrEmpty(folderPath)) return;
|
||||||
|
|
||||||
|
// Build the tree rooted at the case folder. The root node is
|
||||||
|
// selected by default (→ save to case root, matching the previous
|
||||||
|
// default), expanded, and seeded with the default subfolders so
|
||||||
|
// they appear even before the share listing returns. Deeper levels
|
||||||
|
// load lazily as the user expands them.
|
||||||
|
var root = new FolderNodeViewModel(_client, _logger, _dispatcher, RootSentinel, folderPath, relativePath: null);
|
||||||
|
OnUi(() =>
|
||||||
|
{
|
||||||
|
FolderTree.Add(root);
|
||||||
|
SelectedFolder = root;
|
||||||
|
root.IsSelected = true;
|
||||||
|
});
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var items = await _client.ListNetworkStorageFolderAsync(folderPath).ConfigureAwait(true);
|
await root.LoadChildrenAsync(DefaultCaseSubfolders).ConfigureAwait(true);
|
||||||
foreach (var item in items)
|
|
||||||
{
|
|
||||||
if (!item.IsFolder) continue;
|
|
||||||
if (Subfolders.Contains(item.Name)) continue;
|
|
||||||
if (string.Equals(item.Name, RootSentinel, StringComparison.Ordinal)) continue;
|
|
||||||
Subfolders.Add(item.Name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.Warning(ex, "Listing subfolders for case {CaseId} failed", c.Id);
|
_logger.Warning(ex, "Listing subfolders for case {CaseId} failed", c.Id);
|
||||||
}
|
}
|
||||||
|
OnUi(() => root.IsExpanded = true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
@@ -178,18 +179,61 @@ namespace MarcusLaw.OutlookAddin.UI.ViewModels
|
|||||||
}
|
}
|
||||||
|
|
||||||
var deployment = System.Deployment.Application.ApplicationDeployment.CurrentDeployment;
|
var deployment = System.Deployment.Application.ApplicationDeployment.CurrentDeployment;
|
||||||
var info = await Task.Run(() => deployment.CheckForDetailedUpdate(false)).ConfigureAwait(true);
|
var currentVersion = deployment.CurrentVersion;
|
||||||
if (!info.UpdateAvailable)
|
var manifestUri = deployment.UpdateLocation;
|
||||||
|
|
||||||
|
// ApplicationDeployment.CheckForDetailedUpdate triggers a
|
||||||
|
// TrustManager re-evaluation which throws TrustNotGranted
|
||||||
|
// inside a hosted VSTO process even when the publisher and
|
||||||
|
// permissions are unchanged. Bypass it by fetching the
|
||||||
|
// deployment manifest directly and reading the version.
|
||||||
|
Version? availableVersion = null;
|
||||||
|
try
|
||||||
{
|
{
|
||||||
UpdateStatusBrush = SuccessBrush;
|
availableVersion = await Task.Run(() => FetchManifestVersion(manifestUri)).ConfigureAwait(true);
|
||||||
UpdateStatus = "אתה על הגרסה האחרונה (" + deployment.CurrentVersion + ").";
|
}
|
||||||
|
catch (Exception fetchEx)
|
||||||
|
{
|
||||||
|
_logger.Warning(fetchEx, "CheckForUpdate: manifest fetch failed");
|
||||||
|
UpdateStatusBrush = ErrorBrush;
|
||||||
|
UpdateStatus = "שגיאה בבדיקת השרת: " + fetchEx.Message;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateStatus = $"זמינה גרסה {info.AvailableVersion} — מוריד…";
|
if (availableVersion == null)
|
||||||
var result = await Task.Run(() => deployment.Update()).ConfigureAwait(true);
|
{
|
||||||
|
UpdateStatusBrush = ErrorBrush;
|
||||||
|
UpdateStatus = "לא ניתן לקרוא את גרסת השרת מ-" + manifestUri;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (availableVersion <= currentVersion)
|
||||||
|
{
|
||||||
|
UpdateStatusBrush = SuccessBrush;
|
||||||
|
UpdateStatus = "אתה על הגרסה האחרונה (" + currentVersion + ").";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A running Outlook holds file locks on the loaded add-in
|
||||||
|
// DLLs. Neither ApplicationDeployment.Update (TrustNotGranted)
|
||||||
|
// nor a direct VSTOInstaller.exe /I call (0x8007007E
|
||||||
|
// ERROR_MOD_NOT_FOUND) nor Process.Start(.vsto URL) (Chrome
|
||||||
|
// downloads to local-machine zone — InvalidDeploymentException)
|
||||||
|
// can install over those locks. The only path that actually
|
||||||
|
// works is the one VSTO runtime takes automatically on Outlook
|
||||||
|
// startup: it checks the manifest URL before loading the
|
||||||
|
// add-in, downloads + installs if there's a newer version,
|
||||||
|
// then loads it.
|
||||||
|
//
|
||||||
|
// So the button's job is just to tell the user: "close and
|
||||||
|
// reopen Outlook." That's the same flow the user has been
|
||||||
|
// doing manually all along; we're just confirming the new
|
||||||
|
// version is there waiting.
|
||||||
UpdateStatusBrush = SuccessBrush;
|
UpdateStatusBrush = SuccessBrush;
|
||||||
UpdateStatus = $"הותקנה גרסה {info.AvailableVersion}. סגור ופתח את Outlook כדי לטעון אותה.";
|
UpdateStatus =
|
||||||
|
$"זמינה גרסה {availableVersion}. סגור ופתח את Outlook — " +
|
||||||
|
"הגרסה החדשה תותקן אוטומטית בעלייה.";
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
catch (System.Deployment.Application.DeploymentDownloadException ex)
|
catch (System.Deployment.Application.DeploymentDownloadException ex)
|
||||||
{
|
{
|
||||||
@@ -215,6 +259,33 @@ namespace MarcusLaw.OutlookAddin.UI.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the top-level <assemblyIdentity> version from the
|
||||||
|
/// .vsto deployment manifest at <paramref name="manifestUri"/>.
|
||||||
|
/// Returns null if the document doesn't look like a deployment
|
||||||
|
/// manifest. Runs on a worker thread (synchronous HTTP).
|
||||||
|
/// </summary>
|
||||||
|
private static Version? FetchManifestVersion(Uri manifestUri)
|
||||||
|
{
|
||||||
|
// The .vsto manifest is small (≈6KB). Keep this synchronous —
|
||||||
|
// no point pulling in HttpClient and its lifecycle just for one
|
||||||
|
// GET. WebRequest works fine on .NET FW 4.8 and through proxies.
|
||||||
|
var req = System.Net.WebRequest.Create(manifestUri);
|
||||||
|
req.Timeout = 10_000;
|
||||||
|
using (var response = req.GetResponse())
|
||||||
|
using (var stream = response.GetResponseStream())
|
||||||
|
{
|
||||||
|
var doc = System.Xml.Linq.XDocument.Load(stream);
|
||||||
|
System.Xml.Linq.XNamespace asmv1 = "urn:schemas-microsoft-com:asm.v1";
|
||||||
|
var identity = doc.Root?
|
||||||
|
.Elements()
|
||||||
|
.FirstOrDefault(e => e.Name.LocalName == "assemblyIdentity" && e.Name.Namespace == asmv1);
|
||||||
|
var versionAttr = identity?.Attribute("version")?.Value;
|
||||||
|
if (string.IsNullOrWhiteSpace(versionAttr)) return null;
|
||||||
|
return Version.TryParse(versionAttr, out var v) ? v : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private bool CanCheckForUpdate() => !IsCheckingForUpdate;
|
private bool CanCheckForUpdate() => !IsCheckingForUpdate;
|
||||||
|
|
||||||
partial void OnIsCheckingForUpdateChanged(bool value)
|
partial void OnIsCheckingForUpdateChanged(bool value)
|
||||||
|
|||||||
@@ -36,11 +36,10 @@
|
|||||||
<PublishUrl>C:\Users\Chaim\source\repos\OutlookAddin\Publish\</PublishUrl>
|
<PublishUrl>C:\Users\Chaim\source\repos\OutlookAddin\Publish\</PublishUrl>
|
||||||
<InstallUrl>https://gitea.dev.marcus-law.co.il/espocrm-extensions/OutlookAddin/raw/branch/main/Publish/</InstallUrl>
|
<InstallUrl>https://gitea.dev.marcus-law.co.il/espocrm-extensions/OutlookAddin/raw/branch/main/Publish/</InstallUrl>
|
||||||
<TargetCulture>en</TargetCulture>
|
<TargetCulture>en</TargetCulture>
|
||||||
<ApplicationVersion>1.1.3.0</ApplicationVersion>
|
<ApplicationVersion>1.2.10.0</ApplicationVersion>
|
||||||
<AutoIncrementApplicationRevision>false</AutoIncrementApplicationRevision>
|
<AutoIncrementApplicationRevision>false</AutoIncrementApplicationRevision>
|
||||||
<UpdateEnabled>true</UpdateEnabled>
|
<UpdateEnabled>true</UpdateEnabled>
|
||||||
<UpdateInterval>7</UpdateInterval>
|
<UpdatePeriodically>false</UpdatePeriodically>
|
||||||
<UpdateIntervalUnits>days</UpdateIntervalUnits>
|
|
||||||
<ProductName>MarcusLaw.OutlookAddin</ProductName>
|
<ProductName>MarcusLaw.OutlookAddin</ProductName>
|
||||||
<PublisherName />
|
<PublisherName />
|
||||||
<SupportUrl />
|
<SupportUrl />
|
||||||
@@ -258,6 +257,9 @@
|
|||||||
<EmbeddedResource Include="Ribbon\InspectorRibbon.xml">
|
<EmbeddedResource Include="Ribbon\InspectorRibbon.xml">
|
||||||
<LogicalName>OutlookAddin.Ribbon.InspectorRibbon.xml</LogicalName>
|
<LogicalName>OutlookAddin.Ribbon.InspectorRibbon.xml</LogicalName>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
<EmbeddedResource Include="Ribbon\ReadMailRibbon.xml">
|
||||||
|
<LogicalName>OutlookAddin.Ribbon.ReadMailRibbon.xml</LogicalName>
|
||||||
|
</EmbeddedResource>
|
||||||
<EmbeddedResource Include="Images\klear-file.png">
|
<EmbeddedResource Include="Images\klear-file.png">
|
||||||
<LogicalName>OutlookAddin.Images.klear-file.png</LogicalName>
|
<LogicalName>OutlookAddin.Images.klear-file.png</LogicalName>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
|||||||
@@ -33,6 +33,6 @@ using System.Security;
|
|||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
// by using the '*' as shown below:
|
// by using the '*' as shown below:
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyVersion("1.1.3.0")]
|
[assembly: AssemblyVersion("1.2.16.0")]
|
||||||
[assembly: AssemblyFileVersion("1.1.3.0")]
|
[assembly: AssemblyFileVersion("1.2.16.0")]
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ namespace OutlookAddin.Ribbon
|
|||||||
{
|
{
|
||||||
private const string ExplorerResource = "OutlookAddin.Ribbon.ExplorerRibbon.xml";
|
private const string ExplorerResource = "OutlookAddin.Ribbon.ExplorerRibbon.xml";
|
||||||
private const string InspectorResource = "OutlookAddin.Ribbon.InspectorRibbon.xml";
|
private const string InspectorResource = "OutlookAddin.Ribbon.InspectorRibbon.xml";
|
||||||
|
private const string ReadMailResource = "OutlookAddin.Ribbon.ReadMailRibbon.xml";
|
||||||
|
|
||||||
// Every button whose `getEnabled` depends on the current Explorer
|
// Every button whose `getEnabled` depends on the current Explorer
|
||||||
// selection must be re-evaluated on every SelectionChange — Office
|
// selection must be re-evaluated on every SelectionChange — Office
|
||||||
@@ -40,6 +41,8 @@ namespace OutlookAddin.Ribbon
|
|||||||
return LoadResource(ExplorerResource);
|
return LoadResource(ExplorerResource);
|
||||||
case "Microsoft.Outlook.Mail.Compose":
|
case "Microsoft.Outlook.Mail.Compose":
|
||||||
return LoadResource(InspectorResource);
|
return LoadResource(InspectorResource);
|
||||||
|
case "Microsoft.Outlook.Mail.Read":
|
||||||
|
return LoadResource(ReadMailResource);
|
||||||
default:
|
default:
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
@@ -77,6 +80,51 @@ namespace OutlookAddin.Ribbon
|
|||||||
_inspectorRibbon = ribbon;
|
_inspectorRibbon = ribbon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The read-mail inspector ribbon loads fresh for each opened message,
|
||||||
|
// so its getEnabled callback re-runs per window — no cached IRibbonUI
|
||||||
|
// or invalidation is needed here.
|
||||||
|
public void OnReadMailRibbonLoad(IRibbonUI ribbon)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enabled when the message open in this read inspector has at least
|
||||||
|
/// one attachment. Mirrors <see cref="OnGetSaveAttachmentsEnabled"/>
|
||||||
|
/// but reads the item from the Inspector context rather than the
|
||||||
|
/// Explorer selection.
|
||||||
|
/// </summary>
|
||||||
|
public bool OnGetSaveAttachmentsInspectorEnabled(IRibbonControl control)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var inspector = control?.Context as Outlook.Inspector;
|
||||||
|
if (inspector?.CurrentItem is not Outlook.MailItem mail) return false;
|
||||||
|
var attachments = mail.Attachments;
|
||||||
|
if (attachments == null) return false;
|
||||||
|
return attachments.Count > 0;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnSaveAttachmentsFromInspector(IRibbonControl control)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var inspector = control?.Context as Outlook.Inspector;
|
||||||
|
if (inspector?.CurrentItem is Outlook.MailItem mail)
|
||||||
|
{
|
||||||
|
_ = Globals.ThisAddIn.AddInHost.LaunchSaveAttachmentsAsync(mail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Globals.ThisAddIn.AddInHost.Logger.Warning(ex, "OnSaveAttachmentsFromInspector failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool OnGetFileToEspoCrmEnabled(IRibbonControl control)
|
public bool OnGetFileToEspoCrmEnabled(IRibbonControl control)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -206,6 +254,7 @@ namespace OutlookAddin.Ribbon
|
|||||||
{
|
{
|
||||||
case "FileToEspoCrm": fileName = "klear-file.png"; break;
|
case "FileToEspoCrm": fileName = "klear-file.png"; break;
|
||||||
case "SaveAttachments": fileName = "klear-attach.png"; break;
|
case "SaveAttachments": fileName = "klear-attach.png"; break;
|
||||||
|
case "SaveAttachmentsRead": fileName = "klear-attach.png"; break;
|
||||||
case "ShowSidebar": fileName = "klear-sidebar.png"; break;
|
case "ShowSidebar": fileName = "klear-sidebar.png"; break;
|
||||||
case "OpenEspoCrmSettings": fileName = "klear-settings.png"; break;
|
case "OpenEspoCrmSettings": fileName = "klear-settings.png"; break;
|
||||||
case "ComposeFromCase": fileName = "klear-compose.png"; break;
|
case "ComposeFromCase": fileName = "klear-compose.png"; break;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<ribbon>
|
<ribbon>
|
||||||
<tabs>
|
<tabs>
|
||||||
<tab idMso="TabMail">
|
<tab idMso="TabMail">
|
||||||
<group id="MarcusLawGroup" label="Marcus-Law" insertBeforeMso="GroupMailMove">
|
<group id="MarcusLawGroup" label="Klear" insertBeforeMso="GroupMailMove">
|
||||||
<button id="FileToEspoCrm"
|
<button id="FileToEspoCrm"
|
||||||
label="Klear"
|
label="Klear"
|
||||||
screentip="תייק את המייל הנבחר ל-Klear"
|
screentip="תייק את המייל הנבחר ל-Klear"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<ribbon>
|
<ribbon>
|
||||||
<tabs>
|
<tabs>
|
||||||
<tab idMso="TabNewMailMessage">
|
<tab idMso="TabNewMailMessage">
|
||||||
<group id="MarcusLawComposeGroup" label="Marcus-Law" insertBeforeMso="GroupClipboard">
|
<group id="MarcusLawComposeGroup" label="Klear" insertBeforeMso="GroupClipboard">
|
||||||
<button id="ComposeFromCase"
|
<button id="ComposeFromCase"
|
||||||
label="כתוב מתיק"
|
label="כתוב מתיק"
|
||||||
screentip="פתח את המייל מתיק Klear"
|
screentip="פתח את המייל מתיק Klear"
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="OnReadMailRibbonLoad">
|
||||||
|
<ribbon>
|
||||||
|
<tabs>
|
||||||
|
<tab idMso="TabReadMessage">
|
||||||
|
<group id="MarcusLawReadGroup" label="Klear">
|
||||||
|
<button id="SaveAttachmentsRead"
|
||||||
|
label="שמור קבצים"
|
||||||
|
screentip="שמור את הקבצים המצורפים בלבד"
|
||||||
|
supertip="מעלה את הקבצים המצורפים של המייל הזה ל-Klear כ-Documents מקושרים לתיק שתבחר, בלי לתייק את המייל עצמו."
|
||||||
|
size="large"
|
||||||
|
getImage="OnGetImage"
|
||||||
|
onAction="OnSaveAttachmentsFromInspector"
|
||||||
|
getEnabled="OnGetSaveAttachmentsInspectorEnabled" />
|
||||||
|
</group>
|
||||||
|
</tab>
|
||||||
|
</tabs>
|
||||||
|
</ribbon>
|
||||||
|
</customUI>
|
||||||
@@ -127,6 +127,62 @@ namespace OutlookAddin.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shows a message box that is guaranteed to render above Outlook and
|
||||||
|
/// any other window. A bare <see cref="MessageBox.Show(string)"/> has
|
||||||
|
/// no owner — once our WPF dialog closes there is no active window on
|
||||||
|
/// the add-in thread, so the box sinks behind Outlook and the user
|
||||||
|
/// never sees the success/error result. We anchor it to a transient,
|
||||||
|
/// invisible top-most owner window parented to the foreground Outlook
|
||||||
|
/// window so it always surfaces on top. Caption is always "Klear".
|
||||||
|
/// </summary>
|
||||||
|
private MessageBoxResult ShowMessage(
|
||||||
|
string text,
|
||||||
|
MessageBoxButton button = MessageBoxButton.OK,
|
||||||
|
MessageBoxImage icon = MessageBoxImage.None)
|
||||||
|
{
|
||||||
|
Window? owner = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// A 1×1 borderless window at screen centre: imperceptible, but
|
||||||
|
// gives the MessageBox a top-most owner to z-order above. The
|
||||||
|
// box centres on this point → effectively centred on screen.
|
||||||
|
owner = new Window
|
||||||
|
{
|
||||||
|
Width = 1,
|
||||||
|
Height = 1,
|
||||||
|
WindowStyle = WindowStyle.None,
|
||||||
|
ResizeMode = ResizeMode.NoResize,
|
||||||
|
ShowInTaskbar = false,
|
||||||
|
Topmost = true,
|
||||||
|
WindowStartupLocation = WindowStartupLocation.CenterScreen,
|
||||||
|
};
|
||||||
|
|
||||||
|
var hwnd = GetForegroundWindow();
|
||||||
|
if (hwnd == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
hwnd = System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle;
|
||||||
|
}
|
||||||
|
if (hwnd != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
new WindowInteropHelper(owner).Owner = hwnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
owner.Show();
|
||||||
|
owner.Activate();
|
||||||
|
return MessageBox.Show(owner, text, "Klear", button, icon);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.Warning(ex, "ShowMessage top-most owner failed; falling back to ownerless box");
|
||||||
|
return MessageBox.Show(text, "Klear", button, icon);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
try { owner?.Close(); } catch { /* ignore */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void EnableModernTls()
|
private static void EnableModernTls()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -402,9 +458,8 @@ namespace OutlookAddin.Services
|
|||||||
if (mail == null) return;
|
if (mail == null) return;
|
||||||
if (!IsConfigured)
|
if (!IsConfigured)
|
||||||
{
|
{
|
||||||
MessageBox.Show(
|
ShowMessage(
|
||||||
"התוסף עדיין לא מוגדר. פתח את ההגדרות תחילה.",
|
"התוסף עדיין לא מוגדר. פתח את ההגדרות תחילה.",
|
||||||
"Marcus-Law OutlookAddin",
|
|
||||||
MessageBoxButton.OK,
|
MessageBoxButton.OK,
|
||||||
MessageBoxImage.Information);
|
MessageBoxImage.Information);
|
||||||
return;
|
return;
|
||||||
@@ -423,9 +478,8 @@ namespace OutlookAddin.Services
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.Error(ex, "LaunchComposeFromCaseAsync failed");
|
Logger.Error(ex, "LaunchComposeFromCaseAsync failed");
|
||||||
MessageBox.Show(
|
ShowMessage(
|
||||||
"טעינת התיק נכשלה: " + ex.Message,
|
"טעינת התיק נכשלה: " + ex.Message,
|
||||||
"Marcus-Law OutlookAddin",
|
|
||||||
MessageBoxButton.OK,
|
MessageBoxButton.OK,
|
||||||
MessageBoxImage.Error);
|
MessageBoxImage.Error);
|
||||||
}
|
}
|
||||||
@@ -444,9 +498,8 @@ namespace OutlookAddin.Services
|
|||||||
if (mail == null) return;
|
if (mail == null) return;
|
||||||
if (!IsConfigured)
|
if (!IsConfigured)
|
||||||
{
|
{
|
||||||
var result = MessageBox.Show(
|
var result = ShowMessage(
|
||||||
"התוסף עדיין לא מוגדר. לפתוח את חלון ההגדרות עכשיו?",
|
"התוסף עדיין לא מוגדר. לפתוח את חלון ההגדרות עכשיו?",
|
||||||
"Marcus-Law OutlookAddin",
|
|
||||||
MessageBoxButton.YesNo,
|
MessageBoxButton.YesNo,
|
||||||
MessageBoxImage.Information);
|
MessageBoxImage.Information);
|
||||||
if (result == MessageBoxResult.Yes) LaunchSettings();
|
if (result == MessageBoxResult.Yes) LaunchSettings();
|
||||||
@@ -463,9 +516,8 @@ namespace OutlookAddin.Services
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.Error(ex, "LaunchSaveAttachmentsAsync: extract failed");
|
Logger.Error(ex, "LaunchSaveAttachmentsAsync: extract failed");
|
||||||
MessageBox.Show(
|
ShowMessage(
|
||||||
"קריאת הקבצים המצורפים נכשלה: " + ex.Message,
|
"קריאת הקבצים המצורפים נכשלה: " + ex.Message,
|
||||||
"Marcus-Law OutlookAddin",
|
|
||||||
MessageBoxButton.OK,
|
MessageBoxButton.OK,
|
||||||
MessageBoxImage.Error);
|
MessageBoxImage.Error);
|
||||||
return;
|
return;
|
||||||
@@ -473,9 +525,8 @@ namespace OutlookAddin.Services
|
|||||||
|
|
||||||
if (envelope.Attachments.Count == 0)
|
if (envelope.Attachments.Count == 0)
|
||||||
{
|
{
|
||||||
MessageBox.Show(
|
ShowMessage(
|
||||||
"אין במייל הזה קבצים מצורפים לשמירה.",
|
"אין במייל הזה קבצים מצורפים לשמירה.",
|
||||||
"Marcus-Law OutlookAddin",
|
|
||||||
MessageBoxButton.OK,
|
MessageBoxButton.OK,
|
||||||
MessageBoxImage.Information);
|
MessageBoxImage.Information);
|
||||||
return;
|
return;
|
||||||
@@ -485,6 +536,13 @@ namespace OutlookAddin.Services
|
|||||||
// Subfolders are populated lazily once the user picks a case;
|
// Subfolders are populated lazily once the user picks a case;
|
||||||
// the default static set is already pre-loaded.
|
// the default static set is already pre-loaded.
|
||||||
|
|
||||||
|
// If the sender already maps to a known client, seed the case
|
||||||
|
// list so the user sees the identified case pre-selected instead
|
||||||
|
// of having to search. Uses the same matching lookup the sidebar
|
||||||
|
// does (cached for 10 min), so this is normally instant. Any
|
||||||
|
// failure here is non-fatal — the dialog still opens empty.
|
||||||
|
await TryPreselectSenderCaseAsync(vm, envelope.From).ConfigureAwait(true);
|
||||||
|
|
||||||
var dialog = new SaveAttachmentsDialog(vm);
|
var dialog = new SaveAttachmentsDialog(vm);
|
||||||
AttachOwnerToOutlook(dialog);
|
AttachOwnerToOutlook(dialog);
|
||||||
var ok = dialog.ShowDialog();
|
var ok = dialog.ShowDialog();
|
||||||
@@ -503,9 +561,8 @@ namespace OutlookAddin.Services
|
|||||||
: SaveAttachmentsViewModel.ResolveCaseFolderPath(picked);
|
: SaveAttachmentsViewModel.ResolveCaseFolderPath(picked);
|
||||||
if (string.IsNullOrEmpty(caseFolder))
|
if (string.IsNullOrEmpty(caseFolder))
|
||||||
{
|
{
|
||||||
MessageBox.Show(
|
ShowMessage(
|
||||||
"לא ניתן לחשב את נתיב התיקייה של התיק. ייתכן שהתיק עוד לא הוגדר ב-Klear.",
|
"לא ניתן לחשב את נתיב התיקייה של התיק. ייתכן שהתיק עוד לא הוגדר ב-Klear.",
|
||||||
"Marcus-Law OutlookAddin",
|
|
||||||
MessageBoxButton.OK,
|
MessageBoxButton.OK,
|
||||||
MessageBoxImage.Warning);
|
MessageBoxImage.Warning);
|
||||||
return;
|
return;
|
||||||
@@ -533,15 +590,38 @@ namespace OutlookAddin.Services
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.Error(ex, "LaunchSaveAttachmentsAsync failed");
|
Logger.Error(ex, "LaunchSaveAttachmentsAsync failed");
|
||||||
MessageBox.Show(
|
ShowMessage(
|
||||||
"שמירת הקבצים נכשלה: " + ex.Message,
|
"שמירת הקבצים נכשלה: " + ex.Message,
|
||||||
"Marcus-Law OutlookAddin",
|
|
||||||
MessageBoxButton.OK,
|
MessageBoxButton.OK,
|
||||||
MessageBoxImage.Error);
|
MessageBoxImage.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ShowAttachmentSummary(AttachmentSaveSummary summary, string caseLabel, string targetPath)
|
/// <summary>
|
||||||
|
/// Looks up the mail sender against the CRM (reusing the sidebar's
|
||||||
|
/// cached match) and, when it resolves to one or more linked cases,
|
||||||
|
/// seeds the save-attachments dialog so the already-identified client
|
||||||
|
/// case shows up pre-selected. Best-effort: swallows any error.
|
||||||
|
/// </summary>
|
||||||
|
private async Task TryPreselectSenderCaseAsync(SaveAttachmentsViewModel vm, string? senderEmail)
|
||||||
|
{
|
||||||
|
if (MatchingService == null || string.IsNullOrWhiteSpace(senderEmail)) return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var match = await MatchingService.LookupAsync(senderEmail!).ConfigureAwait(true);
|
||||||
|
// Ambiguous (same email on several contacts) → don't guess; let
|
||||||
|
// the user search. A clean match with linked cases → seed them.
|
||||||
|
if (match == null || match.IsAmbiguous) return;
|
||||||
|
if (match.RecentCases == null || match.RecentCases.Count == 0) return;
|
||||||
|
vm.PreselectCases(match.RecentCases);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.Warning(ex, "Sender-case preselect for save-attachments failed (non-fatal)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowAttachmentSummary(AttachmentSaveSummary summary, string caseLabel, string targetPath)
|
||||||
{
|
{
|
||||||
string message;
|
string message;
|
||||||
MessageBoxImage icon;
|
MessageBoxImage icon;
|
||||||
@@ -558,7 +638,7 @@ namespace OutlookAddin.Services
|
|||||||
message = parts.Count == 0 ? "לא נשמרו פריטים." : string.Join(" · ", parts);
|
message = parts.Count == 0 ? "לא נשמרו פריטים." : string.Join(" · ", parts);
|
||||||
icon = summary.FailedCount > 0 ? MessageBoxImage.Warning : MessageBoxImage.Information;
|
icon = summary.FailedCount > 0 ? MessageBoxImage.Warning : MessageBoxImage.Information;
|
||||||
}
|
}
|
||||||
MessageBox.Show(message, "Marcus-Law OutlookAddin", MessageBoxButton.OK, icon);
|
ShowMessage(message, MessageBoxButton.OK, icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -570,9 +650,8 @@ namespace OutlookAddin.Services
|
|||||||
{
|
{
|
||||||
if (!IsConfigured)
|
if (!IsConfigured)
|
||||||
{
|
{
|
||||||
MessageBox.Show(
|
ShowMessage(
|
||||||
"התוסף עדיין לא מוגדר. פתח את ההגדרות תחילה.",
|
"התוסף עדיין לא מוגדר. פתח את ההגדרות תחילה.",
|
||||||
"Marcus-Law OutlookAddin",
|
|
||||||
MessageBoxButton.OK,
|
MessageBoxButton.OK,
|
||||||
MessageBoxImage.Information);
|
MessageBoxImage.Information);
|
||||||
return;
|
return;
|
||||||
@@ -589,9 +668,8 @@ namespace OutlookAddin.Services
|
|||||||
{
|
{
|
||||||
Logger.Error(ex, "LaunchComposeFromCaseByIdAsync failed for caseId={CaseId}", caseId);
|
Logger.Error(ex, "LaunchComposeFromCaseByIdAsync failed for caseId={CaseId}", caseId);
|
||||||
if (mail != null) try { Marshal.ReleaseComObject(mail); } catch { }
|
if (mail != null) try { Marshal.ReleaseComObject(mail); } catch { }
|
||||||
MessageBox.Show(
|
ShowMessage(
|
||||||
"פתיחת המייל מתיק נכשלה: " + ex.Message,
|
"פתיחת המייל מתיק נכשלה: " + ex.Message,
|
||||||
"Marcus-Law OutlookAddin",
|
|
||||||
MessageBoxButton.OK,
|
MessageBoxButton.OK,
|
||||||
MessageBoxImage.Error);
|
MessageBoxImage.Error);
|
||||||
}
|
}
|
||||||
@@ -654,9 +732,8 @@ namespace OutlookAddin.Services
|
|||||||
{
|
{
|
||||||
if (!IsConfigured)
|
if (!IsConfigured)
|
||||||
{
|
{
|
||||||
var result = MessageBox.Show(
|
var result = ShowMessage(
|
||||||
"התוסף עדיין לא מוגדר. לפתוח את חלון ההגדרות עכשיו?",
|
"התוסף עדיין לא מוגדר. לפתוח את חלון ההגדרות עכשיו?",
|
||||||
"Marcus-Law OutlookAddin",
|
|
||||||
MessageBoxButton.YesNo,
|
MessageBoxButton.YesNo,
|
||||||
MessageBoxImage.Information);
|
MessageBoxImage.Information);
|
||||||
if (result == MessageBoxResult.Yes)
|
if (result == MessageBoxResult.Yes)
|
||||||
@@ -669,9 +746,8 @@ namespace OutlookAddin.Services
|
|||||||
var mailItems = ReadCurrentSelection();
|
var mailItems = ReadCurrentSelection();
|
||||||
if (mailItems.Count == 0)
|
if (mailItems.Count == 0)
|
||||||
{
|
{
|
||||||
MessageBox.Show(
|
ShowMessage(
|
||||||
"לא נבחר מייל לתיוק. סמן מייל אחד או יותר ונסה שוב.",
|
"לא נבחר מייל לתיוק. סמן מייל אחד או יותר ונסה שוב.",
|
||||||
"Marcus-Law OutlookAddin",
|
|
||||||
MessageBoxButton.OK,
|
MessageBoxButton.OK,
|
||||||
MessageBoxImage.Information);
|
MessageBoxImage.Information);
|
||||||
return;
|
return;
|
||||||
@@ -712,9 +788,8 @@ namespace OutlookAddin.Services
|
|||||||
Logger.Warning(
|
Logger.Warning(
|
||||||
"Filing skipped — selected EspoEntityRef has no usable Id/EntityType (id={Id}, name={Name}, type={Type})",
|
"Filing skipped — selected EspoEntityRef has no usable Id/EntityType (id={Id}, name={Name}, type={Type})",
|
||||||
vm.SelectedTarget?.Id, vm.SelectedTarget?.Name, vm.SelectedTarget?.EntityType);
|
vm.SelectedTarget?.Id, vm.SelectedTarget?.Name, vm.SelectedTarget?.EntityType);
|
||||||
MessageBox.Show(
|
ShowMessage(
|
||||||
"התיק שנבחר לא הוחזר עם סוג ישות (entityType) תקין. ייתכן ש-Klear שלך מחזיר שדה אחר; הלוג מכיל את הפרטים. שלח לאדמין.",
|
"התיק שנבחר לא הוחזר עם סוג ישות (entityType) תקין. ייתכן ש-Klear שלך מחזיר שדה אחר; הלוג מכיל את הפרטים. שלח לאדמין.",
|
||||||
"Marcus-Law OutlookAddin",
|
|
||||||
MessageBoxButton.OK,
|
MessageBoxButton.OK,
|
||||||
MessageBoxImage.Warning);
|
MessageBoxImage.Warning);
|
||||||
return;
|
return;
|
||||||
@@ -886,7 +961,7 @@ namespace OutlookAddin.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ShowSummary(FilingBatchSummary summary, FilingTarget target)
|
private void ShowSummary(FilingBatchSummary summary, FilingTarget target)
|
||||||
{
|
{
|
||||||
string message;
|
string message;
|
||||||
MessageBoxImage icon;
|
MessageBoxImage icon;
|
||||||
@@ -907,7 +982,7 @@ namespace OutlookAddin.Services
|
|||||||
icon = summary.FailedCount > 0 ? MessageBoxImage.Warning : MessageBoxImage.Information;
|
icon = summary.FailedCount > 0 ? MessageBoxImage.Warning : MessageBoxImage.Information;
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageBox.Show(message, "Marcus-Law OutlookAddin", MessageBoxButton.OK, icon);
|
ShowMessage(message, MessageBoxButton.OK, icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string? TryGetSenderName(Outlook.MailItem item)
|
private static string? TryGetSenderName(Outlook.MailItem item)
|
||||||
|
|||||||
@@ -42,21 +42,7 @@ namespace OutlookAddin.Services
|
|||||||
if (string.IsNullOrWhiteSpace(caseId)) throw new ArgumentException("caseId required", nameof(caseId));
|
if (string.IsNullOrWhiteSpace(caseId)) throw new ArgumentException("caseId required", nameof(caseId));
|
||||||
|
|
||||||
var caseEntity = await _client.GetCaseAsync(caseId, "id,name,number,status,contactsIds,accountId").ConfigureAwait(true);
|
var caseEntity = await _client.GetCaseAsync(caseId, "id,name,number,status,contactsIds,accountId").ConfigureAwait(true);
|
||||||
ContactEntity? primaryContact = null;
|
var recipientEmail = await ResolveRecipientEmailAsync(caseEntity, caseId).ConfigureAwait(true);
|
||||||
if (caseEntity.ContactsIds != null && caseEntity.ContactsIds.Count > 0)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
primaryContact = await _client.GetContactAsync(
|
|
||||||
caseEntity.ContactsIds[0],
|
|
||||||
"id,name,emailAddress",
|
|
||||||
default).ConfigureAwait(true);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.Warning(ex, "ComposeService: failed to load primary contact for case {CaseId}", caseId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var guid = Guid.NewGuid().ToString("N");
|
var guid = Guid.NewGuid().ToString("N");
|
||||||
StampUserProperty(mail, EspoCaseIdProperty, caseEntity.Id);
|
StampUserProperty(mail, EspoCaseIdProperty, caseEntity.Id);
|
||||||
@@ -65,14 +51,14 @@ namespace OutlookAddin.Services
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrWhiteSpace(primaryContact?.EmailAddress))
|
if (!string.IsNullOrWhiteSpace(recipientEmail))
|
||||||
{
|
{
|
||||||
var existingTo = mail.To ?? string.Empty;
|
var existingTo = mail.To ?? string.Empty;
|
||||||
if (!existingTo.Contains(primaryContact!.EmailAddress!))
|
if (!existingTo.Contains(recipientEmail!))
|
||||||
{
|
{
|
||||||
mail.To = string.IsNullOrEmpty(existingTo)
|
mail.To = string.IsNullOrEmpty(existingTo)
|
||||||
? primaryContact.EmailAddress
|
? recipientEmail
|
||||||
: existingTo + "; " + primaryContact.EmailAddress;
|
: existingTo + "; " + recipientEmail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,6 +93,61 @@ namespace OutlookAddin.Services
|
|||||||
new FilingTarget("Case", caseEntity.Id, caseEntity.Name ?? caseEntity.Id));
|
new FilingTarget("Case", caseEntity.Id, caseEntity.Name ?? caseEntity.Id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Find a usable recipient email for the case. EspoCRM's Case.contactsIds
|
||||||
|
/// is a many-to-many bag (primary + co-counsel + witnesses + …) and the
|
||||||
|
/// first entry isn't guaranteed to be the actual client — and even when
|
||||||
|
/// it is, the contact may have no emailAddress stored. So walk the list
|
||||||
|
/// and return the first non-empty address, then fall back to the
|
||||||
|
/// linked Account's email.
|
||||||
|
/// </summary>
|
||||||
|
private async Task<string?> ResolveRecipientEmailAsync(CaseEntity caseEntity, string caseId)
|
||||||
|
{
|
||||||
|
if (caseEntity.ContactsIds != null)
|
||||||
|
{
|
||||||
|
foreach (var contactId in caseEntity.ContactsIds)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(contactId)) continue;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var contact = await _client.GetContactAsync(
|
||||||
|
contactId,
|
||||||
|
"id,name,emailAddress,emailAddressData",
|
||||||
|
default).ConfigureAwait(true);
|
||||||
|
if (!string.IsNullOrWhiteSpace(contact?.EmailAddress))
|
||||||
|
{
|
||||||
|
return contact!.EmailAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Warning(ex, "ComposeService: failed to load contact {ContactId} for case {CaseId}", contactId, caseId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(caseEntity.AccountId))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var account = await _client.GetAccountAsync(
|
||||||
|
caseEntity.AccountId!,
|
||||||
|
"id,name,emailAddress",
|
||||||
|
default).ConfigureAwait(true);
|
||||||
|
if (!string.IsNullOrWhiteSpace(account?.EmailAddress))
|
||||||
|
{
|
||||||
|
return account!.EmailAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Warning(ex, "ComposeService: failed to load account {AccountId} for case {CaseId}", caseEntity.AccountId, caseId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public static string? ReadEspoCaseId(Outlook.MailItem mail) => TryReadUserProperty(mail, EspoCaseIdProperty);
|
public static string? ReadEspoCaseId(Outlook.MailItem mail) => TryReadUserProperty(mail, EspoCaseIdProperty);
|
||||||
public static string? ReadEspoCaseName(Outlook.MailItem mail) => TryReadUserProperty(mail, EspoCaseNameProperty);
|
public static string? ReadEspoCaseName(Outlook.MailItem mail) => TryReadUserProperty(mail, EspoCaseNameProperty);
|
||||||
public static string? ReadAddInGuid(Outlook.MailItem mail) => TryReadUserProperty(mail, AddInGuidProperty);
|
public static string? ReadAddInGuid(Outlook.MailItem mail) => TryReadUserProperty(mail, AddInGuidProperty);
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ namespace OutlookAddin
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
System.Windows.MessageBox.Show(
|
System.Windows.MessageBox.Show(
|
||||||
"האתחול של תוסף Marcus-Law נכשל: " + ex.Message,
|
"האתחול של תוסף Klear נכשל: " + ex.Message,
|
||||||
"Marcus-Law OutlookAddin",
|
"Klear",
|
||||||
System.Windows.MessageBoxButton.OK,
|
System.Windows.MessageBoxButton.OK,
|
||||||
System.Windows.MessageBoxImage.Error);
|
System.Windows.MessageBoxImage.Error);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user