Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/user-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -1179,6 +1179,13 @@ The token must have access to the specific repository you're configuring as a wo
- Use the tab context menu action **Save as managed query**
- Saving the same query text does not create a new version; changing text creates a new version

**Copy URI of a managed query:**

- In the **Query Browser**: use the **Copy URI** action button next to any query to copy its URI to the clipboard
- In the **tab context menu** (right-click a tab): use **Copy URI** when the tab is linked to a managed query
- For SPARQL workspaces the URI is the managed-query IRI stored in the triplestore
- For Git workspaces the URI is the browser-accessible link to the file in the repository (GitHub/GitLab/Bitbucket/Gitea)

**Credentials:**

- Tokens are stored locally, not saved together with the managed query and are not re-displayed after entry
Expand Down
42 changes: 42 additions & 0 deletions packages/yasgui/src/TabContextMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { default as Yasgui, getRandomId } from "./";
import Tab from "./Tab";
import { TabListEl } from "./TabElements";
import { cloneDeep } from "lodash-es";
import { getWorkspaceBackend } from "./queryManagement/backends/getWorkspaceBackend";
import type { GitQueryRef, SparqlQueryRef } from "./queryManagement/types";
import "./TabContextMenu.scss";
export interface TabContextConfig {
name: string;
Expand All @@ -17,6 +19,7 @@ export default class TabContextMenu {
private duplicateTabEl!: HTMLElement;
private saveManagedQueryEl!: HTMLElement;
private saveAsRqFileEl!: HTMLElement;
private copyManagedQueryUriEl!: HTMLElement;
private closeTabEl!: HTMLElement;
private closeOtherTabsEl!: HTMLElement;
private reOpenOldTab!: HTMLElement;
Expand Down Expand Up @@ -55,6 +58,8 @@ export default class TabContextMenu {

this.saveAsRqFileEl = this.getMenuItemEl("Save as .rq file");

this.copyManagedQueryUriEl = this.getMenuItemEl("Copy URI");

this.closeTabEl = this.getMenuItemEl("Close Tab");

this.closeOtherTabsEl = this.getMenuItemEl("Close other tabs");
Expand All @@ -67,6 +72,7 @@ export default class TabContextMenu {
dropDownList.appendChild(this.duplicateTabEl);
dropDownList.appendChild(this.saveManagedQueryEl);
dropDownList.appendChild(this.saveAsRqFileEl);
dropDownList.appendChild(this.copyManagedQueryUriEl);
// Add divider
dropDownList.appendChild(document.createElement("hr"));
dropDownList.appendChild(this.closeTabEl);
Expand Down Expand Up @@ -125,6 +131,42 @@ export default class TabContextMenu {
this.closeConfigMenu();
};

// Copy URI for managed query tabs
const meta = tab?.getManagedQueryMetadata();
if (meta) {
const workspaceConfig = this.yasgui.persistentConfig?.getWorkspaces().find((w) => w.id === meta.workspaceId);
if (workspaceConfig) {
const queryId =
meta.backendType === "git"
? (meta.queryRef as GitQueryRef).path
: (meta.queryRef as SparqlQueryRef).managedQueryIri;
if (queryId) {
const backend = getWorkspaceBackend(workspaceConfig, {
persistentConfig: this.yasgui.persistentConfig,
});
const uri = backend.getQueryUri?.(queryId);
if (uri) {
this.copyManagedQueryUriEl.onclick = async () => {
try {
await navigator.clipboard.writeText(uri);
} catch {
window.prompt("Copy this URI:", uri);
}
this.closeConfigMenu();
};
} else {
addClass(this.copyManagedQueryUriEl, "disabled");
}
} else {
addClass(this.copyManagedQueryUriEl, "disabled");
}
} else {
addClass(this.copyManagedQueryUriEl, "disabled");
}
} else {
addClass(this.copyManagedQueryUriEl, "disabled");
}

// Close tab functionality
this.closeTabEl.onclick = () => tab?.close();

Expand Down
85 changes: 85 additions & 0 deletions packages/yasgui/src/queryManagement/QueryBrowser.scss
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,91 @@
white-space: nowrap;
}

&__context-menu {
position: fixed;
z-index: 10001;
list-style: none;
padding: 4px 0;
margin: 0;
min-width: 140px;
background: var(--yasgui-bg-primary, white);
border: 1px solid var(--yasgui-border-color, #e0e0e0);
border-radius: 4px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

&__context-menu-item {
padding: 7px 16px;
cursor: pointer;
white-space: nowrap;
color: var(--yasgui-text-primary, #000);
font-size: 13px;
line-height: 1.4;

&:hover {
background: var(--yasgui-bg-secondary, #f5f5f5);
color: var(--yasgui-button-hover, #000);
}

&--danger {
color: var(--yasgui-error-color, #c00);

&:hover {
background: var(--yasgui-bg-secondary, #f5f5f5);
color: var(--yasgui-error-color, #c00);
}
}
}

&__rename-input {
flex: 1;
min-width: 0;
font: inherit;
font-size: 13px;
color: var(--yasgui-text-primary, #000);
background: var(--yasgui-bg-primary, white);
border: 1px solid var(--yasgui-accent-color, #337ab7);
border-radius: 3px;
padding: 1px 4px;
outline: none;
box-shadow: 0 0 0 2px rgba(51, 122, 183, 0.25);
}

&__inline-confirm {
flex: 1;
font-size: 13px;
color: var(--yasgui-text-primary, #000);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

&__inline-confirm-btn {
appearance: none;
background: transparent;
border: 1px solid var(--yasgui-border-color, #e0e0e0);
border-radius: 3px;
padding: 1px 8px;
font: inherit;
font-size: 12px;
cursor: pointer;
color: var(--yasgui-text-primary, #000);
flex-shrink: 0;

&:hover {
background: var(--yasgui-bg-secondary, #f5f5f5);
}

&--danger {
color: var(--yasgui-error-color, #c00);
border-color: var(--yasgui-error-color, #c00);

&:hover {
background: rgba(204, 0, 0, 0.08);
}
}
}

&__tree-meta {
padding: 4px 8px;
font-size: 13px;
Expand Down
Loading
Loading