Skip to content

Commit 400562a

Browse files
committed
fix: returned the possibility to add arbitrary headers to the sparql request (fixes #114)
1 parent 726ba23 commit 400562a

File tree

2 files changed

+151
-0
lines changed

2 files changed

+151
-0
lines changed

packages/yasgui/src/TabSettingsModal.scss

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,63 @@
290290
}
291291
}
292292

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+
293350
.prefixTextarea {
294351
width: 100%;
295352
padding: 10px;

packages/yasgui/src/TabSettingsModal.ts

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ const AcceptHeaderGraphMap: { key: string; value: string }[] = [
2424
{ key: "TSV", value: "text/tab-separated-values,*/*;q=0.9" },
2525
];
2626

27+
// Type for key-value pairs (headers, args, etc.)
28+
type KeyValuePair = { name: string; value: string };
29+
2730
// Default API Key header name
2831
const DEFAULT_API_KEY_HEADER = "X-API-Key";
2932

@@ -1380,6 +1383,81 @@ export default class TabSettingsModal {
13801383
acceptGraphSelect.setAttribute("data-config", "acceptHeaderGraph");
13811384
acceptGraphSection.appendChild(acceptGraphSelect);
13821385
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);
13831461
}
13841462

13851463
private createSection(title: string): HTMLElement {
@@ -1546,6 +1624,22 @@ export default class TabSettingsModal {
15461624
updates[config] = (select as HTMLSelectElement).value;
15471625
}
15481626
});
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+
15491643
this.tab.setRequestConfig(updates);
15501644
}
15511645

0 commit comments

Comments
 (0)