Update component header, format, streamline SV5 components

This commit is contained in:
Christoph Kluge
2025-07-02 18:43:25 +02:00
parent dd48f5ab87
commit 60ec7e54f5
76 changed files with 2070 additions and 1988 deletions

View File

@@ -1,6 +1,9 @@
<!--
@component Admin settings wrapper
-->
@component Admin settings wrapper
Properties:
- `ncontent String`: The homepage notice content
-->
<script>
import { Row, Col } from "@sveltestrap/sveltestrap";
@@ -13,7 +16,9 @@
import NoticeEdit from "./admin/NoticeEdit.svelte";
/* Svelte 5 Props */
let { ncontent } = $props();
let {
ncontent
} = $props();
/* Const Init*/
const ccconfig = getContext("cc-config");

View File

@@ -1,12 +1,12 @@
<!--
@component Support settings wrapper
Properties: None
-->
@component Support settings wrapper
-->
<script>
import { getContext } from "svelte";
import SupportOptions from "./support/SupportOptions.svelte";
/* Const Init */
const ccconfig = getContext("cc-config");
</script>

View File

@@ -1,10 +1,10 @@
<!--
@component User settings wrapper
@component User settings wrapper
Properties:
- `username String!`: Empty string if auth. is disabled, otherwise the username as string
- `isApi Bool!`: Is currently logged in user api authority
-->
Properties:
- `username String!`: Empty string if auth. is disabled, otherwise the username as string
- `isApi Bool!`: Is currently logged in user api authority
-->
<script>
import { getContext } from "svelte";

View File

@@ -1,19 +1,20 @@
<!--
@component User creation form card
@component User creation form card
Properties:
- `roles [String]!`: List of roles used in app as strings
Properties:
- `roles [String]!`: List of roles used in app as strings
- `reloadUser Func`: The callback function to reload the user list
-->
Events:
- `reload`: Trigger upstream reload of user list after user creation
-->
<script>
import { Button, Card, CardTitle } from "@sveltestrap/sveltestrap";
import { fade } from "svelte/transition";
/* Svelte 5 Props */
let { roles, reloadUser } = $props();
let {
roles,
reloadUser
} = $props();
/* State Init */
let message = $state({ msg: "", color: "#d63384" });

View File

@@ -1,16 +1,18 @@
<!--
@component User managed project edit form card
@component User managed project edit form card
Events:
- `reload`: Trigger upstream reload of user list after project update
-->
Properties:
- `reloadUser Func`: The callback function to reload the user list
-->
<script>
import { Card, CardTitle, CardBody } from "@sveltestrap/sveltestrap";
import { fade } from "svelte/transition";
/* Svelte 5 Props */
let { reloadUser } = $props();
let {
reloadUser
} = $props();
/* State Init */
let message = $state({ msg: "", color: "#d63384" });

View File

@@ -1,19 +1,20 @@
<!--
@component User role edit form card
@component User role edit form card
Properties:
- `roles [String]!`: List of roles used in app as strings
Events:
- `reload`: Trigger upstream reload of user list after role edit
-->
Properties:
- `roles [String]!`: List of roles used in app as strings
- `reloadUser Func`: The callback function to reload the user list
-->
<script>
import { Card, CardTitle, CardBody } from "@sveltestrap/sveltestrap";
import { fade } from "svelte/transition";
/* SVelte 5 Props */
let {roles, reloadUser } = $props();
let {
roles,
reloadUser
} = $props();
/* State Init */
let message = $state({ msg: "", color: "#d63384" });

View File

@@ -1,13 +1,18 @@
<!--
@component Admin edit notice.txt content card
-->
@component Admin edit notice content card
Properties:
- `ncontent String`: The homepage notice content
-->
<script>
import { Col, Card, CardTitle, CardBody } from "@sveltestrap/sveltestrap";
import { fade } from "svelte/transition";
/* Svelte 5 Props */
let { ncontent } = $props();
let {
ncontent
} = $props();
/* State Init */
let message = $state({ msg: "", color: "#d63384" });

View File

@@ -1,6 +1,6 @@
<!--
@component Admin option select card
-->
@component Admin option select card
-->
<script>
import { getContext, onMount } from "svelte";

View File

