@copilotz/admin 0.9.27 → 0.9.29

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/index.cjs CHANGED
@@ -580,16 +580,6 @@ function CardHeader({ className, ...props }) {
580
580
  }
581
581
  );
582
582
  }
583
- function CardTitle({ className, ...props }) {
584
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
585
- "div",
586
- {
587
- "data-slot": "card-title",
588
- className: cn("leading-none font-semibold", className),
589
- ...props
590
- }
591
- );
592
- }
593
583
  function CardContent({ className, ...props }) {
594
584
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
595
585
  "div",
@@ -1483,73 +1473,24 @@ var PAGE_TITLES = {
1483
1473
  var AdminHeader = ({
1484
1474
  config,
1485
1475
  currentRoute,
1486
- range,
1487
- interval,
1488
- onRangeChange,
1489
- onIntervalChange,
1490
1476
  onRefresh,
1491
- isLoading
1477
+ isLoading,
1478
+ controls
1492
1479
  }) => {
1493
1480
  let pageTitle = config.labels[`${currentRoute.page}Title`] || PAGE_TITLES[currentRoute.page] || currentRoute.page;
1494
1481
  if (currentRoute.page === "collection-items" && currentRoute.collection) {
1495
1482
  pageTitle = currentRoute.collection.charAt(0).toUpperCase() + currentRoute.collection.slice(1);
1496
1483
  }
1497
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Card, { className: "py-0 border-b rounded-none relative z-10 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/80", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(CardHeader, { className: "p-2", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
1498
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-1", children: [
1484
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Card, { className: "py-0 border-b rounded-none relative z-10 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/80 shadow-none", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(CardHeader, { className: "px-3 py-2", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex min-h-10 flex-wrap items-center gap-2", children: [
1485
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex min-w-0 items-center gap-1", children: [
1499
1486
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Tooltip, { children: [
1500
1487
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SidebarTrigger, { className: "-ml-1" }) }),
1501
1488
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TooltipContent, { children: "Toggle Sidebar" })
1502
1489
  ] }),
1503
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h1", { className: "text-sm font-medium ml-2", children: pageTitle })
1490
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h1", { className: "ml-2 whitespace-nowrap text-sm font-medium", children: pageTitle })
1504
1491
  ] }),
1505
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex-1" }),
1506
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-1", children: [
1507
- currentRoute.page === "dashboard" && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
1508
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1509
- Button,
1510
- {
1511
- variant: range === "24h" ? "default" : "ghost",
1512
- size: "sm",
1513
- className: "h-7 text-xs",
1514
- onClick: () => onRangeChange("24h"),
1515
- children: config.labels.range24h
1516
- }
1517
- ),
1518
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1519
- Button,
1520
- {
1521
- variant: range === "7d" ? "default" : "ghost",
1522
- size: "sm",
1523
- className: "h-7 text-xs",
1524
- onClick: () => onRangeChange("7d"),
1525
- children: config.labels.range7d
1526
- }
1527
- ),
1528
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1529
- Button,
1530
- {
1531
- variant: range === "30d" ? "default" : "ghost",
1532
- size: "sm",
1533
- className: "h-7 text-xs",
1534
- onClick: () => onRangeChange("30d"),
1535
- children: config.labels.range30d
1536
- }
1537
- ),
1538
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1539
- Select,
1540
- {
1541
- value: interval,
1542
- onValueChange: (v) => onIntervalChange(v),
1543
- children: [
1544
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SelectTrigger, { className: "h-7 w-[90px] text-xs", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SelectValue, {}) }),
1545
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(SelectContent, { children: [
1546
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SelectItem, { value: "hour", children: config.labels.intervalHour }),
1547
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SelectItem, { value: "day", children: config.labels.intervalDay })
1548
- ] })
1549
- ]
1550
- }
1551
- )
1552
- ] }),
1492
+ controls && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex min-w-[240px] flex-1 items-center justify-end gap-2 overflow-x-auto", children: controls }),
1493
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "ml-auto flex items-center gap-1", children: [
1553
1494
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Tooltip, { children: [
1554
1495
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1555
1496
  Button,
@@ -1749,7 +1690,9 @@ var DashboardView = ({
1749
1690
  onParticipantSearchChange,
1750
1691
  onAgentSearchChange,
1751
1692
  onThreadClick,
1752
- namespace
1693
+ namespace,
1694
+ setHeaderControls,
1695
+ setHeaderRefresh
1753
1696
  }) => {
1754
1697
  void overview;
1755
1698
  void activity;
@@ -1777,13 +1720,17 @@ var DashboardView = ({
1777
1720
  UsageDashboard,
1778
1721
  {
1779
1722
  config,
1780
- namespace
1723
+ namespace,
1724
+ setHeaderControls,
1725
+ setHeaderRefresh
1781
1726
  }
1782
1727
  );
1783
1728
  };
1784
1729
  function UsageDashboard({
1785
1730
  config,
1786
- namespace
1731
+ namespace,
1732
+ setHeaderControls,
1733
+ setHeaderRefresh
1787
1734
  }) {
1788
1735
  const [period, setPeriod] = import_react2.default.useState("7d");
1789
1736
  const [bucket, setBucket] = import_react2.default.useState("day");
@@ -1881,256 +1828,107 @@ function UsageDashboard({
1881
1828
  period === "custom" ? customFrom : "",
1882
1829
  period === "custom" ? customTo : ""
1883
1830
  ].filter((value) => value.trim().length > 0).length;
1884
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "space-y-4", children: [
1885
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between", children: [
1886
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
1887
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h2", { className: "text-2xl font-semibold tracking-tight", children: config.labels.llmUsageTitle }),
1888
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "mt-2 flex flex-wrap items-center gap-2", children: [
1889
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Badge, { variant: "outline", children: formatUsageRangeLabel(period, range) }),
1890
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Badge, { variant: "secondary", children: getGroupByLabel(groupBy) }),
1891
- groupBy === "participant" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Badge, { variant: "outline", children: attribution === "initiatedBy" ? "Initiated by sender" : "Generated by caller" })
1892
- ] })
1893
- ] }),
1894
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1895
- Button,
1896
- {
1897
- className: "w-full sm:w-auto",
1898
- disabled: isLoading,
1899
- onClick: () => void loadUsage(),
1900
- size: "sm",
1901
- variant: "outline",
1902
- children: [
1903
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react6.RefreshCw, { className: cn("size-4", isLoading && "animate-spin") }),
1904
- config.labels.refresh
1905
- ]
1906
- }
1907
- )
1908
- ] }),
1909
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1910
- UsageSummary,
1911
- {
1912
- dimension,
1913
- labels: config.labels,
1914
- metricKind,
1915
- totals
1916
- }
1917
- ),
1918
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Card, { className: "gap-4 overflow-hidden py-4", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(CardContent, { className: "space-y-4 px-4 lg:px-5", children: [
1919
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "grid gap-2 md:grid-cols-2 xl:grid-cols-6", children: [
1920
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1921
- UsageSelect,
1922
- {
1923
- label: "Period",
1924
- onValueChange: (value) => setPeriod(value),
1925
- options: [
1926
- ["24h", config.labels.range24h],
1927
- ["7d", config.labels.range7d],
1928
- ["30d", config.labels.range30d],
1929
- ["custom", "Custom"]
1930
- ],
1931
- value: period
1932
- }
1933
- ),
1934
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1935
- UsageSelect,
1936
- {
1937
- label: "Bucket",
1938
- onValueChange: (value) => setBucket(value),
1939
- options: [
1940
- ["minute", "Minute"],
1941
- ["hour", "Hour"],
1942
- ["day", "Day"],
1943
- ["week", "Week"],
1944
- ["month", "Month"]
1945
- ],
1946
- value: bucket
1947
- }
1948
- ),
1949
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1950
- UsageSelect,
1951
- {
1952
- label: config.labels.usageMetricLabel,
1953
- onValueChange: (value) => setMetricKind(value),
1954
- options: [
1955
- ["cost", config.labels.usageMetricCost],
1956
- ["tokens", config.labels.usageMetricTokens],
1957
- ["calls", "Calls"]
1958
- ],
1959
- value: metricKind
1960
- }
1961
- ),
1962
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1963
- UsageSelect,
1964
- {
1965
- label: "Group",
1966
- onValueChange: (value) => setGroupBy(value),
1967
- options: [
1968
- ["participant", "Participant"],
1969
- ["thread", "Thread"],
1970
- ["namespace", "Namespace"],
1971
- ["provider", "Provider"],
1972
- ["model", "Model"]
1973
- ],
1974
- value: groupBy
1975
- }
1976
- ),
1977
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1978
- UsageSelect,
1979
- {
1980
- label: "Attribution",
1981
- onValueChange: (value) => setAttribution(value),
1982
- options: [
1983
- ["initiatedBy", "Initiated by"],
1984
- ["generatedBy", "Generated by"]
1985
- ],
1986
- value: attribution
1987
- }
1988
- ),
1831
+ const clearFilters = import_react2.default.useCallback(() => {
1832
+ setParticipantType("all");
1833
+ setThreadId("");
1834
+ setParticipantId("");
1835
+ setProvider("");
1836
+ setModel("");
1837
+ setCustomFrom("");
1838
+ setCustomTo("");
1839
+ }, []);
1840
+ const headerControls = import_react2.default.useMemo(() => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1841
+ DashboardHeaderControls,
1842
+ {
1843
+ attribution,
1844
+ bucket,
1845
+ config,
1846
+ dimension,
1847
+ groupBy,
1848
+ metricKind,
1849
+ period,
1850
+ setAttribution,
1851
+ setBucket,
1852
+ setDimension,
1853
+ setGroupBy,
1854
+ setMetricKind,
1855
+ setPeriod
1856
+ }
1857
+ ), [
1858
+ attribution,
1859
+ bucket,
1860
+ config,
1861
+ dimension,
1862
+ groupBy,
1863
+ metricKind,
1864
+ period
1865
+ ]);
1866
+ import_react2.default.useEffect(() => {
1867
+ setHeaderControls?.(headerControls);
1868
+ return () => setHeaderControls?.(null);
1869
+ }, [headerControls, setHeaderControls]);
1870
+ import_react2.default.useEffect(() => {
1871
+ setHeaderRefresh?.(() => () => {
1872
+ void loadUsage();
1873
+ });
1874
+ return () => setHeaderRefresh?.(null);
1875
+ }, [loadUsage, setHeaderRefresh]);
1876
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "grid h-full min-h-0 grid-rows-[auto_minmax(0,4fr)_minmax(0,5fr)] gap-3", children: [
1877
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "space-y-3", children: [
1878
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col gap-3 xl:flex-row xl:items-start xl:justify-between", children: [
1879
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "min-w-0", children: [
1880
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h2", { className: "text-xl font-semibold tracking-tight", children: config.labels.llmUsageTitle }),
1881
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "mt-1 flex flex-wrap items-center gap-2", children: [
1882
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Badge, { variant: "outline", children: formatUsageRangeLabel(period, range) }),
1883
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Badge, { variant: "secondary", children: getGroupByLabel(groupBy) }),
1884
+ groupBy === "participant" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Badge, { variant: "outline", children: attribution === "initiatedBy" ? "Initiated by sender" : "Generated by caller" }),
1885
+ isLoading && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Badge, { variant: "outline", children: config.labels.loading })
1886
+ ] })
1887
+ ] }),
1989
1888
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1990
- UsageSelect,
1889
+ InlineFilters,
1991
1890
  {
1992
- label: config.labels.usageDimensionLabel,
1993
- onValueChange: (value) => setDimension(value),
1994
- options: USAGE_DIMENSIONS.map((nextDimension) => [
1995
- nextDimension,
1996
- getUsageDimensionLabel(config.labels, nextDimension)
1997
- ]),
1998
- value: dimension
1891
+ activeFilterCount,
1892
+ clearFilters,
1893
+ customFrom,
1894
+ customTo,
1895
+ model,
1896
+ participantId,
1897
+ participantType,
1898
+ period,
1899
+ provider,
1900
+ setCustomFrom,
1901
+ setCustomTo,
1902
+ setModel,
1903
+ setParticipantId,
1904
+ setParticipantType,
1905
+ setProvider,
1906
+ setThreadId,
1907
+ threadId
1999
1908
  }
