feat(mail): return exact messages from Quick Access
Module Package Release / publish-packages (push) Successful in 12s

This commit is contained in:
2026-08-21 16:03:29 +02:00
parent 2fe56fca00
commit cfd3847524
4 changed files with 66 additions and 11 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@govoplan/mail-webui",
"version": "0.1.18",
"version": "0.1.19",
"private": true,
"type": "module",
"main": "src/index.ts",
+45 -9
View File
@@ -1,8 +1,9 @@
import { useCallback, useRef, useState } from "react";
import { ExternalLink, FilePenLine, Mail, Pencil } from "lucide-react";
import { ExternalLink, FilePenLine, Mail, Pencil, X } from "lucide-react";
import { Link } from "react-router";
import {
DashboardWidgetList,
Button,
DismissibleAlert,
EmailAddressInput,
LoadingFrame,
@@ -34,10 +35,16 @@ type MailQuickAccessData = {
type Props = Pick<
QuickAccessToolRenderContext,
"settings" | "launchContext" | "close"
"settings" | "launchContext" | "complete" | "cancel" | "close"
>;
export default function MailQuickAccess({ settings, launchContext, close }: Props) {
export default function MailQuickAccess({
settings,
launchContext,
complete,
cancel,
close
}: Props) {
const [composing, setComposing] = useState(false);
const [recipients, setRecipients] = useState<MailboxAddress[]>([]);
const [suggestions, setSuggestions] = useState<MailboxAddress[]>([]);
@@ -60,6 +67,8 @@ export default function MailQuickAccess({ settings, launchContext, close }: Prop
};
}, [settings]);
const { data, loading, error } = useDashboardWidgetData(load, 0);
const selectingForCase = launchContext.activeObject?.ownerModule === "cases"
&& launchContext.activeObject.kind === "case";
const lookupRecipients = useCallback(async (query: string) => {
const request = ++lookupRequestRef.current;
@@ -85,6 +94,12 @@ export default function MailQuickAccess({ settings, launchContext, close }: Prop
return (
<LoadingFrame loading={loading} label="i18n:govoplan-mail.loading_messages.4294022c">
{error ? <DismissibleAlert tone="warning" resetKey={error}>{error}</DismissibleAlert> : null}
{selectingForCase ? (
<p className="muted small-note">
Select an authorized exact message for {launchContext.activeObject?.label}.
Mail content remains in Mail and access is checked again when opened.
</p>
) : null}
<DashboardWidgetList
emptyText={data?.available ? "i18n:govoplan-mail.no_messages_in_this_folder.5c7fa25d" : "i18n:govoplan-mail.select_an_imap_profile.5445648c"}
items={(data?.messages ?? []).map((message) => ({
@@ -93,12 +108,27 @@ export default function MailQuickAccess({ settings, launchContext, close }: Prop
detail: message.from_header || data?.profileName,
meta: formatMessageDate(message.date),
leading: <Mail size={17} aria-hidden="true" />,
to: mailboxMessageLaunchPath(data!.profileId!, message),
state: quickAccessLaunchState(launchContext),
onClick: close
to: selectingForCase
? undefined
: mailboxMessageLaunchPath(data!.profileId!, message),
state: selectingForCase ? undefined : quickAccessLaunchState(launchContext),
onClick: selectingForCase ? () => complete({
contractVersion: "1",
outcome: "completed",
action: "selected",
reference: {
ownerModule: "mail",
kind: "message",
objectId: `${data!.profileId!}:${message.folder}:${message.uid}`,
tenantId: launchContext.tenantId,
label: message.subject || "Mail message",
version: message.uid,
path: mailboxMessageLaunchPath(data!.profileId!, message)
}
}) : close
}))}
/>
{composing ? (
{!selectingForCase && composing ? (
<div className="mail-quick-compose" aria-label="i18n:govoplan-mail.compose">
<label>i18n:govoplan-mail.recipients</label>
<EmailAddressInput
@@ -125,7 +155,13 @@ export default function MailQuickAccess({ settings, launchContext, close }: Prop
</div>
</div>
) : null}
<div className="dashboard-contribution-footer">
{selectingForCase ? (
<div className="dashboard-contribution-footer">
<Button onClick={() => cancel("user")}>
<X size={15} aria-hidden="true" /> Cancel selection
</Button>
</div>
) : <div className="dashboard-contribution-footer">
<button type="button" className="btn btn-secondary" onClick={() => setComposing((current) => !current)} aria-expanded={composing}>
<Pencil size={15} aria-hidden="true" /> i18n:govoplan-mail.compose
</button>
@@ -147,7 +183,7 @@ export default function MailQuickAccess({ settings, launchContext, close }: Prop
>
<ExternalLink size={15} aria-hidden="true" /> i18n:govoplan-mail.open_mail
</Link>
</div>
</div>}
</LoadingFrame>
);
}