Compare commits

..

2 Commits

Author SHA1 Message Date
agent_coder
703b883165 feat(temp-notes): add 'Move to trash' button to the temporary-note banner (closes #273)
The banner only offered 'Make permanent'. Add a secondary destructive
'Move to trash' button that soft-deletes the note now instead of waiting for
TTL expiry, reusing the tree/header soft-delete path (useTreeMutation.handleDelete):
optimistic tree removal, the undo-toast, the deletedAt cache stamp, and the
redirect to space home. No confirm modal (project convention = undo-toast).
Gated on the existing Edit permission. Client-only, no server/i18n changes
(both labels already exist).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 01:20:01 +03:00
2524f39a36 Merge pull request 'docs: how to bring up a local dev stand (+ gotchas), referenced from AGENTS.md' (#272) from docs/dev-stand-guide into develop
Reviewed-on: #272
2026-07-01 18:32:35 +03:00

View File

@@ -1,8 +1,10 @@
import { Button, Group, Paper, Text } from "@mantine/core"; import { Button, Group, Paper, Text } from "@mantine/core";
import { IconClockHour4 } from "@tabler/icons-react"; import { IconClockHour4, IconTrash } from "@tabler/icons-react";
import { useState } from "react";
import { Trans, useTranslation } from "react-i18next"; import { Trans, useTranslation } from "react-i18next";
import { useTimeAgo } from "@/hooks/use-time-ago.tsx"; import { useTimeAgo } from "@/hooks/use-time-ago.tsx";
import { usePageQuery } from "@/features/page/queries/page-query.ts"; import { usePageQuery } from "@/features/page/queries/page-query.ts";
import { useTreeMutation } from "@/features/page/tree/hooks/use-tree-mutation.ts";
import { import {
useToggleTemporaryMutation, useToggleTemporaryMutation,
syncTemporaryExpiresInCache, syncTemporaryExpiresInCache,
@@ -31,6 +33,11 @@ export function TemporaryNoteBanner({ slugId }: TemporaryNoteBannerProps) {
const spaceAbility = useSpaceAbility(space?.membership?.permissions); const spaceAbility = useSpaceAbility(space?.membership?.permissions);
const expiresTimeAgo = useTimeAgo(page?.temporaryExpiresAt); const expiresTimeAgo = useTimeAgo(page?.temporaryExpiresAt);
const toggleTemporary = useToggleTemporaryMutation(); const toggleTemporary = useToggleTemporaryMutation();
// Reuse the exact soft-delete path the tree/header menus use: optimistic
// tree removal, the "Page moved to trash" undo-toast, the deletedAt cache
// stamp, and the redirect to space home (which unmounts this banner).
const { handleDelete: trashPage } = useTreeMutation(page?.spaceId ?? "");
const [isDeleting, setIsDeleting] = useState(false);
// Don't show on a note that is already in trash; the deleted-page banner // Don't show on a note that is already in trash; the deleted-page banner
// owns that state. // owns that state.
@@ -38,6 +45,16 @@ export function TemporaryNoteBanner({ slugId }: TemporaryNoteBannerProps) {
const canEdit = spaceAbility.can(SpaceCaslAction.Edit, SpaceCaslSubject.Page); const canEdit = spaceAbility.can(SpaceCaslAction.Edit, SpaceCaslSubject.Page);
const handleTrashNow = async () => {
// No confirm modal by convention — the undo-toast is the safety net.
setIsDeleting(true);
try {
await trashPage(page.id);
} finally {
setIsDeleting(false);
}
};
const handleMakePermanent = async () => { const handleMakePermanent = async () => {
try { try {
const res = await toggleTemporary.mutateAsync({ const res = await toggleTemporary.mutateAsync({
@@ -70,16 +87,28 @@ export function TemporaryNoteBanner({ slugId }: TemporaryNoteBannerProps) {
</Text> </Text>
</Group> </Group>
{canEdit && ( {canEdit && (
<Button <Group gap="xs" wrap="nowrap">
size="xs" <Button
variant="light" size="xs"
color="orange" variant="subtle"
leftSection={<IconClockHour4 size={16} />} color="red"
onClick={handleMakePermanent} leftSection={<IconTrash size={16} />}
loading={toggleTemporary.isPending} onClick={handleTrashNow}
> loading={isDeleting}
{t("Make permanent")} >
</Button> {t("Move to trash")}
</Button>
<Button
size="xs"
variant="light"
color="orange"
leftSection={<IconClockHour4 size={16} />}
onClick={handleMakePermanent}
loading={toggleTemporary.isPending}
>
{t("Make permanent")}
</Button>
</Group>
)} )}
</Group> </Group>
</Paper> </Paper>