2000
1909
  )
2001
1910
  ] }),
2002
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "rounded-lg border bg-muted/30 p-3", children: [
2003
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "mb-3 flex items-center justify-between gap-3", children: [
2004
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-2 text-sm font-medium", children: [
2005
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react6.Filter, { className: "size-4" }),
2006
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "Filters" }),
2007
- activeFilterCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Badge, { variant: "secondary", children: activeFilterCount })
2008
- ] }),
2009
- activeFilterCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2010
- Button,
2011
- {
2012
- onClick: () => {
2013
- setParticipantType("all");
2014
- setThreadId("");
2015
- setParticipantId("");
2016
- setProvider("");
2017
- setModel("");
2018
- setCustomFrom("");
2019
- setCustomTo("");
2020
- },
2021
- size: "sm",
2022
- variant: "ghost",
2023
- children: "Clear"
2024
- }
2025
- )
2026
- ] }),
2027
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "grid gap-2 md:grid-cols-2 xl:grid-cols-6", children: [
2028
- period === "custom" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
2029
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2030
- FilterInput,
2031
- {
2032
- label: "From",
2033
- onChange: setCustomFrom,
2034
- type: "datetime-local",
2035
- value: customFrom
2036
- }
2037
- ),
2038
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2039
- FilterInput,
2040
- {
2041
- label: "To",
2042
- onChange: setCustomTo,
2043
- type: "datetime-local",
2044
- value: customTo
2045
- }
2046
- )
2047
- ] }),
2048
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2049
- UsageSelect,
2050
- {
2051
- label: "Type",
2052
- onValueChange: (value) => setParticipantType(
2053
- value
2054
- ),
2055
- options: [
2056
- ["all", "All"],
2057
- ["human", "Human"],
2058
- ["agent", "Agent"],
2059
- ["job", "Job"]
2060
- ],
2061
- value: participantType
2062
- }
2063
- ),
2064
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2065
- FilterInput,
2066
- {
2067
- icon: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react6.Search, { className: "size-3.5" }),
2068
- label: "Thread",
2069
- onChange: setThreadId,
2070
- value: threadId
2071
- }
2072
- ),
2073
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2074
- FilterInput,
2075
- {
2076
- icon: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react6.Users, { className: "size-3.5" }),
2077
- label: "Participant",
2078
- onChange: setParticipantId,
2079
- value: participantId
2080
- }
2081
- ),
2082
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2083
- FilterInput,
2084
- {
2085
- icon: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react6.Database, { className: "size-3.5" }),
2086
- label: "Provider",
2087
- onChange: setProvider,
2088
- value: provider
2089
- }
2090
- ),
2091
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2092
- FilterInput,
2093
- {
2094
- icon: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react6.Sparkles, { className: "size-3.5" }),
2095
- label: "Model",
2096
- onChange: setModel,
2097
- value: model
2098
- }
2099
- )
2100
- ] })
2101
- ] })
2102
- ] }) }),
2103
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Card, { className: "gap-3 overflow-hidden py-4", children: [
2104
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CardHeader, { className: "px-4 lg:px-5", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col gap-2 md:flex-row md:items-start md:justify-between", children: [
2105
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
2106
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CardTitle, { className: "text-base", children: getUsageSummaryLabel(config.labels, metricKind, dimension) }),
2107
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("p", { className: "mt-1 text-sm text-muted-foreground", children: [
2108
- formatMetricValue(
2109
- getUsageTotalValue(totals, metricKind, dimension),
2110
- metricKind
2111
- ),
2112
- " ",
2113
- "across ",
2114
- formatNumber(totals.totalCalls),
2115
- " calls"
2116
- ] })
2117
- ] }),
2118
- isLoading && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Badge, { variant: "outline", children: config.labels.loading })
2119
- ] }) }),
2120
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CardContent, { className: "px-2 lg:px-4", children: error ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "rounded-lg border border-destructive/30 bg-destructive/10 p-4 text-sm text-destructive", children: error }) : chartState.data.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2121
- EmptyDashboard,
2122
- {
2123
- description: config.labels.noResults,
2124
- title: "No usage"
2125
- }
2126
- ) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2127
- UsageChart,
1911
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1912
+ UsageSummary,
2128
1913
  {
2129
- chartState,
2130
- metricKind
1914
+ labels: config.labels,
1915
+ totals
2131
1916
  }
