Skip to main content
Glama

Storyden

by Southclaws
Mozilla Public License 2.0
229
useLibraryPageMenu.ts5.46 kB
import { MenuSelectionDetails } from "@ark-ui/react"; import { match } from "ts-pattern"; import { Account, Node, Permission, Visibility } from "src/api/openapi-schema"; import { useSession } from "src/auth"; import { handle } from "@/api/client"; import { useConfirmation } from "@/components/site/useConfirmation"; import { useLibraryMutation } from "@/lib/library/library"; import { hasPermission } from "@/utils/permissions"; export type Props = { node: Node; onClose?: () => void; }; export function useLibraryPageMenu(props: Props) { const account = useSession(); const { deleteNode, updateNodeVisibility, updateNodeChildVisibility, revalidate, } = useLibraryMutation(props.node); const { isConfirming: isConfirmingDelete, handleConfirmAction: handleConfirmDelete, handleCancelAction: handleCancelDelete, } = useConfirmation(handleDelete); const isManager = hasPermission(account, Permission.MANAGE_LIBRARY); const isOwner = account?.id === props.node.owner.id; const availableOperations = visibilityStateChanges[ props.node.visibility ].filter((c) => account && c.condition(account, props.node)); // Managers can delete any page, owners can only delete non-published pages. const deleteEnabled = isManager || (isOwner && props.node.visibility !== Visibility.published); const isChildrenHidden = props.node.hide_child_tree; async function handleToggleChildrenVisibility() { await handle( async () => { await updateNodeChildVisibility(props.node.slug, !isChildrenHidden); }, { promiseToast: { loading: "Saving...", success: match(!isChildrenHidden) .with(true, () => "Children hidden from sidebar") .with(false, () => "Children visible in sidebar") .exhaustive(), }, }, ); } async function handleDelete() { return handle( async () => { await deleteNode(props.node.slug); }, { cleanup: async () => await revalidate(), }, ); } async function handleVisibilityChange(visibility: Visibility) { await handle( async () => { await updateNodeVisibility(props.node.slug, visibility); }, { promiseToast: { loading: "Saving...", success: match(visibility) .with(Visibility.published, () => "Published") .with(Visibility.draft, () => "Set to draft") .with(Visibility.review, () => "Submitted for review") .with(Visibility.unlisted, () => "Set to unlisted") .exhaustive(), }, cleanup: () => revalidate(), }, ); } function handleSelect({ value }: MenuSelectionDetails) { if (value === "report-node") { return; } switch (value as Visibility | "toggle-hide-in-tree" | "delete") { case "toggle-hide-in-tree": return handleToggleChildrenVisibility(); case "delete": return handleConfirmDelete(); case Visibility.draft: return handleVisibilityChange(Visibility.draft); case Visibility.unlisted: return handleVisibilityChange(Visibility.unlisted); case Visibility.review: return handleVisibilityChange(Visibility.review); case Visibility.published: return handleVisibilityChange(Visibility.published); } } return { availableOperations, deleteEnabled, isConfirmingDelete, isChildrenHidden, isManager, handlers: { handleCancelDelete, handleSelect, }, }; } type VisibilityStateChangeMenuItem = { label: string; targetVisibility: Visibility; condition: (account: Account, node: Node) => boolean; }; const visibilityStateChanges: Record< Visibility, VisibilityStateChangeMenuItem[] > = { [Visibility.draft]: [ { label: "Publish to library", targetVisibility: Visibility.published, condition: (account) => hasPermission(account, Permission.MANAGE_LIBRARY), }, { label: "Submit for review", targetVisibility: Visibility.review, condition: (account, node) => account.id === node.owner.id, }, { label: "Publish to profile", targetVisibility: Visibility.unlisted, condition: (account, node) => account.id === node.owner.id, }, ], [Visibility.unlisted]: [ { label: "Revert to draft", targetVisibility: Visibility.draft, condition: (account, node) => account.id === node.owner.id, }, { label: "Submit for review", targetVisibility: Visibility.review, condition: (account, node) => account.id === node.owner.id, }, ], [Visibility.review]: [ { label: "Publish to library", targetVisibility: Visibility.published, condition: (account) => hasPermission(account, Permission.MANAGE_LIBRARY), }, { label: "Reject", targetVisibility: Visibility.draft, condition: (account, node) => account.id !== node.owner.id && hasPermission(account, Permission.MANAGE_LIBRARY), }, { label: "Revert to draft", targetVisibility: Visibility.draft, condition: (account, node) => account.id === node.owner.id, }, ], [Visibility.published]: [ { label: "Unpublish", targetVisibility: Visibility.draft, condition: (account) => hasPermission(account, Permission.MANAGE_LIBRARY), }, ], };

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Southclaws/storyden'

If you have feedback or need assistance with the MCP directory API, please join our Discord server