Skip to content
Open
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
3 changes: 2 additions & 1 deletion docs/developer-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -3285,7 +3285,7 @@ export default class ChartPlugin implements Plugin {
}
```

### Host API for Result Plugins (yasr hostApi v1)
### Host API for Result Plugins (yasr hostApi v2)

YASR exposes a small host API so plugins share one describe panel and one toolbar style. Feature-detect it with `yasr.hostApi`, never with version strings, and keep your own fallback for older hosts:

Expand All @@ -3302,6 +3302,7 @@ const bar = host?.toolbar && typeof this.yasr.getPluginToolbar === "function" ?
- `yasr.describe(iri, { direction?, source?, newHistory? }): Promise<void>` opens the shared describe panel. It runs a CONSTRUCT query through `yasr.executeQuery` with `Accept: text/turtle` and never rejects; errors show in the panel. `newHistory: false` adds to the panel's back/forward history instead of starting a new one. `yasr.closeDescribe()` closes it, `yasr.isDescribeOpen()` reports its state, and YASR emits `"describe"` with `(yasr, iri, direction)` each time a resource is shown.
- `yasr.getPluginToolbar()` returns `div.yasr_pluginToolbar`, a full-width bar under the YASR header. YASR empties it before every `draw()` and hides it while it is empty. A plugin that redraws itself must remove its own items first. Build controls inside it with `.yasr_toolbarButton` (toggle with `aria-pressed="true"` or `.is-active`), `.yasr_toolbarSelect` (`<label><span>Label</span><select>`), `.yasr_toolbarSearch` (`<input type="search">`), `.yasr_toolbarGroup` and `.yasr_toolbarSpacer` (a direct child of the slot). Put "View settings" last, as a `.yasr_toolbarButton` with the Lucide `sliders-horizontal` icon.
- Hosts can set the YASR config hook `openQueryInNewTab(query)` to enable the panel's "Open as query" button. YASGUI sets it to open a new tab on the same endpoint.
- `yasr.executeQuery(query, options)` runs a background request with the endpoint, method, headers and authentication of the tab and resolves with the raw response (`status`, `headers`, `content`). Since host API 2 (`hostApi.queryRequest`), `options.extraArgs` adds request parameters next to the query (for example `{ explain: "details" }`) and `options.endpoint` sends the request to another URL with the same settings (for example Stardog's `/{db}/explain`). Older hosts ignore both, so a plugin that needs them checks `hostApi.queryRequest` first.
- Style with `var(--yasgui-…, fallback)`. Inside `.yasr`, the `--yasr-ui-*` shorthands (for example `--yasr-ui-brand`, `--yasr-ui-line`) already carry light and dark fallbacks.

### Plugin Best Practices
Expand Down
53 changes: 53 additions & 0 deletions docs/user-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
- [Graph Plugin](#graph-plugin)
- [Geo Plugin](#geo-plugin)
- [Chart Plugin](#chart-plugin)
- [Explain Plugin](#explain-plugin)
- [Error Plugin](#error-plugin)
- [Plugin Selection](#plugin-selection)
- [Describing a Resource](#describing-a-resource)
Expand Down Expand Up @@ -2070,6 +2071,58 @@ Your choices are saved per tab. When the query returns other variables, the char

Visit the [Chart Plugin repository](https://github.com/Matdata-eu/yasgui-chart-plugin) for full documentation and the [online demo](https://matdata-eu.github.io/yasgui-chart-plugin/).

### Explain Plugin

Shows how your query is executed. The **Explain** tab has two parts:

- **Execution plan**: the operations the triple store ran for your query, with the rows and the time of each. MatGUI asks the endpoint for it with one extra request after your query completed, using the authentication and request settings of the tab. The slowest operation is highlighted, which is usually the answer to "why is this query slow".
- **Algebra**: your query translated to SPARQL algebra, the form in which engines plan it (`project`, `join`, `leftjoin`, `filter`, `union`, ...). It is computed in MatGUI itself and works for any endpoint. Syntax errors are reported here with the parser's message.

**Best For:**

- Finding the join or scan that takes the time in a slow query
- Checking that a `FILTER` or `OPTIONAL` is evaluated where you think it is
- Learning how a query reads in SPARQL algebra

---

**Supported engines:**

| Engine | What the plan shows |
|---|---|
| QLever | The operation tree with time, rows and cache status per operation |
| GraphDB | The chosen order of the patterns with estimated sizes (no timings) |
| Stardog | The profiled plan with rows, wall time and memory per operator |
| Blazegraph | Blazegraph's explain page (syntax tree, operator plan, statistics) |
| Amazon Neptune | Neptune's explain table, one row per operator |

Virtuoso, Jena Fuseki, Oxigraph, RDF4J and Comunica publish no plan over the SPARQL protocol; for those endpoints only the algebra is shown.

---

**Getting Started:**

1. Run your query.
2. Open the **Explain** tab. The algebra appears at once.
3. MatGUI recognises the engine from the endpoint URL (QLever, GraphDB, Blazegraph, Stardog and Neptune have recognisable URLs). When it does not, pick the engine in the **Engine** list; the choice is remembered for that endpoint. **No plan** switches the request off for an endpoint.
4. **Refresh plan** asks the engine again, for example after the endpoint's cache warmed up.

Each operation of the plan can be folded. **Expand all**, **Collapse all** and **Copy** act on the whole tree; **Download** in the results header saves the plan and the algebra as a text file. The algebra's **Copy** gives the s-expression notation used by Apache Jena ARQ and the SPARQL specification, handy for issues and documentation.

---

**Good to know:**

- The plan request is a second, separate request. Your results are never changed by it, and when it fails (unsupported engine, authentication, CORS) only the plan section says so.
- QLever answers the plan request from its result cache, so operations that were already cached show their original times in their details.
- The GraphDB plan is asked with the `onto:explain` pseudo graph. RDF4J shares GraphDB's URL layout but has no explain, so the request fails there.

---

**More Information:**

Visit the [Explain Plugin repository](https://github.com/Matdata-eu/yasgui-explain-plugin) for full documentation and the [online demo](https://matdata-eu.github.io/yasgui-explain-plugin/).

### Error Plugin

Displays error messages and diagnostic information when queries fail.
Expand Down
196 changes: 193 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"dependencies": {
"@fortawesome/fontawesome-free": "^7.1.0",
"@matdata/yasgui-chart-plugin": "^1.2.0",
"@matdata/yasgui-explain-plugin": "^1.0.0",
"@matdata/yasgui-geo-plugin": "^1.3.0",
"@matdata/yasgui-graph-plugin": "^1.7.0",
"@matdata/yasgui-table-plugin": "^1.7.1",
Expand Down
2 changes: 2 additions & 0 deletions packages/yasgui/src/Tab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1841,6 +1841,8 @@ export class Tab extends EventEmitter {
customQuery: query,
customAccept: options?.acceptHeader,
signal: options?.signal,
extraArgs: options?.extraArgs,
customEndpoint: options?.endpoint,
silent: true,
});
return response;
Expand Down
3 changes: 3 additions & 0 deletions packages/yasgui/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ import { default as Yasqe, PartialConfig as YasqeConfig, RequestConfig } from "@
import { default as Yasr, Config as YasrConfig } from "@matdata/yasr";
import { addClass, removeClass } from "@matdata/yasgui-utils";
import ChartPlugin from "@matdata/yasgui-chart-plugin";
import ExplainPlugin from "@matdata/yasgui-explain-plugin";
import GeoPlugin from "@matdata/yasgui-geo-plugin";
import GraphPlugin from "@matdata/yasgui-graph-plugin";
import TablePlugin from "@matdata/yasgui-table-plugin";
import { moveTabIdToFront, removeTabId } from "./tabNavigationHistory";
import "@matdata/yasgui-chart-plugin/dist/yasgui-chart-plugin.min.css";
import "@matdata/yasgui-explain-plugin/dist/yasgui-explain-plugin.min.css";
import "@matdata/yasgui-graph-plugin/dist/yasgui-graph-plugin.min.css";
import "@matdata/yasgui-table-plugin/dist/yasgui-table-plugin.min.css";
import { ThemeManager, Theme } from "./ThemeManager";
Expand All @@ -35,6 +37,7 @@ Yasr.registerPlugin("Table", TablePlugin);
Yasr.registerPlugin("Geo", GeoPlugin as any);
Yasr.registerPlugin("Graph", GraphPlugin);
Yasr.registerPlugin("Chart", ChartPlugin as any);
Yasr.registerPlugin("Explain", ExplainPlugin as any);
if (window) {
//We're storing yasqe and yasr as a member of Yasgui, but _also_ in the window
//That way, we dont have to tweak e.g. pro plugins to register themselves to both
Expand Down
Loading
Loading