@burdenoff/microfe-channel 2026.513.1 → 2026.514.1
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/dist/channel/ChannelRoot.js +1 -1
- package/dist/channel/ChannelRoot.js.map +1 -1
- package/dist/channel/hooks/useChannelSubscription.d.ts +4 -4
- package/dist/channel/hooks/useChannelSubscription.d.ts.map +1 -1
- package/dist/channel/hooks/useChannelSubscription.js +2 -2
- package/dist/channel/hooks/useChannelSubscription.js.map +1 -1
- package/dist/channel/hooks/useChannels.d.ts.map +1 -1
- package/dist/channel/hooks/useChannels.js +130 -124
- package/dist/channel/hooks/useChannels.js.map +1 -1
- package/dist/channel/modules/channels/pages/ChannelSettingsPage.js +5 -5
- package/dist/channel/modules/channels/pages/ChannelSettingsPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/ChannelUsersPage.d.ts.map +1 -1
- package/dist/channel/modules/channels/pages/ChannelUsersPage.js +25 -7
- package/dist/channel/modules/channels/pages/ChannelUsersPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/ConnectionDetailsPage.js +7 -7
- package/dist/channel/modules/channels/pages/ConnectionDetailsPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/ConnectionsListPage.d.ts.map +1 -1
- package/dist/channel/modules/channels/pages/ConnectionsListPage.js +137 -133
- package/dist/channel/modules/channels/pages/ConnectionsListPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/DeliveryHistoryPage.d.ts.map +1 -1
- package/dist/channel/modules/channels/pages/DeliveryHistoryPage.js +162 -158
- package/dist/channel/modules/channels/pages/DeliveryHistoryPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/EditChannelPage.js +5 -5
- package/dist/channel/modules/channels/pages/EditChannelPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/SendMessagePage.js +2 -2
- package/dist/channel/modules/channels/pages/SendMessagePage.js.map +1 -1
- package/dist/channel/modules/channels/pages/WebhookEventsPage.d.ts.map +1 -1
- package/dist/channel/modules/channels/pages/WebhookEventsPage.js +11 -3
- package/dist/channel/modules/channels/pages/WebhookEventsPage.js.map +1 -1
- package/dist/generated/wspace-types.d.ts +681 -145
- package/dist/generated/wspace-types.d.ts.map +1 -1
- package/dist/translations/en.d.ts +260 -0
- package/dist/translations/en.d.ts.map +1 -0
- package/package.json +3 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConnectionsListPage.js","names":[],"sources":["../../../../../src/channel/modules/channels/pages/ConnectionsListPage.tsx"],"sourcesContent":["/**\n * Connections List Page\n *\n * Displays all connections across channels with their status.\n */\n\nimport { useState } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { TagBadge } from '@burdenoff/fe-libs/tag';\nimport {\n ArrowLeft,\n Plus,\n Loader2,\n AlertCircle,\n CheckCircle2,\n XCircle,\n RefreshCw,\n Settings,\n Link,\n} from 'lucide-react';\nimport { useChannels } from '../../../hooks/useChannels';\nimport { useChannel as useChannelContext } from '../../../providers/ChannelProvider';\nimport { PermissionGuard } from '../../../components/PermissionGuard';\nimport { CHANNEL_PERMISSIONS } from '../../../constants/permissions';\nimport {\n CONNECTION_STATUS_CHANGED_SUBSCRIPTION,\n useChannelSubscription,\n} from '../../../hooks/useChannelSubscription';\n\nconst HEALTH_CONFIG: Record<string, { icon: typeof CheckCircle2; color: string; label: string }> = {\n true: { icon: CheckCircle2, color: 'text-green-500', label: 'Healthy' },\n false: { icon: XCircle, color: 'text-red-500', label: 'Unhealthy' },\n};\n\nexport function ConnectionsListPage() {\n const navigate = useNavigate();\n const { channels, isLoading, error, refetch } = useChannels();\n const { organizationId } = useChannelContext();\n\n // Real-time connection status. Subscribes to `connectionStatusChanged`\n // when the gateway exposes it; otherwise polls every 60s as a\n // conservative fallback when subs are unavailable.\n useChannelSubscription({\n query: CONNECTION_STATUS_CHANGED_SUBSCRIPTION,\n variables: { organizationId },\n operationName: 'ConnectionStatusChanged',\n enabled: Boolean(organizationId),\n onData: () => void refetch(),\n pollFn: refetch,\n pollIntervalMs: 60_000,\n });\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 // Filter state\n const [healthFilter, setHealthFilter] = useState<string>('all');\n const [platformFilter, setPlatformFilter] = useState<string>('all');\n\n // Get all connections from channels\n const connections = channels\n .filter((ch) => ch.connection)\n .map((ch) => ({\n channelId: ch.id,\n channelName: ch.name,\n platform: ch.platform,\n adapterType: ch.adapterType,\n channelStatus: ch.status,\n connectionId: ch.connection!.id,\n isActive: ch.connection!.isActive,\n isHealthy: ch.connection!.isHealthy,\n needsTokenRefresh: ch.connection!.needsTokenRefresh,\n lastTestedAt: ch.connection!.lastTestedAt,\n authType: ch.connection!.authType,\n tagAssignments: ch.connection!.tagAssignments ?? [],\n }));\n\n // Get unique platforms\n const platforms = [...new Set(connections.map((c) => c.platform))];\n\n // Apply filters\n const filteredConnections = connections.filter((conn) => {\n if (healthFilter === 'healthy' && !conn.isHealthy) return false;\n if (healthFilter === 'unhealthy' && conn.isHealthy) return false;\n if (platformFilter !== 'all' && conn.platform !== platformFilter) return false;\n return true;\n });\n\n if (isLoading) {\n return (\n <div className=\"flex items-center justify-center min-h-screen\">\n <Loader2 className=\"w-8 h-8 animate-spin text-muted-foreground\" />\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"flex flex-col items-center justify-center min-h-screen gap-4\">\n <AlertCircle className=\"w-12 h-12 text-destructive\" />\n <h1 className=\"text-xl font-semibold\">\n {tr('channel.loadConnectionsFailed', 'Failed to load connections')}\n </h1>\n <p className=\"text-sm text-muted-foreground\">{error}</p>\n <button\n onClick={() => refetch()}\n className=\"px-4 py-2 rounded-lg bg-primary text-primary-foreground hover:bg-primary/90\"\n >\n {tr('channel.retry', 'Retry')}\n </button>\n </div>\n );\n }\n\n return (\n <PermissionGuard permission={CHANNEL_PERMISSIONS.CHANNEL_CONNECTION_READ}>\n <div className=\"min-h-screen bg-background\">\n {/* Header */}\n <div className=\"border-b bg-card\">\n <div className=\"container mx-auto px-6 py-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <button\n onClick={() => navigate('./list')}\n className=\"p-2 hover:bg-muted rounded-lg transition-colors\"\n >\n <ArrowLeft className=\"w-5 h-5\" />\n </button>\n <div>\n <h1 className=\"text-2xl font-bold\">{tr('channel.connections', 'Connections')}</h1>\n <p className=\"text-sm text-muted-foreground\">\n {filteredConnections.length} connection\n {filteredConnections.length !== 1 ? 's' : ''}\n </p>\n </div>\n </div>\n <button\n onClick={() => navigate('./create')}\n className=\"px-4 py-2 rounded-lg bg-primary text-primary-foreground hover:bg-primary/90 transition-colors flex items-center gap-2\"\n >\n <Plus className=\"w-4 h-4\" />\n {tr('channel.newChannel', 'New Channel')}\n </button>\n </div>\n </div>\n </div>\n\n {/* Filters */}\n <div className=\"container mx-auto px-6 py-4\">\n <div className=\"flex items-center gap-4\">\n <select\n value={platformFilter}\n onChange={(e) => setPlatformFilter(e.target.value)}\n className=\"px-4 py-2 rounded-lg border bg-background focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n <option value=\"all\">{tr('channel.allPlatforms', 'All Platforms')}</option>\n {platforms.map((p) => (\n <option key={p} value={p}>\n {p}\n </option>\n ))}\n </select>\n\n <select\n value={healthFilter}\n onChange={(e) => setHealthFilter(e.target.value)}\n className=\"px-4 py-2 rounded-lg border bg-background focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n <option value=\"all\">{tr('channel.allStatus', 'All Status')}</option>\n <option value=\"healthy\">{tr('channel.healthy', 'Healthy')}</option>\n <option value=\"unhealthy\">{tr('channel.unhealthy', 'Unhealthy')}</option>\n </select>\n\n <button\n onClick={() => refetch()}\n className=\"p-2 hover:bg-muted rounded-lg transition-colors\"\n title={tr('channel.refresh', 'Refresh')}\n >\n <RefreshCw className=\"w-5 h-5\" />\n </button>\n </div>\n </div>\n\n {/* Connections List */}\n <div className=\"container mx-auto px-6 pb-8\">\n {filteredConnections.length === 0 ? (\n <div className=\"text-center py-12\">\n <Link className=\"w-12 h-12 mx-auto text-muted-foreground mb-4\" />\n <h2 className=\"text-lg font-semibold mb-2\">\n {tr('channel.noConnectionsFound', 'No connections found')}\n </h2>\n <p className=\"text-sm text-muted-foreground mb-4\">\n {channels.length === 0\n ? tr('channel.createChannelFirst', 'Create a channel first to add connections')\n : tr('channel.noConnectionsMatchFilter', 'No connections match your filters')}\n </p>\n {channels.length === 0 ? (\n <button\n onClick={() => navigate('./create')}\n className=\"px-4 py-2 rounded-lg bg-primary text-primary-foreground hover:bg-primary/90\"\n >\n {tr('channel.createChannel', 'Create Channel')}\n </button>\n ) : (\n <button\n onClick={() => {\n setHealthFilter('all');\n setPlatformFilter('all');\n }}\n className=\"px-4 py-2 rounded-lg border hover:bg-muted\"\n >\n {tr('channel.clearFilters', 'Clear Filters')}\n </button>\n )}\n </div>\n ) : (\n <div className=\"border rounded-lg divide-y\">\n {filteredConnections.map((conn) => {\n const health = HEALTH_CONFIG[String(conn.isHealthy)] || HEALTH_CONFIG.false;\n const HealthIcon = health.icon;\n\n return (\n <div\n key={conn.connectionId}\n className=\"p-4 hover:bg-muted/50 transition-colors cursor-pointer\"\n onClick={() => navigate(`./${conn.channelId}`)}\n >\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <div className={health.color}>\n <HealthIcon className=\"w-5 h-5\" />\n </div>\n <div>\n <p className=\"font-medium\">{conn.channelName}</p>\n <p className=\"text-sm text-muted-foreground\">\n {conn.platform} • {conn.adapterType} • {conn.authType}\n </p>\n </div>\n </div>\n\n <div className=\"flex items-center gap-4\">\n <div className=\"text-right\">\n <p className=\"text-sm\">\n {conn.channelStatus === 'ACTIVE' ? (\n <span className=\"text-green-500\">\n {tr('channel.activeStatus', 'Active')}\n </span>\n ) : conn.channelStatus === 'INACTIVE' ? (\n <span className=\"text-muted-foreground\">\n {tr('channel.inactiveStatus', 'Inactive')}\n </span>\n ) : conn.channelStatus === 'ERROR' ? (\n <span className=\"text-red-500\">\n {tr('channel.errorStatus', 'Error')}\n </span>\n ) : conn.channelStatus === 'SUSPENDED' ? (\n <span className=\"text-yellow-500\">\n {tr('channel.suspendedStatus', 'Suspended')}\n </span>\n ) : conn.channelStatus === 'ARCHIVED' ? (\n <span className=\"text-muted-foreground\">\n {tr('channel.archivedStatus', 'Archived')}\n </span>\n ) : (\n <span className=\"text-muted-foreground\">\n {tr('channel.inactiveStatus', 'Inactive')}\n </span>\n )}\n </p>\n {conn.lastTestedAt && (\n <p className=\"text-xs text-muted-foreground\">\n Last tested: {new Date(conn.lastTestedAt).toLocaleDateString()}\n </p>\n )}\n </div>\n\n {conn.needsTokenRefresh && (\n <span className=\"px-2 py-1 text-xs bg-yellow-500/10 text-yellow-500 rounded\">\n Token Expires\n </span>\n )}\n\n {conn.tagAssignments.length > 0 && (\n <div className=\"flex flex-wrap gap-1\" aria-label=\"Connection tags\">\n {conn.tagAssignments.slice(0, 3).map((a) => (\n <TagBadge key={a.id} id={a.tagId} label={a.tagId} size=\"sm\" />\n ))}\n {conn.tagAssignments.length > 3 && (\n <span className=\"text-xs text-muted-foreground\">\n +{conn.tagAssignments.length - 3}\n </span>\n )}\n </div>\n )}\n\n <button\n onClick={(e) => {\n e.stopPropagation();\n navigate(`/channels/${conn.channelId}`);\n }}\n className=\"p-2 hover:bg-muted rounded-lg transition-colors\"\n >\n <Settings className=\"w-4 h-4\" />\n </button>\n </div>\n </div>\n </div>\n );\n })}\n </div>\n )}\n </div>\n </div>\n </PermissionGuard>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ConnectionsListPage.js","names":[],"sources":["../../../../../src/channel/modules/channels/pages/ConnectionsListPage.tsx"],"sourcesContent":["/**\n * Connections List Page\n *\n * Displays all connections across channels with their status.\n */\n\nimport { useState, useEffect } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { TagBadge } from '@burdenoff/fe-libs/tag';\nimport {\n ArrowLeft,\n Plus,\n Loader2,\n AlertCircle,\n CheckCircle2,\n XCircle,\n RefreshCw,\n Settings,\n Link,\n} from 'lucide-react';\nimport { useChannels } from '../../../hooks/useChannels';\nimport { PermissionGuard } from '../../../components/PermissionGuard';\nimport { CHANNEL_PERMISSIONS } from '../../../constants/permissions';\n\nconst HEALTH_CONFIG: Record<string, { icon: typeof CheckCircle2; color: string; label: string }> = {\n true: { icon: CheckCircle2, color: 'text-success-500', label: 'Healthy' },\n false: { icon: XCircle, color: 'text-error-500', label: 'Unhealthy' },\n};\n\nexport function ConnectionsListPage() {\n const navigate = useNavigate();\n const { channels, isLoading, error, refetch } = useChannels();\n\n // Poll for connection status updates every 60 s.\n // connectionStatusChanged subscription is scoped to a single channelId;\n // this page shows all connections, so polling is used instead.\n useEffect(() => {\n const timer = setInterval(() => {\n void refetch();\n }, 60_000);\n return () => clearInterval(timer);\n }, [refetch]);\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 // Filter state\n const [healthFilter, setHealthFilter] = useState<string>('all');\n const [platformFilter, setPlatformFilter] = useState<string>('all');\n\n // Get all connections from channels\n const connections = channels\n .filter((ch) => ch.connection)\n .map((ch) => ({\n channelId: ch.id,\n channelName: ch.name,\n platform: ch.platform,\n adapterType: ch.adapterType,\n channelStatus: ch.status,\n connectionId: ch.connection!.id,\n isActive: ch.connection!.isActive,\n isHealthy: ch.connection!.isHealthy,\n needsTokenRefresh: ch.connection!.needsTokenRefresh,\n lastTestedAt: ch.connection!.lastTestedAt,\n authType: ch.connection!.authType,\n tagAssignments: ch.connection!.tagAssignments ?? [],\n }));\n\n // Get unique platforms\n const platforms = [...new Set(connections.map((c) => c.platform))];\n\n // Apply filters\n const filteredConnections = connections.filter((conn) => {\n if (healthFilter === 'healthy' && !conn.isHealthy) return false;\n if (healthFilter === 'unhealthy' && conn.isHealthy) return false;\n if (platformFilter !== 'all' && conn.platform !== platformFilter) return false;\n return true;\n });\n\n if (isLoading) {\n return (\n <div className=\"flex items-center justify-center min-h-screen\">\n <Loader2 className=\"w-8 h-8 animate-spin text-muted-foreground\" />\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"flex flex-col items-center justify-center min-h-screen gap-4\">\n <AlertCircle className=\"w-12 h-12 text-destructive\" />\n <h1 className=\"text-xl font-semibold\">\n {tr('channel.loadConnectionsFailed', 'Failed to load connections')}\n </h1>\n <p className=\"text-sm text-muted-foreground\">{error}</p>\n <button\n onClick={() => refetch()}\n className=\"px-4 py-2 rounded-lg bg-primary text-primary-foreground hover:bg-primary/90\"\n >\n {tr('channel.retry', 'Retry')}\n </button>\n </div>\n );\n }\n\n return (\n <PermissionGuard permission={CHANNEL_PERMISSIONS.CHANNEL_CONNECTION_READ}>\n <div className=\"min-h-screen bg-background\">\n {/* Header */}\n <div className=\"border-b bg-card\">\n <div className=\"container mx-auto px-6 py-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <button\n onClick={() => navigate('./list')}\n aria-label={tr('channel.backToChannels', 'Back to channels')}\n className=\"p-2 hover:bg-muted rounded-lg transition-colors\"\n >\n <ArrowLeft className=\"w-5 h-5\" />\n </button>\n <div>\n <h1 className=\"text-2xl font-bold\">{tr('channel.connections', 'Connections')}</h1>\n <p className=\"text-sm text-muted-foreground\">\n {filteredConnections.length} connection\n {filteredConnections.length !== 1 ? 's' : ''}\n </p>\n </div>\n </div>\n <button\n onClick={() => navigate('./create')}\n className=\"px-4 py-2 rounded-lg bg-primary text-primary-foreground hover:bg-primary/90 transition-colors flex items-center gap-2\"\n >\n <Plus className=\"w-4 h-4\" />\n {tr('channel.newChannel', 'New Channel')}\n </button>\n </div>\n </div>\n </div>\n\n {/* Filters */}\n <div className=\"container mx-auto px-6 py-4\">\n <div className=\"flex items-center gap-4\">\n <select\n value={platformFilter}\n onChange={(e) => setPlatformFilter(e.target.value)}\n className=\"px-4 py-2 rounded-lg border bg-background focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n <option value=\"all\">{tr('channel.allPlatforms', 'All Platforms')}</option>\n {platforms.map((p) => (\n <option key={p} value={p}>\n {p}\n </option>\n ))}\n </select>\n\n <select\n value={healthFilter}\n onChange={(e) => setHealthFilter(e.target.value)}\n className=\"px-4 py-2 rounded-lg border bg-background focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n <option value=\"all\">{tr('channel.allStatus', 'All Status')}</option>\n <option value=\"healthy\">{tr('channel.healthy', 'Healthy')}</option>\n <option value=\"unhealthy\">{tr('channel.unhealthy', 'Unhealthy')}</option>\n </select>\n\n <button\n onClick={() => refetch()}\n aria-label={tr('channel.refresh', 'Refresh')}\n className=\"p-2 hover:bg-muted rounded-lg transition-colors\"\n >\n <RefreshCw className=\"w-5 h-5\" aria-hidden=\"true\" />\n </button>\n </div>\n </div>\n\n {/* Connections List */}\n <div className=\"container mx-auto px-6 pb-8\">\n {filteredConnections.length === 0 ? (\n <div className=\"text-center py-12\">\n <Link className=\"w-12 h-12 mx-auto text-muted-foreground mb-4\" />\n <h2 className=\"text-lg font-semibold mb-2\">\n {tr('channel.noConnectionsFound', 'No connections found')}\n </h2>\n <p className=\"text-sm text-muted-foreground mb-4\">\n {channels.length === 0\n ? tr('channel.createChannelFirst', 'Create a channel first to add connections')\n : tr('channel.noConnectionsMatchFilter', 'No connections match your filters')}\n </p>\n {channels.length === 0 ? (\n <button\n onClick={() => navigate('./create')}\n className=\"px-4 py-2 rounded-lg bg-primary text-primary-foreground hover:bg-primary/90\"\n >\n {tr('channel.createChannel', 'Create Channel')}\n </button>\n ) : (\n <button\n onClick={() => {\n setHealthFilter('all');\n setPlatformFilter('all');\n }}\n className=\"px-4 py-2 rounded-lg border hover:bg-muted\"\n >\n {tr('channel.clearFilters', 'Clear Filters')}\n </button>\n )}\n </div>\n ) : (\n <div className=\"border rounded-lg divide-y\">\n {filteredConnections.map((conn) => {\n const health = HEALTH_CONFIG[String(conn.isHealthy)] || HEALTH_CONFIG.false;\n const HealthIcon = health.icon;\n\n return (\n <div\n key={conn.connectionId}\n className=\"p-4 hover:bg-muted/50 transition-colors cursor-pointer\"\n onClick={() => navigate(`./${conn.channelId}`)}\n >\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <div className={health.color} aria-label={health.label}>\n <HealthIcon className=\"w-5 h-5\" aria-hidden=\"true\" />\n </div>\n <div>\n <p className=\"font-medium\">{conn.channelName}</p>\n <p className=\"text-sm text-muted-foreground\">\n {conn.platform} • {conn.adapterType} • {conn.authType}\n </p>\n </div>\n </div>\n\n <div className=\"flex items-center gap-4\">\n <div className=\"text-right\">\n <p className=\"text-sm\">\n {conn.channelStatus === 'ACTIVE' ? (\n <span className=\"text-success-500\">\n {tr('channel.activeStatus', 'Active')}\n </span>\n ) : conn.channelStatus === 'INACTIVE' ? (\n <span className=\"text-muted-foreground\">\n {tr('channel.inactiveStatus', 'Inactive')}\n </span>\n ) : conn.channelStatus === 'ERROR' ? (\n <span className=\"text-error-500\">\n {tr('channel.errorStatus', 'Error')}\n </span>\n ) : conn.channelStatus === 'SUSPENDED' ? (\n <span className=\"text-warning-500\">\n {tr('channel.suspendedStatus', 'Suspended')}\n </span>\n ) : conn.channelStatus === 'ARCHIVED' ? (\n <span className=\"text-muted-foreground\">\n {tr('channel.archivedStatus', 'Archived')}\n </span>\n ) : (\n <span className=\"text-muted-foreground\">\n {tr('channel.inactiveStatus', 'Inactive')}\n </span>\n )}\n </p>\n {conn.lastTestedAt && (\n <p className=\"text-xs text-muted-foreground\">\n Last tested: {new Date(conn.lastTestedAt).toLocaleDateString()}\n </p>\n )}\n </div>\n\n {conn.needsTokenRefresh && (\n <span className=\"px-2 py-1 text-xs bg-warning-500/10 text-warning-500 rounded\">\n Token Expires\n </span>\n )}\n\n {conn.tagAssignments.length > 0 && (\n <div className=\"flex flex-wrap gap-1\" aria-label=\"Connection tags\">\n {conn.tagAssignments.slice(0, 3).map((a) => (\n <TagBadge key={a.id} id={a.tagId} label={a.tagId} size=\"sm\" />\n ))}\n {conn.tagAssignments.length > 3 && (\n <span className=\"text-xs text-muted-foreground\">\n +{conn.tagAssignments.length - 3}\n </span>\n )}\n </div>\n )}\n\n <button\n onClick={(e) => {\n e.stopPropagation();\n navigate(`/channels/${conn.channelId}`);\n }}\n aria-label={tr('channel.viewChannelSettings', 'View channel settings')}\n className=\"p-2 hover:bg-muted rounded-lg transition-colors\"\n >\n <Settings className=\"w-4 h-4\" />\n </button>\n </div>\n </div>\n </div>\n );\n })}\n </div>\n )}\n </div>\n </div>\n </PermissionGuard>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeliveryHistoryPage.d.ts","sourceRoot":"","sources":["../../../../../src/channel/modules/channels/pages/DeliveryHistoryPage.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"DeliveryHistoryPage.d.ts","sourceRoot":"","sources":["../../../../../src/channel/modules/channels/pages/DeliveryHistoryPage.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AA6CH,wBAAgB,mBAAmB,4CAiTlC"}
|
|
@@ -1,360 +1,364 @@
|
|
|
1
1
|
import { useChannel as e } from "../../../providers/ChannelProvider.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { jsx as C, jsxs as w } from "react/jsx-runtime";
|
|
2
|
+
import { useChannel as t } from "../../../hooks/useChannels.js";
|
|
3
|
+
import { PermissionGuard as n } from "../../../components/PermissionGuard.js";
|
|
4
|
+
import { CHANNEL_PERMISSIONS as r } from "../../../constants/permissions.js";
|
|
5
|
+
import { useExportDeliveryAttempts as i } from "../hooks/useExport.js";
|
|
6
|
+
import { useCallback as a, useEffect as o, useState as s } from "react";
|
|
7
|
+
import { useI18n as c } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
8
|
+
import { AlertCircle as l, ArrowLeft as u, CheckCircle2 as d, Clock as f, Download as p, Loader2 as m, RefreshCw as h, RotateCcw as g, Send as _, XCircle as v } from "lucide-react";
|
|
9
|
+
import { useNavigate as y, useParams as b } from "react-router-dom";
|
|
10
|
+
import { jsx as x, jsxs as S } from "react/jsx-runtime";
|
|
12
11
|
//#region src/channel/modules/channels/pages/DeliveryHistoryPage.tsx
|
|
13
|
-
var
|
|
12
|
+
var C = {
|
|
14
13
|
PENDING: {
|
|
15
14
|
label: "Pending",
|
|
16
15
|
color: "text-muted-foreground bg-muted",
|
|
17
|
-
icon:
|
|
16
|
+
icon: f
|
|
18
17
|
},
|
|
19
18
|
QUEUED: {
|
|
20
19
|
label: "Queued",
|
|
21
20
|
color: "text-info-500 bg-info-100",
|
|
22
|
-
icon:
|
|
21
|
+
icon: f
|
|
23
22
|
},
|
|
24
23
|
SENDING: {
|
|
25
24
|
label: "Sending",
|
|
26
25
|
color: "text-accent-primary bg-accent-primary/10",
|
|
27
|
-
icon:
|
|
26
|
+
icon: _
|
|
28
27
|
},
|
|
29
28
|
SENT: {
|
|
30
29
|
label: "Sent",
|
|
31
30
|
color: "text-success-500 bg-success-100",
|
|
32
|
-
icon:
|
|
31
|
+
icon: d
|
|
33
32
|
},
|
|
34
33
|
DELIVERED: {
|
|
35
34
|
label: "Delivered",
|
|
36
35
|
color: "text-success-500 bg-success-100",
|
|
37
|
-
icon:
|
|
36
|
+
icon: d
|
|
38
37
|
},
|
|
39
38
|
FAILED: {
|
|
40
39
|
label: "Failed",
|
|
41
40
|
color: "text-error-500 bg-error-100",
|
|
42
|
-
icon:
|
|
41
|
+
icon: v
|
|
43
42
|
},
|
|
44
43
|
BOUNCED: {
|
|
45
44
|
label: "Bounced",
|
|
46
45
|
color: "text-warning-500 bg-warning-100",
|
|
47
|
-
icon:
|
|
46
|
+
icon: l
|
|
48
47
|
},
|
|
49
48
|
REJECTED: {
|
|
50
49
|
label: "Rejected",
|
|
51
50
|
color: "text-error-500 bg-error-100",
|
|
52
|
-
icon:
|
|
51
|
+
icon: v
|
|
53
52
|
},
|
|
54
53
|
RATE_LIMITED: {
|
|
55
54
|
label: "Rate Limited",
|
|
56
55
|
color: "text-warning-500 bg-warning-100",
|
|
57
|
-
icon:
|
|
56
|
+
icon: f
|
|
58
57
|
},
|
|
59
58
|
RETRYING: {
|
|
60
59
|
label: "Retrying",
|
|
61
60
|
color: "text-accent-primary bg-accent-primary/10",
|
|
62
|
-
icon:
|
|
61
|
+
icon: h
|
|
63
62
|
},
|
|
64
63
|
OPENED: {
|
|
65
64
|
label: "Opened",
|
|
66
65
|
color: "text-success-500 bg-success-100",
|
|
67
|
-
icon:
|
|
66
|
+
icon: d
|
|
68
67
|
},
|
|
69
68
|
CLICKED: {
|
|
70
69
|
label: "Clicked",
|
|
71
70
|
color: "text-success-500 bg-success-100",
|
|
72
|
-
icon:
|
|
71
|
+
icon: d
|
|
73
72
|
}
|
|
74
73
|
};
|
|
75
|
-
function
|
|
76
|
-
let { channelId:
|
|
77
|
-
let n =
|
|
74
|
+
function w() {
|
|
75
|
+
let { channelId: d } = b(), f = y(), { t: v } = c(), w = (e, t) => {
|
|
76
|
+
let n = v(e);
|
|
78
77
|
return n === e ? t : n;
|
|
79
|
-
}, { organizationId:
|
|
80
|
-
if (
|
|
81
|
-
|
|
78
|
+
}, { organizationId: T } = e(), { triggerExport: E, isExporting: D, exportError: O } = i(T ?? void 0, d), [k, A] = s(!0), [j, M] = s([]), [N, P] = s(null), [F, I] = s(null), [L, R] = s(25), { channel: z, isLoading: B, error: V, fetchDeliveryAttempts: H, retryDelivery: U } = t(d), W = a(async () => {
|
|
79
|
+
if (d) {
|
|
80
|
+
A(!0), I(null);
|
|
82
81
|
try {
|
|
83
|
-
|
|
82
|
+
M(await H(L));
|
|
84
83
|
} finally {
|
|
85
|
-
|
|
84
|
+
A(!1);
|
|
86
85
|
}
|
|
87
86
|
}
|
|
88
87
|
}, [
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
88
|
+
d,
|
|
89
|
+
H,
|
|
90
|
+
L
|
|
92
91
|
]);
|
|
93
|
-
|
|
94
|
-
Promise.resolve().then(() =>
|
|
95
|
-
}, [
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
let q = async (e) => {
|
|
105
|
-
I(e), R(null);
|
|
92
|
+
o(() => {
|
|
93
|
+
Promise.resolve().then(() => W());
|
|
94
|
+
}, [W]), o(() => {
|
|
95
|
+
if (!d) return;
|
|
96
|
+
let e = setInterval(() => {
|
|
97
|
+
W();
|
|
98
|
+
}, 6e4);
|
|
99
|
+
return () => clearInterval(e);
|
|
100
|
+
}, [d, W]);
|
|
101
|
+
let G = async (e) => {
|
|
102
|
+
P(e), I(null);
|
|
106
103
|
try {
|
|
107
|
-
let t = await
|
|
108
|
-
t.success ||
|
|
104
|
+
let t = await U(e);
|
|
105
|
+
t.success || I(t.error || "Retry failed");
|
|
109
106
|
} finally {
|
|
110
|
-
|
|
107
|
+
P(null);
|
|
111
108
|
}
|
|
112
|
-
},
|
|
113
|
-
return
|
|
109
|
+
}, K = (e) => C[e] || C.PENDING;
|
|
110
|
+
return B ? /* @__PURE__ */ x("div", {
|
|
114
111
|
className: "flex items-center justify-center min-h-screen",
|
|
115
|
-
|
|
112
|
+
role: "status",
|
|
113
|
+
"aria-label": w("channel.loading", "Loading"),
|
|
114
|
+
children: /* @__PURE__ */ x(m, {
|
|
116
115
|
size: 32,
|
|
117
|
-
className: "animate-spin text-accent-primary"
|
|
116
|
+
className: "animate-spin text-accent-primary",
|
|
117
|
+
"aria-hidden": "true"
|
|
118
118
|
})
|
|
119
|
-
}) :
|
|
119
|
+
}) : V || !z ? /* @__PURE__ */ x("div", {
|
|
120
120
|
className: "p-6",
|
|
121
|
-
children: /* @__PURE__ */
|
|
121
|
+
children: /* @__PURE__ */ S("div", {
|
|
122
122
|
className: "flex items-center gap-3 p-4 bg-error-100 border border-error-500 rounded-lg",
|
|
123
123
|
children: [
|
|
124
|
-
/* @__PURE__ */
|
|
124
|
+
/* @__PURE__ */ x(l, {
|
|
125
125
|
size: 20,
|
|
126
126
|
className: "text-error-500"
|
|
127
127
|
}),
|
|
128
|
-
/* @__PURE__ */
|
|
128
|
+
/* @__PURE__ */ x("div", { children: /* @__PURE__ */ x("p", {
|
|
129
129
|
className: "text-sm font-medium text-error-700",
|
|
130
|
-
children:
|
|
130
|
+
children: V || "Channel not found"
|
|
131
131
|
}) }),
|
|
132
|
-
/* @__PURE__ */
|
|
133
|
-
onClick: () =>
|
|
132
|
+
/* @__PURE__ */ x("button", {
|
|
133
|
+
onClick: () => f(`/channels/${d}`),
|
|
134
134
|
className: "ml-auto px-3 py-1 text-sm text-error-700 hover:bg-error-200 rounded transition-colors",
|
|
135
135
|
children: "Go Back"
|
|
136
136
|
})
|
|
137
137
|
]
|
|
138
138
|
})
|
|
139
|
-
}) : /* @__PURE__ */
|
|
140
|
-
permission:
|
|
141
|
-
children: /* @__PURE__ */
|
|
139
|
+
}) : /* @__PURE__ */ x(n, {
|
|
140
|
+
permission: r.CHANNEL_DELIVERY_READ,
|
|
141
|
+
children: /* @__PURE__ */ S("div", {
|
|
142
142
|
className: "space-y-6 p-3 sm:p-6",
|
|
143
143
|
children: [
|
|
144
|
-
/* @__PURE__ */
|
|
144
|
+
/* @__PURE__ */ S("div", {
|
|
145
145
|
className: "flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between",
|
|
146
|
-
children: [/* @__PURE__ */
|
|
146
|
+
children: [/* @__PURE__ */ S("div", {
|
|
147
147
|
className: "flex items-center gap-3",
|
|
148
|
-
children: [/* @__PURE__ */
|
|
149
|
-
onClick: () =>
|
|
148
|
+
children: [/* @__PURE__ */ x("button", {
|
|
149
|
+
onClick: () => f(`/channels/${d}`),
|
|
150
|
+
"aria-label": w("channel.backToChannel", "Back to channel"),
|
|
150
151
|
className: "p-2 text-muted-foreground hover:text-foreground hover:bg-muted rounded-lg transition-colors",
|
|
151
|
-
children: /* @__PURE__ */
|
|
152
|
-
|
|
152
|
+
children: /* @__PURE__ */ x(u, {
|
|
153
|
+
size: 20,
|
|
154
|
+
"aria-hidden": "true"
|
|
155
|
+
})
|
|
156
|
+
}), /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("h1", {
|
|
153
157
|
className: "text-xl sm:text-2xl font-bold text-foreground",
|
|
154
|
-
children:
|
|
155
|
-
}), /* @__PURE__ */
|
|
158
|
+
children: w("channel.deliveryHistory", "Delivery History")
|
|
159
|
+
}), /* @__PURE__ */ S("p", {
|
|
156
160
|
className: "text-sm text-muted-foreground mt-1",
|
|
157
|
-
children: [
|
|
161
|
+
children: [z.name, " - Message deliveries"]
|
|
158
162
|
})] })]
|
|
159
|
-
}), /* @__PURE__ */
|
|
163
|
+
}), /* @__PURE__ */ S("div", {
|
|
160
164
|
className: "flex items-center gap-3",
|
|
161
165
|
children: [
|
|
162
|
-
/* @__PURE__ */
|
|
163
|
-
value:
|
|
164
|
-
onChange: (e) =>
|
|
166
|
+
/* @__PURE__ */ S("select", {
|
|
167
|
+
value: L,
|
|
168
|
+
onChange: (e) => R(Number(e.target.value)),
|
|
165
169
|
className: "px-3 py-2 text-sm bg-surface border border-border rounded-lg focus:outline-none focus:ring-2 focus:ring-action-primary-bg/50 text-foreground",
|
|
166
170
|
children: [
|
|
167
|
-
/* @__PURE__ */
|
|
171
|
+
/* @__PURE__ */ x("option", {
|
|
168
172
|
value: 10,
|
|
169
173
|
children: "10 results"
|
|
170
174
|
}),
|
|
171
|
-
/* @__PURE__ */
|
|
175
|
+
/* @__PURE__ */ x("option", {
|
|
172
176
|
value: 25,
|
|
173
177
|
children: "25 results"
|
|
174
178
|
}),
|
|
175
|
-
/* @__PURE__ */
|
|
179
|
+
/* @__PURE__ */ x("option", {
|
|
176
180
|
value: 50,
|
|
177
181
|
children: "50 results"
|
|
178
182
|
}),
|
|
179
|
-
/* @__PURE__ */
|
|
183
|
+
/* @__PURE__ */ x("option", {
|
|
180
184
|
value: 100,
|
|
181
185
|
children: "100 results"
|
|
182
186
|
})
|
|
183
187
|
]
|
|
184
188
|
}),
|
|
185
|
-
/* @__PURE__ */
|
|
186
|
-
onClick:
|
|
187
|
-
disabled:
|
|
189
|
+
/* @__PURE__ */ S("button", {
|
|
190
|
+
onClick: W,
|
|
191
|
+
disabled: k,
|
|
188
192
|
className: "flex items-center gap-2 px-4 py-2 text-sm font-medium text-muted-foreground hover:text-foreground hover:bg-muted rounded-lg transition-colors disabled:opacity-50",
|
|
189
|
-
children: [/* @__PURE__ */
|
|
193
|
+
children: [/* @__PURE__ */ x(h, {
|
|
190
194
|
size: 16,
|
|
191
|
-
className:
|
|
192
|
-
}),
|
|
195
|
+
className: k ? "animate-spin" : ""
|
|
196
|
+
}), w("channel.refresh", "Refresh")]
|
|
193
197
|
}),
|
|
194
|
-
/* @__PURE__ */
|
|
195
|
-
permission:
|
|
196
|
-
children: /* @__PURE__ */
|
|
197
|
-
onClick: () => void
|
|
198
|
-
disabled:
|
|
198
|
+
/* @__PURE__ */ x(n, {
|
|
199
|
+
permission: r.CHANNEL_ADMIN,
|
|
200
|
+
children: /* @__PURE__ */ S("button", {
|
|
201
|
+
onClick: () => void E(),
|
|
202
|
+
disabled: D,
|
|
199
203
|
className: "flex items-center gap-2 px-4 py-2 text-sm font-medium text-fg border border-border hover:bg-bg-elevated rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed",
|
|
200
|
-
title:
|
|
201
|
-
children: [
|
|
204
|
+
title: w("channel.exportCSV", "Export to CSV"),
|
|
205
|
+
children: [D ? /* @__PURE__ */ x(m, {
|
|
202
206
|
size: 16,
|
|
203
207
|
className: "animate-spin"
|
|
204
|
-
}) : /* @__PURE__ */
|
|
208
|
+
}) : /* @__PURE__ */ x(p, { size: 16 }), w("channel.export", "Export")]
|
|
205
209
|
})
|
|
206
210
|
})
|
|
207
211
|
]
|
|
208
212
|
})]
|
|
209
213
|
}),
|
|
210
|
-
|
|
214
|
+
O && /* @__PURE__ */ S("div", {
|
|
211
215
|
className: "p-4 bg-error-100 border border-error-500 rounded-lg flex items-center gap-3",
|
|
212
|
-
children: [/* @__PURE__ */
|
|
216
|
+
children: [/* @__PURE__ */ x(l, {
|
|
213
217
|
size: 20,
|
|
214
218
|
className: "text-error-500"
|
|
215
|
-
}), /* @__PURE__ */
|
|
219
|
+
}), /* @__PURE__ */ x("p", {
|
|
216
220
|
className: "text-sm text-error-700 flex-1",
|
|
217
|
-
children:
|
|
221
|
+
children: O
|
|
218
222
|
})]
|
|
219
223
|
}),
|
|
220
|
-
|
|
224
|
+
F && /* @__PURE__ */ S("div", {
|
|
221
225
|
className: "p-4 bg-error-100 border border-error-500 rounded-lg flex items-center gap-3",
|
|
222
226
|
children: [
|
|
223
|
-
/* @__PURE__ */
|
|
227
|
+
/* @__PURE__ */ x(l, {
|
|
224
228
|
size: 20,
|
|
225
229
|
className: "text-error-500"
|
|
226
230
|
}),
|
|
227
|
-
/* @__PURE__ */
|
|
231
|
+
/* @__PURE__ */ x("p", {
|
|
228
232
|
className: "text-sm text-error-700 flex-1",
|
|
229
|
-
children:
|
|
233
|
+
children: F
|
|
230
234
|
}),
|
|
231
|
-
/* @__PURE__ */
|
|
232
|
-
onClick: () =>
|
|
235
|
+
/* @__PURE__ */ x("button", {
|
|
236
|
+
onClick: () => I(null),
|
|
233
237
|
className: "text-error-500 hover:text-error-700",
|
|
234
|
-
children:
|
|
238
|
+
children: w("channel.dismiss", "Dismiss")
|
|
235
239
|
})
|
|
236
240
|
]
|
|
237
241
|
}),
|
|
238
|
-
/* @__PURE__ */
|
|
242
|
+
/* @__PURE__ */ x("div", {
|
|
239
243
|
className: "p-4 bg-surface border border-border rounded-lg",
|
|
240
|
-
children: /* @__PURE__ */
|
|
244
|
+
children: /* @__PURE__ */ x("p", {
|
|
241
245
|
className: "text-sm text-muted-foreground",
|
|
242
246
|
children: "Delivery history shows all message attempts sent through this channel. Data is retained for 7 days. Click retry on a failed delivery to attempt sending again."
|
|
243
247
|
})
|
|
244
248
|
}),
|
|
245
|
-
/* @__PURE__ */
|
|
249
|
+
/* @__PURE__ */ x("div", {
|
|
246
250
|
className: "bg-surface border border-border rounded-lg overflow-hidden",
|
|
247
|
-
children: /* @__PURE__ */
|
|
251
|
+
children: /* @__PURE__ */ x("div", {
|
|
248
252
|
className: "overflow-x-auto min-w-full",
|
|
249
|
-
children: /* @__PURE__ */
|
|
253
|
+
children: /* @__PURE__ */ S("table", {
|
|
250
254
|
className: "w-full min-w-[700px]",
|
|
251
|
-
children: [/* @__PURE__ */
|
|
255
|
+
children: [/* @__PURE__ */ x("thead", {
|
|
252
256
|
className: "bg-muted/50 border-b border-border",
|
|
253
|
-
children: /* @__PURE__ */
|
|
254
|
-
/* @__PURE__ */
|
|
257
|
+
children: /* @__PURE__ */ S("tr", { children: [
|
|
258
|
+
/* @__PURE__ */ x("th", {
|
|
255
259
|
className: "px-4 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider",
|
|
256
|
-
children:
|
|
260
|
+
children: w("channel.status", "Status")
|
|
257
261
|
}),
|
|
258
|
-
/* @__PURE__ */
|
|
262
|
+
/* @__PURE__ */ x("th", {
|
|
259
263
|
className: "px-4 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider",
|
|
260
|
-
children:
|
|
264
|
+
children: w("channel.content", "Content")
|
|
261
265
|
}),
|
|
262
|
-
/* @__PURE__ */
|
|
266
|
+
/* @__PURE__ */ x("th", {
|
|
263
267
|
className: "px-4 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider",
|
|
264
|
-
children:
|
|
268
|
+
children: w("channel.sentAt", "Sent At")
|
|
265
269
|
}),
|
|
266
|
-
/* @__PURE__ */
|
|
270
|
+
/* @__PURE__ */ x("th", {
|
|
267
271
|
className: "px-4 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider",
|
|
268
|
-
children:
|
|
272
|
+
children: w("channel.retries", "Retries")
|
|
269
273
|
}),
|
|
270
|
-
/* @__PURE__ */
|
|
274
|
+
/* @__PURE__ */ x("th", {
|
|
271
275
|
className: "px-4 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider",
|
|
272
|
-
children:
|
|
276
|
+
children: w("channel.error", "Error")
|
|
273
277
|
}),
|
|
274
|
-
/* @__PURE__ */
|
|
278
|
+
/* @__PURE__ */ x("th", {
|
|
275
279
|
className: "px-4 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider",
|
|
276
|
-
children:
|
|
280
|
+
children: w("channel.actions", "Actions")
|
|
277
281
|
})
|
|
278
282
|
] })
|
|
279
|
-
}), /* @__PURE__ */
|
|
283
|
+
}), /* @__PURE__ */ x("tbody", {
|
|
280
284
|
className: "divide-y divide-border",
|
|
281
|
-
children:
|
|
285
|
+
children: k ? /* @__PURE__ */ x("tr", { children: /* @__PURE__ */ S("td", {
|
|
282
286
|
colSpan: 6,
|
|
283
287
|
className: "px-4 py-12 text-center",
|
|
284
|
-
children: [/* @__PURE__ */
|
|
288
|
+
children: [/* @__PURE__ */ x(m, {
|
|
285
289
|
size: 24,
|
|
286
290
|
className: "animate-spin text-accent-primary mx-auto"
|
|
287
|
-
}), /* @__PURE__ */
|
|
291
|
+
}), /* @__PURE__ */ x("p", {
|
|
288
292
|
className: "text-sm text-muted-foreground mt-2",
|
|
289
293
|
children: "Loading delivery attempts..."
|
|
290
294
|
})]
|
|
291
|
-
}) }) :
|
|
295
|
+
}) }) : j.length === 0 ? /* @__PURE__ */ x("tr", { children: /* @__PURE__ */ x("td", {
|
|
292
296
|
colSpan: 6,
|
|
293
297
|
className: "px-4 py-12 text-center",
|
|
294
|
-
children: /* @__PURE__ */
|
|
298
|
+
children: /* @__PURE__ */ S("div", {
|
|
295
299
|
className: "flex flex-col items-center gap-2",
|
|
296
300
|
children: [
|
|
297
|
-
/* @__PURE__ */
|
|
301
|
+
/* @__PURE__ */ x(_, {
|
|
298
302
|
size: 32,
|
|
299
303
|
className: "text-muted-foreground"
|
|
300
304
|
}),
|
|
301
|
-
/* @__PURE__ */
|
|
305
|
+
/* @__PURE__ */ x("p", {
|
|
302
306
|
className: "text-sm font-medium text-foreground",
|
|
303
|
-
children:
|
|
307
|
+
children: w("channel.noDeliveryAttempts", "No delivery attempts yet")
|
|
304
308
|
}),
|
|
305
|
-
/* @__PURE__ */
|
|
309
|
+
/* @__PURE__ */ x("p", {
|
|
306
310
|
className: "text-xs text-muted-foreground",
|
|
307
|
-
children:
|
|
311
|
+
children: w("channel.sendMessageToSeeHistory", "Send a message through this channel to see delivery history")
|
|
308
312
|
})
|
|
309
313
|
]
|
|
310
314
|
})
|
|
311
|
-
}) }) :
|
|
312
|
-
let t =
|
|
313
|
-
return /* @__PURE__ */
|
|
315
|
+
}) }) : j.map((e) => {
|
|
316
|
+
let t = K(e.status), i = t.icon, a = e.status === "FAILED" || e.status === "BOUNCED" || e.status === "REJECTED";
|
|
317
|
+
return /* @__PURE__ */ S("tr", {
|
|
314
318
|
className: "hover:bg-muted/30 transition-colors",
|
|
315
319
|
children: [
|
|
316
|
-
/* @__PURE__ */
|
|
320
|
+
/* @__PURE__ */ x("td", {
|
|
317
321
|
className: "px-4 py-3",
|
|
318
|
-
children: /* @__PURE__ */
|
|
322
|
+
children: /* @__PURE__ */ S("div", {
|
|
319
323
|
className: "flex items-center gap-2",
|
|
320
|
-
children: [/* @__PURE__ */
|
|
324
|
+
children: [/* @__PURE__ */ x(i, {
|
|
321
325
|
size: 14,
|
|
322
326
|
className: t.color.split(" ")[0]
|
|
323
|
-
}), /* @__PURE__ */
|
|
327
|
+
}), /* @__PURE__ */ x("span", {
|
|
324
328
|
className: `text-sm font-medium ${t.color}`,
|
|
325
329
|
children: t.label
|
|
326
330
|
})]
|
|
327
331
|
})
|
|
328
332
|
}),
|
|
329
|
-
/* @__PURE__ */
|
|
333
|
+
/* @__PURE__ */ x("td", {
|
|
330
334
|
className: "px-4 py-3 text-sm text-foreground truncate max-w-xs",
|
|
331
335
|
children: e.content
|
|
332
336
|
}),
|
|
333
|
-
/* @__PURE__ */
|
|
337
|
+
/* @__PURE__ */ x("td", {
|
|
334
338
|
className: "px-4 py-3 text-sm text-muted-foreground",
|
|
335
339
|
children: e.sentAt ? new Date(e.sentAt).toLocaleString() : "-"
|
|
336
340
|
}),
|
|
337
|
-
/* @__PURE__ */
|
|
341
|
+
/* @__PURE__ */ x("td", {
|
|
338
342
|
className: "px-4 py-3 text-sm text-muted-foreground",
|
|
339
343
|
children: e.retryCount
|
|
340
344
|
}),
|
|
341
|
-
/* @__PURE__ */
|
|
345
|
+
/* @__PURE__ */ x("td", {
|
|
342
346
|
className: "px-4 py-3 text-sm text-error-500 max-w-xs truncate",
|
|
343
347
|
children: e.errorMessage || "-"
|
|
344
348
|
}),
|
|
345
|
-
/* @__PURE__ */
|
|
349
|
+
/* @__PURE__ */ x("td", {
|
|
346
350
|
className: "px-4 py-3",
|
|
347
|
-
children:
|
|
348
|
-
permission:
|
|
349
|
-
children: /* @__PURE__ */
|
|
350
|
-
onClick: () =>
|
|
351
|
-
disabled:
|
|
351
|
+
children: a && /* @__PURE__ */ x(n, {
|
|
352
|
+
permission: r.CHANNEL_DELIVERY_EXECUTE,
|
|
353
|
+
children: /* @__PURE__ */ S("button", {
|
|
354
|
+
onClick: () => G(e.id),
|
|
355
|
+
disabled: N === e.id,
|
|
352
356
|
className: "flex items-center gap-1 px-2 py-1 text-xs font-medium text-accent-primary hover:bg-accent-primary/10 rounded transition-colors disabled:opacity-50",
|
|
353
|
-
title:
|
|
354
|
-
children: [/* @__PURE__ */
|
|
357
|
+
title: w("channel.retryDelivery", "Retry this delivery"),
|
|
358
|
+
children: [/* @__PURE__ */ x(g, {
|
|
355
359
|
size: 12,
|
|
356
|
-
className:
|
|
357
|
-
}),
|
|
360
|
+
className: N === e.id ? "animate-spin" : ""
|
|
361
|
+
}), N === e.id ? w("channel.retrying", "Retrying...") : w("channel.retry", "Retry")]
|
|
358
362
|
})
|
|
359
363
|
})
|
|
360
364
|
})
|
|
@@ -370,6 +374,6 @@ function E() {
|
|
|
370
374
|
});
|
|
371
375
|
}
|
|
372
376
|
//#endregion
|
|
373
|
-
export {
|
|
377
|
+
export { w as DeliveryHistoryPage };
|
|
374
378
|
|
|
375
379
|
//# sourceMappingURL=DeliveryHistoryPage.js.map
|