@cartanova/qgrid-cli 1.6.0 → 1.6.2

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.
Files changed (50) hide show
  1. package/bundle/dist/application/qgrid/qgrid.dispatcher.js +18 -6
  2. package/bundle/dist/application/qgrid/qgrid.frame.js +19 -3
  3. package/bundle/dist/application/qgrid/qgrid.types.js +2 -1
  4. package/bundle/dist/application/queries.generated.js +2 -1
  5. package/bundle/dist/application/request-log/request-log.model.js +9 -2
  6. package/bundle/dist/application/request-log/request-log.types.js +6 -2
  7. package/bundle/dist/application/sonamu.generated.js +29 -8
  8. package/bundle/dist/application/sonamu.generated.sso.js +40 -17
  9. package/bundle/dist/i18n/sd.generated.js +6 -3
  10. package/bundle/dist/migrations/20260423180818_alter_request_logs_add1_alter1.js +17 -0
  11. package/bundle/dist/migrations/20260423182017_alter_request_logs_add2_drop1_alter1.js +19 -0
  12. package/bundle/dist/migrations/20260423183613_alter_request_logs_add1_alter1.js +16 -0
  13. package/bundle/src/application/qgrid/qgrid.dispatcher.ts +24 -4
  14. package/bundle/src/application/qgrid/qgrid.frame.ts +10 -1
  15. package/bundle/src/application/qgrid/qgrid.types.ts +1 -0
  16. package/bundle/src/application/queries.generated.ts +3 -0
  17. package/bundle/src/application/request-log/request-log.entity.json +49 -17
  18. package/bundle/src/application/request-log/request-log.model.ts +26 -2
  19. package/bundle/src/application/request-log/request-log.types.ts +6 -2
  20. package/bundle/src/application/sonamu.generated.http +16 -2
  21. package/bundle/src/application/sonamu.generated.sso.ts +25 -6
  22. package/bundle/src/application/sonamu.generated.ts +41 -6
  23. package/bundle/src/i18n/sd.generated.ts +5 -2
  24. package/bundle/src/migrations/20260423180818_alter_request_logs_add1_alter1.ts +18 -0
  25. package/bundle/src/migrations/20260423182017_alter_request_logs_add2_drop1_alter1.ts +20 -0
  26. package/bundle/src/migrations/20260423183613_alter_request_logs_add1_alter1.ts +15 -0
  27. package/bundle/web-dist/client/assets/index-BkbCF47q.css +1 -0
  28. package/bundle/web-dist/client/assets/index-C1um9umC.js +78 -0
  29. package/bundle/web-dist/client/assets/logs-Codp88zO.js +1 -0
  30. package/bundle/web-dist/client/assets/{routes-DQKecVGa.js → routes-fpJMuLAs.js} +1 -1
  31. package/bundle/web-dist/client/assets/{sd.generated-NHYHS_-0.js → sd.generated-CIOZewtL.js} +1 -1
  32. package/bundle/web-dist/client/assets/{services.generated-DDVXMid7.js → services.generated-B2N0iPav.js} +1 -1
  33. package/bundle/web-dist/client/assets/{show-D2z1qxJ5.js → show-xk8Zz6U1.js} +2 -2
  34. package/bundle/web-dist/client/assets/tokens-CPoiSVb6.js +1 -0
  35. package/bundle/web-dist/client/index.html +3 -3
  36. package/bundle/web-dist/server/assets/{copy-BVWDOV2T.js → copy-CKCGxwII.js} +1 -1
  37. package/bundle/web-dist/server/assets/{lazyRouteComponent-BJmwxFyJ.js → lazyRouteComponent-BlvOfJIF.js} +2 -2
  38. package/bundle/web-dist/server/assets/{logs-DgIbufNf.js → logs-C7lTCP1X.js} +167 -87
  39. package/bundle/web-dist/server/assets/{routes-x7-hqUm0.js → routes-p2n4SfAB.js} +2 -2
  40. package/bundle/web-dist/server/assets/{sd.generated-BZPIp4uL.js → sd.generated-CIg_jf8e.js} +5 -2
  41. package/bundle/web-dist/server/assets/{services.generated-BA0gbdmd.js → services.generated-DIeiDdqy.js} +20 -4
  42. package/bundle/web-dist/server/assets/{shim-DGrmZkac.js → shim-Dq_Izqnc.js} +1 -1
  43. package/bundle/web-dist/server/assets/{show-Bk3NayMH.js → show-DZ_U1u-N.js} +30 -9
  44. package/bundle/web-dist/server/assets/{tokens-CVSwt0x0.js → tokens-DTUDs-4D.js} +30 -8
  45. package/bundle/web-dist/server/entry-server.generated.js +12 -8
  46. package/package.json +1 -1
  47. package/bundle/web-dist/client/assets/index-BRZCFaFz.css +0 -1
  48. package/bundle/web-dist/client/assets/index-D8eEjsZj.js +0 -78
  49. package/bundle/web-dist/client/assets/logs-CKnJzuH6.js +0 -1
  50. package/bundle/web-dist/client/assets/tokens-BaywaQkm.js +0 -1
