Merge branch 'main' into feature/526-average-resample

This commit is contained in:
2026-06-18 07:17:41 +02:00
34 changed files with 423 additions and 226 deletions

View File

@@ -4,7 +4,7 @@ import {
setContextClient,
fetchExchange,
} from "@urql/svelte";
import { setContext, getContext, hasContext, onDestroy, tick } from "svelte";
import { setContext, getContext, onDestroy, tick } from "svelte";
import { readable } from "svelte/store";
import { round } from "mathjs";
@@ -21,14 +21,11 @@ import { round } from "mathjs";
* - Adds 'getHardwareTopology' to the context, a function that takes a cluster nad subCluster and returns the subCluster topology (or undefined)
*/
export function init(extraInitQuery = "") {
const jwt = hasContext("jwt")
? getContext("jwt")
: getContext("cc-config")["jwt"];
// The web UI authenticates GraphQL requests via the session cookie
// (same-origin), so no Authorization header is attached here. External
// clients use a JWT against /query directly.
const client = new Client({
url: `${window.location.origin}/query`,
fetchOptions:
jwt != null ? { headers: { Authorization: `Bearer ${jwt}` } } : {},
exchanges: [
expiringCacheExchange({
ttl: 5 * 60 * 1000,

View File

@@ -52,8 +52,8 @@
{{block "footer" .}}
<footer class="site-footer bg-light">
<ul class="footer-list">
<li class="footer-list-item"><a class="link-secondary fs-5" href="/imprint" title="Imprint" rel="nofollow">Imprint</a></li>
<li class="footer-list-item"><a class="link-secondary fs-5" href="/privacy" title="Privacy Policy" rel="nofollow">Privacy Policy</a></li>
<li class="footer-list-item"><a class="link-secondary fs-5" href="{{ .FooterLinks.Imprint.URL }}" title="Imprint"{{ if .FooterLinks.Imprint.External }} target="_blank" rel="noopener noreferrer"{{ else }} rel="nofollow"{{ end }}>Imprint</a></li>
<li class="footer-list-item"><a class="link-secondary fs-5" href="{{ .FooterLinks.Privacy.URL }}" title="Privacy Policy"{{ if .FooterLinks.Privacy.External }} target="_blank" rel="noopener noreferrer"{{ else }} rel="nofollow"{{ end }}>Privacy Policy</a></li>
</ul>
<ul class="build-list">
<li class="build-list-item">Version {{ .Build.Version }}</li>

View File

@@ -76,6 +76,32 @@ type PlotConfiguration struct {
ResamplePolicy string `json:"resample-policy"`
}
const (
defaultImprintLink = "/imprint"
defaultPrivacyLink = "/privacy"
)
// FooterLink is the render-time representation of a single footer legal link.
type FooterLink struct {
URL string // Resolved target: internal path or external URL.
External bool // True if the target is an external URL (opened in a new tab).
}
// FooterLinks holds the resolved legal links shown in the site footer.
type FooterLinks struct {
Imprint FooterLink
Privacy FooterLink
}
// resolveFooterLink falls back to def when v is empty and flags external URLs.
func resolveFooterLink(v, def string) FooterLink {
if v == "" {
v = def
}
external := strings.HasPrefix(v, "http://") || strings.HasPrefix(v, "https://")
return FooterLink{URL: v, External: external}
}
var UIDefaults = WebConfig{
JobList: JobListConfig{
UsePaging: false,
@@ -270,6 +296,7 @@ type Page struct {
Config map[string]any // UI settings for the currently logged in user (e.g. line width, ...)
Resampling *config.ResampleConfig // If not nil, defines resampling trigger and resolutions
Redirect string // The originally requested URL, for intermediate login handling
FooterLinks FooterLinks // Resolved legal links for the site footer
}
func RenderTemplate(rw http.ResponseWriter, file string, page *Page) {
@@ -293,6 +320,11 @@ func RenderTemplate(rw http.ResponseWriter, file string, page *Page) {
}
}
page.FooterLinks = FooterLinks{
Imprint: resolveFooterLink(config.Keys.FooterLinks.Imprint, defaultImprintLink),
Privacy: resolveFooterLink(config.Keys.FooterLinks.Privacy, defaultPrivacyLink),
}
cclog.Debugf("Page config : %v\n", page.Config)
if err := t.Execute(rw, page); err != nil {
cclog.Errorf("Template error: %s", err.Error())