5242abb585
After reading the NetworkStorageIntegration repo I realized the previous
"save attachments" flow was wrong on every level — Marcus-Law doesn't
use EspoCRM's stock Document/DocumentFolder model. Folders are real
filesystem paths under the network share, named after the Case (format
"<number>-<primary contact name>") with four standard subfolders:
מסמכים, אסמכתאות, התכתבויות, כללי.
Rewire the save pipeline against the integration's real endpoints
(documented in routes.json on the server repo):
Core — three new IEspoCrmClient methods:
- EnsureCaseSubfoldersAsync(caseId)
POST /NetworkStorage/action/createSubfolders
Idempotent — creates case folder + defaults if missing.
- ListNetworkStorageFolderAsync(path)
GET /NetworkStorage/folderContents?path=…
Returns folders + files; we filter to type=folder for the dropdown.
- UploadAttachmentToNetworkStorageAsync(attachmentId, targetPath)
POST /NetworkStorage/action/upload
Moves the staged Attachment binary onto the share at <path>/<name>.
CaseEntity gets a new `networkStorageFolderPath` field (set by the
integration's hook on first Document save; empty until then).
NetworkStorageItem DTO captures the folder-listing rows.
AttachmentSaveService rewritten — no more Document creation, no more
DocumentFolder picker. The new contract is:
SaveAsync(attachments, targetFolderPath)
Where targetFolderPath = "<case folder>[/subfolder]". For each
attachment: upload binary via standard /Attachment, then move via
NetworkStorage upload.
UI — SaveAttachmentsViewModel:
- Subfolder dropdown switched from DocumentFolder objects to strings.
- Static defaults loaded up-front:
"(שורש התיק)" + 4 server-side defaults.
- When the user picks a case:
1) hydrate Case (number + networkStorageFolderPath) via GetCase
2) call EnsureCaseSubfoldersAsync to materialise standard folders
3) listFolder at the case path to merge any custom subfolders into
the dropdown.
- ResolveCaseFolderPath: use Case.networkStorageFolderPath if set,
otherwise compute "<number>-<contact-name>" with a client-side
SanitizeFolderSegment that mirrors LocalFilesystemClient::sanitizeFileName
on the server (geresh/gershayim/quotes removed, illegal chars → hyphen).
AddInHost.LaunchSaveAttachmentsAsync:
- Composes <caseFolder>[/subfolder] from the VM choice.
- Pre-flight ensureCaseSubfolders as a safety net (in case the user
submitted before the dialog's lazy refresh completed).
- Summary MessageBox now shows the resolved storage path instead of a
bare entity name.
Tests: 39 passing. The build is clean across Core / UI / Tests.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
28 lines
825 B
C#
28 lines
825 B
C#
using System.Text.Json.Serialization;
|
|
|
|
namespace MarcusLaw.OutlookAddin.Core.Models
|
|
{
|
|
/// <summary>
|
|
/// One row from GET /NetworkStorage/folderContents — folder or file.
|
|
/// </summary>
|
|
public sealed class NetworkStorageItem
|
|
{
|
|
[JsonPropertyName("name")]
|
|
public string Name { get; set; } = string.Empty;
|
|
|
|
[JsonPropertyName("path")]
|
|
public string Path { get; set; } = string.Empty;
|
|
|
|
[JsonPropertyName("type")]
|
|
public string Type { get; set; } = string.Empty; // "folder" or "file"
|
|
|
|
[JsonPropertyName("size")]
|
|
public long Size { get; set; }
|
|
|
|
[JsonPropertyName("modified")]
|
|
public string? Modified { get; set; }
|
|
|
|
public bool IsFolder => string.Equals(Type, "folder", System.StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
}
|