@@ -1,10 +1,9 @@
1
- import { D as require_react, E as require_jsx_runtime, ot as __toESM } from "./sd.generated-BZPIp4uL.js";
2
- import { n as RequestLogService, r as TokenService, t as QgridService } from "./services.generated-BA0gbdmd.js";
3
- import { a as Link, o as useNavigate } from "./lazyRouteComponent-BJmwxFyJ.js";
1
+ import { D as require_react, E as require_jsx_runtime, b as object, x as string, y as number } from "./sd.generated-CIg_jf8e.js";
2
+ import { n as RequestLogService, r as TokenService, t as QgridService } from "./services.generated-DIeiDdqy.js";
3
+ import { a as Link, o as useNavigate } from "./lazyRouteComponent-BlvOfJIF.js";
4
4
  import { n as Route } from "../entry-server.generated.js";
5
5
  import { n as formatUsd, t as formatMicroUsd } from "./cost-DdHTzQDR.js";
6
- //#region ~icons/lucide/chevron-left.jsx
7
- var import_react = /* @__PURE__ */ __toESM(require_react());
6
+ require_react();
8
7
  var import_jsx_runtime = require_jsx_runtime();
9
8
  var lucideChevronLeft = (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", {
10
9
  viewBox: "0 0 24 24",
@@ -39,6 +38,7 @@ var lucideChevronRight = (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
39
38
  //#endregion
40
39
  //#region src/components/qgrid/RequestLogTable.tsx
41
40
  var PAGE_SIZE = 50;
41
+ var UNASSIGNED = "__unassigned__";
42
42
  function formatDateTime(iso) {
43
43
  const d = new Date(iso);
44
44
  return `${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")} ${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}`;
@@ -46,41 +46,117 @@ function formatDateTime(iso) {
46
46
  function formatNum(n) {
47
47
  return n.toLocaleString();
48
48
  }
49
+ function formatDuration(ms) {
50
+ const total = Math.round(ms / 1e3);
51
+ const m = Math.floor(total / 60);
52
+ const s = total % 60;
53
+ return m > 0 ? `${m}m ${s}s` : `${s}s`;
54
+ }
49
55
  function calcCacheHitRate(row) {
50
56
  const denom = row.input_tokens + row.cache_read_tokens + row.cache_creation_tokens;
51
57
  if (denom === 0) return "—";
52
58
  return `${Math.round(row.cache_read_tokens / denom * 100)}%`;
53
59
  }
54
- function trimQuery(q, maxLen = 30) {
55
- return q.length > maxLen ? `${q.slice(0, maxLen)}...` : q;
56
- }
57
- function RequestLogTable({ page: externalPage, onPageChange } = {}) {
60
+ var COLUMNS = [
61
+ {
62
+ label: "ID",
63
+ align: "left",
64
+ width: "w-12"
65
+ },
66
+ {
67
+ label: "Date",
68
+ align: "left",
69
+ width: "w-20"
70
+ },
71
+ {
72
+ label: "Project",
73
+ align: "left",
74
+ width: "w-20"
75
+ },
76
+ {
77
+ label: "Token",
78
+ align: "left",
79
+ width: "w-24"
80
+ },
81
+ {
82
+ label: "Model",
83
+ align: "left",
84
+ width: "w-20"
85
+ },
86
+ {
87
+ label: "Duration",
88
+ align: "left",
89
+ width: "w-20"
90
+ },
91
+ {
92
+ label: "In",
93
+ align: "left",
94
+ width: "w-16"
95
+ },
96
+ {
97
+ label: "Out",
98
+ align: "left",
99
+ width: "w-20"
100
+ },
101
+ {
102
+ label: "C.Read",
103
+ align: "left",
104
+ width: "w-20"
105
+ },
106
+ {
107
+ label: "C.Write",
108
+ align: "left",
109
+ width: "w-20"
110
+ },
111
+ {
112
+ label: "Hit",
113
+ align: "left",
114
+ width: "w-14"
115
+ },
116
+ {
117
+ label: "Cost",
118
+ align: "left",
119
+ width: "w-20"
120
+ }
121
+ ];
122
+ function RequestLogTable({ search, onSearchChange }) {
58
123
  const navigate = useNavigate();
59
- const [internalPage, setInternalPage] = (0, import_react.useState)(1);
60
- const page = externalPage ?? internalPage;
61
- const setPage = onPageChange ?? setInternalPage;
62
- const [tokenFilter, setTokenFilter] = (0, import_react.useState)("");
124
+ const page = search.page ?? 1;
125
+ const tokenFilter = search.token ?? "";
126
+ const projectFilter = search.project ?? "";
63
127
  const { data: tokensData } = TokenService.useTokens("A");
64
128
  const tokenNames = (tokensData?.rows ?? []).map((t) => t.name).filter(Boolean);
65
- const { data, isLoading } = RequestLogService.useRequestLogs("A", {
129
+ const { data: projectData } = QgridService.useProjectNames();
130
+ const projectNames = projectData?.names ?? [];
131
+ const projectFilterParam = (() => {
132
+ if (projectFilter === UNASSIGNED) return { project_name_is_null: true };
133
+ if (projectFilter) return { project_name: projectFilter };
134
+ return {};
135
+ })();
136
+ const { data, isLoading } = RequestLogService.useRequestLogs("P", {
66
137
  num: PAGE_SIZE,
67
138
  page,
68
139
  orderBy: "id-desc",
69
- ...tokenFilter ? { token_name: tokenFilter } : {}
140
+ ...tokenFilter ? { token_name: tokenFilter } : {},
141
+ ...projectFilterParam
70
142
  });
71
143
  const { data: costData } = QgridService.useTotalCost(tokenFilter || void 0);
72
144
  const rows = data?.rows ?? [];
73
145
  const total = data?.total ?? 0;
74
146
  const totalPages = Math.ceil(total / PAGE_SIZE);
147
+ const updateFilter = (patch) => {
148
+ onSearchChange({
149
+ ...search,
150
+ ...patch,
151
+ page: 1
152
+ });
153
+ };
75
154
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
76
- className: "flex items-center gap-2 mb-3 flex-wrap",
155
+ className: "flex items-center gap-2 mb-10 flex-wrap",
77
156
  children: [
78
157
  tokenNames.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", {
79
158
  value: tokenFilter,
80
- onChange: (e) => {
81
- setTokenFilter(e.target.value);
82
- setPage(1);
83
- },
159
+ onChange: (e) => updateFilter({ token: e.target.value || void 0 }),
84
160
  className: "border border-sand-200 rounded-md px-2 py-1 text-xs text-sand-700 bg-white focus:outline-none focus:border-sienna-300",
85
161
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
86
162
  value: "",
@@ -90,6 +166,25 @@ function RequestLogTable({ page: externalPage, onPageChange } = {}) {
90
166
  children: name
91
167
  }, name))]
92
168
  }),
169
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", {
170
+ value: projectFilter,
171
+ onChange: (e) => updateFilter({ project: e.target.value || void 0 }),
172
+ className: "border border-sand-200 rounded-md px-2 py-1 text-xs text-sand-700 bg-white focus:outline-none focus:border-sienna-300",
173
+ children: [
174
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
175
+ value: "",
176
+ children: "All Projects"
177
+ }),
178
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
179
+ value: UNASSIGNED,
180
+ children: "(unassigned)"
181
+ }),
182
+ projectNames.map((name) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
183
+ value: name,
184
+ children: name
185
+ }, name))
186
+ ]
187
+ }),
93
188
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
94
189
  className: "text-[11px] text-sand-400",
