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
4 changes: 3 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/build
/node_modules
/.git
/.git
/.vscode
/.github
54 changes: 54 additions & 0 deletions .github/workflows/push-docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Build and Push Docker Image
permissions:
contents: read
packages: write
id-token: write
pages: write

on:
push:
branches:
- main
release:
types: [published]

jobs:
build-and-push:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@885d1462b80bc1c1c7f0b00334ad271f09369c55

- name: Login to DockerHub
uses: docker/login-action@465a07811f14bebb1938fbed4728c6a1ff8901fc
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
with:
images: ${{ vars.DOCKERHUB_REPO }}

- name: Build and push Docker image
uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671
with:
context: .
file: ./docker/Dockerfile
push: true
build-args: GITHUB_REF=${{ github.ref_name }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: linux/amd64,linux/arm64

- uses: shrink/actions-docker-extract@f97780187d59e88f06a98b166a7e700c0f400314
id: extract
with:
image: ${{ vars.DOCKERHUB_REPO }}
path: /usr/share/nginx/html/.
destination: dist
35 changes: 35 additions & 0 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Use the official Node.js image as the base image
FROM node:20

# Set the working directory
WORKDIR /app

# Copy package.json and package-lock.json
COPY package*.json ./

# Install dependencies
RUN npm install

# Copy the rest of the application code
COPY . .

# Build the React app
RUN npm run build

# Use the official Nginx image to serve the React app
FROM nginxinc/nginx-unprivileged:alpine

# Copy only JS/CSS from the build output
COPY --from=0 /app/build/yasgui.min.js /usr/share/nginx/html/
COPY --from=0 /app/build/yasgui.min.css /usr/share/nginx/html/

# Copy other static assets
COPY docker/src/ /usr/share/nginx/html/

USER root

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/

USER 1001
Comment thread
MathiasVDA marked this conversation as resolved.
14 changes: 14 additions & 0 deletions docker/change-default-endpoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/sh

# Set default value if the environment variable is not set
: ${YASGUI_DEFAULT_ENDPOINT:="https://dbpedia.org/sparql"}

# Replace the default endpoint in the bundle.js file
echo "Switching YASGUI default endpoint to: $YASGUI_DEFAULT_ENDPOINT"
sed -i "s|https://change.to.default.endpoint/sparql|$(printf '%s' "$YASGUI_DEFAULT_ENDPOINT" | sed 's/[&/\]/\\&/g')|g" /usr/share/nginx/html/*.js

# Execute the command passed to the entrypoint
exec "$@"

# Execute the original Docker entrypoint script
exec /docker-entrypoint.sh
Comment on lines +11 to +14

Copilot AI Dec 7, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script has two exec statements that will cause an issue. Line 11 exec "$@" will replace the current process with the command passed as arguments, so line 14 exec /docker-entrypoint.sh will never be executed. You should either:

  1. Remove line 11 if you want to always execute the nginx entrypoint, or
  2. Remove line 14 if you want to execute the command passed to this script

Based on the context (this is used as a Docker entrypoint), line 14 should likely be exec /docker-entrypoint.sh "$@" and line 11 should be removed.

Suggested change
exec "$@"
# Execute the original Docker entrypoint script
exec /docker-entrypoint.sh
# Execute the original Docker entrypoint script
exec /docker-entrypoint.sh "$@"

Copilot uses AI. Check for mistakes.
Binary file added docker/src/favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
57 changes: 57 additions & 0 deletions docker/src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="utf-8" />
<link rel="icon" href="favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="Yasgui - SPARQL interface" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="manifest.json" />

<!-- YASGUI CSS -->
<link rel="stylesheet" href="yasgui.min.css">

<!-- Font Awesome for icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">

Copilot AI Dec 7, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Loading Font Awesome from a CDN without Subresource Integrity (SRI) creates a security risk. If the CDN is compromised, malicious code could be injected. Consider adding the integrity and crossorigin attributes to ensure the resource hasn't been tampered with.

Suggested change
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" integrity="sha512-papm6H1Yzsa3sGJNZaG0/gt0XiY8h1NIsDPKySx1VHa4EraseFH8blYNx+a3Pl6xNcNehJIK/gB1LsY5cqK8Ug==" crossorigin="anonymous">

Copilot uses AI. Check for mistakes.

<!-- Main site stylesheet -->
<link rel="stylesheet" href="main.css">

<title>Yasgui</title>
</head>

<body>
<noscript>You need to enable JavaScript to run this app.</noscript>

<!-- YASGUI container -->
<div id="yasgui"></div>

<!-- YASGUI JavaScript -->
<script src="yasgui.min.js"></script>

<!-- Footer toggle button (visible on small screens) -->
<button id="footer-toggle" aria-label="Toggle footer">
<i class="fas fa-info-circle"></i>
</button>

<div id="footer">
<a href="https://matdata.eu/" target="_blank" rel="noopener noreferrer" class="footer-left">
<img id="logo" src="logo.svg" alt="Matdata Logo">
</a>
<div class="footer-center">
<small>Source code available on <a href="https://github.com/Matdata-eu/yasgui">Matdata-eu/yasgui</a> with credits to <a href="https://github.com/zazuko/yasgui">Zazuko/Yasgui</a>,
<a href="https://github.com/triplydb/Yasgui">TriplyDB/Yasgui</a>, <a href="https://github.com/Thib-G/yasgui-geo-tg">Thib-G/yasgui-plugin-geo</a>
and <a href="https://github.com/Matdata-eu/yasgui-graph-plugin">Matdata-eu/yasgui-graph-plugin</a></small>
</div>
</div>

<!-- Main site script -->
<script src="main.js"></script>
</body>

</html>
1 change: 1 addition & 0 deletions docker/src/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
128 changes: 128 additions & 0 deletions docker/src/main.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/* Global styles */
body {
margin: 0;
padding: 0;
font-family:
-apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans",
"Helvetica Neue", sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

/* YASGUI container */
#yasgui {
margin-top: 0px;
height: calc(100vh - 60px);
}

/* Footer styles */
#footer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background-color: #f5f5f5;
padding: 8px 20px;
border-top: 1px solid #e0e0e0;
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
transition: transform 0.3s ease-in-out;
}

