@arbidocs/react 0.5.108 → 0.5.110

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
@@ -3332,13 +3332,18 @@ function useUploadFiles() {
3332
3332
  }
3333
3333
  const total = input.files.reduce((sum, file) => sum + file.size, 0);
3334
3334
  const loadedByBatch = new Array(batches.length).fill(0);
3335
+ const filesByBatch = new Array(batches.length).fill(0);
3335
3336
  let done = 0;
3337
+ let highest = 0;
3336
3338
  const report = () => {
3337
3339
  const loaded = loadedByBatch.reduce((sum, bytes) => sum + bytes, 0);
3340
+ const sent = filesByBatch.reduce((sum, files) => sum + files, 0);
3341
+ const share = input.files.length > 0 ? sent / input.files.length : 0;
3342
+ highest = Math.max(highest, Math.min(Math.round(share * 100), 100));
3338
3343
  onProgress?.({
3339
3344
  loaded,
3340
3345
  total,
3341
- percentage: total > 0 ? Math.min(Math.round(loaded / total * 100), 100) : 0,
3346
+ percentage: highest,
3342
3347
  batches: batches.length > 1 ? { current: done, total: batches.length } : null
3343
3348
  });
3344
3349
  };
@@ -3352,11 +3357,14 @@ function useUploadFiles() {
3352
3357
  configExtId: input.configExtId ?? void 0,
3353
3358
  // Named even when it is the open one: batches sent after a switch stay in this workspace.
3354
3359
  workspaceExtId: workspaceId,
3360
+ // One request for the batch: its files count by the share of its bytes sent.
3355
3361
  onProgress: (loaded) => {
3356
3362
  loadedByBatch[index] = Math.min(loaded, bytes);
3363
+ filesByBatch[index] = bytes > 0 ? loadedByBatch[index] / bytes * files.length : 0;
3357
3364
  report();
3358
3365
  }
3359
3366
  });
