@copilotz/admin 0.9.23 → 0.9.25
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 +458 -74
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +30 -2
- package/dist/index.d.ts +30 -2
- package/dist/index.js +458 -75
- package/dist/index.js.map +1 -1
- package/dist/styles.css +57 -35
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -39,6 +39,7 @@ __export(index_exports, {
|
|
|
39
39
|
fetchAdminOverview: () => fetchAdminOverview,
|
|
40
40
|
fetchAdminParticipants: () => fetchAdminParticipants,
|
|
41
41
|
fetchAdminThreads: () => fetchAdminThreads,
|
|
42
|
+
fetchAdminUsage: () => fetchAdminUsage,
|
|
42
43
|
fetchCollectionItem: () => fetchCollectionItem,
|
|
43
44
|
fetchCollectionItems: () => fetchCollectionItems,
|
|
44
45
|
fetchCollectionNames: () => fetchCollectionNames,
|
|
@@ -299,6 +300,21 @@ async function fetchAdminAgents(search, namespace, options) {
|
|
|
299
300
|
limit: "8"
|
|
300
301
|
}, options);
|
|
301
302
|
}
|
|
303
|
+
async function fetchAdminUsage(filters, options) {
|
|
304
|
+
return await fetchAdminJson("/v1/admin/usage", {
|
|
305
|
+
from: filters.from,
|
|
306
|
+
to: filters.to,
|
|
307
|
+
interval: filters.interval,
|
|
308
|
+
metric: filters.metric,
|
|
309
|
+
groupBy: filters.groupBy,
|
|
310
|
+
threadId: filters.threadId,
|
|
311
|
+
participantId: filters.participantId,
|
|
312
|
+
participantType: filters.participantType,
|
|
313
|
+
namespace: filters.namespace,
|
|
314
|
+
provider: filters.provider,
|
|
315
|
+
model: filters.model
|
|
316
|
+
}, options);
|
|
317
|
+
}
|
|
302
318
|
async function fetchThreadDetail(threadId, options) {
|
|
303
319
|
return await fetchAdminJson(
|
|
304
320
|
`/v1/threads/${encodeURIComponent(threadId)}`,
|
|
@@ -1603,10 +1619,11 @@ var DashboardView = ({
|
|
|
1603
1619
|
onThreadSearchChange,
|
|
1604
1620
|
onParticipantSearchChange,
|
|
1605
1621
|
onAgentSearchChange,
|
|
1606
|
-
onThreadClick
|
|
1622
|
+
onThreadClick,
|
|
1623
|
+
namespace
|
|
1607
1624
|
}) => {
|
|
1608
1625
|
const [usageMetricKind, setUsageMetricKind] = import_react2.default.useState(
|
|
1609
|
-
"
|
|
1626
|
+
"cost"
|
|
1610
1627
|
);
|
|
1611
1628
|
const [usageDimension, setUsageDimension] = import_react2.default.useState(
|
|
1612
1629
|
"total"
|
|
@@ -1617,11 +1634,6 @@ var DashboardView = ({
|
|
|
1617
1634
|
usageMetricKind,
|
|
1618
1635
|
usageDimension
|
|
1619
1636
|
);
|
|
1620
|
-
const usageBreakdownCards = USAGE_DIMENSIONS.map((dimension) => ({
|
|
1621
|
-
dimension,
|
|
1622
|
-
label: getUsageDimensionLabel(config.labels, dimension),
|
|
1623
|
-
value: overview ? getOverviewUsageValue(overview, usageMetricKind, dimension) : 0
|
|
1624
|
-
}));
|
|
1625
1637
|
const cards = [
|
|
1626
1638
|
{
|
|
1627
1639
|
label: config.labels.messagesCard,
|
|
@@ -1636,7 +1648,7 @@ var DashboardView = ({
|
|
|
1636
1648
|
{
|
|
1637
1649
|
label: config.labels.participantsCard,
|
|
1638
1650
|
value: overview?.participantTotals.total ?? 0,
|
|
1639
|
-
detail: `${overview?.participantTotals.agents ?? 0} agents`
|
|
1651
|
+
detail: `${overview?.participantTotals.agents ?? 0} agents, ${overview?.participantTotals.jobs ?? 0} jobs`
|
|
1640
1652
|
},
|
|
1641
1653
|
{
|
|
1642
1654
|
label: llmSummaryLabel,
|
|
@@ -1674,71 +1686,17 @@ var DashboardView = ({
|
|
|
1674
1686
|
card.label
|
|
1675
1687
|
)) })
|
|
1676
1688
|
] }),
|
|
1677
|
-
config.features.showOverview && /* @__PURE__ */ (0, import_jsx_runtime12.
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
children: [
|
|
1689
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SelectTrigger, { className: "h-9 w-full min-w-[160px]", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SelectValue, {}) }),
|
|
1690
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(SelectContent, { children: [
|
|
1691
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SelectItem, { value: "tokens", children: config.labels.usageMetricTokens }),
|
|
1692
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SelectItem, { value: "cost", children: config.labels.usageMetricCost })
|
|
1693
|
-
] })
|
|
1694
|
-
]
|
|
1695
|
-
}
|
|
1696
|
-
)
|
|
1697
|
-
] }),
|
|
1698
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "space-y-1", children: [
|
|
1699
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-xs font-medium uppercase tracking-[0.18em] text-muted-foreground", children: config.labels.usageDimensionLabel }),
|
|
1700
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
1701
|
-
Select,
|
|
1702
|
-
{
|
|
1703
|
-
value: usageDimension,
|
|
1704
|
-
onValueChange: (value) => setUsageDimension(value),
|
|
1705
|
-
children: [
|
|
1706
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SelectTrigger, { className: "h-9 w-full min-w-[160px]", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SelectValue, {}) }),
|
|
1707
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SelectContent, { children: USAGE_DIMENSIONS.map((dimension) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SelectItem, { value: dimension, children: getUsageDimensionLabel(config.labels, dimension) }, dimension)) })
|
|
1708
|
-
]
|
|
1709
|
-
}
|
|
1710
|
-
)
|
|
1711
|
-
] })
|
|
1712
|
-
] })
|
|
1713
|
-
] }),
|
|
1714
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "grid gap-4 sm:grid-cols-2 xl:grid-cols-3", children: usageBreakdownCards.map((card) => {
|
|
1715
|
-
const isSelected = card.dimension === usageDimension;
|
|
1716
|
-
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
1717
|
-
"div",
|
|
1718
|
-
{
|
|
1719
|
-
className: cn(
|
|
1720
|
-
"rounded-xl border bg-card p-5 shadow-sm transition-colors",
|
|
1721
|
-
isSelected && "border-primary/60 ring-1 ring-primary/15"
|
|
1722
|
-
),
|
|
1723
|
-
children: [
|
|
1724
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-start justify-between gap-3", children: [
|
|
1725
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
1726
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm font-medium text-muted-foreground", children: card.label }),
|
|
1727
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "mt-3 text-2xl font-semibold tracking-tight", children: formatMetricValue(card.value, usageMetricKind) })
|
|
1728
|
-
] }),
|
|
1729
|
-
isSelected && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Badge, { variant: "outline", children: config.labels.usageDimensionLabel })
|
|
1730
|
-
] }),
|
|
1731
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("p", { className: "mt-2 text-xs text-muted-foreground", children: [
|
|
1732
|
-
overview?.llmTotals.totalCalls ?? 0,
|
|
1733
|
-
" ",
|
|
1734
|
-
config.labels.usageCallsDetail
|
|
1735
|
-
] })
|
|
1736
|
-
]
|
|
1737
|
-
},
|
|
1738
|
-
card.dimension
|
|
1739
|
-
);
|
|
1740
|
-
}) })
|
|
1741
|
-
] }),
|
|
1689
|
+
config.features.showOverview && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1690
|
+
UsageExplorer,
|
|
1691
|
+
{
|
|
1692
|
+
config,
|
|
1693
|
+
metricKind: usageMetricKind,
|
|
1694
|
+
namespace,
|
|
1695
|
+
onDimensionChange: setUsageDimension,
|
|
1696
|
+
onMetricKindChange: setUsageMetricKind,
|
|
1697
|
+
selectedDimension: usageDimension
|
|
1698
|
+
}
|
|
1699
|
+
),
|
|
1742
1700
|
config.features.showActivity && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("section", { className: "space-y-4", children: [
|
|
1743
1701
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SectionHeading, { title: config.labels.activityTitle }),
|
|
1744
1702
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
@@ -1808,6 +1766,318 @@ var DashboardView = ({
|
|
|
1808
1766
|
function SectionHeading({ title }) {
|
|
1809
1767
|
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h3", { className: "text-lg font-semibold tracking-tight", children: title });
|
|
1810
1768
|
}
|
|
1769
|
+
function UsageExplorer(props) {
|
|
1770
|
+
const [period, setPeriod] = import_react2.default.useState("7d");
|
|
1771
|
+
const [bucket, setBucket] = import_react2.default.useState("day");
|
|
1772
|
+
const [groupBy, setGroupBy] = import_react2.default.useState("participant");
|
|
1773
|
+
const [participantType, setParticipantType] = import_react2.default.useState("all");
|
|
1774
|
+
const [threadId, setThreadId] = import_react2.default.useState("");
|
|
1775
|
+
const [participantId, setParticipantId] = import_react2.default.useState("");
|
|
1776
|
+
const [provider, setProvider] = import_react2.default.useState("");
|
|
1777
|
+
const [model, setModel] = import_react2.default.useState("");
|
|
1778
|
+
const [customFrom, setCustomFrom] = import_react2.default.useState("");
|
|
1779
|
+
const [customTo, setCustomTo] = import_react2.default.useState("");
|
|
1780
|
+
const [usage, setUsage] = import_react2.default.useState(null);
|
|
1781
|
+
const [isLoading, setIsLoading] = import_react2.default.useState(false);
|
|
1782
|
+
const [error, setError] = import_react2.default.useState(null);
|
|
1783
|
+
const range = import_react2.default.useMemo(() => getUsageRange(period, customFrom, customTo), [
|
|
1784
|
+
customFrom,
|
|
1785
|
+
customTo,
|
|
1786
|
+
period
|
|
1787
|
+
]);
|
|
1788
|
+
const loadUsage = import_react2.default.useCallback(async () => {
|
|
1789
|
+
setIsLoading(true);
|
|
1790
|
+
setError(null);
|
|
1791
|
+
try {
|
|
1792
|
+
const next = await fetchAdminUsage({
|
|
1793
|
+
from: range.from,
|
|
1794
|
+
to: range.to,
|
|
1795
|
+
interval: bucket,
|
|
1796
|
+
metric: props.metricKind,
|
|
1797
|
+
groupBy,
|
|
1798
|
+
namespace: props.namespace || void 0,
|
|
1799
|
+
participantType,
|
|
1800
|
+
threadId: emptyToUndefined(threadId),
|
|
1801
|
+
participantId: emptyToUndefined(participantId),
|
|
1802
|
+
provider: emptyToUndefined(provider),
|
|
1803
|
+
model: emptyToUndefined(model)
|
|
1804
|
+
}, {
|
|
1805
|
+
baseUrl: props.config.baseUrl,
|
|
1806
|
+
getRequestHeaders: props.config.getRequestHeaders
|
|
1807
|
+
});
|
|
1808
|
+
setUsage(next);
|
|
1809
|
+
} catch (err) {
|
|
1810
|
+
setError(err instanceof Error ? err.message : "Failed to load usage");
|
|
1811
|
+
setUsage(null);
|
|
1812
|
+
} finally {
|
|
1813
|
+
setIsLoading(false);
|
|
1814
|
+
}
|
|
1815
|
+
}, [
|
|
1816
|
+
bucket,
|
|
1817
|
+
groupBy,
|
|
1818
|
+
model,
|
|
1819
|
+
participantId,
|
|
1820
|
+
participantType,
|
|
1821
|
+
props.config.baseUrl,
|
|
1822
|
+
props.config.getRequestHeaders,
|
|
1823
|
+
props.metricKind,
|
|
1824
|
+
props.namespace,
|
|
1825
|
+
provider,
|
|
1826
|
+
range.from,
|
|
1827
|
+
range.to,
|
|
1828
|
+
threadId
|
|
1829
|
+
]);
|
|
1830
|
+
import_react2.default.useEffect(() => {
|
|
1831
|
+
void loadUsage();
|
|
1832
|
+
}, [loadUsage]);
|
|
1833
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("section", { className: "space-y-4", children: [
|
|
1834
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex flex-col gap-3 lg:flex-row lg:items-end lg:justify-between", children: [
|
|
1835
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SectionHeading, { title: props.config.labels.llmUsageTitle }),
|
|
1836
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "grid gap-3 sm:grid-cols-2 lg:grid-cols-5", children: [
|
|
1837
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1838
|
+
UsageSelect,
|
|
1839
|
+
{
|
|
1840
|
+
label: "Period",
|
|
1841
|
+
value: period,
|
|
1842
|
+
onValueChange: (value) => setPeriod(value),
|
|
1843
|
+
options: [
|
|
1844
|
+
["24h", props.config.labels.range24h],
|
|
1845
|
+
["7d", props.config.labels.range7d],
|
|
1846
|
+
["30d", props.config.labels.range30d],
|
|
1847
|
+
["custom", "Custom"]
|
|
1848
|
+
]
|
|
1849
|
+
}
|
|
1850
|
+
),
|
|
1851
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1852
|
+
UsageSelect,
|
|
1853
|
+
{
|
|
1854
|
+
label: "Bucket",
|
|
1855
|
+
value: bucket,
|
|
1856
|
+
onValueChange: (value) => setBucket(value),
|
|
1857
|
+
options: [
|
|
1858
|
+
["minute", "Minute"],
|
|
1859
|
+
["hour", "Hour"],
|
|
1860
|
+
["day", "Day"],
|
|
1861
|
+
["week", "Week"],
|
|
1862
|
+
["month", "Month"]
|
|
1863
|
+
]
|
|
1864
|
+
}
|
|
1865
|
+
),
|
|
1866
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1867
|
+
UsageSelect,
|
|
1868
|
+
{
|
|
1869
|
+
label: props.config.labels.usageMetricLabel,
|
|
1870
|
+
value: props.metricKind,
|
|
1871
|
+
onValueChange: (value) => props.onMetricKindChange(value),
|
|
1872
|
+
options: [
|
|
1873
|
+
["cost", props.config.labels.usageMetricCost],
|
|
1874
|
+
["tokens", props.config.labels.usageMetricTokens],
|
|
1875
|
+
["calls", "Calls"]
|
|
1876
|
+
]
|
|
1877
|
+
}
|
|
1878
|
+
),
|
|
1879
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1880
|
+
UsageSelect,
|
|
1881
|
+
{
|
|
1882
|
+
label: "Group by",
|
|
1883
|
+
value: groupBy,
|
|
1884
|
+
onValueChange: (value) => setGroupBy(value),
|
|
1885
|
+
options: [
|
|
1886
|
+
["participant", "Participant"],
|
|
1887
|
+
["thread", "Thread"],
|
|
1888
|
+
["namespace", "Namespace"],
|
|
1889
|
+
["provider", "Provider"],
|
|
1890
|
+
["model", "Model"]
|
|
1891
|
+
]
|
|
1892
|
+
}
|
|
1893
|
+
),
|
|
1894
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1895
|
+
UsageSelect,
|
|
1896
|
+
{
|
|
1897
|
+
label: props.config.labels.usageDimensionLabel,
|
|
1898
|
+
value: props.selectedDimension,
|
|
1899
|
+
onValueChange: (value) => props.onDimensionChange(value),
|
|
1900
|
+
options: USAGE_DIMENSIONS.map((dimension) => [
|
|
1901
|
+
dimension,
|
|
1902
|
+
getUsageDimensionLabel(props.config.labels, dimension)
|
|
1903
|
+
])
|
|
1904
|
+
}
|
|
1905
|
+
)
|
|
1906
|
+
] })
|
|
1907
|
+
] }),
|
|
1908
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rounded-xl border bg-card p-5 shadow-sm", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "grid gap-3 md:grid-cols-2 xl:grid-cols-6", children: [
|
|
1909
|
+
period === "custom" && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
1910
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(FilterInput, { label: "From", type: "datetime-local", value: customFrom, onChange: setCustomFrom }),
|
|
1911
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(FilterInput, { label: "To", type: "datetime-local", value: customTo, onChange: setCustomTo })
|
|
1912
|
+
] }),
|
|
1913
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1914
|
+
UsageSelect,
|
|
1915
|
+
{
|
|
1916
|
+
label: "Participant type",
|
|
1917
|
+
value: participantType,
|
|
1918
|
+
onValueChange: (value) => setParticipantType(value),
|
|
1919
|
+
options: [
|
|
1920
|
+
["all", "All"],
|
|
1921
|
+
["human", "Human"],
|
|
1922
|
+
["agent", "Agent"],
|
|
1923
|
+
["job", "Job"]
|
|
1924
|
+
]
|
|
1925
|
+
}
|
|
1926
|
+
),
|
|
1927
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(FilterInput, { label: "Thread", value: threadId, onChange: setThreadId }),
|
|
1928
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(FilterInput, { label: "Participant", value: participantId, onChange: setParticipantId }),
|
|
1929
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(FilterInput, { label: "Provider", value: provider, onChange: setProvider }),
|
|
1930
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(FilterInput, { label: "Model", value: model, onChange: setModel }),
|
|
1931
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "flex items-end", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1932
|
+
Button,
|
|
1933
|
+
{
|
|
1934
|
+
className: "h-9 w-full",
|
|
1935
|
+
onClick: () => void loadUsage(),
|
|
1936
|
+
disabled: isLoading,
|
|
1937
|
+
variant: "outline",
|
|
1938
|
+
children: props.config.labels.refresh
|
|
1939
|
+
}
|
|
1940
|
+
) })
|
|
1941
|
+
] }) }),
|
|
1942
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1943
|
+
UsageChart,
|
|
1944
|
+
{
|
|
1945
|
+
labels: props.config.labels,
|
|
1946
|
+
metricKind: props.metricKind,
|
|
1947
|
+
dimension: props.selectedDimension,
|
|
1948
|
+
points: usage?.points ?? [],
|
|
1949
|
+
bucket,
|
|
1950
|
+
isLoading,
|
|
1951
|
+
error
|
|
1952
|
+
}
|
|
1953
|
+
),
|
|
1954
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1955
|
+
UsageTable,
|
|
1956
|
+
{
|
|
1957
|
+
labels: props.config.labels,
|
|
1958
|
+
metricKind: props.metricKind,
|
|
1959
|
+
dimension: props.selectedDimension,
|
|
1960
|
+
rows: usage?.rows ?? [],
|
|
1961
|
+
isLoading
|
|
1962
|
+
}
|
|
1963
|
+
)
|
|
1964
|
+
] });
|
|
1965
|
+
}
|
|
1966
|
+
function UsageSelect(props) {
|
|
1967
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "space-y-1", children: [
|
|
1968
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-xs font-medium uppercase tracking-[0.18em] text-muted-foreground", children: props.label }),
|
|
1969
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Select, { value: props.value, onValueChange: props.onValueChange, children: [
|
|
1970
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SelectTrigger, { className: "h-9 w-full min-w-[140px]", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SelectValue, {}) }),
|
|
1971
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SelectContent, { children: props.options.map(([value, label]) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SelectItem, { value, children: label }, value)) })
|
|
1972
|
+
] })
|
|
1973
|
+
] });
|
|
1974
|
+
}
|
|
1975
|
+
function FilterInput(props) {
|
|
1976
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "space-y-1", children: [
|
|
1977
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-xs font-medium uppercase tracking-[0.18em] text-muted-foreground", children: props.label }),
|
|
1978
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1979
|
+
Input,
|
|
1980
|
+
{
|
|
1981
|
+
className: "h-9",
|
|
1982
|
+
type: props.type ?? "text",
|
|
1983
|
+
value: props.value,
|
|
1984
|
+
onChange: (event) => props.onChange(event.target.value)
|
|
1985
|
+
}
|
|
1986
|
+
)
|
|
1987
|
+
] });
|
|
1988
|
+
}
|
|
1989
|
+
function UsageChart(props) {
|
|
1990
|
+
const buckets = import_react2.default.useMemo(() => buildUsageBuckets(props.points), [props.points]);
|
|
1991
|
+
const visibleBuckets = buckets.slice(-18);
|
|
1992
|
+
const groups = import_react2.default.useMemo(() => topUsageGroups(props.points, props.metricKind, props.dimension), [
|
|
1993
|
+
props.dimension,
|
|
1994
|
+
props.metricKind,
|
|
1995
|
+
props.points
|
|
1996
|
+
]);
|
|
1997
|
+
const maxBucketValue = Math.max(
|
|
1998
|
+
...visibleBuckets.map(
|
|
1999
|
+
(bucket) => bucket.points.reduce((sum, point) => sum + getUsagePointValue(point, props.metricKind, props.dimension), 0)
|
|
2000
|
+
),
|
|
2001
|
+
1
|
|
2002
|
+
);
|
|
2003
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "rounded-xl border bg-card p-5 shadow-sm", children: props.error ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm text-destructive", children: props.error }) : props.isLoading && props.points.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm text-muted-foreground", children: props.labels.loading }) : visibleBuckets.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm text-muted-foreground", children: props.labels.noResults }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "space-y-4", children: [
|
|
2004
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "flex min-h-56 items-end gap-2", children: visibleBuckets.map((bucket) => {
|
|
2005
|
+
const bucketTotal = bucket.points.reduce((sum, point) => sum + getUsagePointValue(point, props.metricKind, props.dimension), 0);
|
|
2006
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col items-center gap-2", children: [
|
|
2007
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "flex h-40 w-full items-end rounded-lg bg-muted px-1 pb-1", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2008
|
+
"div",
|
|
2009
|
+
{
|
|
2010
|
+
className: "flex w-full flex-col-reverse overflow-hidden rounded-md",
|
|
2011
|
+
style: {
|
|
2012
|
+
height: `${Math.max(bucketTotal / maxBucketValue * 100, 6)}%`
|
|
2013
|
+
},
|
|
2014
|
+
children: groups.map((group, index) => {
|
|
2015
|
+
const point = bucket.points.find((item) => item.groupKey === group.key);
|
|
2016
|
+
const value = point ? getUsagePointValue(point, props.metricKind, props.dimension) : 0;
|
|
2017
|
+
if (value <= 0 || bucketTotal <= 0) return null;
|
|
2018
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2019
|
+
"div",
|
|
2020
|
+
{
|
|
2021
|
+
title: `${group.label}: ${formatMetricValue(value, props.metricKind)}`,
|
|
2022
|
+
style: {
|
|
2023
|
+
height: `${value / bucketTotal * 100}%`,
|
|
2024
|
+
backgroundColor: USAGE_CHART_COLORS[index % USAGE_CHART_COLORS.length]
|
|
2025
|
+
}
|
|
2026
|
+
},
|
|
2027
|
+
group.key
|
|
2028
|
+
);
|
|
2029
|
+
})
|
|
2030
|
+
}
|
|
2031
|
+
) }),
|
|
2032
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "text-center", children: [
|
|
2033
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-xs font-medium", children: formatUsageBucket(bucket.bucket, props.bucket) }),
|
|
2034
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-[11px] text-muted-foreground", children: formatMetricValue(bucketTotal, props.metricKind) })
|
|
2035
|
+
] })
|
|
2036
|
+
] }, bucket.bucket);
|
|
2037
|
+
}) }),
|
|
2038
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "flex flex-wrap gap-3", children: groups.map((group, index) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center gap-2 text-xs", children: [
|
|
2039
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2040
|
+
"span",
|
|
2041
|
+
{
|
|
2042
|
+
className: "size-2 rounded-sm",
|
|
2043
|
+
style: { backgroundColor: USAGE_CHART_COLORS[index % USAGE_CHART_COLORS.length] }
|
|
2044
|
+
}
|
|
2045
|
+
),
|
|
2046
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "max-w-48 truncate text-muted-foreground", children: group.label })
|
|
2047
|
+
] }, group.key)) })
|
|
2048
|
+
] }) });
|
|
2049
|
+
}
|
|
2050
|
+
function UsageTable(props) {
|
|
2051
|
+
const rows = props.rows.slice(0, 40);
|
|
2052
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "rounded-xl border bg-card p-5 shadow-sm", children: [
|
|
2053
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "mb-4 flex items-center justify-between gap-3", children: [
|
|
2054
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SectionHeading, { title: "Usage detail" }),
|
|
2055
|
+
props.isLoading && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Badge, { variant: "outline", children: props.labels.loading })
|
|
2056
|
+
] }),
|
|
2057
|
+
rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm text-muted-foreground", children: props.labels.noResults }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("table", { className: "w-full min-w-[720px] text-sm", children: [
|
|
2058
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("tr", { className: "border-b text-left text-xs uppercase tracking-[0.14em] text-muted-foreground", children: [
|
|
2059
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { className: "py-2 pr-4 font-medium", children: "Interval" }),
|
|
2060
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { className: "py-2 pr-4 font-medium", children: "Group" }),
|
|
2061
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { className: "py-2 pr-4 text-right font-medium", children: "Input" }),
|
|
2062
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { className: "py-2 pr-4 text-right font-medium", children: "Output" }),
|
|
2063
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { className: "py-2 pr-4 text-right font-medium", children: "Reasoning" }),
|
|
2064
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { className: "py-2 pr-4 text-right font-medium", children: "Cache read" }),
|
|
2065
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { className: "py-2 pr-4 text-right font-medium", children: "Cache write" }),
|
|
2066
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { className: "py-2 text-right font-medium", children: getUsageSummaryLabel(props.labels, props.metricKind, props.dimension) })
|
|
2067
|
+
] }) }),
|
|
2068
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("tbody", { children: rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("tr", { className: "border-b last:border-0", children: [
|
|
2069
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { className: "py-2 pr-4 text-muted-foreground", children: formatDate(row.bucket) }),
|
|
2070
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { className: "max-w-72 truncate py-2 pr-4 font-medium", children: row.groupLabel }),
|
|
2071
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { className: "py-2 pr-4 text-right", children: formatMetricValue(getUsagePointValue(row, props.metricKind, "input"), props.metricKind) }),
|
|
2072
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { className: "py-2 pr-4 text-right", children: formatMetricValue(getUsagePointValue(row, props.metricKind, "output"), props.metricKind) }),
|
|
2073
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { className: "py-2 pr-4 text-right", children: formatMetricValue(getUsagePointValue(row, props.metricKind, "reasoning"), props.metricKind) }),
|
|
2074
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { className: "py-2 pr-4 text-right", children: formatMetricValue(getUsagePointValue(row, props.metricKind, "cacheRead"), props.metricKind) }),
|
|
2075
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { className: "py-2 pr-4 text-right", children: formatMetricValue(getUsagePointValue(row, props.metricKind, "cacheWrite"), props.metricKind) }),
|
|
2076
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { className: "py-2 text-right font-medium", children: formatMetricValue(getUsagePointValue(row, props.metricKind, props.dimension), props.metricKind) })
|
|
2077
|
+
] }, `${row.bucket}:${row.groupKey}`)) })
|
|
2078
|
+
] }) })
|
|
2079
|
+
] });
|
|
2080
|
+
}
|
|
1811
2081
|
function ActivityChart(props) {
|
|
1812
2082
|
const trimmedPoints = props.points.slice(-props.maxBars);
|
|
1813
2083
|
const maxUsageValue = Math.max(
|
|
@@ -2006,6 +2276,28 @@ function formatBucket(bucket, interval) {
|
|
|
2006
2276
|
day: "numeric"
|
|
2007
2277
|
});
|
|
2008
2278
|
}
|
|
2279
|
+
function formatUsageBucket(bucket, interval) {
|
|
2280
|
+
const date = new Date(bucket);
|
|
2281
|
+
if (Number.isNaN(date.getTime())) return bucket;
|
|
2282
|
+
if (interval === "minute" || interval === "hour") {
|
|
2283
|
+
return date.toLocaleString(void 0, {
|
|
2284
|
+
month: "short",
|
|
2285
|
+
day: "numeric",
|
|
2286
|
+
hour: "numeric",
|
|
2287
|
+
minute: interval === "minute" ? "2-digit" : void 0
|
|
2288
|
+
});
|
|
2289
|
+
}
|
|
2290
|
+
if (interval === "month") {
|
|
2291
|
+
return date.toLocaleDateString(void 0, {
|
|
2292
|
+
month: "short",
|
|
2293
|
+
year: "numeric"
|
|
2294
|
+
});
|
|
2295
|
+
}
|
|
2296
|
+
return date.toLocaleDateString(void 0, {
|
|
2297
|
+
month: "short",
|
|
2298
|
+
day: "numeric"
|
|
2299
|
+
});
|
|
2300
|
+
}
|
|
2009
2301
|
function formatDate(value) {
|
|
2010
2302
|
if (!value) return "No activity";
|
|
2011
2303
|
const date = new Date(value);
|
|
@@ -2028,6 +2320,58 @@ var USAGE_DIMENSIONS = [
|
|
|
2028
2320
|
"cacheRead",
|
|
2029
2321
|
"cacheWrite"
|
|
2030
2322
|
];
|
|
2323
|
+
var USAGE_CHART_COLORS = [
|
|
2324
|
+
"hsl(var(--primary))",
|
|
2325
|
+
"hsl(var(--chart-2, 142 76% 36%))",
|
|
2326
|
+
"hsl(var(--chart-3, 38 92% 50%))",
|
|
2327
|
+
"hsl(var(--chart-4, 199 89% 48%))",
|
|
2328
|
+
"hsl(var(--chart-5, 346 77% 49%))",
|
|
2329
|
+
"hsl(var(--muted-foreground))"
|
|
2330
|
+
];
|
|
2331
|
+
function emptyToUndefined(value) {
|
|
2332
|
+
const trimmed = value.trim();
|
|
2333
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
2334
|
+
}
|
|
2335
|
+
function getUsageRange(period, customFrom, customTo) {
|
|
2336
|
+
if (period === "custom") {
|
|
2337
|
+
return {
|
|
2338
|
+
from: customFrom ? new Date(customFrom).toISOString() : void 0,
|
|
2339
|
+
to: customTo ? new Date(customTo).toISOString() : void 0
|
|
2340
|
+
};
|
|
2341
|
+
}
|
|
2342
|
+
const to = /* @__PURE__ */ new Date();
|
|
2343
|
+
const from = new Date(to);
|
|
2344
|
+
if (period === "24h") {
|
|
2345
|
+
from.setHours(from.getHours() - 24);
|
|
2346
|
+
} else if (period === "30d") {
|
|
2347
|
+
from.setDate(from.getDate() - 30);
|
|
2348
|
+
} else {
|
|
2349
|
+
from.setDate(from.getDate() - 7);
|
|
2350
|
+
}
|
|
2351
|
+
return { from: from.toISOString(), to: to.toISOString() };
|
|
2352
|
+
}
|
|
2353
|
+
function buildUsageBuckets(points) {
|
|
2354
|
+
const byBucket = /* @__PURE__ */ new Map();
|
|
2355
|
+
for (const point of points) {
|
|
2356
|
+
const rows = byBucket.get(point.bucket) ?? [];
|
|
2357
|
+
rows.push(point);
|
|
2358
|
+
byBucket.set(point.bucket, rows);
|
|
2359
|
+
}
|
|
2360
|
+
return Array.from(byBucket.entries()).map(([bucket, bucketPoints]) => ({ bucket, points: bucketPoints })).sort((a, b) => new Date(a.bucket).getTime() - new Date(b.bucket).getTime());
|
|
2361
|
+
}
|
|
2362
|
+
function topUsageGroups(points, metricKind, dimension) {
|
|
2363
|
+
const totals = /* @__PURE__ */ new Map();
|
|
2364
|
+
for (const point of points) {
|
|
2365
|
+
const existing = totals.get(point.groupKey) ?? {
|
|
2366
|
+
key: point.groupKey,
|
|
2367
|
+
label: point.groupLabel,
|
|
2368
|
+
value: 0
|
|
2369
|
+
};
|
|
2370
|
+
existing.value += getUsagePointValue(point, metricKind, dimension);
|
|
2371
|
+
totals.set(point.groupKey, existing);
|
|
2372
|
+
}
|
|
2373
|
+
return Array.from(totals.values()).sort((a, b) => b.value - a.value).slice(0, 6);
|
|
2374
|
+
}
|
|
2031
2375
|
function getUsageDimensionLabel(labels, dimension) {
|
|
2032
2376
|
switch (dimension) {
|
|
2033
2377
|
case "input":
|
|
@@ -2046,11 +2390,12 @@ function getUsageDimensionLabel(labels, dimension) {
|
|
|
2046
2390
|
}
|
|
2047
2391
|
}
|
|
2048
2392
|
function getUsageSummaryLabel(labels, metricKind, dimension) {
|
|
2049
|
-
const metricLabel = metricKind === "cost" ? labels.usageMetricCost : labels.usageMetricTokens;
|
|
2393
|
+
const metricLabel = metricKind === "cost" ? labels.usageMetricCost : metricKind === "calls" ? "Calls" : labels.usageMetricTokens;
|
|
2050
2394
|
return `${getUsageDimensionLabel(labels, dimension)} ${metricLabel}`;
|
|
2051
2395
|
}
|
|
2052
2396
|
function getOverviewUsageValue(overview, metricKind, dimension) {
|
|
2053
2397
|
const llmTotals = overview.llmTotals;
|
|
2398
|
+
if (metricKind === "calls") return llmTotals.totalCalls;
|
|
2054
2399
|
if (metricKind === "cost") {
|
|
2055
2400
|
switch (dimension) {
|
|
2056
2401
|
case "input":
|
|
@@ -2102,6 +2447,7 @@ function getAgentUsageValue(agent, metricKind, dimension) {
|
|
|
2102
2447
|
return agent.totalCostUsd;
|
|
2103
2448
|
}
|
|
2104
2449
|
}
|
|
2450
|
+
if (metricKind === "calls") return agent.llmCallCount;
|
|
2105
2451
|
switch (dimension) {
|
|
2106
2452
|
case "input":
|
|
2107
2453
|
return agent.inputTokens;
|
|
@@ -2136,6 +2482,42 @@ function getActivityUsageValue(point, metricKind, dimension) {
|
|
|
2136
2482
|
return point.totalCostUsd;
|
|
2137
2483
|
}
|
|
2138
2484
|
}
|
|
2485
|
+
if (metricKind === "calls") return point.llmCallCount;
|
|
2486
|
+
switch (dimension) {
|
|
2487
|
+
case "input":
|
|
2488
|
+
return point.inputTokens;
|
|
2489
|
+
case "output":
|
|
2490
|
+
return point.outputTokens;
|
|
2491
|
+
case "reasoning":
|
|
2492
|
+
return point.reasoningTokens;
|
|
2493
|
+
case "cacheRead":
|
|
2494
|
+
return point.cacheReadInputTokens;
|
|
2495
|
+
case "cacheWrite":
|
|
2496
|
+
return point.cacheCreationInputTokens;
|
|
2497
|
+
case "total":
|
|
2498
|
+
default:
|
|
2499
|
+
return point.totalTokens;
|
|
2500
|
+
}
|
|
2501
|
+
}
|
|
2502
|
+
function getUsagePointValue(point, metricKind, dimension) {
|
|
2503
|
+
if (metricKind === "cost") {
|
|
2504
|
+
switch (dimension) {
|
|
2505
|
+
case "input":
|
|
2506
|
+
return point.inputCostUsd;
|
|
2507
|
+
case "output":
|
|
2508
|
+
return point.outputCostUsd;
|
|
2509
|
+
case "reasoning":
|
|
2510
|
+
return point.reasoningCostUsd;
|
|
2511
|
+
case "cacheRead":
|
|
2512
|
+
return point.cacheReadInputCostUsd;
|
|
2513
|
+
case "cacheWrite":
|
|
2514
|
+
return point.cacheCreationInputCostUsd;
|
|
2515
|
+
case "total":
|
|
2516
|
+
default:
|
|
2517
|
+
return point.totalCostUsd;
|
|
2518
|
+
}
|
|
2519
|
+
}
|
|
2520
|
+
if (metricKind === "calls") return point.totalCalls;
|
|
2139
2521
|
switch (dimension) {
|
|
2140
2522
|
case "input":
|
|
2141
2523
|
return point.inputTokens;
|
|
@@ -3209,6 +3591,7 @@ var CopilotzAdmin = ({
|
|
|
3209
3591
|
participants: admin.participants,
|
|
3210
3592
|
agents: admin.agents,
|
|
3211
3593
|
interval: admin.filters.interval,
|
|
3594
|
+
namespace,
|
|
3212
3595
|
threadSearch,
|
|
3213
3596
|
participantSearch,
|
|
3214
3597
|
agentSearch,
|
|
@@ -3337,6 +3720,7 @@ var CopilotzAdmin = ({
|
|
|
3337
3720
|
fetchAdminOverview,
|
|
3338
3721
|
fetchAdminParticipants,
|
|
3339
3722
|
fetchAdminThreads,
|
|
3723
|
+
fetchAdminUsage,
|
|
3340
3724
|
fetchCollectionItem,
|
|
3341
3725
|
fetchCollectionItems,
|
|
3342
3726
|
fetchCollectionNames,
|