mirror of
https://github.com/ClusterCockpit/cc-backend
synced 2025-07-27 22:56:08 +02:00
Upgrade frontend dependencies
Change to most recent @sveltestrap/sveltestrap Reformat with Svelte LSP
This commit is contained in:
@@ -1,54 +1,53 @@
|
||||
<script>
|
||||
import { Row, Col } from 'sveltestrap'
|
||||
import { onMount } from 'svelte'
|
||||
import EditRole from './admin/EditRole.svelte'
|
||||
import EditProject from './admin/EditProject.svelte'
|
||||
import AddUser from './admin/AddUser.svelte'
|
||||
import ShowUsers from './admin/ShowUsers.svelte'
|
||||
import Options from './admin/Options.svelte'
|
||||
import { Row, Col } from "@sveltestrap/sveltestrap";
|
||||
import { onMount } from "svelte";
|
||||
import EditRole from "./admin/EditRole.svelte";
|
||||
import EditProject from "./admin/EditProject.svelte";
|
||||
import AddUser from "./admin/AddUser.svelte";
|
||||
import ShowUsers from "./admin/ShowUsers.svelte";
|
||||
import Options from "./admin/Options.svelte";
|
||||
|
||||
let users = []
|
||||
let roles = []
|
||||
let users = [];
|
||||
let roles = [];
|
||||
|
||||
function getUserList() {
|
||||
fetch('/api/users/?via-ldap=false¬-just-user=true')
|
||||
.then(res => res.json())
|
||||
.then(usersRaw => {
|
||||
users = usersRaw
|
||||
})
|
||||
}
|
||||
function getUserList() {
|
||||
fetch("/api/users/?via-ldap=false¬-just-user=true")
|
||||
.then((res) => res.json())
|
||||
.then((usersRaw) => {
|
||||
users = usersRaw;
|
||||
});
|
||||
}
|
||||
|
||||
function getValidRoles() {
|
||||
fetch('/api/roles/')
|
||||
.then(res => res.json())
|
||||
.then(rolesRaw => {
|
||||
roles = rolesRaw
|
||||
})
|
||||
}
|
||||
function getValidRoles() {
|
||||
fetch("/api/roles/")
|
||||
.then((res) => res.json())
|
||||
.then((rolesRaw) => {
|
||||
roles = rolesRaw;
|
||||
});
|
||||
}
|
||||
|
||||
function initAdmin() {
|
||||
getUserList()
|
||||
getValidRoles()
|
||||
}
|
||||
|
||||
onMount(() => initAdmin())
|
||||
function initAdmin() {
|
||||
getUserList();
|
||||
getValidRoles();
|
||||
}
|
||||
|
||||
onMount(() => initAdmin());
|
||||
</script>
|
||||
|
||||
<Row cols={2} class="p-2 g-2" >
|
||||
<Col class="mb-1">
|
||||
<AddUser roles={roles} on:reload={getUserList}/>
|
||||
</Col>
|
||||
<Col class="mb-1">
|
||||
<ShowUsers on:reload={getUserList} bind:users={users}/>
|
||||
</Col>
|
||||
<Col>
|
||||
<EditRole roles={roles} on:reload={getUserList}/>
|
||||
</Col>
|
||||
<Col>
|
||||
<EditProject on:reload={getUserList}/>
|
||||
</Col>
|
||||
<Col>
|
||||
<Options/>
|
||||
</Col>
|
||||
<Row cols={2} class="p-2 g-2">
|
||||
<Col class="mb-1">
|
||||
<AddUser {roles} on:reload={getUserList} />
|
||||
</Col>
|
||||
<Col class="mb-1">
|
||||
<ShowUsers on:reload={getUserList} bind:users />
|
||||
</Col>
|
||||
<Col>
|
||||
<EditRole {roles} on:reload={getUserList} />
|
||||
</Col>
|
||||
<Col>
|
||||
<EditProject on:reload={getUserList} />
|
||||
</Col>
|
||||
<Col>
|
||||
<Options />
|
||||
</Col>
|
||||
</Row>
|
||||
|
@@ -1,171 +1,498 @@
|
||||
<script>
|
||||
import { Button, Table, Row, Col, Card, CardBody, CardTitle } from 'sveltestrap'
|
||||
import { fade } from 'svelte/transition'
|
||||
import {
|
||||
Button,
|
||||
Table,
|
||||
Row,
|
||||
Col,
|
||||
Card,
|
||||
CardTitle,
|
||||
} from "@sveltestrap/sveltestrap";
|
||||
import { fade } from "svelte/transition";
|
||||
|
||||
export let config
|
||||
export let config;
|
||||
|
||||
let message = {msg: '', target: '', color: '#d63384'}
|
||||
let displayMessage = false
|
||||
let message = { msg: "", target: "", color: "#d63384" };
|
||||
let displayMessage = false;
|
||||
|
||||
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 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)",
|
||||
],
|
||||
};
|
||||
|
||||
async function handleSettingSubmit(selector, target) {
|
||||
let form = document.querySelector(selector)
|
||||
let formData = new FormData(form)
|
||||
try {
|
||||
const res = await fetch(form.action, { method: 'POST', body: formData });
|
||||
if (res.ok) {
|
||||
let text = await res.text()
|
||||
popMessage(text, target, '#048109')
|
||||
} else {
|
||||
let text = await res.text()
|
||||
// console.log(res.statusText)
|
||||
throw new Error('Response Code ' + res.status + '-> ' + text)
|
||||
}
|
||||
} catch (err) {
|
||||
popMessage(err, target, '#d63384')
|
||||
async function handleSettingSubmit(selector, target) {
|
||||
let form = document.querySelector(selector);
|
||||
let formData = new FormData(form);
|
||||
try {
|
||||
const res = await fetch(form.action, { method: "POST", body: formData });
|
||||
if (res.ok) {
|
||||
let text = await res.text();
|
||||
popMessage(text, target, "#048109");
|
||||
} else {
|
||||
let text = await res.text();
|
||||
// console.log(res.statusText)
|
||||
throw new Error("Response Code " + res.status + "-> " + text);
|
||||
}
|
||||
|
||||
return false
|
||||
} catch (err) {
|
||||
popMessage(err, target, "#d63384");
|
||||
}
|
||||
|
||||
function popMessage(response, restarget, rescolor) {
|
||||
message = {msg: response, target: restarget, color: rescolor}
|
||||
displayMessage = true
|
||||
setTimeout(function() {
|
||||
displayMessage = false
|
||||
}, 3500)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function popMessage(response, restarget, rescolor) {
|
||||
message = { msg: response, target: restarget, color: rescolor };
|
||||
displayMessage = true;
|
||||
setTimeout(function () {
|
||||
displayMessage = false;
|
||||
}, 3500);
|
||||
}
|
||||
</script>
|
||||
|
||||
<Row cols={3} class="p-2 g-2">
|
||||
<!-- LINE WIDTH -->
|
||||
<Col><Card class="h-100">
|
||||
<!-- Important: Function with arguments needs to be event-triggered like on:submit={() => functionName('Some','Args')} OR no arguments and like this: on:submit={functionName} -->
|
||||
<form id="line-width-form" method="post" action="/api/configuration/" class="card-body" on:submit|preventDefault={() => handleSettingSubmit('#line-width-form', '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;">
|
||||
<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>
|
||||
<!-- LINE WIDTH -->
|
||||
<Col
|
||||
><Card class="h-100">
|
||||
<!-- Important: Function with arguments needs to be event-triggered like on:submit={() => functionName('Some','Args')} OR no arguments and like this: on:submit={functionName} -->
|
||||
<form
|
||||
id="line-width-form"
|
||||
method="post"
|
||||
action="/api/configuration/"
|
||||
class="card-body"
|
||||
on:submit|preventDefault={() =>
|
||||
handleSettingSubmit("#line-width-form", "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;"
|
||||
>
|
||||
<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>
|
||||
<Button color="primary" type="submit">Submit</Button>
|
||||
</form>
|
||||
</Card></Col>
|
||||
{/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="/api/configuration/" class="card-body" on:submit|preventDefault={() => handleSettingSubmit('#plots-per-row-form', '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>
|
||||
<!-- PLOTS PER ROW -->
|
||||
<Col
|
||||
><Card class="h-100">
|
||||
<form
|
||||
id="plots-per-row-form"
|
||||
method="post"
|
||||
action="/api/configuration/"
|
||||
class="card-body"
|
||||
on:submit|preventDefault={() =>
|
||||
handleSettingSubmit("#plots-per-row-form", "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><Card class="h-100">
|
||||
<form id="backgrounds-form" method="post" action="/api/configuration/" class="card-body" on:submit|preventDefault={() => handleSettingSubmit('#backgrounds-form', '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="true" name="value" value="true" checked/>
|
||||
{:else}
|
||||
<input type="radio" id="true" name="value" value="true" />
|
||||
{/if}
|
||||
<label for="true">Yes</label>
|
||||
</div>
|
||||
<div>
|
||||
{#if config.plot_general_colorBackground}
|
||||
<input type="radio" id="false" name="value" value="false" />
|
||||
{:else}
|
||||
<input type="radio" id="false" name="value" value="false" checked/>
|
||||
{/if}
|
||||
<label for="false">No</label>
|
||||
</div>
|
||||
</div>
|
||||
<Button color="primary" type="submit">Submit</Button>
|
||||
</form>
|
||||
</Card></Col>
|
||||
<!-- BACKGROUND -->
|
||||
<Col
|
||||
><Card class="h-100">
|
||||
<form
|
||||
id="backgrounds-form"
|
||||
method="post"
|
||||
action="/api/configuration/"
|
||||
class="card-body"
|
||||
on:submit|preventDefault={() =>
|
||||
handleSettingSubmit("#backgrounds-form", "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="true" name="value" value="true" checked />
|
||||
{:else}
|
||||
<input type="radio" id="true" name="value" value="true" />
|
||||
{/if}
|
||||
<label for="true">Yes</label>
|
||||
</div>
|
||||
<div>
|
||||
{#if config.plot_general_colorBackground}
|
||||
<input type="radio" id="false" name="value" value="false" />
|
||||
{:else}
|
||||
<input
|
||||
type="radio"
|
||||
id="false"
|
||||
name="value"
|
||||
value="false"
|
||||
checked
|
||||
/>
|
||||
{/if}
|
||||
<label for="false">No</label>
|
||||
</div>
|
||||
</div>
|
||||
<Button color="primary" type="submit">Submit</Button>
|
||||
</form>
|
||||
</Card></Col
|
||||
>
|
||||
</Row>
|
||||
|
||||
<Row cols={1} class="p-2 g-2">
|
||||
<!-- COLORSCHEME -->
|
||||
<Col><Card>
|
||||
<form id="colorscheme-form" method="post" action="/api/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;">
|
||||
<div>Color Scheme for Timeseries Plots</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>
|
||||
{#each Object.entries(colorschemes) as [name, rgbrow]}
|
||||
<tr>
|
||||
<th scope="col">{name}</th>
|
||||
<td>
|
||||
{#if rgbrow.join(',') == config.plot_general_colorscheme}
|
||||
<input type="radio" name="value" value={JSON.stringify(rgbrow)} checked on:click={() => handleSettingSubmit("#colorscheme-form", "cs")}/>
|
||||
{:else}
|
||||
<input type="radio" name="value" value={JSON.stringify(rgbrow)} on:click={() => handleSettingSubmit("#colorscheme-form", "cs")}/>
|
||||
{/if}
|
||||
</td>
|
||||
<td>
|
||||
{#each rgbrow as rgb}
|
||||
<span class="color-dot" style="background-color: {rgb};"></span>
|
||||
{/each}
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</Table>
|
||||
</form>
|
||||
</Card></Col>
|
||||
<!-- COLORSCHEME -->
|
||||
<Col
|
||||
><Card>
|
||||
<form
|
||||
id="colorscheme-form"
|
||||
method="post"
|
||||
action="/api/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;"
|
||||
>
|
||||
<div>Color Scheme for Timeseries Plots</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>
|
||||
{#each Object.entries(colorschemes) as [name, rgbrow]}
|
||||
<tr>
|
||||
<th scope="col">{name}</th>
|
||||
<td>
|
||||
{#if rgbrow.join(",") == config.plot_general_colorscheme}
|
||||
<input
|
||||
type="radio"
|
||||
name="value"
|
||||
value={JSON.stringify(rgbrow)}
|
||||
checked
|
||||
on:click={() =>
|
||||
handleSettingSubmit("#colorscheme-form", "cs")}
|
||||
/>
|
||||
{:else}
|
||||
<input
|
||||
type="radio"
|
||||
name="value"
|
||||
value={JSON.stringify(rgbrow)}
|
||||
on:click={() =>
|
||||
handleSettingSubmit("#colorscheme-form", "cs")}
|
||||
/>
|
||||
{/if}
|
||||
</td>
|
||||
<td>
|
||||
{#each rgbrow as rgb}
|
||||
<span class="color-dot" style="background-color: {rgb};"
|
||||
></span>
|
||||
{/each}
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</Table>
|
||||
</form>
|
||||
</Card></Col
|
||||
>
|
||||
</Row>
|
||||
|
||||
<style>
|
||||
.color-dot {
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
}
|
||||
.color-dot {
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
|
@@ -1,103 +1,156 @@
|
||||
<script>
|
||||
import { Button, Card, CardTitle } from 'sveltestrap'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { fade } from 'svelte/transition'
|
||||
import { Button, Card, CardTitle } from "@sveltestrap/sveltestrap";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import { fade } from "svelte/transition";
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
let message = {msg: '', color: '#d63384'}
|
||||
let displayMessage = false
|
||||
let message = { msg: "", color: "#d63384" };
|
||||
let displayMessage = false;
|
||||
|
||||
export let roles = []
|
||||
export let roles = [];
|
||||
|
||||
async function handleUserSubmit() {
|
||||
let form = document.querySelector('#create-user-form')
|
||||
let formData = new FormData(form)
|
||||
async function handleUserSubmit() {
|
||||
let form = document.querySelector("#create-user-form");
|
||||
let formData = new FormData(form);
|
||||
|
||||
try {
|
||||
const res = await fetch(form.action, { method: 'POST', body: formData });
|
||||
if (res.ok) {
|
||||
let text = await res.text()
|
||||
popMessage(text, '#048109')
|
||||
reloadUserList()
|
||||
form.reset()
|
||||
} else {
|
||||
let text = await res.text()
|
||||
// console.log(res.statusText)
|
||||
throw new Error('Response Code ' + res.status + '-> ' + text)
|
||||
}
|
||||
} catch (err) {
|
||||
popMessage(err, '#d63384')
|
||||
}
|
||||
try {
|
||||
const res = await fetch(form.action, { method: "POST", body: formData });
|
||||
if (res.ok) {
|
||||
let text = await res.text();
|
||||
popMessage(text, "#048109");
|
||||
reloadUserList();
|
||||
form.reset();
|
||||
} else {
|
||||
let text = await res.text();
|
||||
// console.log(res.statusText)
|
||||
throw new Error("Response Code " + res.status + "-> " + text);
|
||||
}
|
||||
} catch (err) {
|
||||
popMessage(err, "#d63384");
|
||||
}
|
||||
}
|
||||
|
||||
function popMessage(response, rescolor) {
|
||||
message = {msg: response, color: rescolor}
|
||||
displayMessage = true
|
||||
setTimeout(function() {
|
||||
displayMessage = false
|
||||
}, 3500)
|
||||
}
|
||||
function popMessage(response, rescolor) {
|
||||
message = { msg: response, color: rescolor };
|
||||
displayMessage = true;
|
||||
setTimeout(function () {
|
||||
displayMessage = false;
|
||||
}, 3500);
|
||||
}
|
||||
|
||||
function reloadUserList() {
|
||||
dispatch('reload')
|
||||
}
|
||||
function reloadUserList() {
|
||||
dispatch("reload");
|
||||
}
|
||||
</script>
|
||||
|
||||
<Card>
|
||||
<form id="create-user-form" method="post" action="/api/users/" class="card-body" on:submit|preventDefault={handleUserSubmit}>
|
||||
<CardTitle class="mb-3">Create User</CardTitle>
|
||||
<div class="mb-3">
|
||||
<label for="username" class="form-label">Username (ID)</label>
|
||||
<input type="text" class="form-control" id="username" name="username" aria-describedby="usernameHelp"/>
|
||||
<div id="usernameHelp" class="form-text">Must be unique.</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">Password</label>
|
||||
<input type="password" class="form-control" id="password" name="password" aria-describedby="passwordHelp"/>
|
||||
<div id="passwordHelp" class="form-text">Only API users are allowed to have a blank password. Users with a blank password can only authenticate via Tokens.</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">Project</label>
|
||||
<input type="text" class="form-control" id="project" name="project" aria-describedby="projectHelp"/>
|
||||
<div id="projectHelp" class="form-text">Only Manager users can have a project. Allows to inspect jobs and users of given project.</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">Name</label>
|
||||
<input type="text" class="form-control" id="name" name="name" aria-describedby="nameHelp"/>
|
||||
<div id="nameHelp" class="form-text">Optional, can be blank.</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">Email address</label>
|
||||
<input type="email" class="form-control" id="email" name="email" aria-describedby="emailHelp"/>
|
||||
<div id="emailHelp" class="form-text">Optional, can be blank.</div>
|
||||
</div>
|
||||
<form
|
||||
id="create-user-form"
|
||||
method="post"
|
||||
action="/api/users/"
|
||||
class="card-body"
|
||||
on:submit|preventDefault={handleUserSubmit}
|
||||
>
|
||||
<CardTitle class="mb-3">Create User</CardTitle>
|
||||
<div class="mb-3">
|
||||
<label for="username" class="form-label">Username (ID)</label>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="username"
|
||||
name="username"
|
||||
aria-describedby="usernameHelp"
|
||||
/>
|
||||
<div id="usernameHelp" class="form-text">Must be unique.</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">Password</label>
|
||||
<input
|
||||
type="password"
|
||||
class="form-control"
|
||||
id="password"
|
||||
name="password"
|
||||
aria-describedby="passwordHelp"
|
||||
/>
|
||||
<div id="passwordHelp" class="form-text">
|
||||
Only API users are allowed to have a blank password. Users with a blank
|
||||
password can only authenticate via Tokens.
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">Project</label>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="project"
|
||||
name="project"
|
||||
aria-describedby="projectHelp"
|
||||
/>
|
||||
<div id="projectHelp" class="form-text">
|
||||
Only Manager users can have a project. Allows to inspect jobs and users
|
||||
of given project.
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">Name</label>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="name"
|
||||
name="name"
|
||||
aria-describedby="nameHelp"
|
||||
/>
|
||||
<div id="nameHelp" class="form-text">Optional, can be blank.</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">Email address</label>
|
||||
<input
|
||||
type="email"
|
||||
class="form-control"
|
||||
id="email"
|
||||
name="email"
|
||||
aria-describedby="emailHelp"
|
||||
/>
|
||||
<div id="emailHelp" class="form-text">Optional, can be blank.</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-3">
|
||||
<p>Role:</p>
|
||||
{#each roles as role, i}
|
||||
{#if i == 0}
|
||||
<div>
|
||||
<input type="radio" id={role} name="role" value={role} checked/>
|
||||
<label for={role}>{role.toUpperCase()} (Allowed to interact with REST API.)</label>
|
||||
</div>
|
||||
{:else if i == 1}
|
||||
<div>
|
||||
<input type="radio" id={role} name="role" value={role} checked/>
|
||||
<label for={role}>{role.charAt(0).toUpperCase() + role.slice(1)} (Same as if created via LDAP sync.)</label>
|
||||
</div>
|
||||
{:else}
|
||||
<div>
|
||||
<input type="radio" id={role} name="role" value={role}/>
|
||||
<label for={role}>{role.charAt(0).toUpperCase() + role.slice(1)}</label>
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
<p style="display: flex; align-items: center;">
|
||||
<Button type="submit" color="primary">Submit</Button>
|
||||
{#if displayMessage}<div style="margin-left: 1.5em;"><b><code style="color: {message.color};" out:fade>{message.msg}</code></b></div>{/if}
|
||||
</p>
|
||||
</form>
|
||||
<div class="mb-3">
|
||||
<p>Role:</p>
|
||||
{#each roles as role, i}
|
||||
{#if i == 0}
|
||||
<div>
|
||||
<input type="radio" id={role} name="role" value={role} checked />
|
||||
<label for={role}
|
||||
>{role.toUpperCase()} (Allowed to interact with REST API.)</label
|
||||
>
|
||||
</div>
|
||||
{:else if i == 1}
|
||||
<div>
|
||||
<input type="radio" id={role} name="role" value={role} checked />
|
||||
<label for={role}
|
||||
>{role.charAt(0).toUpperCase() + role.slice(1)} (Same as if created
|
||||
via LDAP sync.)</label
|
||||
>
|
||||
</div>
|
||||
{:else}
|
||||
<div>
|
||||
<input type="radio" id={role} name="role" value={role} />
|
||||
<label for={role}
|
||||
>{role.charAt(0).toUpperCase() + role.slice(1)}</label
|
||||
>
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
<p style="display: flex; align-items: center;">
|
||||
<Button type="submit" color="primary">Submit</Button>
|
||||
{#if displayMessage}<div style="margin-left: 1.5em;">
|
||||
<b
|
||||
><code style="color: {message.color};" out:fade>{message.msg}</code
|
||||
></b
|
||||
>
|
||||
</div>{/if}
|
||||
</p>
|
||||
</form>
|
||||
</Card>
|
||||
|
@@ -1,97 +1,129 @@
|
||||
<script>
|
||||
import { Card, CardTitle, CardBody } from 'sveltestrap'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { fade } from 'svelte/transition'
|
||||
import { Card, CardTitle, CardBody } from "@sveltestrap/sveltestrap";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import { fade } from "svelte/transition";
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
let message = {msg: '', color: '#d63384'}
|
||||
let displayMessage = false
|
||||
let message = { msg: "", color: "#d63384" };
|
||||
let displayMessage = false;
|
||||
|
||||
async function handleAddProject() {
|
||||
const username = document.querySelector('#project-username').value
|
||||
const project = document.querySelector('#project-id').value
|
||||
async function handleAddProject() {
|
||||
const username = document.querySelector("#project-username").value;
|
||||
const project = document.querySelector("#project-id").value;
|
||||
|
||||
if (username == "" || project == "") {
|
||||
alert('Please fill in a username and select a project.')
|
||||
return
|
||||
}
|
||||
|
||||
let formData = new FormData()
|
||||
formData.append('username', username)
|
||||
formData.append('add-project', project)
|
||||
|
||||
try {
|
||||
const res = await fetch(`/api/user/${username}`, { method: 'POST', body: formData })
|
||||
if (res.ok) {
|
||||
let text = await res.text()
|
||||
popMessage(text, '#048109')
|
||||
reloadUserList()
|
||||
} else {
|
||||
let text = await res.text()
|
||||
// console.log(res.statusText)
|
||||
throw new Error('Response Code ' + res.status + '-> ' + text)
|
||||
}
|
||||
} catch (err) {
|
||||
popMessage(err, '#d63384')
|
||||
}
|
||||
if (username == "" || project == "") {
|
||||
alert("Please fill in a username and select a project.");
|
||||
return;
|
||||
}
|
||||
|
||||
async function handleRemoveProject() {
|
||||
const username = document.querySelector('#project-username').value
|
||||
const project = document.querySelector('#project-id').value
|
||||
let formData = new FormData();
|
||||
formData.append("username", username);
|
||||
formData.append("add-project", project);
|
||||
|
||||
if (username == "" || project == "") {
|
||||
alert('Please fill in a username and select a project.')
|
||||
return
|
||||
}
|
||||
try {
|
||||
const res = await fetch(`/api/user/${username}`, {
|
||||
method: "POST",
|
||||
body: formData,
|
||||
});
|
||||
if (res.ok) {
|
||||
let text = await res.text();
|
||||
popMessage(text, "#048109");
|
||||
reloadUserList();
|
||||
} else {
|
||||
let text = await res.text();
|
||||
// console.log(res.statusText)
|
||||
throw new Error("Response Code " + res.status + "-> " + text);
|
||||
}
|
||||
} catch (err) {
|
||||
popMessage(err, "#d63384");
|
||||
}
|
||||
}
|
||||
|
||||
let formData = new FormData()
|
||||
formData.append('username', username)
|
||||
formData.append('remove-project', project)
|
||||
async function handleRemoveProject() {
|
||||
const username = document.querySelector("#project-username").value;
|
||||
const project = document.querySelector("#project-id").value;
|
||||
|
||||
try {
|
||||
const res = await fetch(`/api/user/${username}`, { method: 'POST', body: formData })
|
||||
if (res.ok) {
|
||||
let text = await res.text()
|
||||
popMessage(text, '#048109')
|
||||
reloadUserList()
|
||||
} else {
|
||||
let text = await res.text()
|
||||
// console.log(res.statusText)
|
||||
throw new Error('Response Code ' + res.status + '-> ' + text)
|
||||
}
|
||||
} catch (err) {
|
||||
popMessage(err, '#d63384')
|
||||
}
|
||||
if (username == "" || project == "") {
|
||||
alert("Please fill in a username and select a project.");
|
||||
return;
|
||||
}
|
||||
|
||||
function popMessage(response, rescolor) {
|
||||
message = {msg: response, color: rescolor}
|
||||
displayMessage = true
|
||||
setTimeout(function() {
|
||||
displayMessage = false
|
||||
}, 3500)
|
||||
}
|
||||
let formData = new FormData();
|
||||
formData.append("username", username);
|
||||
formData.append("remove-project", project);
|
||||
|
||||
function reloadUserList() {
|
||||
dispatch('reload')
|
||||
try {
|
||||
const res = await fetch(`/api/user/${username}`, {
|
||||
method: "POST",
|
||||
body: formData,
|
||||
});
|
||||
if (res.ok) {
|
||||
let text = await res.text();
|
||||
popMessage(text, "#048109");
|
||||
reloadUserList();
|
||||
} else {
|
||||
let text = await res.text();
|
||||
// console.log(res.statusText)
|
||||
throw new Error("Response Code " + res.status + "-> " + text);
|
||||
}
|
||||
} catch (err) {
|
||||
popMessage(err, "#d63384");
|
||||
}
|
||||
}
|
||||
|
||||
function popMessage(response, rescolor) {
|
||||
message = { msg: response, color: rescolor };
|
||||
displayMessage = true;
|
||||
setTimeout(function () {
|
||||
displayMessage = false;
|
||||
}, 3500);
|
||||
}
|
||||
|
||||
function reloadUserList() {
|
||||
dispatch("reload");
|
||||
}
|
||||
</script>
|
||||
|
||||
<Card>
|
||||
<CardBody>
|
||||
<CardTitle class="mb-3">Edit Project Managed By User (Manager Only)</CardTitle>
|
||||
<div class="input-group mb-3">
|
||||
<input type="text" class="form-control" placeholder="username" id="project-username"/>
|
||||
<input type="text" class="form-control" placeholder="project-id" id="project-id"/>
|
||||
<!-- PreventDefault on Sveltestrap-Button more complex to achieve than just use good ol' html button -->
|
||||
<!-- see: https://stackoverflow.com/questions/69630422/svelte-how-to-use-event-modifiers-in-my-own-components -->
|
||||
<button class="btn btn-primary" type="button" id="add-project-button" on:click|preventDefault={handleAddProject}>Add</button>
|
||||
<button class="btn btn-danger" type="button" id="remove-project-button" on:click|preventDefault={handleRemoveProject}>Remove</button>
|
||||
</div>
|
||||
<p>
|
||||
{#if displayMessage}<b><code style="color: {message.color};" out:fade>Update: {message.msg}</code></b>{/if}
|
||||
</p>
|
||||
</CardBody>
|
||||
<CardBody>
|
||||
<CardTitle class="mb-3"
|
||||
>Edit Project Managed By User (Manager Only)</CardTitle
|
||||
>
|
||||
<div class="input-group mb-3">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
placeholder="username"
|
||||
id="project-username"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
placeholder="project-id"
|
||||
id="project-id"
|
||||
/>
|
||||
<!-- PreventDefault on Sveltestrap-Button more complex to achieve than just use good ol' html button -->
|
||||
<!-- see: https://stackoverflow.com/questions/69630422/svelte-how-to-use-event-modifiers-in-my-own-components -->
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
type="button"
|
||||
id="add-project-button"
|
||||
on:click|preventDefault={handleAddProject}>Add</button
|
||||
>
|
||||
<button
|
||||
class="btn btn-danger"
|
||||
type="button"
|
||||
id="remove-project-button"
|
||||
on:click|preventDefault={handleRemoveProject}>Remove</button
|
||||
>
|
||||
</div>
|
||||
<p>
|
||||
{#if displayMessage}<b
|
||||
><code style="color: {message.color};" out:fade
|
||||
>Update: {message.msg}</code
|
||||
></b
|
||||
>{/if}
|
||||
</p>
|
||||
</CardBody>
|
||||
</Card>
|
||||
|
@@ -1,104 +1,131 @@
|
||||
<script>
|
||||
import { Card, CardTitle, CardBody } from 'sveltestrap'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { fade } from 'svelte/transition'
|
||||
import { Card, CardTitle, CardBody } from "@sveltestrap/sveltestrap";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import { fade } from "svelte/transition";
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
let message = {msg: '', color: '#d63384'}
|
||||
let displayMessage = false
|
||||
let message = { msg: "", color: "#d63384" };
|
||||
let displayMessage = false;
|
||||
|
||||
export let roles = []
|
||||
export let roles = [];
|
||||
|
||||
async function handleAddRole() {
|
||||
const username = document.querySelector('#role-username').value
|
||||
const role = document.querySelector('#role-select').value
|
||||
async function handleAddRole() {
|
||||
const username = document.querySelector("#role-username").value;
|
||||
const role = document.querySelector("#role-select").value;
|
||||
|
||||
if (username == "" || role == "") {
|
||||
alert('Please fill in a username and select a role.')
|
||||
return
|
||||
}
|
||||
|
||||
let formData = new FormData()
|
||||
formData.append('username', username)
|
||||
formData.append('add-role', role)
|
||||
|
||||
try {
|
||||
const res = await fetch(`/api/user/${username}`, { method: 'POST', body: formData })
|
||||
if (res.ok) {
|
||||
let text = await res.text()
|
||||
popMessage(text, '#048109')
|
||||
reloadUserList()
|
||||
} else {
|
||||
let text = await res.text()
|
||||
// console.log(res.statusText)
|
||||
throw new Error('Response Code ' + res.status + '-> ' + text)
|
||||
}
|
||||
} catch (err) {
|
||||
popMessage(err, '#d63384')
|
||||
}
|
||||
if (username == "" || role == "") {
|
||||
alert("Please fill in a username and select a role.");
|
||||
return;
|
||||
}
|
||||
|
||||
async function handleRemoveRole() {
|
||||
const username = document.querySelector('#role-username').value
|
||||
const role = document.querySelector('#role-select').value
|
||||
let formData = new FormData();
|
||||
formData.append("username", username);
|
||||
formData.append("add-role", role);
|
||||
|
||||
if (username == "" || role == "") {
|
||||
alert('Please fill in a username and select a role.')
|
||||
return
|
||||
}
|
||||
try {
|
||||
const res = await fetch(`/api/user/${username}`, {
|
||||
method: "POST",
|
||||
body: formData,
|
||||
});
|
||||
if (res.ok) {
|
||||
let text = await res.text();
|
||||
popMessage(text, "#048109");
|
||||
reloadUserList();
|
||||
} else {
|
||||
let text = await res.text();
|
||||
// console.log(res.statusText)
|
||||
throw new Error("Response Code " + res.status + "-> " + text);
|
||||
}
|
||||
} catch (err) {
|
||||
popMessage(err, "#d63384");
|
||||
}
|
||||
}
|
||||
|
||||
let formData = new FormData()
|
||||
formData.append('username', username)
|
||||
formData.append('remove-role', role)
|
||||
async function handleRemoveRole() {
|
||||
const username = document.querySelector("#role-username").value;
|
||||
const role = document.querySelector("#role-select").value;
|
||||
|
||||
try {
|
||||
const res = await fetch(`/api/user/${username}`, { method: 'POST', body: formData })
|
||||
if (res.ok) {
|
||||
let text = await res.text()
|
||||
popMessage(text, '#048109')
|
||||
reloadUserList()
|
||||
} else {
|
||||
let text = await res.text()
|
||||
// console.log(res.statusText)
|
||||
throw new Error('Response Code ' + res.status + '-> ' + text)
|
||||
}
|
||||
} catch (err) {
|
||||
popMessage(err, '#d63384')
|
||||
}
|
||||
if (username == "" || role == "") {
|
||||
alert("Please fill in a username and select a role.");
|
||||
return;
|
||||
}
|
||||
|
||||
function popMessage(response, rescolor) {
|
||||
message = {msg: response, color: rescolor}
|
||||
displayMessage = true
|
||||
setTimeout(function() {
|
||||
displayMessage = false
|
||||
}, 3500)
|
||||
}
|
||||
let formData = new FormData();
|
||||
formData.append("username", username);
|
||||
formData.append("remove-role", role);
|
||||
|
||||
function reloadUserList() {
|
||||
dispatch('reload')
|
||||
try {
|
||||
const res = await fetch(`/api/user/${username}`, {
|
||||
method: "POST",
|
||||
body: formData,
|
||||
});
|
||||
if (res.ok) {
|
||||
let text = await res.text();
|
||||
popMessage(text, "#048109");
|
||||
reloadUserList();
|
||||
} else {
|
||||
let text = await res.text();
|
||||
// console.log(res.statusText)
|
||||
throw new Error("Response Code " + res.status + "-> " + text);
|
||||
}
|
||||
} catch (err) {
|
||||
popMessage(err, "#d63384");
|
||||
}
|
||||
}
|
||||
|
||||
function popMessage(response, rescolor) {
|
||||
message = { msg: response, color: rescolor };
|
||||
displayMessage = true;
|
||||
setTimeout(function () {
|
||||
displayMessage = false;
|
||||
}, 3500);
|
||||
}
|
||||
|
||||
function reloadUserList() {
|
||||
dispatch("reload");
|
||||
}
|
||||
</script>
|
||||
|
||||
<Card>
|
||||
<CardBody>
|
||||
<CardTitle class="mb-3">Edit User Roles</CardTitle>
|
||||
<div class="input-group mb-3">
|
||||
<input type="text" class="form-control" placeholder="username" id="role-username"/>
|
||||
<select class="form-select" id="role-select">
|
||||
<option selected value="">Role...</option>
|
||||
{#each roles as role}
|
||||
<option value={role}>{role.charAt(0).toUpperCase() + role.slice(1)}</option>
|
||||
{/each}
|
||||
</select>
|
||||
<!-- PreventDefault on Sveltestrap-Button more complex to achieve than just use good ol' html button -->
|
||||
<!-- see: https://stackoverflow.com/questions/69630422/svelte-how-to-use-event-modifiers-in-my-own-components -->
|
||||
<button class="btn btn-primary" type="button" id="add-role-button" on:click|preventDefault={handleAddRole}>Add</button>
|
||||
<button class="btn btn-danger" type="button" id="remove-role-button" on:click|preventDefault={handleRemoveRole}>Remove</button>
|
||||
</div>
|
||||
<p>
|
||||
{#if displayMessage}<b><code style="color: {message.color};" out:fade>Update: {message.msg}</code></b>{/if}
|
||||
</p>
|
||||
</CardBody>
|
||||
<CardBody>
|
||||
<CardTitle class="mb-3">Edit User Roles</CardTitle>
|
||||
<div class="input-group mb-3">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
placeholder="username"
|
||||
id="role-username"
|
||||
/>
|
||||
<select class="form-select" id="role-select">
|
||||
<option selected value="">Role...</option>
|
||||
{#each roles as role}
|
||||
<option value={role}
|
||||
>{role.charAt(0).toUpperCase() + role.slice(1)}</option
|
||||
>
|
||||
{/each}
|
||||
</select>
|
||||
<!-- PreventDefault on Sveltestrap-Button more complex to achieve than just use good ol' html button -->
|
||||
<!-- see: https://stackoverflow.com/questions/69630422/svelte-how-to-use-event-modifiers-in-my-own-components -->
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
type="button"
|
||||
id="add-role-button"
|
||||
on:click|preventDefault={handleAddRole}>Add</button
|
||||
>
|
||||
<button
|
||||
class="btn btn-danger"
|
||||
type="button"
|
||||
id="remove-role-button"
|
||||
on:click|preventDefault={handleRemoveRole}>Remove</button
|
||||
>
|
||||
</div>
|
||||
<p>
|
||||
{#if displayMessage}<b
|
||||
><code style="color: {message.color};" out:fade
|
||||
>Update: {message.msg}</code
|
||||
></b
|
||||
>{/if}
|
||||
</p>
|
||||
</CardBody>
|
||||
</Card>
|
||||
|
@@ -1,29 +1,34 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte'
|
||||
import { Card, CardBody, CardTitle } from 'sveltestrap'
|
||||
import { onMount } from "svelte";
|
||||
import { Card, CardBody, CardTitle } from "@sveltestrap/sveltestrap";
|
||||
|
||||
let scrambled
|
||||
let scrambled;
|
||||
|
||||
onMount(() => {
|
||||
scrambled = window.localStorage.getItem("cc-scramble-names") != null
|
||||
})
|
||||
onMount(() => {
|
||||
scrambled = window.localStorage.getItem("cc-scramble-names") != null;
|
||||
});
|
||||
|
||||
function handleScramble() {
|
||||
if (!scrambled) {
|
||||
scrambled = true
|
||||
window.localStorage.setItem("cc-scramble-names", "true")
|
||||
} else {
|
||||
scrambled = false
|
||||
window.localStorage.removeItem("cc-scramble-names")
|
||||
}
|
||||
function handleScramble() {
|
||||
if (!scrambled) {
|
||||
scrambled = true;
|
||||
window.localStorage.setItem("cc-scramble-names", "true");
|
||||
} else {
|
||||
scrambled = false;
|
||||
window.localStorage.removeItem("cc-scramble-names");
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<Card class="h-100">
|
||||
<CardBody>
|
||||
<CardTitle class="mb-3">Scramble Names / Presentation Mode</CardTitle>
|
||||
<input type="checkbox" id="scramble-names-checkbox" style="margin-right: 1em;" on:click={handleScramble} bind:checked={scrambled}/>
|
||||
Active?
|
||||
</CardBody>
|
||||
<CardBody>
|
||||
<CardTitle class="mb-3">Scramble Names / Presentation Mode</CardTitle>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="scramble-names-checkbox"
|
||||
style="margin-right: 1em;"
|
||||
on:click={handleScramble}
|
||||
bind:checked={scrambled}
|
||||
/>
|
||||
Active?
|
||||
</CardBody>
|
||||
</Card>
|
||||
|
@@ -1,68 +1,87 @@
|
||||
<script>
|
||||
import { Button, Table, Card, CardTitle, CardBody } from 'sveltestrap'
|
||||
import { onMount, createEventDispatcher } from "svelte";
|
||||
import ShowUsersRow from './ShowUsersRow.svelte'
|
||||
import {
|
||||
Button,
|
||||
Table,
|
||||
Card,
|
||||
CardTitle,
|
||||
CardBody,
|
||||
} from "@sveltestrap/sveltestrap";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import ShowUsersRow from "./ShowUsersRow.svelte";
|
||||
|
||||
export let users = []
|
||||
export let users = [];
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
function reloadUserList() {
|
||||
dispatch('reload')
|
||||
}
|
||||
const dispatch = createEventDispatcher();
|
||||
function reloadUserList() {
|
||||
dispatch("reload");
|
||||
}
|
||||
|
||||
function deleteUser(username) {
|
||||
if (confirm('Are you sure?')) {
|
||||
let formData = new FormData()
|
||||
formData.append('username', username)
|
||||
fetch('/api/users/', { method: 'DELETE', body: formData }).then(res => {
|
||||
if (res.status == 200) {
|
||||
reloadUserList()
|
||||
} else {
|
||||
confirm(res.statusText)
|
||||
}
|
||||
})
|
||||
function deleteUser(username) {
|
||||
if (confirm("Are you sure?")) {
|
||||
let formData = new FormData();
|
||||
formData.append("username", username);
|
||||
fetch("/api/users/", { method: "DELETE", body: formData }).then((res) => {
|
||||
if (res.status == 200) {
|
||||
reloadUserList();
|
||||
} else {
|
||||
confirm(res.statusText);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$: userList = users
|
||||
|
||||
$: userList = users;
|
||||
</script>
|
||||
|
||||
<Card class="h-100">
|
||||
<CardBody>
|
||||
<CardTitle class="mb-3">Special Users</CardTitle>
|
||||
<p>
|
||||
Not created by an LDAP sync and/or having a role other than <code>user</code>
|
||||
<Button color="secondary" size="sm" on:click={reloadUserList} style="float: right;">Reload</Button>
|
||||
</p>
|
||||
<div style="width: 100%; max-height: 500px; overflow-y: scroll;">
|
||||
<Table hover>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Username</th>
|
||||
<th>Name</th>
|
||||
<th>Project(s)</th>
|
||||
<th>Email</th>
|
||||
<th>Roles</th>
|
||||
<th>JWT</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="users-list">
|
||||
{#each userList as user}
|
||||
<tr id="user-{user.username}">
|
||||
<ShowUsersRow {user}/>
|
||||
<td><button class="btn btn-danger del-user" on:click={deleteUser(user.username)}>Delete</button></td>
|
||||
</tr>
|
||||
{:else}
|
||||
<tr>
|
||||
<td colspan="4">
|
||||
<div class="spinner-border" role="status"><span class="visually-hidden">Loading...</span></div>
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</Table>
|
||||
</div>
|
||||
</CardBody>
|
||||
<CardBody>
|
||||
<CardTitle class="mb-3">Special Users</CardTitle>
|
||||
<p>
|
||||
Not created by an LDAP sync and/or having a role other than <code
|
||||
>user</code
|
||||
>
|
||||
<Button
|
||||
color="secondary"
|
||||
size="sm"
|
||||
on:click={reloadUserList}
|
||||
style="float: right;">Reload</Button
|
||||
>
|
||||
</p>
|
||||
<div style="width: 100%; max-height: 500px; overflow-y: scroll;">
|
||||
<Table hover>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Username</th>
|
||||
<th>Name</th>
|
||||
<th>Project(s)</th>
|
||||
<th>Email</th>
|
||||
<th>Roles</th>
|
||||
<th>JWT</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="users-list">
|
||||
{#each userList as user}
|
||||
<tr id="user-{user.username}">
|
||||
<ShowUsersRow {user} />
|
||||
<td
|
||||
><button
|
||||
class="btn btn-danger del-user"
|
||||
on:click={deleteUser(user.username)}>Delete</button
|
||||
></td
|
||||
>
|
||||
</tr>
|
||||
{:else}
|
||||
<tr>
|
||||
<td colspan="4">
|
||||
<div class="spinner-border" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</Table>
|
||||
</div>
|
||||
</CardBody>
|
||||
</Card>
|
||||
|
@@ -1,28 +1,32 @@
|
||||
<script>
|
||||
import { Button } from 'sveltestrap'
|
||||
import { Button } from "@sveltestrap/sveltestrap";
|
||||
|
||||
export let user
|
||||
let jwt = ""
|
||||
export let user;
|
||||
let jwt = "";
|
||||
|
||||
function getUserJwt(username) {
|
||||
fetch(`/api/jwt/?username=${username}`)
|
||||
.then(res => res.text())
|
||||
.then(text => {
|
||||
jwt = text
|
||||
navigator.clipboard.writeText(text).catch(reason => console.error(reason))
|
||||
})
|
||||
}
|
||||
function getUserJwt(username) {
|
||||
fetch(`/api/jwt/?username=${username}`)
|
||||
.then((res) => res.text())
|
||||
.then((text) => {
|
||||
jwt = text;
|
||||
navigator.clipboard
|
||||
.writeText(text)
|
||||
.catch((reason) => console.error(reason));
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<td>{user.username}</td>
|
||||
<td>{user.name}</td>
|
||||
<td>{user.projects}</td>
|
||||
<td>{user.email}</td>
|
||||
<td><code>{user.roles.join(', ')}</code></td>
|
||||
<td><code>{user.roles.join(", ")}</code></td>
|
||||
<td>
|
||||
{#if ! jwt}
|
||||
<Button color="success" on:click={getUserJwt(user.username)}>Gen. JWT</Button>
|
||||
{:else}
|
||||
<textarea rows="3" cols="20">{jwt}</textarea>
|
||||
{/if}
|
||||
{#if !jwt}
|
||||
<Button color="success" on:click={getUserJwt(user.username)}
|
||||
>Gen. JWT</Button
|
||||
>
|
||||
{:else}
|
||||
<textarea rows="3" cols="20">{jwt}</textarea>
|
||||
{/if}
|
||||
</td>
|
||||
|
Reference in New Issue
Block a user