@arbidocs/react 0.5.108 → 0.5.109

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
@@ -10965,6 +10965,8 @@ var DEFAULT_USAGE_SOURCE_LABELS = {
10965
10965
  description: "AI usage of your projects by day and model: \xA3 (ex VAT), tokens and requests.",
10966
10966
  period: "Period",
10967
10967
  periods: { current: "This period", previous: "Last period" },
10968
+ projectParam: "Project",
10969
+ allProjects: "All your projects",
10968
10970
  day: "Day",
10969
10971
  project: "Project",
10970
10972
  model: "Model",
@@ -10972,9 +10974,32 @@ var DEFAULT_USAGE_SOURCE_LABELS = {
10972
10974
  tokens: "Tokens",
10973
10975
  requests: "Requests"
10974
10976
  };
10977
+ var DEFAULT_USAGE_BREAKDOWN_SOURCE_LABELS = {
10978
+ ...DEFAULT_USAGE_SOURCE_LABELS,
10979
+ source: "AI usage breakdown",
10980
+ description: "AI usage of your projects this period, in total or by user, workspace, model or feature: \xA3 (ex VAT), tokens and requests.",
10981
+ breakdown: "Breakdown",
10982
+ by: { total: "Total", user: "User", workspace: "Workspace", model: "Model", feature: "Feature" }
10983
+ };
10975
10984
  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(
10985
+ var projectOf = (params) => typeof params.project === "string" && params.project ? params.project : void 0;
10986
+ var BREAKDOWNS = ["total", "user", "workspace", "model", "feature"];
10987
+ var breakdownOf = (params) => BREAKDOWNS.find((b) => b === params.by) ?? "user";
10988
+ var ownedBy = (projects, me) => (projects ?? []).filter((p) => !!me && p.created_by === me);
10989
+ function periodDays(start) {
10990
+ const end = /* @__PURE__ */ new Date(`${start}T00:00:00Z`);
10991
+ end.setUTCMonth(end.getUTCMonth() + 1);
10992
+ end.setUTCDate(end.getUTCDate() - 1);
10993
+ const days = [];
10994
+ for (const d = /* @__PURE__ */ new Date(`${start}T00:00:00Z`); d <= end; d.setUTCDate(d.getUTCDate() + 1)) {
10995
+ days.push(d.toISOString().slice(0, 10));
10996
+ }
10997
+ return days;
10998
+ }
10999
+ var featureLabel = (key) => key.replace(/[_-]+/g, " ").replace(/^\w/, (c) => c.toUpperCase());
11000
+ var modelLabelOf = (group) => MODEL_GROUP_LABELS[group] ?? group;
11001
+ function usageRows(usage, project, modelLabel = modelLabelOf) {
11002
+ const rows = (usage.daily ?? []).flatMap(
10978
11003
  (day2) => Object.entries(day2.model_groups ?? {}).map(([group, mg]) => ({
10979
11004
  day: day2.date,
10980
11005
  project,
@@ -10984,6 +11009,127 @@ function usageRows(usage, project, modelLabel = (g) => MODEL_GROUP_LABELS[g] ??
10984
11009
  requests: (mg.successful_requests ?? 0) + (mg.failed_requests ?? 0)
10985
11010
  }))
10986
11011
  );
11012
+ const model = rows[0]?.model;
11013
+ if (!usage.period_start || model === void 0) return rows;
11014
+ const used = new Set(rows.map((r) => r.day));
11015
+ const gaps = periodDays(usage.period_start).filter((day2) => !used.has(day2)).map((day2) => ({ day: day2, project, model, spend: 0, tokens: 0, requests: 0 }));
11016
+ return [...rows, ...gaps];
11017
+ }
11018
+ function usageNamesOf(workspaces) {
11019
+ const names = {};
11020
+ for (const ws of workspaces) {
11021
+ names[ws.external_id] = ws.name;
11022
+ for (const wu of ws.users ?? []) {
11023
+ const user = wu.user;
11024
+ if (user?.external_id && !names[user.external_id]) {
11025
+ names[user.external_id] = chunkEEIYXVM4_cjs.getUserDisplayName(user);
11026
+ }
11027
+ }
11028
+ }
11029
+ return names;
11030
+ }
11031
+ function usageBreakdownRows(usage, project, by, names = {}, totalLabel = "Total") {
11032
+ if (by === "total") {
11033
+ return [
11034
+ {
11035
+ project,
11036
+ name: totalLabel,
11037
+ spend: usage.total_spend ?? 0,
11038
+ tokens: usage.total_tokens ?? 0,
11039
+ requests: usage.total_requests ?? 0
11040
+ }
11041
+ ];
11042
+ }
11043
+ if (by === "model") {
11044
+ return Object.entries(usage.model_groups ?? {}).map(([group, mg]) => ({
11045
+ project,
11046
+ name: names[group] ?? modelLabelOf(group),
11047
+ spend: mg.spend ?? 0,
11048
+ tokens: mg.total_tokens ?? 0,
11049
+ requests: (mg.successful_requests ?? 0) + (mg.failed_requests ?? 0)
11050
+ }));
11051
+ }
11052
+ const totals = by === "workspace" ? usage.by_workspace : by === "feature" ? usage.by_feature : usage.by_user;
11053
+ return Object.entries(totals ?? {}).map(([key, t]) => ({
11054
+ project,
11055
+ name: by === "feature" ? featureLabel(key) : names[key] ?? key,
11056
+ spend: t.spend ?? 0,
11057
+ tokens: t.total_tokens ?? 0,
11058
+ requests: t.requests ?? 0
11059
+ }));
11060
+ }
11061
+ function useUsageResponses(params, enabled) {
11062
+ const arbi = chunk7LIMHY56_cjs.useArbi();
11063
+ const monthsBack = monthsBackOf(params);
11064
+ const only = projectOf(params);
11065
+ const projects = chunk5HDKL6XB_cjs.useProjects({ enabled });
11066
+ const user = chunk5HDKL6XB_cjs.useCurrentUser({ enabled: enabled && arbi.isLoggedIn && !only });
11067
+ const me = user.data?.external_id;
11068
+ const list = React.useMemo(() => {
11069
+ const all = projects.data ?? [];
11070
+ if (only) return [all.find((p) => p.external_id === only) ?? { external_id: only, name: only }];
11071
+ return ownedBy(all, me);
11072
+ }, [projects.data, me, only]);
11073
+ const results = reactQuery.useQueries({
11074
+ queries: list.map((p) => ({
11075
+ queryKey: chunk7LIMHY56_cjs.arbiQueryKeys.projectUsage(p.external_id, monthsBack),
11076
+ queryFn: () => arbi.projects.usage(p.external_id, monthsBack),
11077
+ enabled: enabled && arbi.isLoggedIn,
11078
+ retry: false
11079
+ }))
11080
+ });
11081
+ const signature = results.map((r) => `${r.status}:${r.dataUpdatedAt}`).join("|");
11082
+ const usages = React.useMemo(() => {
11083
+ if (results.some((r) => r.isLoading)) return void 0;
11084
+ if (!only && (!projects.data || !me)) return void 0;
11085
+ return results.map((r, i) => ({
11086
+ project: list[i],
11087
+ usage: r.data
11088
+ }));
11089
+ }, [projects.data, me, only, signature]);
11090
+ const loading = results.some((r) => r.isLoading);
11091
+ return only ? (
11092
+ // One project: its usage is the point, so its error shows (the project's name can wait).
11093
+ { usages, isLoading: loading, error: results[0]?.error ?? null }
11094
+ ) : {
11095
+ usages,
11096
+ isLoading: projects.isLoading || user.isLoading || loading,
11097
+ // One project's usage failing (not its owner after all, a hiccup) leaves it out.
11098
+ error: projects.error ?? user.error ?? null
11099
+ };
11100
+ }
11101
+ function usageParams(l) {
11102
+ const periodOptions = {
11103
+ options: [
11104
+ { value: "0", label: l.periods.current },
11105
+ { value: "1", label: l.periods.previous }
11106
+ ],
11107
+ isLoading: false
11108
+ };
11109
+ return [
11110
+ {
11111
+ id: "period",
11112
+ label: l.period,
11113
+ placeholder: l.periods.current,
11114
+ useOptions: () => periodOptions
11115
+ },
11116
+ {
11117
+ id: "project",
11118
+ label: l.projectParam,
11119
+ placeholder: l.allProjects,
11120
+ useOptions() {
11121
+ const arbi = chunk7LIMHY56_cjs.useArbi();
11122
+ const projects = chunk5HDKL6XB_cjs.useProjects();
11123
+ const user = chunk5HDKL6XB_cjs.useCurrentUser({ enabled: arbi.isLoggedIn });
11124
+ const me = user.data?.external_id;
11125
+ const options = React.useMemo(
11126
+ () => ownedBy(projects.data, me).map((p) => ({ value: p.external_id, label: p.name })),
11127
+ [projects.data, me]
11128
+ );
11129
+ return { options, isLoading: projects.isLoading || user.isLoading };
11130
+ }
11131
+ }
11132
+ ];
10987
11133
  }
10988
11134
  function createUsageSource(labels) {
10989
11135
  const l = { ...DEFAULT_USAGE_SOURCE_LABELS, ...labels };
@@ -10995,59 +11141,70 @@ function createUsageSource(labels) {
10995
11141
  { id: "tokens", label: l.tokens, type: "number", unit: "tokens" },
10996
11142
  { id: "requests", label: l.requests, type: "number" }
10997
11143
  ];
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
11144
  return defineRowsSource({
11006
11145
  id: "usage",
11007
11146
  label: l.source,
11008
11147
  description: l.description,
11009
- params: [
11148
+ params: usageParams(l),
11149
+ useFields: staticFields(fields),
11150
+ useRows(params, enabled) {
11151
+ const { usages, isLoading, error } = useUsageResponses(params, enabled);
11152
+ const rows = React.useMemo(
11153
+ () => usages?.flatMap((u) => u.usage ? usageRows(u.usage, u.project.name) : []),
11154
+ [usages]
11155
+ );
11156
+ return { rows, isLoading, error };
11157
+ }
11158
+ });
11159
+ }
11160
+ function createUsageBreakdownSource(labels) {
11161
+ const l = { ...DEFAULT_USAGE_BREAKDOWN_SOURCE_LABELS, ...labels };
11162
+ const fieldsBy = Object.fromEntries(
11163
+ BREAKDOWNS.map((by) => [
11164
+ by,
11010
11165
  {
11011
- id: "period",
11012
- label: l.period,
11013
- placeholder: l.periods.current,
11014
- useOptions: () => periodOptions
11166
+ fields: [
11167
+ { id: "project", label: l.project, type: "string" },
11168
+ { id: "name", label: l.by[by], type: "string" },
11169
+ { id: "spend", label: l.spend, type: "number", unit: "gbp" },
11170
+ { id: "tokens", label: l.tokens, type: "number", unit: "tokens" },
11171
+ { id: "requests", label: l.requests, type: "number" }
11172
+ ],
11173
+ isLoading: false,
11174
+ error: null
11015
11175
  }
11176
+ ])
11177
+ );
11178
+ const byOptions = {
11179
+ options: BREAKDOWNS.map((by) => ({ value: by, label: l.by[by] })),
11180
+ isLoading: false
11181
+ };
11182
+ return defineRowsSource({
11183
+ id: "usage-breakdown",
11184
+ label: l.source,
11185
+ description: l.description,
11186
+ params: [
11187
+ ...usageParams(l),
11188
+ { id: "by", label: l.breakdown, placeholder: l.by.user, useOptions: () => byOptions }
11016
11189
  ],
11017
- useFields: staticFields(fields),
11190
+ useFields: (params) => fieldsBy[breakdownOf(params)],
11018
11191
  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
11192
+ const by = breakdownOf(params);
11193
+ const { usages, isLoading, error } = useUsageResponses(params, enabled);
11194
+ const workspaces = chunk5HDKL6XB_cjs.useWorkspaces({
11195
+ enabled: enabled && (by === "user" || by === "workspace")
11196
+ });
11197
+ const names = React.useMemo(
11198
+ () => usageNamesOf(workspaces.data ?? []),
11199
+ [workspaces.data]
11200
+ );
11201
+ const rows = React.useMemo(
11202
+ () => usages?.flatMap(
11203
+ (u) => u.usage ? usageBreakdownRows(u.usage, u.project.name, by, names, l.by.total) : []
11027
11204
  ),
11028
- [projects.data, me]
11205
+ [usages, by, names, l.by.total]
11029
11206
  );
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
- };
11207
+ return { rows, isLoading, error };
11051
11208
  }
11052
11209
  });
11053
11210
  }
@@ -11114,6 +11271,7 @@ function createWorkspacesSource(labels) {
11114
11271
  // src/datasets/registry.ts
11115
11272
  var BUILTIN_DATA_SOURCES = [
11116
11273
  createUsageSource(),
11274
+ createUsageBreakdownSource(),
11117
11275
  createDocumentsSource(),
11118
11276
  createConversationsSource(),
11119
11277
  createProjectsSource(),
@@ -19459,6 +19617,7 @@ exports.DEFAULT_FACTS_SOURCE_LABELS = DEFAULT_FACTS_SOURCE_LABELS;
19459
19617
  exports.DEFAULT_PASSWORD_CHANGE_FORM_MESSAGES = DEFAULT_PASSWORD_CHANGE_FORM_MESSAGES;
19460
19618
  exports.DEFAULT_PROJECTS_SOURCE_LABELS = DEFAULT_PROJECTS_SOURCE_LABELS;
19461
19619
  exports.DEFAULT_TAGS_SOURCE_LABELS = DEFAULT_TAGS_SOURCE_LABELS;
19620
+ exports.DEFAULT_USAGE_BREAKDOWN_SOURCE_LABELS = DEFAULT_USAGE_BREAKDOWN_SOURCE_LABELS;
19462
19621
  exports.DEFAULT_USAGE_SOURCE_LABELS = DEFAULT_USAGE_SOURCE_LABELS;
19463
19622
  exports.DEFAULT_WORKFLOWS_SOURCE_LABELS = DEFAULT_WORKFLOWS_SOURCE_LABELS;
19464
19623
  exports.DEFAULT_WORKSPACES_SOURCE_LABELS = DEFAULT_WORKSPACES_SOURCE_LABELS;
@@ -19565,6 +19724,7 @@ exports.createProjectsSource = createProjectsSource;
19565
19724
  exports.createSkillPack = createSkillPack;
19566
19725
  exports.createStreamHandlers = createStreamHandlers;
19567
19726
  exports.createTagsSource = createTagsSource;
19727
+ exports.createUsageBreakdownSource = createUsageBreakdownSource;
19568
19728
  exports.createUsageSource = createUsageSource;
19569
19729
  exports.createWorkflowsSource = createWorkflowsSource;
19570
19730
  exports.createWorkspaceSwitch = createWorkspaceSwitch;