95
190
  children: [total, " results"]
@@ -106,54 +201,18 @@ function RequestLogTable({ page: externalPage, onPageChange } = {}) {
106
201
  className: "text-sand-400 text-center py-12 text-sm",
107
202
  children: "No requests yet."
108
203
  }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
109
- className: "rounded-lg bg-sand-50 overflow-hidden",
204
+ className: "rounded-lg bg-sand-50 overflow-hidden w-fit mx-auto px-10 py-4",
110
205
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", {
111
- className: "w-full text-sm",
206
+ className: "text-sm",
112
207
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", {
113
208
  className: "border-b border-sand-200",
114
- children: [
115
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
116
- className: "text-left px-3 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium",
117
- children: "ID"
118
- }),
119
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
120
- className: "text-left px-3 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium",
121
- children: "Date"
122
- }),
123
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
124
- className: "text-left px-3 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium",
125
- children: "Token"
126
- }),
127
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
128
- className: "text-left px-3 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium",
129
- children: "Query"
130
- }),
131
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
132
- className: "text-right px-3 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium",
133
- children: "In"
134
- }),
135
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
136
- className: "text-right px-3 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium",
137
- children: "Out"
138
- }),
139
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
140
- className: "text-right px-3 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium",
141
- children: "C.Read"
142
- }),
143
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
144
- className: "text-right px-3 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium",
145
- children: "C.Write"
146
- }),
147
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
148
- className: "text-right px-3 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium",
149
- children: "Hit"
150
- }),
151
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
152
- className: "text-right px-3 py-2.5 text-[10px] uppercase tracking-wider text-sand-400 font-medium",
153
- children: "Cost"
154
- }),
155
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { className: "w-8 px-2 py-2.5" })
156
- ]
209
+ children: [COLUMNS.map((col) => {
210
+ const padX = col.label === "Duration" ? "pl-5 pr-3" : col.width ? "px-4" : "px-3";
211
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
212
+ className: `text-${col.align} ${col.width ?? ""} ${col.width ? "whitespace-nowrap" : ""} ${padX} py-1.5 text-[10px] uppercase text-sand-400 font-medium`,
213
+ children: col.label
214
+ }, col.label);
215
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { className: "w-8" })]
157
216
  }) }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", {
