@rogatio/cli 6.9.1 → 6.11.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.
@@ -163,28 +163,60 @@
163
163
  display: flex;
164
164
  flex-wrap: wrap;
165
165
  align-items: center;
166
- gap: 0.35rem;
166
+ gap: 0.75rem 1rem;
167
167
  border-bottom: 1px solid var(--rogatio-border);
168
168
  background: color-mix(in srgb, var(--rogatio-surface) 92%, #000);
169
169
  padding: 0.6rem 1rem;
170
170
  backdrop-filter: blur(8px);
171
171
  }
172
- .rogatio-editor [data-desktop-route-rail] button {
173
- border: 1px solid transparent;
174
- border-radius: 999px;
175
- background: transparent;
176
- padding: 0.35rem 0.8rem;
172
+ .rogatio-editor [data-route-breadcrumb] {
173
+ display: flex;
174
+ flex-wrap: wrap;
175
+ align-items: center;
176
+ margin: 0;
177
+ padding: 0;
178
+ list-style: none;
179
+ min-width: 0;
180
+ }
181
+ .rogatio-editor [data-route-breadcrumb] li {
182
+ display: inline-flex;
183
+ align-items: center;
184
+ min-width: 0;
185
+ max-width: 18rem;
186
+ }
187
+ .rogatio-editor [data-route-breadcrumb] li + li::before {
188
+ content: "/";
189
+ margin: 0 0.45rem;
177
190
  color: var(--rogatio-muted);
191
+ font-weight: 500;
178
192
  }
179
- .rogatio-editor [data-desktop-route-rail] button:hover:not(:disabled) {
180
- background: var(--rogatio-surface-raised);
181
- color: var(--rogatio-text);
193
+ .rogatio-editor [data-route-breadcrumb] button {
194
+ max-width: 18rem;
195
+ overflow: hidden;
196
+ border-color: transparent;
197
+ background: transparent;
198
+ padding: 0.15rem 0.2rem;
199
+ font-weight: 700;
200
+ text-overflow: ellipsis;
201
+ white-space: nowrap;
182
202
  }
183
- .rogatio-editor [data-desktop-route-rail] button[aria-current=page] {
184
- border-color: rgba(59, 158, 255, 0.45);
185
- background: var(--rogatio-primary-bg);
203
+ .rogatio-editor [data-route-breadcrumb] button:hover:not(:disabled) {
204
+ border-color: transparent;
205
+ background: transparent;
206
+ color: var(--rogatio-primary);
207
+ }
208
+ .rogatio-editor [data-route-breadcrumb] button[aria-current=page] {
186
209
  color: var(--rogatio-text);
187
- font-weight: 700;
210
+ }
211
+ .rogatio-editor [data-route-breadcrumb] button:not([aria-current=page]) {
212
+ color: var(--rogatio-muted);
213
+ font-weight: 600;
214
+ }
215
+ .rogatio-editor [data-search-wrap] {
216
+ margin-left: auto;
217
+ flex: 0 0 auto;
218
+ width: min(18rem, 100%);
219
+ min-width: 0;
188
220
  }
189
221
  .rogatio-editor [data-editor-main] {
190
222
  min-width: 0;
@@ -192,7 +224,7 @@
192
224
  }
193
225
  .rogatio-editor [data-editor-header] {
194
226
  display: grid;
195
- grid-template-columns: minmax(0, 1fr) minmax(14rem, 24rem);
227
+ grid-template-columns: minmax(0, 1fr);
196
228
  gap: 1rem;
197
229
  align-items: end;
198
230
  margin-bottom: 1rem;
@@ -240,9 +272,6 @@
240
272
  min-height: 5rem;
241
273
  resize: vertical;
242
274
  }
243
- .rogatio-editor [data-mobile-route-nav] {
244
- display: none;
245
- }
246
275
  .rogatio-editor [data-editor-status] {
247
276
  min-height: 1.5rem;
248
277
  margin-block: 0.5rem;
@@ -273,6 +302,17 @@
273
302
  text-align: left;
274
303
  text-decoration: underline;
275
304
  }
305
+ .rogatio-editor [data-editor-command-bar] button[aria-current=page] {
306
+ border-color: rgba(59, 158, 255, 0.45);
307
+ background: var(--rogatio-primary-bg);
308
+ font-weight: 700;
309
+ }
310
+ .rogatio-editor [data-project-actions] {
311
+ display: flex;
312
+ flex-wrap: wrap;
313
+ gap: 0.5rem;
314
+ margin-top: 0.75rem;
315
+ }
276
316
  .rogatio-editor [data-editor-command-bar] {
277
317
  display: flex;
278
318
  flex-wrap: wrap;
@@ -580,7 +620,8 @@
580
620
  text-decoration: underline;
581
621
  color: var(--rogatio-text);
582
622
  }
583
- .rogatio-editor [data-editor-confirmation] {
623
+ .rogatio-editor [data-editor-confirmation],
624
+ .rogatio-editor [data-group-picker] {
584
625
  position: fixed;
585
626
  inset: 0;
586
627
  z-index: 2;
@@ -605,6 +646,27 @@
605
646
  flex-wrap: wrap;
606
647
  gap: 0.5rem;
607
648
  }
649
+ .rogatio-editor [data-group-picker-list] {
650
+ list-style: none;
651
+ margin: 0 0 1rem;
652
+ padding: 0;
653
+ display: grid;
654
+ gap: 0.35rem;
655
+ max-height: min(50vh, 20rem);
656
+ overflow: auto;
657
+ }
658
+ .rogatio-editor [data-group-picker-list] button {
659
+ width: 100%;
660
+ display: flex;
661
+ flex-wrap: wrap;
662
+ gap: 0.35rem 0.75rem;
663
+ text-align: left;
664
+ }
665
+ .rogatio-editor [data-group-picker-rules],
666
+ .rogatio-editor [data-group-picker-state] {
667
+ color: var(--rogatio-muted);
668
+ font-size: 0.875rem;
669
+ }
608
670
  .rogatio-editor [data-editor-visually-hidden] {
609
671
  position: absolute;
610
672
  width: 1px;
@@ -616,17 +678,18 @@
616
678
  }
617
679
  .rogatio-editor [data-search-wrap] {
618
680
  position: relative;
619
- margin-left: auto;
620
681
  }
621
682
  .rogatio-editor [data-search-label] {
622
- display: inline-flex;
683
+ display: flex;
623
684
  flex-direction: column;
624
685
  gap: 0.15rem;
686
+ max-width: 100%;
625
687
  font-size: 0.75rem;
626
688
  color: var(--rogatio-muted);
627
689
  }
628
690
  .rogatio-editor [data-search-wrap] input[type=search] {
629
- width: min(18rem, 60vw);
691
+ width: 100%;
692
+ max-width: 18rem;
630
693
  }
631
694
  .rogatio-editor [data-search-results] {
632
695
  position: absolute;
@@ -662,15 +725,6 @@
662
725
  .rogatio-editor [data-editor-layout] {
663
726
  display: block;
664
727
  }
665
- .rogatio-editor [data-desktop-route-rail] {
666
- display: none;
667
- }
668
- .rogatio-editor [data-mobile-route-nav] {
669
- display: grid;
670
- gap: 0.3rem;
671
- margin-block: 1rem;
672
- color: var(--rogatio-muted);
673
- }
674
728
  .rogatio-editor [data-editor-header] {
675
729
  grid-template-columns: 1fr;
676
730
  }
@@ -776,6 +830,21 @@
776
830
  .rogatio-editor [data-test-misses] summary {
777
831
  cursor: pointer;
778
832
  }
833
+ .rogatio-editor [data-test-matches] summary {
834
+ cursor: pointer;
835
+ }
836
+ .rogatio-editor [data-test-matches] summary::before {
837
+ content: "\2713";
838
+ color: var(--rogatio-success);
839
+ font-weight: 700;
840
+ margin-right: 0.4em;
841
+ }
842
+ .rogatio-editor [data-test-misses] summary::before {
843
+ content: "\d7";
844
+ color: var(--rogatio-danger);
845
+ font-weight: 700;
846
+ margin-right: 0.4em;
847
+ }
779
848
  .rogatio-editor [data-test-miss-reason] {
780
849
  color: var(--rogatio-muted);
781
850
  }
@@ -1784,6 +1784,30 @@ var FORBIDDEN_EXTENSION_FIELDS = /* @__PURE__ */ new Set([
1784
1784
  var MAX_SNAPSHOT_ARRAY_LENGTH = 4096;
1785
1785
  var F2_MAX_URL_REGEX_LENGTH2 = 2048;
1786
1786
  var editorInstanceCount = 0;
1787
+ function normalizeProjectActions(value) {
1788
+ if (!Array.isArray(value)) return [];
1789
+ const actions = [];
1790
+ for (let index = 0; index < value.length; index += 1) {
1791
+ if (!Object.hasOwn(value, index)) continue;
1792
+ const item = value[index];
1793
+ if (!isRecord4(item)) continue;
1794
+ const command = item.command;
1795
+ const label = item.label;
1796
+ if (typeof command !== "string" || command.length === 0) continue;
1797
+ if (typeof label !== "string" || label.length === 0) continue;
1798
+ if (item.tone === "danger") {
1799
+ actions.push({ command, label, tone: "danger" });
1800
+ } else {
1801
+ actions.push({ command, label });
1802
+ }
1803
+ }
1804
+ return actions;
1805
+ }
1806
+ function ruleCountLabel(count) {
1807
+ if (count === 0) return "No rules";
1808
+ if (count === 1) return "1 rule";
1809
+ return `${count} rules`;
1810
+ }
1787
1811
  function isRecord4(value) {
1788
1812
  return value !== null && typeof value === "object" && !Array.isArray(value);
1789
1813
  }
@@ -2262,6 +2286,8 @@ var EditorControllerImpl = class {
2262
2286
  extensionControls = /* @__PURE__ */ new Map();
2263
2287
  extensionCleanups = [];
2264
2288
  confirmation;
2289
+ groupPickerOpen = false;
2290
+ projectActions;
2265
2291
  focusRequest;
2266
2292
  saving = false;
2267
2293
  destroyed = false;
@@ -2291,6 +2317,7 @@ var EditorControllerImpl = class {
2291
2317
  this.root = options.root;
2292
2318
  this.document = options.root.ownerDocument;
2293
2319
  this.options = options;
2320
+ this.projectActions = normalizeProjectActions(options.projectActions);
2294
2321
  this.extensions = extensions;
2295
2322
  this.instanceId = `rogatio-editor-${++editorInstanceCount}`;
2296
2323
  this.draft = initial;
@@ -2408,6 +2435,10 @@ var EditorControllerImpl = class {
2408
2435
  if (this.destroyed) return;
2409
2436
  const target = event.target;
2410
2437
  if (!(target instanceof Element)) return;
2438
+ if (this.groupPickerOpen && target instanceof HTMLElement && target.dataset.groupPicker !== void 0 && event.target === target) {
2439
+ this.closeGroupPicker();
2440
+ return;
2441
+ }
2411
2442
  const element = target.closest(
2412
2443
  "[data-command], [data-route], [data-search-result], [data-error-path]"
2413
2444
  );
@@ -2460,12 +2491,6 @@ var EditorControllerImpl = class {
2460
2491
  if (!(target instanceof HTMLInputElement || target instanceof HTMLSelectElement)) {
2461
2492
  return;
2462
2493
  }
2463
- if (target.dataset.mobileRoute !== void 0 && target instanceof HTMLSelectElement) {
2464
- const selectedOption = target.options[target.selectedIndex];
2465
- const groupId = selectedOption?.dataset.groupId;
2466
- this.navigate(target.value, groupId);
2467
- return;
2468
- }
2469
2494
  if (target instanceof HTMLInputElement && target.dataset.resourcePath !== void 0) {
2470
2495
  this.updateResourceTypes(
2471
2496
  target.dataset.resourcePath,
@@ -2521,6 +2546,11 @@ var EditorControllerImpl = class {
2521
2546
  this.render();
2522
2547
  return;
2523
2548
  }
2549
+ if (event.key === "Escape" && this.groupPickerOpen) {
2550
+ event.preventDefault();
2551
+ this.closeGroupPicker();
2552
+ return;
2553
+ }
2524
2554
  const target = event.target;
2525
2555
  const inRenameInput = target instanceof HTMLElement && target.dataset.renameInput !== void 0;
2526
2556
  if (!inRenameInput) return;
@@ -2677,6 +2707,14 @@ var EditorControllerImpl = class {
2677
2707
  this.testUrls = url;
2678
2708
  this.statusMessage = "";
2679
2709
  this.render();
2710
+ return;
2711
+ }
2712
+ if (command === "open-group-picker") {
2713
+ this.openGroupPicker();
2714
+ return;
2715
+ }
2716
+ if (command === "close-group-picker") {
2717
+ this.closeGroupPicker();
2680
2718
  }
2681
2719
  }
2682
2720
  collectDiagnostics(value) {
@@ -3511,8 +3549,8 @@ var EditorControllerImpl = class {
3511
3549
  const matches = urlResult.rules.filter((rule) => rule.matched);
3512
3550
  const misses = urlResult.rules.filter((rule) => !rule.matched);
3513
3551
  card.dataset.matched = matches.length > 0 ? "true" : "false";
3514
- for (const rule of matches) {
3515
- card.append(this.renderTestOutcome(urlResult.url, rule));
3552
+ if (matches.length > 0) {
3553
+ card.append(this.renderTestMatches(urlResult.url, matches));
3516
3554
  }
3517
3555
  if (misses.length > 0) {
3518
3556
  card.append(this.renderTestMisses(misses));
@@ -3567,6 +3605,22 @@ var EditorControllerImpl = class {
3567
3605
  outcome.append(lead, ruleButton, tail);
3568
3606
  return outcome;
3569
3607
  }
3608
+ /**
3609
+ * Matching rules sit under an open disclosure headed by their count, mirroring
3610
+ * the closed misses disclosure so both lists are labeled the same way.
3611
+ */
3612
+ renderTestMatches(url, matches) {
3613
+ const details = this.document.createElement("details");
3614
+ details.dataset.testMatches = "true";
3615
+ details.open = true;
3616
+ const summary = this.document.createElement("summary");
3617
+ summary.textContent = matches.length === 1 ? "1 rule matched" : `${matches.length} rules matched`;
3618
+ details.append(summary);
3619
+ for (const rule of matches) {
3620
+ details.append(this.renderTestOutcome(url, rule));
3621
+ }
3622
+ return details;
3623
+ }
3570
3624
  renderTestMisses(misses) {
3571
3625
  const details = this.document.createElement("details");
3572
3626
  details.dataset.testMisses = "true";
@@ -3639,6 +3693,7 @@ var EditorControllerImpl = class {
3639
3693
  return enablement.isEnabled(id) !== true;
3640
3694
  }
3641
3695
  navigate(route, groupId) {
3696
+ const returnFocusToGroups = this.groupPickerOpen;
3642
3697
  if (route === "project") {
3643
3698
  this.route = { kind: "project" };
3644
3699
  } else if (route === "test") {
@@ -3648,6 +3703,8 @@ var EditorControllerImpl = class {
3648
3703
  } else {
3649
3704
  return;
3650
3705
  }
3706
+ this.groupPickerOpen = false;
3707
+ if (returnFocusToGroups) this.focusRequest = "route:groups";
3651
3708
  this.closeRenameOnLeave();
3652
3709
  this.testRequestId += 1;
3653
3710
  this.statusMessage = "";
@@ -3673,6 +3730,7 @@ var EditorControllerImpl = class {
3673
3730
  }
3674
3731
  }
3675
3732
  navigateToGroup(groupId) {
3733
+ this.groupPickerOpen = false;
3676
3734
  const groupIds = new Set(
3677
3735
  this.draft.groups.map((group) => typeof group.id === "string" ? group.id : "").filter((id) => id.length > 0)
3678
3736
  );
@@ -3745,6 +3803,7 @@ var EditorControllerImpl = class {
3745
3803
  this.revealRuleCard(resolvedGroup, resolvedRule);
3746
3804
  }
3747
3805
  navigateToSearchResult(path) {
3806
+ this.groupPickerOpen = false;
3748
3807
  const segments = decodePointer(path);
3749
3808
  if (segments?.[0] !== "groups") {
3750
3809
  this.route = { kind: "project" };
@@ -3836,7 +3895,9 @@ var EditorControllerImpl = class {
3836
3895
  this.renderSummary();
3837
3896
  this.renderMigrationNotices();
3838
3897
  this.renderSearchResults();
3898
+ if (this.confirmation) this.groupPickerOpen = false;
3839
3899
  this.renderConfirmation();
3900
+ this.renderGroupPicker();
3840
3901
  this.restoreFocus();
3841
3902
  this.focusRequest = void 0;
3842
3903
  }
@@ -3849,39 +3910,7 @@ var EditorControllerImpl = class {
3849
3910
  dirty.dataset.dirtyState = "true";
3850
3911
  dirty.textContent = this.isDirty() ? "Unsaved changes" : "All changes saved";
3851
3912
  titleBlock.append(title, dirty);
3852
- const mobileNav = this.document.createElement("label");
3853
- mobileNav.dataset.mobileRouteNav = "true";
3854
- mobileNav.textContent = "Project section";
3855
- const select = this.document.createElement("select");
3856
- select.dataset.mobileRoute = "true";
3857
- select.dataset.editorKey = "mobile-route";
3858
- const projectOption = this.document.createElement("option");
3859
- projectOption.value = "project";
3860
- projectOption.textContent = "Project";
3861
- select.append(projectOption);
3862
- for (const group of this.draft.groups) {
3863
- const option = this.document.createElement("option");
3864
- option.value = "group";
3865
- option.dataset.groupId = safeText(group.id);
3866
- option.textContent = displayName(group.name, "Unnamed group");
3867
- select.append(option);
3868
- }
3869
- const testOption = this.document.createElement("option");
3870
- testOption.value = "test";
3871
- testOption.textContent = "Test console";
3872
- select.append(testOption);
3873
- if (this.route.kind === "project") {
3874
- select.value = "project";
3875
- } else if (this.route.kind === "test") {
3876
- select.value = "test";
3877
- } else {
3878
- const groupId = this.route.groupId;
3879
- const options = Array.from(select.options);
3880
- const option = options.find((value) => value.dataset.groupId === groupId);
3881
- if (option) select.value = "group";
3882
- }
3883
- mobileNav.append(select);
3884
- this.header.append(titleBlock, mobileNav);
3913
+ this.header.append(titleBlock);
3885
3914
  this.status.textContent = this.statusMessage;
3886
3915
  this.status.setAttribute("aria-busy", this.saving ? "true" : "false");
3887
3916
  }
@@ -3891,30 +3920,34 @@ var EditorControllerImpl = class {
3891
3920
  heading.dataset.editorVisuallyHidden = "true";
3892
3921
  heading.textContent = "Project sections";
3893
3922
  this.rail.append(heading);
3894
- const project = this.createButton("Project", "route:project");
3923
+ const list = this.document.createElement("ol");
3924
+ list.dataset.routeBreadcrumb = "true";
3925
+ const projectItem = this.document.createElement("li");
3926
+ const project = this.createButton(
3927
+ displayName(this.draft.name, "Project"),
3928
+ "route:project"
3929
+ );
3895
3930
  project.dataset.route = "project";
3896
3931
  project.dataset.editorKey = "route:project";
3897
- if (this.route.kind === "project")
3932
+ if (this.route.kind === "project") {
3898
3933
  project.setAttribute("aria-current", "page");
3899
- this.rail.append(project);
3900
- for (const group of this.draft.groups) {
3901
- const groupId = safeText(group.id);
3902
- const name = displayName(group.name, "Unnamed group");
3903
- const button = this.createButton(name, `route:group:${groupId}`);
3904
- button.dataset.route = "group";
3905
- button.dataset.groupId = groupId;
3906
- button.dataset.editorKey = `route:group:${groupId}`;
3907
- if (this.route.kind === "group" && this.route.groupId === groupId) {
3908
- button.setAttribute("aria-current", "page");
3909
- }
3910
- this.rail.append(button);
3911
3934
  }
3912
- const testBtn = this.createButton("Test console", "route:test");
3913
- testBtn.dataset.route = "test";
3914
- testBtn.dataset.editorKey = "route:test";
3915
- if (this.route.kind === "test")
3916
- testBtn.setAttribute("aria-current", "page");
3917
- this.rail.append(testBtn);
3935
+ projectItem.append(project);
3936
+ const groupItem = this.document.createElement("li");
3937
+ const openGroup = this.route.kind === "group" ? this.groupById(this.route.groupId) : void 0;
3938
+ const groups = this.createButton(
3939
+ openGroup ? displayName(openGroup.name, "Unnamed group") : "Groups",
3940
+ "route:groups"
3941
+ );
3942
+ groups.dataset.command = "open-group-picker";
3943
+ groups.dataset.editorKey = "route:groups";
3944
+ if (openGroup) {
3945
+ groups.dataset.groupId = safeText(openGroup.id);
3946
+ groups.setAttribute("aria-current", "page");
3947
+ }
3948
+ groupItem.append(groups);
3949
+ list.append(projectItem, groupItem);
3950
+ this.rail.append(list);
3918
3951
  const searchWrap = this.document.createElement("div");
3919
3952
  searchWrap.dataset.searchWrap = "true";
3920
3953
  const searchLabel = this.document.createElement("label");
@@ -3946,7 +3979,18 @@ var EditorControllerImpl = class {
3946
3979
  this.createCommandButton("AI Assist", "ai-assist", this.saving)
3947
3980
  );
3948
3981
  }
3949
- tools.append(this.createCommandButton("Validate", "validate", this.saving));
3982
+ const testBtn = this.createButton("Test console", "route:test");
3983
+ testBtn.dataset.route = "test";
3984
+ testBtn.dataset.editorKey = "route:test";
3985
+ testBtn.dataset.btn = "secondary";
3986
+ testBtn.disabled = this.saving;
3987
+ if (this.route.kind === "test") {
3988
+ testBtn.setAttribute("aria-current", "page");
3989
+ }
3990
+ tools.append(
3991
+ testBtn,
3992
+ this.createCommandButton("Validate", "validate", this.saving)
3993
+ );
3950
3994
  const commit = this.document.createElement("div");
3951
3995
  commit.dataset.actionCluster = "commit";
3952
3996
  commit.append(
@@ -4123,6 +4167,7 @@ var EditorControllerImpl = class {
4123
4167
  description
4124
4168
  );
4125
4169
  fields.append(fieldGrid);
4170
+ this.renderProjectActions(fields);
4126
4171
  this.form.append(fields);
4127
4172
  const groups = this.document.createElement("section");
4128
4173
  groups.dataset.groupListSection = "true";
@@ -5284,6 +5329,103 @@ var EditorControllerImpl = class {
5284
5329
  }
5285
5330
  return results;
5286
5331
  }
5332
+ renderProjectActions(fields) {
5333
+ if (this.projectActions.length === 0) return;
5334
+ const group = this.document.createElement("div");
5335
+ group.dataset.projectActions = "true";
5336
+ group.setAttribute("role", "group");
5337
+ group.setAttribute("aria-label", "Project settings");
5338
+ for (const action of this.projectActions) {
5339
+ group.append(
5340
+ this.createCommandButton(
5341
+ action.label,
5342
+ action.command,
5343
+ false,
5344
+ {},
5345
+ action.tone === "danger" ? "danger" : "secondary"
5346
+ )
5347
+ );
5348
+ }
5349
+ fields.append(group);
5350
+ }
5351
+ openGroupPicker() {
5352
+ this.groupPickerOpen = true;
5353
+ this.focusRequest = this.draft.groups.length > 0 ? "group-picker-first" : "group-picker-close";
5354
+ this.render();
5355
+ }
5356
+ closeGroupPicker() {
5357
+ this.groupPickerOpen = false;
5358
+ this.focusRequest = "route:groups";
5359
+ this.render();
5360
+ }
5361
+ renderGroupPicker() {
5362
+ const existing = this.host.querySelector("[data-group-picker]");
5363
+ existing?.remove();
5364
+ if (!this.groupPickerOpen) return;
5365
+ const overlay = this.document.createElement("div");
5366
+ overlay.dataset.groupPicker = "true";
5367
+ overlay.setAttribute("role", "presentation");
5368
+ const dialog = this.document.createElement("section");
5369
+ dialog.dataset.editorDialog = "true";
5370
+ dialog.setAttribute("role", "dialog");
5371
+ dialog.setAttribute("aria-modal", "true");
5372
+ const title = this.document.createElement("h2");
5373
+ title.id = `${this.instanceId}-group-picker-title`;
5374
+ title.textContent = "Groups";
5375
+ dialog.setAttribute("aria-labelledby", title.id);
5376
+ dialog.append(title);
5377
+ if (this.draft.groups.length === 0) {
5378
+ const empty = this.document.createElement("p");
5379
+ empty.textContent = "No groups yet.";
5380
+ dialog.append(empty);
5381
+ } else {
5382
+ const list = this.document.createElement("ul");
5383
+ list.dataset.groupPickerList = "true";
5384
+ for (let index = 0; index < this.draft.groups.length; index += 1) {
5385
+ const group = this.draft.groups[index];
5386
+ if (!group) continue;
5387
+ const groupId = safeText(group.id);
5388
+ const name = displayName(group.name, "Unnamed group");
5389
+ const item = this.document.createElement("li");
5390
+ const button = this.document.createElement("button");
5391
+ button.type = "button";
5392
+ button.dataset.route = "group";
5393
+ button.dataset.groupId = groupId;
5394
+ button.dataset.btn = "secondary";
5395
+ button.dataset.editorKey = index === 0 ? "group-picker-first" : `group-picker:${groupId}`;
5396
+ if (this.route.kind === "group" && this.route.groupId === groupId) {
5397
+ button.setAttribute("aria-current", "true");
5398
+ }
5399
+ const nameEl = this.document.createElement("span");
5400
+ nameEl.dataset.groupPickerName = "true";
5401
+ nameEl.textContent = name;
5402
+ const rulesEl = this.document.createElement("span");
5403
+ rulesEl.dataset.groupPickerRules = "true";
5404
+ rulesEl.textContent = ruleCountLabel(group.rules.length);
5405
+ button.append(nameEl, rulesEl);
5406
+ const savedId = this.savedGroupId(group);
5407
+ if (this.options.groupEnablement && savedId) {
5408
+ const stateEl = this.document.createElement("span");
5409
+ stateEl.dataset.groupPickerState = "true";
5410
+ stateEl.textContent = this.options.groupEnablement.isEnabled(savedId) ? "Enabled" : "Disabled";
5411
+ button.append(stateEl);
5412
+ }
5413
+ item.append(button);
5414
+ list.append(item);
5415
+ }
5416
+ dialog.append(list);
5417
+ }
5418
+ const actions = this.document.createElement("div");
5419
+ actions.dataset.editorDialogActions = "true";
5420
+ const close = this.createButton("Close", "group-picker-close");
5421
+ close.dataset.command = "close-group-picker";
5422
+ close.dataset.editorKey = "group-picker-close";
5423
+ close.dataset.btn = "secondary";
5424
+ actions.append(close);
5425
+ dialog.append(actions);
5426
+ overlay.append(dialog);
5427
+ this.host.append(overlay);
5428
+ }
5287
5429
  renderConfirmation() {
5288
5430
  const existing = this.host.querySelector("[data-editor-confirmation]");
5289
5431
  existing?.remove();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rogatio/cli",
3
- "version": "6.9.1",
3
+ "version": "6.11.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Local-first browser request and response rules — editor host, file verification, test runner, and runtime dispatch.",