@matdata/yasgui 5.13.0 → 5.14.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@matdata/yasgui",
3
3
  "description": "Yet Another SPARQL GUI",
4
- "version": "5.13.0",
4
+ "version": "5.14.0",
5
5
  "main": "build/yasgui.min.js",
6
6
  "types": "build/ts/src/index.d.ts",
7
7
  "license": "MIT",
@@ -290,6 +290,63 @@
290
290
  }
291
291
  }
292
292
 
293
+ .keyValueContainer {
294
+ display: flex;
295
+ flex-direction: column;
296
+ gap: 8px;
297
+ }
298
+
299
+ .keyValueRow {
300
+ display: grid;
301
+ grid-template-columns: 1fr 1fr auto;
302
+ gap: 8px;
303
+ align-items: center;
304
+
305
+ .keyInput,
306
+ .valueInput {
307
+ padding: 8px;
308
+ border: 1px solid var(--yasgui-input-border, #ccc);
309
+ border-radius: 4px;
310
+ font-size: 14px;
311
+ background-color: var(--yasgui-bg-secondary, white);
312
+ color: var(--yasgui-text-primary, #000);
313
+
314
+ &:focus {
315
+ outline: none;
316
+ border-color: var(--yasgui-input-focus, #337ab7);
317
+ box-shadow: 0 0 0 2px rgba(51, 122, 183, 0.1);
318
+ }
319
+
320
+ &::placeholder {
321
+ color: var(--yasgui-text-secondary, #999);
322
+ }
323
+ }
324
+
325
+ .removeButton {
326
+ padding: 6px 10px;
327
+ background-color: var(--yasgui-danger-color, #d9534f);
328
+ color: white;
329
+ border: none;
330
+ border-radius: 4px;
331
+ cursor: pointer;
332
+ font-size: 14px;
333
+ transition: background-color 0.2s;
334
+
335
+ &:hover {
336
+ background-color: var(--yasgui-danger-hover, #c9302c);
337
+ }
338
+
339
+ &:focus {
340
+ outline: none;
341
+ box-shadow: 0 0 0 2px rgba(217, 83, 79, 0.3);
342
+ }
343
+
344
+ i {
345
+ pointer-events: none;
346
+ }
347
+ }
348
+ }
349
+
293
350
  .prefixTextarea {
294
351
  width: 100%;
295
352
  padding: 10px;
@@ -24,6 +24,9 @@ const AcceptHeaderGraphMap: { key: string; value: string }[] = [
24
24
  { key: "TSV", value: "text/tab-separated-values,*/*;q=0.9" },
25
25
  ];
26
26
 
27
+ // Type for key-value pairs (headers, args, etc.)
28
+ type KeyValuePair = { name: string; value: string };
29
+
27
30
  // Default API Key header name
28
31
  const DEFAULT_API_KEY_HEADER = "X-API-Key";
29
32
 
@@ -1380,6 +1383,81 @@ export default class TabSettingsModal {
1380
1383
  acceptGraphSelect.setAttribute("data-config", "acceptHeaderGraph");
1381
1384
  acceptGraphSection.appendChild(acceptGraphSelect);
1382
1385
  container.appendChild(acceptGraphSection);
1386
+
1387
+ // Custom Headers section
1388
+ const headersSection = this.createSection("Custom HTTP Headers");
1389
+ const headersContainer = document.createElement("div");
1390
+ addClass(headersContainer, "keyValueContainer");
1391
+ headersContainer.setAttribute("data-config", "headers");
1392
+
1393
+ // Get existing headers
1394
+ const existingHeaders = typeof reqConfig.headers === "function" ? {} : reqConfig.headers || {};
1395
+ const headerPairs: KeyValuePair[] = Object.entries(existingHeaders).map(([name, value]) => ({
1396
+ name,
1397
+ value,
1398
+ }));
1399
+
1400
+ // Draw existing headers
1401
+ headerPairs.forEach((pair, index) => {
1402
+ this.createKeyValueRow(headersContainer, pair, index);
1403
+ });
1404
+
1405
+ // Add empty row for adding new headers
1406
+ this.createKeyValueRow(headersContainer, { name: "", value: "" }, headerPairs.length);
1407
+
1408
+ headersSection.appendChild(headersContainer);
1409
+ container.appendChild(headersSection);
1410
+ }
1411
+
1412
+ private createKeyValueRow(container: HTMLElement, pair: KeyValuePair, index: number) {
1413
+ const row = document.createElement("div");
1414
+ addClass(row, "keyValueRow");
1415
+
1416
+ const nameInput = document.createElement("input");
1417
+ nameInput.type = "text";
1418
+ nameInput.placeholder = "Header Name";
1419
+ nameInput.value = pair.name;
1420
+ addClass(nameInput, "keyInput");
1421
+
1422
+ const valueInput = document.createElement("input");
1423
+ valueInput.type = "text";
1424
+ valueInput.placeholder = "Header Value";
1425
+ valueInput.value = pair.value;
1426
+ addClass(valueInput, "valueInput");
1427
+
1428
+ const removeButton = document.createElement("button");
1429
+ removeButton.type = "button";
1430
+ removeButton.innerHTML = '<i class="fas fa-times"></i>';
1431
+ removeButton.title = "Remove header";
1432
+ addClass(removeButton, "removeButton");
1433
+
1434
+ // Auto-add new empty row when typing in the last row
1435
+ const onInput = () => {
1436
+ const allRows = container.querySelectorAll(".keyValueRow");
1437
+ const isLastRow = row === allRows[allRows.length - 1];
1438
+
1439
+ if (isLastRow && (nameInput.value.trim() || valueInput.value.trim())) {
1440
+ // Add a new empty row
1441
+ this.createKeyValueRow(container, { name: "", value: "" }, allRows.length);
1442
+ }
1443
+ };
1444
+
1445
+ nameInput.addEventListener("input", onInput);
1446
+ valueInput.addEventListener("input", onInput);
1447
+
1448
+ removeButton.onclick = () => {
1449
+ row.remove();
1450
+ // Ensure there's always at least one empty row
1451
+ const remainingRows = container.querySelectorAll(".keyValueRow");
1452
+ if (remainingRows.length === 0) {
1453
+ this.createKeyValueRow(container, { name: "", value: "" }, 0);
1454
+ }
1455
+ };
1456
+
1457
+ row.appendChild(nameInput);
1458
+ row.appendChild(valueInput);
1459
+ row.appendChild(removeButton);
1460
+ container.appendChild(row);
1383
1461
  }
1384
1462
 
1385
1463
  private createSection(title: string): HTMLElement {
@@ -1546,6 +1624,22 @@ export default class TabSettingsModal {
1546
1624
  updates[config] = (select as HTMLSelectElement).value;
1547
1625
  }
1548
1626
  });
1627
+
1628
+ // Save custom headers
1629
+ const headersContainer = requestContent.querySelector(".keyValueContainer[data-config='headers']");
1630
+ if (headersContainer) {
1631
+ const headers: { [key: string]: string } = {};
1632
+ const rows = headersContainer.querySelectorAll(".keyValueRow");
1633
+ rows.forEach((row) => {
1634
+ const nameInput = row.querySelector(".keyInput") as HTMLInputElement;
1635
+ const valueInput = row.querySelector(".valueInput") as HTMLInputElement;
1636
+ if (nameInput && valueInput && nameInput.value.trim()) {
1637
+ headers[nameInput.value.trim()] = valueInput.value;
1638
+ }
1639
+ });
1640
+ updates.headers = headers;
1641
+ }
1642
+
1549
1643
  this.tab.setRequestConfig(updates);
1550
1644
  }
1551
1645
 
package/src/version.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  // Version information for YASGUI
2
2
  // This file is auto-generated during build - do not edit manually
3
- export const VERSION = "5.13.0";
3
+ export const VERSION = "5.14.0";