2132
- ) })
1917
+ )
2133
1918
  ] }),
1919
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Card, { className: "min-h-0 gap-0 overflow-hidden py-2", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CardContent, { className: "min-h-0 flex-1 px-2 lg:px-4", children: error ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "rounded-lg border border-destructive/30 bg-destructive/10 p-4 text-sm text-destructive", children: error }) : chartState.data.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1920
+ EmptyDashboard,
1921
+ {
1922
+ description: config.labels.noResults,
1923
+ title: "No usage"
1924
+ }
1925
+ ) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1926
+ UsageChart,
1927
+ {
1928
+ chartState,
1929
+ metricKind
1930
+ }
1931
+ ) }) }),
2134
1932
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2135
1933
  UsageTable,
2136
1934
  {
@@ -2151,9 +1949,7 @@ function UsageDashboard({
2151
1949
  ] });
2152
1950
  }
2153
1951
  function UsageSummary({
2154
- dimension,
2155
1952
  labels,
2156
- metricKind,
2157
1953
  totals
2158
1954
  }) {
2159
1955
  const summary = [
@@ -2170,28 +1966,19 @@ function UsageSummary({
2170
1966
  icon: import_lucide_react6.Activity
2171
1967
  },
2172
1968
  {
2173
- label: labels.usageCacheRead,
2174
- value: formatMetricValue(totals.cacheReadInputCostUsd, "cost"),
2175
- detail: `${formatMetricValue(totals.cacheReadInputTokens, "tokens")} tokens`,
2176
- icon: import_lucide_react6.Database
2177
- },
2178
- {
2179
- label: getUsageSummaryLabel(labels, metricKind, dimension),
2180
- value: formatMetricValue(
2181
- getUsageTotalValue(totals, metricKind, dimension),
2182
- metricKind
2183
- ),
2184
- detail: labels.usageTotal,
1969
+ label: "Calls",
1970
+ value: formatMetricValue(totals.totalCalls, "calls"),
1971
+ detail: totals.totalCalls > 0 ? `${formatMetricValue(totals.totalCostUsd / totals.totalCalls, "cost")} avg` : "No calls",
2185
1972
  icon: import_lucide_react6.Sparkles
2186
1973
  }
2187
1974
  ];
2188
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "grid gap-3 sm:grid-cols-2 xl:grid-cols-4", children: summary.map((item) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Card, { className: "gap-3 py-4", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CardContent, { className: "px-4", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-start justify-between gap-3", children: [
1975
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "grid gap-2 md:grid-cols-3", children: summary.map((item) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Card, { className: "gap-0 rounded-lg py-2 shadow-xs", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CardContent, { className: "px-3", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center justify-between gap-3", children: [
2189
1976
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "min-w-0", children: [
2190
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "truncate text-sm text-muted-foreground", children: item.label }),
2191
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "mt-1 truncate text-2xl font-semibold tracking-tight", children: item.value }),
2192
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "mt-1 truncate text-xs text-muted-foreground", children: item.detail })
1977
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "truncate text-xs text-muted-foreground", children: item.label }),
1978
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "truncate text-lg font-semibold tracking-tight", children: item.value }),
1979
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "truncate text-[11px] text-muted-foreground", children: item.detail })
2193
1980
  ] }),
