feat(webui): complete postbox quick access
This commit is contained in:
@@ -400,6 +400,8 @@ manifest = ModuleManifest(
|
|||||||
required_any=(READ_SCOPE,),
|
required_any=(READ_SCOPE,),
|
||||||
order=20,
|
order=20,
|
||||||
modes=("browse", "author"),
|
modes=("browse", "author"),
|
||||||
|
returned_reference_kinds=("postbox.message",),
|
||||||
|
help_context_id="postbox.quick_access.messages",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -478,9 +480,12 @@ manifest = ModuleManifest(
|
|||||||
title="Postbox in Communication and Messages",
|
title="Postbox in Communication and Messages",
|
||||||
summary="Use function-bound Postboxes in Communication and the shared Messages Quick Access drawer.",
|
summary="Use function-bound Postboxes in Communication and the shared Messages Quick Access drawer.",
|
||||||
body=(
|
body=(
|
||||||
"Postbox contributes its inbox to Communication. With Quick Access enabled, its owner-rendered unread summary "
|
"Postbox contributes its inbox to Communication. With Quick Access enabled, its owner-rendered surface lists at most "
|
||||||
"appears beside Mail and future chat providers inside Messages while retaining function assignment, classification, "
|
"seven currently readable unread messages beside independent Mail and future chat providers. Selecting or opening a "
|
||||||
"read-receipt, retention, encryption, and evidence semantics in Postbox."
|
"message returns a typed Postbox reference; accounts with message-write permission can launch the full owner-rendered "
|
||||||
|
"composer for a currently accessible function Postbox. Directory, message, and submission calls recheck the active "
|
||||||
|
"assignment or acting context. Function assignment, classification, read-receipt, retention, encryption, and evidence "
|
||||||
|
"semantics remain in Postbox."
|
||||||
),
|
),
|
||||||
layer="configured",
|
layer="configured",
|
||||||
documentation_types=("user", "admin"),
|
documentation_types=("user", "admin"),
|
||||||
@@ -492,8 +497,11 @@ manifest = ModuleManifest(
|
|||||||
"summary": "Funktionsgebundene Postfächer in Kommunikation und der gemeinsamen Schnellzugriffseinblendung Nachrichten verwenden.",
|
"summary": "Funktionsgebundene Postfächer in Kommunikation und der gemeinsamen Schnellzugriffseinblendung Nachrichten verwenden.",
|
||||||
"body": (
|
"body": (
|
||||||
"Postbox ordnet seinen Eingang Kommunikation zu. Ist der Schnellzugriff aktiviert, erscheint die vom Modul gerenderte "
|
"Postbox ordnet seinen Eingang Kommunikation zu. Ist der Schnellzugriff aktiviert, erscheint die vom Modul gerenderte "
|
||||||
"Zusammenfassung ungelesener Nachrichten neben Mail und künftigen Chat-Anbietern unter Nachrichten. "
|
"Oberfläche mit höchstens sieben aktuell lesbaren ungelesenen Nachrichten neben unabhängigen Beiträgen aus Mail. "
|
||||||
"Funktionszuordnung, Klassifikation, Lesestatus, Aufbewahrung, Verschlüsselung und Nachweise verbleiben bei Postbox."
|
"Auswahl oder Öffnen liefert eine typisierte Postbox-Referenz; mit Schreibberechtigung lässt sich der vollständige "
|
||||||
|
"Editor für ein aktuell zugängliches Funktionspostfach öffnen. Verzeichnis, Nachricht und Versand prüfen die aktive "
|
||||||
|
"Zuweisung beziehungsweise den Handlungskontext erneut. Klassifikation, Lesestatus, Aufbewahrung, Verschlüsselung "
|
||||||
|
"und Nachweise verbleiben bei Postbox."
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from govoplan_postbox.backend.manifest import manifest
|
from govoplan_postbox.backend.manifest import manifest
|
||||||
|
|
||||||
|
|
||||||
|
REPOSITORY_ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
|
||||||
|
|
||||||
class PostboxInterfaceDocumentationContractTests(unittest.TestCase):
|
class PostboxInterfaceDocumentationContractTests(unittest.TestCase):
|
||||||
def test_route_and_contributed_surfaces_remain_declared(self) -> None:
|
def test_route_and_contributed_surfaces_remain_declared(self) -> None:
|
||||||
frontend = manifest.frontend
|
frontend = manifest.frontend
|
||||||
@@ -41,6 +45,27 @@ class PostboxInterfaceDocumentationContractTests(unittest.TestCase):
|
|||||||
self.assertIn("archive_postbox", reference.metadata["consequence_classes"])
|
self.assertIn("archive_postbox", reference.metadata["consequence_classes"])
|
||||||
self.assertIn("withdraw_or_expire", reference.metadata["consequence_classes"])
|
self.assertIn("withdraw_or_expire", reference.metadata["consequence_classes"])
|
||||||
|
|
||||||
|
quick_tool = manifest.frontend.quick_access_tools[0]
|
||||||
|
self.assertEqual(("postbox.message",), quick_tool.returned_reference_kinds)
|
||||||
|
self.assertEqual("postbox.quick_access.messages", quick_tool.help_context_id)
|
||||||
|
self.assertEqual("/postbox", quick_tool.full_page_path)
|
||||||
|
|
||||||
|
def test_quick_access_is_bounded_and_owner_launched(self) -> None:
|
||||||
|
quick_access = (
|
||||||
|
REPOSITORY_ROOT / "webui/src/features/postbox/PostboxQuickAccess.tsx"
|
||||||
|
).read_text(encoding="utf-8")
|
||||||
|
page = (
|
||||||
|
REPOSITORY_ROOT / "webui/src/features/postbox/PostboxPage.tsx"
|
||||||
|
).read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
self.assertIn("const MESSAGE_LIMIT = 7", quick_access)
|
||||||
|
self.assertIn('"unread"', quick_access)
|
||||||
|
self.assertIn('kind: "message"', quick_access)
|
||||||
|
self.assertIn("launchContext.actingContext", quick_access)
|
||||||
|
self.assertIn("quickAccessLaunchState(launchContext)", quick_access)
|
||||||
|
self.assertIn('parameters.get("quickAction") !== "compose"', page)
|
||||||
|
self.assertIn("openComposeFor(postbox)", page)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import { FormGrid,
|
|||||||
type ApiSettings,
|
type ApiSettings,
|
||||||
type AuthInfo
|
type AuthInfo
|
||||||
} from "@govoplan/core-webui";
|
} from "@govoplan/core-webui";
|
||||||
|
import { useLocation, useNavigate } from "react-router";
|
||||||
import {
|
import {
|
||||||
createPostboxGrouping,
|
createPostboxGrouping,
|
||||||
createPostboxMessage,
|
createPostboxMessage,
|
||||||
@@ -110,13 +111,16 @@ export default function PostboxPage({
|
|||||||
settings: ApiSettings;
|
settings: ApiSettings;
|
||||||
auth: AuthInfo;
|
auth: AuthInfo;
|
||||||
}) {
|
}) {
|
||||||
|
const location = useLocation();
|
||||||
|
const navigate = useNavigate();
|
||||||
const requestedMessageId = useRef(
|
const requestedMessageId = useRef(
|
||||||
new URLSearchParams(window.location.search).get("message") ?? ""
|
new URLSearchParams(location.search).get("message") ?? ""
|
||||||
);
|
);
|
||||||
const requestedPostboxId = useRef(
|
const requestedPostboxId = useRef(
|
||||||
new URLSearchParams(window.location.search).get("postbox") ?? ""
|
new URLSearchParams(location.search).get("postbox") ?? ""
|
||||||
);
|
);
|
||||||
const requestedMessageLoaded = useRef(false);
|
const requestedMessageLoaded = useRef(false);
|
||||||
|
const requestedComposeLoaded = useRef(false);
|
||||||
const [postboxes, setPostboxes] = useState<PostboxDirectoryItem[]>([]);
|
const [postboxes, setPostboxes] = useState<PostboxDirectoryItem[]>([]);
|
||||||
const [groupings, setGroupings] = useState<PostboxGrouping[]>([]);
|
const [groupings, setGroupings] = useState<PostboxGrouping[]>([]);
|
||||||
const [selectedScope, setSelectedScope] = useState("all");
|
const [selectedScope, setSelectedScope] = useState("all");
|
||||||
@@ -269,6 +273,44 @@ export default function PostboxPage({
|
|||||||
void loadDirectory();
|
void loadDirectory();
|
||||||
}, [loadDirectory]);
|
}, [loadDirectory]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const parameters = new URLSearchParams(location.search);
|
||||||
|
if (
|
||||||
|
requestedComposeLoaded.current ||
|
||||||
|
parameters.get("quickAction") !== "compose" ||
|
||||||
|
loadingDirectory
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
requestedComposeLoaded.current = true;
|
||||||
|
const requestedId = parameters.get("postbox");
|
||||||
|
const postbox =
|
||||||
|
postboxes.find((item) => item.id === requestedId) ?? postboxes[0] ?? null;
|
||||||
|
if (canSend && postbox) {
|
||||||
|
setSelectedPostboxId(postbox.id);
|
||||||
|
openComposeFor(postbox);
|
||||||
|
} else if (!canSend) {
|
||||||
|
setError(POSTBOX_INTERFACE_I18N.noSendReason);
|
||||||
|
} else {
|
||||||
|
setError(POSTBOX_INTERFACE_I18N.noPostbox);
|
||||||
|
}
|
||||||
|
|
||||||
|
parameters.delete("quickAction");
|
||||||
|
const search = parameters.toString();
|
||||||
|
navigate(
|
||||||
|
{ pathname: location.pathname, search: search ? `?${search}` : "" },
|
||||||
|
{ replace: true, state: location.state }
|
||||||
|
);
|
||||||
|
}, [
|
||||||
|
canSend,
|
||||||
|
loadingDirectory,
|
||||||
|
location.pathname,
|
||||||
|
location.search,
|
||||||
|
location.state,
|
||||||
|
navigate,
|
||||||
|
postboxes
|
||||||
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
void loadMessages();
|
void loadMessages();
|
||||||
}, [loadMessages]);
|
}, [loadMessages]);
|
||||||
@@ -469,6 +511,10 @@ export default function PostboxPage({
|
|||||||
function openCompose() {
|
function openCompose() {
|
||||||
const postbox = selectedPostbox ?? postboxes[0] ?? null;
|
const postbox = selectedPostbox ?? postboxes[0] ?? null;
|
||||||
if (!postbox) return;
|
if (!postbox) return;
|
||||||
|
openComposeFor(postbox);
|
||||||
|
}
|
||||||
|
|
||||||
|
function openComposeFor(postbox: PostboxDirectoryItem) {
|
||||||
setReplyParent(null);
|
setReplyParent(null);
|
||||||
const next = {
|
const next = {
|
||||||
...emptyMessageDraft(),
|
...emptyMessageDraft(),
|
||||||
|
|||||||
@@ -0,0 +1,160 @@
|
|||||||
|
import { ExternalLink, Inbox, Pencil, Send } from "lucide-react";
|
||||||
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
|
import { Link } from "react-router";
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
DismissibleAlert,
|
||||||
|
LoadingFrame,
|
||||||
|
SelectionList,
|
||||||
|
SelectionListItem,
|
||||||
|
SelectionListItemContent,
|
||||||
|
hasScope,
|
||||||
|
quickAccessLaunchState,
|
||||||
|
useDashboardWidgetData,
|
||||||
|
usePlatformLanguage,
|
||||||
|
type QuickAccessToolRenderContext
|
||||||
|
} from "@govoplan/core-webui";
|
||||||
|
import {
|
||||||
|
listPostboxMessages,
|
||||||
|
listPostboxes,
|
||||||
|
type PostboxMessage
|
||||||
|
} from "../../api/postbox";
|
||||||
|
|
||||||
|
const MESSAGE_LIMIT = 7;
|
||||||
|
|
||||||
|
type Props = Pick<
|
||||||
|
QuickAccessToolRenderContext,
|
||||||
|
"settings" | "auth" | "launchContext" | "complete" | "close"
|
||||||
|
>;
|
||||||
|
|
||||||
|
/** Function-bound projection; Postbox re-evaluates the current acting context. */
|
||||||
|
export default function PostboxQuickAccess({
|
||||||
|
settings,
|
||||||
|
auth,
|
||||||
|
launchContext,
|
||||||
|
complete,
|
||||||
|
close
|
||||||
|
}: Props) {
|
||||||
|
const { language } = usePlatformLanguage();
|
||||||
|
const [selectedId, setSelectedId] = useState("");
|
||||||
|
const load = useCallback(async () => {
|
||||||
|
const postboxes = await listPostboxes(settings);
|
||||||
|
if (!postboxes.length) return { postboxes, messages: [], total: 0 };
|
||||||
|
const response = await listPostboxMessages(
|
||||||
|
settings,
|
||||||
|
postboxes.map((postbox) => postbox.id),
|
||||||
|
MESSAGE_LIMIT,
|
||||||
|
0,
|
||||||
|
"",
|
||||||
|
"unread"
|
||||||
|
);
|
||||||
|
return { postboxes, ...response };
|
||||||
|
}, [settings]);
|
||||||
|
const { data, loading, error } = useDashboardWidgetData(load, 0);
|
||||||
|
const messages = data?.messages ?? [];
|
||||||
|
const selected = useMemo(
|
||||||
|
() => messages.find((message) => message.id === selectedId) ?? messages[0] ?? null,
|
||||||
|
[messages, selectedId]
|
||||||
|
);
|
||||||
|
const selectedPostbox = data?.postboxes.find(
|
||||||
|
(postbox) => postbox.id === selected?.postbox_id
|
||||||
|
) ?? data?.postboxes[0] ?? null;
|
||||||
|
const canCompose = hasScope(auth, "postbox:message:write");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!selectedId && messages[0]) setSelectedId(messages[0].id);
|
||||||
|
if (selectedId && !messages.some((message) => message.id === selectedId)) {
|
||||||
|
setSelectedId(messages[0]?.id ?? "");
|
||||||
|
}
|
||||||
|
}, [messages, selectedId]);
|
||||||
|
|
||||||
|
function selectForHost(message: PostboxMessage) {
|
||||||
|
complete({
|
||||||
|
contractVersion: "1",
|
||||||
|
outcome: "completed",
|
||||||
|
action: "selected",
|
||||||
|
reference: {
|
||||||
|
ownerModule: "postbox",
|
||||||
|
kind: "message",
|
||||||
|
objectId: message.id,
|
||||||
|
tenantId: message.tenant_id,
|
||||||
|
label: message.subject,
|
||||||
|
version: `${message.status}:${message.delivered_at}`,
|
||||||
|
path: `/postbox?message=${encodeURIComponent(message.id)}`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LoadingFrame loading={loading} label="i18n:govoplan-postbox.quick_loading_unread">
|
||||||
|
{launchContext.actingContext?.assignmentId ? (
|
||||||
|
<p className="muted small-note">
|
||||||
|
i18n:govoplan-postbox.quick_acting_context
|
||||||
|
</p>
|
||||||
|
) : null}
|
||||||
|
{error ? <DismissibleAlert tone="warning" resetKey={error}>{error}</DismissibleAlert> : null}
|
||||||
|
|
||||||
|
{messages.length ? (
|
||||||
|
<SelectionList variant="navigation" label="i18n:govoplan-postbox.quick_unread_messages">
|
||||||
|
{messages.map((message) => (
|
||||||
|
<SelectionListItem
|
||||||
|
key={message.id}
|
||||||
|
selected={selected?.id === message.id}
|
||||||
|
onClick={() => setSelectedId(message.id)}
|
||||||
|
>
|
||||||
|
<SelectionListItemContent
|
||||||
|
leading={<Inbox size={16} aria-hidden="true" />}
|
||||||
|
title={message.subject}
|
||||||
|
description={`${message.sender_label || message.producer_module || "Postbox"} · ${messageDate(message, language)}`}
|
||||||
|
/>
|
||||||
|
</SelectionListItem>
|
||||||
|
))}
|
||||||
|
</SelectionList>
|
||||||
|
) : !loading && !error ? (
|
||||||
|
<p className="muted">i18n:govoplan-postbox.quick_no_unread</p>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{selected ? (
|
||||||
|
<section className="postbox-quick-detail" aria-label="i18n:govoplan-postbox.quick_message_details">
|
||||||
|
<strong>{selected.subject}</strong>
|
||||||
|
<span>{selectedPostbox?.function_name || selectedPostbox?.name}</span>
|
||||||
|
{selected.body_text ? <p>{selected.body_text}</p> : null}
|
||||||
|
<div className="button-row compact-actions">
|
||||||
|
<Button variant="primary" onClick={() => selectForHost(selected)}>
|
||||||
|
<Send size={15} aria-hidden="true" /> i18n:govoplan-postbox.quick_select_message
|
||||||
|
</Button>
|
||||||
|
<Link
|
||||||
|
className="btn btn-secondary"
|
||||||
|
to={`/postbox?message=${encodeURIComponent(selected.id)}`}
|
||||||
|
state={quickAccessLaunchState(launchContext)}
|
||||||
|
onClick={() => selectForHost(selected)}
|
||||||
|
>
|
||||||
|
<ExternalLink size={15} aria-hidden="true" /> i18n:govoplan-postbox.quick_open_message
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
<div className="dashboard-contribution-footer">
|
||||||
|
{canCompose && selectedPostbox ? (
|
||||||
|
<Link
|
||||||
|
className="btn btn-secondary"
|
||||||
|
to={`/postbox?quickAction=compose&postbox=${encodeURIComponent(selectedPostbox.id)}`}
|
||||||
|
state={quickAccessLaunchState(launchContext)}
|
||||||
|
onClick={close}
|
||||||
|
>
|
||||||
|
<Pencil size={15} aria-hidden="true" /> i18n:govoplan-postbox.quick_compose
|
||||||
|
</Link>
|
||||||
|
) : null}
|
||||||
|
<span className="muted small-note">{messages.length} / {data?.total ?? 0}</span>
|
||||||
|
</div>
|
||||||
|
</LoadingFrame>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function messageDate(message: PostboxMessage, language: string): string {
|
||||||
|
return new Intl.DateTimeFormat(language, {
|
||||||
|
dateStyle: "medium",
|
||||||
|
timeStyle: "short"
|
||||||
|
}).format(new Date(message.delivered_at));
|
||||||
|
}
|
||||||
@@ -3,6 +3,14 @@ import type { PlatformTranslations } from "@govoplan/core-webui";
|
|||||||
const en = {
|
const en = {
|
||||||
"i18n:govoplan-postbox.postbox": "Postbox",
|
"i18n:govoplan-postbox.postbox": "Postbox",
|
||||||
"i18n:govoplan-postbox.quick_access_description": "Institutional messages addressed to your functions.",
|
"i18n:govoplan-postbox.quick_access_description": "Institutional messages addressed to your functions.",
|
||||||
|
"i18n:govoplan-postbox.quick_loading_unread": "Loading unread Postbox messages",
|
||||||
|
"i18n:govoplan-postbox.quick_acting_context": "Showing messages for the current acting assignment.",
|
||||||
|
"i18n:govoplan-postbox.quick_unread_messages": "Unread Postbox messages",
|
||||||
|
"i18n:govoplan-postbox.quick_no_unread": "No unread Postbox messages.",
|
||||||
|
"i18n:govoplan-postbox.quick_message_details": "Postbox message details",
|
||||||
|
"i18n:govoplan-postbox.quick_select_message": "Select message",
|
||||||
|
"i18n:govoplan-postbox.quick_open_message": "Open message",
|
||||||
|
"i18n:govoplan-postbox.quick_compose": "Compose message",
|
||||||
"i18n:govoplan-postbox.postboxes": "Postboxes",
|
"i18n:govoplan-postbox.postboxes": "Postboxes",
|
||||||
"i18n:govoplan-postbox.postbox_inbox": "Postbox inbox",
|
"i18n:govoplan-postbox.postbox_inbox": "Postbox inbox",
|
||||||
"i18n:govoplan-postbox.postbox_inbox_description": "Unread messages across accessible Postboxes.",
|
"i18n:govoplan-postbox.postbox_inbox_description": "Unread messages across accessible Postboxes.",
|
||||||
@@ -237,6 +245,14 @@ const de = {
|
|||||||
...en,
|
...en,
|
||||||
"i18n:govoplan-postbox.postbox": "Postfach",
|
"i18n:govoplan-postbox.postbox": "Postfach",
|
||||||
"i18n:govoplan-postbox.quick_access_description": "Institutionelle Nachrichten an Ihre Funktionen.",
|
"i18n:govoplan-postbox.quick_access_description": "Institutionelle Nachrichten an Ihre Funktionen.",
|
||||||
|
"i18n:govoplan-postbox.quick_loading_unread": "Ungelesene Postfachnachrichten werden geladen",
|
||||||
|
"i18n:govoplan-postbox.quick_acting_context": "Nachrichten der aktuellen Handlungszuweisung werden angezeigt.",
|
||||||
|
"i18n:govoplan-postbox.quick_unread_messages": "Ungelesene Postfachnachrichten",
|
||||||
|
"i18n:govoplan-postbox.quick_no_unread": "Keine ungelesenen Postfachnachrichten.",
|
||||||
|
"i18n:govoplan-postbox.quick_message_details": "Details der Postfachnachricht",
|
||||||
|
"i18n:govoplan-postbox.quick_select_message": "Nachricht auswählen",
|
||||||
|
"i18n:govoplan-postbox.quick_open_message": "Nachricht öffnen",
|
||||||
|
"i18n:govoplan-postbox.quick_compose": "Nachricht verfassen",
|
||||||
"i18n:govoplan-postbox.postboxes": "Postfächer",
|
"i18n:govoplan-postbox.postboxes": "Postfächer",
|
||||||
"i18n:govoplan-postbox.postbox_inbox": "Postfach-Eingang",
|
"i18n:govoplan-postbox.postbox_inbox": "Postfach-Eingang",
|
||||||
"i18n:govoplan-postbox.postbox_inbox_description": "Ungelesene Nachrichten aus zugänglichen Postfächern.",
|
"i18n:govoplan-postbox.postbox_inbox_description": "Ungelesene Nachrichten aus zugänglichen Postfächern.",
|
||||||
|
|||||||
+2
-5
@@ -8,6 +8,7 @@ import {
|
|||||||
} from "@govoplan/core-webui";
|
} from "@govoplan/core-webui";
|
||||||
import { generatedTranslations } from "./i18n/generatedTranslations";
|
import { generatedTranslations } from "./i18n/generatedTranslations";
|
||||||
import PostboxInboxWidget from "./features/postbox/PostboxInboxWidget";
|
import PostboxInboxWidget from "./features/postbox/PostboxInboxWidget";
|
||||||
|
import PostboxQuickAccess from "./features/postbox/PostboxQuickAccess";
|
||||||
import "./styles/postbox.css";
|
import "./styles/postbox.css";
|
||||||
|
|
||||||
|
|
||||||
@@ -64,11 +65,7 @@ const postboxQuickAccessTools: QuickAccessToolsUiCapability = {
|
|||||||
tools: [
|
tools: [
|
||||||
{
|
{
|
||||||
id: "postbox.messages",
|
id: "postbox.messages",
|
||||||
render: ({ settings }) => createElement(PostboxInboxWidget, {
|
render: (context) => createElement(PostboxQuickAccess, context)
|
||||||
settings,
|
|
||||||
refreshKey: 0,
|
|
||||||
configuration: { maxItems: 7 }
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -554,6 +554,28 @@
|
|||||||
resize: vertical;
|
resize: vertical;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.postbox-quick-detail {
|
||||||
|
display: grid;
|
||||||
|
gap: 7px;
|
||||||
|
margin-top: 12px;
|
||||||
|
border-top: var(--border-line);
|
||||||
|
padding-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postbox-quick-detail > span,
|
||||||
|
.postbox-quick-detail > p {
|
||||||
|
margin: 0;
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.postbox-quick-detail > p {
|
||||||
|
display: -webkit-box;
|
||||||
|
overflow: hidden;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 4;
|
||||||
|
}
|
||||||
|
|
||||||
.postbox-dialog-actions.end {
|
.postbox-dialog-actions.end {
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
|||||||
Reference in New Issue
Block a user