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
17 changes: 17 additions & 0 deletions .changeset/review-hardening.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
"@matdata/yasgui": minor
"@matdata/yasqe": patch
"@matdata/yasr": patch
"@matdata/yasgui-utils": patch
---

Safer share links, storage and dialogs:

- A query opened from a share link no longer runs on its own when it is an update, has syntax errors, or would send saved credentials or cookies; a message asks first. New `autoRunSharedQueries` option ("safe" by default, "always", "never").
- A malformed `headers` or `outputSettings` parameter in a link is ignored instead of breaking the page.
- When the browser storage is full, MatGUI saves the configuration without query results, and otherwise keeps working and says so. It no longer deletes every tab, endpoint and credential.
- In-app dialogs and toasts replace every `alert`, `confirm` and `prompt`, so they follow the theme and work in sandboxed iframes; available to plugins and embedders as `Yasgui.dialogs`.
- Configuration import reads the Turtle file with a real parser, so tabs without an endpoint or with quotes in their name import correctly.
- Saving a Git query after a stale version tag no longer reports a conflict when the automatic retry succeeded.
- The OAuth 2.0 popup only accepts its result from the origin of the redirect URI.
- Yasqe `requestSendsCredentials()`.
2 changes: 1 addition & 1 deletion .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ module.exports = {
parserOptions: {
ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features
sourceType: "module", // Allows for the use of imports,
project: expensive ? "./tsconfig-validate.json" : undefined,
project: expensive ? ["./tsconfig-validate.json", "./tsconfig-test.json"] : undefined,
tsconfigRootDir: expensive ? "." : undefined,
},
plugins: ["@typescript-eslint", "jest", "lodash"],
Expand Down
36 changes: 36 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
version: 2
updates:
# Monorepo packages (packages/*) and build tooling
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
open-pull-requests-limit: 10
groups:
codemirror:
patterns:
- "@codemirror/*"
- "@lezer/*"
matdata-plugins:
patterns:
- "@matdata/*"
dev-tooling:
dependency-type: development
update-types:
- minor
- patch

# Documentation website
- package-ecosystem: npm
directory: /website
schedule:
interval: monthly
groups:
docusaurus:
patterns:
- "@docusaurus/*"

- package-ecosystem: github-actions
directory: /
schedule:
interval: monthly
11 changes: 11 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ on:
pull_request:
branches:
- main
workflow_dispatch:

jobs:
build:
Expand All @@ -31,6 +32,16 @@ jobs:
- name: Build project
run: npm run build

# After the build, which generates packages/yasgui/src/version.ts
- name: Type-check
run: npm run util:validateTs

- name: Lint
run: npm run util:lint

- name: Bundle size
run: npm run util:bundleSize

- name: Run tests
run: npm run test

Expand Down
29 changes: 0 additions & 29 deletions .github/workflows/test.yaml

This file was deleted.

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ website/node_modules
website/build
website/.docusaurus

bundle-stats
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@

The **documentation for Matgui is hosted on GitHub Pages**:

- **📚 Documentation Website**: [https://matgui-doc.matdata.eu/](https://matdata-eu.github.io/Yasgui/)
- **📚 Documentation Website**: [https://matgui-doc.matdata.eu/](https://matgui-doc.matdata.eu/)
- User Guide, Developer Guide, API Reference
- Built with Docusaurus
- Version-tagged with the repository

- **🚀 Development Build**: [https://matgui-doc.matdata.eu/dev/main/](https://matdata-eu.github.io/Yasgui/dev/main/)
- **🚀 Development Build**: [https://matgui-doc.matdata.eu/dev/main/](https://matgui-doc.matdata.eu/dev/main/)
- Live build from the main branch
- Updated automatically with every commit
- Test latest features before release
Expand Down
3 changes: 2 additions & 1 deletion docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Use the official Node.js image as the base image
FROM node:20
FROM node:24

# Set the working directory
WORKDIR /app
Expand Down Expand Up @@ -36,6 +36,7 @@ COPY docker/src/ /usr/share/nginx/html/

USER root

COPY docker/nginx.conf /etc/nginx/conf.d/default.conf
COPY docker/change-default-endpoint.sh /docker-entrypoint.d/
RUN chmod +x /docker-entrypoint.d/change-default-endpoint.sh
RUN chown 1001:0 -R /usr/share/nginx/html/
Expand Down
36 changes: 36 additions & 0 deletions docker/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# MatGUI static site. Replaces the default server of nginx-unprivileged (which listens on 8080).
server {
listen 8080;
listen [::]:8080;
server_name localhost;
root /usr/share/nginx/html;
index index.html;

# The bundle is about 5 MB of JavaScript; gzip brings the transfer down to about 1.5 MB
gzip on;
gzip_comp_level 6;
gzip_min_length 1024;
gzip_vary on;
gzip_proxied any;
gzip_types text/css application/javascript text/javascript application/json application/manifest+json image/svg+xml text/plain;

add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

# Fonts and images emitted by the build carry a content hash in their name
location ~* "-[A-Z0-9]{8}\.(woff2?|ttf|eot|png|jpg|svg)$" {
expires 1y;
add_header Cache-Control "public, max-age=31536000, immutable";
add_header X-Content-Type-Options "nosniff" always;
}

# yasgui.min.js and .css keep their name across releases: let browsers revalidate them
location ~* \.(js|css)$ {
add_header Cache-Control "no-cache";
add_header X-Content-Type-Options "nosniff" always;
}

location / {
try_files $uri $uri/ /index.html;
}
}
38 changes: 38 additions & 0 deletions docs/developer-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,13 @@ interface Config {
// Populate config from URL parameters
populateFromUrl: boolean | ((config: TabJson) => TabJson); // default: true

// Whether a query opened from a share link runs on load. Update queries never do.
// "safe": runs, unless the request would carry credentials (Authorization or API key
// header, or withCredentials) or the query is invalid; then a message asks first
// "always": runs unless it is an update
// "never": loads the query without running it
autoRunSharedQueries?: "safe" | "always" | "never"; // default: "safe"

// Auto-create first tab on init
autoAddOnInit: boolean; // default: true

Expand Down Expand Up @@ -2577,6 +2584,37 @@ yasgui.helpMenu.removeItem("contact");

`yasgui.whatsNew` (unless `showWhatsNew: false`) has `open()`, `close()`, `hasUnseen()` and `getLatestVersion()`. The release entries live in `packages/yasgui/src/whatsNew/releases.ts`, newest first; add the next version there when preparing a release. The newest version a user has opened is stored as `whatsNewSeen` in the persisted config.

#### Dialogs and notifications

`Yasgui.dialogs` shows alerts, confirmations and toasts in the MatGUI style, inside the Yasgui root so they follow the theme. Unlike `window.alert` and `window.confirm` they don't block the page, and they keep working when MatGUI is embedded in a sandboxed iframe (where `confirm()` silently returns `false`). Plugins and embedding pages can use them too.

```javascript
const { showAlert, showConfirm, showChoice, showToast, showCopyValue } = Yasgui.dialogs;

await showAlert("The query was saved.", { title: "Saved" });

if (await showConfirm("Its queries stay in the repository.", { title: "Remove workspace?", confirmLabel: "Remove", danger: true })) {
// ...
}

const choice = await showChoice(
"This query has unsaved changes.",
[
{ label: "Cancel", value: "cancel" },
{ label: "Discard", value: "discard", kind: "danger" },
{ label: "Save", value: "save", kind: "primary" },
],
"cancel", // returned on Escape or a click outside
);

showToast("Copied", { kind: "success" }); // kind: "info" | "success" | "warning" | "error"
showToast("Results are outdated", { action: { label: "Run again", onClick: () => yasgui.getTab().query() } });

await showCopyValue("Copy the URI of this query", "https://example.org/query/1");
```

Each function takes a `host` option: an element inside the Yasgui instance the dialog belongs to. Without it, the dialog opens in the last Yasgui instance created on the page.

### Tab Class

Represents a query tab.
Expand Down
8 changes: 8 additions & 0 deletions docs/user-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -1277,6 +1277,8 @@ _OAuth 2.0:_
- **Be cautious on shared computers**: Clear your browser data when using Matgui on shared or public computers
- **OAuth 2.0 tokens**: Access tokens are automatically refreshed when expired (if refresh token is available)
- **Token security**: OAuth 2.0 uses secure PKCE flow (Proof Key for Code Exchange) for enhanced security
- **Shared links don't use your credentials on their own**: a link that would query an endpoint with your saved credentials asks before it runs (see [Share Queries](#share-queries))
- **When the browser storage is full**, MatGUI first stops keeping query results with the tabs; if that isn't enough it keeps working without saving and tells you. It never deletes your tabs or credentials to make room

**How Authentication Works:**

Expand Down Expand Up @@ -1645,6 +1647,12 @@ Matgui supports URL-based query sharing:
- `endpoint`: The endpoint URL
- Other tab configurations

**Opening a shared link:** the query of the link opens in a tab and runs straight away, except in these cases, where MatGUI shows a message and waits for you:

- **Update queries** (INSERT, DELETE, LOAD, CLEAR, DROP...) never run from a link. Review the query and press **Run** yourself if you want to change the data.
- **Queries that would use your saved credentials** for that endpoint (or cookies) wait until you click **Run query** in the message, so a link someone sends you can't run a query as you without you seeing it.
- **Queries with syntax errors** are loaded without running.

**Command-Line Formats:**

All command-line formats (cURL, PowerShell, wget) include:
Expand Down
3 changes: 3 additions & 0 deletions esbuild.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@ async function buildPackage(name, entryPoint, globalName) {
},
});
extractCss(iifeResult, name);
// Bundle composition, for `npm run util:bundleSize` (kept out of build/ so it isn't distributed)
fs.mkdirSync("bundle-stats", { recursive: true });
fs.writeFileSync(`bundle-stats/${name}.json`, JSON.stringify(iifeResult.metafile));

// ESM build: consumed by bundlers (vite/webpack/esbuild) and Node via `import`.
// Uses the `.mjs` extension so it is always treated as an ES module.
Expand Down
Loading
Loading