2194
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "rounded-md border bg-muted/50 p-2 text-muted-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(item.icon, { className: "size-4" }) })
1981
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "rounded-md border bg-muted/50 p-1.5 text-muted-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(item.icon, { className: "size-4" }) })
2195
1982
  ] }) }) }, item.label)) });
2196
1983
  }
2197
1984
  function UsageChart({
@@ -2201,7 +1988,7 @@ function UsageChart({
2201
1988
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2202
1989
  ChartContainer,
2203
1990
  {
2204
- className: "h-[320px] w-full",
1991
+ className: "h-full min-h-[220px] w-full",
2205
1992
  config: chartState.config,
2206
1993
  children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2207
1994
  import_recharts.BarChart,
@@ -2230,7 +2017,7 @@ function UsageChart({
2230
2017
  }
2231
2018
  ),
2232
2019
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2233
- import_recharts.Tooltip,
2020
+ Tooltip,
2234
2021
  {
2235
2022
  content: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2236
2023
  ChartTooltipContent,
@@ -2275,97 +2062,343 @@ function UsageTable({
2275
2062
  }) {
2276
2063
  const totalValue = getUsageTotalValue(totals, metricKind, dimension);
2277
2064
  const filterable = groupBy !== "namespace";
2278
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Card, { className: "gap-3 py-4", children: [
2279
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CardHeader, { className: "px-4 lg:px-5", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between", children: [
2280
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CardTitle, { className: "text-base", children: "Usage detail" }),
2281
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Badge, { variant: "outline", children: [
2282
- formatNumber(rows.length),
2283
- " ",
2284
- getGroupByLabel(groupBy).toLowerCase()
2285
- ] })
2065
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Card, { className: "min-h-0 gap-0 overflow-hidden py-0", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CardContent, { className: "min-h-0 flex-1 overflow-hidden px-0", children: rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "px-5 py-4 text-sm text-muted-foreground", children: labels.noResults }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "h-full overflow-auto", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("table", { className: "w-full min-w-[940px] text-sm", children: [
2066
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("thead", { className: "sticky top-0 z-10 bg-card", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("tr", { className: "border-b text-left text-xs uppercase tracking-[0.12em] text-muted-foreground", children: [
2067
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { className: "px-5 py-2.5 font-medium", children: getGroupByLabel(groupBy) }),
2068
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { className: "px-3 py-2.5 text-right font-medium", children: getUsageSummaryLabel(labels, metricKind, dimension) }),
2069
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { className: "px-3 py-2.5 text-right font-medium", children: "Share" }),
2070
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { className: "px-3 py-2.5 text-right font-medium", children: "Calls" }),
2071
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { className: "px-3 py-2.5 text-right font-medium", children: "Input" }),
2072
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { className: "px-3 py-2.5 text-right font-medium", children: "Output" }),
2073
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { className: "px-3 py-2.5 text-right font-medium", children: "Reasoning" }),
2074
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { className: "px-3 py-2.5 text-right font-medium", children: "Cache read" }),
2075
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { className: "px-5 py-2.5 text-right font-medium", children: "Avg/call" })
2286
2076
  ] }) }),
2287
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CardContent, { className: "px-0", children: rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "px-5 py-4 text-sm text-muted-foreground", children: labels.noResults }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("table", { className: "w-full min-w-[940px] text-sm", children: [
2288
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("tr", { className: "border-b text-left text-xs uppercase tracking-[0.12em] text-muted-foreground", children: [
2289
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { className: "px-5 py-2.5 font-medium", children: getGroupByLabel(groupBy) }),
2290
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { className: "px-3 py-2.5 text-right font-medium", children: getUsageSummaryLabel(labels, metricKind, dimension) }),
2291
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { className: "px-3 py-2.5 text-right font-medium", children: "Share" }),
2292
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { className: "px-3 py-2.5 text-right font-medium", children: "Calls" }),
2293
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { className: "px-3 py-2.5 text-right font-medium", children: "Input" }),
2294
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { className: "px-3 py-2.5 text-right font-medium", children: "Output" }),
2295
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { className: "px-3 py-2.5 text-right font-medium", children: "Reasoning" }),
2296
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { className: "px-3 py-2.5 text-right font-medium", children: "Cache read" }),
2297
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { className: "px-5 py-2.5 text-right font-medium", children: "Avg/call" })
2298
- ] }) }),
2299
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("tbody", { children: rows.slice(0, 60).map((row) => {
2300
- const share = totalValue > 0 ? row.value / totalValue : 0;
2301
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2302
- "tr",
2303
- {
2304
- className: cn(
2305
- "border-b last:border-0",
2306
- filterable && "cursor-pointer transition-colors hover:bg-muted/50"
2307
- ),
2308
- onClick: () => filterable && onRowFilter(row),
2309
- children: [
2310
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("td", { className: "px-5 py-3", children: [
2311
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "max-w-80 truncate font-medium", children: row.groupLabel }),
2312
- row.groupKey !== row.groupLabel && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "mt-0.5 max-w-80 truncate text-xs text-muted-foreground", children: row.groupKey })
2313
- ] }),
2314
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { className: "px-3 py-3 text-right font-medium", children: formatMetricValue(row.value, metricKind) }),
2315
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { className: "px-3 py-3 text-right", children: formatPercent(share) }),
2316
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { className: "px-3 py-3 text-right", children: formatNumber(row.totalCalls) }),
2317
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { className: "px-3 py-3 text-right", children: formatMetricValue(
2318
- getUsageTotalValue(row, metricKind, "input"),
2319
- metricKind
2320
- ) }),
2321
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { className: "px-3 py-3 text-right", children: formatMetricValue(
2322
- getUsageTotalValue(row, metricKind, "output"),
2323
- metricKind
2324
- ) }),
2325
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { className: "px-3 py-3 text-right", children: formatMetricValue(
2326
- getUsageTotalValue(row, metricKind, "reasoning"),
2327
- metricKind
2328
- ) }),
2329
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { className: "px-3 py-3 text-right", children: formatMetricValue(
2330
- getUsageTotalValue(row, metricKind, "cacheRead"),
2331
- metricKind
2332
- ) }),
2333
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { className: "px-5 py-3 text-right", children: formatMetricValue(
2334
- row.totalCalls > 0 ? row.value / row.totalCalls : 0,
2335
- metricKind
2336
- ) })
2337
- ]
2338
- },
2339
- row.groupKey
2340
- );
2341
- }) })
2342
- ] }) }) })
2343
- ] });
2077
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("tbody", { children: rows.slice(0, 60).map((row) => {
2078
+ const share = totalValue > 0 ? row.value / totalValue : 0;
2079
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2080
+ "tr",
2081
+ {
2082
+ className: cn(
2083
+ "border-b last:border-0",
2084
+ filterable && "cursor-pointer transition-colors hover:bg-muted/50"
2085
+ ),
2086
+ onClick: () => filterable && onRowFilter(row),
2087
+ children: [
2088
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("td", { className: "px-5 py-3", children: [
2089
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "max-w-80 truncate font-medium", children: row.groupLabel }),
2090
+ row.groupKey !== row.groupLabel && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "mt-0.5 max-w-80 truncate text-xs text-muted-foreground", children: row.groupKey })
2091
+ ] }),
2092
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { className: "px-3 py-3 text-right font-medium", children: formatMetricValue(row.value, metricKind) }),
2093
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { className: "px-3 py-3 text-right", children: formatPercent(share) }),
2094
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { className: "px-3 py-3 text-right", children: formatNumber(row.totalCalls) }),
2095
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { className: "px-3 py-3 text-right", children: formatMetricValue(
2096
+ getUsageTotalValue(row, metricKind, "input"),
2097
+ metricKind
2098
+ ) }),
2099
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { className: "px-3 py-3 text-right", children: formatMetricValue(
2100
+ getUsageTotalValue(row, metricKind, "output"),
2101
+ metricKind
2102
+ ) }),
2103
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { className: "px-3 py-3 text-right", children: formatMetricValue(
2104
+ getUsageTotalValue(row, metricKind, "reasoning"),
2105
+ metricKind
2106
+ ) }),
2107
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { className: "px-3 py-3 text-right", children: formatMetricValue(
2108
+ getUsageTotalValue(row, metricKind, "cacheRead"),
2109
+ metricKind
2110
+ ) }),
2111
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { className: "px-5 py-3 text-right", children: formatMetricValue(
2112
+ row.totalCalls > 0 ? row.value / row.totalCalls : 0,
2113
+ metricKind
2114
+ ) })
2115
+ ]
2116
+ },
2117
+ row.groupKey
2118
+ );
2119
+ }) })
2120
+ ] }) }) }) });
2344
2121
  }
