@shardworks/clerk-apparatus 0.1.260 → 0.1.261

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shardworks/clerk-apparatus",
3
- "version": "0.1.260",
3
+ "version": "0.1.261",
4
4
  "license": "ISC",
5
5
  "repository": {
6
6
  "type": "git",
@@ -20,12 +20,12 @@
20
20
  },
21
21
  "dependencies": {
22
22
  "zod": "4.3.6",
23
- "@shardworks/stacks-apparatus": "0.1.260",
24
- "@shardworks/tools-apparatus": "0.1.260"
23
+ "@shardworks/stacks-apparatus": "0.1.261",
24
+ "@shardworks/tools-apparatus": "0.1.261"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@types/node": "25.5.0",
28
- "@shardworks/nexus-core": "0.1.260"
28
+ "@shardworks/nexus-core": "0.1.261"
29
29
  },
30
30
  "files": [
31
31
  "dist",
@@ -462,12 +462,31 @@
462
462
 
463
463
  // ── Render ─────────────────────────────────────────────────────────
464
464
 
465
+ /**
466
+ * Pure empty-state message chooser — invoked from renderTable's empty
467
+ * branch. When the operator has deselected every type filter, name both
468
+ * the cause and the remedy; for every other empty case (empty backend
469
+ * result, phase filter with no hits, search text with no matches) fall
470
+ * back to the generic "No writs found." message. `forestIsEmpty`
471
+ * documents the caller's precondition (this helper is only meaningful
472
+ * when the table is actually empty) but does not change the decision —
473
+ * the type-deselected branch always wins when it applies, because that
474
+ * is the only case where loadWrits short-circuits the network fetch.
475
+ */
476
+ function chooseEmptyStateMessage(noTypesSelected, forestIsEmpty) {
477
+ if (noTypesSelected) {
478
+ return 'All types deselected — select at least one type to see writs';
479
+ }
480
+ return 'No writs found.';
481
+ }
482
+
465
483
  function renderTable() {
466
484
  const tbody = document.getElementById('writ-tbody');
467
485
  const visible = sortedFilteredWrits();
468
486
 
469
487
  if (visible.length === 0 && forest.length === 0) {
470
- tbody.innerHTML = `<tr><td colspan="6"><div class="empty-state">No writs found.</div></td></tr>`;
488
+ const message = chooseEmptyStateMessage(currentType.size === 0, forest.length === 0);
489
+ tbody.innerHTML = `<tr><td colspan="6"><div class="empty-state">${message}</div></td></tr>`;
471
490
  return;
472
491
  }
473
492
 
@@ -226,6 +226,20 @@ function depthIndentStyle(depth) {
226
226
  return `padding-left:${rem}rem`;
227
227
  }
228
228
 
229
+ /**
230
+ * Mirrors chooseEmptyStateMessage in index.html. Pure: decides which
231
+ * empty-state message to show when the writs table is empty. When the
232
+ * operator has deselected every type filter, name both the cause and the
233
+ * remedy; every other empty case (empty backend result, phase filter with
234
+ * no hits, search text with no matches) falls back to the generic message.
235
+ */
236
+ function chooseEmptyStateMessage(noTypesSelected, forestIsEmpty) {
237
+ if (noTypesSelected) {
238
+ return 'All types deselected — select at least one type to see writs';
239
+ }
240
+ return 'No writs found.';
241
+ }
242
+
229
243
  /**
230
244
  * Extracted renderDetail logic for parent link and children table.
231
245
  * The detail view stays direct-children-only (D20).
@@ -1001,3 +1015,27 @@ describe('Deep descendant rendering in detail view', () => {
1001
1015
  assert.ok(!html.match(/data-action="row-publish"[^>]*data-id="g"/));
1002
1016
  });
1003
1017
  });
1018
+
1019
+ describe('chooseEmptyStateMessage — empty-state message chooser', () => {
1020
+ it('returns the type-deselected message when no types are selected', () => {
1021
+ // When the operator toggles off every type filter, loadWrits short-
1022
+ // circuits with forest = [] and renderTable reaches the empty branch
1023
+ // with currentType.size === 0. The chooser must name the deselection
1024
+ // as the cause and direct the operator to the remedy — verbatim.
1025
+ assert.equal(
1026
+ chooseEmptyStateMessage(true, true),
1027
+ 'All types deselected — select at least one type to see writs',
1028
+ );
1029
+ });
1030
+
1031
+ it('returns the generic "No writs found." message when at least one type is selected but the forest is empty', () => {
1032
+ // Phase filter with no hits, search text with no matches, or a valid
1033
+ // filter set that genuinely returns nothing — all fall through to the
1034
+ // generic message. The string is kept exact so wording drift breaks
1035
+ // the suite.
1036
+ assert.equal(
1037
+ chooseEmptyStateMessage(false, true),
1038
+ 'No writs found.',
1039
+ );
1040
+ });
1041
+ });