@matdata/yasgui 5.4.0 → 5.5.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.
- package/build/ts/src/ConfigExportImport.js +1 -0
- package/build/ts/src/ConfigExportImport.js.map +1 -1
- package/build/ts/src/PersistentConfig.d.ts +7 -1
- package/build/ts/src/PersistentConfig.js +32 -0
- package/build/ts/src/PersistentConfig.js.map +1 -1
- package/build/ts/src/Tab.d.ts +1 -0
- package/build/ts/src/Tab.js +28 -2
- package/build/ts/src/Tab.js.map +1 -1
- package/build/ts/src/TabSettingsModal.d.ts +3 -2
- package/build/ts/src/TabSettingsModal.js +328 -119
- package/build/ts/src/TabSettingsModal.js.map +1 -1
- package/build/ts/src/index.d.ts +10 -0
- package/build/ts/src/index.js.map +1 -1
- package/build/yasgui.min.css +1 -1
- package/build/yasgui.min.css.map +3 -3
- package/build/yasgui.min.js +124 -117
- package/build/yasgui.min.js.map +3 -3
- package/package.json +1 -1
- package/src/ConfigExportImport.ts +1 -0
- package/src/PersistentConfig.ts +44 -2
- package/src/Tab.ts +47 -3
- package/src/TabSettingsModal.scss +385 -16
- package/src/TabSettingsModal.ts +413 -148
- package/src/index.ts +11 -0
package/src/TabSettingsModal.ts
CHANGED
|
@@ -111,56 +111,63 @@ export default class TabSettingsModal {
|
|
|
111
111
|
|
|
112
112
|
this.modalContent.appendChild(header);
|
|
113
113
|
|
|
114
|
-
// Body with
|
|
114
|
+
// Body with sidebar navigation
|
|
115
115
|
const body = document.createElement("div");
|
|
116
116
|
addClass(body, "modalBody");
|
|
117
117
|
|
|
118
|
-
|
|
119
|
-
|
|
118
|
+
// Sidebar navigation
|
|
119
|
+
const sidebar = document.createElement("div");
|
|
120
|
+
addClass(sidebar, "modalSidebar");
|
|
120
121
|
|
|
121
122
|
const requestTab = document.createElement("button");
|
|
122
123
|
requestTab.textContent = "Request";
|
|
123
|
-
addClass(requestTab, "
|
|
124
|
+
addClass(requestTab, "modalNavButton", "active");
|
|
124
125
|
requestTab.onclick = () => this.switchTab("request");
|
|
125
126
|
|
|
127
|
+
const endpointsTab = document.createElement("button");
|
|
128
|
+
endpointsTab.textContent = "SPARQL Endpoints";
|
|
129
|
+
addClass(endpointsTab, "modalNavButton");
|
|
130
|
+
endpointsTab.onclick = () => this.switchTab("endpoints");
|
|
131
|
+
|
|
126
132
|
const prefixTab = document.createElement("button");
|
|
127
133
|
prefixTab.textContent = "Prefixes";
|
|
128
|
-
addClass(prefixTab, "
|
|
134
|
+
addClass(prefixTab, "modalNavButton");
|
|
129
135
|
prefixTab.onclick = () => this.switchTab("prefix");
|
|
130
136
|
|
|
131
137
|
const editorTab = document.createElement("button");
|
|
132
138
|
editorTab.textContent = "Editor";
|
|
133
|
-
addClass(editorTab, "
|
|
139
|
+
addClass(editorTab, "modalNavButton");
|
|
134
140
|
editorTab.onclick = () => this.switchTab("editor");
|
|
135
141
|
|
|
136
|
-
const endpointsTab = document.createElement("button");
|
|
137
|
-
endpointsTab.textContent = "Endpoint Buttons";
|
|
138
|
-
addClass(endpointsTab, "modalTabButton");
|
|
139
|
-
endpointsTab.onclick = () => this.switchTab("endpoints");
|
|
140
|
-
|
|
141
142
|
const importExportTab = document.createElement("button");
|
|
142
143
|
importExportTab.textContent = "Import/Export";
|
|
143
|
-
addClass(importExportTab, "
|
|
144
|
+
addClass(importExportTab, "modalNavButton");
|
|
144
145
|
importExportTab.onclick = () => this.switchTab("importexport");
|
|
145
146
|
|
|
146
147
|
const shortcutsTab = document.createElement("button");
|
|
147
148
|
shortcutsTab.textContent = "Keyboard Shortcuts";
|
|
148
|
-
addClass(shortcutsTab, "
|
|
149
|
+
addClass(shortcutsTab, "modalNavButton");
|
|
149
150
|
shortcutsTab.onclick = () => this.switchTab("shortcuts");
|
|
150
151
|
|
|
151
152
|
const aboutTab = document.createElement("button");
|
|
152
153
|
aboutTab.textContent = "About";
|
|
153
|
-
addClass(aboutTab, "
|
|
154
|
+
addClass(aboutTab, "modalNavButton");
|
|
154
155
|
aboutTab.onclick = () => this.switchTab("about");
|
|
155
156
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
157
|
+
sidebar.appendChild(requestTab);
|
|
158
|
+
sidebar.appendChild(endpointsTab);
|
|
159
|
+
sidebar.appendChild(prefixTab);
|
|
160
|
+
sidebar.appendChild(editorTab);
|
|
161
|
+
sidebar.appendChild(importExportTab);
|
|
162
|
+
sidebar.appendChild(shortcutsTab);
|
|
163
|
+
sidebar.appendChild(aboutTab);
|
|
164
|
+
|
|
165
|
+
// Content area container
|
|
166
|
+
const contentArea = document.createElement("div");
|
|
167
|
+
addClass(contentArea, "modalContentArea");
|
|
168
|
+
|
|
169
|
+
body.appendChild(sidebar);
|
|
170
|
+
body.appendChild(contentArea);
|
|
164
171
|
|
|
165
172
|
// Tab content containers
|
|
166
173
|
const requestContent = document.createElement("div");
|
|
@@ -168,6 +175,11 @@ export default class TabSettingsModal {
|
|
|
168
175
|
requestContent.id = "request-content";
|
|
169
176
|
this.drawRequestSettings(requestContent);
|
|
170
177
|
|
|
178
|
+
const endpointsContent = document.createElement("div");
|
|
179
|
+
addClass(endpointsContent, "modalTabContent");
|
|
180
|
+
endpointsContent.id = "endpoints-content";
|
|
181
|
+
this.drawEndpointsSettings(endpointsContent);
|
|
182
|
+
|
|
171
183
|
const prefixContent = document.createElement("div");
|
|
172
184
|
addClass(prefixContent, "modalTabContent");
|
|
173
185
|
prefixContent.id = "prefix-content";
|
|
@@ -178,11 +190,6 @@ export default class TabSettingsModal {
|
|
|
178
190
|
editorContent.id = "editor-content";
|
|
179
191
|
this.drawEditorSettings(editorContent);
|
|
180
192
|
|
|
181
|
-
const endpointsContent = document.createElement("div");
|
|
182
|
-
addClass(endpointsContent, "modalTabContent");
|
|
183
|
-
endpointsContent.id = "endpoints-content";
|
|
184
|
-
this.drawEndpointButtonsSettings(endpointsContent);
|
|
185
|
-
|
|
186
193
|
const importExportContent = document.createElement("div");
|
|
187
194
|
addClass(importExportContent, "modalTabContent");
|
|
188
195
|
importExportContent.id = "importexport-content";
|
|
@@ -198,13 +205,13 @@ export default class TabSettingsModal {
|
|
|
198
205
|
aboutContent.id = "about-content";
|
|
199
206
|
this.drawAboutSettings(aboutContent);
|
|
200
207
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
+
contentArea.appendChild(requestContent);
|
|
209
|
+
contentArea.appendChild(endpointsContent);
|
|
210
|
+
contentArea.appendChild(prefixContent);
|
|
211
|
+
contentArea.appendChild(editorContent);
|
|
212
|
+
contentArea.appendChild(importExportContent);
|
|
213
|
+
contentArea.appendChild(shortcutsContent);
|
|
214
|
+
contentArea.appendChild(aboutContent);
|
|
208
215
|
|
|
209
216
|
this.modalContent.appendChild(body);
|
|
210
217
|
|
|
@@ -232,15 +239,15 @@ export default class TabSettingsModal {
|
|
|
232
239
|
}
|
|
233
240
|
|
|
234
241
|
private switchTab(tabName: string) {
|
|
235
|
-
const buttons = this.modalContent.querySelectorAll(".
|
|
242
|
+
const buttons = this.modalContent.querySelectorAll(".modalNavButton");
|
|
236
243
|
const contents = this.modalContent.querySelectorAll(".modalTabContent");
|
|
237
244
|
|
|
238
245
|
buttons.forEach((btn, index) => {
|
|
239
246
|
if (
|
|
240
247
|
(tabName === "request" && index === 0) ||
|
|
241
|
-
(tabName === "
|
|
242
|
-
(tabName === "
|
|
243
|
-
(tabName === "
|
|
248
|
+
(tabName === "endpoints" && index === 1) ||
|
|
249
|
+
(tabName === "prefix" && index === 2) ||
|
|
250
|
+
(tabName === "editor" && index === 3) ||
|
|
244
251
|
(tabName === "importexport" && index === 4) ||
|
|
245
252
|
(tabName === "shortcuts" && index === 5) ||
|
|
246
253
|
(tabName === "about" && index === 6)
|
|
@@ -436,6 +443,369 @@ export default class TabSettingsModal {
|
|
|
436
443
|
container.appendChild(snippetsBarSection);
|
|
437
444
|
}
|
|
438
445
|
|
|
446
|
+
private drawEndpointsSettings(container: HTMLElement) {
|
|
447
|
+
const section = document.createElement("div");
|
|
448
|
+
addClass(section, "settingsSection");
|
|
449
|
+
|
|
450
|
+
const label = document.createElement("label");
|
|
451
|
+
label.textContent = "SPARQL Endpoints";
|
|
452
|
+
addClass(label, "settingsLabel");
|
|
453
|
+
|
|
454
|
+
const help = document.createElement("div");
|
|
455
|
+
help.textContent =
|
|
456
|
+
"Manage your SPARQL endpoints. Each endpoint can have its own authentication and be displayed as a quick-switch button.";
|
|
457
|
+
addClass(help, "settingsHelp");
|
|
458
|
+
|
|
459
|
+
section.appendChild(label);
|
|
460
|
+
section.appendChild(help);
|
|
461
|
+
|
|
462
|
+
// List of endpoints
|
|
463
|
+
const endpointsList = document.createElement("div");
|
|
464
|
+
addClass(endpointsList, "endpointsTable");
|
|
465
|
+
this.renderEndpointsList(endpointsList);
|
|
466
|
+
section.appendChild(endpointsList);
|
|
467
|
+
|
|
468
|
+
container.appendChild(section);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
private renderEndpointsList(container: HTMLElement) {
|
|
472
|
+
container.innerHTML = "";
|
|
473
|
+
const configs = this.tab.yasgui.persistentConfig.getEndpointConfigs();
|
|
474
|
+
|
|
475
|
+
// Create table (even if empty, we'll show add form)
|
|
476
|
+
const table = document.createElement("table");
|
|
477
|
+
addClass(table, "endpointsTableElement");
|
|
478
|
+
|
|
479
|
+
// Header
|
|
480
|
+
const thead = document.createElement("thead");
|
|
481
|
+
const headerRow = document.createElement("tr");
|
|
482
|
+
const headers = ["Endpoint", "Label", "Button", "Authentication", "Actions"];
|
|
483
|
+
headers.forEach((h) => {
|
|
484
|
+
const th = document.createElement("th");
|
|
485
|
+
th.textContent = h;
|
|
486
|
+
headerRow.appendChild(th);
|
|
487
|
+
});
|
|
488
|
+
thead.appendChild(headerRow);
|
|
489
|
+
table.appendChild(thead);
|
|
490
|
+
|
|
491
|
+
// Body
|
|
492
|
+
const tbody = document.createElement("tbody");
|
|
493
|
+
|
|
494
|
+
if (configs.length === 0) {
|
|
495
|
+
// Show empty message in table
|
|
496
|
+
const emptyRow = document.createElement("tr");
|
|
497
|
+
const emptyCell = document.createElement("td");
|
|
498
|
+
emptyCell.colSpan = 5;
|
|
499
|
+
emptyCell.textContent = "No endpoints yet. Add one below or access an endpoint to have it automatically tracked.";
|
|
500
|
+
addClass(emptyCell, "emptyMessage");
|
|
501
|
+
emptyCell.style.textAlign = "center";
|
|
502
|
+
emptyCell.style.padding = "20px";
|
|
503
|
+
emptyRow.appendChild(emptyCell);
|
|
504
|
+
tbody.appendChild(emptyRow);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
configs.forEach((config, index) => {
|
|
508
|
+
const row = document.createElement("tr");
|
|
509
|
+
|
|
510
|
+
// Endpoint column
|
|
511
|
+
const endpointCell = document.createElement("td");
|
|
512
|
+
endpointCell.textContent = config.endpoint;
|
|
513
|
+
endpointCell.title = config.endpoint;
|
|
514
|
+
addClass(endpointCell, "endpointCell");
|
|
515
|
+
row.appendChild(endpointCell);
|
|
516
|
+
|
|
517
|
+
// Label column (editable)
|
|
518
|
+
const labelCell = document.createElement("td");
|
|
519
|
+
const labelInput = document.createElement("input");
|
|
520
|
+
labelInput.type = "text";
|
|
521
|
+
labelInput.value = config.label || "";
|
|
522
|
+
labelInput.placeholder = "Optional label";
|
|
523
|
+
addClass(labelInput, "endpointLabelInput");
|
|
524
|
+
labelInput.onchange = () => {
|
|
525
|
+
this.tab.yasgui.persistentConfig.addOrUpdateEndpoint(config.endpoint, {
|
|
526
|
+
label: labelInput.value.trim() || undefined,
|
|
527
|
+
});
|
|
528
|
+
this.renderEndpointsList(container);
|
|
529
|
+
this.tab.refreshEndpointButtons();
|
|
530
|
+
};
|
|
531
|
+
labelCell.appendChild(labelInput);
|
|
532
|
+
row.appendChild(labelCell);
|
|
533
|
+
|
|
534
|
+
// Show as Button checkbox (requires label)
|
|
535
|
+
const buttonCell = document.createElement("td");
|
|
536
|
+
const buttonCheckbox = document.createElement("input");
|
|
537
|
+
buttonCheckbox.type = "checkbox";
|
|
538
|
+
buttonCheckbox.checked = !!config.showAsButton;
|
|
539
|
+
buttonCheckbox.disabled = !config.label;
|
|
540
|
+
buttonCheckbox.setAttribute(
|
|
541
|
+
"aria-label",
|
|
542
|
+
config.label ? "Show this endpoint as a quick-switch button" : "Add a label first to enable button",
|
|
543
|
+
);
|
|
544
|
+
buttonCheckbox.title = config.label
|
|
545
|
+
? "Show this endpoint as a quick-switch button"
|
|
546
|
+
: "Add a label first to enable button";
|
|
547
|
+
buttonCheckbox.onchange = () => {
|
|
548
|
+
this.tab.yasgui.persistentConfig.addOrUpdateEndpoint(config.endpoint, {
|
|
549
|
+
showAsButton: buttonCheckbox.checked,
|
|
550
|
+
});
|
|
551
|
+
this.tab.refreshEndpointButtons();
|
|
552
|
+
};
|
|
553
|
+
buttonCell.appendChild(buttonCheckbox);
|
|
554
|
+
addClass(buttonCell, "centerCell");
|
|
555
|
+
row.appendChild(buttonCell);
|
|
556
|
+
|
|
557
|
+
// Authentication column
|
|
558
|
+
const authCell = document.createElement("td");
|
|
559
|
+
const authButton = document.createElement("button");
|
|
560
|
+
authButton.type = "button";
|
|
561
|
+
addClass(authButton, "configureAuthButton");
|
|
562
|
+
if (config.authentication) {
|
|
563
|
+
authButton.textContent = "✓ Configured";
|
|
564
|
+
addClass(authButton, "authenticated");
|
|
565
|
+
} else {
|
|
566
|
+
authButton.textContent = "Configure";
|
|
567
|
+
}
|
|
568
|
+
authButton.onclick = () => this.showAuthenticationModal(config.endpoint);
|
|
569
|
+
authCell.appendChild(authButton);
|
|
570
|
+
addClass(authCell, "centerCell");
|
|
571
|
+
row.appendChild(authCell);
|
|
572
|
+
|
|
573
|
+
// Actions column
|
|
574
|
+
const actionsCell = document.createElement("td");
|
|
575
|
+
const deleteButton = document.createElement("button");
|
|
576
|
+
deleteButton.type = "button";
|
|
577
|
+
deleteButton.textContent = "Delete";
|
|
578
|
+
addClass(deleteButton, "deleteEndpointButton");
|
|
579
|
+
deleteButton.onclick = () => {
|
|
580
|
+
if (confirm(`Delete endpoint "${config.endpoint}"?`)) {
|
|
581
|
+
this.tab.yasgui.persistentConfig.deleteEndpointConfig(config.endpoint);
|
|
582
|
+
this.renderEndpointsList(container);
|
|
583
|
+
this.tab.refreshEndpointButtons();
|
|
584
|
+
}
|
|
585
|
+
};
|
|
586
|
+
actionsCell.appendChild(deleteButton);
|
|
587
|
+
addClass(actionsCell, "centerCell");
|
|
588
|
+
row.appendChild(actionsCell);
|
|
589
|
+
|
|
590
|
+
tbody.appendChild(row);
|
|
591
|
+
});
|
|
592
|
+
table.appendChild(tbody);
|
|
593
|
+
container.appendChild(table);
|
|
594
|
+
|
|
595
|
+
// Add endpoint form
|
|
596
|
+
const addForm = document.createElement("div");
|
|
597
|
+
addClass(addForm, "addEndpointForm");
|
|
598
|
+
|
|
599
|
+
const addFormTitle = document.createElement("div");
|
|
600
|
+
addFormTitle.textContent = "Add New Endpoint";
|
|
601
|
+
addClass(addFormTitle, "addFormTitle");
|
|
602
|
+
addForm.appendChild(addFormTitle);
|
|
603
|
+
|
|
604
|
+
const formInputs = document.createElement("div");
|
|
605
|
+
addClass(formInputs, "addFormInputs");
|
|
606
|
+
|
|
607
|
+
const endpointInput = document.createElement("input");
|
|
608
|
+
endpointInput.type = "url";
|
|
609
|
+
endpointInput.placeholder = "Endpoint URL (e.g., https://dbpedia.org/sparql)";
|
|
610
|
+
addClass(endpointInput, "addEndpointInput");
|
|
611
|
+
formInputs.appendChild(endpointInput);
|
|
612
|
+
|
|
613
|
+
const addButton = document.createElement("button");
|
|
614
|
+
addButton.type = "button";
|
|
615
|
+
addButton.textContent = "+ Add Endpoint";
|
|
616
|
+
addClass(addButton, "addEndpointButton");
|
|
617
|
+
addButton.onclick = () => {
|
|
618
|
+
const endpoint = endpointInput.value.trim();
|
|
619
|
+
|
|
620
|
+
if (!endpoint) {
|
|
621
|
+
alert("Please enter an endpoint URL.");
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// Validate URL format
|
|
626
|
+
// Check for supported protocol first
|
|
627
|
+
if (!/^https?:\/\//i.test(endpoint)) {
|
|
628
|
+
alert("Endpoint URL must start with http:// or https://");
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
try {
|
|
632
|
+
new URL(endpoint);
|
|
633
|
+
} catch (e) {
|
|
634
|
+
// Show the error message if available, otherwise a generic one
|
|
635
|
+
alert(e instanceof Error && e.message ? "Malformed URL: " + e.message : "Please enter a valid URL.");
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
// Check if endpoint already exists
|
|
640
|
+
const existing = this.tab.yasgui.persistentConfig.getEndpointConfig(endpoint);
|
|
641
|
+
if (existing) {
|
|
642
|
+
alert("This endpoint is already in the list.");
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// Add the endpoint
|
|
647
|
+
this.tab.yasgui.persistentConfig.addOrUpdateEndpoint(endpoint, {});
|
|
648
|
+
|
|
649
|
+
// Clear input
|
|
650
|
+
endpointInput.value = "";
|
|
651
|
+
|
|
652
|
+
// Refresh list
|
|
653
|
+
this.renderEndpointsList(container);
|
|
654
|
+
this.tab.refreshEndpointButtons();
|
|
655
|
+
};
|
|
656
|
+
formInputs.appendChild(addButton);
|
|
657
|
+
|
|
658
|
+
addForm.appendChild(formInputs);
|
|
659
|
+
container.appendChild(addForm);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
private showAuthenticationModal(endpoint: string) {
|
|
663
|
+
const config = this.tab.yasgui.persistentConfig.getEndpointConfig(endpoint);
|
|
664
|
+
const existingAuth = config?.authentication;
|
|
665
|
+
|
|
666
|
+
// Create modal overlay
|
|
667
|
+
const authModalOverlay = document.createElement("div");
|
|
668
|
+
addClass(authModalOverlay, "authModalOverlay");
|
|
669
|
+
authModalOverlay.onclick = () => authModalOverlay.remove();
|
|
670
|
+
|
|
671
|
+
// Create modal content
|
|
672
|
+
const authModal = document.createElement("div");
|
|
673
|
+
addClass(authModal, "authModal");
|
|
674
|
+
authModal.onclick = (e) => e.stopPropagation();
|
|
675
|
+
|
|
676
|
+
// Header
|
|
677
|
+
const header = document.createElement("div");
|
|
678
|
+
addClass(header, "authModalHeader");
|
|
679
|
+
const title = document.createElement("h3");
|
|
680
|
+
title.textContent = "Configure Authentication";
|
|
681
|
+
const subtitle = document.createElement("div");
|
|
682
|
+
subtitle.textContent = endpoint;
|
|
683
|
+
addClass(subtitle, "authModalSubtitle");
|
|
684
|
+
header.appendChild(title);
|
|
685
|
+
header.appendChild(subtitle);
|
|
686
|
+
authModal.appendChild(header);
|
|
687
|
+
|
|
688
|
+
// Body
|
|
689
|
+
const body = document.createElement("div");
|
|
690
|
+
addClass(body, "authModalBody");
|
|
691
|
+
|
|
692
|
+
// Auth type (for now only basic, but designed for future)
|
|
693
|
+
const typeSection = document.createElement("div");
|
|
694
|
+
addClass(typeSection, "authModalSection");
|
|
695
|
+
const typeLabel = document.createElement("label");
|
|
696
|
+
typeLabel.textContent = "Authentication Type";
|
|
697
|
+
const typeSelect = document.createElement("select");
|
|
698
|
+
const basicOption = document.createElement("option");
|
|
699
|
+
basicOption.value = "basic";
|
|
700
|
+
basicOption.textContent = "HTTP Basic Authentication";
|
|
701
|
+
typeSelect.appendChild(basicOption);
|
|
702
|
+
// Future: Add OAuth, Bearer Token, etc.
|
|
703
|
+
typeSection.appendChild(typeLabel);
|
|
704
|
+
typeSection.appendChild(typeSelect);
|
|
705
|
+
body.appendChild(typeSection);
|
|
706
|
+
|
|
707
|
+
// Username
|
|
708
|
+
const usernameSection = document.createElement("div");
|
|
709
|
+
addClass(usernameSection, "authModalSection");
|
|
710
|
+
const usernameLabel = document.createElement("label");
|
|
711
|
+
usernameLabel.textContent = "Username";
|
|
712
|
+
const usernameInput = document.createElement("input");
|
|
713
|
+
usernameInput.type = "text";
|
|
714
|
+
usernameInput.placeholder = "Enter username";
|
|
715
|
+
usernameInput.value = existingAuth?.username || "";
|
|
716
|
+
usernameInput.autocomplete = "username";
|
|
717
|
+
usernameSection.appendChild(usernameLabel);
|
|
718
|
+
usernameSection.appendChild(usernameInput);
|
|
719
|
+
body.appendChild(usernameSection);
|
|
720
|
+
|
|
721
|
+
// Password
|
|
722
|
+
const passwordSection = document.createElement("div");
|
|
723
|
+
addClass(passwordSection, "authModalSection");
|
|
724
|
+
const passwordLabel = document.createElement("label");
|
|
725
|
+
passwordLabel.textContent = "Password";
|
|
726
|
+
const passwordInput = document.createElement("input");
|
|
727
|
+
passwordInput.type = "password";
|
|
728
|
+
passwordInput.placeholder = "Enter password";
|
|
729
|
+
passwordInput.value = existingAuth?.password || "";
|
|
730
|
+
passwordInput.autocomplete = "current-password";
|
|
731
|
+
passwordSection.appendChild(passwordLabel);
|
|
732
|
+
passwordSection.appendChild(passwordInput);
|
|
733
|
+
body.appendChild(passwordSection);
|
|
734
|
+
|
|
735
|
+
// Security notice
|
|
736
|
+
const securityNotice = document.createElement("div");
|
|
737
|
+
addClass(securityNotice, "authSecurityNotice");
|
|
738
|
+
securityNotice.innerHTML = `
|
|
739
|
+
<strong>⚠️ Security Notice:</strong>
|
|
740
|
+
<ul>
|
|
741
|
+
<li>Credentials are stored in browser localStorage</li>
|
|
742
|
+
<li>Only use with HTTPS endpoints</li>
|
|
743
|
+
<li>Be cautious when using on shared computers</li>
|
|
744
|
+
</ul>
|
|
745
|
+
`;
|
|
746
|
+
body.appendChild(securityNotice);
|
|
747
|
+
|
|
748
|
+
authModal.appendChild(body);
|
|
749
|
+
|
|
750
|
+
// Footer
|
|
751
|
+
const footer = document.createElement("div");
|
|
752
|
+
addClass(footer, "authModalFooter");
|
|
753
|
+
|
|
754
|
+
const removeButton = document.createElement("button");
|
|
755
|
+
removeButton.textContent = "Remove Authentication";
|
|
756
|
+
removeButton.type = "button";
|
|
757
|
+
addClass(removeButton, "authRemoveButton");
|
|
758
|
+
removeButton.onclick = () => {
|
|
759
|
+
this.tab.yasgui.persistentConfig.addOrUpdateEndpoint(endpoint, {
|
|
760
|
+
authentication: undefined,
|
|
761
|
+
});
|
|
762
|
+
authModalOverlay.remove();
|
|
763
|
+
const endpointsList = this.modalContent.querySelector(".endpointsTable");
|
|
764
|
+
if (endpointsList) this.renderEndpointsList(endpointsList as HTMLElement);
|
|
765
|
+
};
|
|
766
|
+
if (!existingAuth) {
|
|
767
|
+
removeButton.disabled = true;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
const cancelButton = document.createElement("button");
|
|
771
|
+
cancelButton.textContent = "Cancel";
|
|
772
|
+
cancelButton.type = "button";
|
|
773
|
+
addClass(cancelButton, "authCancelButton");
|
|
774
|
+
cancelButton.onclick = () => authModalOverlay.remove();
|
|
775
|
+
|
|
776
|
+
const saveButton = document.createElement("button");
|
|
777
|
+
saveButton.textContent = "Save";
|
|
778
|
+
saveButton.type = "button";
|
|
779
|
+
addClass(saveButton, "authSaveButton");
|
|
780
|
+
saveButton.onclick = () => {
|
|
781
|
+
const username = usernameInput.value.trim();
|
|
782
|
+
const password = passwordInput.value;
|
|
783
|
+
|
|
784
|
+
if (username && password) {
|
|
785
|
+
this.tab.yasgui.persistentConfig.addOrUpdateEndpoint(endpoint, {
|
|
786
|
+
authentication: {
|
|
787
|
+
type: "basic",
|
|
788
|
+
username,
|
|
789
|
+
password,
|
|
790
|
+
},
|
|
791
|
+
});
|
|
792
|
+
authModalOverlay.remove();
|
|
793
|
+
const endpointsList = this.modalContent.querySelector(".endpointsTable");
|
|
794
|
+
if (endpointsList) this.renderEndpointsList(endpointsList as HTMLElement);
|
|
795
|
+
} else {
|
|
796
|
+
alert("Please enter both username and password.");
|
|
797
|
+
}
|
|
798
|
+
};
|
|
799
|
+
|
|
800
|
+
footer.appendChild(removeButton);
|
|
801
|
+
footer.appendChild(cancelButton);
|
|
802
|
+
footer.appendChild(saveButton);
|
|
803
|
+
authModal.appendChild(footer);
|
|
804
|
+
|
|
805
|
+
authModalOverlay.appendChild(authModal);
|
|
806
|
+
document.body.appendChild(authModalOverlay);
|
|
807
|
+
}
|
|
808
|
+
|
|
439
809
|
private drawRequestSettings(container: HTMLElement) {
|
|
440
810
|
// This is a simplified version - you can expand based on TabPanel.ts
|
|
441
811
|
const reqConfig = this.tab.getRequestConfig();
|
|
@@ -576,6 +946,9 @@ export default class TabSettingsModal {
|
|
|
576
946
|
this.tab.setRequestConfig(updates);
|
|
577
947
|
}
|
|
578
948
|
|
|
949
|
+
// Note: Authentication is now handled per-endpoint in the Endpoints tab,
|
|
950
|
+
// not per-tab anymore. No need to save it here.
|
|
951
|
+
|
|
579
952
|
// Refresh endpoint buttons to show any changes
|
|
580
953
|
this.tab.refreshEndpointButtons();
|
|
581
954
|
|
|
@@ -674,116 +1047,8 @@ export default class TabSettingsModal {
|
|
|
674
1047
|
this.tab.yasgui.persistentConfig.setPrefixes(deduplicated);
|
|
675
1048
|
}
|
|
676
1049
|
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
addClass(section, "settingsSection");
|
|
680
|
-
|
|
681
|
-
const label = document.createElement("label");
|
|
682
|
-
label.textContent = "Custom Endpoint Buttons";
|
|
683
|
-
addClass(label, "settingsLabel");
|
|
684
|
-
|
|
685
|
-
const help = document.createElement("div");
|
|
686
|
-
help.textContent = "Add custom endpoint buttons that will appear next to the endpoint textbox.";
|
|
687
|
-
addClass(help, "settingsHelp");
|
|
688
|
-
|
|
689
|
-
section.appendChild(label);
|
|
690
|
-
section.appendChild(help);
|
|
691
|
-
|
|
692
|
-
// List of existing buttons
|
|
693
|
-
const buttonsList = document.createElement("div");
|
|
694
|
-
addClass(buttonsList, "endpointButtonsList");
|
|
695
|
-
this.renderEndpointButtonsList(buttonsList);
|
|
696
|
-
section.appendChild(buttonsList);
|
|
697
|
-
|
|
698
|
-
// Form to add new button
|
|
699
|
-
const addForm = document.createElement("div");
|
|
700
|
-
addClass(addForm, "addEndpointButtonForm");
|
|
701
|
-
|
|
702
|
-
const labelInput = document.createElement("input");
|
|
703
|
-
labelInput.type = "text";
|
|
704
|
-
labelInput.placeholder = "Button label (e.g., DBpedia)";
|
|
705
|
-
addClass(labelInput, "endpointButtonLabelInput");
|
|
706
|
-
|
|
707
|
-
const endpointInput = document.createElement("input");
|
|
708
|
-
endpointInput.type = "url";
|
|
709
|
-
endpointInput.placeholder = "Endpoint URL (e.g., https://dbpedia.org/sparql)";
|
|
710
|
-
addClass(endpointInput, "endpointButtonEndpointInput");
|
|
711
|
-
|
|
712
|
-
const addButton = document.createElement("button");
|
|
713
|
-
addButton.textContent = "+ Add Button";
|
|
714
|
-
addClass(addButton, "addEndpointButton");
|
|
715
|
-
addButton.type = "button";
|
|
716
|
-
addButton.onclick = () => {
|
|
717
|
-
const labelValue = labelInput.value.trim();
|
|
718
|
-
const endpointValue = endpointInput.value.trim();
|
|
719
|
-
|
|
720
|
-
if (!labelValue || !endpointValue) {
|
|
721
|
-
alert("Please enter both a label and an endpoint URL.");
|
|
722
|
-
return;
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
// Add to persistent config
|
|
726
|
-
const currentButtons = this.tab.yasgui.persistentConfig.getCustomEndpointButtons();
|
|
727
|
-
currentButtons.push({ label: labelValue, endpoint: endpointValue });
|
|
728
|
-
this.tab.yasgui.persistentConfig.setCustomEndpointButtons(currentButtons);
|
|
729
|
-
|
|
730
|
-
// Clear inputs
|
|
731
|
-
labelInput.value = "";
|
|
732
|
-
endpointInput.value = "";
|
|
733
|
-
|
|
734
|
-
// Refresh list
|
|
735
|
-
this.renderEndpointButtonsList(buttonsList);
|
|
736
|
-
};
|
|
737
|
-
|
|
738
|
-
addForm.appendChild(labelInput);
|
|
739
|
-
addForm.appendChild(endpointInput);
|
|
740
|
-
addForm.appendChild(addButton);
|
|
741
|
-
section.appendChild(addForm);
|
|
742
|
-
|
|
743
|
-
container.appendChild(section);
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
private renderEndpointButtonsList(container: HTMLElement) {
|
|
747
|
-
container.innerHTML = "";
|
|
748
|
-
const customButtons = this.tab.yasgui.persistentConfig.getCustomEndpointButtons();
|
|
749
|
-
|
|
750
|
-
if (customButtons.length === 0) {
|
|
751
|
-
const emptyMsg = document.createElement("div");
|
|
752
|
-
emptyMsg.textContent = "No custom buttons yet. Add one below.";
|
|
753
|
-
addClass(emptyMsg, "emptyMessage");
|
|
754
|
-
container.appendChild(emptyMsg);
|
|
755
|
-
return;
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
customButtons.forEach((btn, index) => {
|
|
759
|
-
const item = document.createElement("div");
|
|
760
|
-
addClass(item, "endpointButtonItem");
|
|
761
|
-
|
|
762
|
-
const labelSpan = document.createElement("span");
|
|
763
|
-
labelSpan.textContent = `${btn.label}`;
|
|
764
|
-
addClass(labelSpan, "buttonLabel");
|
|
765
|
-
|
|
766
|
-
const endpointSpan = document.createElement("span");
|
|
767
|
-
endpointSpan.textContent = btn.endpoint;
|
|
768
|
-
addClass(endpointSpan, "buttonEndpoint");
|
|
769
|
-
|
|
770
|
-
const removeBtn = document.createElement("button");
|
|
771
|
-
removeBtn.textContent = "×";
|
|
772
|
-
addClass(removeBtn, "removeButton");
|
|
773
|
-
removeBtn.type = "button";
|
|
774
|
-
removeBtn.onclick = () => {
|
|
775
|
-
const currentButtons = this.tab.yasgui.persistentConfig.getCustomEndpointButtons();
|
|
776
|
-
currentButtons.splice(index, 1);
|
|
777
|
-
this.tab.yasgui.persistentConfig.setCustomEndpointButtons(currentButtons);
|
|
778
|
-
this.renderEndpointButtonsList(container);
|
|
779
|
-
};
|
|
780
|
-
|
|
781
|
-
item.appendChild(labelSpan);
|
|
782
|
-
item.appendChild(endpointSpan);
|
|
783
|
-
item.appendChild(removeBtn);
|
|
784
|
-
container.appendChild(item);
|
|
785
|
-
});
|
|
786
|
-
}
|
|
1050
|
+
// Old endpoint buttons functionality has been merged into drawEndpointsSettings
|
|
1051
|
+
// Keeping this for reference if needed for backwards compatibility
|
|
787
1052
|
|
|
788
1053
|
private getThemeToggleIcon(): string {
|
|
789
1054
|
const currentTheme = this.tab.yasgui.getTheme();
|
package/src/index.ts
CHANGED
|
@@ -35,6 +35,17 @@ export interface EndpointButton {
|
|
|
35
35
|
endpoint: string;
|
|
36
36
|
label: string;
|
|
37
37
|
}
|
|
38
|
+
|
|
39
|
+
export interface EndpointConfig {
|
|
40
|
+
endpoint: string;
|
|
41
|
+
label?: string; // Optional label for the endpoint
|
|
42
|
+
showAsButton?: boolean; // Whether to show as a quick-switch button (requires label)
|
|
43
|
+
authentication?: {
|
|
44
|
+
type: 'basic'; // For now only basic, but designed for future auth types
|
|
45
|
+
username: string;
|
|
46
|
+
password: string;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
38
49
|
export interface Config<EndpointObject extends CatalogueItem = CatalogueItem> {
|
|
39
50
|
/**
|
|
40
51
|
* Autofocus yasqe on load or tab switch
|