2345
- function UsageSelect(props) {
2346
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("label", { className: "space-y-1", children: [
2347
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-[11px] font-medium uppercase tracking-[0.16em] text-muted-foreground", children: props.label }),
2348
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Select, { value: props.value, onValueChange: props.onValueChange, children: [
2349
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SelectTrigger, { className: "h-9 w-full min-w-0 bg-background", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SelectValue, {}) }),
2350
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SelectContent, { children: props.options.map(([value, label]) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SelectItem, { value, children: label }, value)) })
2351
- ] })
2122
+ function DashboardHeaderControls({
2123
+ attribution,
2124
+ bucket,
2125
+ config,
2126
+ dimension,
2127
+ groupBy,
2128
+ metricKind,
2129
+ period,
2130
+ setAttribution,
2131
+ setBucket,
2132
+ setDimension,
2133
+ setGroupBy,
2134
+ setMetricKind,
2135
+ setPeriod
2136
+ }) {
2137
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-1.5", children: [
2138
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2139
+ HeaderSelect,
2140
+ {
2141
+ label: "Period",
2142
+ onValueChange: (value) => setPeriod(value),
2143
+ options: [
2144
+ ["24h", config.labels.range24h],
2145
+ ["7d", config.labels.range7d],
2146
+ ["30d", config.labels.range30d],
2147
+ ["custom", "Custom"]
2148
+ ],
2149
+ value: period,
2150
+ width: "w-[86px]"
2151
+ }
2152
+ ),
2153
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2154
+ HeaderSelect,
2155
+ {
2156
+ label: "Bucket",
2157
+ onValueChange: (value) => setBucket(value),
2158
+ options: [
2159
+ ["minute", "Minute"],
2160
+ ["hour", "Hour"],
2161
+ ["day", "Day"],
2162
+ ["week", "Week"],
2163
+ ["month", "Month"]
2164
+ ],
2165
+ value: bucket,
2166
+ width: "w-[92px]"
2167
+ }
2168
+ ),
2169
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2170
+ HeaderSelect,
2171
+ {
2172
+ label: config.labels.usageMetricLabel,
2173
+ onValueChange: (value) => setMetricKind(value),
2174
+ options: [
2175
+ ["cost", config.labels.usageMetricCost],
2176
+ ["tokens", config.labels.usageMetricTokens],
2177
+ ["calls", "Calls"]
2178
+ ],
2179
+ value: metricKind,
2180
+ width: "w-[94px]"
2181
+ }
2182
+ ),
2183
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2184
+ HeaderSelect,
2185
+ {
2186
+ label: "Group",
2187
+ onValueChange: (value) => setGroupBy(value),
2188
+ options: [
2189
+ ["participant", "Participant"],
2190
+ ["thread", "Thread"],
2191
+ ["namespace", "Namespace"],
2192
+ ["provider", "Provider"],
2193
+ ["model", "Model"]
2194
+ ],
2195
+ value: groupBy,
2196
+ width: "w-[128px]"
2197
+ }
2198
+ ),
2199
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2200
+ HeaderSelect,
2201
+ {
2202
+ label: "Attribution",
2203
+ onValueChange: (value) => setAttribution(value),
2204
+ options: [
2205
+ ["initiatedBy", "Initiated by"],
2206
+ ["generatedBy", "Generated by"]
2207
+ ],
2208
+ value: attribution,
2209
+ width: "w-[132px]"
2210
+ }
2211
+ ),
2212
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2213
+ HeaderSelect,
2214
+ {
2215
+ label: config.labels.usageDimensionLabel,
2216
+ onValueChange: (value) => setDimension(value),
2217
+ options: USAGE_DIMENSIONS.map((nextDimension) => [
2218
+ nextDimension,
2219
+ getUsageDimensionLabel(config.labels, nextDimension)
2220
+ ]),
2221
+ value: dimension,
2222
+ width: "w-[116px]"
2223
+ }
2224
+ )
2352
2225
  ] });