3367
+ const fileShares = new Array(files.length).fill(0);
3360
3368
  const directly = async (key, workspace) => arbi.documents.uploadDirect(
3361
3369
  workspace,
3362
3370
  key,
@@ -3371,9 +3379,15 @@ function useUploadFiles() {
3371
3379
  shared: input.shared,
3372
3380
  folder: folder ?? void 0,
3373
3381
  configExtId: input.configExtId ?? void 0,
3374
- // Ciphertext bytes, scaled back to the files' own so the total stays true.
3375
- onBytesProgress: ({ loaded, total: sent }) => {
3376
- loadedByBatch[index] = sent > 0 ? Math.round(loaded / sent * bytes) : 0;
3382
+ // Per file, in ciphertext bytes: that file's share sent, scaled back to its own
3383
+ // size so the byte total stays true.
3384
+ onBytesProgress: ({ fileIndex, loaded, total: sent }) => {
3385
+ const share = sent > 0 ? Math.min(loaded / sent, 1) : 0;
3386
+ fileShares[fileIndex] = Math.max(fileShares[fileIndex] ?? 0, share);
3387
+ loadedByBatch[index] = Math.round(
3388
+ files.reduce((sum, file, i) => sum + (fileShares[i] ?? 0) * file.size, 0)
3389
+ );
3390
+ filesByBatch[index] = fileShares.reduce((sum, part) => sum + part, 0);
3377
3391
  report();
3378
3392
  }
3379
3393
  }
@@ -3390,6 +3404,7 @@ function useUploadFiles() {
3390
3404
  );
3391
3405
  }
3392
3406
  loadedByBatch[index] = bytes;
3407
+ filesByBatch[index] = files.length;
3393
3408
  done += 1;
3394
3409
  report();
3395
3410
  return result;
@@ -10965,6 +10980,8 @@ var DEFAULT_USAGE_SOURCE_LABELS = {
10965
10980
  description: "AI usage of your projects by day and model: \xA3 (ex VAT), tokens and requests.",
10966
10981
  period: "Period",
10967
10982
  periods: { current: "This period", previous: "Last period" },
10983
+ projectParam: "Project",
10984
+ allProjects: "All your projects",
10968
10985
  day: "Day",
10969
10986
  project: "Project",
10970
10987
  model: "Model",
@@ -10972,9 +10989,32 @@ var DEFAULT_USAGE_SOURCE_LABELS = {
10972
10989
  tokens: "Tokens",
10973
10990
  requests: "Requests"
10974
10991
  };
10992
+ var DEFAULT_USAGE_BREAKDOWN_SOURCE_LABELS = {
10993
+ ...DEFAULT_USAGE_SOURCE_LABELS,
10994
+ source: "AI usage breakdown",
10995
+ description: "AI usage of your projects this period, in total or by user, workspace, model or feature: \xA3 (ex VAT), tokens and requests.",
10996
+ breakdown: "Breakdown",
10997
+ by: { total: "Total", user: "User", workspace: "Workspace", model: "Model", feature: "Feature" }
10998
+ };
10975
10999
  var monthsBackOf = (params) => String(params.period ?? "0") === "1" ? 1 : 0;
10976
- function usageRows(usage, project, modelLabel = (g) => MODEL_GROUP_LABELS[g] ?? g) {
10977
- return (usage.daily ?? []).flatMap(
11000
+ var projectOf = (params) => typeof params.project === "string" && params.project ? params.project : void 0;
11001
+ var BREAKDOWNS = ["total", "user", "workspace", "model", "feature"];
11002
+ var breakdownOf = (params) => BREAKDOWNS.find((b) => b === params.by) ?? "user";
11003
+ var ownedBy = (projects, me) => (projects ?? []).filter((p) => !!me && p.created_by === me);
11004
+ function periodDays(start) {
11005
+ const end = /* @__PURE__ */ new Date(`${start}T00:00:00Z`);
11006
+ end.setUTCMonth(end.getUTCMonth() + 1);
11007
+ end.setUTCDate(end.getUTCDate() - 1);
11008
+ const days = [];
11009
+ for (const d = /* @__PURE__ */ new Date(`${start}T00:00:00Z`); d <= end; d.setUTCDate(d.getUTCDate() + 1)) {
11010
+ days.push(d.toISOString().slice(0, 10));
11011
+ }
11012
+ return days;
11013
+ }
11014
+ var featureLabel = (key) => key.replace(/[_-]+/g, " ").replace(/^\w/, (c) => c.toUpperCase());
11015
+ var modelLabelOf = (group) => MODEL_GROUP_LABELS[group] ?? group;
11016
+ function usageRows(usage, project, modelLabel = modelLabelOf) {
11017
+ const rows = (usage.daily ?? []).flatMap(
10978
11018
  (day2) => Object.entries(day2.model_groups ?? {}).map(([group, mg]) => ({
10979
11019
  day: day2.date,
10980
11020
  project,
@@ -10984,6 +11024,127 @@ function usageRows(usage, project, modelLabel = (g) => MODEL_GROUP_LABELS[g] ??
10984
11024
  requests: (mg.successful_requests ?? 0) + (mg.failed_requests ?? 0)
10985
11025
  }))
10986
11026
  );
11027
+ const model = rows[0]?.model;
11028
+ if (!usage.period_start || model === void 0) return rows;
11029
+ const used = new Set(rows.map((r) => r.day));
11030
+ const gaps = periodDays(usage.period_start).filter((day2) => !used.has(day2)).map((day2) => ({ day: day2, project, model, spend: 0, tokens: 0, requests: 0 }));
11031
+ return [...rows, ...gaps];
11032
+ }
11033
+ function usageNamesOf(workspaces) {
11034
+ const names = {};
11035
+ for (const ws of workspaces) {
11036
+ names[ws.external_id] = ws.name;
11037
+ for (const wu of ws.users ?? []) {
11038
+ const user = wu.user;
11039
+ if (user?.external_id && !names[user.external_id]) {
11040
+ names[user.external_id] = chunkEEIYXVM4_cjs.getUserDisplayName(user);
11041
+ }
11042
+ }
11043
+ }
11044
+ return names;
11045
+ }
11046
+ function usageBreakdownRows(usage, project, by, names = {}, totalLabel = "Total") {
11047
+ if (by === "total") {
11048
+ return [
11049
+ {
11050
+ project,
11051
+ name: totalLabel,
11052
+ spend: usage.total_spend ?? 0,
11053
+ tokens: usage.total_tokens ?? 0,
11054
+ requests: usage.total_requests ?? 0
11055
+ }
11056
+ ];
11057
+ }
11058
+ if (by === "model") {
11059
+ return Object.entries(usage.model_groups ?? {}).map(([group, mg]) => ({
11060
+ project,
11061
+ name: names[group] ?? modelLabelOf(group),
11062
+ spend: mg.spend ?? 0,
11063
+ tokens: mg.total_tokens ?? 0,
11064
+ requests: (mg.successful_requests ?? 0) + (mg.failed_requests ?? 0)
11065
+ }));
11066
+ }
11067
+ const totals = by === "workspace" ? usage.by_workspace : by === "feature" ? usage.by_feature : usage.by_user;
11068
+ return Object.entries(totals ?? {}).map(([key, t]) => ({
11069
+ project,
11070
+ name: by === "feature" ? featureLabel(key) : names[key] ?? key,
11071
+ spend: t.spend ?? 0,
11072
+ tokens: t.total_tokens ?? 0,
11073
+ requests: t.requests ?? 0
11074
+ }));
11075
+ }
11076
+ function useUsageResponses(params, enabled) {
11077
+ const arbi = chunk7LIMHY56_cjs.useArbi();
11078
+ const monthsBack = monthsBackOf(params);
11079
+ const only = projectOf(params);
11080
+ const projects = chunk5HDKL6XB_cjs.useProjects({ enabled });
11081
+ const user = chunk5HDKL6XB_cjs.useCurrentUser({ enabled: enabled && arbi.isLoggedIn && !only });
11082
+ const me = user.data?.external_id;
11083
+ const list = React.useMemo(() => {
11084
+ const all = projects.data ?? [];
11085
+ if (only) return [all.find((p) => p.external_id === only) ?? { external_id: only, name: only }];
11086
+ return ownedBy(all, me);
11087
+ }, [projects.data, me, only]);
11088
+ const results = reactQuery.useQueries({
11089
+ queries: list.map((p) => ({
11090
+ queryKey: chunk7LIMHY56_cjs.arbiQueryKeys.projectUsage(p.external_id, monthsBack),
11091
+ queryFn: () => arbi.projects.usage(p.external_id, monthsBack),
11092
+ enabled: enabled && arbi.isLoggedIn,
11093
+ retry: false
11094
+ }))
11095
+ });
11096
+ const signature = results.map((r) => `${r.status}:${r.dataUpdatedAt}`).join("|");
11097
+ const usages = React.useMemo(() => {
11098
+ if (results.some((r) => r.isLoading)) return void 0;
11099
+ if (!only && (!projects.data || !me)) return void 0;
11100
+ return results.map((r, i) => ({
11101
+ project: list[i],
11102
+ usage: r.data
11103
+ }));
11104
+ }, [projects.data, me, only, signature]);
11105
+ const loading = results.some((r) => r.isLoading);
11106
+ return only ? (
11107
+ // One project: its usage is the point, so its error shows (the project's name can wait).
11108
+ { usages, isLoading: loading, error: results[0]?.error ?? null }
11109
+ ) : {
11110
+ usages,
11111
+ isLoading: projects.isLoading || user.isLoading || loading,
11112
+ // One project's usage failing (not its owner after all, a hiccup) leaves it out.
11113
+ error: projects.error ?? user.error ?? null
11114
+ };
11115
+ }
11116
+ function usageParams(l) {
11117
+ const periodOptions = {
11118
+ options: [
11119
+ { value: "0", label: l.periods.current },
11120
+ { value: "1", label: l.periods.previous }
11121
+ ],
11122
+ isLoading: false
11123
+ };
11124
+ return [
11125
+ {
11126
+ id: "period",
11127
+ label: l.period,
11128
+ placeholder: l.periods.current,
11129
+ useOptions: () => periodOptions
11130
+ },
11131
+ {
11132
+ id: "project",
11133
+ label: l.projectParam,
11134
+ placeholder: l.allProjects,
11135
+ useOptions() {
11136
+ const arbi = chunk7LIMHY56_cjs.useArbi();
11137
+ const projects = chunk5HDKL6XB_cjs.useProjects();
11138
+ const user = chunk5HDKL6XB_cjs.useCurrentUser({ enabled: arbi.isLoggedIn });
11139
+ const me = user.data?.external_id;
11140
+ const options = React.useMemo(
11141
+ () => ownedBy(projects.data, me).map((p) => ({ value: p.external_id, label: p.name })),
11142
+ [projects.data, me]
11143
+ );
11144
+ return { options, isLoading: projects.isLoading || user.isLoading };
11145
+ }
11146
+ }
11147
+ ];
10987
11148
  }
10988
11149
  function createUsageSource(labels) {
10989
11150
  const l = { ...DEFAULT_USAGE_SOURCE_LABELS, ...labels };
@@ -10995,59 +11156,70 @@ function createUsageSource(labels) {
10995
11156
  { id: "tokens", label: l.tokens, type: "number", unit: "tokens" },
10996
11157
  { id: "requests", label: l.requests, type: "number" }
10997
11158
  ];
10998
- const periodOptions = {
10999
- options: [
11000
- { value: "0", label: l.periods.current },
11001
- { value: "1", label: l.periods.previous }
11002
- ],
11003
- isLoading: false
11004
- };
11005
11159
  return defineRowsSource({
11006
11160
  id: "usage",
11007
11161
  label: l.source,
11008
11162
  description: l.description,
11009
- params: [
11163
+ params: usageParams(l),
11164
+ useFields: staticFields(fields),
11165
+ useRows(params, enabled) {
11166
+ const { usages, isLoading, error } = useUsageResponses(params, enabled);
11167
+ const rows = React.useMemo(
11168
+ () => usages?.flatMap((u) => u.usage ? usageRows(u.usage, u.project.name) : []),
11169
+ [usages]
11170
+ );
11171
+ return { rows, isLoading, error };
11172
+ }
11173
+ });
11174
+ }
11175
+ function createUsageBreakdownSource(labels) {
11176
+ const l = { ...DEFAULT_USAGE_BREAKDOWN_SOURCE_LABELS, ...labels };
11177
+ const fieldsBy = Object.fromEntries(
11178
+ BREAKDOWNS.map((by) => [
11179
+ by,
11010
11180
  {
11011
- id: "period",
11012
- label: l.period,
11013
- placeholder: l.periods.current,
11014
- useOptions: () => periodOptions
11181
+ fields: [
11182
+ { id: "project", label: l.project, type: "string" },
11183
+ { id: "name", label: l.by[by], type: "string" },
11184
+ { id: "spend", label: l.spend, type: "number", unit: "gbp" },
11185
+ { id: "tokens", label: l.tokens, type: "number", unit: "tokens" },
11186
+ { id: "requests", label: l.requests, type: "number" }
11187
+ ],
11188
+ isLoading: false,
11189
+ error: null
11015
11190
  }
11191
+ ])
11192
+ );
11193
+ const byOptions = {
11194
+ options: BREAKDOWNS.map((by) => ({ value: by, label: l.by[by] })),
11195
+ isLoading: false
11196
+ };
11197
+ return defineRowsSource({
11198
+ id: "usage-breakdown",
11199
+ label: l.source,
11200
+ description: l.description,
11201
+ params: [
11202
+ ...usageParams(l),
11203
+ { id: "by", label: l.breakdown, placeholder: l.by.user, useOptions: () => byOptions }
11016
11204
  ],
11017
- useFields: staticFields(fields),
11205
+ useFields: (params) => fieldsBy[breakdownOf(params)],
11018
11206
  useRows(params, enabled) {
11019
- const arbi = chunk7LIMHY56_cjs.useArbi();
11020
- const monthsBack = monthsBackOf(params);
11021
- const projects = chunk5HDKL6XB_cjs.useProjects({ enabled });
11022
- const user = chunk5HDKL6XB_cjs.useCurrentUser({ enabled: enabled && arbi.isLoggedIn });
11023
- const me = user.data?.external_id;
11024
- const list = React.useMemo(
11025
- () => (projects.data ?? []).filter(
11026
- (p) => !!me && p.created_by === me
11207
+ const by = breakdownOf(params);
11208
+ const { usages, isLoading, error } = useUsageResponses(params, enabled);
11209
+ const workspaces = chunk5HDKL6XB_cjs.useWorkspaces({
11210
+ enabled: enabled && (by === "user" || by === "workspace")
11211
+ });
11212
+ const names = React.useMemo(
11213
+ () => usageNamesOf(workspaces.data ?? []),
11214
+ [workspaces.data]
11215
+ );
11216
+ const rows = React.useMemo(
11217
+ () => usages?.flatMap(
11218
+ (u) => u.usage ? usageBreakdownRows(u.usage, u.project.name, by, names, l.by.total) : []
11027
11219
  ),
11028
- [projects.data, me]
11220
+ [usages, by, names, l.by.total]
11029
11221
  );
11030
- const results = reactQuery.useQueries({
11031
- queries: list.map((p) => ({
11032
- queryKey: chunk7LIMHY56_cjs.arbiQueryKeys.projectUsage(p.external_id, monthsBack),
11033
- queryFn: () => arbi.projects.usage(p.external_id, monthsBack),
11034
- enabled: enabled && arbi.isLoggedIn,
11035
- retry: false
11036
- }))
11037
- });
11038
- const signature = results.map((r) => `${r.status}:${r.dataUpdatedAt}`).join("|");
11039
- const rows = React.useMemo(() => {
11040
- if (!projects.data || !me || results.some((r) => r.isLoading)) return void 0;
11041
- return results.flatMap(
11042
- (r, i) => r.data ? usageRows(r.data, list[i].name) : []
11043
- );
11044
- }, [projects.data, me, signature]);
11045
- return {
11046
- rows,
11047
- isLoading: projects.isLoading || user.isLoading || results.some((r) => r.isLoading),
11048
- // One project's usage failing (not its owner after all, a hiccup) leaves it out.
11049
- error: projects.error ?? user.error ?? null
11050
- };
11222
+ return { rows, isLoading, error };
11051
11223
  }
11052
11224
  });
11053
11225
  }
@@ -11114,6 +11286,7 @@ function createWorkspacesSource(labels) {
11114
11286
  // src/datasets/registry.ts
11115
11287
  var BUILTIN_DATA_SOURCES = [
11116
11288
  createUsageSource(),
11289
+ createUsageBreakdownSource(),
11117
11290
  createDocumentsSource(),
11118
11291
  createConversationsSource(),
11119
11292
  createProjectsSource(),
@@ -19459,6 +19632,7 @@ exports.DEFAULT_FACTS_SOURCE_LABELS = DEFAULT_FACTS_SOURCE_LABELS;
19459
19632
  exports.DEFAULT_PASSWORD_CHANGE_FORM_MESSAGES = DEFAULT_PASSWORD_CHANGE_FORM_MESSAGES;
19460
19633
  exports.DEFAULT_PROJECTS_SOURCE_LABELS = DEFAULT_PROJECTS_SOURCE_LABELS;
19461
19634
  exports.DEFAULT_TAGS_SOURCE_LABELS = DEFAULT_TAGS_SOURCE_LABELS;
19635
+ exports.DEFAULT_USAGE_BREAKDOWN_SOURCE_LABELS = DEFAULT_USAGE_BREAKDOWN_SOURCE_LABELS;
19462
19636
  exports.DEFAULT_USAGE_SOURCE_LABELS = DEFAULT_USAGE_SOURCE_LABELS;
19463
19637
  exports.DEFAULT_WORKFLOWS_SOURCE_LABELS = DEFAULT_WORKFLOWS_SOURCE_LABELS;
19464
19638
  exports.DEFAULT_WORKSPACES_SOURCE_LABELS = DEFAULT_WORKSPACES_SOURCE_LABELS;
@@ -19565,6 +19739,7 @@ exports.createProjectsSource = createProjectsSource;
19565
19739
  exports.createSkillPack = createSkillPack;
19566
19740
  exports.createStreamHandlers = createStreamHandlers;
19567
19741
  exports.createTagsSource = createTagsSource;
19742
+ exports.createUsageBreakdownSource = createUsageBreakdownSource;
19568
19743
  exports.createUsageSource = createUsageSource;
19569
19744
  exports.createWorkflowsSource = createWorkflowsSource;
19570
19745
  exports.createWorkspaceSwitch = createWorkspaceSwitch;