Update configurations and add new files

This commit is contained in:
sanjay7178 2024-02-19 19:20:23 +05:30
parent 0309720c43
commit 72c5a3dd5e
16 changed files with 849 additions and 203 deletions

View File

@ -1,5 +1,5 @@
{
"addr": "127.0.0.1:8080",
"addr": "0.0.0.0:8080",
"db-driver": "mysql",
"embed-static-files": false,
"static-files": "./web/frontend/public/",

View File

@ -13,4 +13,5 @@ DROP TABLE IF EXISTS volume_groups;
DROP TABLE IF EXISTS physical_volumes;
DROP TABLE IF EXISTS lvm_storage_issuer;
DROP TABLE IF EXISTS machine_conf;
DROP TABLE IF EXISTS file_stash_url ;

View File

@ -167,3 +167,9 @@ CREATE TABLE IF NOT EXISTS machine_conf (
folder_path VARCHAR(255) ,
FOREIGN KEY (machine_serial_number) REFERENCES machines(machine_id)
);
CREATE TABLE IF NOT EXISTS file_stash_url (
id INT AUTO_INCREMENT PRIMARY KEY,
url VARCHAR(255) NOT NULL
);

View File

@ -45,7 +45,10 @@ var routes []Route = []Route{
{"/monitoring/node/{cluster}/{hostname}", "monitoring/node.tmpl", "Node <ID> - ClusterCockpit", false, setupNodeRoute},
{"/monitoring/analysis/{cluster}", "monitoring/analysis.tmpl", "Analysis - ClusterCockpit", true, setupAnalysisRoute},
{"/monitoring/status/{cluster}", "monitoring/status.tmpl", "Status of <ID> - ClusterCockpit", false, setupClusterRoute},
{"/partitions/systems/{cluster}", "partitions/systems.tmpl", "Cluster <ID> - ClusterCockpit", false, setupClusterRoute},
{"/monitoring/partition/{cluster}", "partitions/systems.tmpl", "Cluster <ID> - ClusterCockpit", false, setupClusterRoute},
{"/monitoring/history/", "monitoring/history.tmpl", "Cluster <ID> - ClusterCockpit", false, setupClusterRoute},
}

View File

@ -13,11 +13,13 @@
"@timohausmann/quadtree-js": "^1.2.5",
"rollup": "^3.21.0",
"rollup-plugin-css-only": "^4.3.0",
"rollup-plugin-livereload": "^2.0.5",
"rollup-plugin-svelte": "^7.1.4",
"svelte": "^3.58.0"
},
"dependencies": {
"@rollup/plugin-replace": "^5.0.2",
"@tanstack/svelte-table": "^8.12.0",
"@urql/svelte": "^4.0.1",
"chart.js": "^4.3.3",
"date-fns": "^2.30.0",

View File

@ -8,6 +8,9 @@ dependencies:
'@rollup/plugin-replace':
specifier: ^5.0.2
version: 5.0.5(rollup@3.29.4)
'@tanstack/svelte-table':
specifier: ^8.12.0
version: 8.12.0(svelte@3.59.2)
'@urql/svelte':
specifier: ^4.0.1
version: 4.0.4(graphql@16.8.1)(svelte@3.59.2)
@ -55,6 +58,9 @@ devDependencies:
rollup-plugin-css-only:
specifier: ^4.3.0
version: 4.5.2(rollup@3.29.4)
rollup-plugin-livereload:
specifier: ^2.0.5
version: 2.0.5
rollup-plugin-svelte:
specifier: ^7.1.4
version: 7.1.6(rollup@3.29.4)(svelte@3.59.2)
@ -213,6 +219,21 @@ packages:
picomatch: 2.3.1
rollup: 3.29.4
/@tanstack/svelte-table@8.12.0(svelte@3.59.2):
resolution: {integrity: sha512-IgmCj4tVUgjQAUa895XommqNkNdlbi5K3MgcuyB7SbgRMXZXWUrz4chDSrFSseosLz+hcizXsoavmDcDm/WYwA==}
engines: {node: '>=12'}
peerDependencies:
svelte: ^4.0.0 || ^3.49.0
dependencies:
'@tanstack/table-core': 8.12.0
svelte: 3.59.2
dev: false
/@tanstack/table-core@8.12.0:
resolution: {integrity: sha512-cq/ylWVrOwixmwNXQjgZaQw1Izf7+nPxjczum7paAnMtwPg1S2qRAJU+Jb8rEBUWm69voC/zcChmePlk2hc6ug==}
engines: {node: '>=12'}
dev: false
/@timohausmann/quadtree-js@1.2.6:
resolution: {integrity: sha512-EoAoLMFV2JfSG8+8XD9xWJQdyvfEB5xNpiQWGD7rTDSbDQQV8IVpkm0uOIxwJZ+1uC9hHKri9GmJ5wBSUO4jfg==}
dev: true
@ -251,16 +272,36 @@ packages:
hasBin: true
dev: true
/anymatch@3.1.3:
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
engines: {node: '>= 8'}
dependencies:
normalize-path: 3.0.0
picomatch: 2.3.1
dev: true
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
dev: true
/binary-extensions@2.2.0:
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
engines: {node: '>=8'}
dev: true
/brace-expansion@2.0.1:
resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
dependencies:
balanced-match: 1.0.2
dev: true
/braces@3.0.2:
resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
engines: {node: '>=8'}
dependencies:
fill-range: 7.0.1
dev: true
/buffer-from@1.1.2:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
dev: true
@ -277,6 +318,21 @@ packages:
'@kurkle/color': 0.3.2
dev: false
/chokidar@3.6.0:
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
engines: {node: '>= 8.10.0'}
dependencies:
anymatch: 3.1.3
braces: 3.0.2
glob-parent: 5.1.2
is-binary-path: 2.1.0
is-glob: 4.0.3
normalize-path: 3.0.0
readdirp: 3.6.0
optionalDependencies:
fsevents: 2.3.3
dev: true
/commander@2.20.3:
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
dev: true
@ -312,6 +368,13 @@ packages:
/estree-walker@2.0.2:
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
/fill-range@7.0.1:
resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
engines: {node: '>=8'}
dependencies:
to-regex-range: 5.0.1
dev: true
/fraction.js@4.3.4:
resolution: {integrity: sha512-pwiTgt0Q7t+GHZA4yaLjObx4vXmmdcS0iSJ19o8d/goUGgItX9UZWKWNnLHehxviD8wU2IWRsnR8cD5+yOJP2Q==}
dev: false
@ -331,6 +394,13 @@ packages:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
dev: true
/glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
dependencies:
is-glob: 4.0.3
dev: true
/glob@8.1.0:
resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==}
engines: {node: '>=12'}
@ -365,6 +435,13 @@ packages:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
dev: true
/is-binary-path@2.1.0:
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
engines: {node: '>=8'}
dependencies:
binary-extensions: 2.2.0
dev: true
/is-builtin-module@3.2.1:
resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==}
engines: {node: '>=6'}
@ -378,10 +455,27 @@ packages:
hasown: 2.0.1
dev: true
/is-extglob@2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
dev: true
/is-glob@4.0.3:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
dependencies:
is-extglob: 2.1.1
dev: true
/is-module@1.0.0:
resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==}
dev: true
/is-number@7.0.0:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
dev: true
/is-reference@1.2.1:
resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==}
dependencies:
@ -392,6 +486,24 @@ packages:
resolution: {integrity: sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==}
dev: false
/livereload-js@3.4.1:
resolution: {integrity: sha512-5MP0uUeVCec89ZbNOT/i97Mc+q3SxXmiUGhRFOTmhrGPn//uWVQdCvcLJDy64MSBR5MidFdOR7B9viumoavy6g==}
dev: true
/livereload@0.9.3:
resolution: {integrity: sha512-q7Z71n3i4X0R9xthAryBdNGVGAO2R5X+/xXpmKeuPMrteg+W2U8VusTKV3YiJbXZwKsOlFlHe+go6uSNjfxrZw==}
engines: {node: '>=8.0.0'}
hasBin: true
dependencies:
chokidar: 3.6.0
livereload-js: 3.4.1
opts: 2.0.2
ws: 7.5.9
transitivePeerDependencies:
- bufferutil
- utf-8-validate
dev: true
/magic-string@0.27.0:
resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==}
engines: {node: '>=12'}
@ -429,12 +541,21 @@ packages:
brace-expansion: 2.0.1
dev: true
/normalize-path@3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
dev: true
/once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
dependencies:
wrappy: 1.0.2
dev: true
/opts@2.0.2:
resolution: {integrity: sha512-k41FwbcLnlgnFh69f4qdUfvDQ+5vaSDnVPFI/y5XuhKRq97EnVVneO9F1ESVCdiVu4fCS2L8usX3mU331hB7pg==}
dev: true
/path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
dev: true
@ -449,6 +570,13 @@ packages:
safe-buffer: 5.2.1
dev: true
/readdirp@3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
dependencies:
picomatch: 2.3.1
dev: true
/regenerator-runtime@0.14.1:
resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
dev: false
@ -477,6 +605,16 @@ packages:
rollup: 3.29.4
dev: true
/rollup-plugin-livereload@2.0.5:
resolution: {integrity: sha512-vqQZ/UQowTW7VoiKEM5ouNW90wE5/GZLfdWuR0ELxyKOJUIaj+uismPZZaICU4DnWPVjnpCDDxEqwU7pcKY/PA==}
engines: {node: '>=8.3'}
dependencies:
livereload: 0.9.3
transitivePeerDependencies:
- bufferutil
- utf-8-validate
dev: true
/rollup-plugin-svelte@7.1.6(rollup@3.29.4)(svelte@3.59.2):
resolution: {integrity: sha512-nVFRBpGWI2qUY1OcSiEEA/kjCY2+vAjO9BI8SzA7NRrh2GTunLd6w2EYmnMt/atgdg8GvcNjLsmZmbQs/u4SQA==}
engines: {node: '>=10'}
@ -570,6 +708,13 @@ packages:
resolution: {integrity: sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==}
dev: false
/to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
dependencies:
is-number: 7.0.0
dev: true
/typed-function@4.1.1:
resolution: {integrity: sha512-Pq1DVubcvibmm8bYcMowjVnnMwPVMeh0DIdA8ad8NZY2sJgapANJmiigSUwlt+EgXxpfIv8MWrQXTIzkfYZLYQ==}
engines: {node: '>= 14'}
@ -586,3 +731,16 @@ packages:
/wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
dev: true
/ws@7.5.9:
resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==}
engines: {node: '>=8.3.0'}
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: ^5.0.2
peerDependenciesMeta:
bufferutil:
optional: true
utf-8-validate:
optional: true
dev: true