@@ -1,12 +1,10 @@
<!--
@component User management table
@component User management table
Properties:
- `users [Object]?`: List of users
Events:
- `reload`: Trigger upstream reload of user list
-->
Properties:
- `users [Object]?`: List of users [Bindable, Default: []]
- `reloadUser Func`: The callback function to reload the user list
-->
<script>
import {
@@ -19,7 +17,10 @@
import ShowUsersRow from "./ShowUsersRow.svelte";
/*Svelte 5 Props */
let { users = $bindable([]), reloadUser } = $props();
let {
users = $bindable([]),
reloadUser
} = $props();
/* Functions */
function deleteUser(username) {

View File

@@ -1,17 +1,19 @@
<!--
@component User data row for table
@component User data row for table
Properties:
- `user Object!`: User Object
- {username: String, name: String, roles: [String], projects: String, email: String}
-->
Properties:
- `user Object!`: User Object
- {username: String, name: String, roles: [String], projects: String, email: String}
-->
<script>
import { Button } from "@sveltestrap/sveltestrap";
import { fetchJwt } from "../../generic/utils.js"
/* Svelte 5 Props */
let { user } = $props();
let {
user
} = $props();
/* State Init */
let jwt = $state("");

View File

@@ -1,13 +1,18 @@
<!--
@component Support option select card
-->
@component Support option select card
Properties:
- `config Object`: Config includes latest option states
-->
<script>
import { Row, Col, Card, CardTitle, CardBody, Button} from "@sveltestrap/sveltestrap";
import { fade } from "svelte/transition";
/* Svelte 5 Props */
let { config } = $props();
let {
config
} = $props();
/* State Init */
let message = $state("");

View File

@@ -1,394 +1,392 @@
<!--
@component Plot color scheme selection for users
@component Plot color scheme selection for users
Properties:
- `config Object`: Current cc-config
- `message Object`: Message to display on success or error
- `displayMessage Bool`: If to display message content
Events:
- `update-config, {selector: String, target: String}`: Trigger upstream update of the config option
-->
Properties:
- `config Object`: Current cc-config
- `message Object`: Message to display on success or error [Bindable]
- `displayMessage Bool`: If to display message content [Bindable]
- `cbmode Bool?`: Current colorblindness mode state [Bindable, Default: false]
- `updateSetting Func`: The callback function to apply current option selection
-->
<script>
import {
Table,
Row,
Col,
Card,
CardTitle,
} from "@sveltestrap/sveltestrap";
import { fade } from "svelte/transition";
import {
Table,
Row,
Col,
Card,
CardTitle,
} from "@sveltestrap/sveltestrap";
import { fade } from "svelte/transition";
/* Svelte 5 Props */
let {
config,
message = $bindable(),
displayMessage = $bindable(),
cbmode = $bindable(false),
updateSetting
} = $props();
/* Svelte 5 Props */
let {
config,
message = $bindable(),
displayMessage = $bindable(),
cbmode = $bindable(false),
updateSetting
} = $props();
/* State Init */
let activeRow = $state(JSON.stringify(config?.plot_general_colorscheme));
/* State Init */
let activeRow = $state(JSON.stringify(config?.plot_general_colorscheme));
/* Const Init */
const colorschemes = {
Default: [
"#00bfff",
"#0000ff",
"#ff00ff",
"#ff0000",
"#ff8000",
"#ffff00",
"#80ff00",
],
Autumn: [
"rgb(255,0,0)",
"rgb(255,11,0)",
"rgb(255,20,0)",
"rgb(255,30,0)",
"rgb(255,41,0)",
"rgb(255,50,0)",
"rgb(255,60,0)",
"rgb(255,71,0)",
"rgb(255,80,0)",
"rgb(255,90,0)",
"rgb(255,101,0)",
"rgb(255,111,0)",
"rgb(255,120,0)",
"rgb(255,131,0)",
"rgb(255,141,0)",
"rgb(255,150,0)",
"rgb(255,161,0)",
"rgb(255,171,0)",
"rgb(255,180,0)",
"rgb(255,190,0)",
"rgb(255,201,0)",
"rgb(255,210,0)",
"rgb(255,220,0)",
"rgb(255,231,0)",
"rgb(255,240,0)",
"rgb(255,250,0)",
],
Beach: [
"rgb(0,252,0)",
"rgb(0,233,0)",
"rgb(0,212,0)",
"rgb(0,189,0)",
"rgb(0,169,0)",
"rgb(0,148,0)",
"rgb(0,129,4)",
"rgb(0,145,46)",
"rgb(0,162,90)",
"rgb(0,180,132)",
"rgb(29,143,136)",
"rgb(73,88,136)",
"rgb(115,32,136)",
"rgb(81,9,64)",
"rgb(124,51,23)",
"rgb(162,90,0)",
"rgb(194,132,0)",
"rgb(220,171,0)",
"rgb(231,213,0)",
"rgb(0,0,13)",
"rgb(0,0,55)",
"rgb(0,0,92)",
"rgb(0,0,127)",
"rgb(0,0,159)",
"rgb(0,0,196)",
"rgb(0,0,233)",
],
BlueRed: [
"rgb(0,0,131)",
"rgb(0,0,168)",
"rgb(0,0,208)",
"rgb(0,0,247)",
"rgb(0,27,255)",
"rgb(0,67,255)",
"rgb(0,108,255)",
"rgb(0,148,255)",
"rgb(0,187,255)",
"rgb(0,227,255)",
"rgb(8,255,247)",
"rgb(48,255,208)",
"rgb(87,255,168)",
"rgb(127,255,127)",
"rgb(168,255,87)",
"rgb(208,255,48)",
"rgb(247,255,8)",
"rgb(255,224,0)",
"rgb(255,183,0)",
"rgb(255,143,0)",
"rgb(255,104,0)",
"rgb(255,64,0)",
"rgb(255,23,0)",
"rgb(238,0,0)",
"rgb(194,0,0)",
"rgb(150,0,0)",
],
Rainbow: [
"rgb(125,0,255)",
"rgb(85,0,255)",
"rgb(39,0,255)",
"rgb(0,6,255)",
"rgb(0,51,255)",
"rgb(0,97,255)",
"rgb(0,141,255)",
"rgb(0,187,255)",
"rgb(0,231,255)",
"rgb(0,255,233)",
"rgb(0,255,189)",
"rgb(0,255,143)",
"rgb(0,255,99)",
"rgb(0,255,53)",
"rgb(0,255,9)",
"rgb(37,255,0)",
"rgb(83,255,0)",
"rgb(127,255,0)",
"rgb(173,255,0)",
"rgb(217,255,0)",
"rgb(255,248,0)",
"rgb(255,203,0)",
"rgb(255,159,0)",
"rgb(255,113,0)",
"rgb(255,69,0)",
"rgb(255,23,0)",
],
Binary: [
"rgb(215,215,215)",
"rgb(206,206,206)",
"rgb(196,196,196)",
"rgb(185,185,185)",
"rgb(176,176,176)",
"rgb(166,166,166)",
"rgb(155,155,155)",
"rgb(145,145,145)",
"rgb(136,136,136)",
"rgb(125,125,125)",
"rgb(115,115,115)",
"rgb(106,106,106)",
"rgb(95,95,95)",
"rgb(85,85,85)",
"rgb(76,76,76)",
"rgb(66,66,66)",
"rgb(55,55,55)",
"rgb(46,46,46)",
"rgb(36,36,36)",
"rgb(25,25,25)",
"rgb(16,16,16)",
"rgb(6,6,6)",
],
GistEarth: [
"rgb(0,0,0)",
"rgb(2,7,117)",
"rgb(9,30,118)",
"rgb(16,53,120)",
"rgb(23,73,122)",
"rgb(31,93,124)",
"rgb(39,110,125)",
"rgb(47,126,127)",
"rgb(51,133,119)",
"rgb(57,138,106)",
"rgb(62,145,94)",
"rgb(66,150,82)",
"rgb(74,157,71)",
"rgb(97,162,77)",
"rgb(121,168,83)",
"rgb(136,173,85)",
"rgb(153,176,88)",
"rgb(170,180,92)",
"rgb(185,182,94)",
"rgb(189,173,99)",
"rgb(192,164,101)",
"rgb(203,169,124)",
"rgb(215,178,149)",
"rgb(226,192,176)",
"rgb(238,212,204)",
"rgb(248,236,236)",
],
BlueWaves: [
"rgb(83,0,215)",
"rgb(43,6,108)",
"rgb(9,16,16)",
"rgb(8,32,25)",
"rgb(0,50,8)",
"rgb(27,64,66)",
"rgb(69,67,178)",
"rgb(115,62,210)",
"rgb(155,50,104)",
"rgb(178,43,41)",
"rgb(180,51,34)",
"rgb(161,78,87)",
"rgb(124,117,187)",
"rgb(78,155,203)",
"rgb(34,178,85)",
"rgb(4,176,2)",
"rgb(9,152,27)",
"rgb(4,118,2)",
"rgb(34,92,85)",
"rgb(78,92,203)",
"rgb(124,127,187)",
"rgb(161,187,87)",
"rgb(180,248,34)",
"rgb(178,220,41)",
"rgb(155,217,104)",
"rgb(115,254,210)",
],
BlueGreenRedYellow: [
"rgb(0,0,0)",
"rgb(0,0,20)",
"rgb(0,0,41)",
"rgb(0,0,62)",
"rgb(0,25,83)",
"rgb(0,57,101)",
"rgb(0,87,101)",
"rgb(0,118,101)",
"rgb(0,150,101)",
"rgb(0,150,69)",
"rgb(0,148,37)",
"rgb(0,141,6)",
"rgb(60,120,0)",
"rgb(131,87,0)",
"rgb(180,25,0)",
"rgb(203,13,0)",
"rgb(208,36,0)",
"rgb(213,60,0)",
"rgb(219,83,0)",
"rgb(224,106,0)",
"rgb(229,129,0)",
"rgb(233,152,0)",
"rgb(238,176,0)",
"rgb(243,199,0)",
"rgb(248,222,0)",
"rgb(254,245,0)",
],
};
/* Const Init */
const colorschemes = {
Default: [
"#00bfff",
"#0000ff",
"#ff00ff",
"#ff0000",
"#ff8000",
"#ffff00",
"#80ff00",
],
Autumn: [
"rgb(255,0,0)",
"rgb(255,11,0)",
"rgb(255,20,0)",
"rgb(255,30,0)",
"rgb(255,41,0)",
"rgb(255,50,0)",
"rgb(255,60,0)",
"rgb(255,71,0)",
"rgb(255,80,0)",
"rgb(255,90,0)",
"rgb(255,101,0)",
"rgb(255,111,0)",
"rgb(255,120,0)",
"rgb(255,131,0)",
"rgb(255,141,0)",
"rgb(255,150,0)",
"rgb(255,161,0)",
"rgb(255,171,0)",
"rgb(255,180,0)",
"rgb(255,190,0)",
"rgb(255,201,0)",
"rgb(255,210,0)",
"rgb(255,220,0)",
"rgb(255,231,0)",
"rgb(255,240,0)",
"rgb(255,250,0)",
],
Beach: [
"rgb(0,252,0)",
"rgb(0,233,0)",
"rgb(0,212,0)",
"rgb(0,189,0)",
"rgb(0,169,0)",
"rgb(0,148,0)",
"rgb(0,129,4)",
"rgb(0,145,46)",
"rgb(0,162,90)",
"rgb(0,180,132)",
"rgb(29,143,136)",
"rgb(73,88,136)",
"rgb(115,32,136)",
"rgb(81,9,64)",
"rgb(124,51,23)",
"rgb(162,90,0)",
"rgb(194,132,0)",
"rgb(220,171,0)",
"rgb(231,213,0)",
"rgb(0,0,13)",
"rgb(0,0,55)",
"rgb(0,0,92)",
"rgb(0,0,127)",
"rgb(0,0,159)",
"rgb(0,0,196)",
"rgb(0,0,233)",
],
BlueRed: [
"rgb(0,0,131)",
"rgb(0,0,168)",
"rgb(0,0,208)",
"rgb(0,0,247)",
"rgb(0,27,255)",
"rgb(0,67,255)",
"rgb(0,108,255)",
"rgb(0,148,255)",
"rgb(0,187,255)",
"rgb(0,227,255)",
"rgb(8,255,247)",
"rgb(48,255,208)",
"rgb(87,255,168)",
"rgb(127,255,127)",
"rgb(168,255,87)",
"rgb(208,255,48)",
"rgb(247,255,8)",
"rgb(255,224,0)",
"rgb(255,183,0)",
"rgb(255,143,0)",
"rgb(255,104,0)",
"rgb(255,64,0)",
"rgb(255,23,0)",
"rgb(238,0,0)",
"rgb(194,0,0)",
"rgb(150,0,0)",
],
Rainbow: [
"rgb(125,0,255)",
"rgb(85,0,255)",
"rgb(39,0,255)",
"rgb(0,6,255)",
"rgb(0,51,255)",
"rgb(0,97,255)",
"rgb(0,141,255)",
"rgb(0,187,255)",
"rgb(0,231,255)",
"rgb(0,255,233)",
"rgb(0,255,189)",
"rgb(0,255,143)",
"rgb(0,255,99)",
"rgb(0,255,53)",
"rgb(0,255,9)",
"rgb(37,255,0)",
"rgb(83,255,0)",
"rgb(127,255,0)",
"rgb(173,255,0)",
"rgb(217,255,0)",
"rgb(255,248,0)",
"rgb(255,203,0)",
"rgb(255,159,0)",
"rgb(255,113,0)",
"rgb(255,69,0)",
"rgb(255,23,0)",
],
Binary: [
"rgb(215,215,215)",
"rgb(206,206,206)",
"rgb(196,196,196)",
"rgb(185,185,185)",
"rgb(176,176,176)",
"rgb(166,166,166)",
"rgb(155,155,155)",
"rgb(145,145,145)",
"rgb(136,136,136)",
"rgb(125,125,125)",
"rgb(115,115,115)",
"rgb(106,106,106)",
"rgb(95,95,95)",
"rgb(85,85,85)",
"rgb(76,76,76)",
"rgb(66,66,66)",
"rgb(55,55,55)",
"rgb(46,46,46)",
"rgb(36,36,36)",
"rgb(25,25,25)",
"rgb(16,16,16)",
"rgb(6,6,6)",
],
GistEarth: [
"rgb(0,0,0)",
"rgb(2,7,117)",
"rgb(9,30,118)",
"rgb(16,53,120)",
"rgb(23,73,122)",
"rgb(31,93,124)",
"rgb(39,110,125)",
"rgb(47,126,127)",
"rgb(51,133,119)",
"rgb(57,138,106)",
"rgb(62,145,94)",
"rgb(66,150,82)",
"rgb(74,157,71)",
"rgb(97,162,77)",
"rgb(121,168,83)",
"rgb(136,173,85)",
"rgb(153,176,88)",
"rgb(170,180,92)",
"rgb(185,182,94)",
"rgb(189,173,99)",
"rgb(192,164,101)",
"rgb(203,169,124)",
"rgb(215,178,149)",
"rgb(226,192,176)",
"rgb(238,212,204)",
"rgb(248,236,236)",
],
BlueWaves: [
"rgb(83,0,215)",
"rgb(43,6,108)",
"rgb(9,16,16)",
"rgb(8,32,25)",
"rgb(0,50,8)",
"rgb(27,64,66)",
"rgb(69,67,178)",
"rgb(115,62,210)",
"rgb(155,50,104)",
"rgb(178,43,41)",
"rgb(180,51,34)",
"rgb(161,78,87)",
"rgb(124,117,187)",
"rgb(78,155,203)",
"rgb(34,178,85)",
"rgb(4,176,2)",
"rgb(9,152,27)",
"rgb(4,118,2)",
"rgb(34,92,85)",
"rgb(78,92,203)",
"rgb(124,127,187)",
"rgb(161,187,87)",
"rgb(180,248,34)",
"rgb(178,220,41)",
"rgb(155,217,104)",
"rgb(115,254,210)",
],
BlueGreenRedYellow: [
"rgb(0,0,0)",
"rgb(0,0,20)",
"rgb(0,0,41)",
"rgb(0,0,62)",
"rgb(0,25,83)",
"rgb(0,57,101)",
"rgb(0,87,101)",
"rgb(0,118,101)",
"rgb(0,150,101)",
"rgb(0,150,69)",
"rgb(0,148,37)",
"rgb(0,141,6)",
"rgb(60,120,0)",
"rgb(131,87,0)",
"rgb(180,25,0)",
"rgb(203,13,0)",
"rgb(208,36,0)",
"rgb(213,60,0)",
"rgb(219,83,0)",
"rgb(224,106,0)",
"rgb(229,129,0)",
"rgb(233,152,0)",
"rgb(238,176,0)",
"rgb(243,199,0)",
"rgb(248,222,0)",
"rgb(254,245,0)",
],
};
// https://personal.sron.nl/~pault/
// https://tsitsul.in/blog/coloropt/
const cvdschemes = {
HighContrast: [
"rgb(221,170,51)",
"rgb(187,85,102)",
"rgb(0,68,136)",
"rgb(0,0,0)",
],
Bright: [
"rgb(68,119,170)",
"rgb(102,204,238)",
"rgb(34,136,51)",
"rgb(204,187,68)",
"rgb(238,102,119)",
"rgb(170,51,119)",
"rgb(187,187,187)",
],
Muted: [
"rgb(51,34,136)",
"rgb(136,204,238)",
"rgb(68,170,153)",
"rgb(17,119,51)",
"rgb(153,153,51)",
"rgb(221,204,119)",
"rgb(204,102,119)",
"rgb(136,34,85)",
"rgb(170,68,153)",
"rgb(221,221,221)",
],
NormalSixColor: [
"rgb(64,83,211)",
"rgb(221,179,16)",
"rgb(181,29,20)",
"rgb(0,190,255)",
"rgb(251,73,176)",
"rgb(0,178,93)",
"rgb(202,202,202)",
],
NormalTwelveColor: [
"rgb(235,172,35)",
"rgb(184,0,88)",
"rgb(0,140,249)",
"rgb(0,110,0)",
"rgb(0,187,173)",
"rgb(209,99,230)",
"rgb(178,69,2)",
"rgb(255,146,135)",
"rgb(89,84,214)",
"rgb(0,198,248)",
"rgb(135,133,0)",
"rgb(0,167,108)",
"rgb(189,189,189)",
]
}
// https://personal.sron.nl/~pault/
// https://tsitsul.in/blog/coloropt/
const cvdschemes = {
HighContrast: [
"rgb(221,170,51)",
"rgb(187,85,102)",
"rgb(0,68,136)",
"rgb(0,0,0)",
],
Bright: [
"rgb(68,119,170)",
"rgb(102,204,238)",
"rgb(34,136,51)",
"rgb(204,187,68)",
"rgb(238,102,119)",
"rgb(170,51,119)",
"rgb(187,187,187)",
],
Muted: [
"rgb(51,34,136)",
"rgb(136,204,238)",
"rgb(68,170,153)",
"rgb(17,119,51)",
"rgb(153,153,51)",
"rgb(221,204,119)",
"rgb(204,102,119)",
"rgb(136,34,85)",
"rgb(170,68,153)",
"rgb(221,221,221)",
],
NormalSixColor: [
"rgb(64,83,211)",
"rgb(221,179,16)",
"rgb(181,29,20)",
"rgb(0,190,255)",
"rgb(251,73,176)",
"rgb(0,178,93)",
"rgb(202,202,202)",
],
NormalTwelveColor: [
"rgb(235,172,35)",
"rgb(184,0,88)",
"rgb(0,140,249)",
"rgb(0,110,0)",
"rgb(0,187,173)",
"rgb(209,99,230)",
"rgb(178,69,2)",
"rgb(255,146,135)",
"rgb(89,84,214)",
"rgb(0,198,248)",
"rgb(135,133,0)",
"rgb(0,167,108)",
"rgb(189,189,189)",
]
}
</script>
<Row cols={1} class="p-2 g-2">
<!-- COLORSCHEME -->
<Col
><Card>
<form
id="colorscheme-form"
method="post"
action="/frontend/configuration/"
class="card-body"
<!-- COLORSCHEME -->
<Col>
<Card>
<form
id="colorscheme-form"
method="post"
action="/frontend/configuration/"
class="card-body"
>
<!-- Svelte 'class' directive only on DOMs directly, normal 'class="xxx"' does not work, so style-array it is. -->
<CardTitle
style="margin-bottom: 1em; display: flex; align-items: center;"
>
<!-- Svelte 'class' directive only on DOMs directly, normal 'class="xxx"' does not work, so style-array it is. -->
<CardTitle
style="margin-bottom: 1em; display: flex; align-items: center;"
>
<div>Color Scheme for Timeseries Plots {cbmode ? `(Color Blind Friendly Palettes)` : ``}</div>
{#if displayMessage && message.target == "cs"}<div
style="margin-left: auto; font-size: 0.9em;"
>
<code style="color: {message.color};" out:fade
>Update: {message.msg}</code
>
</div>{/if}
</CardTitle>
<input type="hidden" name="key" value="plot_general_colorscheme" />
<Table hover>
<tbody>
{#key activeRow}
{#each Object.entries(cbmode ? cvdschemes : colorschemes) as [name, rgbrow]}
<tr>
<th scope="col">{name}</th>
<td>
<input
type="radio"
name="value"
value={JSON.stringify(rgbrow)}
checked={activeRow == JSON.stringify(rgbrow)}
onclick={(e) => {
activeRow = JSON.stringify(rgbrow)
updateSetting(e, {
selector: "#colorscheme-form",
target: "cs",
});
}}
/>
</td>
<td>
{#each rgbrow as rgb}
<span class="color-dot" style="background-color: {rgb};"
></span>
{/each}
</td>
</tr>
{/each}
{/key}
</tbody>
</Table>
</form>
</Card></Col
>
<div>Color Scheme for Timeseries Plots {cbmode ? `(Color Blind Friendly Palettes)` : ``}</div>
{#if displayMessage && message.target == "cs"}
<div style="margin-left: auto; font-size: 0.9em;">
<code style="color: {message.color};" out:fade>
Update: {message.msg}
</code>
</div>
{/if}
</CardTitle>
<input type="hidden" name="key" value="plot_general_colorscheme" />
<Table hover>
<tbody>
{#key activeRow}
{#each Object.entries(cbmode ? cvdschemes : colorschemes) as [name, rgbrow]}
<tr>
<th scope="col">{name}</th>
<td>
<input
type="radio"
name="value"
value={JSON.stringify(rgbrow)}
checked={activeRow == JSON.stringify(rgbrow)}
onclick={(e) => {
activeRow = JSON.stringify(rgbrow)
updateSetting(e, {
selector: "#colorscheme-form",
target: "cs",
});
}}
/>
</td>
<td>
{#each rgbrow as rgb}
<span class="color-dot" style="background-color: {rgb};"></span>
{/each}
</td>
</tr>
{/each}
{/key}
</tbody>
</Table>
</form>
</Card>
</Col>
</Row>
<style>
.color-dot {
.color-dot {
margin-left: 1px;
height: 12px;
width: 12px;
border-radius: 50%;
display: inline-block;
}
}
</style>

View File

@@ -1,224 +1,222 @@
<!--
@component Plot render option selection for users
@component Plot render option selection for users
Properties:
- `config Object`: Current cc-config
- `message Object`: Message to display on success or error
- `displayMessage Bool`: If to display message content
Properties:
- `config Object`: Current cc-config
- `message Object`: Message to display on success or error [Bindable]
- `displayMessage Bool`: If to display message content [Bindable]
- `updateSetting Func`: The callback function to apply current option selection
-->
Events:
- `update-config, {selector: String, target: String}`: Trigger upstream update of the config option
-->
<script>
import {
Button,
Row,
Col,
Card,
CardTitle,
} from "@sveltestrap/sveltestrap";
import { fade } from "svelte/transition";
<script>
import {
Button,
Row,
Col,
Card,
CardTitle,
} from "@sveltestrap/sveltestrap";
import { fade } from "svelte/transition";
/* Svelte 5 Props */
let {
config,
message = $bindable(),
displayMessage = $bindable(),
updateSetting
} = $props();
/* Svelte 5 Props */
let {
config,
message = $bindable(),
displayMessage = $bindable(),
updateSetting
} = $props();
</script>
<Row cols={3} class="p-2 g-2">
<!-- LINE WIDTH -->
<Col
><Card class="h-100">
<form
id="line-width-form"
method="post"
action="/frontend/configuration/"
class="card-body"
onsubmit={(e) => updateSetting(e, {
selector: "#line-width-form",
target: "lw",
})}
<!-- LINE WIDTH -->
<Col>
<Card class="h-100">
<form
id="line-width-form"
method="post"
action="/frontend/configuration/"
class="card-body"
onsubmit={(e) => updateSetting(e, {
selector: "#line-width-form",
target: "lw",
})}
>
<!-- Svelte 'class' directive only on DOMs directly, normal 'class="xxx"' does not work, so style-array it is. -->
<CardTitle
style="margin-bottom: 1em; display: flex; align-items: center;"
>
<!-- Svelte 'class' directive only on DOMs directly, normal 'class="xxx"' does not work, so style-array it is. -->
<CardTitle
style="margin-bottom: 1em; display: flex; align-items: center;"
>
<div>Line Width</div>
<!-- Expand If-Clause for clarity once -->
{#if displayMessage && message.target == "lw"}
<div style="margin-left: auto; font-size: 0.9em;">
<code style="color: {message.color};" out:fade>
Update: {message.msg}
</code>
</div>
<div>Line Width</div>
<!-- Expand If-Clause for clarity once -->
{#if displayMessage && message.target == "lw"}
<div style="margin-left: auto; font-size: 0.9em;">
<code style="color: {message.color};" out:fade>
Update: {message.msg}
</code>
</div>
{/if}
</CardTitle>
<input type="hidden" name="key" value="plot_general_lineWidth" />
<div class="mb-3">
<label for="value" class="form-label">Line Width</label>
<input
type="number"
class="form-control"
id="lwvalue"
name="value"
aria-describedby="lineWidthHelp"
value={config.plot_general_lineWidth}
min="1"
/>
<div id="lineWidthHelp" class="form-text">
Width of the lines in the timeseries plots.
</div>
</div>
<Button color="primary" type="submit">Submit</Button>
</form>
</Card>
</Col>
<!-- PLOTS PER ROW -->
<Col>
<Card class="h-100">
<form
id="plots-per-row-form"
method="post"
action="/frontend/configuration/"
class="card-body"
onsubmit={(e) => updateSetting(e, {
selector: "#plots-per-row-form",
target: "ppr",
})}
>
<!-- Svelte 'class' directive only on DOMs directly, normal 'class="xxx"' does not work, so style-array it is. -->
<CardTitle
style="margin-bottom: 1em; display: flex; align-items: center;"
>
<div>Plots per Row</div>
{#if displayMessage && message.target == "ppr"}
<div style="margin-left: auto; font-size: 0.9em;">
<code style="color: {message.color};" out:fade>
Update: {message.msg}
</code>
</div>
{/if}
</CardTitle>
<input type="hidden" name="key" value="plot_view_plotsPerRow" />
<div class="mb-3">
<label for="value" class="form-label">Plots per Row</label>
<input
type="number"
class="form-control"
id="pprvalue"
name="value"
aria-describedby="plotsperrowHelp"
value={config.plot_view_plotsPerRow}
min="1"
/>
<div id="plotsperrowHelp" class="form-text">
How many plots to show next to each other on pages such as
/monitoring/job/, /monitoring/system/...
</div>
</div>
<Button color="primary" type="submit">Submit</Button>
</form>
</Card>
</Col>
<!-- BACKGROUND -->
<Col class="d-flex justify-content-between">
<Card class="h-100" style="width: 49%;">
<form
id="backgrounds-form"
method="post"
action="/frontend/configuration/"
class="card-body"
onsubmit={(e) => updateSetting(e, {
selector: "#backgrounds-form",
target: "bg",
})}
>
<!-- Svelte 'class' directive only on DOMs directly, normal 'class="xxx"' does not work, so style-array it is. -->
<CardTitle
style="margin-bottom: 1em; display: flex; align-items: center;"
>
<div>Colored Backgrounds</div>
{#if displayMessage && message.target == "bg"}
<div style="margin-left: auto; font-size: 0.9em;">
<code style="color: {message.color};" out:fade>
Update: {message.msg}
</code>
</div>
{/if}
</CardTitle>
<input type="hidden" name="key" value="plot_general_colorBackground" />
<div class="mb-3">
<div>
{#if config.plot_general_colorBackground}
<input type="radio" id="colb-true-checked" name="value" value="true" checked />
{:else}
<input type="radio" id="colb-true" name="value" value="true" />
{/if}
</CardTitle>
<input type="hidden" name="key" value="plot_general_lineWidth" />
<div class="mb-3">
<label for="value" class="form-label">Line Width</label>
<input
type="number"
class="form-control"
id="lwvalue"
name="value"
aria-describedby="lineWidthHelp"
value={config.plot_general_lineWidth}
min="1"
/>
<div id="lineWidthHelp" class="form-text">
Width of the lines in the timeseries plots.
</div>
<label for="true">Yes</label>
</div>
<Button color="primary" type="submit">Submit</Button>
</form>
</Card></Col
>
<!-- PLOTS PER ROW -->
<Col
><Card class="h-100">
<form
id="plots-per-row-form"
method="post"
action="/frontend/configuration/"
class="card-body"
onsubmit={(e) => updateSetting(e, {
selector: "#plots-per-row-form",
target: "ppr",
})}
<div>
{#if config.plot_general_colorBackground}
<input type="radio" id="colb-false" name="value" value="false" />
{:else}
<input type="radio" id="colb-false-checked" name="value" value="false" checked />
{/if}
<label for="false">No</label>
</div>
</div>
<Button color="primary" type="submit">Submit</Button>
</form>
</Card>
<Card class="h-100" style="width: 49%;">
<form
id="colorblindmode-form"
method="post"
action="/frontend/configuration/"
class="card-body"
onsubmit={(e) => updateSetting(e, {
selector: "#colorblindmode-form",
target: "cbm",
})}
>
<!-- Svelte 'class' directive only on DOMs directly, normal 'class="xxx"' does not work, so style-array it is. -->
<CardTitle
style="margin-bottom: 1em; display: flex; align-items: center;"
>
<!-- Svelte 'class' directive only on DOMs directly, normal 'class="xxx"' does not work, so style-array it is. -->
<CardTitle
style="margin-bottom: 1em; display: flex; align-items: center;"
>
<div>Plots per Row</div>
{#if displayMessage && message.target == "ppr"}<div
style="margin-left: auto; font-size: 0.9em;"
>
<code style="color: {message.color};" out:fade
>Update: {message.msg}</code
>
</div>{/if}
</CardTitle>
<input type="hidden" name="key" value="plot_view_plotsPerRow" />
<div class="mb-3">
<label for="value" class="form-label">Plots per Row</label>
<input
type="number"
class="form-control"
id="pprvalue"
name="value"
aria-describedby="plotsperrowHelp"
value={config.plot_view_plotsPerRow}
min="1"
/>
<div id="plotsperrowHelp" class="form-text">
How many plots to show next to each other on pages such as
/monitoring/job/, /monitoring/system/...
<div>Color Blind Mode</div>
{#if displayMessage && message.target == "cbm"}
<div style="margin-left: auto; font-size: 0.9em;">
<code style="color: {message.color};" out:fade>
Update: {message.msg}
</code>
</div>
{/if}
</CardTitle>
<input type="hidden" name="key" value="plot_general_colorblindMode" />
<div class="mb-3">
<div>
{#if config?.plot_general_colorblindMode}
<input type="radio" id="cbm-true-checked" name="value" value="true" checked />
{:else}
<input type="radio" id="cbm-true" name="value" value="true" />
{/if}
<label for="true">Yes</label>
</div>
<Button color="primary" type="submit">Submit</Button>
</form>
</Card></Col
>
<!-- BACKGROUND -->
<Col class="d-flex justify-content-between"
><Card class="h-100" style="width: 49%;">
<form
id="backgrounds-form"
method="post"
action="/frontend/configuration/"
class="card-body"
onsubmit={(e) => updateSetting(e, {
selector: "#backgrounds-form",
target: "bg",
})}
>
<!-- Svelte 'class' directive only on DOMs directly, normal 'class="xxx"' does not work, so style-array it is. -->
<CardTitle
style="margin-bottom: 1em; display: flex; align-items: center;"
>
<div>Colored Backgrounds</div>
{#if displayMessage && message.target == "bg"}<div
style="margin-left: auto; font-size: 0.9em;"
>
<code style="color: {message.color};" out:fade
>Update: {message.msg}</code
>
</div>{/if}
</CardTitle>
<input type="hidden" name="key" value="plot_general_colorBackground" />
<div class="mb-3">
<div>
{#if config.plot_general_colorBackground}
<input type="radio" id="colb-true-checked" name="value" value="true" checked />
{:else}
<input type="radio" id="colb-true" name="value" value="true" />
{/if}
<label for="true">Yes</label>
</div>
<div>
{#if config.plot_general_colorBackground}
<input type="radio" id="colb-false" name="value" value="false" />
{:else}
<input type="radio" id="colb-false-checked" name="value" value="false" checked />
{/if}
<label for="false">No</label>
</div>
<div>
{#if config?.plot_general_colorblindMode}
<input type="radio" id="cbm-false" name="value" value="false" />
{:else}
<input type="radio" id="cbm-false-checked" name="value" value="false" checked />
{/if}
<label for="false">No</label>
</div>
<Button color="primary" type="submit">Submit</Button>
</form>
</Card>
<Card class="h-100" style="width: 49%;">
<form
id="colorblindmode-form"
method="post"
action="/frontend/configuration/"
class="card-body"
onsubmit={(e) => updateSetting(e, {
selector: "#colorblindmode-form",
target: "cbm",
})}
>
<!-- Svelte 'class' directive only on DOMs directly, normal 'class="xxx"' does not work, so style-array it is. -->
<CardTitle
style="margin-bottom: 1em; display: flex; align-items: center;"
>
<div>Color Blind Mode</div>
{#if displayMessage && message.target == "cbm"}<div
style="margin-left: auto; font-size: 0.9em;"
>
<code style="color: {message.color};" out:fade
>Update: {message.msg}</code
>
</div>{/if}
</CardTitle>
<input type="hidden" name="key" value="plot_general_colorblindMode" />
<div class="mb-3">
<div>
{#if config?.plot_general_colorblindMode}
<input type="radio" id="cbm-true-checked" name="value" value="true" checked />
{:else}
<input type="radio" id="cbm-true" name="value" value="true" />
{/if}
<label for="true">Yes</label>
</div>
<div>
{#if config?.plot_general_colorblindMode}
<input type="radio" id="cbm-false" name="value" value="false" />
{:else}
<input type="radio" id="cbm-false-checked" name="value" value="false" checked />
{/if}
<label for="false">No</label>
</div>
</div>
<Button color="primary" type="submit">Submit</Button>
</form>
</Card>
</Col>
</div>
<Button color="primary" type="submit">Submit</Button>
</form>
</Card>
</Col>
</Row>

View File

@@ -1,82 +1,80 @@
<!--
@component General option selection for users
@component General option selection for users
Properties:
- `config Object`: Current cc-config
- `message Object`: Message to display on success or error
- `displayMessage Bool`: If to display message content
- `username String!`: Empty string if auth. is disabled, otherwise the username as string
- `isApi Bool!`: Is currently logged in user api authority
Properties:
- `config Object`: Current cc-config
- `message Object`: Message to display on success or error [Bindable]
- `displayMessage Bool`: If to display message content [Bindable]
- `username String!`: Empty string if auth. is disabled, otherwise the username as string
- `isApi Bool!`: Is currently logged in user api authority
- `updateSetting Func`: The callback function to apply current option selection
-->
Events:
- `update-config, {selector: String, target: String}`: Trigger upstream update of the config option
-->
<script>
import {
Button,
Row,
Col,
Card,
CardTitle,
CardBody
} from "@sveltestrap/sveltestrap";
import { fade } from "svelte/transition";
import { fetchJwt } from "../../generic/utils.js";
import {
Button,
Row,
Col,
Card,
CardTitle,
CardBody
} from "@sveltestrap/sveltestrap";
import { fade } from "svelte/transition";
import { fetchJwt } from "../../generic/utils.js";
/* Svelte 5 Props */
let {
config,
message = $bindable(),
displayMessage = $bindable(),
username,
isApi,
updateSetting
} = $props();
/* Svelte 5 Props */
let {
config,
message = $bindable(),
displayMessage = $bindable(),
username,
isApi,
updateSetting
} = $props();
/* State Init */
let jwt = $state("");
let displayCheck = $state(false);
/* State Init */
let jwt = $state("");
let displayCheck = $state(false);
/* Functions */
function getUserJwt(username) {
if (username) {
const p = fetchJwt(username);
p.then((content) => {
jwt = content
}).catch((error) => {
console.error(`Could not get JWT: ${error}`);
});
}
/* Functions */
function getUserJwt(username) {
if (username) {
const p = fetchJwt(username);
p.then((content) => {
jwt = content
}).catch((error) => {
console.error(`Could not get JWT: ${error}`);
});
}
}
function clipJwt() {
displayCheck = true;
// Navigator clipboard api needs a secure context (https)
if (navigator.clipboard && window.isSecureContext) {
navigator.clipboard
.writeText(jwt)
.catch((reason) => console.error(reason));
} else {
// Workaround: Create, Fill, And Copy Content of Textarea
const textArea = document.createElement("textarea");
textArea.value = jwt;
textArea.style.position = "absolute";
textArea.style.left = "-999999px";
document.body.prepend(textArea);
textArea.select();
try {
document.execCommand('copy');
} catch (error) {
console.error(error);
} finally {
textArea.remove();
}
function clipJwt() {
displayCheck = true;
// Navigator clipboard api needs a secure context (https)
if (navigator.clipboard && window.isSecureContext) {
navigator.clipboard
.writeText(jwt)
.catch((reason) => console.error(reason));
} else {
// Workaround: Create, Fill, And Copy Content of Textarea
const textArea = document.createElement("textarea");
textArea.value = jwt;
textArea.style.position = "absolute";
textArea.style.left = "-999999px";
document.body.prepend(textArea);
textArea.select();
try {
document.execCommand('copy');
} catch (error) {
console.error(error);
} finally {
textArea.remove();
}
setTimeout(function () {
displayCheck = false;
}, 1000);
}
setTimeout(function () {
displayCheck = false;
}, 1000);
}
</script>
<Row cols={isApi ? 3 : 1} class="p-2 g-2">
@@ -133,41 +131,41 @@
{#if isApi}
<!-- USER-JWT BTN -->
<Col>
<Card class="h-100">
<CardBody>
<CardTitle>Generate JWT</CardTitle>
{#if jwt}
<Button color="secondary" onclick={() => clipJwt()}>
Copy JWT to Clipboard
</Button>
<p class="mt-2">
Your token is displayed on the right. Press this button to copy it to the clipboard.
</p>
{#if displayCheck}
<p class="mt-2">
<span class="text-success">Copied!</span>
</p>
{/if}
{:else}
<Button color="success" onclick={() => getUserJwt(username)}>
Generate JWT for '{username}'
</Button>
<p class="mt-2">
Generate a JSON Web Token for use with the ClusterCockpit REST-API endpoints.
</p>
{/if}
</CardBody>
</Card>
<Card class="h-100">
<CardBody>
<CardTitle>Generate JWT</CardTitle>
{#if jwt}
<Button color="secondary" onclick={() => clipJwt()}>
Copy JWT to Clipboard
</Button>
<p class="mt-2">
Your token is displayed on the right. Press this button to copy it to the clipboard.
</p>
{#if displayCheck}
<p class="mt-2">
<span class="text-success">Copied!</span>
</p>
{/if}
{:else}
<Button color="success" onclick={() => getUserJwt(username)}>
Generate JWT for '{username}'
</Button>
<p class="mt-2">
Generate a JSON Web Token for use with the ClusterCockpit REST-API endpoints.
</p>
{/if}
</CardBody>
</Card>
</Col>
<!-- USER-JWT RES -->
<Col>
<Card class="h-100">
<CardBody>
<CardTitle>Display JWT</CardTitle>
<textarea cols="32" rows="5" readonly>{jwt ? jwt : 'Press "Gen. JWT" to request token ...'}</textarea>
</CardBody>
</Card>
<Card class="h-100">
<CardBody>
<CardTitle>Display JWT</CardTitle>
<textarea cols="32" rows="5" readonly>{jwt ? jwt : 'Press "Gen. JWT" to request token ...'}</textarea>
</CardBody>
</Card>
</Col>
{/if}
</Row>