2353
2226
  }
2354
- function FilterInput(props) {
2355
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("label", { className: "space-y-1", children: [
2356
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-[11px] font-medium uppercase tracking-[0.16em] text-muted-foreground", children: props.label }),
2357
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "relative", children: [
2358
- props.icon && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground", children: props.icon }),
2227
+ function InlineFilters({
2228
+ activeFilterCount,
2229
+ clearFilters,
2230
+ customFrom,
2231
+ customTo,
2232
+ model,
2233
+ participantId,
2234
+ participantType,
2235
+ period,
2236
+ provider,
2237
+ setCustomFrom,
2238
+ setCustomTo,
2239
+ setModel,
2240
+ setParticipantId,
2241
+ setParticipantType,
2242
+ setProvider,
2243
+ setThreadId,
2244
+ threadId
2245
+ }) {
2246
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex max-w-full flex-wrap items-end justify-end gap-2", children: [
2247
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-2 pb-1 text-xs font-medium text-muted-foreground", children: [
2248
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react6.Filter, { className: "size-3.5" }),
2249
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "Filters" }),
2250
+ activeFilterCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Badge, { variant: "secondary", children: activeFilterCount })
2251
+ ] }),
2252
+ period === "custom" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
2359
2253
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2360
- Input,
2254
+ FilterInput,
2255
+ {
2256
+ compact: true,
2257
+ label: "From",
2258
+ onChange: setCustomFrom,
2259
+ type: "datetime-local",
2260
+ value: customFrom
2261
+ }
2262
+ ),
2263
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2264
+ FilterInput,
2361
2265
  {
2362
- className: cn("h-9 bg-background", props.icon && "pl-8"),
2363
- onChange: (event) => props.onChange(event.target.value),
2364
- type: props.type ?? "text",
2365
- value: props.value
2266
+ compact: true,
2267
+ label: "To",
2268
+ onChange: setCustomTo,
2269
+ type: "datetime-local",
2270
+ value: customTo
2366
2271
  }