View File

@ -4,6 +4,7 @@ import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import terser from '@rollup/plugin-terser';
import css from 'rollup-plugin-css-only';
import livereload from 'rollup-plugin-livereload';
// const production = !process.env.ROLLUP_WATCH;
const production = false
@ -51,6 +52,7 @@ const entrypoint = (name, path) => ({
// we'll extract any component CSS out into
// a separate file - better for performance
css({ output: `${name}.css` }),
!production && livereload('public')
],
watch: {
clearScreen: false
@ -68,5 +70,7 @@ export default [
entrypoint('analysis', 'src/analysis.entrypoint.js'),
entrypoint('status', 'src/status.entrypoint.js'),
entrypoint('config', 'src/config.entrypoint.js'),
entrypoint('partitions', 'src/partitions.entrypoint.js')
entrypoint('partitions', 'src/partitions.entrypoint.js'),
entrypoint('history', 'src/history.entrypoint.js')
];

View File

@ -1,31 +1,67 @@
<script>
import { getContext } from 'svelte'
import { init } from './utils.js'
import { Card, CardHeader, CardTitle } from 'sveltestrap'
import { getContext } from "svelte";
import { init } from "./utils.js";
import {
Card,
CardHeader,
CardTitle,
Col,
Icon,
TabContent,
TabPane,
Row,
} from "sveltestrap";
import PlotSettings from './config/PlotSettings.svelte'
import AdminSettings from './config/AdminSettings.svelte'
import PlotSettings from "./config/PlotSettings.svelte";
import AdminSettings from "./config/AdminSettings.svelte";
// import InfoxDbConf from "./config/admin/InfluxDbConf.svelte";
import InfluxModalDefault from "./config/admin/InfluxModalDefault.svelte";
import FileBrowser from "./config/admin/FileBrowser.svelte";
const { query: initq } = init()
const { query: initq } = init();
const ccconfig = getContext('cc-config')
export let isAdmin
const ccconfig = getContext("cc-config");
export let isAdmin;
</script>
{#if isAdmin == true}
<Card style="margin-bottom: 1.5em;">
<CardHeader>
<CardTitle class="mb-1">Admin Options</CardTitle>
</CardHeader>
<AdminSettings/>
</Card>
{/if}
<Card>
<CardHeader>
<CardTitle class="mb-1">Plotting Options</CardTitle>
</CardHeader>
<PlotSettings config={ccconfig}/>
</Card>
<TabContent>
<TabPane tabId="admin-options" active class="mt-3">
<span slot="tab">
Admin Options
<!-- <Icon name="gear" /> -->
</span>
{#if isAdmin == true}
<Card style="margin-bottom: 1.5em;">
<AdminSettings />
</Card>
{/if}
</TabPane>
<TabPane tabId="plotting-options" class="mt-3">
<span slot="tab">
Plotting Options
<!-- <Icon name="hand-thumbs-up" /> -->
</span>
<Card>
<PlotSettings config={ccconfig} />
</Card>
</TabPane>
<TabPane tabId="influx-conf" class="mt-3">
<span slot="tab">
Default Configuration
<!-- <Icon name="alarm" /> -->
</span>
<Row cols={2} class="p-2 g-2">
<Col class="mb-1">
<Card class="p-3">
<CardHeader>Default InfluxDB Configuration</CardHeader>
<br>
<InfluxModalDefault />
</Card>
</Col>
<Col class="mb-1">
<FileBrowser />
</Col>
</Row>
</TabPane>
</TabContent>

View File

@ -1,186 +1,184 @@
<script>
import {
Icon,
Collapse,
Navbar,
NavbarBrand,
Nav,
NavbarToggler,
Dropdown,
DropdownToggle,
DropdownMenu,
} from "sveltestrap";
import NavbarLinks from "./NavbarLinks.svelte";
import NavbarTools from "./NavbarTools.svelte";
import {
Icon,
Collapse,
Navbar,
NavbarBrand,
Nav,
NavbarToggler,
Dropdown,
DropdownToggle,
DropdownMenu,
} from "sveltestrap";
import NavbarLinks from "./NavbarLinks.svelte";
import NavbarTools from "./NavbarTools.svelte";
export let username; // empty string if auth. is disabled, otherwise the username as string
export let authlevel; // Integer
export let clusters; // array of names
export let roles; // Role Enum-Like
export let username; // empty string if auth. is disabled, otherwise the username as string
export let authlevel; // Integer
export let clusters; // array of names
export let roles; // Role Enum-Like
let isOpen = false;
let screenSize;
let isOpen = false;
let screenSize;
const jobsTitle = new Map();
jobsTitle.set(2, "Job Search");
jobsTitle.set(3, "Managed Jobs");
jobsTitle.set(4, "Jobs");
jobsTitle.set(5, "Jobs");
const usersTitle = new Map();
usersTitle.set(3, "Managed Users");
usersTitle.set(4, "Users");
usersTitle.set(5, "Users");
const jobsTitle = new Map();
jobsTitle.set(2, "Job Search");
jobsTitle.set(3, "Managed Jobs");
jobsTitle.set(4, "Jobs");
jobsTitle.set(5, "Jobs");
const usersTitle = new Map();
usersTitle.set(3, "Managed Users");
usersTitle.set(4, "Users");
usersTitle.set(5, "Users");
const views = [
{
title: "My Jobs",
requiredRole: roles.user,
href: `/monitoring/user/${username}`,
icon: "bar-chart-line-fill",
perCluster: false,
menu: "none",
},
{
title: jobsTitle.get(authlevel),
requiredRole: roles.user,
href: `/monitoring/jobs/`,
icon: "card-list",
perCluster: false,
menu: "none",
},
{
title: usersTitle.get(authlevel),
requiredRole: roles.manager,
href: "/monitoring/users/",
icon: "people-fill",
perCluster: false,
menu: "Groups",
},
{
title: "Projects",
requiredRole: roles.support,
href: "/monitoring/projects/",
icon: "folder",
perCluster: false,
menu: "Groups",
},
{
title: "Tags",
requiredRole: roles.user,
href: "/monitoring/tags/",
icon: "tags",
perCluster: false,
menu: "Groups",
},
{
title: "Analysis",
requiredRole: roles.support,
href: "/monitoring/analysis/",
icon: "graph-up",
perCluster: true,
menu: "Stats",
},
{
title: "Nodes",
requiredRole: roles.admin,
href: "/monitoring/systems/",
icon: "cpu",
perCluster: true,
menu: "Groups",
},
{
title: "Status",
requiredRole: roles.admin,
href: "/monitoring/status/",
icon: "cpu",
perCluster: true,
menu: "Stats",
},
{
title: "Partitions",
requiredRole: roles.admin,
href: "partitions/systems/",
icon: "device-hdd",
perCluster: true,
menu: "Stats",
},
];
const views = [
{
title: "My Jobs",
requiredRole: roles.user,
href: `/monitoring/user/${username}`,
icon: "bar-chart-line-fill",
perCluster: false,
menu: "none",
},
{
title: jobsTitle.get(authlevel),
requiredRole: roles.user,
href: `/monitoring/jobs/`,
icon: "card-list",
perCluster: false,
menu: "none",
},
{
title: usersTitle.get(authlevel),
requiredRole: roles.manager,
href: "/monitoring/users/",
icon: "people-fill",
perCluster: false,
menu: "Groups",
},
{
title: "Projects",
requiredRole: roles.support,
href: "/monitoring/projects/",
icon: "folder",
perCluster: false,
menu: "Groups",
},
{
title: "Tags",
requiredRole: roles.user,
href: "/monitoring/tags/",
icon: "tags",
perCluster: false,
menu: "Groups",
},
{
title: "Analysis",
requiredRole: roles.support,
href: "/monitoring/analysis/",
icon: "graph-up",
perCluster: true,
menu: "Stats",
},
{
title: "Nodes",
requiredRole: roles.admin,
href: "/monitoring/systems/",
icon: "cpu",
perCluster: true,
menu: "Groups",
},
{
title: "Status",
requiredRole: roles.admin,
href: "/monitoring/status/",
icon: "cpu",
perCluster: true,
menu: "Stats",
},
{
title: "Partitions",
requiredRole: roles.admin,
href: "/monitoring/partition/",
icon: "device-hdd",
perCluster: true,
menu: "Stats",
},
{
title: "History",
requiredRole: roles.admin,
href: "/monitoring/history/",
icon: "clock-history",
perCluster: false,
menu: "Stats",
},
];
</script>
<svelte:window bind:innerWidth={screenSize} />
<Navbar color="light" light expand="md" fixed="top">
<NavbarBrand href="/">
<img alt="ClusterCockpit Logo" src="/img/logo.png" height="25rem" />
</NavbarBrand>
<NavbarToggler on:click={() => (isOpen = !isOpen)} />
<Collapse
style="justify-content: space-between"
{isOpen}
navbar
expand="md"
on:update={({ detail }) => (isOpen = detail.isOpen)}
>
<Nav navbar>
{#if screenSize > 1500 || screenSize < 768}
<NavbarLinks
{clusters}
links={views.filter(
(item) => item.requiredRole <= authlevel
)}
/>
{:else if screenSize > 1300}
<NavbarLinks
{clusters}
links={views.filter(
(item) =>
item.requiredRole <= authlevel &&
item.menu != "Stats"
)}
/>
<Dropdown nav>
<DropdownToggle nav caret>
<Icon name="graph-up" />
Stats
</DropdownToggle>
<DropdownMenu class="dropdown-menu-lg-end">
<NavbarLinks
{clusters}
links={views.filter(
(item) =>
item.requiredRole <= authlevel &&
item.menu == "Stats"
)}
/>
</DropdownMenu>
</Dropdown>
{:else}
<NavbarLinks
{clusters}
links={views.filter(
(item) =>
item.requiredRole <= authlevel &&
item.menu == "none"
)}
/>
{#each Array("Groups", "Stats") as menu}
<Dropdown nav>
<DropdownToggle nav caret>
{menu}
</DropdownToggle>
<DropdownMenu class="dropdown-menu-lg-end">
<NavbarLinks
{clusters}
links={views.filter(
(item) =>
item.requiredRole <= authlevel &&
item.menu == menu
)}
/>
</DropdownMenu>
</Dropdown>
{/each}
{/if}
</Nav>
<NavbarTools {username} {authlevel} {roles} {screenSize} />
</Collapse>
<NavbarBrand href="/">
<img alt="ClusterCockpit Logo" src="/img/logo.png" height="25rem" />
</NavbarBrand>
<NavbarToggler on:click={() => (isOpen = !isOpen)} />
<Collapse
style="justify-content: space-between"
{isOpen}
navbar
expand="md"
on:update={({ detail }) => (isOpen = detail.isOpen)}
>
<Nav navbar>
{#if screenSize > 1500 || screenSize < 768}
<NavbarLinks
{clusters}
links={views.filter((item) => item.requiredRole <= authlevel)}
/>
{:else if screenSize > 1300}
<NavbarLinks
{clusters}
links={views.filter(
(item) => item.requiredRole <= authlevel && item.menu != "Stats"
)}
/>
<Dropdown nav>
<DropdownToggle nav caret>
<Icon name="graph-up" />
Stats
</DropdownToggle>
<DropdownMenu class="dropdown-menu-lg-end">
<NavbarLinks
{clusters}
links={views.filter(
(item) => item.requiredRole <= authlevel && item.menu == "Stats"
)}
/>
</DropdownMenu>
</Dropdown>
{:else}
<NavbarLinks
{clusters}
links={views.filter(
(item) => item.requiredRole <= authlevel && item.menu == "none"
)}
/>
{#each Array("Groups", "Stats") as menu}
<Dropdown nav>
<DropdownToggle nav caret>
{menu}
</DropdownToggle>
<DropdownMenu class="dropdown-menu-lg-end">
<NavbarLinks
{clusters}
links={views.filter(
(item) => item.requiredRole <= authlevel && item.menu == menu
)}
/>
</DropdownMenu>
</Dropdown>
{/each}
{/if}
</Nav>
<NavbarTools {username} {authlevel} {roles} {screenSize} />
</Collapse>
</Navbar>

View File

@ -0,0 +1,98 @@
<script>
import {
Col,
Row,
Card,
CardHeader,
CardBody,
CardTitle,
CardSubtitle,
CardText,
InputGroup,
InputGroupText,
Input,
Button,
Icon,
Dropdown,
DropdownToggle,
DropdownMenu,
DropdownItem,
} from "sveltestrap";
import SvTable from "./partition/SvTable.svelte";
let pages = [5, 10, 15, 20];
let selectedPages = 5;
let isOpen = false;
const selectPage = (page) => {
selectedPages = page;
isOpen = false;
};
</script>
<Col cols={1} class="p-2 g-2">
<Row>
<Col>
<Card class="mb-1">
<CardHeader>
<CardTitle>
<h3>History</h3></CardTitle
>
</CardHeader>
<CardBody class="h5">
<CardSubtitle
>History records for past connections are listed here and can be
sorted by clicking the column headers. To search for specific
records, enter a filter string and click "Search". Only records
which match the provided filter string will be listed.
</CardSubtitle>
<CardText></CardText>
<Row>
<Row class="p-3">
<Col>
<!-- bind:value={filterString} -->
<InputGroup>
<Input type="text" placeholder="Filter string" />
<InputGroupText>
<Icon name="search" />
</InputGroupText>
</InputGroup>
</Col>
<Col>
<!-- <Button color="primary" on:click={search}> -->
<Button color="primary">Search</Button>
</Col>
</Row>
</Row>
<!-- <br> -->
<Row class="p-3">
<SvTable />
</Row>
<!-- pagination -->
<Row>
<Col cols="3">
<!-- <Button color="primary" on:click={prevPage}> -->
<Button color="primary">Previous</Button>
<!-- <Button color="primary" on:click={nextPage}> -->
<Button color="primary">Next</Button>
<!-- dropdown for number of pages to show -->
<div>
<Dropdown {isOpen} toggle={() => (isOpen = !isOpen)}>
<DropdownToggle caret>
{selectedPages}
</DropdownToggle>
<DropdownMenu>
{#each pages as page (page)}
<DropdownItem on:click={() => selectPage(page)}
>{page}</DropdownItem
>
{/each}
</DropdownMenu>
</Dropdown>
</div>
</Col>
</Row>
</CardBody>
</Card>
</Col>
</Row>
</Col>

View File

@ -0,0 +1,53 @@
<script>
import { Button, Card, CardText, CardTitle } from 'sveltestrap'
import { createEventDispatcher } from 'svelte'
import { fade } from 'svelte/transition'
const dispatch = createEventDispatcher()
let message = {msg: '', color: '#d63384'}
let displayMessage = false
async function handleUrlSubmit() {
let form = document.querySelector('#create-url-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')
form.reset()
} else {
let text = await res.text()
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)
}
</script>
<Card>
<!-- default url -->
<form id="create-url-form" method="post" action="/api/url/" class="card-body" on:submit|preventDefault={handleUrlSubmit}>
<CardTitle class="mb-3">FileBrowser Configuration</CardTitle>
<CardText><p>Current URL :</p></CardText>
<div class="mb-3">
<label for="url" class="form-label">URL</label>
<input type="text" class="form-control" id="url" name="url" required />
</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>

View File

@ -0,0 +1,193 @@
<script>
import { Button, Card, CardTitle } from "sveltestrap";
import { createEventDispatcher } from "svelte";
import { fade } from "svelte/transition";
const dispatch = createEventDispatcher();
let message = { msg: "", color: "#d63384" };
let displayMessage = false;
async function handleInfluxSubmit() {
let form = document.querySelector("#create-influx-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");
form.reset();
} else {
let text = await res.text();
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);
}
</script>
<Card class="m-2">
<form
id="create-influx-form"
method="post"
action="/api/influx/"
class="card-body"
on:submit|preventDefault={handleInfluxSubmit}
>
<!-- <CardTitle class="mb-3">Create Influx Configuration</CardTitle> -->
<div class="mb-3">
<label for="type" class="form-label">Type</label>
<input
type="text"
class="form-control"
id="type"
name="type"
value="influxasync"
/>
</div>
<div class="mb-3">
<label for="database" class="form-label">Database</label>
<input
type="text"
class="form-control"
id="database"
name="database"
value="Bucket"
/>
</div>
<div class="mb-3">
<label for="host" class="form-label">Host</label>
<input
type="text"
class="form-control"
id="host"
name="host"
value="103.165.95.123"
/>
</div>
<div class="mb-3">
<label for="port" class="form-label">Port</label>
<input
type="text"
class="form-control"
id="port"
name="port"
value="8086"
/>
</div>
<!-- Add more input fields as needed -->
<div class="mb-3">
<label for="user" class="form-label">User</label>
<input type="text" class="form-control" id="user" name="user" value="" />
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input
type="password"
class="form-control"
id="password"
name="password"
value="-7snr5tvEWxx5pnNSwfqSz9C2hO6NHUAqMRIBeS3Q-Z8kmPn0pO6UC-IEWo2EAw3oTorriVGWwiNYahS2BTiFg=="
/>
</div>
<div class="mb-3">
<label for="organization" class="form-label">Organization</label>
<input
type="text"
class="form-control"
id="organization"
name="organization"
value="myorg"
/>
</div>
<div class="mb-3">
<label for="ssl" class="form-label">SSL</label>
<select class="form-control" id="ssl" name="ssl">
{#each ['true', 'false'] as option}
<option>{option}</option>
{/each}
</select>
</div>
<div class="mb-3">
<label for="batch_size" class="form-label">Batch Size</label>
<input
type="number"
class="form-control"
id="batch_size"
name="batch_size"
value="200"
/>
</div>
<div class="mb-3">
<label for="retry_interval" class="form-label">Retry Interval</label>
<input
type="text"
class="form-control"
id="retry_interval"
name="retry_interval"
value="1s"
/>
</div>
<div class="mb-3">
<label for="retry_exponential_base" class="form-label"
>Retry Exponential Base</label
>
<input
type="number"
class="form-control"
id="retry_exponential_base"
name="retry_exponential_base"
value="2"
/>
</div>
<div class="mb-3">
<label for="max_retries" class="form-label">Max Retries</label>
<input
type="number"
class="form-control"
id="max_retries"
name="max_retries"
value="20"
/>
</div>
<div class="mb-3">
<label for="max_retry_time" class="form-label">Max Retry Time</label>
<input
type="text"
class="form-control"
id="max_retry_time"
name="max_retry_time"
value="168h"
/>
</div>
<div class="mb-3">
<label for="meta_as_tags" class="form-label">Meta as Tags</label>
<input
type="text"
class="form-control"
id="meta_as_tags"
name="meta_as_tags"
value="[]"
/>
</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>

View File

@ -0,0 +1,30 @@
<script>
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'sveltestrap';
import InfoxDbConf from './InfluxDbConf.svelte';
import { onMount } from 'svelte';
let isOpen = false;
let influxDbConfig = {};
onMount(async () => {
// Fetch the default values of influxdb configuration from db
const response = await fetch('/api/influxdb-config');
influxDbConfig = await response.json();
});
const toggle = () => {
isOpen = !isOpen;
};
</script>
<Button color="primary btn" style="" on:click={toggle}>Show InfluxDB Configuration</Button>
<Modal isOpen={isOpen} toggle={toggle}>
<ModalHeader toggle={toggle}>InfluxDB Configuration</ModalHeader>
<ModalBody style="max-height: calc(100vh - 210px); overflow-y: auto;">
<InfoxDbConf {influxDbConfig} />
</ModalBody>
<ModalFooter>
<Button color="secondary" on:click={toggle}>Close</Button>
</ModalFooter>
</Modal>

View File

@ -0,0 +1,13 @@
import {} from './header.entrypoint.js'
import History from './History.svelte'
new History({
target: document.getElementById('svelte-app'),
props: {
filterPresets: filterPresets
},
context: new Map([
['cc-config', clusterCockpitConfig]
])
})

View File

@ -0,0 +1,36 @@
<script>
import { Table } from 'sveltestrap';
let data = [
{ username: 'user1', linuxMachine: 'machine1', usage: '20%', role: 'admin' },
{ username: 'user2', linuxMachine: 'machine2', usage: '30%', role: 'user' },
// Add more data as needed
];
</script>
<style>
.bg-light {
background-color: #f8f9fa; /* This is the color Bootstrap uses for .bg-light */
}
</style>
<Table striped>
<thead>
<tr>
<th>Username</th>
<th>Linux-machine</th>
<th>Usage</th>
<th>Role</th>
</tr>
</thead>
<tbody>
{#each data as item (item.username)}
<tr>
<td class=""><p class="font-weight-light">{item.username}</p></td>
<td class="bg-light">{item.linuxMachine}</td>
<td class="bg-light">{item.usage}</td>
<td class="bg-light">{item.role}</td>
</tr>
{/each}
</tbody>
</Table>

View File

@ -0,0 +1,15 @@
{{define "content"}}
<div id="svelte-app"></div>
{{end}}
{{define "stylesheets"}}
<link rel='stylesheet' href='/build/history.css'>
{{end}}
{{define "javascript"}}
<script>
const cluster = {{ .Infos.cluster }};
const filterPresets = {{ .FilterPresets }};
const clusterCockpitConfig = {{ .Config }};
</script>
<script src='/build/history.js'></script>
{{end}}