@matdata/yasgui 5.4.0 → 5.6.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.
@@ -36,6 +36,7 @@ const AcceptHeaderGraphMap = [
36
36
  { key: "CSV", value: "text/csv,*/*;q=0.9" },
37
37
  { key: "TSV", value: "text/tab-separated-values,*/*;q=0.9" },
38
38
  ];
39
+ const DEFAULT_API_KEY_HEADER = "X-API-Key";
39
40
  export default class TabSettingsModal {
40
41
  constructor(tab, controlBarEl) {
41
42
  this.tab = tab;
@@ -90,48 +91,55 @@ export default class TabSettingsModal {
90
91
  this.modalContent.appendChild(header);
91
92
  const body = document.createElement("div");
92
93
  addClass(body, "modalBody");
93
- const tabsContainer = document.createElement("div");
94
- addClass(tabsContainer, "modalTabs");
94
+ const sidebar = document.createElement("div");
95
+ addClass(sidebar, "modalSidebar");
95
96
  const requestTab = document.createElement("button");
96
97
  requestTab.textContent = "Request";
97
- addClass(requestTab, "modalTabButton", "active");
98
+ addClass(requestTab, "modalNavButton", "active");
98
99
  requestTab.onclick = () => this.switchTab("request");
100
+ const endpointsTab = document.createElement("button");
101
+ endpointsTab.textContent = "SPARQL Endpoints";
102
+ addClass(endpointsTab, "modalNavButton");
103
+ endpointsTab.onclick = () => this.switchTab("endpoints");
99
104
  const prefixTab = document.createElement("button");
100
105
  prefixTab.textContent = "Prefixes";
101
- addClass(prefixTab, "modalTabButton");
106
+ addClass(prefixTab, "modalNavButton");
102
107
  prefixTab.onclick = () => this.switchTab("prefix");
103
108
  const editorTab = document.createElement("button");
104
109
  editorTab.textContent = "Editor";
105
- addClass(editorTab, "modalTabButton");
110
+ addClass(editorTab, "modalNavButton");
106
111
  editorTab.onclick = () => this.switchTab("editor");
107
- const endpointsTab = document.createElement("button");
108
- endpointsTab.textContent = "Endpoint Buttons";
109
- addClass(endpointsTab, "modalTabButton");
110
- endpointsTab.onclick = () => this.switchTab("endpoints");
111
112
  const importExportTab = document.createElement("button");
112
113
  importExportTab.textContent = "Import/Export";
113
- addClass(importExportTab, "modalTabButton");
114
+ addClass(importExportTab, "modalNavButton");
114
115
  importExportTab.onclick = () => this.switchTab("importexport");
115
116
  const shortcutsTab = document.createElement("button");
116
117
  shortcutsTab.textContent = "Keyboard Shortcuts";
117
- addClass(shortcutsTab, "modalTabButton");
118
+ addClass(shortcutsTab, "modalNavButton");
118
119
  shortcutsTab.onclick = () => this.switchTab("shortcuts");
119
120
  const aboutTab = document.createElement("button");
120
121
  aboutTab.textContent = "About";
121
- addClass(aboutTab, "modalTabButton");
122
+ addClass(aboutTab, "modalNavButton");
122
123
  aboutTab.onclick = () => this.switchTab("about");
123
- tabsContainer.appendChild(requestTab);
124
- tabsContainer.appendChild(prefixTab);
125
- tabsContainer.appendChild(editorTab);
126
- tabsContainer.appendChild(endpointsTab);
127
- tabsContainer.appendChild(importExportTab);
128
- tabsContainer.appendChild(shortcutsTab);
129
- tabsContainer.appendChild(aboutTab);
130
- body.appendChild(tabsContainer);
124
+ sidebar.appendChild(requestTab);
125
+ sidebar.appendChild(endpointsTab);
126
+ sidebar.appendChild(prefixTab);
127
+ sidebar.appendChild(editorTab);
128
+ sidebar.appendChild(importExportTab);
129
+ sidebar.appendChild(shortcutsTab);
130
+ sidebar.appendChild(aboutTab);
131
+ const contentArea = document.createElement("div");
132
+ addClass(contentArea, "modalContentArea");
133
+ body.appendChild(sidebar);
134
+ body.appendChild(contentArea);
131
135
  const requestContent = document.createElement("div");
132
136
  addClass(requestContent, "modalTabContent", "active");
133
137
  requestContent.id = "request-content";
134
138
  this.drawRequestSettings(requestContent);
139
+ const endpointsContent = document.createElement("div");
140
+ addClass(endpointsContent, "modalTabContent");
141
+ endpointsContent.id = "endpoints-content";
142
+ this.drawEndpointsSettings(endpointsContent);
135
143
  const prefixContent = document.createElement("div");
136
144
  addClass(prefixContent, "modalTabContent");
137
145
  prefixContent.id = "prefix-content";
@@ -140,10 +148,6 @@ export default class TabSettingsModal {
140
148
  addClass(editorContent, "modalTabContent");
141
149
  editorContent.id = "editor-content";
142
150
  this.drawEditorSettings(editorContent);
143
- const endpointsContent = document.createElement("div");
144
- addClass(endpointsContent, "modalTabContent");
145
- endpointsContent.id = "endpoints-content";
146
- this.drawEndpointButtonsSettings(endpointsContent);
147
151
  const importExportContent = document.createElement("div");
148
152
  addClass(importExportContent, "modalTabContent");
149
153
  importExportContent.id = "importexport-content";
@@ -156,13 +160,13 @@ export default class TabSettingsModal {
156
160
  addClass(aboutContent, "modalTabContent");
157
161
  aboutContent.id = "about-content";
158
162
  this.drawAboutSettings(aboutContent);
159
- body.appendChild(requestContent);
160
- body.appendChild(prefixContent);
161
- body.appendChild(editorContent);
162
- body.appendChild(endpointsContent);
163
- body.appendChild(importExportContent);
164
- body.appendChild(shortcutsContent);
165
- body.appendChild(aboutContent);
163
+ contentArea.appendChild(requestContent);
164
+ contentArea.appendChild(endpointsContent);
165
+ contentArea.appendChild(prefixContent);
166
+ contentArea.appendChild(editorContent);
167
+ contentArea.appendChild(importExportContent);
168
+ contentArea.appendChild(shortcutsContent);
169
+ contentArea.appendChild(aboutContent);
166
170
  this.modalContent.appendChild(body);
167
171
  const footer = document.createElement("div");
168
172
  addClass(footer, "modalFooter");
@@ -181,13 +185,13 @@ export default class TabSettingsModal {
181
185
  document.body.appendChild(this.modalOverlay);
182
186
  }
183
187
  switchTab(tabName) {
184
- const buttons = this.modalContent.querySelectorAll(".modalTabButton");
188
+ const buttons = this.modalContent.querySelectorAll(".modalNavButton");
185
189
  const contents = this.modalContent.querySelectorAll(".modalTabContent");
186
190
  buttons.forEach((btn, index) => {
187
191
  if ((tabName === "request" && index === 0) ||
188
- (tabName === "prefix" && index === 1) ||
189
- (tabName === "editor" && index === 2) ||
190
- (tabName === "endpoints" && index === 3) ||
192
+ (tabName === "endpoints" && index === 1) ||
193
+ (tabName === "prefix" && index === 2) ||
194
+ (tabName === "editor" && index === 3) ||
191
195
  (tabName === "importexport" && index === 4) ||
192
196
  (tabName === "shortcuts" && index === 5) ||
193
197
  (tabName === "about" && index === 6)) {
@@ -323,7 +327,9 @@ export default class TabSettingsModal {
323
327
  const snippetsBarCheckbox = document.createElement("input");
324
328
  snippetsBarCheckbox.type = "checkbox";
325
329
  snippetsBarCheckbox.id = "showSnippetsBar";
326
- snippetsBarCheckbox.checked = yasqe.getSnippetsBarVisible();
330
+ const persistedValue = this.tab.yasgui.persistentConfig.getShowSnippetsBar();
331
+ snippetsBarCheckbox.checked =
332
+ persistedValue !== undefined ? persistedValue : this.tab.yasgui.config.showSnippetsBar !== false;
327
333
  const snippetsBarLabel = document.createElement("label");
328
334
  snippetsBarLabel.htmlFor = "showSnippetsBar";
329
335
  snippetsBarLabel.textContent = "Show code snippets bar";
@@ -338,6 +344,405 @@ export default class TabSettingsModal {
338
344
  snippetsBarSection.appendChild(snippetsBarHelp);
339
345
  container.appendChild(snippetsBarSection);
340
346
  }
347
+ drawEndpointsSettings(container) {
348
+ const section = document.createElement("div");
349
+ addClass(section, "settingsSection");
350
+ const label = document.createElement("label");
351
+ label.textContent = "SPARQL Endpoints";
352
+ addClass(label, "settingsLabel");
353
+ const help = document.createElement("div");
354
+ help.textContent =
355
+ "Manage your SPARQL endpoints. Each endpoint can have its own authentication and be displayed as a quick-switch button.";
356
+ addClass(help, "settingsHelp");
357
+ section.appendChild(label);
358
+ section.appendChild(help);
359
+ const endpointsList = document.createElement("div");
360
+ addClass(endpointsList, "endpointsTable");
361
+ this.renderEndpointsList(endpointsList);
362
+ section.appendChild(endpointsList);
363
+ container.appendChild(section);
364
+ }
365
+ renderEndpointsList(container) {
366
+ container.innerHTML = "";
367
+ const configs = this.tab.yasgui.persistentConfig.getEndpointConfigs();
368
+ const table = document.createElement("table");
369
+ addClass(table, "endpointsTableElement");
370
+ const thead = document.createElement("thead");
371
+ const headerRow = document.createElement("tr");
372
+ const headers = ["Endpoint", "Label", "Button", "Authentication", "Actions"];
373
+ headers.forEach((h) => {
374
+ const th = document.createElement("th");
375
+ th.textContent = h;
376
+ headerRow.appendChild(th);
377
+ });
378
+ thead.appendChild(headerRow);
379
+ table.appendChild(thead);
380
+ const tbody = document.createElement("tbody");
381
+ if (configs.length === 0) {
382
+ const emptyRow = document.createElement("tr");
383
+ const emptyCell = document.createElement("td");
384
+ emptyCell.colSpan = 5;
385
+ emptyCell.textContent = "No endpoints yet. Add one below or access an endpoint to have it automatically tracked.";
386
+ addClass(emptyCell, "emptyMessage");
387
+ emptyCell.style.textAlign = "center";
388
+ emptyCell.style.padding = "20px";
389
+ emptyRow.appendChild(emptyCell);
390
+ tbody.appendChild(emptyRow);
391
+ }
392
+ configs.forEach((config, index) => {
393
+ const row = document.createElement("tr");
394
+ const endpointCell = document.createElement("td");
395
+ endpointCell.textContent = config.endpoint;
396
+ endpointCell.title = config.endpoint;
397
+ addClass(endpointCell, "endpointCell");
398
+ row.appendChild(endpointCell);
399
+ const labelCell = document.createElement("td");
400
+ const labelInput = document.createElement("input");
401
+ labelInput.type = "text";
402
+ labelInput.value = config.label || "";
403
+ labelInput.placeholder = "Optional label";
404
+ addClass(labelInput, "endpointLabelInput");
405
+ labelInput.onchange = () => {
406
+ this.tab.yasgui.persistentConfig.addOrUpdateEndpoint(config.endpoint, {
407
+ label: labelInput.value.trim() || undefined,
408
+ });
409
+ this.renderEndpointsList(container);
410
+ this.tab.refreshEndpointButtons();
411
+ };
412
+ labelCell.appendChild(labelInput);
413
+ row.appendChild(labelCell);
414
+ const buttonCell = document.createElement("td");
415
+ const buttonCheckbox = document.createElement("input");
416
+ buttonCheckbox.type = "checkbox";
417
+ buttonCheckbox.checked = !!config.showAsButton;
418
+ buttonCheckbox.disabled = !config.label;
419
+ buttonCheckbox.setAttribute("aria-label", config.label ? "Show this endpoint as a quick-switch button" : "Add a label first to enable button");
420
+ buttonCheckbox.title = config.label
421
+ ? "Show this endpoint as a quick-switch button"
422
+ : "Add a label first to enable button";
423
+ buttonCheckbox.onchange = () => {
424
+ this.tab.yasgui.persistentConfig.addOrUpdateEndpoint(config.endpoint, {
425
+ showAsButton: buttonCheckbox.checked,
426
+ });
427
+ this.tab.refreshEndpointButtons();
428
+ };
429
+ buttonCell.appendChild(buttonCheckbox);
430
+ addClass(buttonCell, "centerCell");
431
+ row.appendChild(buttonCell);
432
+ const authCell = document.createElement("td");
433
+ const authButton = document.createElement("button");
434
+ authButton.type = "button";
435
+ addClass(authButton, "configureAuthButton");
436
+ if (config.authentication) {
437
+ authButton.textContent = "✓ Configured";
438
+ addClass(authButton, "authenticated");
439
+ }
440
+ else {
441
+ authButton.textContent = "Configure";
442
+ }
443
+ authButton.onclick = () => this.showAuthenticationModal(config.endpoint);
444
+ authCell.appendChild(authButton);
445
+ addClass(authCell, "centerCell");
446
+ row.appendChild(authCell);
447
+ const actionsCell = document.createElement("td");
448
+ const deleteButton = document.createElement("button");
449
+ deleteButton.type = "button";
450
+ deleteButton.textContent = "Delete";
451
+ addClass(deleteButton, "deleteEndpointButton");
452
+ deleteButton.onclick = () => {
453
+ if (confirm(`Delete endpoint "${config.endpoint}"?`)) {
454
+ this.tab.yasgui.persistentConfig.deleteEndpointConfig(config.endpoint);
455
+ this.renderEndpointsList(container);
456
+ this.tab.refreshEndpointButtons();
457
+ }
458
+ };
459
+ actionsCell.appendChild(deleteButton);
460
+ addClass(actionsCell, "centerCell");
461
+ row.appendChild(actionsCell);
462
+ tbody.appendChild(row);
463
+ });
464
+ table.appendChild(tbody);
465
+ container.appendChild(table);
466
+ const addForm = document.createElement("div");
467
+ addClass(addForm, "addEndpointForm");
468
+ const addFormTitle = document.createElement("div");
469
+ addFormTitle.textContent = "Add New Endpoint";
470
+ addClass(addFormTitle, "addFormTitle");
471
+ addForm.appendChild(addFormTitle);
472
+ const formInputs = document.createElement("div");
473
+ addClass(formInputs, "addFormInputs");
474
+ const endpointInput = document.createElement("input");
475
+ endpointInput.type = "url";
476
+ endpointInput.placeholder = "Endpoint URL (e.g., https://dbpedia.org/sparql)";
477
+ addClass(endpointInput, "addEndpointInput");
478
+ formInputs.appendChild(endpointInput);
479
+ const addButton = document.createElement("button");
480
+ addButton.type = "button";
481
+ addButton.textContent = "+ Add Endpoint";
482
+ addClass(addButton, "addEndpointButton");
483
+ addButton.onclick = () => {
484
+ const endpoint = endpointInput.value.trim();
485
+ if (!endpoint) {
486
+ alert("Please enter an endpoint URL.");
487
+ return;
488
+ }
489
+ if (!/^https?:\/\//i.test(endpoint)) {
490
+ alert("Endpoint URL must start with http:// or https://");
491
+ return;
492
+ }
493
+ try {
494
+ new URL(endpoint);
495
+ }
496
+ catch (e) {
497
+ alert(e instanceof Error && e.message ? "Malformed URL: " + e.message : "Please enter a valid URL.");
498
+ return;
499
+ }
500
+ const existing = this.tab.yasgui.persistentConfig.getEndpointConfig(endpoint);
501
+ if (existing) {
502
+ alert("This endpoint is already in the list.");
503
+ return;
504
+ }
505
+ this.tab.yasgui.persistentConfig.addOrUpdateEndpoint(endpoint, {});
506
+ endpointInput.value = "";
507
+ this.renderEndpointsList(container);
508
+ this.tab.refreshEndpointButtons();
509
+ };
510
+ formInputs.appendChild(addButton);
511
+ addForm.appendChild(formInputs);
512
+ container.appendChild(addForm);
513
+ }
514
+ showAuthenticationModal(endpoint) {
515
+ const config = this.tab.yasgui.persistentConfig.getEndpointConfig(endpoint);
516
+ const existingAuth = config === null || config === void 0 ? void 0 : config.authentication;
517
+ const authModalOverlay = document.createElement("div");
518
+ addClass(authModalOverlay, "authModalOverlay");
519
+ authModalOverlay.onclick = () => authModalOverlay.remove();
520
+ const authModal = document.createElement("div");
521
+ addClass(authModal, "authModal");
522
+ authModal.onclick = (e) => e.stopPropagation();
523
+ const header = document.createElement("div");
524
+ addClass(header, "authModalHeader");
525
+ const title = document.createElement("h3");
526
+ title.textContent = "Configure Authentication";
527
+ const subtitle = document.createElement("div");
528
+ subtitle.textContent = endpoint;
529
+ addClass(subtitle, "authModalSubtitle");
530
+ header.appendChild(title);
531
+ header.appendChild(subtitle);
532
+ authModal.appendChild(header);
533
+ const body = document.createElement("div");
534
+ addClass(body, "authModalBody");
535
+ const typeSection = document.createElement("div");
536
+ addClass(typeSection, "authModalSection");
537
+ const typeLabel = document.createElement("label");
538
+ typeLabel.textContent = "Authentication Type";
539
+ const typeSelect = document.createElement("select");
540
+ const basicOption = document.createElement("option");
541
+ basicOption.value = "basic";
542
+ basicOption.textContent = "HTTP Basic Authentication";
543
+ typeSelect.appendChild(basicOption);
544
+ const bearerOption = document.createElement("option");
545
+ bearerOption.value = "bearer";
546
+ bearerOption.textContent = "Bearer Token";
547
+ typeSelect.appendChild(bearerOption);
548
+ const apiKeyOption = document.createElement("option");
549
+ apiKeyOption.value = "apiKey";
550
+ apiKeyOption.textContent = "API Key (Custom Header)";
551
+ typeSelect.appendChild(apiKeyOption);
552
+ if (existingAuth) {
553
+ typeSelect.value = existingAuth.type;
554
+ }
555
+ typeSection.appendChild(typeLabel);
556
+ typeSection.appendChild(typeSelect);
557
+ body.appendChild(typeSection);
558
+ const basicAuthFields = document.createElement("div");
559
+ basicAuthFields.id = "basicAuthFields";
560
+ addClass(basicAuthFields, "authFieldsContainer");
561
+ const usernameSection = document.createElement("div");
562
+ addClass(usernameSection, "authModalSection");
563
+ const usernameLabel = document.createElement("label");
564
+ usernameLabel.textContent = "Username";
565
+ const usernameInput = document.createElement("input");
566
+ usernameInput.type = "text";
567
+ usernameInput.placeholder = "Enter username";
568
+ usernameInput.value = (existingAuth === null || existingAuth === void 0 ? void 0 : existingAuth.type) === "basic" ? existingAuth.username : "";
569
+ usernameInput.autocomplete = "username";
570
+ usernameSection.appendChild(usernameLabel);
571
+ usernameSection.appendChild(usernameInput);
572
+ basicAuthFields.appendChild(usernameSection);
573
+ const passwordSection = document.createElement("div");
574
+ addClass(passwordSection, "authModalSection");
575
+ const passwordLabel = document.createElement("label");
576
+ passwordLabel.textContent = "Password";
577
+ const passwordInput = document.createElement("input");
578
+ passwordInput.type = "password";
579
+ passwordInput.placeholder = "Enter password";
580
+ passwordInput.value = (existingAuth === null || existingAuth === void 0 ? void 0 : existingAuth.type) === "basic" ? existingAuth.password : "";
581
+ passwordInput.autocomplete = "current-password";
582
+ passwordSection.appendChild(passwordLabel);
583
+ passwordSection.appendChild(passwordInput);
584
+ basicAuthFields.appendChild(passwordSection);
585
+ body.appendChild(basicAuthFields);
586
+ const bearerAuthFields = document.createElement("div");
587
+ bearerAuthFields.id = "bearerAuthFields";
588
+ addClass(bearerAuthFields, "authFieldsContainer");
589
+ bearerAuthFields.style.display = "none";
590
+ const tokenSection = document.createElement("div");
591
+ addClass(tokenSection, "authModalSection");
592
+ const tokenLabel = document.createElement("label");
593
+ tokenLabel.textContent = "Bearer Token";
594
+ const tokenInput = document.createElement("input");
595
+ tokenInput.type = "password";
596
+ tokenInput.placeholder = "Enter bearer token";
597
+ tokenInput.autocomplete = "off";
598
+ tokenInput.value = (existingAuth === null || existingAuth === void 0 ? void 0 : existingAuth.type) === "bearer" ? existingAuth.token : "";
599
+ tokenSection.appendChild(tokenLabel);
600
+ tokenSection.appendChild(tokenInput);
601
+ bearerAuthFields.appendChild(tokenSection);
602
+ body.appendChild(bearerAuthFields);
603
+ const apiKeyAuthFields = document.createElement("div");
604
+ apiKeyAuthFields.id = "apiKeyAuthFields";
605
+ addClass(apiKeyAuthFields, "authFieldsContainer");
606
+ apiKeyAuthFields.style.display = "none";
607
+ const headerNameSection = document.createElement("div");
608
+ addClass(headerNameSection, "authModalSection");
609
+ const headerNameLabel = document.createElement("label");
610
+ headerNameLabel.textContent = "Header Name";
611
+ const headerNameInput = document.createElement("input");
612
+ headerNameInput.type = "text";
613
+ headerNameInput.placeholder = `e.g., ${DEFAULT_API_KEY_HEADER}`;
614
+ headerNameInput.value = (existingAuth === null || existingAuth === void 0 ? void 0 : existingAuth.type) === "apiKey" ? existingAuth.headerName : DEFAULT_API_KEY_HEADER;
615
+ headerNameSection.appendChild(headerNameLabel);
616
+ headerNameSection.appendChild(headerNameInput);
617
+ apiKeyAuthFields.appendChild(headerNameSection);
618
+ const apiKeySection = document.createElement("div");
619
+ addClass(apiKeySection, "authModalSection");
620
+ const apiKeyLabel = document.createElement("label");
621
+ apiKeyLabel.textContent = "API Key";
622
+ const apiKeyInput = document.createElement("input");
623
+ apiKeyInput.type = "password";
624
+ apiKeyInput.placeholder = "Enter API key";
625
+ apiKeyInput.autocomplete = "off";
626
+ apiKeyInput.value = (existingAuth === null || existingAuth === void 0 ? void 0 : existingAuth.type) === "apiKey" ? existingAuth.apiKey : "";
627
+ apiKeySection.appendChild(apiKeyLabel);
628
+ apiKeySection.appendChild(apiKeyInput);
629
+ apiKeyAuthFields.appendChild(apiKeySection);
630
+ body.appendChild(apiKeyAuthFields);
631
+ const toggleAuthFields = () => {
632
+ const authType = typeSelect.value;
633
+ basicAuthFields.style.display = authType === "basic" ? "block" : "none";
634
+ bearerAuthFields.style.display = authType === "bearer" ? "block" : "none";
635
+ apiKeyAuthFields.style.display = authType === "apiKey" ? "block" : "none";
636
+ };
637
+ toggleAuthFields();
638
+ typeSelect.onchange = toggleAuthFields;
639
+ const securityNotice = document.createElement("div");
640
+ addClass(securityNotice, "authSecurityNotice");
641
+ securityNotice.innerHTML = `
642
+ <strong>⚠️ Security Notice:</strong>
643
+ <ul>
644
+ <li>Credentials are stored in browser localStorage</li>
645
+ <li>Only use with HTTPS endpoints</li>
646
+ <li>Be cautious when using on shared computers</li>
647
+ </ul>
648
+ `;
649
+ body.appendChild(securityNotice);
650
+ authModal.appendChild(body);
651
+ const footer = document.createElement("div");
652
+ addClass(footer, "authModalFooter");
653
+ const removeButton = document.createElement("button");
654
+ removeButton.textContent = "Remove Authentication";
655
+ removeButton.type = "button";
656
+ addClass(removeButton, "authRemoveButton");
657
+ removeButton.onclick = () => {
658
+ this.tab.yasgui.persistentConfig.addOrUpdateEndpoint(endpoint, {
659
+ authentication: undefined,
660
+ });
661
+ authModalOverlay.remove();
662
+ const endpointsList = this.modalContent.querySelector(".endpointsTable");
663
+ if (endpointsList)
664
+ this.renderEndpointsList(endpointsList);
665
+ };
666
+ if (!existingAuth) {
667
+ removeButton.disabled = true;
668
+ }
669
+ const cancelButton = document.createElement("button");
670
+ cancelButton.textContent = "Cancel";
671
+ cancelButton.type = "button";
672
+ addClass(cancelButton, "authCancelButton");
673
+ cancelButton.onclick = () => authModalOverlay.remove();
674
+ const saveButton = document.createElement("button");
675
+ saveButton.textContent = "Save";
676
+ saveButton.type = "button";
677
+ addClass(saveButton, "authSaveButton");
678
+ saveButton.onclick = () => {
679
+ const authType = typeSelect.value;
680
+ if (authType === "basic") {
681
+ const username = usernameInput.value.trim();
682
+ const password = passwordInput.value;
683
+ if (username && password) {
684
+ this.tab.yasgui.persistentConfig.addOrUpdateEndpoint(endpoint, {
685
+ authentication: {
686
+ type: "basic",
687
+ username,
688
+ password,
689
+ },
690
+ });
691
+ authModalOverlay.remove();
692
+ const endpointsList = this.modalContent.querySelector(".endpointsTable");
693
+ if (endpointsList)
694
+ this.renderEndpointsList(endpointsList);
695
+ }
696
+ else {
697
+ alert("Please enter both username and password.");
698
+ }
699
+ }
700
+ else if (authType === "bearer") {
701
+ const token = tokenInput.value.trim();
702
+ if (token) {
703
+ this.tab.yasgui.persistentConfig.addOrUpdateEndpoint(endpoint, {
704
+ authentication: {
705
+ type: "bearer",
706
+ token,
707
+ },
708
+ });
709
+ authModalOverlay.remove();
710
+ const endpointsList = this.modalContent.querySelector(".endpointsTable");
711
+ if (endpointsList)
712
+ this.renderEndpointsList(endpointsList);
713
+ }
714
+ else {
715
+ alert("Please enter a bearer token.");
716
+ }
717
+ }
718
+ else if (authType === "apiKey") {
719
+ const headerName = headerNameInput.value.trim();
720
+ const apiKey = apiKeyInput.value.trim();
721
+ if (headerName && apiKey) {
722
+ this.tab.yasgui.persistentConfig.addOrUpdateEndpoint(endpoint, {
723
+ authentication: {
724
+ type: "apiKey",
725
+ headerName,
726
+ apiKey,
727
+ },
728
+ });
729
+ authModalOverlay.remove();
730
+ const endpointsList = this.modalContent.querySelector(".endpointsTable");
731
+ if (endpointsList)
732
+ this.renderEndpointsList(endpointsList);
733
+ }
734
+ else {
735
+ alert("Please enter both header name and API key.");
736
+ }
737
+ }
738
+ };
739
+ footer.appendChild(removeButton);
740
+ footer.appendChild(cancelButton);
741
+ footer.appendChild(saveButton);
742
+ authModal.appendChild(footer);
743
+ authModalOverlay.appendChild(authModal);
744
+ document.body.appendChild(authModalOverlay);
745
+ }
341
746
  drawRequestSettings(container) {
342
747
  const reqConfig = this.tab.getRequestConfig();
343
748
  const methodSection = this.createSection("Request Method");
@@ -434,7 +839,18 @@ export default class TabSettingsModal {
434
839
  }
435
840
  const snippetsBarCheckbox = document.getElementById("showSnippetsBar");
436
841
  if (snippetsBarCheckbox) {
437
- yasqe.setSnippetsBarVisible(snippetsBarCheckbox.checked);
842
+ this.tab.yasgui.config.showSnippetsBar = snippetsBarCheckbox.checked;
843
+ this.tab.yasgui.persistentConfig.setShowSnippetsBar(snippetsBarCheckbox.checked);
844
+ this.tab.yasgui.persistentConfig.getTabs().forEach((tabId) => {
845
+ const tab = this.tab.yasgui.getTab(tabId);
846
+ if (tab) {
847
+ const tabYasqe = tab.getYasqe();
848
+ if (tabYasqe) {
849
+ tabYasqe.config.showSnippetsBar = snippetsBarCheckbox.checked;
850
+ tabYasqe.refreshSnippetsBar();
851
+ }
852
+ }
853
+ });
438
854
  }
439
855
  yasqe.saveQuery();
440
856
  }
@@ -523,90 +939,6 @@ export default class TabSettingsModal {
523
939
  const deduplicated = this.deduplicatePrefixes(combined);
524
940
  this.tab.yasgui.persistentConfig.setPrefixes(deduplicated);
525
941
  }
526
- drawEndpointButtonsSettings(container) {
527
- const section = document.createElement("div");
528
- addClass(section, "settingsSection");
529
- const label = document.createElement("label");
530
- label.textContent = "Custom Endpoint Buttons";
531
- addClass(label, "settingsLabel");
532
- const help = document.createElement("div");
533
- help.textContent = "Add custom endpoint buttons that will appear next to the endpoint textbox.";
534
- addClass(help, "settingsHelp");
535
- section.appendChild(label);
536
- section.appendChild(help);
537
- const buttonsList = document.createElement("div");
538
- addClass(buttonsList, "endpointButtonsList");
539
- this.renderEndpointButtonsList(buttonsList);
540
- section.appendChild(buttonsList);
541
- const addForm = document.createElement("div");
542
- addClass(addForm, "addEndpointButtonForm");
543
- const labelInput = document.createElement("input");
544
- labelInput.type = "text";
545
- labelInput.placeholder = "Button label (e.g., DBpedia)";
546
- addClass(labelInput, "endpointButtonLabelInput");
547
- const endpointInput = document.createElement("input");
548
- endpointInput.type = "url";
549
- endpointInput.placeholder = "Endpoint URL (e.g., https://dbpedia.org/sparql)";
550
- addClass(endpointInput, "endpointButtonEndpointInput");
551
- const addButton = document.createElement("button");
552
- addButton.textContent = "+ Add Button";
553
- addClass(addButton, "addEndpointButton");
554
- addButton.type = "button";
555
- addButton.onclick = () => {
556
- const labelValue = labelInput.value.trim();
557
- const endpointValue = endpointInput.value.trim();
558
- if (!labelValue || !endpointValue) {
559
- alert("Please enter both a label and an endpoint URL.");
560
- return;
561
- }
562
- const currentButtons = this.tab.yasgui.persistentConfig.getCustomEndpointButtons();
563
- currentButtons.push({ label: labelValue, endpoint: endpointValue });
564
- this.tab.yasgui.persistentConfig.setCustomEndpointButtons(currentButtons);
565
- labelInput.value = "";
566
- endpointInput.value = "";
567
- this.renderEndpointButtonsList(buttonsList);
568
- };
569
- addForm.appendChild(labelInput);
570
- addForm.appendChild(endpointInput);
571
- addForm.appendChild(addButton);
572
- section.appendChild(addForm);
573
- container.appendChild(section);
574
- }
575
- renderEndpointButtonsList(container) {
576
- container.innerHTML = "";
577
- const customButtons = this.tab.yasgui.persistentConfig.getCustomEndpointButtons();
578
- if (customButtons.length === 0) {
579
- const emptyMsg = document.createElement("div");
580
- emptyMsg.textContent = "No custom buttons yet. Add one below.";
581
- addClass(emptyMsg, "emptyMessage");
582
- container.appendChild(emptyMsg);
583
- return;
584
- }
585
- customButtons.forEach((btn, index) => {
586
- const item = document.createElement("div");
587
- addClass(item, "endpointButtonItem");
588
- const labelSpan = document.createElement("span");
589
- labelSpan.textContent = `${btn.label}`;
590
- addClass(labelSpan, "buttonLabel");
591
- const endpointSpan = document.createElement("span");
592
- endpointSpan.textContent = btn.endpoint;
593
- addClass(endpointSpan, "buttonEndpoint");
594
- const removeBtn = document.createElement("button");
595
- removeBtn.textContent = "×";
596
- addClass(removeBtn, "removeButton");
597
- removeBtn.type = "button";
598
- removeBtn.onclick = () => {
599
- const currentButtons = this.tab.yasgui.persistentConfig.getCustomEndpointButtons();
600
- currentButtons.splice(index, 1);
601
- this.tab.yasgui.persistentConfig.setCustomEndpointButtons(currentButtons);
602
- this.renderEndpointButtonsList(container);
603
- };
604
- item.appendChild(labelSpan);
605
- item.appendChild(endpointSpan);
606
- item.appendChild(removeBtn);
607
- container.appendChild(item);
608
- });
609
- }
610
942
  getThemeToggleIcon() {
611
943
  const currentTheme = this.tab.yasgui.getTheme();
612
944
  return currentTheme === "dark" ? MOON_ICON : SUN_ICON;