@burdenoff/microfe-conversations 2026.510.117
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/dist/__tests__/setup.d.ts +2 -0
- package/dist/__tests__/setup.d.ts.map +1 -0
- package/dist/conversations/ConversationsAdminRoot.d.ts +19 -0
- package/dist/conversations/ConversationsAdminRoot.d.ts.map +1 -0
- package/dist/conversations/ConversationsAdminRoot.js +104 -0
- package/dist/conversations/ConversationsAdminRoot.js.map +1 -0
- package/dist/conversations/ConversationsAdminRoutes.d.ts +18 -0
- package/dist/conversations/ConversationsAdminRoutes.d.ts.map +1 -0
- package/dist/conversations/ConversationsAdminRoutes.js +42 -0
- package/dist/conversations/ConversationsAdminRoutes.js.map +1 -0
- package/dist/conversations/ConversationsRoot.d.ts +33 -0
- package/dist/conversations/ConversationsRoot.d.ts.map +1 -0
- package/dist/conversations/ConversationsRoot.js +100 -0
- package/dist/conversations/ConversationsRoot.js.map +1 -0
- package/dist/conversations/ConversationsUserRoot.d.ts +17 -0
- package/dist/conversations/ConversationsUserRoot.d.ts.map +1 -0
- package/dist/conversations/ConversationsUserRoot.js +101 -0
- package/dist/conversations/ConversationsUserRoot.js.map +1 -0
- package/dist/conversations/ConversationsUserRoutes.d.ts +12 -0
- package/dist/conversations/ConversationsUserRoutes.d.ts.map +1 -0
- package/dist/conversations/ConversationsUserRoutes.js +45 -0
- package/dist/conversations/ConversationsUserRoutes.js.map +1 -0
- package/dist/conversations/components/ConversationCard.d.ts +14 -0
- package/dist/conversations/components/ConversationCard.d.ts.map +1 -0
- package/dist/conversations/components/ConversationCard.js +118 -0
- package/dist/conversations/components/ConversationCard.js.map +1 -0
- package/dist/conversations/components/LazyPageBoundary.d.ts +25 -0
- package/dist/conversations/components/LazyPageBoundary.d.ts.map +1 -0
- package/dist/conversations/components/LazyPageBoundary.js +144 -0
- package/dist/conversations/components/LazyPageBoundary.js.map +1 -0
- package/dist/conversations/components/MessageBubble.d.ts +21 -0
- package/dist/conversations/components/MessageBubble.d.ts.map +1 -0
- package/dist/conversations/components/MessageBubble.js +242 -0
- package/dist/conversations/components/MessageBubble.js.map +1 -0
- package/dist/conversations/components/PageLayout.d.ts +55 -0
- package/dist/conversations/components/PageLayout.d.ts.map +1 -0
- package/dist/conversations/components/PageLayout.js +93 -0
- package/dist/conversations/components/PageLayout.js.map +1 -0
- package/dist/conversations/components/PermissionGuard.d.ts +21 -0
- package/dist/conversations/components/PermissionGuard.d.ts.map +1 -0
- package/dist/conversations/components/PermissionGuard.js +25 -0
- package/dist/conversations/components/PermissionGuard.js.map +1 -0
- package/dist/conversations/constants/featureFlags.d.ts +8 -0
- package/dist/conversations/constants/featureFlags.d.ts.map +1 -0
- package/dist/conversations/constants/featureFlags.js +12 -0
- package/dist/conversations/constants/featureFlags.js.map +1 -0
- package/dist/conversations/constants/permissions.d.ts +174 -0
- package/dist/conversations/constants/permissions.d.ts.map +1 -0
- package/dist/conversations/constants/permissions.js +68 -0
- package/dist/conversations/constants/permissions.js.map +1 -0
- package/dist/conversations/hooks/useAdminFeatureFlags.d.ts +8 -0
- package/dist/conversations/hooks/useAdminFeatureFlags.d.ts.map +1 -0
- package/dist/conversations/hooks/useAdminFeatureFlags.js +16 -0
- package/dist/conversations/hooks/useAdminFeatureFlags.js.map +1 -0
- package/dist/conversations/hooks/useConversationQueries.d.ts +83 -0
- package/dist/conversations/hooks/useConversationQueries.d.ts.map +1 -0
- package/dist/conversations/hooks/useConversationQueries.js +136 -0
- package/dist/conversations/hooks/useConversationQueries.js.map +1 -0
- package/dist/conversations/hooks/useExportConversation.d.ts +10 -0
- package/dist/conversations/hooks/useExportConversation.d.ts.map +1 -0
- package/dist/conversations/hooks/useExportConversation.js +41 -0
- package/dist/conversations/hooks/useExportConversation.js.map +1 -0
- package/dist/conversations/hooks/useMessageQueries.d.ts +84 -0
- package/dist/conversations/hooks/useMessageQueries.d.ts.map +1 -0
- package/dist/conversations/hooks/useMessageQueries.js +123 -0
- package/dist/conversations/hooks/useMessageQueries.js.map +1 -0
- package/dist/conversations/hooks/useMessageSubscriptions.d.ts +24 -0
- package/dist/conversations/hooks/useMessageSubscriptions.d.ts.map +1 -0
- package/dist/conversations/hooks/useMessageSubscriptions.js +90 -0
- package/dist/conversations/hooks/useMessageSubscriptions.js.map +1 -0
- package/dist/conversations/hooks/useUserFeatureFlags.d.ts +5 -0
- package/dist/conversations/hooks/useUserFeatureFlags.d.ts.map +1 -0
- package/dist/conversations/hooks/useUserFeatureFlags.js +10 -0
- package/dist/conversations/hooks/useUserFeatureFlags.js.map +1 -0
- package/dist/conversations/index.d.ts +31 -0
- package/dist/conversations/index.d.ts.map +1 -0
- package/dist/conversations/index.js +5 -0
- package/dist/conversations/pages/AdminConversationsLandingPage.d.ts +9 -0
- package/dist/conversations/pages/AdminConversationsLandingPage.d.ts.map +1 -0
- package/dist/conversations/pages/AdminConversationsLandingPage.js +117 -0
- package/dist/conversations/pages/AdminConversationsLandingPage.js.map +1 -0
- package/dist/conversations/pages/ConversationAdminPages.d.ts +5 -0
- package/dist/conversations/pages/ConversationAdminPages.d.ts.map +1 -0
- package/dist/conversations/pages/ConversationAdminPages.js +573 -0
- package/dist/conversations/pages/ConversationAdminPages.js.map +1 -0
- package/dist/conversations/pages/ConversationDetailPage.d.ts +2 -0
- package/dist/conversations/pages/ConversationDetailPage.d.ts.map +1 -0
- package/dist/conversations/pages/ConversationDetailPage.js +439 -0
- package/dist/conversations/pages/ConversationDetailPage.js.map +1 -0
- package/dist/conversations/pages/ConversationListPage.d.ts +6 -0
- package/dist/conversations/pages/ConversationListPage.d.ts.map +1 -0
- package/dist/conversations/pages/ConversationListPage.js +269 -0
- package/dist/conversations/pages/ConversationListPage.js.map +1 -0
- package/dist/conversations/pages/ConversationsLandingPage.d.ts +9 -0
- package/dist/conversations/pages/ConversationsLandingPage.d.ts.map +1 -0
- package/dist/conversations/pages/ConversationsLandingPage.js +124 -0
- package/dist/conversations/pages/ConversationsLandingPage.js.map +1 -0
- package/dist/conversations/pages/ConversationsSettingsPage.d.ts +2 -0
- package/dist/conversations/pages/ConversationsSettingsPage.d.ts.map +1 -0
- package/dist/conversations/pages/ConversationsSettingsPage.js +215 -0
- package/dist/conversations/pages/ConversationsSettingsPage.js.map +1 -0
- package/dist/conversations/pages/NewConversationPage.d.ts +2 -0
- package/dist/conversations/pages/NewConversationPage.d.ts.map +1 -0
- package/dist/conversations/pages/NewConversationPage.js +287 -0
- package/dist/conversations/pages/NewConversationPage.js.map +1 -0
- package/dist/conversations/providers/ConversationsProvider.d.ts +13 -0
- package/dist/conversations/providers/ConversationsProvider.d.ts.map +1 -0
- package/dist/conversations/providers/ConversationsProvider.js +109 -0
- package/dist/conversations/providers/ConversationsProvider.js.map +1 -0
- package/dist/conversations/store/conversationsStore.d.ts +29 -0
- package/dist/conversations/store/conversationsStore.d.ts.map +1 -0
- package/dist/conversations/store/conversationsStore.js +56 -0
- package/dist/conversations/store/conversationsStore.js.map +1 -0
- package/dist/conversations/types/index.d.ts +352 -0
- package/dist/conversations/types/index.d.ts.map +1 -0
- package/dist/conversations/utils/cn.d.ts +8 -0
- package/dist/conversations/utils/cn.d.ts.map +1 -0
- package/dist/conversations/utils/cn.js +10 -0
- package/dist/conversations/utils/cn.js.map +1 -0
- package/dist/conversations/utils/i18n.d.ts +15 -0
- package/dist/conversations/utils/i18n.d.ts.map +1 -0
- package/dist/conversations/utils/i18n.js +14 -0
- package/dist/conversations/utils/i18n.js.map +1 -0
- package/dist/conversations/utils/mappers.d.ts +32 -0
- package/dist/conversations/utils/mappers.d.ts.map +1 -0
- package/dist/conversations/utils/mappers.js +164 -0
- package/dist/conversations/utils/mappers.js.map +1 -0
- package/dist/conversations/utils/navigation.d.ts +18 -0
- package/dist/conversations/utils/navigation.d.ts.map +1 -0
- package/dist/conversations/utils/navigation.js +8 -0
- package/dist/conversations/utils/navigation.js.map +1 -0
- package/dist/dev/main.d.ts +2 -0
- package/dist/dev/main.d.ts.map +1 -0
- package/dist/generated/global-operations.d.ts +2 -0
- package/dist/generated/global-operations.d.ts.map +1 -0
- package/dist/generated/global-types.d.ts +20716 -0
- package/dist/generated/global-types.d.ts.map +1 -0
- package/dist/generated/wspace-operations.d.ts +2008 -0
- package/dist/generated/wspace-operations.d.ts.map +1 -0
- package/dist/generated/wspace-operations.js +997 -0
- package/dist/generated/wspace-operations.js.map +1 -0
- package/dist/generated/wspace-types.d.ts +53363 -0
- package/dist/generated/wspace-types.d.ts.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/node_modules/clsx/dist/clsx.js +18 -0
- package/dist/node_modules/clsx/dist/clsx.js.map +1 -0
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +1674 -0
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -0
- package/dist/utils/nativeBridge.d.ts +3 -0
- package/dist/utils/nativeBridge.d.ts.map +1 -0
- package/dist/utils/nativeBridge.js +2 -0
- package/package.json +115 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessageBubble.js","names":[],"sources":["../../../src/conversations/components/MessageBubble.tsx"],"sourcesContent":["import { memo, useState } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport {\n FileText,\n Image as ImageIcon,\n Reply,\n MoreHorizontal,\n Pencil,\n Trash2,\n Pin,\n SmilePlus,\n Check,\n CheckCheck,\n} from \"lucide-react\";\nimport { cn } from \"../utils/cn\";\nimport type { Message } from \"../types\";\n\ninterface MessageBubbleProps {\n message: Message;\n isOwnMessage?: boolean;\n showAvatar?: boolean;\n showSender?: boolean;\n onReply?: (message: Message) => void;\n onReact?: (messageId: string, emoji: string) => void;\n onEdit?: (message: Message) => void;\n onDelete?: (messageId: string) => void;\n onTogglePin?: (messageId: string, isPinned: boolean) => void;\n}\n\n/**\n * Format a message timestamp for display\n */\nfunction formatMessageTime(dateString: string): string {\n const date = new Date(dateString);\n return date.toLocaleTimeString(undefined, {\n hour: \"2-digit\",\n minute: \"2-digit\",\n });\n}\n\n/**\n * Message status indicator\n */\nfunction MessageStatusIcon({\n status,\n failedLabel,\n}: {\n status: Message[\"status\"];\n failedLabel: string;\n}) {\n switch (status) {\n case \"SENDING\":\n return (\n <span className=\"w-3 h-3 rounded-full border border-muted-foreground animate-pulse\" />\n );\n case \"SENT\":\n return <Check size={12} className=\"text-muted-foreground\" />;\n case \"DELIVERED\":\n return <CheckCheck size={12} className=\"text-muted-foreground\" />;\n case \"READ\":\n return <CheckCheck size={12} className=\"text-accent-blue\" />;\n case \"FAILED\":\n return (\n <span className=\"text-[10px] text-destructive font-medium\">\n {failedLabel}\n </span>\n );\n default:\n return null;\n }\n}\n\nfunction isImageAttachment(mimeType: string): boolean {\n return mimeType.startsWith(\"image/\");\n}\n\n/**\n * MessageBubble - Displays a single message in a chat view.\n * Supports own messages (right-aligned) and other messages (left-aligned).\n * Shows sender info, content, timestamp, reactions, and action buttons.\n */\nexport const MessageBubble = memo(function MessageBubble({\n message,\n isOwnMessage = false,\n showAvatar = true,\n showSender = true,\n onReply,\n onReact,\n onEdit,\n onDelete,\n onTogglePin,\n}: MessageBubbleProps) {\n const [isHovered, setIsHovered] = useState(false);\n const [showReactionPicker, setShowReactionPicker] = useState(false);\n const [showMoreMenu, setShowMoreMenu] = useState(false);\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n\n const {\n sender,\n content,\n type,\n status,\n reactions,\n attachments,\n isEdited,\n createdAt,\n isPinned,\n } = message;\n\n const isSystem = type === \"SYSTEM\";\n\n // System messages render differently\n if (isSystem) {\n return (\n <div className=\"flex justify-center my-2 px-4\">\n <span className=\"text-xs text-muted-foreground bg-muted/50 px-3 py-1 rounded-full\">\n {content}\n </span>\n </div>\n );\n }\n\n return (\n <div\n className={cn(\n \"group flex gap-2 px-4 py-1\",\n isOwnMessage ? \"flex-row-reverse\" : \"flex-row\",\n )}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n >\n {/* Avatar */}\n {showAvatar ? (\n <div\n className={cn(\n \"flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center text-xs font-semibold mt-0.5\",\n isOwnMessage\n ? \"bg-primary/10 text-primary\"\n : \"bg-muted text-muted-foreground\",\n )}\n >\n {sender.avatarUrl ? (\n <img\n src={sender.avatarUrl}\n alt={sender.name}\n className=\"w-full h-full rounded-full object-cover\"\n />\n ) : (\n sender.name\n .split(\" \")\n .map((w) => w[0])\n .join(\"\")\n .toUpperCase()\n .slice(0, 2)\n )}\n </div>\n ) : (\n <div className=\"w-8 flex-shrink-0\" />\n )}\n\n {/* Message content */}\n <div\n className={cn(\n \"flex flex-col max-w-[85%] sm:max-w-[70%]\",\n isOwnMessage ? \"items-end\" : \"items-start\",\n )}\n >\n {/* Sender name + pin indicator */}\n {showSender && !isOwnMessage && (\n <div className=\"flex items-center gap-1.5 mb-0.5\">\n <span className=\"text-xs font-semibold text-foreground\">\n {sender.name}\n </span>\n {isPinned && <Pin size={10} className=\"text-status-warning-text\" />}\n </div>\n )}\n\n {/* Bubble */}\n <div\n className={cn(\n \"relative rounded-2xl px-3.5 py-2 text-sm leading-relaxed\",\n isOwnMessage\n ? \"bg-primary text-primary-foreground rounded-tr-md\"\n : \"bg-muted/70 text-foreground rounded-tl-md\",\n )}\n >\n {/* Text content */}\n <p className=\"whitespace-pre-wrap break-words\">{content}</p>\n\n {/* Attachments */}\n {attachments.length > 0 && (\n <div className=\"mt-2 grid gap-2\">\n {attachments.map((att) => {\n const attachmentClass = cn(\n \"flex min-w-0 items-center gap-2 rounded-lg px-2 py-1.5 text-xs transition-colors\",\n isOwnMessage\n ? \"bg-primary-foreground/10 text-primary-foreground hover:bg-primary-foreground/15\"\n : \"bg-background/50 text-foreground hover:bg-background/70\",\n );\n const attachmentContent = (\n <>\n <div className=\"flex size-10 flex-shrink-0 items-center justify-center overflow-hidden rounded-md bg-background/40\">\n {att.thumbnail && isImageAttachment(att.mimeType) ? (\n <img\n src={att.thumbnail}\n alt={att.fileName}\n className=\"h-full w-full object-contain\"\n />\n ) : isImageAttachment(att.mimeType) ? (\n <ImageIcon size={16} />\n ) : (\n <FileText size={16} />\n )}\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"truncate font-medium\">{att.fileName}</div>\n <div className=\"truncate text-[10px] opacity-70\">\n {formatFileSize(att.fileSize)} - {att.mimeType}\n </div>\n </div>\n </>\n );\n\n return att.downloadUrl ? (\n <a\n key={att.id}\n href={att.downloadUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n className={attachmentClass}\n title={att.fileName}\n >\n {attachmentContent}\n </a>\n ) : (\n <div\n key={att.id}\n className={attachmentClass}\n title={att.fileName}\n >\n {attachmentContent}\n </div>\n );\n })}\n </div>\n )}\n </div>\n\n {/* Reactions */}\n {reactions.length > 0 && (\n <div className=\"flex flex-wrap gap-1 mt-1\">\n {reactions.map((reaction) => (\n <button\n key={reaction.emoji}\n type=\"button\"\n onClick={() => onReact?.(message.id, reaction.emoji)}\n className={cn(\n \"inline-flex items-center gap-1 px-1.5 py-0.5 rounded-full text-xs\",\n \"border transition-colors\",\n reaction.currentUserReacted\n ? \"bg-primary/10 border-primary/30 text-primary\"\n : \"bg-muted/50 border-border text-muted-foreground hover:bg-muted\",\n )}\n >\n <span>{reaction.emoji}</span>\n <span className=\"font-medium\">{reaction.count}</span>\n </button>\n ))}\n </div>\n )}\n\n {/* Timestamp + status row */}\n <div className=\"flex items-center gap-1.5 mt-0.5 px-1\">\n <span className=\"text-[10px] text-muted-foreground\">\n {formatMessageTime(createdAt)}\n </span>\n {isEdited && (\n <span className=\"text-[10px] text-muted-foreground italic\">\n {tr(\"conversations.edited\", \"edited\")}\n </span>\n )}\n {isOwnMessage && (\n <MessageStatusIcon\n status={status}\n failedLabel={tr(\"conversations.failed\", \"Failed\")}\n />\n )}\n </div>\n </div>\n\n {/* Action buttons (shown on hover) */}\n {(isHovered || showReactionPicker || showMoreMenu) && (\n <div\n className={cn(\n \"relative flex items-center gap-0.5 self-start mt-1\",\n \"animate-in fade-in-0 zoom-in-95 duration-150\",\n )}\n >\n {message.permissions.canReact && (\n <ActionButton\n icon={<SmilePlus size={14} />}\n label={tr(\"conversations.react\", \"React\")}\n pressed={showReactionPicker}\n onClick={() => {\n setShowReactionPicker((value) => !value);\n setShowMoreMenu(false);\n }}\n />\n )}\n {message.permissions.canReply && (\n <ActionButton\n icon={<Reply size={14} />}\n label={tr(\"conversations.reply\", \"Reply\")}\n onClick={() => onReply?.(message)}\n />\n )}\n {message.permissions.canEdit && (\n <ActionButton\n icon={<Pencil size={14} />}\n label={tr(\"conversations.edit\", \"Edit\")}\n onClick={() => onEdit?.(message)}\n />\n )}\n {message.permissions.canDelete && (\n <ActionButton\n icon={<Trash2 size={14} />}\n label={tr(\"conversations.delete\", \"Delete\")}\n onClick={() => onDelete?.(message.id)}\n />\n )}\n <ActionButton\n icon={<MoreHorizontal size={14} />}\n label={tr(\"conversations.more\", \"More\")}\n pressed={showMoreMenu}\n onClick={() => {\n setShowMoreMenu((value) => !value);\n setShowReactionPicker(false);\n }}\n />\n {showReactionPicker && (\n <div className=\"absolute top-full z-10 mt-1 flex items-center gap-1 rounded-lg border border-border bg-popover p-1 shadow-lg\">\n {[\"👍\", \"❤️\", \"🎉\", \"👀\", \"✅\"].map((emoji) => (\n <button\n key={emoji}\n type=\"button\"\n onClick={() => {\n onReact?.(message.id, emoji);\n setShowReactionPicker(false);\n }}\n className=\"rounded-md px-2 py-1 text-sm hover:bg-muted/80\"\n aria-label={`${tr(\"conversations.reactWith\", \"React with\")} ${emoji}`}\n >\n {emoji}\n </button>\n ))}\n </div>\n )}\n {showMoreMenu && message.permissions.canPin && onTogglePin && (\n <div className=\"absolute right-0 top-full z-10 mt-1 min-w-40 rounded-lg border border-border bg-popover p-1 shadow-lg\">\n <button\n type=\"button\"\n onClick={() => {\n onTogglePin(message.id, message.isPinned);\n setShowMoreMenu(false);\n }}\n className=\"flex w-full items-center gap-2 rounded-md px-3 py-2 text-left text-sm text-foreground hover:bg-muted/80\"\n >\n <Pin size={14} />\n {message.isPinned\n ? tr(\"conversations.unpinMessage\", \"Unpin message\")\n : tr(\"conversations.pinMessage\", \"Pin message\")}\n </button>\n </div>\n )}\n </div>\n )}\n </div>\n );\n});\n\n/**\n * Small icon button for message actions\n */\nfunction ActionButton({\n icon,\n label,\n onClick,\n pressed,\n}: {\n icon: React.ReactNode;\n label: string;\n onClick: () => void;\n pressed?: boolean;\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n aria-label={label}\n aria-pressed={pressed}\n title={label}\n className=\"p-1 rounded-md text-muted-foreground hover:text-foreground hover:bg-muted/80 transition-colors\"\n >\n {icon}\n </button>\n );\n}\n\n/**\n * Format file size in human-readable form\n */\nfunction formatFileSize(bytes: number): string {\n if (bytes === 0) return \"0 B\";\n const k = 1024;\n const sizes = [\"B\", \"KB\", \"MB\", \"GB\"];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
interface PageLayoutProps {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
/** Page title */
|
|
6
|
+
title?: string;
|
|
7
|
+
/** Page subtitle/description */
|
|
8
|
+
subtitle?: string;
|
|
9
|
+
/** Icon component to display next to title */
|
|
10
|
+
icon?: ReactNode;
|
|
11
|
+
/** Actions to display in header (buttons, etc.) */
|
|
12
|
+
headerActions?: ReactNode;
|
|
13
|
+
/** Additional header content below title */
|
|
14
|
+
headerContent?: ReactNode;
|
|
15
|
+
/** Maximum width of content: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full' */
|
|
16
|
+
maxWidth?: "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "full";
|
|
17
|
+
/** Whether to show the header section */
|
|
18
|
+
showHeader?: boolean;
|
|
19
|
+
/** Additional CSS classes for the container */
|
|
20
|
+
className?: string;
|
|
21
|
+
/** Additional CSS classes for the content area */
|
|
22
|
+
contentClassName?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* PageLayout - A consistent page wrapper with responsive design
|
|
26
|
+
*
|
|
27
|
+
* Features:
|
|
28
|
+
* - Proper max-width constraints
|
|
29
|
+
* - Responsive padding
|
|
30
|
+
* - Animated entrance
|
|
31
|
+
* - Consistent header styling
|
|
32
|
+
*/
|
|
33
|
+
export declare function PageLayout({ children, title, subtitle, icon, headerActions, headerContent, maxWidth, showHeader, className, contentClassName, }: PageLayoutProps): import("react/jsx-runtime").JSX.Element;
|
|
34
|
+
/**
|
|
35
|
+
* PageSection - A section within a page with consistent spacing
|
|
36
|
+
*/
|
|
37
|
+
export declare function PageSection({ children, title, description, actions, className, }: {
|
|
38
|
+
children: ReactNode;
|
|
39
|
+
title?: string;
|
|
40
|
+
description?: string;
|
|
41
|
+
actions?: ReactNode;
|
|
42
|
+
className?: string;
|
|
43
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
44
|
+
/**
|
|
45
|
+
* EmptyState - A consistent empty state component
|
|
46
|
+
*/
|
|
47
|
+
export declare function EmptyState({ icon, title, description, action, className, }: {
|
|
48
|
+
icon?: ReactNode;
|
|
49
|
+
title: string;
|
|
50
|
+
description?: string;
|
|
51
|
+
action?: ReactNode;
|
|
52
|
+
className?: string;
|
|
53
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
54
|
+
export {};
|
|
55
|
+
//# sourceMappingURL=PageLayout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PageLayout.d.ts","sourceRoot":"","sources":["../../../src/conversations/components/PageLayout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,UAAU,eAAe;IACvB,QAAQ,EAAE,SAAS,CAAC;IACpB,iBAAiB;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,mDAAmD;IACnD,aAAa,CAAC,EAAE,SAAS,CAAC;IAC1B,4CAA4C;IAC5C,aAAa,CAAC,EAAE,SAAS,CAAC;IAC1B,mFAAmF;IACnF,QAAQ,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;IAC9D,yCAAyC;IACzC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAYD;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,IAAI,EACJ,aAAa,EACb,aAAa,EACb,QAAe,EACf,UAAiB,EACjB,SAAS,EACT,gBAAgB,GACjB,EAAE,eAAe,2CAsEjB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,KAAK,EACL,WAAW,EACX,OAAO,EACP,SAAS,GACV,EAAE;IACD,QAAQ,EAAE,SAAS,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,2CAmBA;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,KAAK,EACL,WAAW,EACX,MAAM,EACN,SAAS,GACV,EAAE;IACD,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,2CAyBA"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { cn as e } from "../utils/cn.js";
|
|
2
|
+
import { jsx as t, jsxs as n } from "react/jsx-runtime";
|
|
3
|
+
//#region src/conversations/components/PageLayout.tsx
|
|
4
|
+
var r = {
|
|
5
|
+
sm: "max-w-screen-sm",
|
|
6
|
+
md: "max-w-screen-md",
|
|
7
|
+
lg: "max-w-screen-lg",
|
|
8
|
+
xl: "max-w-screen-xl",
|
|
9
|
+
"2xl": "max-w-screen-2xl",
|
|
10
|
+
"3xl": "max-w-[1600px]",
|
|
11
|
+
full: "max-w-full"
|
|
12
|
+
};
|
|
13
|
+
function i({ children: i, title: a, subtitle: o, icon: s, headerActions: c, headerContent: l, maxWidth: u = "xl", showHeader: d = !0, className: f, contentClassName: p }) {
|
|
14
|
+
return /* @__PURE__ */ t("div", {
|
|
15
|
+
className: e("min-h-full w-full", "px-4 sm:px-6 lg:px-8 xl:px-12", "py-6 sm:py-8 lg:py-10", "animate-in fade-in-0 slide-in-from-bottom-4 duration-500", f),
|
|
16
|
+
children: /* @__PURE__ */ n("div", {
|
|
17
|
+
className: e("mx-auto w-full", r[u], p),
|
|
18
|
+
children: [d && (a || c) && /* @__PURE__ */ n("header", {
|
|
19
|
+
className: "mb-6 sm:mb-8",
|
|
20
|
+
children: [/* @__PURE__ */ n("div", {
|
|
21
|
+
className: "flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between",
|
|
22
|
+
children: [/* @__PURE__ */ n("div", {
|
|
23
|
+
className: "space-y-1",
|
|
24
|
+
children: [(a || s) && /* @__PURE__ */ n("div", {
|
|
25
|
+
className: "flex items-center gap-3",
|
|
26
|
+
children: [s && /* @__PURE__ */ t("div", {
|
|
27
|
+
className: "flex-shrink-0 p-2.5 rounded-xl bg-primary/10 text-primary",
|
|
28
|
+
children: s
|
|
29
|
+
}), a && /* @__PURE__ */ t("h1", {
|
|
30
|
+
className: "text-2xl sm:text-3xl font-bold tracking-tight text-foreground",
|
|
31
|
+
children: a
|
|
32
|
+
})]
|
|
33
|
+
}), o && /* @__PURE__ */ t("p", {
|
|
34
|
+
className: "text-sm sm:text-base text-muted-foreground max-w-2xl",
|
|
35
|
+
children: o
|
|
36
|
+
})]
|
|
37
|
+
}), c && /* @__PURE__ */ t("div", {
|
|
38
|
+
className: "flex items-center gap-2 flex-shrink-0",
|
|
39
|
+
children: c
|
|
40
|
+
})]
|
|
41
|
+
}), l && /* @__PURE__ */ t("div", {
|
|
42
|
+
className: "mt-4",
|
|
43
|
+
children: l
|
|
44
|
+
})]
|
|
45
|
+
}), /* @__PURE__ */ t("div", {
|
|
46
|
+
className: "space-y-6",
|
|
47
|
+
children: i
|
|
48
|
+
})]
|
|
49
|
+
})
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
function a({ children: r, title: i, description: a, actions: o, className: s }) {
|
|
53
|
+
return /* @__PURE__ */ n("section", {
|
|
54
|
+
className: e("space-y-4", s),
|
|
55
|
+
children: [(i || o) && /* @__PURE__ */ n("div", {
|
|
56
|
+
className: "flex items-center justify-between",
|
|
57
|
+
children: [/* @__PURE__ */ n("div", { children: [i && /* @__PURE__ */ t("h2", {
|
|
58
|
+
className: "text-lg font-semibold text-foreground",
|
|
59
|
+
children: i
|
|
60
|
+
}), a && /* @__PURE__ */ t("p", {
|
|
61
|
+
className: "text-sm text-muted-foreground",
|
|
62
|
+
children: a
|
|
63
|
+
})] }), o && /* @__PURE__ */ t("div", {
|
|
64
|
+
className: "flex items-center gap-2",
|
|
65
|
+
children: o
|
|
66
|
+
})]
|
|
67
|
+
}), r]
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function o({ icon: r, title: i, description: a, action: o, className: s }) {
|
|
71
|
+
return /* @__PURE__ */ n("div", {
|
|
72
|
+
className: e("flex flex-col items-center justify-center", "py-12 sm:py-16 px-4", "text-center", "animate-in fade-in-0 zoom-in-95 duration-300", s),
|
|
73
|
+
children: [
|
|
74
|
+
r && /* @__PURE__ */ t("div", {
|
|
75
|
+
className: "mb-4 p-4 rounded-2xl bg-muted/50 text-muted-foreground",
|
|
76
|
+
children: r
|
|
77
|
+
}),
|
|
78
|
+
/* @__PURE__ */ t("h3", {
|
|
79
|
+
className: "text-lg font-semibold text-foreground mb-1",
|
|
80
|
+
children: i
|
|
81
|
+
}),
|
|
82
|
+
a && /* @__PURE__ */ t("p", {
|
|
83
|
+
className: "text-sm text-muted-foreground max-w-sm mb-4",
|
|
84
|
+
children: a
|
|
85
|
+
}),
|
|
86
|
+
o
|
|
87
|
+
]
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
//#endregion
|
|
91
|
+
export { o as EmptyState, i as PageLayout, a as PageSection };
|
|
92
|
+
|
|
93
|
+
//# sourceMappingURL=PageLayout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PageLayout.js","names":[],"sources":["../../../src/conversations/components/PageLayout.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"../utils/cn\";\n\ninterface PageLayoutProps {\n children: ReactNode;\n /** Page title */\n title?: string;\n /** Page subtitle/description */\n subtitle?: string;\n /** Icon component to display next to title */\n icon?: ReactNode;\n /** Actions to display in header (buttons, etc.) */\n headerActions?: ReactNode;\n /** Additional header content below title */\n headerContent?: ReactNode;\n /** Maximum width of content: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full' */\n maxWidth?: \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\" | \"3xl\" | \"full\";\n /** Whether to show the header section */\n showHeader?: boolean;\n /** Additional CSS classes for the container */\n className?: string;\n /** Additional CSS classes for the content area */\n contentClassName?: string;\n}\n\nconst maxWidthClasses = {\n sm: \"max-w-screen-sm\", // 640px\n md: \"max-w-screen-md\", // 768px\n lg: \"max-w-screen-lg\", // 1024px\n xl: \"max-w-screen-xl\", // 1280px\n \"2xl\": \"max-w-screen-2xl\", // 1536px\n \"3xl\": \"max-w-[1600px]\",\n full: \"max-w-full\",\n};\n\n/**\n * PageLayout - A consistent page wrapper with responsive design\n *\n * Features:\n * - Proper max-width constraints\n * - Responsive padding\n * - Animated entrance\n * - Consistent header styling\n */\nexport function PageLayout({\n children,\n title,\n subtitle,\n icon,\n headerActions,\n headerContent,\n maxWidth = \"xl\",\n showHeader = true,\n className,\n contentClassName,\n}: PageLayoutProps) {\n return (\n <div\n className={cn(\n // Base styles - full width container with padding\n \"min-h-full w-full\",\n // Responsive horizontal padding\n \"px-4 sm:px-6 lg:px-8 xl:px-12\",\n // Responsive vertical padding\n \"py-6 sm:py-8 lg:py-10\",\n // Entrance animation\n \"animate-in fade-in-0 slide-in-from-bottom-4 duration-500\",\n className,\n )}\n >\n {/* Max-width constrained content container */}\n <div\n className={cn(\n \"mx-auto w-full\",\n maxWidthClasses[maxWidth],\n contentClassName,\n )}\n >\n {/* Page Header */}\n {showHeader && (title || headerActions) && (\n <header className=\"mb-6 sm:mb-8\">\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n {/* Title Section */}\n <div className=\"space-y-1\">\n {(title || icon) && (\n <div className=\"flex items-center gap-3\">\n {icon && (\n <div className=\"flex-shrink-0 p-2.5 rounded-xl bg-primary/10 text-primary\">\n {icon}\n </div>\n )}\n {title && (\n <h1 className=\"text-2xl sm:text-3xl font-bold tracking-tight text-foreground\">\n {title}\n </h1>\n )}\n </div>\n )}\n {subtitle && (\n <p className=\"text-sm sm:text-base text-muted-foreground max-w-2xl\">\n {subtitle}\n </p>\n )}\n </div>\n\n {/* Header Actions */}\n {headerActions && (\n <div className=\"flex items-center gap-2 flex-shrink-0\">\n {headerActions}\n </div>\n )}\n </div>\n\n {/* Additional Header Content */}\n {headerContent && <div className=\"mt-4\">{headerContent}</div>}\n </header>\n )}\n\n {/* Page content — must not use a <main> landmark here because the\n host shell (AppShellLayout) already renders one; nesting <main>\n elements is invalid HTML and an a11y violation. */}\n <div className=\"space-y-6\">{children}</div>\n </div>\n </div>\n );\n}\n\n/**\n * PageSection - A section within a page with consistent spacing\n */\nexport function PageSection({\n children,\n title,\n description,\n actions,\n className,\n}: {\n children: ReactNode;\n title?: string;\n description?: string;\n actions?: ReactNode;\n className?: string;\n}) {\n return (\n <section className={cn(\"space-y-4\", className)}>\n {(title || actions) && (\n <div className=\"flex items-center justify-between\">\n <div>\n {title && (\n <h2 className=\"text-lg font-semibold text-foreground\">{title}</h2>\n )}\n {description && (\n <p className=\"text-sm text-muted-foreground\">{description}</p>\n )}\n </div>\n {actions && <div className=\"flex items-center gap-2\">{actions}</div>}\n </div>\n )}\n {children}\n </section>\n );\n}\n\n/**\n * EmptyState - A consistent empty state component\n */\nexport function EmptyState({\n icon,\n title,\n description,\n action,\n className,\n}: {\n icon?: ReactNode;\n title: string;\n description?: string;\n action?: ReactNode;\n className?: string;\n}) {\n return (\n <div\n className={cn(\n \"flex flex-col items-center justify-center\",\n \"py-12 sm:py-16 px-4\",\n \"text-center\",\n \"animate-in fade-in-0 zoom-in-95 duration-300\",\n className,\n )}\n >\n {icon && (\n <div className=\"mb-4 p-4 rounded-2xl bg-muted/50 text-muted-foreground\">\n {icon}\n </div>\n )}\n <h3 className=\"text-lg font-semibold text-foreground mb-1\">{title}</h3>\n {description && (\n <p className=\"text-sm text-muted-foreground max-w-sm mb-4\">\n {description}\n </p>\n )}\n {action}\n </div>\n );\n}\n"],"mappings":";;;AAyBA,IAAM,IAAkB;CACtB,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,OAAO;CACP,OAAO;CACP,MAAM;CACP;AAWD,SAAgB,EAAW,EACzB,aACA,UACA,aACA,SACA,kBACA,kBACA,cAAW,MACX,gBAAa,IACb,cACA,uBACkB;AAClB,QACE,kBAAC,OAAD;EACE,WAAW,EAET,qBAEA,iCAEA,yBAEA,4DACA,EACD;YAGD,kBAAC,OAAD;GACE,WAAW,EACT,kBACA,EAAgB,IAChB,EACD;aALH,CAQG,MAAe,KAAS,MACvB,kBAAC,UAAD;IAAQ,WAAU;cAAlB,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CAEE,kBAAC,OAAD;MAAK,WAAU;gBAAf,EACI,KAAS,MACT,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACG,KACC,kBAAC,OAAD;QAAK,WAAU;kBACZ;QACG,CAAA,EAEP,KACC,kBAAC,MAAD;QAAI,WAAU;kBACX;QACE,CAAA,CAEH;UAEP,KACC,kBAAC,KAAD;OAAG,WAAU;iBACV;OACC,CAAA,CAEF;SAGL,KACC,kBAAC,OAAD;MAAK,WAAU;gBACZ;MACG,CAAA,CAEJ;QAGL,KAAiB,kBAAC,OAAD;KAAK,WAAU;eAAQ;KAAoB,CAAA,CACtD;OAMX,kBAAC,OAAD;IAAK,WAAU;IAAa;IAAe,CAAA,CACvC;;EACF,CAAA;;AAOV,SAAgB,EAAY,EAC1B,aACA,UACA,gBACA,YACA,gBAOC;AACD,QACE,kBAAC,WAAD;EAAS,WAAW,EAAG,aAAa,EAAU;YAA9C,EACI,KAAS,MACT,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACG,KACC,kBAAC,MAAD;IAAI,WAAU;cAAyC;IAAW,CAAA,EAEnE,KACC,kBAAC,KAAD;IAAG,WAAU;cAAiC;IAAgB,CAAA,CAE5D,EAAA,CAAA,EACL,KAAW,kBAAC,OAAD;IAAK,WAAU;cAA2B;IAAc,CAAA,CAChE;MAEP,EACO;;;AAOd,SAAgB,EAAW,EACzB,SACA,UACA,gBACA,WACA,gBAOC;AACD,QACE,kBAAC,OAAD;EACE,WAAW,EACT,6CACA,uBACA,eACA,gDACA,EACD;YAPH;GASG,KACC,kBAAC,OAAD;IAAK,WAAU;cACZ;IACG,CAAA;GAER,kBAAC,MAAD;IAAI,WAAU;cAA8C;IAAW,CAAA;GACtE,KACC,kBAAC,KAAD;IAAG,WAAU;cACV;IACC,CAAA;GAEL;GACG"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { FC, ReactNode } from 'react';
|
|
2
|
+
import { ConversationsPermission } from '../constants/permissions';
|
|
3
|
+
|
|
4
|
+
interface PermissionGuardProps {
|
|
5
|
+
permission: ConversationsPermission;
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
allowUnavailablePermissions?: boolean;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Wraps page content with a permission check.
|
|
11
|
+
* Shows a loading spinner while permissions resolve, then either
|
|
12
|
+
* renders children (if permitted) or an AccessDenied screen.
|
|
13
|
+
*
|
|
14
|
+
* `allowUnavailablePermissions` is for user-facing routes whose backend
|
|
15
|
+
* resolvers remain authoritative but whose host shell may not have hydrated
|
|
16
|
+
* local RBAC context yet. It only permits rendering when permission data is
|
|
17
|
+
* unavailable; explicit loaded denials still render AccessDenied.
|
|
18
|
+
*/
|
|
19
|
+
export declare const PermissionGuard: FC<PermissionGuardProps>;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=PermissionGuard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PermissionGuard.d.ts","sourceRoot":"","sources":["../../../src/conversations/components/PermissionGuard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAQ3C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAExE,UAAU,oBAAoB;IAC5B,UAAU,EAAE,uBAAuB,CAAC;IACpC,QAAQ,EAAE,SAAS,CAAC;IACpB,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACvC;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,EAAE,EAAE,CAAC,oBAAoB,CA+CpD,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { AccessDenied as e } from "@burdenoff/fe-libs/shared/components";
|
|
2
|
+
import { Loader2 as t } from "lucide-react";
|
|
3
|
+
import { useAuth as n, usePermissions as r } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
4
|
+
import { Fragment as i, jsx as a } from "react/jsx-runtime";
|
|
5
|
+
import { useI18n as o } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
6
|
+
//#region src/conversations/components/PermissionGuard.tsx
|
|
7
|
+
var s = ({ permission: s, children: c, allowUnavailablePermissions: l = !1 }) => {
|
|
8
|
+
let { isAuthenticated: u, tokens: d } = n(), { error: f, hasPermission: p, isLoading: m, permissions: h, query: g, scopeId: _ } = r(), { t: v } = o(), y = (e, t) => {
|
|
9
|
+
let n = v(e);
|
|
10
|
+
return n === e ? t : n;
|
|
11
|
+
};
|
|
12
|
+
if (m) return /* @__PURE__ */ a("div", {
|
|
13
|
+
className: "flex min-h-screen items-center justify-center bg-bg-canvas",
|
|
14
|
+
children: /* @__PURE__ */ a(t, { className: "h-8 w-8 animate-spin text-primary" })
|
|
15
|
+
});
|
|
16
|
+
let b = !h && !f && u && !!d?.accessToken && !!_ && g.status === "pending" && g.fetchStatus === "idle";
|
|
17
|
+
return !p(s) && !(l && b) ? /* @__PURE__ */ a(e, {
|
|
18
|
+
title: y("conversations.accessDenied", "Access Denied"),
|
|
19
|
+
description: y("conversations.noPermissionView", "You don't have permission to view this page.")
|
|
20
|
+
}) : /* @__PURE__ */ a(i, { children: c });
|
|
21
|
+
};
|
|
22
|
+
//#endregion
|
|
23
|
+
export { s as PermissionGuard };
|
|
24
|
+
|
|
25
|
+
//# sourceMappingURL=PermissionGuard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PermissionGuard.js","names":[],"sources":["../../../src/conversations/components/PermissionGuard.tsx"],"sourcesContent":["import type { FC, ReactNode } from \"react\";\nimport { Loader2 } from \"lucide-react\";\nimport {\n useAuth,\n usePermissions,\n} from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { AccessDenied } from \"@burdenoff/fe-libs/shared/components\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport type { ConversationsPermission } from \"../constants/permissions\";\n\ninterface PermissionGuardProps {\n permission: ConversationsPermission;\n children: ReactNode;\n allowUnavailablePermissions?: boolean;\n}\n\n/**\n * Wraps page content with a permission check.\n * Shows a loading spinner while permissions resolve, then either\n * renders children (if permitted) or an AccessDenied screen.\n *\n * `allowUnavailablePermissions` is for user-facing routes whose backend\n * resolvers remain authoritative but whose host shell may not have hydrated\n * local RBAC context yet. It only permits rendering when permission data is\n * unavailable; explicit loaded denials still render AccessDenied.\n */\nexport const PermissionGuard: FC<PermissionGuardProps> = ({\n permission,\n children,\n allowUnavailablePermissions = false,\n}) => {\n const { isAuthenticated, tokens } = useAuth();\n const { error, hasPermission, isLoading, permissions, query, scopeId } =\n usePermissions();\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n\n if (isLoading) {\n return (\n <div className=\"flex min-h-screen items-center justify-center bg-bg-canvas\">\n <Loader2 className=\"h-8 w-8 animate-spin text-primary\" />\n </div>\n );\n }\n\n const permissionHydrationPending =\n !permissions &&\n !error &&\n isAuthenticated &&\n !!tokens?.accessToken &&\n !!scopeId &&\n query.status === \"pending\" &&\n query.fetchStatus === \"idle\";\n\n if (\n !hasPermission(permission) &&\n !(allowUnavailablePermissions && permissionHydrationPending)\n ) {\n return (\n <AccessDenied\n title={tr(\"conversations.accessDenied\", \"Access Denied\")}\n description={tr(\n \"conversations.noPermissionView\",\n \"You don't have permission to view this page.\",\n )}\n />\n );\n }\n\n return <>{children}</>;\n};\n"],"mappings":";;;;;;AA0BA,IAAa,KAA6C,EACxD,eACA,aACA,iCAA8B,SAC1B;CACJ,IAAM,EAAE,oBAAiB,cAAW,GAAS,EACvC,EAAE,UAAO,kBAAe,cAAW,gBAAa,UAAO,eAC3D,GAAgB,EACZ,EAAE,SAAM,GAAS,EACjB,KAAM,GAAa,MAA6B;EACpD,IAAM,IAAQ,EAAE,EAAI;AACpB,SAAO,MAAU,IAAM,IAAW;;AAGpC,KAAI,EACF,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD,EAAS,WAAU,qCAAsC,CAAA;EACrD,CAAA;CAIV,IAAM,IACJ,CAAC,KACD,CAAC,KACD,KACA,CAAC,CAAC,GAAQ,eACV,CAAC,CAAC,KACF,EAAM,WAAW,aACjB,EAAM,gBAAgB;AAiBxB,QAdE,CAAC,EAAc,EAAW,IAC1B,EAAE,KAA+B,KAG/B,kBAAC,GAAD;EACE,OAAO,EAAG,8BAA8B,gBAAgB;EACxD,aAAa,EACX,kCACA,+CACD;EACD,CAAA,GAIC,kBAAA,GAAA,EAAG,aAAY,CAAA"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const CONVERSATIONS_FLAGS: {
|
|
2
|
+
readonly MODERATION: "conversations.moderation";
|
|
3
|
+
readonly BULK_OPERATIONS: "conversations.bulk-operations";
|
|
4
|
+
readonly AUDIT_LOG: "conversations.audit-log";
|
|
5
|
+
readonly APP_INSTALLATIONS: "conversations.app-installations";
|
|
6
|
+
readonly ARCHIVED_VIEW: "conversations.archived-view";
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=featureFlags.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"featureFlags.d.ts","sourceRoot":"","sources":["../../../src/conversations/constants/featureFlags.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,mBAAmB;;;;;;CAMtB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/conversations/constants/featureFlags.ts
|
|
2
|
+
var e = {
|
|
3
|
+
MODERATION: "conversations.moderation",
|
|
4
|
+
BULK_OPERATIONS: "conversations.bulk-operations",
|
|
5
|
+
AUDIT_LOG: "conversations.audit-log",
|
|
6
|
+
APP_INSTALLATIONS: "conversations.app-installations",
|
|
7
|
+
ARCHIVED_VIEW: "conversations.archived-view"
|
|
8
|
+
};
|
|
9
|
+
//#endregion
|
|
10
|
+
export { e as CONVERSATIONS_FLAGS };
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=featureFlags.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"featureFlags.js","names":[],"sources":["../../../src/conversations/constants/featureFlags.ts"],"sourcesContent":["export const CONVERSATIONS_FLAGS = {\n MODERATION: \"conversations.moderation\",\n BULK_OPERATIONS: \"conversations.bulk-operations\",\n AUDIT_LOG: \"conversations.audit-log\",\n APP_INSTALLATIONS: \"conversations.app-installations\",\n ARCHIVED_VIEW: \"conversations.archived-view\",\n} as const;\n"],"mappings":";AAAA,IAAa,IAAsB;CACjC,YAAY;CACZ,iBAAiB;CACjB,WAAW;CACX,mBAAmB;CACnB,eAAe;CAChB"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RBAC permission constants for the Conversations microfrontend.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the @rbac directives in wspace-conversations-svc
|
|
5
|
+
* (12 resources × 17+ actions, all scopeType: "wspace").
|
|
6
|
+
*
|
|
7
|
+
* Three records are exported:
|
|
8
|
+
* - CONVERSATIONS_PERMISSIONS — master record (union of everything)
|
|
9
|
+
* - CONVERSATIONS_USER_PERMISSIONS — curated subset safe for user-facing UI
|
|
10
|
+
* - CONVERSATIONS_ADMIN_PERMISSIONS — curated subset for admin / governance UI
|
|
11
|
+
*
|
|
12
|
+
* Three derived union types are exported alongside:
|
|
13
|
+
* - ConversationsPermission
|
|
14
|
+
* - ConversationsUserPermission
|
|
15
|
+
* - ConversationsAdminPermission
|
|
16
|
+
*
|
|
17
|
+
* The USER / ADMIN split is a UI-level convention — the backend gateway
|
|
18
|
+
* enforces the real rule via @rbac directives and resolver-level ownership
|
|
19
|
+
* checks. See `workspaces-specs/modules/conversations/ADMIN-USER-SPLIT.md`
|
|
20
|
+
* (ownership rule + naming-convention note) and `RBAC.md` for the canonical
|
|
21
|
+
* role-to-permission mapping.
|
|
22
|
+
*/
|
|
23
|
+
export declare const CONVERSATIONS_PERMISSIONS: {
|
|
24
|
+
readonly CONVERSATION_READ: "conversation:read";
|
|
25
|
+
readonly CONVERSATION_LIST: "conversation:list";
|
|
26
|
+
readonly CONVERSATION_CREATE: "conversation:create";
|
|
27
|
+
readonly CONVERSATION_UPDATE: "conversation:update";
|
|
28
|
+
readonly CONVERSATION_DELETE: "conversation:delete";
|
|
29
|
+
readonly CONVERSATION_ARCHIVE: "conversation:archive";
|
|
30
|
+
readonly CONVERSATION_UNARCHIVE: "conversation:unarchive";
|
|
31
|
+
readonly MESSAGE_READ: "message:read";
|
|
32
|
+
readonly MESSAGE_CREATE: "message:create";
|
|
33
|
+
readonly MESSAGE_UPDATE: "message:update";
|
|
34
|
+
readonly MESSAGE_DELETE: "message:delete";
|
|
35
|
+
readonly MESSAGE_REACT: "message:react";
|
|
36
|
+
readonly MESSAGE_PIN: "message:pin";
|
|
37
|
+
readonly MESSAGE_MODERATE: "message:moderate";
|
|
38
|
+
readonly MESSAGE_REPORT: "message:report";
|
|
39
|
+
readonly MESSAGE_VOTE: "message:vote";
|
|
40
|
+
readonly MESSAGE_DRAFT_READ: "message-draft:read";
|
|
41
|
+
readonly MESSAGE_DRAFT_CREATE: "message-draft:create";
|
|
42
|
+
readonly MESSAGE_DRAFT_DELETE: "message-draft:delete";
|
|
43
|
+
readonly PARTICIPANT_READ: "participant:read";
|
|
44
|
+
readonly PARTICIPANT_ADD: "participant:add";
|
|
45
|
+
readonly PARTICIPANT_REMOVE: "participant:remove";
|
|
46
|
+
readonly PARTICIPANT_UPDATE: "participant:update";
|
|
47
|
+
readonly PARTICIPANT_LEAVE: "participant:leave";
|
|
48
|
+
readonly CONVERSATION_INVITE_READ: "conversation-invite:read";
|
|
49
|
+
readonly CONVERSATION_INVITE_CREATE: "conversation-invite:create";
|
|
50
|
+
readonly CONVERSATION_INVITE_JOIN: "conversation-invite:join";
|
|
51
|
+
readonly CALL_READ: "call:read";
|
|
52
|
+
readonly CALL_CREATE: "call:create";
|
|
53
|
+
readonly CALL_JOIN: "call:join";
|
|
54
|
+
readonly CALL_LEAVE: "call:leave";
|
|
55
|
+
readonly CALL_END: "call:end";
|
|
56
|
+
readonly CALL_UPDATE: "call:update";
|
|
57
|
+
readonly CALL_RECORD: "call:record";
|
|
58
|
+
readonly APP_INSTALLATION_READ: "app-installation:read";
|
|
59
|
+
readonly APP_INSTALLATION_CREATE: "app-installation:create";
|
|
60
|
+
readonly APP_INSTALLATION_UPDATE: "app-installation:update";
|
|
61
|
+
readonly APP_INSTALLATION_DELETE: "app-installation:delete";
|
|
62
|
+
readonly APP_INSTALLATION_EXECUTE: "app-installation:execute";
|
|
63
|
+
readonly PRESENCE_READ: "presence:read";
|
|
64
|
+
readonly PRESENCE_UPDATE: "presence:update";
|
|
65
|
+
readonly ENTITY_COMMENT_READ: "entity-comment:read";
|
|
66
|
+
readonly ENTITY_COMMENT_CREATE: "entity-comment:create";
|
|
67
|
+
readonly ENTITY_COMMENT_UPDATE: "entity-comment:update";
|
|
68
|
+
readonly ENTITY_COMMENT_DELETE: "entity-comment:delete";
|
|
69
|
+
readonly ENTITY_COMMENT_ASSIGN: "entity-comment:assign";
|
|
70
|
+
readonly ENTITY_COMMENT_EXPORT: "entity-comment:export";
|
|
71
|
+
readonly COMMENT_ATTACHMENT_READ: "comment-attachment:read";
|
|
72
|
+
readonly COMMENT_ATTACHMENT_CREATE: "comment-attachment:create";
|
|
73
|
+
readonly COMMENT_ATTACHMENT_UPDATE: "comment-attachment:update";
|
|
74
|
+
readonly COMMENT_ATTACHMENT_DELETE: "comment-attachment:delete";
|
|
75
|
+
readonly COMMENT_TAG_READ: "comment-tag:read";
|
|
76
|
+
readonly COMMENT_TAG_ASSIGN: "comment-tag:assign";
|
|
77
|
+
readonly COMMENT_TAG_UPDATE: "comment-tag:update";
|
|
78
|
+
readonly COMMENT_TAG_DELETE: "comment-tag:delete";
|
|
79
|
+
readonly SCHEDULED_COMMENT_READ: "scheduled-comment:read";
|
|
80
|
+
readonly SCHEDULED_COMMENT_CREATE: "scheduled-comment:create";
|
|
81
|
+
readonly SCHEDULED_COMMENT_UPDATE: "scheduled-comment:update";
|
|
82
|
+
readonly SCHEDULED_COMMENT_DELETE: "scheduled-comment:delete";
|
|
83
|
+
readonly SCHEDULED_COMMENT_EXECUTE: "scheduled-comment:execute";
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* USER — curated subset of permissions safe to reference from
|
|
87
|
+
* user-facing UI (inbox, chat detail, personal settings, etc).
|
|
88
|
+
*
|
|
89
|
+
* Users retain full CRUDL on their own conversations / messages.
|
|
90
|
+
* The backend additionally enforces ownership at runtime — see the
|
|
91
|
+
* "Ownership rule" in `workspaces-specs/modules/conversations/ADMIN-USER-SPLIT.md`:
|
|
92
|
+
* these constants authorize the action on actor-owned resources only;
|
|
93
|
+
* the same action on another user's resource requires an ADMIN permission.
|
|
94
|
+
*
|
|
95
|
+
* Per `RBAC.md`: any member can `message:report` and — when the conversation
|
|
96
|
+
* setting `allowInviteLinks=true` — any member can `conversation-invite:create`.
|
|
97
|
+
* Both constants therefore live in the USER subset. The shell additionally
|
|
98
|
+
* gates invite creation on the conversation setting at render time.
|
|
99
|
+
*/
|
|
100
|
+
export declare const CONVERSATIONS_USER_PERMISSIONS: {
|
|
101
|
+
readonly CONVERSATION_READ: "conversation:read";
|
|
102
|
+
readonly CONVERSATION_LIST: "conversation:list";
|
|
103
|
+
readonly CONVERSATION_CREATE: "conversation:create";
|
|
104
|
+
readonly CONVERSATION_UPDATE: "conversation:update";
|
|
105
|
+
readonly MESSAGE_READ: "message:read";
|
|
106
|
+
readonly MESSAGE_CREATE: "message:create";
|
|
107
|
+
readonly MESSAGE_UPDATE: "message:update";
|
|
108
|
+
readonly MESSAGE_DELETE: "message:delete";
|
|
109
|
+
readonly MESSAGE_REACT: "message:react";
|
|
110
|
+
readonly MESSAGE_REPORT: "message:report";
|
|
111
|
+
readonly MESSAGE_VOTE: "message:vote";
|
|
112
|
+
readonly MESSAGE_DRAFT_READ: "message-draft:read";
|
|
113
|
+
readonly MESSAGE_DRAFT_CREATE: "message-draft:create";
|
|
114
|
+
readonly MESSAGE_DRAFT_DELETE: "message-draft:delete";
|
|
115
|
+
readonly PARTICIPANT_READ: "participant:read";
|
|
116
|
+
readonly PARTICIPANT_LEAVE: "participant:leave";
|
|
117
|
+
readonly CONVERSATION_INVITE_READ: "conversation-invite:read";
|
|
118
|
+
readonly CONVERSATION_INVITE_CREATE: "conversation-invite:create";
|
|
119
|
+
readonly CONVERSATION_INVITE_JOIN: "conversation-invite:join";
|
|
120
|
+
readonly CALL_READ: "call:read";
|
|
121
|
+
readonly CALL_CREATE: "call:create";
|
|
122
|
+
readonly CALL_JOIN: "call:join";
|
|
123
|
+
readonly CALL_LEAVE: "call:leave";
|
|
124
|
+
readonly CALL_UPDATE: "call:update";
|
|
125
|
+
readonly APP_INSTALLATION_READ: "app-installation:read";
|
|
126
|
+
readonly PRESENCE_READ: "presence:read";
|
|
127
|
+
readonly PRESENCE_UPDATE: "presence:update";
|
|
128
|
+
readonly ENTITY_COMMENT_READ: "entity-comment:read";
|
|
129
|
+
readonly ENTITY_COMMENT_CREATE: "entity-comment:create";
|
|
130
|
+
readonly ENTITY_COMMENT_UPDATE: "entity-comment:update";
|
|
131
|
+
readonly ENTITY_COMMENT_DELETE: "entity-comment:delete";
|
|
132
|
+
readonly COMMENT_ATTACHMENT_READ: "comment-attachment:read";
|
|
133
|
+
readonly COMMENT_ATTACHMENT_CREATE: "comment-attachment:create";
|
|
134
|
+
readonly COMMENT_ATTACHMENT_UPDATE: "comment-attachment:update";
|
|
135
|
+
readonly COMMENT_ATTACHMENT_DELETE: "comment-attachment:delete";
|
|
136
|
+
readonly COMMENT_TAG_READ: "comment-tag:read";
|
|
137
|
+
readonly SCHEDULED_COMMENT_READ: "scheduled-comment:read";
|
|
138
|
+
readonly SCHEDULED_COMMENT_CREATE: "scheduled-comment:create";
|
|
139
|
+
readonly SCHEDULED_COMMENT_UPDATE: "scheduled-comment:update";
|
|
140
|
+
readonly SCHEDULED_COMMENT_DELETE: "scheduled-comment:delete";
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* ADMIN / MODERATOR governance — curated subset of permissions
|
|
144
|
+
* that should only be referenced from admin surfaces
|
|
145
|
+
* (admin-app ConversationsAdminRoot). Gates bulk operations,
|
|
146
|
+
* moderation, participant administration, and workspace-wide
|
|
147
|
+
* lifecycle actions.
|
|
148
|
+
*/
|
|
149
|
+
export declare const CONVERSATIONS_ADMIN_PERMISSIONS: {
|
|
150
|
+
readonly CONVERSATION_DELETE: "conversation:delete";
|
|
151
|
+
readonly CONVERSATION_ARCHIVE: "conversation:archive";
|
|
152
|
+
readonly CONVERSATION_UNARCHIVE: "conversation:unarchive";
|
|
153
|
+
readonly MESSAGE_PIN: "message:pin";
|
|
154
|
+
readonly MESSAGE_MODERATE: "message:moderate";
|
|
155
|
+
readonly PARTICIPANT_ADD: "participant:add";
|
|
156
|
+
readonly PARTICIPANT_REMOVE: "participant:remove";
|
|
157
|
+
readonly PARTICIPANT_UPDATE: "participant:update";
|
|
158
|
+
readonly CALL_END: "call:end";
|
|
159
|
+
readonly CALL_RECORD: "call:record";
|
|
160
|
+
readonly APP_INSTALLATION_CREATE: "app-installation:create";
|
|
161
|
+
readonly APP_INSTALLATION_UPDATE: "app-installation:update";
|
|
162
|
+
readonly APP_INSTALLATION_DELETE: "app-installation:delete";
|
|
163
|
+
readonly APP_INSTALLATION_EXECUTE: "app-installation:execute";
|
|
164
|
+
readonly ENTITY_COMMENT_ASSIGN: "entity-comment:assign";
|
|
165
|
+
readonly ENTITY_COMMENT_EXPORT: "entity-comment:export";
|
|
166
|
+
readonly COMMENT_TAG_ASSIGN: "comment-tag:assign";
|
|
167
|
+
readonly COMMENT_TAG_UPDATE: "comment-tag:update";
|
|
168
|
+
readonly COMMENT_TAG_DELETE: "comment-tag:delete";
|
|
169
|
+
readonly SCHEDULED_COMMENT_EXECUTE: "scheduled-comment:execute";
|
|
170
|
+
};
|
|
171
|
+
export type ConversationsPermission = (typeof CONVERSATIONS_PERMISSIONS)[keyof typeof CONVERSATIONS_PERMISSIONS];
|
|
172
|
+
export type ConversationsUserPermission = (typeof CONVERSATIONS_USER_PERMISSIONS)[keyof typeof CONVERSATIONS_USER_PERMISSIONS];
|
|
173
|
+
export type ConversationsAdminPermission = (typeof CONVERSATIONS_ADMIN_PERMISSIONS)[keyof typeof CONVERSATIONS_ADMIN_PERMISSIONS];
|
|
174
|
+
//# sourceMappingURL=permissions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../../src/conversations/constants/permissions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2F5B,CAAC;AAEX;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2DjC,CAAC;AAEX;;;;;;GAMG;AACH,eAAO,MAAM,+BAA+B;;;;;;;;;;;;;;;;;;;;;CA6BlC,CAAC;AAEX,MAAM,MAAM,uBAAuB,GACjC,CAAC,OAAO,yBAAyB,CAAC,CAAC,MAAM,OAAO,yBAAyB,CAAC,CAAC;AAE7E,MAAM,MAAM,2BAA2B,GACrC,CAAC,OAAO,8BAA8B,CAAC,CAAC,MAAM,OAAO,8BAA8B,CAAC,CAAC;AAEvF,MAAM,MAAM,4BAA4B,GACtC,CAAC,OAAO,+BAA+B,CAAC,CAAC,MAAM,OAAO,+BAA+B,CAAC,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
//#region src/conversations/constants/permissions.ts
|
|
2
|
+
var e = {
|
|
3
|
+
CONVERSATION_READ: "conversation:read",
|
|
4
|
+
CONVERSATION_LIST: "conversation:list",
|
|
5
|
+
CONVERSATION_CREATE: "conversation:create",
|
|
6
|
+
CONVERSATION_UPDATE: "conversation:update",
|
|
7
|
+
CONVERSATION_DELETE: "conversation:delete",
|
|
8
|
+
CONVERSATION_ARCHIVE: "conversation:archive",
|
|
9
|
+
CONVERSATION_UNARCHIVE: "conversation:unarchive",
|
|
10
|
+
MESSAGE_READ: "message:read",
|
|
11
|
+
MESSAGE_CREATE: "message:create",
|
|
12
|
+
MESSAGE_UPDATE: "message:update",
|
|
13
|
+
MESSAGE_DELETE: "message:delete",
|
|
14
|
+
MESSAGE_REACT: "message:react",
|
|
15
|
+
MESSAGE_PIN: "message:pin",
|
|
16
|
+
MESSAGE_MODERATE: "message:moderate",
|
|
17
|
+
MESSAGE_REPORT: "message:report",
|
|
18
|
+
MESSAGE_VOTE: "message:vote",
|
|
19
|
+
MESSAGE_DRAFT_READ: "message-draft:read",
|
|
20
|
+
MESSAGE_DRAFT_CREATE: "message-draft:create",
|
|
21
|
+
MESSAGE_DRAFT_DELETE: "message-draft:delete",
|
|
22
|
+
PARTICIPANT_READ: "participant:read",
|
|
23
|
+
PARTICIPANT_ADD: "participant:add",
|
|
24
|
+
PARTICIPANT_REMOVE: "participant:remove",
|
|
25
|
+
PARTICIPANT_UPDATE: "participant:update",
|
|
26
|
+
PARTICIPANT_LEAVE: "participant:leave",
|
|
27
|
+
CONVERSATION_INVITE_READ: "conversation-invite:read",
|
|
28
|
+
CONVERSATION_INVITE_CREATE: "conversation-invite:create",
|
|
29
|
+
CONVERSATION_INVITE_JOIN: "conversation-invite:join",
|
|
30
|
+
CALL_READ: "call:read",
|
|
31
|
+
CALL_CREATE: "call:create",
|
|
32
|
+
CALL_JOIN: "call:join",
|
|
33
|
+
CALL_LEAVE: "call:leave",
|
|
34
|
+
CALL_END: "call:end",
|
|
35
|
+
CALL_UPDATE: "call:update",
|
|
36
|
+
CALL_RECORD: "call:record",
|
|
37
|
+
APP_INSTALLATION_READ: "app-installation:read",
|
|
38
|
+
APP_INSTALLATION_CREATE: "app-installation:create",
|
|
39
|
+
APP_INSTALLATION_UPDATE: "app-installation:update",
|
|
40
|
+
APP_INSTALLATION_DELETE: "app-installation:delete",
|
|
41
|
+
APP_INSTALLATION_EXECUTE: "app-installation:execute",
|
|
42
|
+
PRESENCE_READ: "presence:read",
|
|
43
|
+
PRESENCE_UPDATE: "presence:update",
|
|
44
|
+
ENTITY_COMMENT_READ: "entity-comment:read",
|
|
45
|
+
ENTITY_COMMENT_CREATE: "entity-comment:create",
|
|
46
|
+
ENTITY_COMMENT_UPDATE: "entity-comment:update",
|
|
47
|
+
ENTITY_COMMENT_DELETE: "entity-comment:delete",
|
|
48
|
+
ENTITY_COMMENT_ASSIGN: "entity-comment:assign",
|
|
49
|
+
ENTITY_COMMENT_EXPORT: "entity-comment:export",
|
|
50
|
+
COMMENT_ATTACHMENT_READ: "comment-attachment:read",
|
|
51
|
+
COMMENT_ATTACHMENT_CREATE: "comment-attachment:create",
|
|
52
|
+
COMMENT_ATTACHMENT_UPDATE: "comment-attachment:update",
|
|
53
|
+
COMMENT_ATTACHMENT_DELETE: "comment-attachment:delete",
|
|
54
|
+
COMMENT_TAG_READ: "comment-tag:read",
|
|
55
|
+
COMMENT_TAG_ASSIGN: "comment-tag:assign",
|
|
56
|
+
COMMENT_TAG_UPDATE: "comment-tag:update",
|
|
57
|
+
COMMENT_TAG_DELETE: "comment-tag:delete",
|
|
58
|
+
SCHEDULED_COMMENT_READ: "scheduled-comment:read",
|
|
59
|
+
SCHEDULED_COMMENT_CREATE: "scheduled-comment:create",
|
|
60
|
+
SCHEDULED_COMMENT_UPDATE: "scheduled-comment:update",
|
|
61
|
+
SCHEDULED_COMMENT_DELETE: "scheduled-comment:delete",
|
|
62
|
+
SCHEDULED_COMMENT_EXECUTE: "scheduled-comment:execute"
|
|
63
|
+
};
|
|
64
|
+
e.CONVERSATION_READ, e.CONVERSATION_LIST, e.CONVERSATION_CREATE, e.CONVERSATION_UPDATE, e.MESSAGE_READ, e.MESSAGE_CREATE, e.MESSAGE_UPDATE, e.MESSAGE_DELETE, e.MESSAGE_REACT, e.MESSAGE_REPORT, e.MESSAGE_VOTE, e.MESSAGE_DRAFT_READ, e.MESSAGE_DRAFT_CREATE, e.MESSAGE_DRAFT_DELETE, e.PARTICIPANT_READ, e.PARTICIPANT_LEAVE, e.CONVERSATION_INVITE_READ, e.CONVERSATION_INVITE_CREATE, e.CONVERSATION_INVITE_JOIN, e.CALL_READ, e.CALL_CREATE, e.CALL_JOIN, e.CALL_LEAVE, e.CALL_UPDATE, e.APP_INSTALLATION_READ, e.PRESENCE_READ, e.PRESENCE_UPDATE, e.ENTITY_COMMENT_READ, e.ENTITY_COMMENT_CREATE, e.ENTITY_COMMENT_UPDATE, e.ENTITY_COMMENT_DELETE, e.COMMENT_ATTACHMENT_READ, e.COMMENT_ATTACHMENT_CREATE, e.COMMENT_ATTACHMENT_UPDATE, e.COMMENT_ATTACHMENT_DELETE, e.COMMENT_TAG_READ, e.SCHEDULED_COMMENT_READ, e.SCHEDULED_COMMENT_CREATE, e.SCHEDULED_COMMENT_UPDATE, e.SCHEDULED_COMMENT_DELETE, e.CONVERSATION_DELETE, e.CONVERSATION_ARCHIVE, e.CONVERSATION_UNARCHIVE, e.MESSAGE_PIN, e.MESSAGE_MODERATE, e.PARTICIPANT_ADD, e.PARTICIPANT_REMOVE, e.PARTICIPANT_UPDATE, e.CALL_END, e.CALL_RECORD, e.APP_INSTALLATION_CREATE, e.APP_INSTALLATION_UPDATE, e.APP_INSTALLATION_DELETE, e.APP_INSTALLATION_EXECUTE, e.ENTITY_COMMENT_ASSIGN, e.ENTITY_COMMENT_EXPORT, e.COMMENT_TAG_ASSIGN, e.COMMENT_TAG_UPDATE, e.COMMENT_TAG_DELETE, e.SCHEDULED_COMMENT_EXECUTE;
|
|
65
|
+
//#endregion
|
|
66
|
+
export { e as CONVERSATIONS_PERMISSIONS };
|
|
67
|
+
|
|
68
|
+
//# sourceMappingURL=permissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.js","names":[],"sources":["../../../src/conversations/constants/permissions.ts"],"sourcesContent":["/**\n * RBAC permission constants for the Conversations microfrontend.\n *\n * Mirrors the @rbac directives in wspace-conversations-svc\n * (12 resources × 17+ actions, all scopeType: \"wspace\").\n *\n * Three records are exported:\n * - CONVERSATIONS_PERMISSIONS — master record (union of everything)\n * - CONVERSATIONS_USER_PERMISSIONS — curated subset safe for user-facing UI\n * - CONVERSATIONS_ADMIN_PERMISSIONS — curated subset for admin / governance UI\n *\n * Three derived union types are exported alongside:\n * - ConversationsPermission\n * - ConversationsUserPermission\n * - ConversationsAdminPermission\n *\n * The USER / ADMIN split is a UI-level convention — the backend gateway\n * enforces the real rule via @rbac directives and resolver-level ownership\n * checks. See `workspaces-specs/modules/conversations/ADMIN-USER-SPLIT.md`\n * (ownership rule + naming-convention note) and `RBAC.md` for the canonical\n * role-to-permission mapping.\n */\n\nexport const CONVERSATIONS_PERMISSIONS = {\n // ────────────── conversation resource ──────────────\n CONVERSATION_READ: \"conversation:read\",\n CONVERSATION_LIST: \"conversation:list\",\n CONVERSATION_CREATE: \"conversation:create\",\n CONVERSATION_UPDATE: \"conversation:update\",\n CONVERSATION_DELETE: \"conversation:delete\",\n CONVERSATION_ARCHIVE: \"conversation:archive\",\n CONVERSATION_UNARCHIVE: \"conversation:unarchive\",\n\n // ────────────── message resource ──────────────\n MESSAGE_READ: \"message:read\",\n MESSAGE_CREATE: \"message:create\",\n MESSAGE_UPDATE: \"message:update\",\n MESSAGE_DELETE: \"message:delete\",\n MESSAGE_REACT: \"message:react\",\n MESSAGE_PIN: \"message:pin\",\n MESSAGE_MODERATE: \"message:moderate\",\n MESSAGE_REPORT: \"message:report\",\n MESSAGE_VOTE: \"message:vote\",\n\n // ────────────── message-draft resource ──────────────\n // Note: no MESSAGE_DRAFT_UPDATE — drafts are create-and-replace\n // (the backend schema exposes read/create/delete only; saveDraft\n // replaces any existing draft for the conversation).\n MESSAGE_DRAFT_READ: \"message-draft:read\",\n MESSAGE_DRAFT_CREATE: \"message-draft:create\",\n MESSAGE_DRAFT_DELETE: \"message-draft:delete\",\n\n // ────────────── participant resource ──────────────\n PARTICIPANT_READ: \"participant:read\",\n PARTICIPANT_ADD: \"participant:add\",\n PARTICIPANT_REMOVE: \"participant:remove\",\n PARTICIPANT_UPDATE: \"participant:update\",\n PARTICIPANT_LEAVE: \"participant:leave\",\n\n // ────────────── conversation-invite resource ──────────────\n CONVERSATION_INVITE_READ: \"conversation-invite:read\",\n CONVERSATION_INVITE_CREATE: \"conversation-invite:create\",\n CONVERSATION_INVITE_JOIN: \"conversation-invite:join\",\n\n // ────────────── call resource ──────────────\n // CALL_UPDATE is participant-self-service: it backs `updateCallParticipant`\n // (muted / video / screen share state for the calling participant). Call\n // host/moderator-only actions — ending or recording — live in\n // CALL_END / CALL_RECORD and belong in the admin subset.\n CALL_READ: \"call:read\",\n CALL_CREATE: \"call:create\",\n CALL_JOIN: \"call:join\",\n CALL_LEAVE: \"call:leave\",\n CALL_END: \"call:end\",\n CALL_UPDATE: \"call:update\",\n CALL_RECORD: \"call:record\",\n\n // ────────────── app-installation resource ──────────────\n APP_INSTALLATION_READ: \"app-installation:read\",\n APP_INSTALLATION_CREATE: \"app-installation:create\",\n APP_INSTALLATION_UPDATE: \"app-installation:update\",\n APP_INSTALLATION_DELETE: \"app-installation:delete\",\n APP_INSTALLATION_EXECUTE: \"app-installation:execute\",\n\n // ────────────── presence resource ──────────────\n PRESENCE_READ: \"presence:read\",\n PRESENCE_UPDATE: \"presence:update\",\n\n // ────────────── entity-comment resource ──────────────\n ENTITY_COMMENT_READ: \"entity-comment:read\",\n ENTITY_COMMENT_CREATE: \"entity-comment:create\",\n ENTITY_COMMENT_UPDATE: \"entity-comment:update\",\n ENTITY_COMMENT_DELETE: \"entity-comment:delete\",\n ENTITY_COMMENT_ASSIGN: \"entity-comment:assign\",\n ENTITY_COMMENT_EXPORT: \"entity-comment:export\",\n\n // ────────────── comment-attachment resource ──────────────\n COMMENT_ATTACHMENT_READ: \"comment-attachment:read\",\n COMMENT_ATTACHMENT_CREATE: \"comment-attachment:create\",\n COMMENT_ATTACHMENT_UPDATE: \"comment-attachment:update\",\n COMMENT_ATTACHMENT_DELETE: \"comment-attachment:delete\",\n\n // ────────────── comment-tag resource ──────────────\n COMMENT_TAG_READ: \"comment-tag:read\",\n COMMENT_TAG_ASSIGN: \"comment-tag:assign\",\n COMMENT_TAG_UPDATE: \"comment-tag:update\",\n COMMENT_TAG_DELETE: \"comment-tag:delete\",\n\n // ────────────── scheduled-comment resource ──────────────\n SCHEDULED_COMMENT_READ: \"scheduled-comment:read\",\n SCHEDULED_COMMENT_CREATE: \"scheduled-comment:create\",\n SCHEDULED_COMMENT_UPDATE: \"scheduled-comment:update\",\n SCHEDULED_COMMENT_DELETE: \"scheduled-comment:delete\",\n SCHEDULED_COMMENT_EXECUTE: \"scheduled-comment:execute\",\n} as const;\n\n/**\n * USER — curated subset of permissions safe to reference from\n * user-facing UI (inbox, chat detail, personal settings, etc).\n *\n * Users retain full CRUDL on their own conversations / messages.\n * The backend additionally enforces ownership at runtime — see the\n * \"Ownership rule\" in `workspaces-specs/modules/conversations/ADMIN-USER-SPLIT.md`:\n * these constants authorize the action on actor-owned resources only;\n * the same action on another user's resource requires an ADMIN permission.\n *\n * Per `RBAC.md`: any member can `message:report` and — when the conversation\n * setting `allowInviteLinks=true` — any member can `conversation-invite:create`.\n * Both constants therefore live in the USER subset. The shell additionally\n * gates invite creation on the conversation setting at render time.\n */\nexport const CONVERSATIONS_USER_PERMISSIONS = {\n CONVERSATION_READ: CONVERSATIONS_PERMISSIONS.CONVERSATION_READ,\n CONVERSATION_LIST: CONVERSATIONS_PERMISSIONS.CONVERSATION_LIST,\n CONVERSATION_CREATE: CONVERSATIONS_PERMISSIONS.CONVERSATION_CREATE,\n CONVERSATION_UPDATE: CONVERSATIONS_PERMISSIONS.CONVERSATION_UPDATE,\n\n MESSAGE_READ: CONVERSATIONS_PERMISSIONS.MESSAGE_READ,\n MESSAGE_CREATE: CONVERSATIONS_PERMISSIONS.MESSAGE_CREATE,\n MESSAGE_UPDATE: CONVERSATIONS_PERMISSIONS.MESSAGE_UPDATE,\n MESSAGE_DELETE: CONVERSATIONS_PERMISSIONS.MESSAGE_DELETE,\n MESSAGE_REACT: CONVERSATIONS_PERMISSIONS.MESSAGE_REACT,\n MESSAGE_REPORT: CONVERSATIONS_PERMISSIONS.MESSAGE_REPORT,\n MESSAGE_VOTE: CONVERSATIONS_PERMISSIONS.MESSAGE_VOTE,\n\n MESSAGE_DRAFT_READ: CONVERSATIONS_PERMISSIONS.MESSAGE_DRAFT_READ,\n MESSAGE_DRAFT_CREATE: CONVERSATIONS_PERMISSIONS.MESSAGE_DRAFT_CREATE,\n MESSAGE_DRAFT_DELETE: CONVERSATIONS_PERMISSIONS.MESSAGE_DRAFT_DELETE,\n\n PARTICIPANT_READ: CONVERSATIONS_PERMISSIONS.PARTICIPANT_READ,\n PARTICIPANT_LEAVE: CONVERSATIONS_PERMISSIONS.PARTICIPANT_LEAVE,\n\n CONVERSATION_INVITE_READ: CONVERSATIONS_PERMISSIONS.CONVERSATION_INVITE_READ,\n CONVERSATION_INVITE_CREATE:\n CONVERSATIONS_PERMISSIONS.CONVERSATION_INVITE_CREATE,\n CONVERSATION_INVITE_JOIN: CONVERSATIONS_PERMISSIONS.CONVERSATION_INVITE_JOIN,\n\n CALL_READ: CONVERSATIONS_PERMISSIONS.CALL_READ,\n CALL_CREATE: CONVERSATIONS_PERMISSIONS.CALL_CREATE,\n CALL_JOIN: CONVERSATIONS_PERMISSIONS.CALL_JOIN,\n CALL_LEAVE: CONVERSATIONS_PERMISSIONS.CALL_LEAVE,\n // CALL_UPDATE backs `updateCallParticipant` (per-participant self-service\n // state like mute / video / screen share). Host-only call lifecycle actions\n // (end, record) are ADMIN and live in CONVERSATIONS_ADMIN_PERMISSIONS.\n CALL_UPDATE: CONVERSATIONS_PERMISSIONS.CALL_UPDATE,\n\n APP_INSTALLATION_READ: CONVERSATIONS_PERMISSIONS.APP_INSTALLATION_READ,\n\n PRESENCE_READ: CONVERSATIONS_PERMISSIONS.PRESENCE_READ,\n PRESENCE_UPDATE: CONVERSATIONS_PERMISSIONS.PRESENCE_UPDATE,\n\n ENTITY_COMMENT_READ: CONVERSATIONS_PERMISSIONS.ENTITY_COMMENT_READ,\n ENTITY_COMMENT_CREATE: CONVERSATIONS_PERMISSIONS.ENTITY_COMMENT_CREATE,\n ENTITY_COMMENT_UPDATE: CONVERSATIONS_PERMISSIONS.ENTITY_COMMENT_UPDATE,\n ENTITY_COMMENT_DELETE: CONVERSATIONS_PERMISSIONS.ENTITY_COMMENT_DELETE,\n\n COMMENT_ATTACHMENT_READ: CONVERSATIONS_PERMISSIONS.COMMENT_ATTACHMENT_READ,\n COMMENT_ATTACHMENT_CREATE:\n CONVERSATIONS_PERMISSIONS.COMMENT_ATTACHMENT_CREATE,\n COMMENT_ATTACHMENT_UPDATE:\n CONVERSATIONS_PERMISSIONS.COMMENT_ATTACHMENT_UPDATE,\n COMMENT_ATTACHMENT_DELETE:\n CONVERSATIONS_PERMISSIONS.COMMENT_ATTACHMENT_DELETE,\n\n COMMENT_TAG_READ: CONVERSATIONS_PERMISSIONS.COMMENT_TAG_READ,\n\n SCHEDULED_COMMENT_READ: CONVERSATIONS_PERMISSIONS.SCHEDULED_COMMENT_READ,\n SCHEDULED_COMMENT_CREATE: CONVERSATIONS_PERMISSIONS.SCHEDULED_COMMENT_CREATE,\n SCHEDULED_COMMENT_UPDATE: CONVERSATIONS_PERMISSIONS.SCHEDULED_COMMENT_UPDATE,\n SCHEDULED_COMMENT_DELETE: CONVERSATIONS_PERMISSIONS.SCHEDULED_COMMENT_DELETE,\n} as const;\n\n/**\n * ADMIN / MODERATOR governance — curated subset of permissions\n * that should only be referenced from admin surfaces\n * (admin-app ConversationsAdminRoot). Gates bulk operations,\n * moderation, participant administration, and workspace-wide\n * lifecycle actions.\n */\nexport const CONVERSATIONS_ADMIN_PERMISSIONS = {\n CONVERSATION_DELETE: CONVERSATIONS_PERMISSIONS.CONVERSATION_DELETE,\n CONVERSATION_ARCHIVE: CONVERSATIONS_PERMISSIONS.CONVERSATION_ARCHIVE,\n CONVERSATION_UNARCHIVE: CONVERSATIONS_PERMISSIONS.CONVERSATION_UNARCHIVE,\n\n MESSAGE_PIN: CONVERSATIONS_PERMISSIONS.MESSAGE_PIN,\n MESSAGE_MODERATE: CONVERSATIONS_PERMISSIONS.MESSAGE_MODERATE,\n\n PARTICIPANT_ADD: CONVERSATIONS_PERMISSIONS.PARTICIPANT_ADD,\n PARTICIPANT_REMOVE: CONVERSATIONS_PERMISSIONS.PARTICIPANT_REMOVE,\n PARTICIPANT_UPDATE: CONVERSATIONS_PERMISSIONS.PARTICIPANT_UPDATE,\n\n CALL_END: CONVERSATIONS_PERMISSIONS.CALL_END,\n CALL_RECORD: CONVERSATIONS_PERMISSIONS.CALL_RECORD,\n\n APP_INSTALLATION_CREATE: CONVERSATIONS_PERMISSIONS.APP_INSTALLATION_CREATE,\n APP_INSTALLATION_UPDATE: CONVERSATIONS_PERMISSIONS.APP_INSTALLATION_UPDATE,\n APP_INSTALLATION_DELETE: CONVERSATIONS_PERMISSIONS.APP_INSTALLATION_DELETE,\n APP_INSTALLATION_EXECUTE: CONVERSATIONS_PERMISSIONS.APP_INSTALLATION_EXECUTE,\n\n ENTITY_COMMENT_ASSIGN: CONVERSATIONS_PERMISSIONS.ENTITY_COMMENT_ASSIGN,\n ENTITY_COMMENT_EXPORT: CONVERSATIONS_PERMISSIONS.ENTITY_COMMENT_EXPORT,\n\n COMMENT_TAG_ASSIGN: CONVERSATIONS_PERMISSIONS.COMMENT_TAG_ASSIGN,\n COMMENT_TAG_UPDATE: CONVERSATIONS_PERMISSIONS.COMMENT_TAG_UPDATE,\n COMMENT_TAG_DELETE: CONVERSATIONS_PERMISSIONS.COMMENT_TAG_DELETE,\n\n SCHEDULED_COMMENT_EXECUTE:\n CONVERSATIONS_PERMISSIONS.SCHEDULED_COMMENT_EXECUTE,\n} as const;\n\nexport type ConversationsPermission =\n (typeof CONVERSATIONS_PERMISSIONS)[keyof typeof CONVERSATIONS_PERMISSIONS];\n\nexport type ConversationsUserPermission =\n (typeof CONVERSATIONS_USER_PERMISSIONS)[keyof typeof CONVERSATIONS_USER_PERMISSIONS];\n\nexport type ConversationsAdminPermission =\n (typeof CONVERSATIONS_ADMIN_PERMISSIONS)[keyof typeof CONVERSATIONS_ADMIN_PERMISSIONS];\n"],"mappings":";AAuBA,IAAa,IAA4B;CAEvC,mBAAmB;CACnB,mBAAmB;CACnB,qBAAqB;CACrB,qBAAqB;CACrB,qBAAqB;CACrB,sBAAsB;CACtB,wBAAwB;CAGxB,cAAc;CACd,gBAAgB;CAChB,gBAAgB;CAChB,gBAAgB;CAChB,eAAe;CACf,aAAa;CACb,kBAAkB;CAClB,gBAAgB;CAChB,cAAc;CAMd,oBAAoB;CACpB,sBAAsB;CACtB,sBAAsB;CAGtB,kBAAkB;CAClB,iBAAiB;CACjB,oBAAoB;CACpB,oBAAoB;CACpB,mBAAmB;CAGnB,0BAA0B;CAC1B,4BAA4B;CAC5B,0BAA0B;CAO1B,WAAW;CACX,aAAa;CACb,WAAW;CACX,YAAY;CACZ,UAAU;CACV,aAAa;CACb,aAAa;CAGb,uBAAuB;CACvB,yBAAyB;CACzB,yBAAyB;CACzB,yBAAyB;CACzB,0BAA0B;CAG1B,eAAe;CACf,iBAAiB;CAGjB,qBAAqB;CACrB,uBAAuB;CACvB,uBAAuB;CACvB,uBAAuB;CACvB,uBAAuB;CACvB,uBAAuB;CAGvB,yBAAyB;CACzB,2BAA2B;CAC3B,2BAA2B;CAC3B,2BAA2B;CAG3B,kBAAkB;CAClB,oBAAoB;CACpB,oBAAoB;CACpB,oBAAoB;CAGpB,wBAAwB;CACxB,0BAA0B;CAC1B,0BAA0B;CAC1B,0BAA0B;CAC1B,2BAA2B;CAC5B;AAkBoB,EAA0B,mBAC1B,EAA0B,mBACxB,EAA0B,qBAC1B,EAA0B,qBAEjC,EAA0B,cACxB,EAA0B,gBAC1B,EAA0B,gBAC1B,EAA0B,gBAC3B,EAA0B,eACzB,EAA0B,gBAC5B,EAA0B,cAEpB,EAA0B,oBACxB,EAA0B,sBAC1B,EAA0B,sBAE9B,EAA0B,kBACzB,EAA0B,mBAEnB,EAA0B,0BAElD,EAA0B,4BACF,EAA0B,0BAEzC,EAA0B,WACxB,EAA0B,aAC5B,EAA0B,WACzB,EAA0B,YAIzB,EAA0B,aAEhB,EAA0B,uBAElC,EAA0B,eACxB,EAA0B,iBAEtB,EAA0B,qBACxB,EAA0B,uBAC1B,EAA0B,uBAC1B,EAA0B,uBAExB,EAA0B,yBAEjD,EAA0B,2BAE1B,EAA0B,2BAE1B,EAA0B,2BAEV,EAA0B,kBAEpB,EAA0B,wBACxB,EAA0B,0BAC1B,EAA0B,0BAC1B,EAA0B,0BAW/B,EAA0B,qBACzB,EAA0B,sBACxB,EAA0B,wBAErC,EAA0B,aACrB,EAA0B,kBAE3B,EAA0B,iBACvB,EAA0B,oBAC1B,EAA0B,oBAEpC,EAA0B,UACvB,EAA0B,aAEd,EAA0B,yBAC1B,EAA0B,yBAC1B,EAA0B,yBACzB,EAA0B,0BAE7B,EAA0B,uBAC1B,EAA0B,uBAE7B,EAA0B,oBAC1B,EAA0B,oBAC1B,EAA0B,oBAG5C,EAA0B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAdminFeatureFlags.d.ts","sourceRoot":"","sources":["../../../src/conversations/hooks/useAdminFeatureFlags.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,iBAAiB;IAChC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,oBAAoB,IAAI,iBAAiB,CAaxD"}
|