@matdata/yasgui 5.12.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/build/ts/src/TabSettingsModal.d.ts +1 -0
- package/build/ts/src/TabSettingsModal.js +70 -5
- package/build/ts/src/TabSettingsModal.js.map +1 -1
- package/build/ts/src/ThemeManager.js +2 -2
- package/build/ts/src/ThemeManager.js.map +1 -1
- package/build/ts/src/queryManagement/QueryBrowser.js +27 -6
- package/build/ts/src/queryManagement/QueryBrowser.js.map +1 -1
- package/build/ts/src/queryManagement/SaveManagedQueryModal.js +3 -3
- package/build/ts/src/queryManagement/SaveManagedQueryModal.js.map +1 -1
- package/build/ts/src/queryManagement/backends/BitbucketProviderClient.js +2 -2
- package/build/ts/src/queryManagement/backends/BitbucketProviderClient.js.map +1 -1
- package/build/ts/src/queryManagement/backends/GiteaProviderClient.js +2 -2
- package/build/ts/src/queryManagement/backends/GiteaProviderClient.js.map +1 -1
- package/build/ts/src/queryManagement/backends/GithubProviderClient.js +2 -2
- package/build/ts/src/queryManagement/backends/GithubProviderClient.js.map +1 -1
- package/build/ts/src/queryManagement/backends/GitlabProviderClient.js +2 -2
- package/build/ts/src/queryManagement/backends/GitlabProviderClient.js.map +1 -1
- package/build/ts/src/queryManagement/backends/InMemoryWorkspaceBackend.js +4 -4
- package/build/ts/src/queryManagement/backends/InMemoryWorkspaceBackend.js.map +1 -1
- package/build/ts/src/queryManagement/normalizeQueryFilename.js +2 -2
- package/build/ts/src/queryManagement/normalizeQueryFilename.js.map +1 -1
- package/build/ts/src/version.d.ts +1 -1
- package/build/ts/src/version.js +1 -1
- package/build/yasgui.min.css +1 -1
- package/build/yasgui.min.css.map +3 -3
- package/build/yasgui.min.js +167 -167
- package/build/yasgui.min.js.map +3 -3
- package/package.json +1 -1
- package/src/TabSettingsModal.scss +69 -0
- package/src/TabSettingsModal.ts +97 -5
- package/src/ThemeManager.ts +2 -2
- package/src/github-dark-theme.scss +31 -6
- package/src/queryManagement/QueryBrowser.ts +34 -7
- package/src/queryManagement/SaveManagedQueryModal.ts +3 -3
- package/src/queryManagement/backends/BitbucketProviderClient.ts +2 -2
- package/src/queryManagement/backends/GiteaProviderClient.ts +2 -2
- package/src/queryManagement/backends/GithubProviderClient.ts +2 -2
- package/src/queryManagement/backends/GitlabProviderClient.ts +2 -2
- package/src/queryManagement/backends/InMemoryWorkspaceBackend.ts +4 -4
- package/src/queryManagement/normalizeQueryFilename.ts +4 -2
- package/src/version.ts +1 -1
package/package.json
CHANGED
|
@@ -160,6 +160,18 @@
|
|
|
160
160
|
font-style: italic;
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
+
.settingsLink {
|
|
164
|
+
display: inline-block;
|
|
165
|
+
margin-top: 5px;
|
|
166
|
+
font-size: 13px;
|
|
167
|
+
color: var(--yasgui-accent-color, #337ab7);
|
|
168
|
+
text-decoration: none;
|
|
169
|
+
|
|
170
|
+
&:hover {
|
|
171
|
+
text-decoration: underline;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
163
175
|
.settingsField {
|
|
164
176
|
margin-bottom: 10px;
|
|
165
177
|
}
|
|
@@ -278,6 +290,63 @@
|
|
|
278
290
|
}
|
|
279
291
|
}
|
|
280
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
|
+
|
|
281
350
|
.prefixTextarea {
|
|
282
351
|
width: 100%;
|
|
283
352
|
padding: 10px;
|
package/src/TabSettingsModal.ts
CHANGED
|
@@ -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
|
|
|
@@ -452,7 +455,7 @@ export default class TabSettingsModal {
|
|
|
452
455
|
});
|
|
453
456
|
|
|
454
457
|
const storedDarkTheme = this.tab.yasgui.persistentConfig.getCodeMirrorTheme("dark");
|
|
455
|
-
themeDarkSelect.value = storedDarkTheme || "
|
|
458
|
+
themeDarkSelect.value = storedDarkTheme || "github-dark";
|
|
456
459
|
|
|
457
460
|
themeDarkSection.appendChild(themeDarkLabel);
|
|
458
461
|
themeDarkSection.appendChild(themeDarkHelp);
|
|
@@ -468,9 +471,7 @@ export default class TabSettingsModal {
|
|
|
468
471
|
themeReferenceLink.target = "_blank";
|
|
469
472
|
themeReferenceLink.rel = "noopener noreferrer";
|
|
470
473
|
themeReferenceLink.textContent = "Preview CodeMirror themes →";
|
|
471
|
-
themeReferenceLink
|
|
472
|
-
themeReferenceLink.style.marginTop = "5px";
|
|
473
|
-
themeReferenceLink.style.fontSize = "13px";
|
|
474
|
+
addClass(themeReferenceLink, "settingsLink");
|
|
474
475
|
|
|
475
476
|
themeReferenceSection.appendChild(themeReferenceLink);
|
|
476
477
|
container.appendChild(themeReferenceSection);
|
|
@@ -1382,6 +1383,81 @@ export default class TabSettingsModal {
|
|
|
1382
1383
|
acceptGraphSelect.setAttribute("data-config", "acceptHeaderGraph");
|
|
1383
1384
|
acceptGraphSection.appendChild(acceptGraphSelect);
|
|
1384
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);
|
|
1385
1461
|
}
|
|
1386
1462
|
|
|
1387
1463
|
private createSection(title: string): HTMLElement {
|
|
@@ -1493,7 +1569,7 @@ export default class TabSettingsModal {
|
|
|
1493
1569
|
const currentMode = this.tab.yasgui.getTheme();
|
|
1494
1570
|
const themeToApply =
|
|
1495
1571
|
currentMode === "dark"
|
|
1496
|
-
? codeMirrorThemeDarkSelect?.value || "
|
|
1572
|
+
? codeMirrorThemeDarkSelect?.value || "github-dark"
|
|
1497
1573
|
: codeMirrorThemeLightSelect?.value || "default";
|
|
1498
1574
|
|
|
1499
1575
|
// Apply theme to all CodeMirror instances
|
|
@@ -1548,6 +1624,22 @@ export default class TabSettingsModal {
|
|
|
1548
1624
|
updates[config] = (select as HTMLSelectElement).value;
|
|
1549
1625
|
}
|
|
1550
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
|
+
|
|
1551
1643
|
this.tab.setRequestConfig(updates);
|
|
1552
1644
|
}
|
|
1553
1645
|
|
package/src/ThemeManager.ts
CHANGED
|
@@ -74,10 +74,10 @@ export class ThemeManager {
|
|
|
74
74
|
let cmTheme: string;
|
|
75
75
|
if (this.persistentConfig) {
|
|
76
76
|
const storedTheme = this.persistentConfig.getCodeMirrorTheme(theme);
|
|
77
|
-
cmTheme = storedTheme || (theme === "dark" ? "
|
|
77
|
+
cmTheme = storedTheme || (theme === "dark" ? "github-dark" : "default");
|
|
78
78
|
} else {
|
|
79
79
|
// Fallback if persistentConfig not yet available
|
|
80
|
-
cmTheme = theme === "dark" ? "
|
|
80
|
+
cmTheme = theme === "dark" ? "github-dark" : "default";
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
// Find all CodeMirror instances within the root element
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
.cm-s-github-dark span.cm-atom {
|
|
65
|
-
color: #
|
|
65
|
+
color: #f3f9ff; // Variables (?var, $var)
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
.cm-s-github-dark span.cm-string {
|
|
@@ -70,19 +70,19 @@
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
.cm-s-github-dark span.cm-string-2 {
|
|
73
|
-
color: #
|
|
73
|
+
color: #5784ff; // Prefix namespace (rdf:, foaf:)
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
.cm-s-github-dark span.cm-variable-3 {
|
|
77
|
-
color: #
|
|
77
|
+
color: #1b9b8e; // URIs in angle brackets
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
.cm-s-github-dark span.cm-number {
|
|
81
|
-
color: #
|
|
81
|
+
color: #4faaf9; // Numbers
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
.cm-s-github-dark span.cm-comment {
|
|
85
|
-
color: #
|
|
85
|
+
color: #696e74; // Comments
|
|
86
86
|
font-style: italic;
|
|
87
87
|
}
|
|
88
88
|
|
|
@@ -127,7 +127,32 @@
|
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
.cm-s-github-dark span.cm-bracket {
|
|
130
|
-
color: #c9d1d9; // Brackets
|
|
130
|
+
color: #c9d1d9; // Brackets (fallback)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Rainbow bracket colors
|
|
134
|
+
.cm-s-github-dark span.cm-bracket-level-0 {
|
|
135
|
+
color: #ffd700; // Gold
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.cm-s-github-dark span.cm-bracket-level-1 {
|
|
139
|
+
color: #d2a8ff; // Purple
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.cm-s-github-dark span.cm-bracket-level-2 {
|
|
143
|
+
color: #d85896; // Blue
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.cm-s-github-dark span.cm-bracket-level-3 {
|
|
147
|
+
color: #229922; // Green
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.cm-s-github-dark span.cm-bracket-paren {
|
|
151
|
+
color: #c9d1d9; // Constant color for () and []
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.cm-s-github-dark span.cm-bracket-mismatch {
|
|
155
|
+
color: #ff7b72; // Red for mismatched brackets
|
|
131
156
|
}
|
|
132
157
|
|
|
133
158
|
.cm-s-github-dark span.cm-error {
|
|
@@ -3,7 +3,7 @@ import { addClass, removeClass } from "@matdata/yasgui-utils";
|
|
|
3
3
|
import type { WorkspaceConfig, FolderEntry } from "./types";
|
|
4
4
|
import { filterFolderEntriesByName } from "./browserFilter";
|
|
5
5
|
import { getWorkspaceBackend } from "./backends/getWorkspaceBackend";
|
|
6
|
-
import { asWorkspaceBackendError } from "./backends/errors";
|
|
6
|
+
import { asWorkspaceBackendError, isWorkspaceBackendError, WorkspaceBackendError } from "./backends/errors";
|
|
7
7
|
import { getEndpointToAutoSwitch } from "./openManagedQuery";
|
|
8
8
|
import { hashQueryText } from "./textHash";
|
|
9
9
|
import type { BackendType, VersionRef, ManagedTabMetadata } from "./types";
|
|
@@ -36,7 +36,7 @@ export default class QueryBrowser {
|
|
|
36
36
|
private expandedFolderIds = new Set<string>();
|
|
37
37
|
private folderEntriesById = new Map<string, FolderEntry[]>();
|
|
38
38
|
private folderLoadingById = new Set<string>();
|
|
39
|
-
private folderErrorById = new Map<string,
|
|
39
|
+
private folderErrorById = new Map<string, WorkspaceBackendError>();
|
|
40
40
|
|
|
41
41
|
private debouncedSearchHandle?: number;
|
|
42
42
|
|
|
@@ -315,7 +315,7 @@ export default class QueryBrowser {
|
|
|
315
315
|
this.folderEntriesById.set(key, entries);
|
|
316
316
|
} catch (e) {
|
|
317
317
|
const err = asWorkspaceBackendError(e);
|
|
318
|
-
this.folderErrorById.set(key, err
|
|
318
|
+
this.folderErrorById.set(key, err);
|
|
319
319
|
this.folderEntriesById.set(key, []);
|
|
320
320
|
} finally {
|
|
321
321
|
this.folderLoadingById.delete(key);
|
|
@@ -325,6 +325,22 @@ export default class QueryBrowser {
|
|
|
325
325
|
private formatStatusError(err: Error, workspaceType: WorkspaceConfig["type"]) {
|
|
326
326
|
const message = err.message || "Unknown error";
|
|
327
327
|
|
|
328
|
+
// Check for authentication/authorization errors
|
|
329
|
+
if (isWorkspaceBackendError(err)) {
|
|
330
|
+
if (err.code === "AUTH_FAILED") {
|
|
331
|
+
return `⚠️ Authentication failed. Please check your workspace configuration and credentials in Settings → Workspaces.`;
|
|
332
|
+
}
|
|
333
|
+
if (err.code === "FORBIDDEN") {
|
|
334
|
+
return `⚠️ Access forbidden. Please verify your ${workspaceType === "git" ? "token permissions" : "endpoint authentication"} in Settings → Workspaces.`;
|
|
335
|
+
}
|
|
336
|
+
if (err.code === "NETWORK_ERROR") {
|
|
337
|
+
return `⚠️ Unable to connect to workspace. Please check your workspace configuration and network connection.`;
|
|
338
|
+
}
|
|
339
|
+
if (err.code === "NOT_FOUND") {
|
|
340
|
+
return `⚠️ Workspace not found. Please verify your workspace configuration in Settings → Workspaces.`;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
328
344
|
if (message.includes("No GitProviderClient configured")) {
|
|
329
345
|
return "Git workspaces require a supported provider. Supported: GitHub, GitLab, Bitbucket Cloud (bitbucket.org), and Gitea. For self-hosted/enterprise instances, configure a git workspace 'provider' and/or 'apiBaseUrl'.";
|
|
330
346
|
}
|
|
@@ -333,7 +349,8 @@ export default class QueryBrowser {
|
|
|
333
349
|
return "This workspace backend is not supported yet.";
|
|
334
350
|
}
|
|
335
351
|
|
|
336
|
-
|
|
352
|
+
// Generic error with helpful suggestion
|
|
353
|
+
return `⚠️ Failed to load workspace: ${message}. Please check your workspace configuration and authentication in Settings → Workspaces.`;
|
|
337
354
|
}
|
|
338
355
|
|
|
339
356
|
private clearList() {
|
|
@@ -923,7 +940,7 @@ export default class QueryBrowser {
|
|
|
923
940
|
addClass(error, "yasgui-query-browser__tree-meta");
|
|
924
941
|
addClass(error, "yasgui-query-browser__tree-meta--error");
|
|
925
942
|
error.setAttribute("style", makeIndentStyle(depth + 1));
|
|
926
|
-
error.textContent = err;
|
|
943
|
+
error.textContent = this.formatStatusError(err, backend.type);
|
|
927
944
|
this.listEl.appendChild(error);
|
|
928
945
|
}
|
|
929
946
|
|
|
@@ -1041,6 +1058,15 @@ export default class QueryBrowser {
|
|
|
1041
1058
|
if (runId !== this.refreshRunId) return;
|
|
1042
1059
|
|
|
1043
1060
|
const rootKey = this.folderKey(undefined);
|
|
1061
|
+
|
|
1062
|
+
// Check if root folder failed to load
|
|
1063
|
+
const rootError = this.folderErrorById.get(rootKey);
|
|
1064
|
+
if (rootError) {
|
|
1065
|
+
this.setStatus(this.formatStatusError(rootError, workspace.type));
|
|
1066
|
+
this.clearList();
|
|
1067
|
+
return;
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1044
1070
|
const rootEntries = this.folderEntriesById.get(rootKey) || [];
|
|
1045
1071
|
|
|
1046
1072
|
const expandedIds = Array.from(this.expandedFolderIds).sort();
|
|
@@ -1053,8 +1079,9 @@ export default class QueryBrowser {
|
|
|
1053
1079
|
.sort()
|
|
1054
1080
|
.join("|");
|
|
1055
1081
|
const loading = this.folderLoadingById.has(key) ? "1" : "0";
|
|
1056
|
-
const err = this.folderErrorById.get(key)
|
|
1057
|
-
|
|
1082
|
+
const err = this.folderErrorById.get(key);
|
|
1083
|
+
const errStr = err ? `${err.code}:${err.message}` : "";
|
|
1084
|
+
return `${key}:${loading}:${errStr}:${entryPart}`;
|
|
1058
1085
|
})
|
|
1059
1086
|
.join(";");
|
|
1060
1087
|
|
|
@@ -185,7 +185,7 @@ export default class SaveManagedQueryModal {
|
|
|
185
185
|
this.nameEl.addEventListener("input", () => {
|
|
186
186
|
if (this.filenameTouched) return;
|
|
187
187
|
const suggested = this.suggestFilenameFromName(this.nameEl.value);
|
|
188
|
-
if (suggested) this.filenameEl.value = suggested.replace(/\.sparql$/i, "");
|
|
188
|
+
if (suggested) this.filenameEl.value = suggested.replace(/\.(rq|sparql)$/i, "");
|
|
189
189
|
});
|
|
190
190
|
|
|
191
191
|
this.filenameEl = document.createElement("input");
|
|
@@ -373,7 +373,7 @@ export default class SaveManagedQueryModal {
|
|
|
373
373
|
let resolvedFilename = filename;
|
|
374
374
|
|
|
375
375
|
if (isGit) {
|
|
376
|
-
resolvedFilename = resolvedFilename.replace(/\.sparql$/i, "");
|
|
376
|
+
resolvedFilename = resolvedFilename.replace(/\.(rq|sparql)$/i, "");
|
|
377
377
|
if (!resolvedFilename) {
|
|
378
378
|
window.alert("Please enter a filename");
|
|
379
379
|
return;
|
|
@@ -446,7 +446,7 @@ export default class SaveManagedQueryModal {
|
|
|
446
446
|
|
|
447
447
|
const defaultFilename =
|
|
448
448
|
defaults?.filename ?? (defaultName ? (this.suggestFilenameFromName(defaultName) ?? "") : "");
|
|
449
|
-
this.filenameEl.value = defaultFilename.replace(/\.sparql$/i, "");
|
|
449
|
+
this.filenameEl.value = defaultFilename.replace(/\.(rq|sparql)$/i, "");
|
|
450
450
|
this.messageEl.value = defaults?.message ?? "";
|
|
451
451
|
|
|
452
452
|
this.folderPickerOpen = false;
|
|
@@ -217,9 +217,9 @@ export class BitbucketProviderClient extends BaseGitProviderClient {
|
|
|
217
217
|
}
|
|
218
218
|
|
|
219
219
|
if (v.type === "commit_file") {
|
|
220
|
-
if (!/\.sparql$/i.test(name)) continue;
|
|
220
|
+
if (!/\.(rq|sparql)$/i.test(name)) continue;
|
|
221
221
|
const id = relPath ? this.joinPath(relPath, name) : name;
|
|
222
|
-
const label = name.replace(/\.sparql$/i, "");
|
|
222
|
+
const label = name.replace(/\.(rq|sparql)$/i, "");
|
|
223
223
|
entries.push({ kind: "query", id, label, parentId: relPath || undefined });
|
|
224
224
|
}
|
|
225
225
|
}
|
|
@@ -137,9 +137,9 @@ export class GiteaProviderClient extends BaseGitProviderClient {
|
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
if (item.type === "file") {
|
|
140
|
-
if (!/\.sparql$/i.test(item.name)) continue;
|
|
140
|
+
if (!/\.(rq|sparql)$/i.test(item.name)) continue;
|
|
141
141
|
const id = relPath ? this.joinPath(relPath, item.name) : item.name;
|
|
142
|
-
const label = item.name.replace(/\.sparql$/i, "");
|
|
142
|
+
const label = item.name.replace(/\.(rq|sparql)$/i, "");
|
|
143
143
|
entries.push({ kind: "query", id, label, parentId: relPath || undefined });
|
|
144
144
|
}
|
|
145
145
|
}
|
|
@@ -148,11 +148,11 @@ export class GithubProviderClient extends BaseGitProviderClient {
|
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
if (item.type === "file") {
|
|
151
|
-
if (!/\.sparql$/i.test(item.name)) continue;
|
|
151
|
+
if (!/\.(rq|sparql)$/i.test(item.name)) continue;
|
|
152
152
|
const id = config.rootPath
|
|
153
153
|
? item.path.slice(this.joinPath(config.rootPath).length).replace(/^\//, "")
|
|
154
154
|
: item.path;
|
|
155
|
-
const label = item.name.replace(/\.sparql$/i, "");
|
|
155
|
+
const label = item.name.replace(/\.(rq|sparql)$/i, "");
|
|
156
156
|
entries.push({ kind: "query", id, label, parentId: relPath || undefined });
|
|
157
157
|
}
|
|
158
158
|
}
|
|
@@ -160,9 +160,9 @@ export class GitlabProviderClient extends BaseGitProviderClient {
|
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
if (item.type === "blob") {
|
|
163
|
-
if (!/\.sparql$/i.test(item.name)) continue;
|
|
163
|
+
if (!/\.(rq|sparql)$/i.test(item.name)) continue;
|
|
164
164
|
const id = relPath ? this.joinPath(relPath, item.name) : item.name;
|
|
165
|
-
const label = item.name.replace(/\.sparql$/i, "");
|
|
165
|
+
const label = item.name.replace(/\.(rq|sparql)$/i, "");
|
|
166
166
|
entries.push({ kind: "query", id, label, parentId: relPath || undefined });
|
|
167
167
|
}
|
|
168
168
|
}
|
|
@@ -65,7 +65,7 @@ export default class InMemoryWorkspaceBackend implements WorkspaceBackend {
|
|
|
65
65
|
queries.push({
|
|
66
66
|
kind: "query",
|
|
67
67
|
id: queryId,
|
|
68
|
-
label: basename(queryId).replace(/\.sparql$/i, ""),
|
|
68
|
+
label: basename(queryId).replace(/\.(rq|sparql)$/i, ""),
|
|
69
69
|
parentId: undefined,
|
|
70
70
|
});
|
|
71
71
|
continue;
|
|
@@ -75,7 +75,7 @@ export default class InMemoryWorkspaceBackend implements WorkspaceBackend {
|
|
|
75
75
|
queries.push({
|
|
76
76
|
kind: "query",
|
|
77
77
|
id: queryId,
|
|
78
|
-
label: basename(queryId).replace(/\.sparql$/i, ""),
|
|
78
|
+
label: basename(queryId).replace(/\.(rq|sparql)$/i, ""),
|
|
79
79
|
parentId: folder,
|
|
80
80
|
});
|
|
81
81
|
continue;
|
|
@@ -101,7 +101,7 @@ export default class InMemoryWorkspaceBackend implements WorkspaceBackend {
|
|
|
101
101
|
if (!q) return [];
|
|
102
102
|
const hits: FolderEntry[] = [];
|
|
103
103
|
for (const queryId of this.versionsByQueryId.keys()) {
|
|
104
|
-
const label = basename(queryId).replace(/\.sparql$/i, "");
|
|
104
|
+
const label = basename(queryId).replace(/\.(rq|sparql)$/i, "");
|
|
105
105
|
if (label.toLowerCase().includes(q)) {
|
|
106
106
|
hits.push({ kind: "query", id: queryId, label, parentId: dirname(queryId) || undefined });
|
|
107
107
|
}
|
|
@@ -159,7 +159,7 @@ export default class InMemoryWorkspaceBackend implements WorkspaceBackend {
|
|
|
159
159
|
const versions = this.versionsByQueryId.get(queryId);
|
|
160
160
|
if (!versions || versions.length === 0) throw new WorkspaceBackendError("NOT_FOUND", "Query not found");
|
|
161
161
|
|
|
162
|
-
const newId = dirname(queryId) ? `${dirname(queryId)}/${trimmed}.
|
|
162
|
+
const newId = dirname(queryId) ? `${dirname(queryId)}/${trimmed}.rq` : `${trimmed}.rq`;
|
|
163
163
|
if (newId === queryId) return;
|
|
164
164
|
if (this.versionsByQueryId.has(newId))
|
|
165
165
|
throw new WorkspaceBackendError("CONFLICT", "A query with this name already exists");
|
|
@@ -3,6 +3,8 @@ export function normalizeQueryFilename(rawName: string): string {
|
|
|
3
3
|
if (!name) throw new Error("Filename is required");
|
|
4
4
|
|
|
5
5
|
const lower = name.toLowerCase();
|
|
6
|
-
|
|
7
|
-
return
|
|
6
|
+
// Accept both .rq and .sparql extensions for backwards compatibility
|
|
7
|
+
if (lower.endsWith(".rq") || lower.endsWith(".sparql")) return name;
|
|
8
|
+
// Default to .rq for new files
|
|
9
|
+
return `${name}.rq`;
|
|
8
10
|
}
|
package/src/version.ts
CHANGED