2367
2272
  )
2368
- ] })
2273
+ ] }),
2274
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2275
+ UsageSelect,
2276
+ {
2277
+ compact: true,
2278
+ label: "Type",
2279
+ onValueChange: (value) => setParticipantType(value),
2280
+ options: [
2281
+ ["all", "All"],
2282
+ ["human", "Human"],
2283
+ ["agent", "Agent"],
2284
+ ["job", "Job"]
2285
+ ],
2286
+ value: participantType
2287
+ }
2288
+ ),
2289
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2290
+ FilterInput,
2291
+ {
2292
+ compact: true,
2293
+ icon: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react6.Search, { className: "size-3.5" }),
2294
+ label: "Thread",
2295
+ onChange: setThreadId,
2296
+ value: threadId
2297
+ }
2298
+ ),
2299
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2300
+ FilterInput,
2301
+ {
2302
+ compact: true,
2303
+ icon: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react6.Users, { className: "size-3.5" }),
2304
+ label: "Participant",
2305
+ onChange: setParticipantId,
2306
+ value: participantId
2307
+ }
2308
+ ),
2309
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2310
+ FilterInput,
2311
+ {
2312
+ compact: true,
2313
+ icon: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react6.Database, { className: "size-3.5" }),
2314
+ label: "Provider",
2315
+ onChange: setProvider,
2316
+ value: provider
2317
+ }
2318
+ ),
2319
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2320
+ FilterInput,
2321
+ {
2322
+ compact: true,
2323
+ icon: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react6.Sparkles, { className: "size-3.5" }),
2324
+ label: "Model",
2325
+ onChange: setModel,
2326
+ value: model
2327
+ }
2328
+ ),
2329
+ activeFilterCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2330
+ Button,
2331
+ {
2332
+ className: "h-8",
2333
+ onClick: clearFilters,
2334
+ size: "sm",
2335
+ variant: "ghost",
2336
+ children: "Clear"
2337
+ }
2338
+ )
2339
+ ] });
2340
+ }
2341
+ function HeaderSelect(props) {
2342
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Tooltip, { children: [
2343
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Select, { value: props.value, onValueChange: props.onValueChange, children: [
2344
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2345
+ SelectTrigger,
2346
+ {
2347
+ "aria-label": props.label,
2348
+ className: cn("h-8 bg-background text-xs", props.width),
2349
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SelectValue, {})
2350
+ }
2351
+ ) }),
2352
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SelectContent, { children: props.options.map(([value, label]) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SelectItem, { value, children: label }, value)) })
2353
+ ] }),
2354
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TooltipContent, { children: props.label })
2355
+ ] });
2356
+ }
2357
+ function UsageSelect(props) {
2358
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Tooltip, { children: [
2359
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("label", { className: cn("space-y-1", props.compact && "w-[116px]"), children: [
2360
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "sr-only", children: props.label }),
2361
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Select, { value: props.value, onValueChange: props.onValueChange, children: [
2362
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2363
+ SelectTrigger,
2364
+ {
2365
+ "aria-label": props.label,
2366
+ className: cn(
2367
+ "w-full min-w-0 bg-background",
2368
+ props.compact ? "h-8 text-xs" : "h-9"
2369
+ ),
2370
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SelectValue, {})
2371
+ }
2372
+ ) }),
2373
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SelectContent, { children: props.options.map(([value, label]) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SelectItem, { value, children: label }, value)) })
2374
+ ] })
2375
+ ] }),
2376
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TooltipContent, { children: props.label })
2377
+ ] });
2378
+ }
2379
+ function FilterInput(props) {
2380
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Tooltip, { children: [
2381
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("label", { className: cn("space-y-1", props.compact && "w-[150px]"), children: [
2382
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "sr-only", children: props.label }),
2383
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "relative", children: [
2384
+ props.icon && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground", children: props.icon }),
2385
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2386
+ Input,
2387
+ {
2388
+ "aria-label": props.label,
2389
+ className: cn(
2390
+ "bg-background",
2391
+ props.compact ? "h-8 text-xs" : "h-9",
2392
+ props.icon && "pl-8"
2393
+ ),
2394
+ onChange: (event) => props.onChange(event.target.value),
2395
+ type: props.type ?? "text",
2396
+ value: props.value
2397
+ }
2398
+ )
2399
+ ] }) })
2400
+ ] }),
2401
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TooltipContent, { children: props.label })
2369
2402
  ] });
