@matdata/yasgui 5.12.0 → 5.13.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.
Files changed (40) hide show
  1. package/build/ts/src/TabSettingsModal.js +3 -5
  2. package/build/ts/src/TabSettingsModal.js.map +1 -1
  3. package/build/ts/src/ThemeManager.js +2 -2
  4. package/build/ts/src/ThemeManager.js.map +1 -1
  5. package/build/ts/src/queryManagement/QueryBrowser.js +27 -6
  6. package/build/ts/src/queryManagement/QueryBrowser.js.map +1 -1
  7. package/build/ts/src/queryManagement/SaveManagedQueryModal.js +3 -3
  8. package/build/ts/src/queryManagement/SaveManagedQueryModal.js.map +1 -1
  9. package/build/ts/src/queryManagement/backends/BitbucketProviderClient.js +2 -2
  10. package/build/ts/src/queryManagement/backends/BitbucketProviderClient.js.map +1 -1
  11. package/build/ts/src/queryManagement/backends/GiteaProviderClient.js +2 -2
  12. package/build/ts/src/queryManagement/backends/GiteaProviderClient.js.map +1 -1
  13. package/build/ts/src/queryManagement/backends/GithubProviderClient.js +2 -2
  14. package/build/ts/src/queryManagement/backends/GithubProviderClient.js.map +1 -1
  15. package/build/ts/src/queryManagement/backends/GitlabProviderClient.js +2 -2
  16. package/build/ts/src/queryManagement/backends/GitlabProviderClient.js.map +1 -1
  17. package/build/ts/src/queryManagement/backends/InMemoryWorkspaceBackend.js +4 -4
  18. package/build/ts/src/queryManagement/backends/InMemoryWorkspaceBackend.js.map +1 -1
  19. package/build/ts/src/queryManagement/normalizeQueryFilename.js +2 -2
  20. package/build/ts/src/queryManagement/normalizeQueryFilename.js.map +1 -1
  21. package/build/ts/src/version.d.ts +1 -1
  22. package/build/ts/src/version.js +1 -1
  23. package/build/yasgui.min.css +1 -1
  24. package/build/yasgui.min.css.map +3 -3
  25. package/build/yasgui.min.js +165 -165
  26. package/build/yasgui.min.js.map +3 -3
  27. package/package.json +1 -1
  28. package/src/TabSettingsModal.scss +12 -0
  29. package/src/TabSettingsModal.ts +3 -5
  30. package/src/ThemeManager.ts +2 -2
  31. package/src/github-dark-theme.scss +31 -6
  32. package/src/queryManagement/QueryBrowser.ts +34 -7
  33. package/src/queryManagement/SaveManagedQueryModal.ts +3 -3
  34. package/src/queryManagement/backends/BitbucketProviderClient.ts +2 -2
  35. package/src/queryManagement/backends/GiteaProviderClient.ts +2 -2
  36. package/src/queryManagement/backends/GithubProviderClient.ts +2 -2
  37. package/src/queryManagement/backends/GitlabProviderClient.ts +2 -2
  38. package/src/queryManagement/backends/InMemoryWorkspaceBackend.ts +4 -4
  39. package/src/queryManagement/normalizeQueryFilename.ts +4 -2
  40. package/src/version.ts +1 -1
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.12.0",
4
+ "version": "5.13.0",
5
5
  "main": "build/yasgui.min.js",
6
6
  "types": "build/ts/src/index.d.ts",
7
7
  "license": "MIT",
@@ -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
  }
@@ -452,7 +452,7 @@ export default class TabSettingsModal {
452
452
  });
453
453
 
454
454
  const storedDarkTheme = this.tab.yasgui.persistentConfig.getCodeMirrorTheme("dark");
455
- themeDarkSelect.value = storedDarkTheme || "material-palenight";
455
+ themeDarkSelect.value = storedDarkTheme || "github-dark";
456
456
 
457
457
  themeDarkSection.appendChild(themeDarkLabel);
458
458
  themeDarkSection.appendChild(themeDarkHelp);
@@ -468,9 +468,7 @@ export default class TabSettingsModal {
468
468
  themeReferenceLink.target = "_blank";
469
469
  themeReferenceLink.rel = "noopener noreferrer";
470
470
  themeReferenceLink.textContent = "Preview CodeMirror themes →";
471
- themeReferenceLink.style.display = "inline-block";
472
- themeReferenceLink.style.marginTop = "5px";
473
- themeReferenceLink.style.fontSize = "13px";
471
+ addClass(themeReferenceLink, "settingsLink");
474
472
 
475
473
  themeReferenceSection.appendChild(themeReferenceLink);
476
474
  container.appendChild(themeReferenceSection);
@@ -1493,7 +1491,7 @@ export default class TabSettingsModal {
1493
1491
  const currentMode = this.tab.yasgui.getTheme();
1494
1492
  const themeToApply =
1495
1493
  currentMode === "dark"
1496
- ? codeMirrorThemeDarkSelect?.value || "material-palenight"
1494
+ ? codeMirrorThemeDarkSelect?.value || "github-dark"
1497
1495
  : codeMirrorThemeLightSelect?.value || "default";
1498
1496
 
1499
1497
  // Apply theme to all CodeMirror instances
@@ -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" ? "material-palenight" : "default");
77
+ cmTheme = storedTheme || (theme === "dark" ? "github-dark" : "default");
78
78
  } else {
79
79
  // Fallback if persistentConfig not yet available
80
- cmTheme = theme === "dark" ? "material-palenight" : "default";
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: #79c0ff; // Variables (?var, $var)
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: #ffa657; // Prefixed names (rdf:type, foaf:name)
73
+ color: #5784ff; // Prefix namespace (rdf:, foaf:)
74
74
  }
75
75
 
76
76
  .cm-s-github-dark span.cm-variable-3 {
77
- color: #d2a8ff; // URIs in angle brackets
77
+ color: #1b9b8e; // URIs in angle brackets
78
78
  }
79
79
 
80
80
  .cm-s-github-dark span.cm-number {
81
- color: #79c0ff; // Numbers
81
+ color: #4faaf9; // Numbers
82
82
  }
83
83
 
84
84
  .cm-s-github-dark span.cm-comment {
85
- color: #8b949e; // Comments
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, 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.message || "Failed to load folder");
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
- return message;
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
- return `${key}:${loading}:${err}:${entryPart}`;
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}.sparql` : `${trimmed}.sparql`;
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
- if (lower.endsWith(".sparql")) return name;
7
- return `${name}.sparql`;
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
@@ -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.12.0";
3
+ export const VERSION = "5.13.0";