+
{props.title ?? props.dataset}
@@ -383,19 +381,19 @@
groupBy={selectedGroupBy}
routers={selectedRouters}
flowScope={flowScopeKey}
- on:startDateChange={handleStartDateChange}
- on:endDateChange={handleEndDateChange}
- on:groupByChange={handleGroupByChange}
- on:routersChange={handleRoutersChange}
- on:scopeChange={handleScopeChange}
- on:resetView={handleResetView}
+ onStartDateChange={handleStartDateChange}
+ onEndDateChange={handleEndDateChange}
+ onGroupByChange={handleGroupByChange}
+ onRoutersChange={handleRoutersChange}
+ onScopeChange={handleScopeChange}
+ onResetView={handleResetView}
/>
{#each chartOrder as chartId (chartId)}
{
handleChartDragStart(event, chartId);
}}
@@ -421,9 +419,9 @@
{dataOptions}
{srcVisibility}
{dstVisibility}
- on:dateChange={handleDateChange}
- on:groupByChange={handleGroupByChange}
- on:dataOptionsChange={handleDataOptionsChange}
+ onDateChange={handleDateChange}
+ onGroupByChange={handleGroupByChange}
+ onDataOptionsChange={handleDataOptionsChange}
/>
{:else if chartId === 'characteristics'}
{:else if chartId === 'ip'}
-
{:else if chartId === 'protocol'}
- {
- protocolMetrics = event.detail.metrics;
+ onDateChange={handleDateChange}
+ onGroupByChange={handleGroupByChange}
+ onMetricsChange={(payload) => {
+ protocolMetrics = payload.metrics;
}}
/>
{:else if chartId === 'spectrum'}
- {
- selectedSpectrumRouter = event.detail.router;
+ onDateChange={handleDateChange}
+ onGroupByChange={handleGroupByChange}
+ onRouterChange={(payload) => {
+ selectedSpectrumRouter = payload.router;
}}
- on:addressTypeChange={(event) => {
- selectedSpectrumAddressType = event.detail.addressType;
+ onAddressTypeChange={(payload) => {
+ selectedSpectrumAddressType = payload.addressType;
}}
/>
{:else}
diff --git a/apps/web/src/lib/components/netflow/NetflowDashboard.svelte b/apps/web/src/lib/components/netflow/NetflowDashboard.svelte
index fd084632..cab11dcb 100644
--- a/apps/web/src/lib/components/netflow/NetflowDashboard.svelte
+++ b/apps/web/src/lib/components/netflow/NetflowDashboard.svelte
@@ -1,6 +1,6 @@
-
-
+
- Traffic Overview
+
+ Traffic Overview
+
-
+
-
+
{#if loading}
-
+
Loading data...
@@ -334,13 +331,11 @@
{:else if error}
- {error}
+ {error}
{:else if results.length === 0}
-
- No data available for the selected filters
-
+ No data available for the selected filters
{:else}
{/if}
-
-
+
+
diff --git a/apps/web/src/lib/components/netflow/NetflowFileAnalysisPane.svelte b/apps/web/src/lib/components/netflow/NetflowFileAnalysisPane.svelte
index e75225a8..7ba07b33 100644
--- a/apps/web/src/lib/components/netflow/NetflowFileAnalysisPane.svelte
+++ b/apps/web/src/lib/components/netflow/NetflowFileAnalysisPane.svelte
@@ -1,6 +1,7 @@
-
+
NetFlow File: {filename}
-
- File Information
-
+
+
+ File Information
+
+
Date: {year}-{month}-{day}
Time: {hour}:{minute}
Processed in DB: {processedAt}
-
-
+
+
diff --git a/apps/web/src/lib/components/netflow/NetflowFileLoadingSkeleton.svelte b/apps/web/src/lib/components/netflow/NetflowFileLoadingSkeleton.svelte
index 929367c0..8e92884f 100644
--- a/apps/web/src/lib/components/netflow/NetflowFileLoadingSkeleton.svelte
+++ b/apps/web/src/lib/components/netflow/NetflowFileLoadingSkeleton.svelte
@@ -1,77 +1,78 @@
{#each skeletons as skeletonId (`summary-skeleton-${skeletonId}`)}
-
-
-
-
+
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
{#each [0, 1, 2, 3] as columnIndex (`summary-column-${skeletonId}-${columnIndex}`)}
-
-
-
-
-
+
+
+
+
+
{/each}
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
-
+
+
{/each}
diff --git a/apps/web/src/lib/components/netflow/NetflowFileMessageCard.svelte b/apps/web/src/lib/components/netflow/NetflowFileMessageCard.svelte
index 9b59f39c..b96095d8 100644
--- a/apps/web/src/lib/components/netflow/NetflowFileMessageCard.svelte
+++ b/apps/web/src/lib/components/netflow/NetflowFileMessageCard.svelte
@@ -1,4 +1,7 @@
-
- {message}
- {#if action && actionLabel}
-
- {/if}
-
+
+
+ {message}
+ {#if action && actionLabel}
+
+ {/if}
+
+
diff --git a/apps/web/src/lib/components/netflow/NetflowFileRouterAnalysisSection.svelte b/apps/web/src/lib/components/netflow/NetflowFileRouterAnalysisSection.svelte
index fcbb92bc..c9c1e628 100644
--- a/apps/web/src/lib/components/netflow/NetflowFileRouterAnalysisSection.svelte
+++ b/apps/web/src/lib/components/netflow/NetflowFileRouterAnalysisSection.svelte
@@ -19,7 +19,7 @@
- {title}
+ {title}
diff --git a/apps/web/src/lib/components/netflow/NetflowFileRouterCard.svelte b/apps/web/src/lib/components/netflow/NetflowFileRouterCard.svelte
index f99c8aa0..8967bd95 100644
--- a/apps/web/src/lib/components/netflow/NetflowFileRouterCard.svelte
+++ b/apps/web/src/lib/components/netflow/NetflowFileRouterCard.svelte
@@ -1,6 +1,7 @@
-
+
-
- MAAD Analysis
+
+ MAAD Analysis
-
+
Source
-
+
Destination
@@ -45,5 +42,5 @@
destination={row.destination.spectrum}
/>
-
-
+
+
diff --git a/apps/web/src/lib/components/netflow/NetflowFileRouterSummary.svelte b/apps/web/src/lib/components/netflow/NetflowFileRouterSummary.svelte
index 22d40eae..ad77e7b0 100644
--- a/apps/web/src/lib/components/netflow/NetflowFileRouterSummary.svelte
+++ b/apps/web/src/lib/components/netflow/NetflowFileRouterSummary.svelte
@@ -1,6 +1,7 @@
-
+
- Source: {row.router}
-
+
+ Source: {row.router}
+
+
{row.summary.file_path ?? 'No input locator recorded'}
- Kind
+ Kind
{row.summary.input_kind ?? 'unknown'}
- Status
+ Status
{row.summary.input_status ?? 'unknown'}
- Bucket
+ Bucket
{formatOptionalTimestamp(row.summary.bucket_start)}
- On Disk
+ On Disk
{row.summary.file_exists_on_disk ? 'yes' : 'no'}
{#if row.summary.input_error_message}
-
+
{row.summary.input_error_message}
{/if}
@@ -108,4 +113,4 @@
Seq failures: {formatCount(row.summary.sequence_failures)}
-
+
diff --git a/apps/web/src/lib/components/ui/button/button.svelte b/apps/web/src/lib/components/ui/button/button.svelte
new file mode 100644
index 00000000..611b8929
--- /dev/null
+++ b/apps/web/src/lib/components/ui/button/button.svelte
@@ -0,0 +1,91 @@
+
+
+
+
+{#if href}
+
+
+ {@render children?.()}
+
+
+{:else}
+
+{/if}
diff --git a/apps/web/src/lib/components/ui/button/index.ts b/apps/web/src/lib/components/ui/button/index.ts
new file mode 100644
index 00000000..5414d9d3
--- /dev/null
+++ b/apps/web/src/lib/components/ui/button/index.ts
@@ -0,0 +1,17 @@
+import Root, {
+ type ButtonProps,
+ type ButtonSize,
+ type ButtonVariant,
+ buttonVariants
+} from './button.svelte';
+
+export {
+ Root,
+ type ButtonProps as Props,
+ //
+ Root as Button,
+ buttonVariants,
+ type ButtonProps,
+ type ButtonSize,
+ type ButtonVariant
+};
diff --git a/apps/web/src/lib/components/ui/card/card-action.svelte b/apps/web/src/lib/components/ui/card/card-action.svelte
new file mode 100644
index 00000000..bc79c73d
--- /dev/null
+++ b/apps/web/src/lib/components/ui/card/card-action.svelte
@@ -0,0 +1,23 @@
+
+
+
+ {@render children?.()}
+
diff --git a/apps/web/src/lib/components/ui/card/card-content.svelte b/apps/web/src/lib/components/ui/card/card-content.svelte
new file mode 100644
index 00000000..4d887798
--- /dev/null
+++ b/apps/web/src/lib/components/ui/card/card-content.svelte
@@ -0,0 +1,20 @@
+
+
+
+ {@render children?.()}
+
diff --git a/apps/web/src/lib/components/ui/card/card-description.svelte b/apps/web/src/lib/components/ui/card/card-description.svelte
new file mode 100644
index 00000000..58c0904c
--- /dev/null
+++ b/apps/web/src/lib/components/ui/card/card-description.svelte
@@ -0,0 +1,20 @@
+
+
+
+ {@render children?.()}
+
diff --git a/apps/web/src/lib/components/ui/card/card-footer.svelte b/apps/web/src/lib/components/ui/card/card-footer.svelte
new file mode 100644
index 00000000..253e7f23
--- /dev/null
+++ b/apps/web/src/lib/components/ui/card/card-footer.svelte
@@ -0,0 +1,23 @@
+
+
+
+ {@render children?.()}
+
diff --git a/apps/web/src/lib/components/ui/card/card-header.svelte b/apps/web/src/lib/components/ui/card/card-header.svelte
new file mode 100644
index 00000000..b2f5f4df
--- /dev/null
+++ b/apps/web/src/lib/components/ui/card/card-header.svelte
@@ -0,0 +1,23 @@
+
+
+
+ {@render children?.()}
+
diff --git a/apps/web/src/lib/components/ui/card/card-title.svelte b/apps/web/src/lib/components/ui/card/card-title.svelte
new file mode 100644
index 00000000..cc49a4d1
--- /dev/null
+++ b/apps/web/src/lib/components/ui/card/card-title.svelte
@@ -0,0 +1,20 @@
+
+
+
+ {@render children?.()}
+
diff --git a/apps/web/src/lib/components/ui/card/card.svelte b/apps/web/src/lib/components/ui/card/card.svelte
new file mode 100644
index 00000000..54f3f751
--- /dev/null
+++ b/apps/web/src/lib/components/ui/card/card.svelte
@@ -0,0 +1,25 @@
+
+
+img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(4)] *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl',
+ className
+ )}
+ {...restProps}
+>
+ {@render children?.()}
+
diff --git a/apps/web/src/lib/components/ui/card/index.ts b/apps/web/src/lib/components/ui/card/index.ts
new file mode 100644
index 00000000..6a3ae41f
--- /dev/null
+++ b/apps/web/src/lib/components/ui/card/index.ts
@@ -0,0 +1,25 @@
+import Action from './card-action.svelte';
+import Content from './card-content.svelte';
+import Description from './card-description.svelte';
+import Footer from './card-footer.svelte';
+import Header from './card-header.svelte';
+import Title from './card-title.svelte';
+import Root from './card.svelte';
+
+export {
+ Root,
+ Content,
+ Description,
+ Footer,
+ Header,
+ Title,
+ Action,
+ //
+ Root as Card,
+ Content as CardContent,
+ Description as CardDescription,
+ Footer as CardFooter,
+ Header as CardHeader,
+ Title as CardTitle,
+ Action as CardAction
+};
diff --git a/apps/web/src/lib/components/ui/checkbox/checkbox.svelte b/apps/web/src/lib/components/ui/checkbox/checkbox.svelte
new file mode 100644
index 00000000..56a5447b
--- /dev/null
+++ b/apps/web/src/lib/components/ui/checkbox/checkbox.svelte
@@ -0,0 +1,39 @@
+
+
+
+ {#snippet children({ checked, indeterminate })}
+
+ {#if checked}
+
+ {:else if indeterminate}
+
+ {/if}
+
+ {/snippet}
+
diff --git a/apps/web/src/lib/components/ui/checkbox/index.ts b/apps/web/src/lib/components/ui/checkbox/index.ts
new file mode 100644
index 00000000..5c276719
--- /dev/null
+++ b/apps/web/src/lib/components/ui/checkbox/index.ts
@@ -0,0 +1,6 @@
+import Root from './checkbox.svelte';
+export {
+ Root,
+ //
+ Root as Checkbox
+};
diff --git a/apps/web/src/lib/components/ui/select/index.ts b/apps/web/src/lib/components/ui/select/index.ts
new file mode 100644
index 00000000..23ba7ded
--- /dev/null
+++ b/apps/web/src/lib/components/ui/select/index.ts
@@ -0,0 +1,37 @@
+import Content from './select-content.svelte';
+import GroupHeading from './select-group-heading.svelte';
+import Group from './select-group.svelte';
+import Item from './select-item.svelte';
+import Label from './select-label.svelte';
+import Portal from './select-portal.svelte';
+import ScrollDownButton from './select-scroll-down-button.svelte';
+import ScrollUpButton from './select-scroll-up-button.svelte';
+import Separator from './select-separator.svelte';
+import Trigger from './select-trigger.svelte';
+import Root from './select.svelte';
+
+export {
+ Root,
+ Group,
+ Label,
+ Item,
+ Content,
+ Trigger,
+ Separator,
+ ScrollDownButton,
+ ScrollUpButton,
+ GroupHeading,
+ Portal,
+ //
+ Root as Select,
+ Group as SelectGroup,
+ Label as SelectLabel,
+ Item as SelectItem,
+ Content as SelectContent,
+ Trigger as SelectTrigger,
+ Separator as SelectSeparator,
+ ScrollDownButton as SelectScrollDownButton,
+ ScrollUpButton as SelectScrollUpButton,
+ GroupHeading as SelectGroupHeading,
+ Portal as SelectPortal
+};
diff --git a/apps/web/src/lib/components/ui/select/select-content.svelte b/apps/web/src/lib/components/ui/select/select-content.svelte
new file mode 100644
index 00000000..c63791ca
--- /dev/null
+++ b/apps/web/src/lib/components/ui/select/select-content.svelte
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+ {@render children?.()}
+
+
+
+
diff --git a/apps/web/src/lib/components/ui/select/select-group-heading.svelte b/apps/web/src/lib/components/ui/select/select-group-heading.svelte
new file mode 100644
index 00000000..3ff70030
--- /dev/null
+++ b/apps/web/src/lib/components/ui/select/select-group-heading.svelte
@@ -0,0 +1,21 @@
+
+
+
+ {@render children?.()}
+
diff --git a/apps/web/src/lib/components/ui/select/select-group.svelte b/apps/web/src/lib/components/ui/select/select-group.svelte
new file mode 100644
index 00000000..553f7e70
--- /dev/null
+++ b/apps/web/src/lib/components/ui/select/select-group.svelte
@@ -0,0 +1,17 @@
+
+
+
diff --git a/apps/web/src/lib/components/ui/select/select-item.svelte b/apps/web/src/lib/components/ui/select/select-item.svelte
new file mode 100644
index 00000000..f9f9f946
--- /dev/null
+++ b/apps/web/src/lib/components/ui/select/select-item.svelte
@@ -0,0 +1,40 @@
+
+
+
+ {#snippet children({ selected, highlighted })}
+
+ {#if selected}
+
+ {/if}
+
+
+ {#if childrenProp}
+ {@render childrenProp({ selected, highlighted })}
+ {:else}
+ {label || value}
+ {/if}
+
+ {/snippet}
+
diff --git a/apps/web/src/lib/components/ui/select/select-label.svelte b/apps/web/src/lib/components/ui/select/select-label.svelte
new file mode 100644
index 00000000..6c76ced6
--- /dev/null
+++ b/apps/web/src/lib/components/ui/select/select-label.svelte
@@ -0,0 +1,20 @@
+
+
+
+ {@render children?.()}
+
diff --git a/apps/web/src/lib/components/ui/select/select-portal.svelte b/apps/web/src/lib/components/ui/select/select-portal.svelte
new file mode 100644
index 00000000..59c4b78e
--- /dev/null
+++ b/apps/web/src/lib/components/ui/select/select-portal.svelte
@@ -0,0 +1,7 @@
+
+
+
diff --git a/apps/web/src/lib/components/ui/select/select-scroll-down-button.svelte b/apps/web/src/lib/components/ui/select/select-scroll-down-button.svelte
new file mode 100644
index 00000000..7edad9a9
--- /dev/null
+++ b/apps/web/src/lib/components/ui/select/select-scroll-down-button.svelte
@@ -0,0 +1,23 @@
+
+
+
+
+
diff --git a/apps/web/src/lib/components/ui/select/select-scroll-up-button.svelte b/apps/web/src/lib/components/ui/select/select-scroll-up-button.svelte
new file mode 100644
index 00000000..324fb795
--- /dev/null
+++ b/apps/web/src/lib/components/ui/select/select-scroll-up-button.svelte
@@ -0,0 +1,23 @@
+
+
+
+
+
diff --git a/apps/web/src/lib/components/ui/select/select-separator.svelte b/apps/web/src/lib/components/ui/select/select-separator.svelte
new file mode 100644
index 00000000..c508e26a
--- /dev/null
+++ b/apps/web/src/lib/components/ui/select/select-separator.svelte
@@ -0,0 +1,18 @@
+
+
+
diff --git a/apps/web/src/lib/components/ui/select/select-trigger.svelte b/apps/web/src/lib/components/ui/select/select-trigger.svelte
new file mode 100644
index 00000000..28fb7c1a
--- /dev/null
+++ b/apps/web/src/lib/components/ui/select/select-trigger.svelte
@@ -0,0 +1,29 @@
+
+
+
+ {@render children?.()}
+
+
diff --git a/apps/web/src/lib/components/ui/select/select.svelte b/apps/web/src/lib/components/ui/select/select.svelte
new file mode 100644
index 00000000..b9bf9ba5
--- /dev/null
+++ b/apps/web/src/lib/components/ui/select/select.svelte
@@ -0,0 +1,11 @@
+
+
+
diff --git a/apps/web/src/lib/components/ui/separator/index.ts b/apps/web/src/lib/components/ui/separator/index.ts
new file mode 100644
index 00000000..768efac9
--- /dev/null
+++ b/apps/web/src/lib/components/ui/separator/index.ts
@@ -0,0 +1,7 @@
+import Root from './separator.svelte';
+
+export {
+ Root,
+ //
+ Root as Separator
+};
diff --git a/apps/web/src/lib/components/ui/separator/separator.svelte b/apps/web/src/lib/components/ui/separator/separator.svelte
new file mode 100644
index 00000000..37da5e55
--- /dev/null
+++ b/apps/web/src/lib/components/ui/separator/separator.svelte
@@ -0,0 +1,23 @@
+
+
+
diff --git a/apps/web/src/lib/components/ui/skeleton/index.ts b/apps/web/src/lib/components/ui/skeleton/index.ts
new file mode 100644
index 00000000..3120ce12
--- /dev/null
+++ b/apps/web/src/lib/components/ui/skeleton/index.ts
@@ -0,0 +1,7 @@
+import Root from './skeleton.svelte';
+
+export {
+ Root,
+ //
+ Root as Skeleton
+};
diff --git a/apps/web/src/lib/components/ui/skeleton/skeleton.svelte b/apps/web/src/lib/components/ui/skeleton/skeleton.svelte
new file mode 100644
index 00000000..3a28b0c2
--- /dev/null
+++ b/apps/web/src/lib/components/ui/skeleton/skeleton.svelte
@@ -0,0 +1,17 @@
+
+
+
diff --git a/apps/web/src/lib/components/ui/table/index.ts b/apps/web/src/lib/components/ui/table/index.ts
new file mode 100644
index 00000000..553b6b44
--- /dev/null
+++ b/apps/web/src/lib/components/ui/table/index.ts
@@ -0,0 +1,28 @@
+import Body from './table-body.svelte';
+import Caption from './table-caption.svelte';
+import Cell from './table-cell.svelte';
+import Footer from './table-footer.svelte';
+import Head from './table-head.svelte';
+import Header from './table-header.svelte';
+import Row from './table-row.svelte';
+import Root from './table.svelte';
+
+export {
+ Root,
+ Body,
+ Caption,
+ Cell,
+ Footer,
+ Head,
+ Header,
+ Row,
+ //
+ Root as Table,
+ Body as TableBody,
+ Caption as TableCaption,
+ Cell as TableCell,
+ Footer as TableFooter,
+ Head as TableHead,
+ Header as TableHeader,
+ Row as TableRow
+};
diff --git a/apps/web/src/lib/components/ui/table/table-body.svelte b/apps/web/src/lib/components/ui/table/table-body.svelte
new file mode 100644
index 00000000..cf720f47
--- /dev/null
+++ b/apps/web/src/lib/components/ui/table/table-body.svelte
@@ -0,0 +1,20 @@
+
+
+
+ {@render children?.()}
+
diff --git a/apps/web/src/lib/components/ui/table/table-caption.svelte b/apps/web/src/lib/components/ui/table/table-caption.svelte
new file mode 100644
index 00000000..61ac4153
--- /dev/null
+++ b/apps/web/src/lib/components/ui/table/table-caption.svelte
@@ -0,0 +1,20 @@
+
+
+
+ {@render children?.()}
+
diff --git a/apps/web/src/lib/components/ui/table/table-cell.svelte b/apps/web/src/lib/components/ui/table/table-cell.svelte
new file mode 100644
index 00000000..1fb325bb
--- /dev/null
+++ b/apps/web/src/lib/components/ui/table/table-cell.svelte
@@ -0,0 +1,20 @@
+
+
+
+ {@render children?.()}
+
diff --git a/apps/web/src/lib/components/ui/table/table-footer.svelte b/apps/web/src/lib/components/ui/table/table-footer.svelte
new file mode 100644
index 00000000..53a9eb45
--- /dev/null
+++ b/apps/web/src/lib/components/ui/table/table-footer.svelte
@@ -0,0 +1,20 @@
+
+
+tr]:last:border-b-0', className)}
+ {...restProps}
+>
+ {@render children?.()}
+
diff --git a/apps/web/src/lib/components/ui/table/table-head.svelte b/apps/web/src/lib/components/ui/table/table-head.svelte
new file mode 100644
index 00000000..1ef7f1d9
--- /dev/null
+++ b/apps/web/src/lib/components/ui/table/table-head.svelte
@@ -0,0 +1,23 @@
+
+
+
+ {@render children?.()}
+
diff --git a/apps/web/src/lib/components/ui/table/table-header.svelte b/apps/web/src/lib/components/ui/table/table-header.svelte
new file mode 100644
index 00000000..615b5d8e
--- /dev/null
+++ b/apps/web/src/lib/components/ui/table/table-header.svelte
@@ -0,0 +1,20 @@
+
+
+
+ {@render children?.()}
+
diff --git a/apps/web/src/lib/components/ui/table/table-row.svelte b/apps/web/src/lib/components/ui/table/table-row.svelte
new file mode 100644
index 00000000..d0d5fed1
--- /dev/null
+++ b/apps/web/src/lib/components/ui/table/table-row.svelte
@@ -0,0 +1,23 @@
+
+
+
+ {@render children?.()}
+
diff --git a/apps/web/src/lib/components/ui/table/table.svelte b/apps/web/src/lib/components/ui/table/table.svelte
new file mode 100644
index 00000000..a5acd8f2
--- /dev/null
+++ b/apps/web/src/lib/components/ui/table/table.svelte
@@ -0,0 +1,22 @@
+
+
+
+
+ {@render children?.()}
+
+
diff --git a/apps/web/src/lib/components/ui/tabs/index.ts b/apps/web/src/lib/components/ui/tabs/index.ts
new file mode 100644
index 00000000..c5a15a0b
--- /dev/null
+++ b/apps/web/src/lib/components/ui/tabs/index.ts
@@ -0,0 +1,18 @@
+import Content from './tabs-content.svelte';
+import Trigger from './tabs-trigger.svelte';
+import Root from './tabs.svelte';
+import List, { tabsListVariants, type TabsListVariant } from './tabs-list.svelte';
+
+export {
+ Root,
+ Content,
+ List,
+ Trigger,
+ tabsListVariants,
+ type TabsListVariant,
+ //
+ Root as Tabs,
+ Content as TabsContent,
+ List as TabsList,
+ Trigger as TabsTrigger
+};
diff --git a/apps/web/src/lib/components/ui/tabs/tabs-content.svelte b/apps/web/src/lib/components/ui/tabs/tabs-content.svelte
new file mode 100644
index 00000000..2f30880d
--- /dev/null
+++ b/apps/web/src/lib/components/ui/tabs/tabs-content.svelte
@@ -0,0 +1,17 @@
+
+
+
diff --git a/apps/web/src/lib/components/ui/tabs/tabs-list.svelte b/apps/web/src/lib/components/ui/tabs/tabs-list.svelte
new file mode 100644
index 00000000..b98149d7
--- /dev/null
+++ b/apps/web/src/lib/components/ui/tabs/tabs-list.svelte
@@ -0,0 +1,40 @@
+
+
+
+
+
diff --git a/apps/web/src/lib/components/ui/tabs/tabs-trigger.svelte b/apps/web/src/lib/components/ui/tabs/tabs-trigger.svelte
new file mode 100644
index 00000000..dabe8df4
--- /dev/null
+++ b/apps/web/src/lib/components/ui/tabs/tabs-trigger.svelte
@@ -0,0 +1,23 @@
+
+
+
diff --git a/apps/web/src/lib/components/ui/tabs/tabs.svelte b/apps/web/src/lib/components/ui/tabs/tabs.svelte
new file mode 100644
index 00000000..9a9b0ce9
--- /dev/null
+++ b/apps/web/src/lib/components/ui/tabs/tabs.svelte
@@ -0,0 +1,19 @@
+
+
+
diff --git a/apps/web/src/lib/components/ui/tooltip/index.ts b/apps/web/src/lib/components/ui/tooltip/index.ts
new file mode 100644
index 00000000..b98d5771
--- /dev/null
+++ b/apps/web/src/lib/components/ui/tooltip/index.ts
@@ -0,0 +1,19 @@
+import Content from './tooltip-content.svelte';
+import Portal from './tooltip-portal.svelte';
+import Provider from './tooltip-provider.svelte';
+import Trigger from './tooltip-trigger.svelte';
+import Root from './tooltip.svelte';
+
+export {
+ Root,
+ Trigger,
+ Content,
+ Provider,
+ Portal,
+ //
+ Root as Tooltip,
+ Content as TooltipContent,
+ Trigger as TooltipTrigger,
+ Provider as TooltipProvider,
+ Portal as TooltipPortal
+};
diff --git a/apps/web/src/lib/components/ui/tooltip/tooltip-content.svelte b/apps/web/src/lib/components/ui/tooltip/tooltip-content.svelte
new file mode 100644
index 00000000..9e5d0774
--- /dev/null
+++ b/apps/web/src/lib/components/ui/tooltip/tooltip-content.svelte
@@ -0,0 +1,52 @@
+
+
+
+
+ {@render children?.()}
+
+ {#snippet child({ props })}
+
+ {/snippet}
+
+
+
diff --git a/apps/web/src/lib/components/ui/tooltip/tooltip-portal.svelte b/apps/web/src/lib/components/ui/tooltip/tooltip-portal.svelte
new file mode 100644
index 00000000..7d328f01
--- /dev/null
+++ b/apps/web/src/lib/components/ui/tooltip/tooltip-portal.svelte
@@ -0,0 +1,7 @@
+
+
+
diff --git a/apps/web/src/lib/components/ui/tooltip/tooltip-provider.svelte b/apps/web/src/lib/components/ui/tooltip/tooltip-provider.svelte
new file mode 100644
index 00000000..fde5bb28
--- /dev/null
+++ b/apps/web/src/lib/components/ui/tooltip/tooltip-provider.svelte
@@ -0,0 +1,7 @@
+
+
+
diff --git a/apps/web/src/lib/components/ui/tooltip/tooltip-trigger.svelte b/apps/web/src/lib/components/ui/tooltip/tooltip-trigger.svelte
new file mode 100644
index 00000000..0f041627
--- /dev/null
+++ b/apps/web/src/lib/components/ui/tooltip/tooltip-trigger.svelte
@@ -0,0 +1,7 @@
+
+
+
diff --git a/apps/web/src/lib/components/ui/tooltip/tooltip.svelte b/apps/web/src/lib/components/ui/tooltip/tooltip.svelte
new file mode 100644
index 00000000..16eeb706
--- /dev/null
+++ b/apps/web/src/lib/components/ui/tooltip/tooltip.svelte
@@ -0,0 +1,7 @@
+
+
+
diff --git a/apps/web/src/lib/stores/rangeSelection.svelte.ts b/apps/web/src/lib/stores/rangeSelection.svelte.ts
new file mode 100644
index 00000000..2094efe5
--- /dev/null
+++ b/apps/web/src/lib/stores/rangeSelection.svelte.ts
@@ -0,0 +1,19 @@
+export interface RangeSelectionState {
+ sourceChartId: string;
+ startLabel: string;
+ endLabel: string;
+}
+
+class RangeSelection {
+ selection = $state(null);
+
+ set(selection: RangeSelectionState) {
+ this.selection = selection;
+ }
+
+ clear() {
+ this.selection = null;
+ }
+}
+
+export const rangeSelection = new RangeSelection();
diff --git a/apps/web/src/lib/stores/rangeSelection.ts b/apps/web/src/lib/stores/rangeSelection.ts
deleted file mode 100644
index ef7db39a..00000000
--- a/apps/web/src/lib/stores/rangeSelection.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { writable } from 'svelte/store';
-
-export interface RangeSelectionState {
- sourceChartId: string;
- startLabel: string;
- endLabel: string;
-}
-
-export const rangeSelectionStore = writable(null);
diff --git a/apps/web/src/lib/utils.ts b/apps/web/src/lib/utils.ts
new file mode 100644
index 00000000..f92bfcbb
--- /dev/null
+++ b/apps/web/src/lib/utils.ts
@@ -0,0 +1,13 @@
+import { clsx, type ClassValue } from 'clsx';
+import { twMerge } from 'tailwind-merge';
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs));
+}
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export type WithoutChild = T extends { child?: any } ? Omit : T;
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export type WithoutChildren = T extends { children?: any } ? Omit : T;
+export type WithoutChildrenOrChild = WithoutChildren>;
+export type WithElementRef = T & { ref?: U | null };
diff --git a/apps/web/src/routes/+error.svelte b/apps/web/src/routes/+error.svelte
index 409616d8..9821ea13 100644
--- a/apps/web/src/routes/+error.svelte
+++ b/apps/web/src/routes/+error.svelte
@@ -1,6 +1,8 @@
-
-
-
-
-
-
- ATLANTIS
-
+
+
+
-
-
-
- {@render children()}
-
-
-
+ Built as part of an NSF REU with the Oregon Networking Research Group
+ © 2025 Oliver Boorstein · MIT License
+
+
+
+
diff --git a/apps/web/src/routes/+page.svelte b/apps/web/src/routes/+page.svelte
index 1dca3c53..de9bc190 100644
--- a/apps/web/src/routes/+page.svelte
+++ b/apps/web/src/routes/+page.svelte
@@ -1,6 +1,8 @@
- NetFlow Files
+ NetFlow Files
-
- Navigate to File by Timestamp
-
-
- Dataset
-
-
-
-
- File Timestamp (YYYYMMDDHHmm)
-
-
-
- {error || ' '}
+
+
+ Navigate to File by Timestamp
+
+
+
+
+ Dataset
+
+
+
+
+ File Timestamp (YYYYMMDDHHmm)
+
+
+
+ {error || ' '}
+
+
+
+
-
-
-
-
-
- Choose a dataset, then enter the exact 12-digit timestamp from NetFlow filenames (e.g.,
- `nfcapd.202601011200`).
-
-
+
+ Choose a dataset, then enter the exact 12-digit timestamp from NetFlow filenames (e.g.,
+ `nfcapd.202601011200`).
+
+
+
diff --git a/bun.lock b/bun.lock
index d257fb6b..7d37ac74 100644
--- a/bun.lock
+++ b/bun.lock
@@ -31,7 +31,7 @@
"name": "@atlantis/web",
"version": "0.0.1",
"dependencies": {
- "@lucide/svelte": "^0.511.0",
+ "@lucide/svelte": "^1.33.0",
"better-sqlite3": "^12.6.2",
"chart.js": "^4.4.9",
"chartjs-plugin-annotation": "^3.1.0",
@@ -43,6 +43,7 @@
"@cloudflare/workers-types": "^4.20260511.1",
"@eslint/compat": "^1.2.5",
"@eslint/js": "^9.18.0",
+ "@internationalized/date": "^3.12.0",
"@playwright/test": "1.52.0",
"@sveltejs/adapter-cloudflare": "^7.2.8",
"@sveltejs/kit": "^2.16.0",
@@ -50,6 +51,8 @@
"@tailwindcss/vite": "^4.0.0",
"@types/better-sqlite3": "^7.6.13",
"@types/node": "^22.15.17",
+ "bits-ui": "^2.16.3",
+ "clsx": "^2.1.1",
"eslint": "^9.18.0",
"eslint-config-prettier": "^10.0.1",
"eslint-plugin-svelte": "^3.0.0",
@@ -57,9 +60,13 @@
"prettier": "^3.8.1",
"prettier-plugin-svelte": "^3.5.1",
"prettier-plugin-tailwindcss": "^0.7.2",
+ "shadcn-svelte": "^1.5.0",
"svelte": "^5.0.0",
"svelte-check": "^4.0.0",
+ "tailwind-merge": "^3.6.0",
+ "tailwind-variants": "^3.3.1",
"tailwindcss": "^4.0.0",
+ "tw-animate-css": "^1.4.0",
"typescript": "^5.0.0",
"typescript-eslint": "^8.20.0",
"vite": "^6.2.6",
@@ -197,6 +204,12 @@
"@eslint/plugin-kit": ["@eslint/plugin-kit@0.6.1", "", { "dependencies": { "@eslint/core": "^1.1.1", "levn": "^0.4.1" } }, "sha512-iH1B076HoAshH1mLpHMgwdGeTs0CYwL0SPMkGuSebZrwBp16v415e9NZXg2jtrqPVQjf6IANe2Vtlr5KswtcZQ=="],
+ "@floating-ui/core": ["@floating-ui/core@1.8.0", "", { "dependencies": { "@floating-ui/utils": "^0.2.12" } }, "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ=="],
+
+ "@floating-ui/dom": ["@floating-ui/dom@1.8.0", "", { "dependencies": { "@floating-ui/core": "^1.8.0", "@floating-ui/utils": "^0.2.12" } }, "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg=="],
+
+ "@floating-ui/utils": ["@floating-ui/utils@0.2.12", "", {}, "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww=="],
+
"@gar/promisify": ["@gar/promisify@1.1.3", "", {}, "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw=="],
"@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
@@ -257,6 +270,8 @@
"@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.5", "", { "os": "win32", "cpu": "x64" }, "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw=="],
+ "@internationalized/date": ["@internationalized/date@3.12.3", "", { "dependencies": { "@swc/helpers": "^0.5.0" } }, "sha512-fuLX+3ZKLsxI73y8b01EG/WjHb6gE6weCqlfawPO27kBWGMh9G1yH6Csv1uU7/cac9H2GHmOMt6CjmuQ1aia4Q=="],
+
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
"@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="],
@@ -269,7 +284,7 @@
"@kurkle/color": ["@kurkle/color@0.3.4", "", {}, "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w=="],
- "@lucide/svelte": ["@lucide/svelte@0.511.0", "", { "peerDependencies": { "svelte": "^5" } }, "sha512-aLCSPMUJmHlCuLXzXENXa4Z1NV2mN1iAZAFKk4bEbey+/MdsNlu+/DqwVkgW3Yvj6p8y8Vn5xZ2v9CLmPlA6Vw=="],
+ "@lucide/svelte": ["@lucide/svelte@1.33.0", "", { "peerDependencies": { "svelte": "^5" } }, "sha512-b+osTYG2V4dge5Lr7tnaTaahhy/4vH7Xb8zcqVjmctjwgkpXS0NNOJPkGzHHZoxtw/OO+2YAU28omeMfYCaawg=="],
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
@@ -379,6 +394,8 @@
"@sveltejs/vite-plugin-svelte-inspector": ["@sveltejs/vite-plugin-svelte-inspector@4.0.1", "", { "dependencies": { "debug": "^4.3.7" }, "peerDependencies": { "@sveltejs/vite-plugin-svelte": "^5.0.0", "svelte": "^5.0.0", "vite": "^6.0.0" } }, "sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw=="],
+ "@swc/helpers": ["@swc/helpers@0.5.23", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw=="],
+
"@tailwindcss/node": ["@tailwindcss/node@4.2.2", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.19.0", "jiti": "^2.6.1", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.2.2" } }, "sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA=="],
"@tailwindcss/oxide": ["@tailwindcss/oxide@4.2.2", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.2.2", "@tailwindcss/oxide-darwin-arm64": "4.2.2", "@tailwindcss/oxide-darwin-x64": "4.2.2", "@tailwindcss/oxide-freebsd-x64": "4.2.2", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.2", "@tailwindcss/oxide-linux-arm64-gnu": "4.2.2", "@tailwindcss/oxide-linux-arm64-musl": "4.2.2", "@tailwindcss/oxide-linux-x64-gnu": "4.2.2", "@tailwindcss/oxide-linux-x64-musl": "4.2.2", "@tailwindcss/oxide-wasm32-wasi": "4.2.2", "@tailwindcss/oxide-win32-arm64-msvc": "4.2.2", "@tailwindcss/oxide-win32-x64-msvc": "4.2.2" } }, "sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg=="],
@@ -531,6 +548,8 @@
"bindings": ["bindings@1.5.0", "", { "dependencies": { "file-uri-to-path": "1.0.0" } }, "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ=="],
+ "bits-ui": ["bits-ui@2.19.0", "", { "dependencies": { "@floating-ui/core": "^1.7.1", "@floating-ui/dom": "^1.7.1", "esm-env": "^1.1.2", "runed": "^0.35.1", "svelte-toolbelt": "^0.10.6", "tabbable": "^6.2.0" }, "peerDependencies": { "@internationalized/date": "^3.8.1", "svelte": "^5.33.0" } }, "sha512-dHDm5Jw2NZJgLRvHAwPeuR4BnZij+AqTIq33OqVfo+qiMXontoC/yIvGT5TZaviv7OuBdJ2QUy2JPQ2yKBvF6w=="],
+
"bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="],
"blake3-wasm": ["blake3-wasm@2.1.5", "", {}, "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g=="],
@@ -591,7 +610,7 @@
"comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="],
- "commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="],
+ "commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="],
"common-ancestor-path": ["common-ancestor-path@2.0.0", "", {}, "sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng=="],
@@ -849,6 +868,8 @@
"ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="],
+ "inline-style-parser": ["inline-style-parser@0.2.7", "", {}, "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA=="],
+
"ip-address": ["ip-address@10.1.0", "", {}, "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q=="],
"iron-webcrypto": ["iron-webcrypto@1.2.1", "", {}, "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg=="],
@@ -1263,6 +1284,8 @@
"set-cookie-parser": ["set-cookie-parser@3.1.0", "", {}, "sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw=="],
+ "shadcn-svelte": ["shadcn-svelte@1.5.0", "", { "dependencies": { "commander": "^14.0.0", "node-fetch-native": "^1.6.4", "postcss": "^8.5.10", "tailwind-merge": "^3.6.0" }, "peerDependencies": { "svelte": "^5.0.0" }, "bin": { "shadcn-svelte": "dist/index.mjs" } }, "sha512-fcxTeUwEIvELkL/h0Vg2i/9Sf6exAmLG5u3GXc0aN8CA+3fNffKQnfrTdMgkjUEmx9XP619I+wcJOvlr5aDWYQ=="],
+
"sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="],
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
@@ -1325,6 +1348,8 @@
"strip-literal": ["strip-literal@3.1.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg=="],
+ "style-to-object": ["style-to-object@1.0.14", "", { "dependencies": { "inline-style-parser": "0.2.7" } }, "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw=="],
+
"suf-log": ["suf-log@2.5.3", "", { "dependencies": { "s.color": "0.0.15" } }, "sha512-KvC8OPjzdNOe+xQ4XWJV2whQA0aM1kGVczMQ8+dStAO6KfEB140JEVQ9dE76ONZ0/Ylf67ni4tILPJB41U0eow=="],
"supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="],
@@ -1335,10 +1360,18 @@
"svelte-eslint-parser": ["svelte-eslint-parser@1.6.0", "", { "dependencies": { "eslint-scope": "^8.2.0", "eslint-visitor-keys": "^4.0.0", "espree": "^10.0.0", "postcss": "^8.4.49", "postcss-scss": "^4.0.9", "postcss-selector-parser": "^7.0.0", "semver": "^7.7.2" }, "peerDependencies": { "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0" }, "optionalPeers": ["svelte"] }, "sha512-qoB1ehychT6OxEtQAqc/guSqLS20SlA53Uijl7x375s8nlUT0lb9ol/gzraEEatQwsyPTJo87s2CmKL9Xab+Uw=="],
+ "svelte-toolbelt": ["svelte-toolbelt@0.10.6", "", { "dependencies": { "clsx": "^2.1.1", "runed": "^0.35.1", "style-to-object": "^1.0.8" }, "peerDependencies": { "svelte": "^5.30.2" } }, "sha512-YWuX+RE+CnWYx09yseAe4ZVMM7e7GRFZM6OYWpBKOb++s+SQ8RBIMMe+Bs/CznBMc0QPLjr+vDBxTAkozXsFXQ=="],
+
"svgo": ["svgo@4.0.1", "", { "dependencies": { "commander": "^11.1.0", "css-select": "^5.1.0", "css-tree": "^3.0.1", "css-what": "^6.1.0", "csso": "^5.0.5", "picocolors": "^1.1.1", "sax": "^1.5.0" }, "bin": "./bin/svgo.js" }, "sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w=="],
"synckit": ["synckit@0.11.12", "", { "dependencies": { "@pkgr/core": "^0.2.9" } }, "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ=="],
+ "tabbable": ["tabbable@6.5.0", "", {}, "sha512-wieBHXygIm7OyQOu5hQlkk62/WyCFYGlWg7L6/ZCUZwx0o398Zkn4pVmMyfYhfMG8kGrj/Krt8eIk6UKC6VzwA=="],
+
+ "tailwind-merge": ["tailwind-merge@3.6.0", "", {}, "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w=="],
+
+ "tailwind-variants": ["tailwind-variants@3.3.1", "", { "peerDependencies": { "tailwind-merge": ">=3.0.0", "tailwindcss": "*" }, "optionalPeers": ["tailwind-merge", "tailwindcss"] }, "sha512-4pAvwUtM4HKBiRZftncAbpn6V9Hhwoa5Fl7O2u5zbp7Z5Cvu+/o/6+176WY3WCEES209543quG8zFIcXCsc5Jw=="],
+
"tailwindcss": ["tailwindcss@4.2.2", "", {}, "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q=="],
"tapable": ["tapable@2.3.2", "", {}, "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA=="],
@@ -1385,6 +1418,8 @@
"tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="],
+ "tw-animate-css": ["tw-animate-css@1.4.0", "", {}, "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ=="],
+
"type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
@@ -1553,6 +1588,8 @@
"astro-eslint-parser/espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="],
+ "bits-ui/runed": ["runed@0.35.1", "", { "dependencies": { "dequal": "^2.0.3", "esm-env": "^1.0.0", "lz-string": "^1.5.0" }, "peerDependencies": { "@sveltejs/kit": "^2.21.0", "svelte": "^5.7.0" }, "optionalPeers": ["@sveltejs/kit"] }, "sha512-2F4Q/FZzbeJTFdIS/PuOoPRSm92sA2LhzTnv6FXhCoENb3huf5+fDuNOg1LNvGOouy3u/225qxmuJvcV3IZK5Q=="],
+
"cacache/chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="],
"cacache/lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="],
@@ -1599,6 +1636,8 @@
"rc/strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="],
+ "shadcn-svelte/postcss": ["postcss@8.5.26", "", { "dependencies": { "nanoid": "^3.3.17", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ=="],
+
"sitemap/@types/node": ["@types/node@24.12.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ=="],
"ssri/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
@@ -1611,6 +1650,10 @@
"svelte-eslint-parser/espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="],
+ "svelte-toolbelt/runed": ["runed@0.35.1", "", { "dependencies": { "dequal": "^2.0.3", "esm-env": "^1.0.0", "lz-string": "^1.5.0" }, "peerDependencies": { "@sveltejs/kit": "^2.21.0", "svelte": "^5.7.0" }, "optionalPeers": ["@sveltejs/kit"] }, "sha512-2F4Q/FZzbeJTFdIS/PuOoPRSm92sA2LhzTnv6FXhCoENb3huf5+fDuNOg1LNvGOouy3u/225qxmuJvcV3IZK5Q=="],
+
+ "svgo/commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="],
+
"tar/chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="],
"tsx/esbuild": ["esbuild@0.27.7", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.7", "@esbuild/android-arm": "0.27.7", "@esbuild/android-arm64": "0.27.7", "@esbuild/android-x64": "0.27.7", "@esbuild/darwin-arm64": "0.27.7", "@esbuild/darwin-x64": "0.27.7", "@esbuild/freebsd-arm64": "0.27.7", "@esbuild/freebsd-x64": "0.27.7", "@esbuild/linux-arm": "0.27.7", "@esbuild/linux-arm64": "0.27.7", "@esbuild/linux-ia32": "0.27.7", "@esbuild/linux-loong64": "0.27.7", "@esbuild/linux-mips64el": "0.27.7", "@esbuild/linux-ppc64": "0.27.7", "@esbuild/linux-riscv64": "0.27.7", "@esbuild/linux-s390x": "0.27.7", "@esbuild/linux-x64": "0.27.7", "@esbuild/netbsd-arm64": "0.27.7", "@esbuild/netbsd-x64": "0.27.7", "@esbuild/openbsd-arm64": "0.27.7", "@esbuild/openbsd-x64": "0.27.7", "@esbuild/openharmony-arm64": "0.27.7", "@esbuild/sunos-x64": "0.27.7", "@esbuild/win32-arm64": "0.27.7", "@esbuild/win32-ia32": "0.27.7", "@esbuild/win32-x64": "0.27.7" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w=="],
@@ -1763,6 +1806,8 @@
"p-locate/p-limit/yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
+ "shadcn-svelte/postcss/nanoid": ["nanoid@3.3.18", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w=="],
+
"sitemap/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
"tsx/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.7", "", { "os": "aix", "cpu": "ppc64" }, "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg=="],
Traffic Overview
+Traffic Overview
+NetFlow File: {filename}
File Information
-File Information
{message}
- {#if action && actionLabel} - - {/if} -{message}
+ {#if action && actionLabel} + + {/if} +{title}
+{title}
MAAD Analysis
+MAAD Analysis
+
Source
-
+
Destination
Destination
Source: {row.router}
-
+ Source: {row.router}
+
{row.summary.file_path ?? 'No input locator recorded'}
Kind
+Kind
{row.summary.input_kind ?? 'unknown'}
Status
+Status
{row.summary.input_status ?? 'unknown'}
Bucket
+Bucket
{formatOptionalTimestamp(row.summary.bucket_start)}
On Disk
+On Disk
{row.summary.file_exists_on_disk ? 'yes' : 'no'}
+
{row.summary.input_error_message}
{/if} @@ -108,4 +113,4 @@Seq failures: {formatCount(row.summary.sequence_failures)}
+ {@render children?.()} +
diff --git a/apps/web/src/lib/components/ui/card/card-footer.svelte b/apps/web/src/lib/components/ui/card/card-footer.svelte new file mode 100644 index 00000000..253e7f23 --- /dev/null +++ b/apps/web/src/lib/components/ui/card/card-footer.svelte @@ -0,0 +1,23 @@ + + +- ATLANTIS -
+ +NetFlow Files
+NetFlow Files
-Navigate to File by Timestamp
-Navigate to File by Timestamp
- Choose a dataset, then enter the exact 12-digit timestamp from NetFlow filenames (e.g., - `nfcapd.202601011200`). -
-+ Choose a dataset, then enter the exact 12-digit timestamp from NetFlow filenames (e.g., + `nfcapd.202601011200`). +
+ +