2370
2403
  }
2371
2404
  function EmptyDashboard({
@@ -3610,6 +3643,8 @@ var CopilotzAdmin = ({
3610
3643
  const [route, setRoute] = (0, import_react8.useState)({ page: config.defaultPage });
3611
3644
  const [namespace, setNamespace] = (0, import_react8.useState)(config.namespace);
3612
3645
  const [collections, setCollections] = (0, import_react8.useState)([]);
3646
+ const [headerControls, setHeaderControls] = (0, import_react8.useState)(null);
3647
+ const [headerRefresh, setHeaderRefresh] = (0, import_react8.useState)(null);
3613
3648
  const [threadSearch, setThreadSearch] = (0, import_react8.useState)("");
3614
3649
  const [participantSearch, setParticipantSearch] = (0, import_react8.useState)("");
3615
3650
  const [agentSearch, setAgentSearch] = (0, import_react8.useState)("");
@@ -3718,7 +3753,9 @@ var CopilotzAdmin = ({
3718
3753
  onThreadSearchChange: setThreadSearch,
3719
3754
  onParticipantSearchChange: setParticipantSearch,
3720
3755
  onAgentSearchChange: setAgentSearch,
3721
- onThreadClick: handleThreadClick
3756
+ onThreadClick: handleThreadClick,
3757
+ setHeaderControls,
3758
+ setHeaderRefresh
3722
3759
  }
3723
3760
  );
3724
3761
  case "threads":
@@ -3815,15 +3852,18 @@ var CopilotzAdmin = ({
3815
3852
  {
3816
3853
  config,
3817
3854
  currentRoute: route,
3818
- range: admin.filters.range,
3819
- interval: admin.filters.interval,
3820
- onRangeChange: admin.setRange,
3821
- onIntervalChange: admin.setInterval,
3822
- onRefresh: () => void admin.refresh(),
3823
- isLoading: admin.isLoading
3855
+ onRefresh: () => {
3856
+ if (route.page === "dashboard" && headerRefresh) {
3857
+ headerRefresh();
3858
+ return;
3859
+ }
3860
+ void admin.refresh();
3861
+ },
3862
+ isLoading: admin.isLoading,
3863
+ controls: route.page === "dashboard" ? headerControls : null
3824
3864
  }
3825
3865
  ),
3826
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex-1 overflow-auto p-6", children: renderCurrentView() })
3866
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex-1 overflow-auto p-4", children: renderCurrentView() })
3827
3867
  ] }) })
3828
3868
  ]
3829
3869
  }