@dudousxd/nestjs-durable-dashboard 0.40.0 → 0.42.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.
@@ -135,6 +135,11 @@ var DashboardService = class {
135
135
  listRuns(query) {
136
136
  return this.gateway.listRuns(query);
137
137
  }
138
+ /** `(status, origin)` counts over the same predicates {@link listRuns} pages — what keeps the
139
+ * console's chips exact while its list is bounded to a page. */
140
+ runFacets(query) {
141
+ return this.gateway.runFacets(query);
142
+ }
138
143
  /** This deployment's durable role (control plane vs tenant) + tenant name — for the dashboard header
139
144
  * badge. Routes through the gateway, which knows its own topology (store-backed = operator, proxy =
140
145
  * tenant). Works on both topologies (no store/engine needed). */
@@ -163,8 +168,12 @@ var DashboardService = class {
163
168
  return this.gateway.cancel(runId, opts);
164
169
  }
165
170
  /**
166
- * Apply `retry` or `cancel` to every run matching a filter (status / tag / workflow) — e.g. "retry
167
- * every `dead` run tagged `type:mel`". Capped at 500 runs per call; runs that can't be acted on
171
+ * Apply `retry` or `cancel` to every run matching a filter (status / tag / workflow / namespace /
172
+ * origin) — e.g. "retry every `dead` run tagged `type:mel`". The filter is the same one the run
173
+ * list uses, so a bulk action can never reach wider than the list it was launched from — but note
174
+ * an ABSENT predicate still means "every value on that axis" (an omitted `namespace` is every
175
+ * tenant), which is what makes passing the operator's full filter through mandatory, not optional.
176
+ * Capped at 500 runs per call; runs that can't be acted on
168
177
  * (already terminal) are skipped. Returns how many matched and how many the action applied to.
169
178
  */
170
179
  async bulk(action, filter, opts) {
@@ -276,6 +285,13 @@ function parseAttrFilters(attr) {
276
285
  }
277
286
  __name(parseAttrFilters, "parseAttrFilters");
278
287
 
288
+ // src/server/run-list-row.ts
289
+ function toRunListRow(run) {
290
+ const { input: _input, output: _output, error: _error, ...row } = run;
291
+ return row;
292
+ }
293
+ __name(toRunListRow, "toRunListRow");
294
+
279
295
  // src/server/durable-api.controller.ts
280
296
  function _ts_decorate2(decorators, target, key, desc) {
281
297
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -294,6 +310,41 @@ function _ts_param2(paramIndex, decorator) {
294
310
  };
295
311
  }
296
312
  __name(_ts_param2, "_ts_param");
313
+ function pageBounds(limit, offset) {
314
+ const bound = /* @__PURE__ */ __name((raw) => {
315
+ const n = Number(raw);
316
+ return raw !== void 0 && raw !== "" && Number.isInteger(n) && n >= 0 ? n : void 0;
317
+ }, "bound");
318
+ const l = bound(limit);
319
+ const o = bound(offset);
320
+ return {
321
+ ...l !== void 0 ? {
322
+ limit: l
323
+ } : {},
324
+ ...o !== void 0 ? {
325
+ offset: o
326
+ } : {}
327
+ };
328
+ }
329
+ __name(pageBounds, "pageBounds");
330
+ function statusPredicate(status) {
331
+ if (Array.isArray(status)) return status.length ? {
332
+ statuses: status
333
+ } : {};
334
+ return status ? {
335
+ status
336
+ } : {};
337
+ }
338
+ __name(statusPredicate, "statusPredicate");
339
+ function originPredicate(origin, unattributed) {
340
+ if (unattributed === "true" || unattributed === "1") return {
341
+ origin: null
342
+ };
343
+ return origin ? {
344
+ origin
345
+ } : {};
346
+ }
347
+ __name(originPredicate, "originPredicate");
297
348
  var DurableApiController = class {
298
349
  static {
299
350
  __name(this, "DurableApiController");
@@ -302,12 +353,40 @@ var DurableApiController = class {
302
353
  constructor(dashboard) {
303
354
  this.dashboard = dashboard;
304
355
  }
305
- runs(status, workflow, tag, attr) {
306
- return this.dashboard.listRuns({
307
- status,
356
+ /**
357
+ * The run list, filtered by whatever the operator asked for. Every predicate is OPTIONAL and an
358
+ * omitted one means "don't narrow on this axis" — in particular `namespace`, whose absence keeps
359
+ * the historical, deliberate behaviour that read paths are NOT namespace-scoped (core,
360
+ * `WorkflowRun.namespace`): the console shows every tenant's runs until an operator chooses one.
361
+ * A blank param (`?namespace=`, from a cleared filter box) is the same as an absent one; passing
362
+ * `''` through would be an exact match on a tenant nobody has, i.e. a silently empty console.
363
+ */
364
+ async runs(status, workflow, tag, attr, namespace, origin, unattributed, limit, offset) {
365
+ const runs = await this.dashboard.listRuns({
366
+ ...statusPredicate(status),
308
367
  workflow,
309
368
  tag,
310
- attributes: parseAttrFilters(attr)
369
+ attributes: parseAttrFilters(attr),
370
+ namespace: namespace || void 0,
371
+ ...originPredicate(origin, unattributed),
372
+ ...pageBounds(limit, offset)
373
+ });
374
+ return runs.map(toRunListRow);
375
+ }
376
+ /**
377
+ * `(status, origin)` counts for the runs matching the same tag/tenant/attribute predicates as
378
+ * `GET runs`. This is what lets that listing be PAGED at all: the page bounds what the console
379
+ * renders, this bounds nothing and keeps its status and origin chips exact.
380
+ *
381
+ * `status`, `origin` and the page bounds are deliberately NOT accepted — they are the axes being
382
+ * counted, so narrowing by them would report the answer back to itself.
383
+ */
384
+ facets(workflow, tag, attr, namespace) {
385
+ return this.dashboard.runFacets({
386
+ workflow,
387
+ tag,
388
+ attributes: parseAttrFilters(attr),
389
+ namespace: namespace || void 0
311
390
  });
312
391
  }
313
392
  /** Prometheus-text metrics (runs/steps by outcome, per-workflow counts) for a scrape. */
@@ -339,13 +418,22 @@ var DurableApiController = class {
339
418
  retryWithInput(id, body) {
340
419
  return this.dashboard.retryWithInput(id, body?.input);
341
420
  }
342
- /** Bulk retry/cancel every run matching a filter (status / tag / workflow). */
343
- bulk(action, status, tag, workflow, attr, compensate) {
421
+ /**
422
+ * Bulk retry/cancel every run matching a filter (status / tag / workflow / namespace / origin).
423
+ * The filter takes the SAME params as `GET runs` and is parsed identically, so "retry all" acts on
424
+ * exactly the set the operator was looking at rather than a wider one.
425
+ */
426
+ bulk(action, status, tag, workflow, attr, compensate, namespace, origin, unattributed) {
344
427
  return this.dashboard.bulk(action === "cancel" ? "cancel" : "retry", {
345
428
  status,
346
429
  tag,
347
430
  workflow,
348
- attributes: parseAttrFilters(attr)
431
+ attributes: parseAttrFilters(attr),
432
+ namespace: namespace || void 0,
433
+ // The unattributed bucket is a scope a console can actually SELECT, so a bulk action launched
434
+ // under it must be narrowed to it. Dropping the param would widen a retry/cancel to every
435
+ // origin — acting on runs the operator was not looking at.
436
+ ...originPredicate(origin, unattributed)
349
437
  }, {
350
438
  compensate: compensate === "true"
351
439
  });
@@ -394,15 +482,40 @@ _ts_decorate2([
394
482
  _ts_param2(1, (0, import_common2.Query)("workflow")),
395
483
  _ts_param2(2, (0, import_common2.Query)("tag")),
396
484
  _ts_param2(3, (0, import_common2.Query)("attr")),
485
+ _ts_param2(4, (0, import_common2.Query)("namespace")),
486
+ _ts_param2(5, (0, import_common2.Query)("origin")),
487
+ _ts_param2(6, (0, import_common2.Query)("unattributed")),
488
+ _ts_param2(7, (0, import_common2.Query)("limit")),
489
+ _ts_param2(8, (0, import_common2.Query)("offset")),
397
490
  _ts_metadata2("design:type", Function),
398
491
  _ts_metadata2("design:paramtypes", [
399
- typeof RunStatus === "undefined" ? Object : RunStatus,
492
+ Object,
400
493
  String,
401
494
  String,
402
- Object
495
+ Object,
496
+ String,
497
+ String,
498
+ String,
499
+ String,
500
+ String
403
501
  ]),
404
- _ts_metadata2("design:returntype", void 0)
502
+ _ts_metadata2("design:returntype", Promise)
405
503
  ], DurableApiController.prototype, "runs", null);
504
+ _ts_decorate2([
505
+ (0, import_common2.Get)("runs/facets"),
506
+ _ts_param2(0, (0, import_common2.Query)("workflow")),
507
+ _ts_param2(1, (0, import_common2.Query)("tag")),
508
+ _ts_param2(2, (0, import_common2.Query)("attr")),
509
+ _ts_param2(3, (0, import_common2.Query)("namespace")),
510
+ _ts_metadata2("design:type", Function),
511
+ _ts_metadata2("design:paramtypes", [
512
+ String,
513
+ String,
514
+ Object,
515
+ String
516
+ ]),
517
+ _ts_metadata2("design:returntype", void 0)
518
+ ], DurableApiController.prototype, "facets", null);
406
519
  _ts_decorate2([
407
520
  (0, import_common2.Get)("metrics"),
408
521
  (0, import_common2.Header)("Content-Type", "text/plain; version=0.0.4"),
@@ -468,6 +581,9 @@ _ts_decorate2([
468
581
  _ts_param2(3, (0, import_common2.Query)("workflow")),
469
582
  _ts_param2(4, (0, import_common2.Query)("attr")),
470
583
  _ts_param2(5, (0, import_common2.Query)("compensate")),
584
+ _ts_param2(6, (0, import_common2.Query)("namespace")),
585
+ _ts_param2(7, (0, import_common2.Query)("origin")),
586
+ _ts_param2(8, (0, import_common2.Query)("unattributed")),
471
587
  _ts_metadata2("design:type", Function),
472
588
  _ts_metadata2("design:paramtypes", [
473
589
  String,
@@ -475,6 +591,9 @@ _ts_decorate2([
475
591
  String,
476
592
  String,
477
593
  Object,
594
+ String,
595
+ String,
596
+ String,
478
597
  String
479
598
  ]),
480
599
  _ts_metadata2("design:returntype", void 0)