.footer-left {
position: absolute;
left: 20px;
display: flex;
align-items: center;
}

.footer-center {
text-align: center;
}

#logo {
height: 35px;
width: auto;
transition: opacity 0.2s;
}

#logo:hover {
opacity: 0.8;
}

#footer a {
color: #0066cc;
text-decoration: none;
}

#footer a:hover {
text-decoration: underline;
}

/* Footer toggle button */
#footer-toggle {
display: none;
position: fixed;
bottom: 20px;
right: 20px;
width: 50px;
height: 50px;
border-radius: 50%;
background-color: #0066cc;
color: white;
border: none;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
cursor: pointer;
z-index: 999;
font-size: 20px;
transition: all 0.3s ease;
}

#footer-toggle:hover {
background-color: #0052a3;
transform: scale(1.1);
}

#footer-toggle:active {
transform: scale(0.95);
}

/* Responsive behavior for small screens */
@media (max-width: 768px) {
#footer {
transform: translateY(100%);
}

#footer.expanded {
transform: translateY(0);
}

#footer-toggle {
display: flex;
align-items: center;
justify-content: center;
}

#footer-toggle.hidden {
opacity: 0;
pointer-events: none;
transform: scale(0);
}

.footer-left {
position: relative;
left: 0;
margin-bottom: 10px;
}

#footer {
flex-direction: column;
padding: 15px 20px;
}

.footer-center {
margin-top: 10px;
}
}
74 changes: 74 additions & 0 deletions docker/src/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Footer toggle functionality for small screens
(function () {
const footer = document.getElementById("footer");
const footerToggle = document.getElementById("footer-toggle");

if (!footer || !footerToggle) return;

// Toggle footer visibility
footerToggle.addEventListener("click", function () {
footer.classList.toggle("expanded");
footerToggle.classList.toggle("hidden");
});

// Close footer when clicking outside
document.addEventListener("click", function (event) {
const isClickInsideFooter = footer.contains(event.target);
const isClickOnToggle = footerToggle.contains(event.target);

// Only close if footer is expanded, click is outside, and not on toggle button
if (footer.classList.contains("expanded") && !isClickInsideFooter && !isClickOnToggle) {
footer.classList.remove("expanded");
footerToggle.classList.remove("hidden");
}
});
})();

// YASGUI is loaded via CDN in index.html and available as a global variable
if (typeof Yasgui !== "undefined") {
const yasgui = new Yasgui(document.getElementById("yasgui"), {
Comment thread
MathiasVDA marked this conversation as resolved.
// Set the SPARQL endpoint
requestConfig: {
endpoint: "https://change.to.default.endpoint/sparql",
},

// Allow resizing of the Yasqe editor
resizeable: true,
Comment thread
MathiasVDA marked this conversation as resolved.

// Whether to autofocus on Yasqe on page load
autofocus: true,

// Use the default endpoint when a new tab is opened
copyEndpointOnNewTab: true,

// Configuring which endpoints appear in the endpoint catalogue list
endpointCatalogueOptions: {
getData: () => {
return [
//List of objects should contain the endpoint field
//Feel free to include any other fields (e.g. a description or icon
//that you'd like to use when rendering)
{
endpoint: "https://data-interop.era.europa.eu/api/sparql",
},
{
endpoint: "https://dbpedia.org/sparql",
},
{
endpoint: "https://query.wikidata.org",
},
// ...
];
},
//Data object keys that are used for filtering. The 'endpoint' key already used by default
keys: [],
//Data argument contains a `value` property for the matched data object
//Source argument is the suggestion DOM element to append your rendered item to
renderItem: (data, source) => {
const contentDiv = document.createElement("div");
contentDiv.innerText = data.value.endpoint;
source.appendChild(contentDiv);
},
},
});
}
15 changes: 15 additions & 0 deletions docker/src/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"short_name": "Yasgui",
"name": "Yet Another SPARQL GUI",
"icons": [
{
"src": "favicon.png",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
Loading