158
217
  className: "divide-y divide-sand-200/60",
159
218
  children: rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", {
@@ -170,7 +229,7 @@ function RequestLogTable({ page: externalPage, onPageChange } = {}) {
170
229
  },
171
230
  children: [
172
231
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", {
173
- className: "px-3 py-2.5",
232
+ className: "px-4 py-1.5 whitespace-nowrap",
174
233
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Link, {
175
234
  to: "/requests/show",
176
235
  search: { id: row.id },
@@ -180,53 +239,63 @@ function RequestLogTable({ page: externalPage, onPageChange } = {}) {
180
239
  })
181
240
  }),
182
241
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", {
183
- className: "px-3 py-2.5",
242
+ className: "px-4 py-1.5 whitespace-nowrap",
184
243
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
185
- className: "text-[10px] text-sand-400 tabular-nums whitespace-nowrap",
244
+ className: "text-xs text-sand-400 tabular-nums",
186
245
  children: formatDateTime(row.created_at)
187
246
  })
188
247
  }),
189
248
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", {
190
- className: "px-3 py-2.5",
249
+ className: "px-4 py-1.5 whitespace-nowrap",
250
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
251
+ className: "text-xs text-sand-600",
252
+ children: row.project_name ?? "—"
253
+ })
254
+ }),
255
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", {
256
+ className: "px-4 py-1.5 whitespace-nowrap",
191
257
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
192
258
  className: "text-xs text-sand-500",
193
259
  children: row.token_name
194
260
  })
195
261
  }),
196
262
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", {
197
- className: "px-3 py-2.5",
263
+ className: "px-4 py-1.5 whitespace-nowrap",
198
264
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
199
- className: "text-sand-800 truncate max-w-48",
200
- title: row.query,
201
- children: trimQuery(row.query)
265
+ className: "text-xs text-sand-500",
266
+ children: row.model_name ?? "—"
202
267
  })
203
268
  }),
204
269
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", {
205
- className: "px-3 py-2.5 text-right tabular-nums text-sand-700",
270
+ className: "pl-5 pr-3 py-1.5 text-left tabular-nums text-sand-500 whitespace-nowrap",
271
+ children: formatDuration(row.duration_ms)
272
+ }),
273
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", {
274
+ className: "px-3 py-1.5 text-left tabular-nums text-sand-700",
206
275
  children: formatNum(row.input_tokens)
207
276
  }),
208
277
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", {
209
- className: "px-3 py-2.5 text-right tabular-nums text-sand-700",
278
+ className: "px-3 py-1.5 text-left tabular-nums text-sand-700",
210
279
  children: formatNum(row.output_tokens)
211
280
  }),
212
281
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", {
213
- className: "px-3 py-2.5 text-right tabular-nums text-sand-700",
282
+ className: "px-3 py-1.5 text-left tabular-nums text-sand-700",
214
283
  children: formatNum(row.cache_read_tokens)
