@streamoid/settings 0.14.0 → 0.15.0
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.d.mts +207 -5
- package/dist/index.d.ts +207 -5
- package/dist/index.js +532 -66
- package/dist/index.mjs +533 -66
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -34,7 +34,9 @@ __export(index_exports, {
|
|
|
34
34
|
CreditPoolMemberModal: () => CreditPoolMemberModal,
|
|
35
35
|
DEFAULT_PERMISSIONS: () => DEFAULT_PERMISSIONS,
|
|
36
36
|
DEFAULT_USER_LANGUAGE: () => DEFAULT_USER_LANGUAGE,
|
|
37
|
+
EMPTY_USAGE_LOGS_PAGE: () => EMPTY_USAGE_LOGS_PAGE,
|
|
37
38
|
ExportDateModal: () => ExportDateModal,
|
|
39
|
+
INITIAL_USAGE_LOGS_STATE: () => INITIAL_USAGE_LOGS_STATE,
|
|
38
40
|
InviteUpdateModal: () => InviteUpdateModal,
|
|
39
41
|
MemberCreditLimitModal: () => MemberCreditLimitModal,
|
|
40
42
|
MemberListFrame: () => MemberListFrame,
|
|
@@ -67,7 +69,12 @@ __export(index_exports, {
|
|
|
67
69
|
TeamsContent: () => TeamsContent,
|
|
68
70
|
TokensContent: () => TokensContent,
|
|
69
71
|
URL_TO_TAB: () => URL_TO_TAB,
|
|
72
|
+
USAGE_LOGS_EXPORT_BATCH_SIZE: () => USAGE_LOGS_EXPORT_BATCH_SIZE,
|
|
73
|
+
USAGE_LOGS_EXPORT_EXTRA_REQUESTS: () => USAGE_LOGS_EXPORT_EXTRA_REQUESTS,
|
|
74
|
+
USAGE_LOGS_EXPORT_MAX_ROWS: () => USAGE_LOGS_EXPORT_MAX_ROWS,
|
|
75
|
+
USAGE_LOGS_PAGE_SIZE: () => USAGE_LOGS_PAGE_SIZE,
|
|
70
76
|
USER_LANGUAGES: () => USER_LANGUAGES,
|
|
77
|
+
UsageLogsPager: () => UsageLogsPager,
|
|
71
78
|
WORKSPACE_LIST_PAGE_SIZE: () => WORKSPACE_LIST_PAGE_SIZE,
|
|
72
79
|
WorkspaceGeneralTab: () => WorkspaceGeneralTab,
|
|
73
80
|
WorkspaceListTab: () => WorkspaceListTab,
|
|
@@ -79,6 +86,7 @@ __export(index_exports, {
|
|
|
79
86
|
cleanCreditLimitInput: () => cleanCreditLimitInput,
|
|
80
87
|
cleanPoolValueInput: () => cleanPoolValueInput,
|
|
81
88
|
countLabel: () => countLabel,
|
|
89
|
+
createUsedByNamesLoader: () => createUsedByNamesLoader,
|
|
82
90
|
creditCycleUnit: () => creditCycleUnit,
|
|
83
91
|
creditsMeter: () => creditsMeter,
|
|
84
92
|
deriveWorkspaceInvitePermission: () => deriveWorkspaceInvitePermission,
|
|
@@ -88,6 +96,7 @@ __export(index_exports, {
|
|
|
88
96
|
entitlementFromBody: () => entitlementFromBody,
|
|
89
97
|
entitlementFromFailure: () => entitlementFromFailure,
|
|
90
98
|
expiryChoiceFor: () => expiryChoiceFor,
|
|
99
|
+
fetchUsageLogsInRange: () => fetchUsageLogsInRange,
|
|
91
100
|
findBillingError: () => findBillingError,
|
|
92
101
|
findPoolError: () => findPoolError,
|
|
93
102
|
formatCreditLimit: () => formatCreditLimit,
|
|
@@ -122,8 +131,16 @@ __export(index_exports, {
|
|
|
122
131
|
settingsReturnTarget: () => settingsReturnTarget,
|
|
123
132
|
sharedPoolBannerText: () => sharedPoolBannerText,
|
|
124
133
|
sharedPoolEndsText: () => sharedPoolEndsText,
|
|
134
|
+
sliceUsageLogsPage: () => sliceUsageLogsPage,
|
|
125
135
|
sponsoredCreditsText: () => sponsoredCreditsText,
|
|
136
|
+
toCsv: () => toCsv,
|
|
126
137
|
toLocalDateInput: () => toLocalDateInput,
|
|
138
|
+
usageLogsCsvRows: () => usageLogsCsvRows,
|
|
139
|
+
usageLogsDateRange: () => usageLogsDateRange,
|
|
140
|
+
usageLogsExportFileName: () => usageLogsExportFileName,
|
|
141
|
+
usageLogsPage: () => usageLogsPage,
|
|
142
|
+
usageLogsReducer: () => usageLogsReducer,
|
|
143
|
+
usageLogsSpentByOthers: () => usageLogsSpentByOthers,
|
|
127
144
|
useBillingEntitlement: () => useBillingEntitlement,
|
|
128
145
|
useSettingsAdapters: () => useSettingsAdapters,
|
|
129
146
|
useWorkspaceInvitePermission: () => useWorkspaceInvitePermission,
|
|
@@ -7897,7 +7914,10 @@ function formatDateRange(date) {
|
|
|
7897
7914
|
function ExportDateModal({
|
|
7898
7915
|
title,
|
|
7899
7916
|
onClose,
|
|
7900
|
-
onExport
|
|
7917
|
+
onExport,
|
|
7918
|
+
busy = false,
|
|
7919
|
+
busyText,
|
|
7920
|
+
notice = null
|
|
7901
7921
|
}) {
|
|
7902
7922
|
useOverlayOpen(true, onClose);
|
|
7903
7923
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -7984,6 +8004,7 @@ function ExportDateModal({
|
|
|
7984
8004
|
[rangeStart, rangeEnd, isFuture]
|
|
7985
8005
|
);
|
|
7986
8006
|
const handleExport = () => {
|
|
8007
|
+
if (busy) return;
|
|
7987
8008
|
if (rangeStart && rangeEnd) onExport(rangeStart, rangeEnd);
|
|
7988
8009
|
};
|
|
7989
8010
|
const getCellVisuals = (cell, idx) => {
|
|
@@ -8205,24 +8226,42 @@ function ExportDateModal({
|
|
|
8205
8226
|
borderTop: "1px solid var(--alias-border-subtle)"
|
|
8206
8227
|
},
|
|
8207
8228
|
children: [
|
|
8208
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.
|
|
8209
|
-
|
|
8210
|
-
|
|
8211
|
-
|
|
8212
|
-
|
|
8213
|
-
|
|
8214
|
-
|
|
8215
|
-
|
|
8216
|
-
|
|
8217
|
-
|
|
8218
|
-
|
|
8219
|
-
|
|
8220
|
-
|
|
8221
|
-
|
|
8229
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex-1 min-w-0 flex flex-col", children: [
|
|
8230
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
8231
|
+
"p",
|
|
8232
|
+
{
|
|
8233
|
+
className: "min-w-0 truncate",
|
|
8234
|
+
style: {
|
|
8235
|
+
fontFamily: "var(--font-family-font-family-body)",
|
|
8236
|
+
fontSize: "var(--font-size-font-size-md)",
|
|
8237
|
+
fontWeight: 400,
|
|
8238
|
+
lineHeight: "var(--line-height-line-height-md)",
|
|
8239
|
+
color: "var(--alias-text---icons-primary)"
|
|
8240
|
+
},
|
|
8241
|
+
"aria-live": "polite",
|
|
8242
|
+
children: busy && busyText ? busyText : rangeStart && rangeEnd ? `${formatDateRange(rangeStart)} - ${formatDateRange(rangeEnd)}` : rangeStart ? `${formatDateRange(rangeStart)} - Select end date` : "Select date range"
|
|
8243
|
+
}
|
|
8244
|
+
),
|
|
8245
|
+
notice && !busy && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
8246
|
+
"p",
|
|
8247
|
+
{
|
|
8248
|
+
role: "alert",
|
|
8249
|
+
style: {
|
|
8250
|
+
fontFamily: "var(--font-family-font-family-body)",
|
|
8251
|
+
fontSize: "var(--font-size-font-size-sm)",
|
|
8252
|
+
fontWeight: 400,
|
|
8253
|
+
lineHeight: "var(--line-height-line-height-sm)",
|
|
8254
|
+
color: "var(--alias-text---icons-error)"
|
|
8255
|
+
},
|
|
8256
|
+
children: notice
|
|
8257
|
+
}
|
|
8258
|
+
)
|
|
8259
|
+
] }),
|
|
8222
8260
|
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
8223
8261
|
"div",
|
|
8224
8262
|
{
|
|
8225
|
-
className: `flex items-center justify-center shrink-0 ${rangeStart && rangeEnd ? "cursor-pointer" : "opacity-50 cursor-not-allowed"}`,
|
|
8263
|
+
className: `flex items-center justify-center shrink-0 ${rangeStart && rangeEnd && !busy ? "cursor-pointer" : "opacity-50 cursor-not-allowed"}`,
|
|
8264
|
+
"aria-disabled": busy || !(rangeStart && rangeEnd),
|
|
8226
8265
|
style: {
|
|
8227
8266
|
backgroundColor: "var(--alias-text---icons-primary)",
|
|
8228
8267
|
borderRadius: "var(--radius-xl)",
|
|
@@ -8240,7 +8279,7 @@ function ExportDateModal({
|
|
|
8240
8279
|
lineHeight: "var(--line-height-line-height-sm)",
|
|
8241
8280
|
color: "var(--alias-text---icons-inverse)"
|
|
8242
8281
|
},
|
|
8243
|
-
children: "Export"
|
|
8282
|
+
children: busy ? "Exporting\u2026" : "Export"
|
|
8244
8283
|
}
|
|
8245
8284
|
)
|
|
8246
8285
|
}
|
|
@@ -10659,6 +10698,196 @@ async function loadCurrentPlan(fetchCurrentPlan) {
|
|
|
10659
10698
|
return { subscription, entitlement, paid: hasPaidFeatures({ entitlement, subscription }) };
|
|
10660
10699
|
}
|
|
10661
10700
|
|
|
10701
|
+
// src/usage-logs.ts
|
|
10702
|
+
var USAGE_LOGS_PAGE_SIZE = 50;
|
|
10703
|
+
var USAGE_LOGS_EXPORT_BATCH_SIZE = 100;
|
|
10704
|
+
var USAGE_LOGS_EXPORT_MAX_ROWS = 2e4;
|
|
10705
|
+
var USAGE_LOGS_EXPORT_EXTRA_REQUESTS = 10;
|
|
10706
|
+
function rowsOf(res) {
|
|
10707
|
+
return Array.isArray(res?.data) ? res.data : [];
|
|
10708
|
+
}
|
|
10709
|
+
function sliceUsageLogsPage(all, page, pageSize = USAGE_LOGS_PAGE_SIZE) {
|
|
10710
|
+
const total = all.length;
|
|
10711
|
+
const totalPages = Math.max(1, Math.ceil(total / pageSize));
|
|
10712
|
+
const safePage = Math.min(Math.max(1, Math.floor(page) || 1), totalPages);
|
|
10713
|
+
return {
|
|
10714
|
+
rows: all.slice((safePage - 1) * pageSize, safePage * pageSize),
|
|
10715
|
+
page: safePage,
|
|
10716
|
+
totalPages,
|
|
10717
|
+
total,
|
|
10718
|
+
unpaged: all
|
|
10719
|
+
};
|
|
10720
|
+
}
|
|
10721
|
+
function usageLogsPage(res, page, pageSize = USAGE_LOGS_PAGE_SIZE) {
|
|
10722
|
+
const data = rowsOf(res);
|
|
10723
|
+
const pagination = res?.pagination;
|
|
10724
|
+
if (!pagination || !Number.isFinite(pagination.total)) {
|
|
10725
|
+
return sliceUsageLogsPage(data, page, pageSize);
|
|
10726
|
+
}
|
|
10727
|
+
const total = Math.max(0, pagination.total);
|
|
10728
|
+
const limit = pagination.limit > 0 ? pagination.limit : pageSize;
|
|
10729
|
+
const totalPages = Math.max(
|
|
10730
|
+
1,
|
|
10731
|
+
pagination.totalPages > 0 ? pagination.totalPages : Math.ceil(total / limit)
|
|
10732
|
+
);
|
|
10733
|
+
return {
|
|
10734
|
+
rows: data.slice(0, pageSize),
|
|
10735
|
+
page: pagination.page > 0 ? pagination.page : page,
|
|
10736
|
+
totalPages,
|
|
10737
|
+
total,
|
|
10738
|
+
unpaged: null
|
|
10739
|
+
};
|
|
10740
|
+
}
|
|
10741
|
+
var EMPTY_USAGE_LOGS_PAGE = {
|
|
10742
|
+
rows: [],
|
|
10743
|
+
page: 1,
|
|
10744
|
+
totalPages: 1,
|
|
10745
|
+
total: 0,
|
|
10746
|
+
unpaged: null
|
|
10747
|
+
};
|
|
10748
|
+
var INITIAL_USAGE_LOGS_STATE = {
|
|
10749
|
+
logs: EMPTY_USAGE_LOGS_PAGE,
|
|
10750
|
+
requestedPage: 1,
|
|
10751
|
+
loading: false,
|
|
10752
|
+
error: null
|
|
10753
|
+
};
|
|
10754
|
+
function usageLogsReducer(state, action) {
|
|
10755
|
+
switch (action.type) {
|
|
10756
|
+
case "request":
|
|
10757
|
+
return { ...state, requestedPage: action.page, loading: true, error: null };
|
|
10758
|
+
case "loaded":
|
|
10759
|
+
return {
|
|
10760
|
+
logs: action.logs,
|
|
10761
|
+
requestedPage: action.logs.page,
|
|
10762
|
+
loading: false,
|
|
10763
|
+
error: null
|
|
10764
|
+
};
|
|
10765
|
+
case "failed":
|
|
10766
|
+
return { ...state, loading: false, error: action.error };
|
|
10767
|
+
case "turn": {
|
|
10768
|
+
if (!state.logs.unpaged || state.error) return state;
|
|
10769
|
+
const logs = sliceUsageLogsPage(state.logs.unpaged, action.page);
|
|
10770
|
+
return { ...state, logs, requestedPage: logs.page };
|
|
10771
|
+
}
|
|
10772
|
+
case "reset":
|
|
10773
|
+
return INITIAL_USAGE_LOGS_STATE;
|
|
10774
|
+
}
|
|
10775
|
+
}
|
|
10776
|
+
function usageLogsSpentByOthers(logs, workspaceId) {
|
|
10777
|
+
return (logs.unpaged ?? logs.rows).some(
|
|
10778
|
+
(log) => usedByWorkspaceKey(log, workspaceId) !== null
|
|
10779
|
+
);
|
|
10780
|
+
}
|
|
10781
|
+
function createUsedByNamesLoader(save) {
|
|
10782
|
+
let savedFor = null;
|
|
10783
|
+
let inFlight = null;
|
|
10784
|
+
return {
|
|
10785
|
+
async load(workspaceId, fetchCreditPool) {
|
|
10786
|
+
if (savedFor === workspaceId || inFlight?.workspaceId === workspaceId) {
|
|
10787
|
+
return;
|
|
10788
|
+
}
|
|
10789
|
+
const lookup = { workspaceId };
|
|
10790
|
+
inFlight = lookup;
|
|
10791
|
+
try {
|
|
10792
|
+
const pool = await fetchCreditPool();
|
|
10793
|
+
if (inFlight !== lookup) return;
|
|
10794
|
+
if (save(workspaceId, usedByNamesFrom(pool))) savedFor = workspaceId;
|
|
10795
|
+
} catch {
|
|
10796
|
+
} finally {
|
|
10797
|
+
if (inFlight === lookup) inFlight = null;
|
|
10798
|
+
}
|
|
10799
|
+
},
|
|
10800
|
+
reset() {
|
|
10801
|
+
savedFor = null;
|
|
10802
|
+
inFlight = null;
|
|
10803
|
+
}
|
|
10804
|
+
};
|
|
10805
|
+
}
|
|
10806
|
+
function usageLogsExportFileName(start, end) {
|
|
10807
|
+
return `usage_logs_${toLocalDateInput(start)}_${toLocalDateInput(end)}.csv`;
|
|
10808
|
+
}
|
|
10809
|
+
function usageLogsDateRange(start, end) {
|
|
10810
|
+
const from = new Date(start);
|
|
10811
|
+
from.setHours(0, 0, 0, 0);
|
|
10812
|
+
const to = new Date(end);
|
|
10813
|
+
to.setHours(23, 59, 59, 999);
|
|
10814
|
+
return { startDate: from.toISOString(), endDate: to.toISOString() };
|
|
10815
|
+
}
|
|
10816
|
+
async function fetchUsageLogsInRange(fetchUsageLogs, range, {
|
|
10817
|
+
batchSize = USAGE_LOGS_EXPORT_BATCH_SIZE,
|
|
10818
|
+
maxRows = USAGE_LOGS_EXPORT_MAX_ROWS,
|
|
10819
|
+
maxRequests,
|
|
10820
|
+
onProgress,
|
|
10821
|
+
signal
|
|
10822
|
+
} = {}) {
|
|
10823
|
+
const first = await fetchUsageLogs({ ...range, page: 1, limit: batchSize });
|
|
10824
|
+
if (signal?.aborted) return { status: "cancelled" };
|
|
10825
|
+
if (!first?.pagination || !Number.isFinite(first.pagination.total)) {
|
|
10826
|
+
const from = Date.parse(range.startDate);
|
|
10827
|
+
const to = Date.parse(range.endDate);
|
|
10828
|
+
const rows2 = rowsOf(first).filter((row) => {
|
|
10829
|
+
const at = Date.parse(row.createdAt);
|
|
10830
|
+
return at >= from && at <= to;
|
|
10831
|
+
});
|
|
10832
|
+
if (rows2.length > maxRows) return { status: "too-large", total: rows2.length };
|
|
10833
|
+
onProgress?.(rows2.length, rows2.length);
|
|
10834
|
+
return { status: "ok", rows: rows2, total: rows2.length };
|
|
10835
|
+
}
|
|
10836
|
+
let total = Math.max(0, first.pagination.total);
|
|
10837
|
+
if (total > maxRows) return { status: "too-large", total };
|
|
10838
|
+
const limit = first.pagination.limit > 0 ? first.pagination.limit : batchSize;
|
|
10839
|
+
const requestCap = maxRequests ?? Math.ceil(maxRows / limit) + USAGE_LOGS_EXPORT_EXTRA_REQUESTS;
|
|
10840
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10841
|
+
const rows = [];
|
|
10842
|
+
const add = (batch) => {
|
|
10843
|
+
for (const row of batch) {
|
|
10844
|
+
if (rows.length >= maxRows) return;
|
|
10845
|
+
if (seen.has(row._id)) continue;
|
|
10846
|
+
seen.add(row._id);
|
|
10847
|
+
rows.push(row);
|
|
10848
|
+
}
|
|
10849
|
+
};
|
|
10850
|
+
const hasNextAfter = (pagination, page) => typeof pagination?.hasNextPage === "boolean" ? pagination.hasNextPage : page * limit < total;
|
|
10851
|
+
add(rowsOf(first));
|
|
10852
|
+
onProgress?.(rows.length, total);
|
|
10853
|
+
let hasNext = hasNextAfter(first.pagination, 1);
|
|
10854
|
+
let requests = 1;
|
|
10855
|
+
for (let page = 2; hasNext && rows.length < total; page++) {
|
|
10856
|
+
if (requests >= requestCap) {
|
|
10857
|
+
return { status: "incomplete", fetched: rows.length, total };
|
|
10858
|
+
}
|
|
10859
|
+
if (signal?.aborted) return { status: "cancelled" };
|
|
10860
|
+
const res = await fetchUsageLogs({ ...range, page, limit });
|
|
10861
|
+
requests++;
|
|
10862
|
+
if (signal?.aborted) return { status: "cancelled" };
|
|
10863
|
+
if (res?.pagination && Number.isFinite(res.pagination.total)) {
|
|
10864
|
+
total = Math.max(0, res.pagination.total);
|
|
10865
|
+
if (total > maxRows) return { status: "too-large", total };
|
|
10866
|
+
}
|
|
10867
|
+
const batch = rowsOf(res);
|
|
10868
|
+
if (batch.length === 0) break;
|
|
10869
|
+
add(batch);
|
|
10870
|
+
onProgress?.(rows.length, total);
|
|
10871
|
+
hasNext = hasNextAfter(res?.pagination, page);
|
|
10872
|
+
}
|
|
10873
|
+
return { status: "ok", rows, total };
|
|
10874
|
+
}
|
|
10875
|
+
function usageLogsCsvRows(logs, userMap, formatDate5) {
|
|
10876
|
+
return [
|
|
10877
|
+
["Date", "Type", "Credits", "Service", "User ID"],
|
|
10878
|
+
...logs.map((log) => [
|
|
10879
|
+
formatDate5(log.createdAt),
|
|
10880
|
+
log.type,
|
|
10881
|
+
log.amount.toLocaleString("en-US"),
|
|
10882
|
+
log.service?.serviceGroupName ?? log.meta?.info ?? "",
|
|
10883
|
+
log.triggeredByUserId != null ? userMap[log.triggeredByUserId] ?? log.triggeredByUserId : ""
|
|
10884
|
+
])
|
|
10885
|
+
];
|
|
10886
|
+
}
|
|
10887
|
+
function toCsv(rows) {
|
|
10888
|
+
return rows.map((r) => r.map((cell) => `"${String(cell).replace(/"/g, '""')}"`).join(",")).join("\n");
|
|
10889
|
+
}
|
|
10890
|
+
|
|
10662
10891
|
// src/billing-content.tsx
|
|
10663
10892
|
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
10664
10893
|
var DEFAULT_TOPUP_SERVICE = "catalogix";
|
|
@@ -11544,6 +11773,8 @@ function UsageLogsTable({
|
|
|
11544
11773
|
logs,
|
|
11545
11774
|
userMap,
|
|
11546
11775
|
loading,
|
|
11776
|
+
error = null,
|
|
11777
|
+
onRetry,
|
|
11547
11778
|
currentWorkspaceId = null,
|
|
11548
11779
|
usedByNames = {}
|
|
11549
11780
|
}) {
|
|
@@ -11574,6 +11805,50 @@ function UsageLogsTable({
|
|
|
11574
11805
|
}
|
|
11575
11806
|
);
|
|
11576
11807
|
}
|
|
11808
|
+
if (error) {
|
|
11809
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
11810
|
+
"div",
|
|
11811
|
+
{
|
|
11812
|
+
role: "alert",
|
|
11813
|
+
className: "flex flex-col items-center justify-center w-full",
|
|
11814
|
+
style: {
|
|
11815
|
+
backgroundColor: "var(--alias-surface-base)",
|
|
11816
|
+
borderRadius: "var(--radius-3xl)",
|
|
11817
|
+
border: "1px solid var(--alias-border-subtle)",
|
|
11818
|
+
padding: "var(--spacing-6xl)",
|
|
11819
|
+
gap: "var(--spacing-md)"
|
|
11820
|
+
},
|
|
11821
|
+
children: [
|
|
11822
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
11823
|
+
"span",
|
|
11824
|
+
{
|
|
11825
|
+
style: {
|
|
11826
|
+
fontFamily: "var(--font-family-font-family-body)",
|
|
11827
|
+
fontSize: "var(--font-size-font-size-sm)",
|
|
11828
|
+
fontWeight: 400,
|
|
11829
|
+
lineHeight: "var(--line-height-line-height-sm)",
|
|
11830
|
+
color: "var(--alias-text---icons-muted)",
|
|
11831
|
+
textAlign: "center"
|
|
11832
|
+
},
|
|
11833
|
+
children: [
|
|
11834
|
+
"Couldn't load usage logs. ",
|
|
11835
|
+
error
|
|
11836
|
+
]
|
|
11837
|
+
}
|
|
11838
|
+
),
|
|
11839
|
+
onRetry && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
11840
|
+
import_ui17.ScButton,
|
|
11841
|
+
{
|
|
11842
|
+
text: "Try again",
|
|
11843
|
+
variant: "tertiary",
|
|
11844
|
+
size: "sm",
|
|
11845
|
+
onClick: onRetry
|
|
11846
|
+
}
|
|
11847
|
+
)
|
|
11848
|
+
]
|
|
11849
|
+
}
|
|
11850
|
+
);
|
|
11851
|
+
}
|
|
11577
11852
|
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
11578
11853
|
"div",
|
|
11579
11854
|
{
|
|
@@ -11749,6 +12024,71 @@ function UsageLogsTable({
|
|
|
11749
12024
|
}
|
|
11750
12025
|
);
|
|
11751
12026
|
}
|
|
12027
|
+
function UsageLogsPager({
|
|
12028
|
+
page,
|
|
12029
|
+
totalPages,
|
|
12030
|
+
total,
|
|
12031
|
+
loading = false,
|
|
12032
|
+
onPageChange
|
|
12033
|
+
}) {
|
|
12034
|
+
if (total <= 0) return null;
|
|
12035
|
+
const canPrevious = !loading && page > 1;
|
|
12036
|
+
const canNext = !loading && page < totalPages;
|
|
12037
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
12038
|
+
"div",
|
|
12039
|
+
{
|
|
12040
|
+
className: "flex items-center justify-between shrink-0 w-full",
|
|
12041
|
+
style: { gap: "var(--spacing-md)" },
|
|
12042
|
+
children: [
|
|
12043
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
12044
|
+
"span",
|
|
12045
|
+
{
|
|
12046
|
+
style: {
|
|
12047
|
+
color: "var(--alias-text---icons-muted)",
|
|
12048
|
+
fontFamily: "var(--font-family-font-family-body)",
|
|
12049
|
+
fontSize: "var(--font-size-font-size-sm)",
|
|
12050
|
+
lineHeight: "var(--line-height-line-height-sm)"
|
|
12051
|
+
},
|
|
12052
|
+
children: [
|
|
12053
|
+
"Page ",
|
|
12054
|
+
page.toLocaleString("en-US"),
|
|
12055
|
+
" of",
|
|
12056
|
+
" ",
|
|
12057
|
+
totalPages.toLocaleString("en-US"),
|
|
12058
|
+
" \xB7",
|
|
12059
|
+
" ",
|
|
12060
|
+
total.toLocaleString("en-US"),
|
|
12061
|
+
" ",
|
|
12062
|
+
total === 1 ? "log" : "logs"
|
|
12063
|
+
]
|
|
12064
|
+
}
|
|
12065
|
+
),
|
|
12066
|
+
totalPages > 1 && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex items-center", style: { gap: "var(--spacing-md)" }, children: [
|
|
12067
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
12068
|
+
import_ui17.ScButton,
|
|
12069
|
+
{
|
|
12070
|
+
text: "Previous",
|
|
12071
|
+
variant: "tertiary",
|
|
12072
|
+
size: "sm",
|
|
12073
|
+
state: canPrevious ? "default" : "disabled",
|
|
12074
|
+
onClick: canPrevious ? () => onPageChange(page - 1) : void 0
|
|
12075
|
+
}
|
|
12076
|
+
),
|
|
12077
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
12078
|
+
import_ui17.ScButton,
|
|
12079
|
+
{
|
|
12080
|
+
text: "Next",
|
|
12081
|
+
variant: "tertiary",
|
|
12082
|
+
size: "sm",
|
|
12083
|
+
state: canNext ? "default" : "disabled",
|
|
12084
|
+
onClick: canNext ? () => onPageChange(page + 1) : void 0
|
|
12085
|
+
}
|
|
12086
|
+
)
|
|
12087
|
+
] })
|
|
12088
|
+
]
|
|
12089
|
+
}
|
|
12090
|
+
);
|
|
12091
|
+
}
|
|
11752
12092
|
function BackToBilling({ onClick }) {
|
|
11753
12093
|
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
11754
12094
|
"div",
|
|
@@ -11828,6 +12168,9 @@ function BillingContent({
|
|
|
11828
12168
|
else setShowSharedCreditsInternal(next);
|
|
11829
12169
|
};
|
|
11830
12170
|
const [showExportModal, setShowExportModal] = (0, import_react23.useState)(false);
|
|
12171
|
+
const [exportProgress, setExportProgress] = (0, import_react23.useState)(null);
|
|
12172
|
+
const [exportNotice, setExportNotice] = (0, import_react23.useState)(null);
|
|
12173
|
+
const exportAbortRef = (0, import_react23.useRef)(null);
|
|
11831
12174
|
const [showBuyCreditsModal, setShowBuyCreditsModal] = (0, import_react23.useState)(false);
|
|
11832
12175
|
const [subscription, setSubscription] = (0, import_react23.useState)(null);
|
|
11833
12176
|
const [entitlement, setEntitlement] = (0, import_react23.useState)(
|
|
@@ -11839,7 +12182,24 @@ function BillingContent({
|
|
|
11839
12182
|
const [products, setProducts] = (0, import_react23.useState)([]);
|
|
11840
12183
|
const [invoices, setInvoices] = (0, import_react23.useState)([]);
|
|
11841
12184
|
const [totalCredits, setTotalCredits] = (0, import_react23.useState)(null);
|
|
11842
|
-
const [
|
|
12185
|
+
const [usageLogsState, dispatchUsageLogs] = (0, import_react23.useReducer)(
|
|
12186
|
+
usageLogsReducer,
|
|
12187
|
+
INITIAL_USAGE_LOGS_STATE
|
|
12188
|
+
);
|
|
12189
|
+
const {
|
|
12190
|
+
logs: usageLogs,
|
|
12191
|
+
loading: loadingUsageLogs,
|
|
12192
|
+
error: usageLogsError
|
|
12193
|
+
} = usageLogsState;
|
|
12194
|
+
const usageLogsRequestRef = (0, import_react23.useRef)(0);
|
|
12195
|
+
const workspaceIdRef = (0, import_react23.useRef)(workspaceId);
|
|
12196
|
+
workspaceIdRef.current = workspaceId;
|
|
12197
|
+
const loadUsedByNamesRef = (0, import_react23.useRef)(null);
|
|
12198
|
+
loadUsedByNamesRef.current ??= createUsedByNamesLoader((forWorkspace, names) => {
|
|
12199
|
+
if (forWorkspace !== workspaceIdRef.current) return false;
|
|
12200
|
+
setUsedByNames(names);
|
|
12201
|
+
return true;
|
|
12202
|
+
});
|
|
11843
12203
|
const [userMap, setUserMap] = (0, import_react23.useState)({});
|
|
11844
12204
|
const [customPlanCredits, setCustomPlanCredits] = (0, import_react23.useState)(
|
|
11845
12205
|
null
|
|
@@ -11923,8 +12283,68 @@ function BillingContent({
|
|
|
11923
12283
|
} catch {
|
|
11924
12284
|
}
|
|
11925
12285
|
}, [api]);
|
|
12286
|
+
const ensureUsedByNames = (0, import_react23.useCallback)(
|
|
12287
|
+
(logs) => {
|
|
12288
|
+
const fetchCreditPool = api.fetchCreditPool;
|
|
12289
|
+
if (!fetchCreditPool || !workspaceId || !usageLogsSpentByOthers(logs, workspaceId)) {
|
|
12290
|
+
return;
|
|
12291
|
+
}
|
|
12292
|
+
void loadUsedByNamesRef.current?.load(
|
|
12293
|
+
workspaceId,
|
|
12294
|
+
() => fetchCreditPool.call(api)
|
|
12295
|
+
);
|
|
12296
|
+
},
|
|
12297
|
+
[api, workspaceId]
|
|
12298
|
+
);
|
|
12299
|
+
const loadUsageLogsPage = (0, import_react23.useCallback)(
|
|
12300
|
+
async (page) => {
|
|
12301
|
+
const request = ++usageLogsRequestRef.current;
|
|
12302
|
+
if (!api.fetchUsageLogs) {
|
|
12303
|
+
dispatchUsageLogs({ type: "loaded", logs: EMPTY_USAGE_LOGS_PAGE });
|
|
12304
|
+
return;
|
|
12305
|
+
}
|
|
12306
|
+
dispatchUsageLogs({ type: "request", page });
|
|
12307
|
+
try {
|
|
12308
|
+
const res = await api.fetchUsageLogs({
|
|
12309
|
+
page,
|
|
12310
|
+
limit: USAGE_LOGS_PAGE_SIZE
|
|
12311
|
+
});
|
|
12312
|
+
if (request !== usageLogsRequestRef.current) return;
|
|
12313
|
+
const next = usageLogsPage(res, page);
|
|
12314
|
+
dispatchUsageLogs({ type: "loaded", logs: next });
|
|
12315
|
+
ensureUsedByNames(next);
|
|
12316
|
+
} catch (err) {
|
|
12317
|
+
if (request !== usageLogsRequestRef.current) return;
|
|
12318
|
+
dispatchUsageLogs({
|
|
12319
|
+
type: "failed",
|
|
12320
|
+
error: errorMessage(err, { method: "GET" })
|
|
12321
|
+
});
|
|
12322
|
+
}
|
|
12323
|
+
},
|
|
12324
|
+
[api, ensureUsedByNames]
|
|
12325
|
+
);
|
|
12326
|
+
const goToUsageLogsPage = (0, import_react23.useCallback)(
|
|
12327
|
+
(page) => {
|
|
12328
|
+
if (usageLogs.unpaged && !usageLogsError) {
|
|
12329
|
+
dispatchUsageLogs({ type: "turn", page });
|
|
12330
|
+
ensureUsedByNames(usageLogs);
|
|
12331
|
+
return;
|
|
12332
|
+
}
|
|
12333
|
+
void loadUsageLogsPage(page);
|
|
12334
|
+
},
|
|
12335
|
+
[usageLogs, usageLogsError, loadUsageLogsPage, ensureUsedByNames]
|
|
12336
|
+
);
|
|
12337
|
+
(0, import_react23.useEffect)(() => {
|
|
12338
|
+
if (!loadingUsageLogs && !usageLogsError && usageLogs.unpaged === null && usageLogs.rows.length === 0 && usageLogs.total > 0 && usageLogs.page > usageLogs.totalPages) {
|
|
12339
|
+
void loadUsageLogsPage(usageLogs.totalPages);
|
|
12340
|
+
}
|
|
12341
|
+
}, [usageLogs, loadingUsageLogs, usageLogsError, loadUsageLogsPage]);
|
|
11926
12342
|
const fetchTableData = (0, import_react23.useCallback)(
|
|
11927
12343
|
async (tab) => {
|
|
12344
|
+
if (tab === "usage") {
|
|
12345
|
+
await loadUsageLogsPage(1);
|
|
12346
|
+
return;
|
|
12347
|
+
}
|
|
11928
12348
|
setLoadingTable(true);
|
|
11929
12349
|
try {
|
|
11930
12350
|
if (tab === "invoice") {
|
|
@@ -11936,25 +12356,14 @@ function BillingContent({
|
|
|
11936
12356
|
(item) => item.expiresAt && item.expiresAt.split("T")[0] > today
|
|
11937
12357
|
).reduce((total, item) => total + item.amount, 0)
|
|
11938
12358
|
);
|
|
11939
|
-
} else if (api.fetchUsageLogs) {
|
|
11940
|
-
const res = await api.fetchUsageLogs();
|
|
11941
|
-
const logs = res.data?.length ? res.data : [];
|
|
11942
|
-
setUsageLogs(logs);
|
|
11943
|
-
if (api.fetchCreditPool && logs.some((log) => usedByWorkspaceKey(log, workspaceId))) {
|
|
11944
|
-
const pool = await api.fetchCreditPool().catch(() => null);
|
|
11945
|
-
setUsedByNames(usedByNamesFrom(pool));
|
|
11946
|
-
}
|
|
11947
|
-
} else {
|
|
11948
|
-
setUsageLogs([]);
|
|
11949
12359
|
}
|
|
11950
12360
|
} catch {
|
|
11951
|
-
|
|
11952
|
-
else setUsageLogs([]);
|
|
12361
|
+
setInvoices([]);
|
|
11953
12362
|
} finally {
|
|
11954
12363
|
setLoadingTable(false);
|
|
11955
12364
|
}
|
|
11956
12365
|
},
|
|
11957
|
-
[api,
|
|
12366
|
+
[api, loadUsageLogsPage]
|
|
11958
12367
|
);
|
|
11959
12368
|
const handlePlanAction = (0, import_react23.useCallback)(
|
|
11960
12369
|
async ({ productId, priceId, planName: planName2 }) => {
|
|
@@ -12061,6 +12470,10 @@ function BillingContent({
|
|
|
12061
12470
|
setProducts([]);
|
|
12062
12471
|
setTotalCredits(null);
|
|
12063
12472
|
setCustomPlanCredits(null);
|
|
12473
|
+
usageLogsRequestRef.current++;
|
|
12474
|
+
dispatchUsageLogs({ type: "reset" });
|
|
12475
|
+
loadUsedByNamesRef.current?.reset();
|
|
12476
|
+
setUsedByNames({});
|
|
12064
12477
|
}, [workspaceId]);
|
|
12065
12478
|
(0, import_react23.useEffect)(() => {
|
|
12066
12479
|
setInitialFetchTriggered(true);
|
|
@@ -12163,35 +12576,74 @@ function BillingContent({
|
|
|
12163
12576
|
toast.success(`Opened ${successCount} invoice PDF(s).`);
|
|
12164
12577
|
}
|
|
12165
12578
|
} else {
|
|
12166
|
-
|
|
12167
|
-
|
|
12168
|
-
|
|
12579
|
+
await exportUsageLogs(startDate, endDate);
|
|
12580
|
+
}
|
|
12581
|
+
};
|
|
12582
|
+
const closeExportModal = () => {
|
|
12583
|
+
exportAbortRef.current?.abort();
|
|
12584
|
+
exportAbortRef.current = null;
|
|
12585
|
+
setExportProgress(null);
|
|
12586
|
+
setExportNotice(null);
|
|
12587
|
+
setShowExportModal(false);
|
|
12588
|
+
};
|
|
12589
|
+
(0, import_react23.useEffect)(() => () => exportAbortRef.current?.abort(), []);
|
|
12590
|
+
const exportUsageLogs = async (startDate, endDate) => {
|
|
12591
|
+
if (!api.fetchUsageLogs) {
|
|
12592
|
+
toast.info?.("Usage logs are not available in this workspace.");
|
|
12593
|
+
closeExportModal();
|
|
12594
|
+
return;
|
|
12595
|
+
}
|
|
12596
|
+
exportAbortRef.current?.abort();
|
|
12597
|
+
const controller = new AbortController();
|
|
12598
|
+
exportAbortRef.current = controller;
|
|
12599
|
+
setExportNotice(null);
|
|
12600
|
+
setExportProgress({ fetched: 0, total: 0 });
|
|
12601
|
+
const range = usageLogsDateRange(startDate, endDate);
|
|
12602
|
+
try {
|
|
12603
|
+
const result = await fetchUsageLogsInRange(api.fetchUsageLogs, range, {
|
|
12604
|
+
signal: controller.signal,
|
|
12605
|
+
onProgress: (fetched, total) => {
|
|
12606
|
+
if (!controller.signal.aborted) setExportProgress({ fetched, total });
|
|
12607
|
+
}
|
|
12169
12608
|
});
|
|
12170
|
-
if (
|
|
12609
|
+
if (result.status === "cancelled" || controller.signal.aborted) return;
|
|
12610
|
+
if (result.status === "too-large") {
|
|
12611
|
+
setExportNotice(
|
|
12612
|
+
`${result.total.toLocaleString("en-US")} logs in this range; an export holds up to ${USAGE_LOGS_EXPORT_MAX_ROWS.toLocaleString("en-US")}. Choose a shorter range.`
|
|
12613
|
+
);
|
|
12614
|
+
return;
|
|
12615
|
+
}
|
|
12616
|
+
if (result.status === "incomplete") {
|
|
12617
|
+
setExportNotice(
|
|
12618
|
+
"Usage logs kept changing while exporting, so some were missed. Try again."
|
|
12619
|
+
);
|
|
12620
|
+
return;
|
|
12621
|
+
}
|
|
12622
|
+
if (result.rows.length === 0) {
|
|
12171
12623
|
toast.info?.("No usage logs found in the selected date range.");
|
|
12172
|
-
|
|
12624
|
+
closeExportModal();
|
|
12173
12625
|
return;
|
|
12174
12626
|
}
|
|
12175
|
-
const headers = ["Date", "Type", "Credits", "Service", "User ID"];
|
|
12176
|
-
const rows = filtered.map((log) => [
|
|
12177
|
-
formatDate3(log.createdAt),
|
|
12178
|
-
log.type,
|
|
12179
|
-
log.amount.toLocaleString("en-US"),
|
|
12180
|
-
log.service?.serviceGroupName ?? log.meta?.info ?? "",
|
|
12181
|
-
log.triggeredByUserId != null ? userMap[log.triggeredByUserId] ?? log.triggeredByUserId : ""
|
|
12182
|
-
]);
|
|
12183
12627
|
downloadCsv(
|
|
12184
|
-
|
|
12185
|
-
|
|
12628
|
+
usageLogsCsvRows(result.rows, userMap, formatDate3),
|
|
12629
|
+
usageLogsExportFileName(startDate, endDate)
|
|
12186
12630
|
);
|
|
12187
|
-
toast.success(`Exported ${
|
|
12188
|
-
|
|
12631
|
+
toast.success(`Exported ${result.rows.length.toLocaleString("en-US")} log(s).`);
|
|
12632
|
+
closeExportModal();
|
|
12633
|
+
} catch (err) {
|
|
12634
|
+
if (controller.signal.aborted) return;
|
|
12635
|
+
setExportNotice(
|
|
12636
|
+
`Couldn't export usage logs. ${errorMessage(err, { method: "GET" })}`
|
|
12637
|
+
);
|
|
12638
|
+
} finally {
|
|
12639
|
+
if (exportAbortRef.current === controller) {
|
|
12640
|
+
exportAbortRef.current = null;
|
|
12641
|
+
setExportProgress(null);
|
|
12642
|
+
}
|
|
12189
12643
|
}
|
|
12190
12644
|
};
|
|
12191
12645
|
function downloadCsv(rows, filename) {
|
|
12192
|
-
const csv = rows
|
|
12193
|
-
(r) => r.map((cell) => `"${String(cell).replace(/"/g, '""')}"`).join(",")
|
|
12194
|
-
).join("\n");
|
|
12646
|
+
const csv = toCsv(rows);
|
|
12195
12647
|
const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
|
|
12196
12648
|
const url = URL.createObjectURL(blob);
|
|
12197
12649
|
const a = document.createElement("a");
|
|
@@ -12202,9 +12654,6 @@ function BillingContent({
|
|
|
12202
12654
|
document.body.removeChild(a);
|
|
12203
12655
|
URL.revokeObjectURL(url);
|
|
12204
12656
|
}
|
|
12205
|
-
function fmtFilename(d) {
|
|
12206
|
-
return d.toISOString().slice(0, 10);
|
|
12207
|
-
}
|
|
12208
12657
|
async function handleBuyCredits(credits2, price) {
|
|
12209
12658
|
if (!workspaceId) {
|
|
12210
12659
|
toast.error("Missing workspace details for credit top-up");
|
|
@@ -12657,22 +13106,39 @@ function BillingContent({
|
|
|
12657
13106
|
loading: loadingTable,
|
|
12658
13107
|
workspaceCountry: workspace.current?.country
|
|
12659
13108
|
}
|
|
12660
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime29.
|
|
12661
|
-
|
|
12662
|
-
|
|
12663
|
-
|
|
12664
|
-
|
|
12665
|
-
|
|
12666
|
-
|
|
12667
|
-
|
|
12668
|
-
|
|
12669
|
-
|
|
13109
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
|
|
13110
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
13111
|
+
UsageLogsTable,
|
|
13112
|
+
{
|
|
13113
|
+
logs: usageLogs.rows,
|
|
13114
|
+
userMap,
|
|
13115
|
+
loading: loadingUsageLogs,
|
|
13116
|
+
error: usageLogsError,
|
|
13117
|
+
onRetry: () => void loadUsageLogsPage(usageLogsState.requestedPage),
|
|
13118
|
+
currentWorkspaceId: workspaceId,
|
|
13119
|
+
usedByNames
|
|
13120
|
+
}
|
|
13121
|
+
),
|
|
13122
|
+
!usageLogsError && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
13123
|
+
UsageLogsPager,
|
|
13124
|
+
{
|
|
13125
|
+
page: usageLogs.page,
|
|
13126
|
+
totalPages: usageLogs.totalPages,
|
|
13127
|
+
total: usageLogs.total,
|
|
13128
|
+
loading: loadingUsageLogs,
|
|
13129
|
+
onPageChange: goToUsageLogsPage
|
|
13130
|
+
}
|
|
13131
|
+
)
|
|
13132
|
+
] }),
|
|
12670
13133
|
showExportModal && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
12671
13134
|
ExportDateModal,
|
|
12672
13135
|
{
|
|
12673
13136
|
title: activeTab === "invoice" ? "Export invoices" : "Export log",
|
|
12674
|
-
onClose:
|
|
12675
|
-
onExport: handleExport
|
|
13137
|
+
onClose: closeExportModal,
|
|
13138
|
+
onExport: handleExport,
|
|
13139
|
+
busy: exportProgress !== null,
|
|
13140
|
+
busyText: exportProgress && exportProgress.total > 0 ? `Fetched ${exportProgress.fetched.toLocaleString("en-US")} of ${exportProgress.total.toLocaleString("en-US")} logs\u2026` : "Fetching logs\u2026",
|
|
13141
|
+
notice: exportNotice
|
|
12676
13142
|
}
|
|
12677
13143
|
),
|
|
12678
13144
|
showBuyCreditsModal && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|