Skip to content

Commit de482b4

Browse files
committed
feat: add documentation if now workspaces have been defined
1 parent 75ae1fa commit de482b4

File tree

2 files changed

+181
-5
lines changed

2 files changed

+181
-5
lines changed

packages/yasgui/src/queryManagement/QueryBrowser.scss

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,16 +66,32 @@
6666
gap: 12px;
6767
}
6868

69+
&__header-buttons {
70+
display: flex;
71+
align-items: center;
72+
gap: 4px;
73+
}
74+
75+
&__help,
6976
&__close {
7077
background: none;
7178
border: none;
72-
padding: 6px 8px;
79+
padding: 6px;
7380
color: var(--yasgui-text-secondary, #666);
7481
cursor: pointer;
7582
border-radius: 4px;
83+
display: flex;
84+
align-items: center;
85+
justify-content: center;
86+
87+
svg {
88+
width: 20px;
89+
height: 20px;
90+
}
7691

7792
&:hover {
7893
color: var(--yasgui-text-primary, #000);
94+
background: var(--yasgui-bg-secondary, #f5f5f5);
7995
}
8096
}
8197

@@ -319,6 +335,84 @@
319335
&__tree-meta--error {
320336
color: var(--yasgui-text-secondary, #666);
321337
}
338+
339+
&__empty-state {
340+
display: flex;
341+
flex-direction: column;
342+
align-items: center;
343+
justify-content: center;
344+
padding: 40px 20px;
345+
text-align: center;
346+
gap: 16px;
347+
}
348+
349+
&__empty-icon {
350+
width: 64px;
351+
height: 64px;
352+
color: var(--yasgui-text-secondary, #999);
353+
opacity: 0.6;
354+
355+
svg {
356+
width: 100%;
357+
height: 100%;
358+
}
359+
}
360+
361+
&__empty-title {
362+
margin: 0;
363+
font-size: 18px;
364+
font-weight: 600;
365+
color: var(--yasgui-text-primary, #000);
366+
}
367+
368+
&__empty-description {
369+
margin: 0;
370+
max-width: 360px;
371+
font-size: 14px;
372+
line-height: 1.5;
373+
color: var(--yasgui-text-secondary, #666);
374+
}
375+
376+
&__empty-actions {
377+
display: flex;
378+
flex-direction: column;
379+
align-items: center;
380+
gap: 12px;
381+
margin-top: 8px;
382+
}
383+
384+
&__empty-button {
385+
padding: 10px 20px;
386+
border-radius: 6px;
387+
border: none;
388+
font-size: 14px;
389+
font-weight: 500;
390+
cursor: pointer;
391+
transition: all 0.2s;
392+
393+
&--primary {
394+
background: var(--yasgui-accent-color, #337ab7);
395+
color: white;
396+
397+
&:hover {
398+
background: var(--yasgui-accent-color-hover, #2a6496);
399+
}
400+
401+
&:active {
402+
transform: translateY(1px);
403+
}
404+
}
405+
}
406+
407+
&__empty-link {
408+
font-size: 14px;
409+
color: var(--yasgui-accent-color, #337ab7);
410+
text-decoration: none;
411+
412+
&:hover {
413+
text-decoration: underline;
414+
}
415+
}
322416
}
323417
}
324418
@keyframes queryBrowserActionSpin {

packages/yasgui/src/queryManagement/QueryBrowser.ts

Lines changed: 86 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,13 +140,36 @@ export default class QueryBrowser {
140140
addClass(titleEl, "yasgui-query-browser__title");
141141
titleEl.textContent = "Query Browser";
142142

143+
const headerButtons = document.createElement("div");
144+
addClass(headerButtons, "yasgui-query-browser__header-buttons");
145+
146+
const helpButton = document.createElement("button");
147+
helpButton.type = "button";
148+
addClass(helpButton, "yasgui-query-browser__help");
149+
helpButton.setAttribute("aria-label", "Open documentation");
150+
helpButton.innerHTML = `<svg viewBox="0 0 24 24" fill="currentColor">
151+
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 12.9 13 13.5 13 15h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z"/>
152+
</svg>`;
153+
helpButton.addEventListener("click", () => {
154+
window.open(
155+
"https://yasgui-doc.matdata.eu/docs/user-guide#managed-queries-and-workspaces",
156+
"_blank",
157+
"noopener,noreferrer",
158+
);
159+
});
160+
143161
const closeButton = document.createElement("button");
144162
closeButton.type = "button";
145-
closeButton.textContent = "Close";
146163
addClass(closeButton, "yasgui-query-browser__close");
147164
closeButton.setAttribute("aria-label", "Close query browser");
165+
closeButton.innerHTML = `<svg viewBox="0 0 24 24" fill="currentColor">
166+
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
167+
</svg>`;
148168
closeButton.addEventListener("click", () => this.close());
149169

170+
headerButtons.appendChild(helpButton);
171+
headerButtons.appendChild(closeButton);
172+
150173
const headerControls = document.createElement("div");
151174
addClass(headerControls, "yasgui-query-browser__header-controls");
152175
headerControls.appendChild(this.workspaceSelectEl);
@@ -155,7 +178,7 @@ export default class QueryBrowser {
155178
const headerTop = document.createElement("div");
156179
addClass(headerTop, "yasgui-query-browser__header-top");
157180
headerTop.appendChild(titleEl);
158-
headerTop.appendChild(closeButton);
181+
headerTop.appendChild(headerButtons);
159182

160183
this.headerEl.appendChild(headerTop);
161184
this.headerEl.appendChild(headerControls);
@@ -321,6 +344,64 @@ export default class QueryBrowser {
321344
this.listEl.innerHTML = "";
322345
}
323346

347+
private renderEmptyWorkspaceState() {
348+
const emptyState = document.createElement("div");
349+
addClass(emptyState, "yasgui-query-browser__empty-state");
350+
351+
const icon = document.createElement("div");
352+
addClass(icon, "yasgui-query-browser__empty-icon");
353+
icon.innerHTML = `<svg viewBox="0 0 24 24" fill="currentColor">
354+
<path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-5 14H7v-2h7v2zm3-4H7v-2h10v2zm0-4H7V7h10v2z"/>
355+
</svg>`;
356+
357+
const title = document.createElement("h3");
358+
addClass(title, "yasgui-query-browser__empty-title");
359+
title.textContent = "No Workspaces Configured";
360+
361+
const description = document.createElement("p");
362+
addClass(description, "yasgui-query-browser__empty-description");
363+
description.innerHTML = `Workspaces allow you to save and manage SPARQL queries in a shared, versioned store.
364+
You can use SPARQL endpoints (recommended) or Git repositories (GitHub, GitLab, Bitbucket, Gitea) to store your queries.`;
365+
366+
const actionsContainer = document.createElement("div");
367+
addClass(actionsContainer, "yasgui-query-browser__empty-actions");
368+
369+
const addWorkspaceBtn = document.createElement("button");
370+
addClass(addWorkspaceBtn, "yasgui-query-browser__empty-button");
371+
addClass(addWorkspaceBtn, "yasgui-query-browser__empty-button--primary");
372+
addWorkspaceBtn.textContent = "Add Workspace";
373+
addWorkspaceBtn.addEventListener("click", () => {
374+
this.close();
375+
const tab = this.yasgui.getTab();
376+
if (tab && (tab as any).settingsModal) {
377+
const modal = (tab as any).settingsModal;
378+
modal.open();
379+
// Switch to workspaces tab after a short delay to ensure modal is rendered
380+
setTimeout(() => {
381+
const workspacesButton = modal.modalContent?.querySelector(".modalNavButton:nth-child(3)") as HTMLElement;
382+
if (workspacesButton) workspacesButton.click();
383+
}, 50);
384+
}
385+
});
386+
387+
const learnMoreLink = document.createElement("a");
388+
addClass(learnMoreLink, "yasgui-query-browser__empty-link");
389+
learnMoreLink.href = "https://yasgui-doc.matdata.eu/docs/user-guide#managed-queries-and-workspaces";
390+
learnMoreLink.target = "_blank";
391+
learnMoreLink.rel = "noopener noreferrer";
392+
learnMoreLink.textContent = "Learn more about workspaces";
393+
394+
actionsContainer.appendChild(addWorkspaceBtn);
395+
actionsContainer.appendChild(learnMoreLink);
396+
397+
emptyState.appendChild(icon);
398+
emptyState.appendChild(title);
399+
emptyState.appendChild(description);
400+
emptyState.appendChild(actionsContainer);
401+
402+
this.listEl.appendChild(emptyState);
403+
}
404+
324405
private formatQueryPreview(queryText: string, description?: string): string {
325406
const normalized = queryText.replace(/\r\n?/g, "\n").trim();
326407
const lines = normalized.split("\n").map((l) => l.trimEnd());
@@ -917,8 +998,9 @@ export default class QueryBrowser {
917998
const workspaces = this.getWorkspaces();
918999
if (!this.selectedWorkspaceId || workspaces.length === 0) {
9191000
this.backButtonEl.disabled = true;
920-
this.setStatus("No workspaces configured. Add one in settings.");
1001+
this.setStatus("");
9211002
this.clearList();
1003+
this.renderEmptyWorkspaceState();
9221004
return;
9231005
}
9241006

@@ -988,7 +1070,7 @@ export default class QueryBrowser {
9881070
`folders:${foldersPart}`,
9891071
].join(";");
9901072

991-
this.setStatus(rootEntries.length ? "" : "No queries");
1073+
this.setStatus(rootEntries.length ? "" : "No queries, add one by saving a tab to this workspace.");
9921074
if (signature !== this.lastRenderedSignature) {
9931075
this.lastRenderedSignature = signature;
9941076
this.renderTree(backend);

0 commit comments

Comments
 (0)