215
284
  }),
216
285
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", {
217
- className: "px-3 py-2.5 text-right tabular-nums text-sand-700",
286
+ className: "px-3 py-1.5 text-left tabular-nums text-sand-700",
218
287
  children: formatNum(row.cache_creation_tokens)
219
288
  }),
220
289
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", {
221
- className: "px-3 py-2.5 text-right tabular-nums text-sand-700",
290
+ className: "px-3 py-1.5 text-left tabular-nums text-sand-700",
222
291
  children: calcCacheHitRate(row)
223
292
  }),
224
293
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", {
225
- className: "px-3 py-2.5 text-right tabular-nums text-sand-700",
226
- children: row.cost_usd !== null ? formatMicroUsd(row.cost_usd) : "-"
294
+ className: "px-3 py-1.5 text-left tabular-nums text-sand-700",
295
+ children: row.cost_usd !== null ? formatMicroUsd(row.cost_usd) : ""
227
296
  }),
228
297
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", {
229
- className: "px-2 py-2.5",
298
+ className: "px-2 py-1.5",
230
299
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(lucideChevronRight, { className: "size-4 text-sand-400" })
231
300
  })
232
301
  ]
@@ -240,7 +309,10 @@ function RequestLogTable({ page: externalPage, onPageChange } = {}) {
240
309
  type: "button",
241
310
  className: "p-1 rounded text-sand-400 hover:text-sand-600 disabled:opacity-30 transition-colors",
242
311
  disabled: page === 1,
243
- onClick: () => setPage(page - 1),
312
+ onClick: () => onSearchChange({
313
+ ...search,
314
+ page: page - 1
315
+ }),
244
316
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(lucideChevronLeft, { className: "size-4" })
245
317
  }),
246
318
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
@@ -255,7 +327,10 @@ function RequestLogTable({ page: externalPage, onPageChange } = {}) {
255
327
  type: "button",
256
328
  className: "p-1 rounded text-sand-400 hover:text-sand-600 disabled:opacity-30 transition-colors",
257
329
  disabled: page === totalPages,
258
- onClick: () => setPage(page + 1),
330
+ onClick: () => onSearchChange({
331
+ ...search,
332
+ page: page + 1
333
+ }),
259
334
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(lucideChevronRight, { className: "size-4" })
260
335
  })
261
336
  ]
@@ -263,17 +338,22 @@ function RequestLogTable({ page: externalPage, onPageChange } = {}) {
263
338
  }
264
339
  //#endregion
265
340
  //#region src/routes/logs.tsx?tsr-split=component
341
+ object({
342
+ token: string().optional(),
343
+ project: string().optional(),
344
+ page: number().optional().default(1)
345
+ });
266
346
  function LogsPage() {
267
- const { page } = Route.useSearch();
347
+ const search = Route.useSearch();
268
348
  const navigate = Route.useNavigate();
269
349
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
270
- className: "space-y-5 max-w-300 mx-auto -translate-x-4",
350
+ className: "space-y-5 max-w-[96rem] mx-auto -translate-x-4",
271
351
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", {
272
352
  className: "text-xl font-medium text-sand-900 tracking-tight",
273
353
  children: "Request Logs"
274
354
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RequestLogTable, {
275
- page,
276
- onPageChange: (p) => navigate({ search: { page: p } })
355
+ search,
356
+ onSearchChange: (next) => navigate({ search: next })
277
357
  })]
278
358
  });
279
359
  }
@@ -1,5 +1,5 @@
1
- import { C as require_react_dom, D as require_react, E as require_jsx_runtime, T as useQueryClient, ot as __toESM } from "./sd.generated-BZPIp4uL.js";
2
- import { r as TokenService, t as QgridService } from "./services.generated-BA0gbdmd.js";
1
+ import { C as require_react_dom, D as require_react, E as require_jsx_runtime, T as useQueryClient, ot as __toESM } from "./sd.generated-CIg_jf8e.js";
2
+ import { r as TokenService, t as QgridService } from "./services.generated-DIeiDdqy.js";
3
3
  import { n as formatUsd } from "./cost-DdHTzQDR.js";
4
4
  //#region ../../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@19.2.4/node_modules/@dnd-kit/utilities/dist/utilities.esm.js
5
5
  var import_react_dom = /* @__PURE__ */ __toESM(require_react_dom());
