@burdenoff/microfe-bigconsole 2026.805.1 → 2026.805.2
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/bigconsole/AdminRoot.js +21 -16
- package/dist/bigconsole/AdminRoot.js.map +1 -1
- package/dist/bigconsole/BigConsoleRoot.js +44 -39
- package/dist/bigconsole/BigConsoleRoot.js.map +1 -1
- package/dist/bigconsole/components/dashboard/DashboardToolbar.js +115 -100
- package/dist/bigconsole/components/dashboard/DashboardToolbar.js.map +1 -1
- package/dist/bigconsole/components/dashboard/PageTabsManager/PageTabsManager.js +100 -98
- package/dist/bigconsole/components/dashboard/PageTabsManager/PageTabsManager.js.map +1 -1
- package/dist/bigconsole/components/dashboard/ShareDialog/EmbedTab.js +164 -161
- package/dist/bigconsole/components/dashboard/ShareDialog/EmbedTab.js.map +1 -1
- package/dist/bigconsole/components/datasink/DataSinkCard.js +20 -20
- package/dist/bigconsole/components/datasink/DataSinkCard.js.map +1 -1
- package/dist/bigconsole/components/widgets/ActionConfigDialog.js +96 -90
- package/dist/bigconsole/components/widgets/ActionConfigDialog.js.map +1 -1
- package/dist/bigconsole/components/widgets/WidgetMenu.js +87 -76
- package/dist/bigconsole/components/widgets/WidgetMenu.js.map +1 -1
- package/dist/bigconsole/components/widgets/widget-actions/WidgetActions.js +120 -118
- package/dist/bigconsole/components/widgets/widget-actions/WidgetActions.js.map +1 -1
- package/dist/bigconsole/pages/DashboardBuilderPage.js +113 -104
- package/dist/bigconsole/pages/DashboardBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/DashboardViewPage.js +208 -199
- package/dist/bigconsole/pages/DashboardViewPage.js.map +1 -1
- package/dist/bigconsole/pages/DashboardsPage.js +376 -325
- package/dist/bigconsole/pages/DashboardsPage.js.map +1 -1
- package/dist/bigconsole/pages/DataParsersPage.js +135 -125
- package/dist/bigconsole/pages/DataParsersPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSinkBuilderPage.js +182 -172
- package/dist/bigconsole/pages/DataSinkBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSinkViewPage.js +237 -219
- package/dist/bigconsole/pages/DataSinkViewPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSinksPage.js +281 -268
- package/dist/bigconsole/pages/DataSinksPage.js.map +1 -1
- package/dist/bigconsole/pages/ParserBuilderPage.js +238 -223
- package/dist/bigconsole/pages/ParserBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/ParserViewPage.js +162 -144
- package/dist/bigconsole/pages/ParserViewPage.js.map +1 -1
- package/dist/bigconsole/pages/PipelineBuilderPage.js +212 -204
- package/dist/bigconsole/pages/PipelineBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/PipelineViewPage.js +191 -183
- package/dist/bigconsole/pages/PipelineViewPage.js.map +1 -1
- package/dist/bigconsole/pages/PipelinesPage.js +128 -103
- package/dist/bigconsole/pages/PipelinesPage.js.map +1 -1
- package/dist/bigconsole/pages/WorkflowViewPage.js +238 -217
- package/dist/bigconsole/pages/WorkflowViewPage.js.map +1 -1
- package/dist/bigconsole/pages/WorkflowsPage.js +116 -102
- package/dist/bigconsole/pages/WorkflowsPage.js.map +1 -1
- package/dist/constants/permissions.js +83 -0
- package/dist/constants/permissions.js.map +1 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkflowsPage.js","names":[],"sources":["../../../src/bigconsole/pages/WorkflowsPage.tsx"],"sourcesContent":["/**\n * Workflows Page\n *\n * List and manage FluidGrids Workflows.\n * Uses fe-libs shared UI components and semantic tokens for consistent styling.\n */\n\nimport { memo, useState, useMemo, useCallback } from 'react';\nimport { useAppNavigate } from '../contexts';\nimport { isNative, nativeNotify } from '../../utils/nativeBridge';\nimport { newWorkflowPath } from '../BigConsoleRoutes';\nimport { useWorkflowOperations } from '../hooks/useWorkflowOperations';\nimport { useWorkflowStore } from '../store/workflowStore';\nimport { WorkflowCard } from '../components/workflow/WorkflowCard';\nimport { WorkflowDeleteDialog } from '../components/workflow/WorkflowDeleteDialog';\nimport type { FluidGridsWorkflowStatus } from '../types';\n\n// fe-libs UI components\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Input } from '@burdenoff/fe-libs/ui';\nimport { Card, CardContent } from '@burdenoff/fe-libs/ui';\nimport { Spinner } from '@burdenoff/fe-libs/ui';\nimport { AuroraBackground, GradientText, GlassCard, IllustratedEmptyState, PagePurpose } from '@burdenoff/fe-libs/ui';\n\n// Lucide icons\nimport { Plus, Search, Workflow, AlertCircle } from 'lucide-react';\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\ntype StatusFilter = 'all' | FluidGridsWorkflowStatus;\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\nexport const WorkflowsPage = memo(function WorkflowsPage() {\n const navigate = useAppNavigate();\n\n // Local state\n const [statusFilter, setStatusFilter] = useState<StatusFilter>('all');\n\n // Store state\n const searchQuery = useWorkflowStore((state) => state.searchQuery);\n const setSearchQuery = useWorkflowStore((state) => state.setSearchQuery);\n const deleteDialogOpen = useWorkflowStore((state) => state.deleteDialogOpen);\n const currentWorkflow = useWorkflowStore((state) => state.currentWorkflow);\n const openDeleteDialog = useWorkflowStore((state) => state.openDeleteDialog);\n const closeDeleteDialog = useWorkflowStore((state) => state.closeDeleteDialog);\n\n // Operations\n const { loading, error, workflows, deleteWorkflow, refetch } = useWorkflowOperations();\n\n // Filter workflows\n const filteredWorkflows = useMemo(() => {\n let filtered = [...workflows];\n\n // Apply status filter\n if (statusFilter !== 'all') {\n filtered = filtered.filter((wf) => wf.status === statusFilter);\n }\n\n // Apply search filter\n if (searchQuery.trim()) {\n const query = searchQuery.toLowerCase();\n filtered = filtered.filter(\n (wf) =>\n wf.name.toLowerCase().includes(query) ||\n wf.key.toLowerCase().includes(query) ||\n wf.description?.toLowerCase().includes(query)\n );\n }\n\n // Sort by updatedAt descending\n return filtered.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());\n }, [workflows, statusFilter, searchQuery]);\n\n // Handlers\n const handleCreateWorkflow = useCallback(() => {\n navigate(newWorkflowPath());\n }, [navigate]);\n\n const handleViewWorkflow = useCallback(\n (id: string) => {\n navigate(`/workflows/${id}`);\n },\n [navigate]\n );\n\n const handleEditWorkflow = useCallback(\n (id: string) => {\n navigate(`/workflows/${id}/edit`);\n },\n [navigate]\n );\n\n const handleDeleteClick = useCallback(\n (id: string) => {\n const workflow = workflows.find((wf) => wf.id === id);\n if (workflow) {\n openDeleteDialog(workflow);\n }\n },\n [workflows, openDeleteDialog]\n );\n\n const handleDeleteConfirm = useCallback(async () => {\n if (currentWorkflow) {\n try {\n await deleteWorkflow(currentWorkflow.id);\n if (isNative()) void nativeNotify('success');\n } catch (err) {\n if (isNative()) void nativeNotify('error');\n throw err;\n }\n closeDeleteDialog();\n }\n }, [currentWorkflow, deleteWorkflow, closeDeleteDialog]);\n\n // Status filter options\n const statusOptions: { value: StatusFilter; label: string }[] = [\n { value: 'all', label: 'All' },\n { value: 'draft', label: 'Draft' },\n { value: 'active', label: 'Active' },\n { value: 'paused', label: 'Paused' },\n { value: 'error', label: 'Error' },\n { value: 'archived', label: 'Archived' },\n ];\n\n // Error state\n if (error) {\n return (\n <div style={{ padding: 'var(--space-pagePadding)' }}>\n <Card\n style={{\n borderColor: 'var(--color-status-error-border)',\n backgroundColor: 'var(--color-status-error-bgSubtle)',\n }}\n >\n <CardContent style={{ padding: 'var(--space-pagePadding)' }}>\n <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', textAlign: 'center' }}>\n <div\n style={{\n padding: 'var(--space-controlGap)',\n borderRadius: '50%',\n backgroundColor: 'var(--color-status-error-bgSubtle)',\n marginBottom: 'var(--space-formGap)',\n }}\n >\n <AlertCircle\n style={{\n height: 'var(--size-icon-xl)',\n width: 'var(--size-icon-xl)',\n color: 'var(--color-status-error-text)',\n }}\n />\n </div>\n <h3\n style={{\n fontSize: 'var(--font-size-body-lg)',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-status-error-text)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n Failed to load Workflows\n </h3>\n <p\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-secondary)',\n marginBottom: 'var(--space-formGap)',\n }}\n >\n {error.message}\n </p>\n <Button size=\"sm\" onClick={() => refetch()}>\n Try Again\n </Button>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n }\n\n return (\n <div style={{ minHeight: '100vh', backgroundColor: 'var(--color-bg-canvas)' }}>\n {/* Header Section */}\n <div className=\"relative overflow-hidden border-b border-border-seam bg-gloss-card\">\n <AuroraBackground intensity=\"subtle\" />\n <div style={{ padding: 'var(--space-pagePadding)' }}>\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-formGap)' }}>\n <div\n style={{\n display: 'flex',\n height: 'var(--size-controlHeight-lg)',\n width: 'var(--size-controlHeight-lg)',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: 'var(--radius-card)',\n backgroundColor: 'var(--color-action-primary-bg)',\n }}\n >\n <Workflow\n style={{\n height: 'var(--size-icon-lg)',\n width: 'var(--size-icon-lg)',\n color: 'var(--color-action-primary-text)',\n }}\n />\n </div>\n <div>\n <h1\n style={{\n fontSize: 'var(--font-size-heading-h4)',\n fontWeight: 'var(--font-weight-bold)',\n margin: 0,\n color: 'var(--color-text-primary)',\n }}\n >\n <GradientText>Workflows</GradientText>\n </h1>\n <p style={{ fontSize: 'var(--font-size-body-sm)', color: 'var(--color-text-secondary)', margin: 0 }}>\n Design ETL workflows with FluidGrids and link them to DataSinks\n </p>\n </div>\n </div>\n\n <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-controlGap)' }}>\n <Button onClick={handleCreateWorkflow}>\n <Plus\n style={{\n marginRight: 'var(--space-iconGap)',\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n }}\n />\n Design Workflow\n </Button>\n </div>\n </div>\n </div>\n </div>\n\n {/* Main Content */}\n <div style={{ padding: 'var(--space-pagePadding)' }}>\n <PagePurpose className=\"mb-[var(--space-sectionGap)]\">\n Workflows are visual ETL jobs built with the FluidGrids builder — they fetch data from external systems,\n transform it, and load it into your BigConsole DataSinks on a schedule or on demand. Use them to keep\n dashboards fed with fresh, shaped data without writing glue code.\n </PagePurpose>\n\n {/* Status Filter Tabs */}\n <div style={{ marginBottom: 'var(--space-formGap)' }}>\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '2px',\n padding: '4px',\n backgroundColor: 'var(--color-bg-sunken)',\n borderRadius: 'var(--radius-card)',\n width: 'fit-content',\n }}\n >\n {statusOptions.map((option) => (\n <button\n key={option.value}\n type=\"button\"\n onClick={() => setStatusFilter(option.value)}\n style={{\n padding: 'var(--space-controlGap) var(--space-formGap)',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n borderRadius: 'var(--radius-button)',\n border: 'none',\n cursor: 'pointer',\n transition: 'all 0.2s ease',\n backgroundColor: statusFilter === option.value ? 'var(--color-bg-surface)' : 'transparent',\n color: statusFilter === option.value ? 'var(--color-text-primary)' : 'var(--color-text-secondary)',\n boxShadow: statusFilter === option.value ? '0 1px 2px rgba(0,0,0,0.05)' : 'none',\n }}\n >\n {option.label}\n </button>\n ))}\n </div>\n </div>\n\n {/* Search Bar */}\n <div style={{ marginBottom: 'var(--space-sectionGap)' }}>\n <div style={{ position: 'relative', maxWidth: '400px' }}>\n <Search\n style={{\n position: 'absolute',\n left: 'var(--space-controlGap)',\n top: '50%',\n transform: 'translateY(-50%)',\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n color: 'var(--color-text-muted)',\n }}\n />\n <Input\n type=\"text\"\n placeholder=\"Search workflows...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n style={{ paddingLeft: 'var(--size-controlHeight-md)', height: 'var(--size-controlHeight-md)' }}\n />\n </div>\n </div>\n\n {/* Loading state */}\n {loading && workflows.length === 0 && (\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '80px 0' }}>\n <div style={{ textAlign: 'center' }}>\n <Spinner\n style={{\n height: 'var(--size-icon-xl)',\n width: 'var(--size-icon-xl)',\n margin: '0 auto var(--space-formGap)',\n }}\n />\n <p style={{ fontSize: 'var(--font-size-body-sm)', color: 'var(--color-text-muted)' }}>\n Loading workflows...\n </p>\n </div>\n </div>\n )}\n\n {/* Empty state */}\n {!loading && workflows.length === 0 && (\n <GlassCard treatment=\"insight\" className=\"border-border-seam\">\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No Workflows yet\"\n description=\"Design ETL workflows with the FluidGrids visual builder to fetch, transform, and deliver data into BigConsole DataSinks.\"\n action={\n <Button onClick={handleCreateWorkflow}>\n <Plus\n style={{\n marginRight: 'var(--space-iconGap)',\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n }}\n />\n Design Workflow\n </Button>\n }\n />\n </GlassCard>\n )}\n\n {/* No results state */}\n {!loading && filteredWorkflows.length === 0 && workflows.length > 0 && (\n <GlassCard treatment=\"insight\" className=\"border-border-seam\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No matching workflows\"\n description=\"No workflows match your filters\"\n />\n </GlassCard>\n )}\n\n {/* Workflow Grid */}\n {filteredWorkflows.length > 0 && (\n <div\n style={{\n display: 'grid',\n gridTemplateColumns: 'repeat(auto-fill, minmax(320px, 1fr))',\n gap: 'var(--space-formGap)',\n }}\n >\n {filteredWorkflows.map((workflow) => (\n <WorkflowCard\n key={workflow.id}\n workflow={workflow}\n onView={handleViewWorkflow}\n onEdit={handleEditWorkflow}\n onDelete={handleDeleteClick}\n />\n ))}\n </div>\n )}\n </div>\n\n {/* Delete Dialog */}\n {currentWorkflow && (\n <WorkflowDeleteDialog\n workflow={currentWorkflow}\n isOpen={deleteDialogOpen}\n onClose={closeDeleteDialog}\n onConfirm={handleDeleteConfirm}\n />\n )}\n </div>\n );\n});\n\nexport default WorkflowsPage;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"WorkflowsPage.js","names":[],"sources":["../../../src/bigconsole/pages/WorkflowsPage.tsx"],"sourcesContent":["/**\n * Workflows Page\n *\n * List and manage FluidGrids Workflows.\n * Uses fe-libs shared UI components and semantic tokens for consistent styling.\n */\n\nimport { memo, useState, useMemo, useCallback } from 'react';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { AccessDenied, PermissionButton } from '@burdenoff/fe-libs/shared/components';\nimport { BIGCONSOLE_PERMISSIONS } from '../../constants/permissions';\nimport { useAppNavigate } from '../contexts';\nimport { isNative, nativeNotify } from '../../utils/nativeBridge';\nimport { newWorkflowPath } from '../BigConsoleRoutes';\nimport { useWorkflowOperations } from '../hooks/useWorkflowOperations';\nimport { useWorkflowStore } from '../store/workflowStore';\nimport { WorkflowCard } from '../components/workflow/WorkflowCard';\nimport { WorkflowDeleteDialog } from '../components/workflow/WorkflowDeleteDialog';\nimport type { FluidGridsWorkflowStatus } from '../types';\n\n// fe-libs UI components\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Input } from '@burdenoff/fe-libs/ui';\nimport { Card, CardContent } from '@burdenoff/fe-libs/ui';\nimport { Spinner } from '@burdenoff/fe-libs/ui';\nimport { AuroraBackground, GradientText, GlassCard, IllustratedEmptyState, PagePurpose } from '@burdenoff/fe-libs/ui';\n\n// Lucide icons\nimport { Plus, Search, Workflow, AlertCircle } from 'lucide-react';\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\ntype StatusFilter = 'all' | FluidGridsWorkflowStatus;\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\nexport const WorkflowsPage = memo(function WorkflowsPage() {\n const navigate = useAppNavigate();\n\n // RBAC permissions\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n const canRead = hasPermission(BIGCONSOLE_PERMISSIONS.WORKFLOW_READ);\n const canUpdate = hasPermission(BIGCONSOLE_PERMISSIONS.WORKFLOW_UPDATE);\n const canDelete = hasPermission(BIGCONSOLE_PERMISSIONS.WORKFLOW_DELETE);\n\n // Local state\n const [statusFilter, setStatusFilter] = useState<StatusFilter>('all');\n\n // Store state\n const searchQuery = useWorkflowStore((state) => state.searchQuery);\n const setSearchQuery = useWorkflowStore((state) => state.setSearchQuery);\n const deleteDialogOpen = useWorkflowStore((state) => state.deleteDialogOpen);\n const currentWorkflow = useWorkflowStore((state) => state.currentWorkflow);\n const openDeleteDialog = useWorkflowStore((state) => state.openDeleteDialog);\n const closeDeleteDialog = useWorkflowStore((state) => state.closeDeleteDialog);\n\n // Operations\n const { loading, error, workflows, deleteWorkflow, refetch } = useWorkflowOperations();\n\n // Filter workflows\n const filteredWorkflows = useMemo(() => {\n let filtered = [...workflows];\n\n // Apply status filter\n if (statusFilter !== 'all') {\n filtered = filtered.filter((wf) => wf.status === statusFilter);\n }\n\n // Apply search filter\n if (searchQuery.trim()) {\n const query = searchQuery.toLowerCase();\n filtered = filtered.filter(\n (wf) =>\n wf.name.toLowerCase().includes(query) ||\n wf.key.toLowerCase().includes(query) ||\n wf.description?.toLowerCase().includes(query)\n );\n }\n\n // Sort by updatedAt descending\n return filtered.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());\n }, [workflows, statusFilter, searchQuery]);\n\n // Handlers\n const handleCreateWorkflow = useCallback(() => {\n navigate(newWorkflowPath());\n }, [navigate]);\n\n const handleViewWorkflow = useCallback(\n (id: string) => {\n navigate(`/workflows/${id}`);\n },\n [navigate]\n );\n\n const handleEditWorkflow = useCallback(\n (id: string) => {\n navigate(`/workflows/${id}/edit`);\n },\n [navigate]\n );\n\n const handleDeleteClick = useCallback(\n (id: string) => {\n const workflow = workflows.find((wf) => wf.id === id);\n if (workflow) {\n openDeleteDialog(workflow);\n }\n },\n [workflows, openDeleteDialog]\n );\n\n const handleDeleteConfirm = useCallback(async () => {\n if (currentWorkflow) {\n try {\n await deleteWorkflow(currentWorkflow.id);\n if (isNative()) void nativeNotify('success');\n } catch (err) {\n if (isNative()) void nativeNotify('error');\n throw err;\n }\n closeDeleteDialog();\n }\n }, [currentWorkflow, deleteWorkflow, closeDeleteDialog]);\n\n // Status filter options\n const statusOptions: { value: StatusFilter; label: string }[] = [\n { value: 'all', label: 'All' },\n { value: 'draft', label: 'Draft' },\n { value: 'active', label: 'Active' },\n { value: 'paused', label: 'Paused' },\n { value: 'error', label: 'Error' },\n { value: 'archived', label: 'Archived' },\n ];\n\n // Page-level read gate — only after permissions have finished loading so we\n // don't flash Access Denied while the permission set is still being fetched.\n if (!permissionsLoading && !canRead) {\n return <AccessDenied title=\"Access Denied\" description=\"You don't have permission to view workflows.\" />;\n }\n\n // Error state\n if (error) {\n return (\n <div style={{ padding: 'var(--space-pagePadding)' }}>\n <Card\n style={{\n borderColor: 'var(--color-status-error-border)',\n backgroundColor: 'var(--color-status-error-bgSubtle)',\n }}\n >\n <CardContent style={{ padding: 'var(--space-pagePadding)' }}>\n <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', textAlign: 'center' }}>\n <div\n style={{\n padding: 'var(--space-controlGap)',\n borderRadius: '50%',\n backgroundColor: 'var(--color-status-error-bgSubtle)',\n marginBottom: 'var(--space-formGap)',\n }}\n >\n <AlertCircle\n style={{\n height: 'var(--size-icon-xl)',\n width: 'var(--size-icon-xl)',\n color: 'var(--color-status-error-text)',\n }}\n />\n </div>\n <h3\n style={{\n fontSize: 'var(--font-size-body-lg)',\n fontWeight: 'var(--font-weight-medium)',\n color: 'var(--color-status-error-text)',\n marginBottom: 'var(--space-controlGap)',\n }}\n >\n Failed to load Workflows\n </h3>\n <p\n style={{\n fontSize: 'var(--font-size-body-sm)',\n color: 'var(--color-text-secondary)',\n marginBottom: 'var(--space-formGap)',\n }}\n >\n {error.message}\n </p>\n <Button size=\"sm\" onClick={() => refetch()}>\n Try Again\n </Button>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n }\n\n return (\n <div style={{ minHeight: '100vh', backgroundColor: 'var(--color-bg-canvas)' }}>\n {/* Header Section */}\n <div className=\"relative overflow-hidden border-b border-border-seam bg-gloss-card\">\n <AuroraBackground intensity=\"subtle\" />\n <div style={{ padding: 'var(--space-pagePadding)' }}>\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-formGap)' }}>\n <div\n style={{\n display: 'flex',\n height: 'var(--size-controlHeight-lg)',\n width: 'var(--size-controlHeight-lg)',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: 'var(--radius-card)',\n backgroundColor: 'var(--color-action-primary-bg)',\n }}\n >\n <Workflow\n style={{\n height: 'var(--size-icon-lg)',\n width: 'var(--size-icon-lg)',\n color: 'var(--color-action-primary-text)',\n }}\n />\n </div>\n <div>\n <h1\n style={{\n fontSize: 'var(--font-size-heading-h4)',\n fontWeight: 'var(--font-weight-bold)',\n margin: 0,\n color: 'var(--color-text-primary)',\n }}\n >\n <GradientText>Workflows</GradientText>\n </h1>\n <p style={{ fontSize: 'var(--font-size-body-sm)', color: 'var(--color-text-secondary)', margin: 0 }}>\n Design ETL workflows with FluidGrids and link them to DataSinks\n </p>\n </div>\n </div>\n\n <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-controlGap)' }}>\n <PermissionButton permission={BIGCONSOLE_PERMISSIONS.WORKFLOW_CREATE} deniedBehavior=\"disable\">\n <Button onClick={handleCreateWorkflow}>\n <Plus\n style={{\n marginRight: 'var(--space-iconGap)',\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n }}\n />\n Design Workflow\n </Button>\n </PermissionButton>\n </div>\n </div>\n </div>\n </div>\n\n {/* Main Content */}\n <div style={{ padding: 'var(--space-pagePadding)' }}>\n <PagePurpose className=\"mb-[var(--space-sectionGap)]\">\n Workflows are visual ETL jobs built with the FluidGrids builder — they fetch data from external systems,\n transform it, and load it into your BigConsole DataSinks on a schedule or on demand. Use them to keep\n dashboards fed with fresh, shaped data without writing glue code.\n </PagePurpose>\n\n {/* Status Filter Tabs */}\n <div style={{ marginBottom: 'var(--space-formGap)' }}>\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '2px',\n padding: '4px',\n backgroundColor: 'var(--color-bg-sunken)',\n borderRadius: 'var(--radius-card)',\n width: 'fit-content',\n }}\n >\n {statusOptions.map((option) => (\n <button\n key={option.value}\n type=\"button\"\n onClick={() => setStatusFilter(option.value)}\n style={{\n padding: 'var(--space-controlGap) var(--space-formGap)',\n fontSize: 'var(--font-size-body-sm)',\n fontWeight: 'var(--font-weight-medium)',\n borderRadius: 'var(--radius-button)',\n border: 'none',\n cursor: 'pointer',\n transition: 'all 0.2s ease',\n backgroundColor: statusFilter === option.value ? 'var(--color-bg-surface)' : 'transparent',\n color: statusFilter === option.value ? 'var(--color-text-primary)' : 'var(--color-text-secondary)',\n boxShadow: statusFilter === option.value ? '0 1px 2px rgba(0,0,0,0.05)' : 'none',\n }}\n >\n {option.label}\n </button>\n ))}\n </div>\n </div>\n\n {/* Search Bar */}\n <div style={{ marginBottom: 'var(--space-sectionGap)' }}>\n <div style={{ position: 'relative', maxWidth: '400px' }}>\n <Search\n style={{\n position: 'absolute',\n left: 'var(--space-controlGap)',\n top: '50%',\n transform: 'translateY(-50%)',\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n color: 'var(--color-text-muted)',\n }}\n />\n <Input\n type=\"text\"\n placeholder=\"Search workflows...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n style={{ paddingLeft: 'var(--size-controlHeight-md)', height: 'var(--size-controlHeight-md)' }}\n />\n </div>\n </div>\n\n {/* Loading state */}\n {loading && workflows.length === 0 && (\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '80px 0' }}>\n <div style={{ textAlign: 'center' }}>\n <Spinner\n style={{\n height: 'var(--size-icon-xl)',\n width: 'var(--size-icon-xl)',\n margin: '0 auto var(--space-formGap)',\n }}\n />\n <p style={{ fontSize: 'var(--font-size-body-sm)', color: 'var(--color-text-muted)' }}>\n Loading workflows...\n </p>\n </div>\n </div>\n )}\n\n {/* Empty state */}\n {!loading && workflows.length === 0 && (\n <GlassCard treatment=\"insight\" className=\"border-border-seam\">\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No Workflows yet\"\n description=\"Design ETL workflows with the FluidGrids visual builder to fetch, transform, and deliver data into BigConsole DataSinks.\"\n action={\n <PermissionButton permission={BIGCONSOLE_PERMISSIONS.WORKFLOW_CREATE} deniedBehavior=\"disable\">\n <Button onClick={handleCreateWorkflow}>\n <Plus\n style={{\n marginRight: 'var(--space-iconGap)',\n height: 'var(--size-icon-sm)',\n width: 'var(--size-icon-sm)',\n }}\n />\n Design Workflow\n </Button>\n </PermissionButton>\n }\n />\n </GlassCard>\n )}\n\n {/* No results state */}\n {!loading && filteredWorkflows.length === 0 && workflows.length > 0 && (\n <GlassCard treatment=\"insight\" className=\"border-border-seam\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No matching workflows\"\n description=\"No workflows match your filters\"\n />\n </GlassCard>\n )}\n\n {/* Workflow Grid */}\n {filteredWorkflows.length > 0 && (\n <div\n style={{\n display: 'grid',\n gridTemplateColumns: 'repeat(auto-fill, minmax(320px, 1fr))',\n gap: 'var(--space-formGap)',\n }}\n >\n {filteredWorkflows.map((workflow) => (\n <WorkflowCard\n key={workflow.id}\n workflow={workflow}\n onView={handleViewWorkflow}\n onEdit={canUpdate ? handleEditWorkflow : undefined}\n onDelete={canDelete ? handleDeleteClick : undefined}\n />\n ))}\n </div>\n )}\n </div>\n\n {/* Delete Dialog */}\n {currentWorkflow && (\n <WorkflowDeleteDialog\n workflow={currentWorkflow}\n isOpen={deleteDialogOpen}\n onClose={closeDeleteDialog}\n onConfirm={handleDeleteConfirm}\n />\n )}\n </div>\n );\n});\n\nexport default WorkflowsPage;\n"],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
//#region src/constants/permissions.ts
|
|
2
|
+
var e = {
|
|
3
|
+
DASHBOARD_READ: "bigconsole-dashboard:read",
|
|
4
|
+
DASHBOARD_CREATE: "bigconsole-dashboard:create",
|
|
5
|
+
DASHBOARD_UPDATE: "bigconsole-dashboard:update",
|
|
6
|
+
DASHBOARD_DELETE: "bigconsole-dashboard:delete",
|
|
7
|
+
DASHBOARD_EXPORT: "bigconsole-dashboard:export",
|
|
8
|
+
DASHBOARD_IMPORT: "bigconsole-dashboard:import",
|
|
9
|
+
DASHBOARD_PUBLISH: "bigconsole-dashboard:publish",
|
|
10
|
+
DASHBOARD_SHARE: "bigconsole-dashboard:share",
|
|
11
|
+
DASHBOARD_MANAGE_EMBED: "bigconsole-dashboard:manage_embed",
|
|
12
|
+
DASHBOARD_PAGE_CREATE: "bigconsole-dashboard-page:create",
|
|
13
|
+
DASHBOARD_PAGE_UPDATE: "bigconsole-dashboard-page:update",
|
|
14
|
+
DASHBOARD_PAGE_DELETE: "bigconsole-dashboard-page:delete",
|
|
15
|
+
FILTER_CREATE: "bigconsole-filter:create",
|
|
16
|
+
FILTER_UPDATE: "bigconsole-filter:update",
|
|
17
|
+
FILTER_DELETE: "bigconsole-filter:delete",
|
|
18
|
+
FILTER_PRESET_READ: "bigconsole-filter-preset:read",
|
|
19
|
+
FILTER_PRESET_CREATE: "bigconsole-filter-preset:create",
|
|
20
|
+
FILTER_PRESET_UPDATE: "bigconsole-filter-preset:update",
|
|
21
|
+
FILTER_PRESET_DELETE: "bigconsole-filter-preset:delete",
|
|
22
|
+
RLS_POLICY_READ: "bigconsole-rls-policy:read",
|
|
23
|
+
RLS_POLICY_CREATE: "bigconsole-rls-policy:create",
|
|
24
|
+
RLS_POLICY_UPDATE: "bigconsole-rls-policy:update",
|
|
25
|
+
RLS_POLICY_DELETE: "bigconsole-rls-policy:delete",
|
|
26
|
+
SHARE_READ: "bigconsole-share:read",
|
|
27
|
+
TEMPLATE_READ: "bigconsole-template:read",
|
|
28
|
+
TEMPLATE_CREATE: "bigconsole-template:create",
|
|
29
|
+
TEMPLATE_UPDATE: "bigconsole-template:update",
|
|
30
|
+
TEMPLATE_DELETE: "bigconsole-template:delete",
|
|
31
|
+
TEMPLATE_PUBLISH: "bigconsole-template:publish",
|
|
32
|
+
VIEW_READ: "bigconsole-view:read",
|
|
33
|
+
VIEW_CREATE: "bigconsole-view:create",
|
|
34
|
+
VIEW_UPDATE: "bigconsole-view:update",
|
|
35
|
+
VIEW_DELETE: "bigconsole-view:delete",
|
|
36
|
+
DATASINK_READ: "bigconsole-datasink:read",
|
|
37
|
+
DATASINK_CREATE: "bigconsole-datasink:create",
|
|
38
|
+
DATASINK_UPDATE: "bigconsole-datasink:update",
|
|
39
|
+
DATASINK_DELETE: "bigconsole-datasink:delete",
|
|
40
|
+
DATASINK_EXECUTE: "bigconsole-datasink:execute",
|
|
41
|
+
DATASINK_MANAGE: "bigconsole-datasink:manage",
|
|
42
|
+
PARSER_READ: "bigconsole-parser:read",
|
|
43
|
+
PARSER_CREATE: "bigconsole-parser:create",
|
|
44
|
+
PARSER_UPDATE: "bigconsole-parser:update",
|
|
45
|
+
PARSER_DELETE: "bigconsole-parser:delete",
|
|
46
|
+
PARSER_EXECUTE: "bigconsole-parser:execute",
|
|
47
|
+
PARSER_TEST: "bigconsole-parser:test",
|
|
48
|
+
PIPELINE_READ: "bigconsole-pipeline:read",
|
|
49
|
+
PIPELINE_CREATE: "bigconsole-pipeline:create",
|
|
50
|
+
PIPELINE_UPDATE: "bigconsole-pipeline:update",
|
|
51
|
+
PIPELINE_DELETE: "bigconsole-pipeline:delete",
|
|
52
|
+
PIPELINE_EXECUTE: "bigconsole-pipeline:execute",
|
|
53
|
+
PIPELINE_TEST: "bigconsole-pipeline:test",
|
|
54
|
+
PROMPT_READ: "bigconsole-prompt:read",
|
|
55
|
+
PROMPT_CREATE: "bigconsole-prompt:create",
|
|
56
|
+
PROMPT_UPDATE: "bigconsole-prompt:update",
|
|
57
|
+
PROMPT_DELETE: "bigconsole-prompt:delete",
|
|
58
|
+
WORKFLOW_READ: "bigconsole-workflow:read",
|
|
59
|
+
WORKFLOW_CREATE: "bigconsole-workflow:create",
|
|
60
|
+
WORKFLOW_UPDATE: "bigconsole-workflow:update",
|
|
61
|
+
WORKFLOW_DELETE: "bigconsole-workflow:delete",
|
|
62
|
+
WORKFLOW_EXECUTE: "bigconsole-workflow:execute",
|
|
63
|
+
WIDGET_READ: "bigconsole-widget:read",
|
|
64
|
+
WIDGET_CREATE: "bigconsole-widget:create",
|
|
65
|
+
WIDGET_UPDATE: "bigconsole-widget:update",
|
|
66
|
+
WIDGET_DELETE: "bigconsole-widget:delete",
|
|
67
|
+
WIDGET_ACTION_READ: "bigconsole-widget-action:read",
|
|
68
|
+
WIDGET_ACTION_CREATE: "bigconsole-widget-action:create",
|
|
69
|
+
WIDGET_ACTION_UPDATE: "bigconsole-widget-action:update",
|
|
70
|
+
WIDGET_ACTION_DELETE: "bigconsole-widget-action:delete",
|
|
71
|
+
WIDGET_ACTION_EXECUTE: "bigconsole-widget-action:execute",
|
|
72
|
+
EVENT_LOG_READ: "bigconsole-event-log:read",
|
|
73
|
+
EVENT_LOG_EXECUTE: "bigconsole-event-log:execute",
|
|
74
|
+
WEBHOOK_READ: "bigconsole-webhook:read",
|
|
75
|
+
WEBHOOK_CREATE: "bigconsole-webhook:create",
|
|
76
|
+
WEBHOOK_UPDATE: "bigconsole-webhook:update",
|
|
77
|
+
WEBHOOK_DELETE: "bigconsole-webhook:delete",
|
|
78
|
+
WEBHOOK_TEST: "bigconsole-webhook:test"
|
|
79
|
+
};
|
|
80
|
+
//#endregion
|
|
81
|
+
export { e as BIGCONSOLE_PERMISSIONS };
|
|
82
|
+
|
|
83
|
+
//# sourceMappingURL=permissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.js","names":[],"sources":["../../src/constants/permissions.ts"],"sourcesContent":["/**\n * BigConsole Permission Constants\n *\n * All permission strings for BigConsole resources.\n * Use with fe-libs usePermissions hook:\n * hasPermission(BIGCONSOLE_PERMISSIONS.DASHBOARD_CREATE)\n *\n * IMPORTANT — only strings present in the wspace-rbac-svc seed\n * (`prisma/seed-unified-rbac.ts` ACTION_DEFINITIONS, `// BIGCONSOLE MODULE`\n * section) are ever returned by `myPermissions` / `hasPermission`. Gating on a\n * string the seed does NOT define makes `hasPermission` return false for\n * EVERYONE → a full lockout. Every constant below is verified against the seed\n * as of 2026-08-05.\n *\n * NOTE ON `list` — the BigConsole backend has NO `*:list` action. Every list\n * query (`listDashboards`, `listDataSinks`, …) is gated by the resource's\n * `read` action via its `@rbac` directive. Therefore list pages MUST gate on\n * `<resource>:read`, NOT a `:list` string (which is unseeded → lockout).\n *\n * Resource types (17) and their seeded actions:\n * - bigconsole-dashboard: read, create, update, delete, export, import, publish, share, manage_embed\n * - bigconsole-dashboard-page: create, update, delete\n * - bigconsole-filter: create, update, delete\n * - bigconsole-filter-preset: read, create, update, delete\n * - bigconsole-rls-policy: read, create, update, delete\n * - bigconsole-share: read\n * - bigconsole-template: read, create, update, delete, publish\n * - bigconsole-view: read, create, update, delete\n * - bigconsole-datasink: read, create, update, delete, execute, manage\n * - bigconsole-parser: read, create, update, delete, execute, test\n * - bigconsole-pipeline: read, create, update, delete, execute, test\n * - bigconsole-prompt: read, create, update, delete\n * - bigconsole-workflow: read, create, update, delete, execute\n * - bigconsole-widget: read, create, update, delete\n * - bigconsole-widget-action: read, create, update, delete, execute\n * - bigconsole-event-log: read, execute\n * - bigconsole-webhook: read, create, update, delete, test\n */\n\nexport const BIGCONSOLE_PERMISSIONS = {\n // Dashboard resources\n DASHBOARD_READ: 'bigconsole-dashboard:read',\n DASHBOARD_CREATE: 'bigconsole-dashboard:create',\n DASHBOARD_UPDATE: 'bigconsole-dashboard:update',\n DASHBOARD_DELETE: 'bigconsole-dashboard:delete',\n DASHBOARD_EXPORT: 'bigconsole-dashboard:export',\n DASHBOARD_IMPORT: 'bigconsole-dashboard:import',\n DASHBOARD_PUBLISH: 'bigconsole-dashboard:publish',\n DASHBOARD_SHARE: 'bigconsole-dashboard:share',\n // Embed policy CRUD (`manage_embed` on all embed.gql operations)\n DASHBOARD_MANAGE_EMBED: 'bigconsole-dashboard:manage_embed',\n\n // Dashboard page (sub-resource) resources\n DASHBOARD_PAGE_CREATE: 'bigconsole-dashboard-page:create',\n DASHBOARD_PAGE_UPDATE: 'bigconsole-dashboard-page:update',\n DASHBOARD_PAGE_DELETE: 'bigconsole-dashboard-page:delete',\n\n // Global filter resources\n FILTER_CREATE: 'bigconsole-filter:create',\n FILTER_UPDATE: 'bigconsole-filter:update',\n FILTER_DELETE: 'bigconsole-filter:delete',\n\n // Filter preset resources\n FILTER_PRESET_READ: 'bigconsole-filter-preset:read',\n FILTER_PRESET_CREATE: 'bigconsole-filter-preset:create',\n FILTER_PRESET_UPDATE: 'bigconsole-filter-preset:update',\n FILTER_PRESET_DELETE: 'bigconsole-filter-preset:delete',\n\n // Row-level-security policy resources\n RLS_POLICY_READ: 'bigconsole-rls-policy:read',\n RLS_POLICY_CREATE: 'bigconsole-rls-policy:create',\n RLS_POLICY_UPDATE: 'bigconsole-rls-policy:update',\n RLS_POLICY_DELETE: 'bigconsole-rls-policy:delete',\n\n // Dashboard share resources (read-only surface; share mutations enforce\n // `bigconsole-dashboard:share`, see DASHBOARD_SHARE)\n SHARE_READ: 'bigconsole-share:read',\n\n // Template resources\n TEMPLATE_READ: 'bigconsole-template:read',\n TEMPLATE_CREATE: 'bigconsole-template:create',\n TEMPLATE_UPDATE: 'bigconsole-template:update',\n TEMPLATE_DELETE: 'bigconsole-template:delete',\n TEMPLATE_PUBLISH: 'bigconsole-template:publish',\n\n // Dashboard view resources\n VIEW_READ: 'bigconsole-view:read',\n VIEW_CREATE: 'bigconsole-view:create',\n VIEW_UPDATE: 'bigconsole-view:update',\n VIEW_DELETE: 'bigconsole-view:delete',\n\n // DataSink resources\n DATASINK_READ: 'bigconsole-datasink:read',\n DATASINK_CREATE: 'bigconsole-datasink:create',\n DATASINK_UPDATE: 'bigconsole-datasink:update',\n DATASINK_DELETE: 'bigconsole-datasink:delete',\n // `refreshDataSink` enforces `execute`\n DATASINK_EXECUTE: 'bigconsole-datasink:execute',\n // `invalidateDataSinkCache` enforces `manage`\n DATASINK_MANAGE: 'bigconsole-datasink:manage',\n\n // Parser resources\n PARSER_READ: 'bigconsole-parser:read',\n PARSER_CREATE: 'bigconsole-parser:create',\n PARSER_UPDATE: 'bigconsole-parser:update',\n PARSER_DELETE: 'bigconsole-parser:delete',\n // `executeParser` enforces `execute`\n PARSER_EXECUTE: 'bigconsole-parser:execute',\n // `testParserExpression` enforces `test`\n PARSER_TEST: 'bigconsole-parser:test',\n\n // Pipeline resources\n PIPELINE_READ: 'bigconsole-pipeline:read',\n PIPELINE_CREATE: 'bigconsole-pipeline:create',\n PIPELINE_UPDATE: 'bigconsole-pipeline:update',\n PIPELINE_DELETE: 'bigconsole-pipeline:delete',\n // `executePipeline` enforces `execute`\n PIPELINE_EXECUTE: 'bigconsole-pipeline:execute',\n // `testPipeline` enforces `test`\n PIPELINE_TEST: 'bigconsole-pipeline:test',\n\n // Prompt / AI-generation resources\n PROMPT_READ: 'bigconsole-prompt:read',\n PROMPT_CREATE: 'bigconsole-prompt:create',\n PROMPT_UPDATE: 'bigconsole-prompt:update',\n PROMPT_DELETE: 'bigconsole-prompt:delete',\n\n // Workflow resources\n WORKFLOW_READ: 'bigconsole-workflow:read',\n WORKFLOW_CREATE: 'bigconsole-workflow:create',\n WORKFLOW_UPDATE: 'bigconsole-workflow:update',\n WORKFLOW_DELETE: 'bigconsole-workflow:delete',\n // `executeWorkflow` enforces `execute`\n WORKFLOW_EXECUTE: 'bigconsole-workflow:execute',\n\n // Widget resources\n WIDGET_READ: 'bigconsole-widget:read',\n WIDGET_CREATE: 'bigconsole-widget:create',\n WIDGET_UPDATE: 'bigconsole-widget:update',\n WIDGET_DELETE: 'bigconsole-widget:delete',\n\n // Widget action resources (widget event/action bindings)\n WIDGET_ACTION_READ: 'bigconsole-widget-action:read',\n WIDGET_ACTION_CREATE: 'bigconsole-widget-action:create',\n WIDGET_ACTION_UPDATE: 'bigconsole-widget-action:update',\n WIDGET_ACTION_DELETE: 'bigconsole-widget-action:delete',\n // `emitWidgetEvent` enforces `execute`\n WIDGET_ACTION_EXECUTE: 'bigconsole-widget-action:execute',\n\n // Event log resources\n EVENT_LOG_READ: 'bigconsole-event-log:read',\n // `retryEventDelivery` enforces `execute`\n EVENT_LOG_EXECUTE: 'bigconsole-event-log:execute',\n\n // Event webhook mapping resources\n WEBHOOK_READ: 'bigconsole-webhook:read',\n WEBHOOK_CREATE: 'bigconsole-webhook:create',\n WEBHOOK_UPDATE: 'bigconsole-webhook:update',\n WEBHOOK_DELETE: 'bigconsole-webhook:delete',\n // `testWebhookMapping` enforces `test`\n WEBHOOK_TEST: 'bigconsole-webhook:test',\n} as const;\n\nexport type BigConsolePermission = (typeof BIGCONSOLE_PERMISSIONS)[keyof typeof BIGCONSOLE_PERMISSIONS];\n"],"mappings":";AAuCA,IAAa,IAAyB;CAEpC,gBAAgB;CAChB,kBAAkB;CAClB,kBAAkB;CAClB,kBAAkB;CAClB,kBAAkB;CAClB,kBAAkB;CAClB,mBAAmB;CACnB,iBAAiB;CAEjB,wBAAwB;CAGxB,uBAAuB;CACvB,uBAAuB;CACvB,uBAAuB;CAGvB,eAAe;CACf,eAAe;CACf,eAAe;CAGf,oBAAoB;CACpB,sBAAsB;CACtB,sBAAsB;CACtB,sBAAsB;CAGtB,iBAAiB;CACjB,mBAAmB;CACnB,mBAAmB;CACnB,mBAAmB;CAInB,YAAY;CAGZ,eAAe;CACf,iBAAiB;CACjB,iBAAiB;CACjB,iBAAiB;CACjB,kBAAkB;CAGlB,WAAW;CACX,aAAa;CACb,aAAa;CACb,aAAa;CAGb,eAAe;CACf,iBAAiB;CACjB,iBAAiB;CACjB,iBAAiB;CAEjB,kBAAkB;CAElB,iBAAiB;CAGjB,aAAa;CACb,eAAe;CACf,eAAe;CACf,eAAe;CAEf,gBAAgB;CAEhB,aAAa;CAGb,eAAe;CACf,iBAAiB;CACjB,iBAAiB;CACjB,iBAAiB;CAEjB,kBAAkB;CAElB,eAAe;CAGf,aAAa;CACb,eAAe;CACf,eAAe;CACf,eAAe;CAGf,eAAe;CACf,iBAAiB;CACjB,iBAAiB;CACjB,iBAAiB;CAEjB,kBAAkB;CAGlB,aAAa;CACb,eAAe;CACf,eAAe;CACf,eAAe;CAGf,oBAAoB;CACpB,sBAAsB;CACtB,sBAAsB;CACtB,sBAAsB;CAEtB,uBAAuB;CAGvB,gBAAgB;CAEhB,mBAAmB;CAGnB,cAAc;CACd,gBAAgB;CAChB,gBAAgB;CAChB,gBAAgB;CAEhB,cAAc;CACf"}
|