@@ -22067,7 +22067,10 @@ var entityLabels = {
22067
22067
  "entity.RequestLog.id": "ID",
22068
22068
  "entity.RequestLog.created_at": "등록일시",
22069
22069
  "entity.RequestLog.token_name": "토큰 이름",
22070
- "entity.RequestLog.query": "prompt 전문",
22070
+ "entity.RequestLog.project_name": "프로젝트 이름",
22071
+ "entity.RequestLog.model_name": "모델 이름",
22072
+ "entity.RequestLog.user_prompt": "사용자 프롬프트",
22073
+ "entity.RequestLog.system_prompt": "시스템 프롬프트",
22071
22074
  "entity.RequestLog.response": "llm 응답 전문",
22072
22075
  "entity.RequestLog.input_tokens": "입력 토큰",
22073
22076
  "entity.RequestLog.output_tokens": "출력 토큰",
@@ -22078,7 +22081,7 @@ var entityLabels = {
22078
22081
  "enum.RequestLogOrderBy.id-desc": "ID최신순",
22079
22082
  "enum.RequestLogSearchField.id": "ID",
22080
22083
  "enum.RequestLogSearchField.token_name": "토큰이름",
22081
- "enum.RequestLogSearchField.query": "쿼리",
22084
+ "enum.RequestLogSearchField.user_prompt": "사용자 프롬프트",
22082
22085
  "entity.Token": "Token",
22083
22086
  "entity.Token.id": "ID",
22084
22087
  "entity.Token.created_at": "등록일시",
@@ -1,4 +1,4 @@
1
- import { $ as timeUntilStale, A as hasNextPage, B as hashKey, D as require_react, E as require_jsx_runtime, G as noop, H as isValidTimeout, I as notifyManager, J as resolveEnabled, L as pendingThenable, M as infiniteQueryBehavior, P as fetchState, R as environmentManager, S as require_lib, T as useQueryClient, X as shallowEqualObjects, Y as resolveStaleTime, Z as shouldThrowError, a as dedupeAndFlatten, et as timeoutManager, j as hasPreviousPage, k as getDefaultState, nt as Subscribable, o as fetch, ot as __toESM, q as replaceData, s as useRefreshable, tt as focusManager } from "./sd.generated-BZPIp4uL.js";
1
+ import { $ as timeUntilStale, A as hasNextPage, B as hashKey, D as require_react, E as require_jsx_runtime, G as noop, H as isValidTimeout, I as notifyManager, J as resolveEnabled, L as pendingThenable, M as infiniteQueryBehavior, P as fetchState, R as environmentManager, S as require_lib, T as useQueryClient, X as shallowEqualObjects, Y as resolveStaleTime, Z as shouldThrowError, a as dedupeAndFlatten, et as timeoutManager, j as hasPreviousPage, k as getDefaultState, nt as Subscribable, o as fetch, ot as __toESM, q as replaceData, s as useRefreshable, tt as focusManager } from "./sd.generated-CIg_jf8e.js";
2
2
  //#region ../../node_modules/.pnpm/@tanstack+query-core@5.95.2/node_modules/@tanstack/query-core/build/modern/queryObserver.js
3
3
  var QueryObserver = class extends Subscribable {
4
4
  constructor(client, options) {
@@ -835,7 +835,7 @@ var RequestLogService;
835
835
  })(RequestLogService || (RequestLogService = {}));
836
836
  var QgridService;
837
837
  (function(_QgridService) {
838
- async function query(prompt, system, timeout, model) {
838
+ async function query(prompt, system, timeout, model, projectName) {
839
839
  return fetch({
840
840
  method: "POST",
841
841
  url: `/api/qgrid/query`,
@@ -843,12 +843,13 @@ var QgridService;
843
843
  prompt,
844
844
  system,
845
845
  timeout,
846
- model
846
+ model,
847
+ projectName
847
848
  }
848
849
  });
849
850
  }
850
851
  _QgridService.query = query;
851
- _QgridService.useQueryMutation = () => useMutation({ mutationFn: (params) => query(params.prompt, params.system, params.timeout, params.model) });
852
+ _QgridService.useQueryMutation = () => useMutation({ mutationFn: (params) => query(params.prompt, params.system, params.timeout, params.model, params.projectName) });
852
853
  async function stats() {
853
854
  return fetch({
854
855
  method: "GET",
@@ -883,6 +884,21 @@ var QgridService;
883
884
  ...totalCostQueryOptions(tokenName),
884
885
  ...options
885
886
  }));
887
+ async function projectNames() {
888
+ return fetch({
889
+ method: "GET",
890
+ url: `/api/qgrid/projectNames`
891
+ });
892
+ }
893
+ _QgridService.projectNames = projectNames;
894
+ const projectNamesQueryOptions = _QgridService.projectNamesQueryOptions = () => queryOptions({
895
+ queryKey: ["Qgrid", "projectNames"],
896
+ queryFn: () => projectNames()
897
+ });
898
+ _QgridService.useProjectNames = (options) => useRefreshable(useQuery({
899
+ ...projectNamesQueryOptions(),
900
+ ...options
901
+ }));
886
902
  async function addToken(token, name, refreshToken) {
887
903
  return fetch({
888
904
  method: "POST",
@@ -1,4 +1,4 @@
1
- import { D as require_react, rt as __commonJSMin } from "./sd.generated-BZPIp4uL.js";
1
+ import { D as require_react, rt as __commonJSMin } from "./sd.generated-CIg_jf8e.js";
2
2
  //#region ../../node_modules/.pnpm/use-sync-external-store@1.6.0_react@19.2.4/node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.production.js
3
3
  /**
4
4
  * @license React
@@ -1,8 +1,8 @@
1
- import { D as require_react, E as require_jsx_runtime, it as __exportAll, ot as __toESM, rt as __commonJSMin } from "./sd.generated-BZPIp4uL.js";
2
- import { n as RequestLogService } from "./services.generated-BA0gbdmd.js";
3
- import { a as Link } from "./lazyRouteComponent-BJmwxFyJ.js";
1
+ import { D as require_react, E as require_jsx_runtime, it as __exportAll, ot as __toESM, rt as __commonJSMin } from "./sd.generated-CIg_jf8e.js";
2
+ import { n as RequestLogService } from "./services.generated-DIeiDdqy.js";
3
+ import { a as Link } from "./lazyRouteComponent-BlvOfJIF.js";
4
4
  import { t as Route } from "../entry-server.generated.js";
5
- import { n as lucideCheck, t as lucideCopy } from "./copy-BVWDOV2T.js";
5
+ import { n as lucideCheck, t as lucideCopy } from "./copy-CKCGxwII.js";
6
6
  import minpath from "node:path";
7
7
  import minproc from "node:process";
8
8
  import { fileURLToPath as urlToPath } from "node:url";
@@ -23457,13 +23457,20 @@ function RequestDetail({ id }) {
23457
23457
  children: "Request Detail"
23458
23458
  }),
23459
23459
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Section, {
23460
- title: "Query",
23461
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
23462
- className: "rounded-lg bg-sand-50 px-4 py-3",
23463
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FormattedContent, { text: data.query })
23460
+ title: "System",
23461
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
23462
+ className: "relative rounded-lg bg-sand-50 px-4 py-3",
23463
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CopyButton, { text: data.system_prompt ?? "null" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FormattedContent, { text: data.system_prompt ?? "null" })]
23464
+ })
23465
+ }),
23466
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Section, {
23467
+ title: "User",
23468
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
23469
+ className: "relative rounded-lg bg-sand-50 px-4 py-3",
23470
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CopyButton, { text: data.user_prompt ?? "null" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FormattedContent, { text: data.user_prompt ?? "null" })]
23464
23471
  })
23465
23472
  }),
23466
- data.response && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Section, {
23473
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Section, {
23467
23474
  title: "Response",
23468
23475
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
23469
23476
  className: "relative rounded-lg bg-sand-50 px-4 py-3",
@@ -23534,6 +23541,13 @@ function RequestDetail({ id }) {
23534
23541
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tbody", {
23535
23542
  className: "text-sand-700",
23536
23543
  children: [
23544
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", {
23545
+ className: "py-1.5 text-sand-500",
23546
+ children: "Project"
23547
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", {
23548
+ className: "py-1.5 text-right font-medium text-sand-800",
23549
+ children: data.project_name ?? "—"
23550
+ })] }),
23537
23551
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", {
23538
23552
  className: "py-1.5 text-sand-500",
23539
23553
  children: "Token"
@@ -23541,6 +23555,13 @@ function RequestDetail({ id }) {
23541
23555
  className: "py-1.5 text-right font-medium text-sand-800",
23542
23556
  children: data.token_name
23543
23557
  })] }),
23558
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", {
23559
+ className: "py-1.5 text-sand-500",
23560
+ children: "Model"
23561
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", {
23562
+ className: "py-1.5 text-right font-medium text-sand-800",
23563
+ children: data.model_name ?? "—"
23564
+ })] }),
23544
23565
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", {
23545
23566
  className: "py-1.5 text-sand-500",
23546
23567
  children: "Time"
@@ -1,7 +1,7 @@
1
- import { D as require_react, E as require_jsx_runtime, T as useQueryClient, _ as date, b as object, c as zArrayable, g as custom, h as boolean, i as SonamuQueryMode, m as bigint, ot as __toESM, p as _enum, v as int, x as string, y as number } from "./sd.generated-BZPIp4uL.js";
2
- import { r as TokenService, t as QgridService } from "./services.generated-BA0gbdmd.js";
1
+ import { D as require_react, E as require_jsx_runtime, T as useQueryClient, _ as date, b as object, c as zArrayable, g as custom, h as boolean, i as SonamuQueryMode, m as bigint, ot as __toESM, p as _enum, v as int, x as string, y as number } from "./sd.generated-CIg_jf8e.js";
2
+ import { r as TokenService, t as QgridService } from "./services.generated-DIeiDdqy.js";
3
3
  import { a as lucideKeyRound, i as ro, r as Q } from "../entry-server.generated.js";
4
- import { n as lucideCheck, t as lucideCopy } from "./copy-BVWDOV2T.js";
4
+ import { n as lucideCheck, t as lucideCopy } from "./copy-CKCGxwII.js";
5
5
  //#region ~icons/lucide/eye.jsx
6
6
  var import_react = /* @__PURE__ */ __toESM(require_react());
7
7
  var import_jsx_runtime = require_jsx_runtime();
@@ -65,7 +65,7 @@ var RequestLogOrderBy = _enum(["id-desc"]).describe("RequestLogOrderBy");
65
65
  var RequestLogSearchField = _enum([
66
66
  "id",
67
67
  "token_name",
68
- "query"
68
+ "user_prompt"
69
69
  ]).describe("RequestLogSearchField");
70
70
  var TokenOrderBy = _enum(["id-desc", "ord-asc"]).describe("TokenOrderBy");
71
71
  var TokenSearchField = _enum(["id", "name"]).describe("TokenSearchField");
@@ -73,7 +73,10 @@ object({
73
73
  id: int(),
74
74
  created_at: date(),
75
75
  token_name: string().max(100),
76
- query: string(),
76
+ project_name: string().max(50).nullable(),
77
+ model_name: string().max(50).nullable(),
78
+ user_prompt: string().nullable(),
79
+ system_prompt: string().nullable(),
77
80
  response: string(),
78
81
  input_tokens: int(),
79
82
  output_tokens: int(),
@@ -102,7 +105,9 @@ object({
102
105
  queryMode: SonamuQueryMode,
103
106
  id: zArrayable(number().int().positive()),
104
107
  sonamuFilter: custom(),
105
- token_name: string().max(100)
108
+ token_name: string().max(100),
109
+ project_name: string().max(50).nullable(),
110
+ model_name: string().max(50).nullable()
106
111
  }).partial();
107
112
  object({
108
113
  num: number().int().nonnegative(),
@@ -119,7 +124,10 @@ object({
119
124
  id: int(),
120
125
  created_at: date(),
121
126
  token_name: string().max(100),
122
- query: string(),
127
+ project_name: string().max(50).nullable(),
128
+ model_name: string().max(50).nullable(),
129
+ user_prompt: string().nullable(),
130
+ system_prompt: string().nullable(),
123
131
  response: string(),
124
132
  input_tokens: int(),
125
133
  output_tokens: int(),
@@ -128,7 +136,20 @@ object({
128
136
  duration_ms: int(),
129
137
  cost_usd: int().nullable()
130
138
  });
131
- _enum(["A"]);
139
+ object({
140
+ id: int(),
141
+ created_at: date(),
142
+ token_name: string().max(100),
143
+ project_name: string().max(50).nullable(),
144
+ model_name: string().max(50).nullable(),
145
+ input_tokens: int(),
146
+ output_tokens: int(),
147
+ cache_read_tokens: int(),
148
+ cache_creation_tokens: int(),
149
+ duration_ms: int(),
150
+ cost_usd: int().nullable()
151
+ });
152
+ _enum(["A", "P"]);
132
153
  object({
133
154
  id: int(),
134
155
  created_at: date(),
@@ -356,6 +377,7 @@ object({
356
377
  object({
357
378
  text: string(),
358
379
  tokenName: string().optional(),
380
+ model: string().optional(),
359
381
  usage: object({
360
382
  input_tokens: number(),
361
383
  output_tokens: number(),