mirror of
https://github.com/ClusterCockpit/cc-backend
synced 2026-06-17 17:07:29 +02:00
Merge branch 'main' into feature/526-average-resample
This commit is contained in:
80
web/frontend/package-lock.json
generated
80
web/frontend/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "cc-frontend",
|
||||
"version": "1.5.2",
|
||||
"version": "1.5.3",
|
||||
"lockfileVersion": 4,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "cc-frontend",
|
||||
"version": "1.5.2",
|
||||
"version": "1.5.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@rollup/plugin-replace": "^6.0.3",
|
||||
@@ -608,9 +608,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@sveltejs/acorn-typescript": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.9.tgz",
|
||||
"integrity": "sha512-lVJX6qEgs/4DOcRTpo56tmKzVPtoWAaVbL4hfO7t7NVwl9AAXzQR6cihesW1BmNMPl+bK6dreu2sOKBP2Q9CIA==",
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.10.tgz",
|
||||
"integrity": "sha512-4WfKk68eTih+MiJD4fSbxN7E8kVBmTMPWHUPYjvl2N0rMs53YLTT8/YjKU5Dtnz5LqDjl7LEw4U7lXR2W3J5WA==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"acorn": "^8.9.0"
|
||||
@@ -654,19 +654,6 @@
|
||||
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "8.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.1.tgz",
|
||||
"integrity": "sha512-S29BOBPJSFUiblEl6RzPPjJt6w25A6XsBqRVDt53tA/tlL8q7ceQNZHTjPeONt/3S7KRI4quk+yP9jK2WjBiPQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@urql/core": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@urql/core/-/core-5.2.0.tgz",
|
||||
@@ -803,9 +790,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/devalue": {
|
||||
"version": "5.6.4",
|
||||
"resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.4.tgz",
|
||||
"integrity": "sha512-Gp6rDldRsFh/7XuouDbxMH3Mx8GMCcgzIb1pDTvNyn8pZGQ22u+Wa+lGV9dQCltFQ7uVw0MhRyb8XDskNFOReA==",
|
||||
"version": "5.8.1",
|
||||
"resolved": "https://registry.npmjs.org/devalue/-/devalue-5.8.1.tgz",
|
||||
"integrity": "sha512-4CXDYRBGqN+57wVJkuXBYmpAVUSg3L6JAQa/DFqm238G73E1wuyc/JhGQJzN7vUf/CMphYau2zXbfWzDR5aTEw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/escape-latex": {
|
||||
@@ -821,13 +808,20 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/esrap": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.4.tgz",
|
||||
"integrity": "sha512-suICpxAmZ9A8bzJjEl/+rLJiDKC0X4gYWUxT6URAWBLvlXmtbZd5ySMu/N2ZGEtMCAmflUDPSehrP9BQcsGcSg==",
|
||||
"version": "2.2.9",
|
||||
"resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.9.tgz",
|
||||
"integrity": "sha512-4KijP+NxCWthMCUC3qHbE6n4vCjqgJS1uAYKhuT/GWfFTf1Qyive2TgOjep+gzbSzRfnNyaN/UU9YmdOt8Eg0A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/sourcemap-codec": "^1.4.15",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.15"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@typescript-eslint/types": "^8.2.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@typescript-eslint/types": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/estree-walker": {
|
||||
@@ -968,9 +962,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/mathjs": {
|
||||
"version": "15.1.1",
|
||||
"resolved": "https://registry.npmjs.org/mathjs/-/mathjs-15.1.1.tgz",
|
||||
"integrity": "sha512-rM668DTtpSzMVoh/cKAllyQVEbBApM5g//IMGD8vD7YlrIz9ITRr3SrdhjaDxcBNTdyETWwPebj2unZyHD7ZdA==",
|
||||
"version": "15.2.0",
|
||||
"resolved": "https://registry.npmjs.org/mathjs/-/mathjs-15.2.0.tgz",
|
||||
"integrity": "sha512-UAQzSVob9rNLdGpqcFMYmSu9dkuLYy7Lr2hBEQS5SHQdknA9VppJz3cy2KkpMzTODunad6V6cNv+5kOLsePLow==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.26.10",
|
||||
@@ -998,9 +992,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
|
||||
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
@@ -1134,9 +1128,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/rollup-plugin-svelte/node_modules/picomatch": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
|
||||
"integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -1153,9 +1147,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/serialize-javascript": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.0.4.tgz",
|
||||
"integrity": "sha512-DuGdB+Po43Q5Jxwpzt1lhyFSYKryqoNjQSA9M92tyw0lyHIOur+XCalOUe0KTJpyqzT8+fQ5A0Jf7vCx/NKmIg==",
|
||||
"version": "7.0.5",
|
||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.0.5.tgz",
|
||||
"integrity": "sha512-F4LcB0UqUl1zErq+1nYEEzSHJnIwb3AF2XWB94b+afhrekOUijwooAYqFyRbjYkm2PAKBabx6oYv/xDxNi8IBw==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
@@ -1207,23 +1201,23 @@
|
||||
}
|
||||
},
|
||||
"node_modules/svelte": {
|
||||
"version": "5.54.0",
|
||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.54.0.tgz",
|
||||
"integrity": "sha512-TTDxwYnHkova6Wsyj1PGt9TByuWqvMoeY1bQiuAf2DM/JeDSMw7FjRKzk8K/5mJ99vGOKhbCqTDpyAKwjp4igg==",
|
||||
"version": "5.55.10",
|
||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.55.10.tgz",
|
||||
"integrity": "sha512-v9mFVBY1USosyIWdXE7Cg4AN0ywyKCMcAhONvli8doMowEhFhMdNLKD1j7O/UnsrdVTHaUOk/jv8hD/HClVy+g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/remapping": "^2.3.4",
|
||||
"@jridgewell/sourcemap-codec": "^1.5.0",
|
||||
"@sveltejs/acorn-typescript": "^1.0.5",
|
||||
"@sveltejs/acorn-typescript": "^1.0.10",
|
||||
"@types/estree": "^1.0.5",
|
||||
"@types/trusted-types": "^2.0.7",
|
||||
"acorn": "^8.12.1",
|
||||
"aria-query": "5.3.1",
|
||||
"axobject-query": "^4.1.0",
|
||||
"clsx": "^2.1.1",
|
||||
"devalue": "^5.6.4",
|
||||
"devalue": "^5.8.1",
|
||||
"esm-env": "^1.2.1",
|
||||
"esrap": "^2.2.2",
|
||||
"esrap": "^2.2.9",
|
||||
"is-reference": "^3.0.3",
|
||||
"locate-character": "^3.0.0",
|
||||
"magic-string": "^0.30.11",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cc-frontend",
|
||||
"version": "1.5.2",
|
||||
"version": "1.5.3",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "rollup -c",
|
||||
|
||||
@@ -237,7 +237,7 @@
|
||||
The following note was added by administrators:
|
||||
</Card>
|
||||
<Card body>
|
||||
{@html thisJob.metaData.message}
|
||||
<span style="white-space: pre-wrap">{thisJob.metaData.message}</span>
|
||||
</Card>
|
||||
</CardBody>
|
||||
</TabPane>
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
let entries = $state([]);
|
||||
let loading = $state(false);
|
||||
let error = $state(null);
|
||||
let timer = $state(null);
|
||||
let timer = null;
|
||||
|
||||
function levelColor(priority) {
|
||||
if (priority <= 2) return "danger";
|
||||
|
||||
@@ -54,11 +54,16 @@
|
||||
const paging = { itemsPerPage: 50, page: 1 };
|
||||
const sorting = { field: "startTime", type: "col", order: "DESC" };
|
||||
const nodeMetricsQuery = gql`
|
||||
query ($cluster: String!, $nodes: [String!], $from: Time!, $to: Time!) {
|
||||
query (
|
||||
$cluster: String!,
|
||||
$nodes: [String!],
|
||||
$from: Time!,
|
||||
$to: Time!,
|
||||
$nodeFilter: [NodeFilter!]!,
|
||||
$sorting: OrderByInput!
|
||||
) {
|
||||
nodeMetrics(cluster: $cluster, nodes: $nodes, from: $from, to: $to) {
|
||||
host
|
||||
nodeState
|
||||
metricHealth
|
||||
subCluster
|
||||
metrics {
|
||||
name
|
||||
@@ -79,7 +84,14 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
nodeStatus: nodes(filter: $nodeFilter, order: $sorting) {
|
||||
count
|
||||
items {
|
||||
schedulerState
|
||||
healthState
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
const nodeJobsQuery = gql`
|
||||
@@ -146,6 +158,8 @@
|
||||
nodes: [hostname],
|
||||
from: from?.toISOString(),
|
||||
to: to?.toISOString(),
|
||||
nodeFilter: { hostname: { eq: hostname }},
|
||||
sorting // $sorting unused in backend: Use placeholder
|
||||
},
|
||||
})
|
||||
);
|
||||
@@ -157,8 +171,8 @@
|
||||
})
|
||||
);
|
||||
|
||||
const thisNodeState = $derived($nodeMetricsData?.data?.nodeMetrics[0]?.nodeState || 'notindb');
|
||||
const thisMetricHealth = $derived($nodeMetricsData?.data?.nodeMetrics[0]?.metricHealth || 'unknown');
|
||||
const thisNodeState = $derived($nodeMetricsData?.data?.nodeStatus?.items[0]?.schedulerState || 'notindb');
|
||||
const thisMetricHealth = $derived($nodeMetricsData?.data?.nodeStatus?.items[0]?.healthState || 'unknown');
|
||||
</script>
|
||||
|
||||
<Row cols={{ xs: 2, lg: 3}}>
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
userMatch: "contains",
|
||||
// Filter Modals
|
||||
cluster: null,
|
||||
subCluster: null,
|
||||
partition: null,
|
||||
states: allJobStates,
|
||||
shared: "",
|
||||
@@ -107,6 +108,7 @@
|
||||
user: filterPresets?.user || "",
|
||||
userMatch: filterPresets?.userMatch || "contains",
|
||||
cluster: filterPresets?.cluster || null,
|
||||
subCluster: filterPresets?.subCluster || null,
|
||||
partition: filterPresets?.partition || null,
|
||||
states:
|
||||
filterPresets?.states || filterPresets?.state
|
||||
@@ -158,6 +160,7 @@
|
||||
if (filters.dbId.length != 0)
|
||||
items.push({ dbId: filters.dbId });
|
||||
if (filters.cluster) items.push({ cluster: { eq: filters.cluster } });
|
||||
if (filters.subCluster) items.push({ subCluster: { eq: filters.subCluster } });
|
||||
if (filters.partition) items.push({ partition: { eq: filters.partition } });
|
||||
if (filters.states.length != allJobStates?.length)
|
||||
items.push({ state: filters.states });
|
||||
@@ -166,12 +169,12 @@
|
||||
items.push({ project: { [filters.projectMatch]: filters.project } });
|
||||
if (filters.user)
|
||||
items.push({ user: { [filters.userMatch]: filters.user } });
|
||||
if (filters.numNodes.from != null || filters.numNodes.to != null) {
|
||||
if (filters.numNodes.from != null && filters.numNodes.to != null) {
|
||||
items.push({
|
||||
numNodes: { from: filters.numNodes.from, to: filters.numNodes.to },
|
||||
});
|
||||
}
|
||||
if (filters.numAccelerators.from != null || filters.numAccelerators.to != null) {
|
||||
if (filters.numAccelerators.from != null && filters.numAccelerators.to != null) {
|
||||
items.push({
|
||||
numAccelerators: {
|
||||
from: filters.numAccelerators.from,
|
||||
@@ -179,7 +182,7 @@
|
||||
},
|
||||
});
|
||||
}
|
||||
if (filters.numHWThreads.from != null || filters.numHWThreads.to != null) {
|
||||
if (filters.numHWThreads.from != null && filters.numHWThreads.to != null) {
|
||||
items.push({
|
||||
numHWThreads: {
|
||||
from: filters.numHWThreads.from,
|
||||
@@ -206,14 +209,21 @@
|
||||
items.push({ duration: { to: filters.duration.lessThan, from: 0 } });
|
||||
if (filters.duration.moreThan)
|
||||
items.push({ duration: { to: 0, from: filters.duration.moreThan } });
|
||||
if (filters.energy.from != null || filters.energy.to != null)
|
||||
if (filters.energy.from != null && filters.energy.to != null)
|
||||
items.push({
|
||||
energy: { from: filters.energy.from, to: filters.energy.to },
|
||||
});
|
||||
if (filters.jobId)
|
||||
items.push({ jobId: { [filters.jobIdMatch]: filters.jobId } });
|
||||
if (filters.stats.length != 0)
|
||||
items.push({ metricStats: filters.stats.map((st) => { return { metricName: st.field, range: { from: st.from, to: st.to }} }) });
|
||||
if (filters.stats.length != 0) {
|
||||
const metricStats = [];
|
||||
filters.stats.forEach((st) => {
|
||||
if (st.from != null && st.to != null)
|
||||
metricStats.push({ metricName: st.field, range: { from: st.from, to: st.to }});
|
||||
});
|
||||
if (metricStats.length != 0)
|
||||
items.push({metricStats})
|
||||
};
|
||||
if (filters.node) items.push({ node: { [filters.nodeMatch]: filters.node } });
|
||||
if (filters.jobName) items.push({ jobName: { contains: filters.jobName } });
|
||||
if (filters.schedule) items.push({ schedule: filters.schedule });
|
||||
@@ -260,6 +270,7 @@
|
||||
opts.push(`userMatch=${filters.userMatch}`);
|
||||
// Filter Modals
|
||||
if (filters.cluster) opts.push(`cluster=${filters.cluster}`);
|
||||
if (filters.subCluster) opts.push(`subCluster=${filters.subCluster}`);
|
||||
if (filters.partition) opts.push(`partition=${filters.partition}`);
|
||||
if (filters.states.length != allJobStates?.length)
|
||||
for (let state of filters.states) opts.push(`state=${state}`);
|
||||
@@ -280,40 +291,40 @@
|
||||
opts.push(`duration=morethan-${filters.duration.moreThan}`);
|
||||
if (filters.tags.length != 0)
|
||||
for (let tag of filters.tags) opts.push(`tag=${tag}`);
|
||||
if (filters.numNodes.from > 1 && filters.numNodes.to > 0)
|
||||
if (filters.numNodes.from > 0 && filters.numNodes.to > 0)
|
||||
opts.push(`numNodes=${filters.numNodes.from}-${filters.numNodes.to}`);
|
||||
else if (filters.numNodes.from > 1 && filters.numNodes.to == 0)
|
||||
else if (filters.numNodes.from > 0 && filters.numNodes.to == 0)
|
||||
opts.push(`numNodes=morethan-${filters.numNodes.from}`);
|
||||
else if (filters.numNodes.from == 1 && filters.numNodes.to > 0)
|
||||
else if (filters.numNodes.from == 0 && filters.numNodes.to > 0)
|
||||
opts.push(`numNodes=lessthan-${filters.numNodes.to}`);
|
||||
if (filters.numHWThreads.from > 1 && filters.numHWThreads.to > 0)
|
||||
if (filters.numHWThreads.from > 0 && filters.numHWThreads.to > 0)
|
||||
opts.push(`numHWThreads=${filters.numHWThreads.from}-${filters.numHWThreads.to}`);
|
||||
else if (filters.numHWThreads.from > 1 && filters.numHWThreads.to == 0)
|
||||
else if (filters.numHWThreads.from > 0 && filters.numHWThreads.to == 0)
|
||||
opts.push(`numHWThreads=morethan-${filters.numHWThreads.from}`);
|
||||
else if (filters.numHWThreads.from == 1 && filters.numHWThreads.to > 0)
|
||||
else if (filters.numHWThreads.from == 0 && filters.numHWThreads.to > 0)
|
||||
opts.push(`numHWThreads=lessthan-${filters.numHWThreads.to}`);
|
||||
if (filters.numAccelerators.from && filters.numAccelerators.to)
|
||||
if (filters.numAccelerators.from > 0 && filters.numAccelerators.to > 0)
|
||||
opts.push(`numAccelerators=${filters.numAccelerators.from}-${filters.numAccelerators.to}`);
|
||||
else if (filters.numAccelerators.from > 1 && filters.numAccelerators.to == 0)
|
||||
else if (filters.numAccelerators.from > 0 && filters.numAccelerators.to == 0)
|
||||
opts.push(`numAccelerators=morethan-${filters.numAccelerators.from}`);
|
||||
else if (filters.numAccelerators.from == 1 && filters.numAccelerators.to > 0)
|
||||
else if (filters.numAccelerators.from == 0 && filters.numAccelerators.to > 0)
|
||||
opts.push(`numAccelerators=lessthan-${filters.numAccelerators.to}`);
|
||||
if (filters.node) opts.push(`node=${filters.node}`);
|
||||
if (filters.node && filters.nodeMatch != "eq") // "eq" is default-case
|
||||
opts.push(`nodeMatch=${filters.nodeMatch}`);
|
||||
if (filters.energy.from > 1 && filters.energy.to > 0)
|
||||
if (filters.energy.from > 0 && filters.energy.to > 0)
|
||||
opts.push(`energy=${filters.energy.from}-${filters.energy.to}`);
|
||||
else if (filters.energy.from > 1 && filters.energy.to == 0)
|
||||
else if (filters.energy.from > 0 && filters.energy.to == 0)
|
||||
opts.push(`energy=morethan-${filters.energy.from}`);
|
||||
else if (filters.energy.from == 1 && filters.energy.to > 0)
|
||||
else if (filters.energy.from == 0 && filters.energy.to > 0)
|
||||
opts.push(`energy=lessthan-${filters.energy.to}`);
|
||||
if (filters.stats.length > 0)
|
||||
for (let stat of filters.stats) {
|
||||
if (stat.from > 1 && stat.to > 0)
|
||||
if (stat.from > 0 && stat.to > 0)
|
||||
opts.push(`stat=${stat.field}-${stat.from}-${stat.to}`);
|
||||
else if (stat.from > 1 && stat.to == 0)
|
||||
else if (stat.from > 0 && stat.to == 0)
|
||||
opts.push(`stat=${stat.field}-morethan-${stat.from}`);
|
||||
else if (stat.from == 1 && stat.to > 0)
|
||||
else if (stat.from == 0 && stat.to > 0)
|
||||
opts.push(`stat=${stat.field}-lessthan-${stat.to}`);
|
||||
}
|
||||
// Build && Return
|
||||
@@ -339,7 +350,7 @@
|
||||
{/if}
|
||||
<DropdownItem header>Manage Filters</DropdownItem>
|
||||
<DropdownItem onclick={() => (isClusterOpen = true)}>
|
||||
<Icon name="cpu" /> Cluster/Partition
|
||||
<Icon name="cpu" /> Cluster/SubCluster/Partition
|
||||
</DropdownItem>
|
||||
<DropdownItem onclick={() => (isJobStatesOpen = true)}>
|
||||
<Icon name="gear-fill" /> Job States
|
||||
@@ -433,6 +444,9 @@
|
||||
{#if filters.cluster}
|
||||
<Info icon="cpu" onclick={() => (isClusterOpen = true)}>
|
||||
{filters.cluster}
|
||||
{#if filters.subCluster}
|
||||
[{filters.subCluster}]
|
||||
{/if}
|
||||
{#if filters.partition}
|
||||
({filters.partition})
|
||||
{/if}
|
||||
@@ -511,43 +525,43 @@
|
||||
</Info>
|
||||
{/if}
|
||||
|
||||
{#if filters.numNodes.from > 1 && filters.numNodes.to > 0}
|
||||
{#if filters.numNodes.from > 0 && filters.numNodes.to > 0}
|
||||
<Info icon="hdd-stack" onclick={() => (isResourcesOpen = true)}>
|
||||
Nodes: {filters.numNodes.from} - {filters.numNodes.to}
|
||||
</Info>
|
||||
{:else if filters.numNodes.from > 1 && filters.numNodes.to == 0}
|
||||
{:else if filters.numNodes.from > 0 && filters.numNodes.to == 0}
|
||||
<Info icon="hdd-stack" onclick={() => (isResourcesOpen = true)}>
|
||||
≥ {filters.numNodes.from} Node(s)
|
||||
</Info>
|
||||
{:else if filters.numNodes.from == 1 && filters.numNodes.to > 0}
|
||||
{:else if filters.numNodes.from == 0 && filters.numNodes.to > 0}
|
||||
<Info icon="hdd-stack" onclick={() => (isResourcesOpen = true)}>
|
||||
≤ {filters.numNodes.to} Node(s)
|
||||
</Info>
|
||||
{/if}
|
||||
|
||||
{#if filters.numHWThreads.from > 1 && filters.numHWThreads.to > 0}
|
||||
{#if filters.numHWThreads.from > 0 && filters.numHWThreads.to > 0}
|
||||
<Info icon="cpu" onclick={() => (isResourcesOpen = true)}>
|
||||
HWThreads: {filters.numHWThreads.from} - {filters.numHWThreads.to}
|
||||
</Info>
|
||||
{:else if filters.numHWThreads.from > 1 && filters.numHWThreads.to == 0}
|
||||
{:else if filters.numHWThreads.from > 0 && filters.numHWThreads.to == 0}
|
||||
<Info icon="cpu" onclick={() => (isResourcesOpen = true)}>
|
||||
≥ {filters.numHWThreads.from} HWThread(s)
|
||||
</Info>
|
||||
{:else if filters.numHWThreads.from == 1 && filters.numHWThreads.to > 0}
|
||||
{:else if filters.numHWThreads.from == 0 && filters.numHWThreads.to > 0}
|
||||
<Info icon="cpu" onclick={() => (isResourcesOpen = true)}>
|
||||
≤ {filters.numHWThreads.to} HWThread(s)
|
||||
</Info>
|
||||
{/if}
|
||||
|
||||
{#if filters.numAccelerators.from > 1 && filters.numAccelerators.to > 0}
|
||||
{#if filters.numAccelerators.from > 0 && filters.numAccelerators.to > 0}
|
||||
<Info icon="gpu-card" onclick={() => (isResourcesOpen = true)}>
|
||||
Accelerators: {filters.numAccelerators.from} - {filters.numAccelerators.to}
|
||||
</Info>
|
||||
{:else if filters.numAccelerators.from > 1 && filters.numAccelerators.to == 0}
|
||||
{:else if filters.numAccelerators.from > 0 && filters.numAccelerators.to == 0}
|
||||
<Info icon="gpu-card" onclick={() => (isResourcesOpen = true)}>
|
||||
≥ {filters.numAccelerators.from} Acc(s)
|
||||
</Info>
|
||||
{:else if filters.numAccelerators.from == 1 && filters.numAccelerators.to > 0}
|
||||
{:else if filters.numAccelerators.from == 0 && filters.numAccelerators.to > 0}
|
||||
<Info icon="gpu-card" onclick={() => (isResourcesOpen = true)}>
|
||||
≤ {filters.numAccelerators.to} Acc(s)
|
||||
</Info>
|
||||
@@ -559,15 +573,15 @@
|
||||
</Info>
|
||||
{/if}
|
||||
|
||||
{#if filters.energy.from > 1 && filters.energy.to > 0}
|
||||
{#if filters.energy.from > 0 && filters.energy.to > 0}
|
||||
<Info icon="lightning-charge-fill" onclick={() => (isEnergyOpen = true)}>
|
||||
Total Energy: {filters.energy.from} - {filters.energy.to} kWh
|
||||
</Info>
|
||||
{:else if filters.energy.from > 1 && filters.energy.to == 0}
|
||||
{:else if filters.energy.from > 0 && filters.energy.to == 0}
|
||||
<Info icon="lightning-charge-fill" onclick={() => (isEnergyOpen = true)}>
|
||||
Total Energy ≥ {filters.energy.from} kWh
|
||||
</Info>
|
||||
{:else if filters.energy.from == 1 && filters.energy.to > 0}
|
||||
{:else if filters.energy.from == 0 && filters.energy.to > 0}
|
||||
<Info icon="lightning-charge-fill" onclick={() => (isEnergyOpen = true)}>
|
||||
Total Energy ≤ {filters.energy.to} kWh
|
||||
</Info>
|
||||
@@ -575,15 +589,15 @@
|
||||
|
||||
{#if filters.stats.length > 0}
|
||||
{#each filters.stats as stat}
|
||||
{#if stat.from > 1 && stat.to > 0}
|
||||
{#if stat.from > 0 && stat.to > 0}
|
||||
<Info icon="bar-chart" onclick={() => (isStatsOpen = true)}>
|
||||
{stat.field}: {stat.from} - {stat.to} {stat.unit}
|
||||
</Info> 
|
||||
{:else if stat.from > 1 && stat.to == 0}
|
||||
{:else if stat.from > 0 && stat.to == 0}
|
||||
<Info icon="bar-chart" onclick={() => (isStatsOpen = true)}>
|
||||
{stat.field} ≥ {stat.from} {stat.unit}
|
||||
</Info> 
|
||||
{:else if stat.from == 1 && stat.to > 0}
|
||||
{:else if stat.from == 0 && stat.to > 0}
|
||||
<Info icon="bar-chart" onclick={() => (isStatsOpen = true)}>
|
||||
{stat.field} ≤ {stat.to} {stat.unit}
|
||||
</Info> 
|
||||
@@ -596,6 +610,7 @@
|
||||
bind:isOpen={isClusterOpen}
|
||||
presetCluster={filters.cluster}
|
||||
presetPartition={filters.partition}
|
||||
presetSubCluster={filters.subCluster}
|
||||
{disableClusterSelection}
|
||||
setFilter={(filter) => updateFilters(filter)}
|
||||
/>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<!--
|
||||
@component Filter sub-component for selecting cluster and subCluster
|
||||
@component Filter sub-component for selecting cluster, partition and subCluster
|
||||
|
||||
Properties:
|
||||
- `isOpen Bool?`: Is this filter component opened [Bindable, Default: false]
|
||||
- `presetCluster String?`: The latest selected cluster [Default: ""]
|
||||
- `presetPartition String?`: The latest selected partition [Default: ""]
|
||||
- `presetSubCluster String?`: The latest selected subCluster [Default: ""]
|
||||
- `disableClusterSelection Bool?`: Is the selection disabled [Default: false]
|
||||
- `setFilter Func`: The callback function to apply current filter selection
|
||||
-->
|
||||
@@ -26,6 +27,7 @@
|
||||
isOpen = $bindable(false),
|
||||
presetCluster = "",
|
||||
presetPartition = "",
|
||||
presetSubCluster = "",
|
||||
disableClusterSelection = false,
|
||||
setFilter
|
||||
} = $props();
|
||||
@@ -36,10 +38,11 @@
|
||||
const clusterInfos = $derived($initialized ? getContext("clusters") : null);
|
||||
let pendingCluster = $derived(presetCluster);
|
||||
let pendingPartition = $derived(presetPartition);
|
||||
let pendingSubCluster = $derived(presetSubCluster);
|
||||
</script>
|
||||
|
||||
<Modal {isOpen} toggle={() => (isOpen = !isOpen)}>
|
||||
<ModalHeader>Select Cluster & Slurm Partition</ModalHeader>
|
||||
<ModalHeader>Select Cluster, SubCluster & Partition</ModalHeader>
|
||||
<ModalBody>
|
||||
{#if $initialized}
|
||||
<h4>Cluster</h4>
|
||||
@@ -51,7 +54,7 @@
|
||||
<ListGroupItem
|
||||
disabled={disableClusterSelection}
|
||||
active={pendingCluster == null}
|
||||
onclick={() => ((pendingCluster = null), (pendingPartition = null))}
|
||||
onclick={() => ((pendingCluster = null), (pendingPartition = null), (pendingSubCluster = null))}
|
||||
>
|
||||
Any Cluster
|
||||
</ListGroupItem>
|
||||
@@ -60,7 +63,7 @@
|
||||
disabled={disableClusterSelection}
|
||||
active={pendingCluster == cluster.name}
|
||||
onclick={() => (
|
||||
(pendingCluster = cluster.name), (pendingPartition = null)
|
||||
(pendingCluster = cluster.name), (pendingPartition = null), (pendingSubCluster = null)
|
||||
)}
|
||||
>
|
||||
{cluster.name}
|
||||
@@ -71,7 +74,27 @@
|
||||
{/if}
|
||||
{#if $initialized && pendingCluster != null}
|
||||
<br />
|
||||
<h4>Partiton</h4>
|
||||
<h4>SubCluster</h4>
|
||||
<ListGroup>
|
||||
<ListGroupItem
|
||||
active={pendingSubCluster == null}
|
||||
onclick={() => (pendingSubCluster = null)}
|
||||
>
|
||||
Any SubCluster
|
||||
</ListGroupItem>
|
||||
{#each clusterInfos?.find((c) => c.name == pendingCluster)?.subClusters as subCluster}
|
||||
<ListGroupItem
|
||||
active={pendingSubCluster == subCluster.name}
|
||||
onclick={() => (pendingSubCluster = subCluster.name)}
|
||||
>
|
||||
{subCluster.name}
|
||||
</ListGroupItem>
|
||||
{/each}
|
||||
</ListGroup>
|
||||
{/if}
|
||||
{#if $initialized && pendingCluster != null}
|
||||
<br />
|
||||
<h4>Partition</h4>
|
||||
<ListGroup>
|
||||
<ListGroupItem
|
||||
active={pendingPartition == null}
|
||||
@@ -95,7 +118,7 @@
|
||||
color="primary"
|
||||
onclick={() => {
|
||||
isOpen = false;
|
||||
setFilter({ cluster: pendingCluster, partition: pendingPartition });
|
||||
setFilter({ cluster: pendingCluster, subCluster: pendingSubCluster, partition: pendingPartition });
|
||||
}}>Close & Apply</Button
|
||||
>
|
||||
{#if !disableClusterSelection}
|
||||
@@ -105,7 +128,8 @@
|
||||
isOpen = false;
|
||||
pendingCluster = null;
|
||||
pendingPartition = null;
|
||||
setFilter({ cluster: pendingCluster, partition: pendingPartition})
|
||||
pendingSubCluster = null;
|
||||
setFilter({ cluster: pendingCluster, subCluster: pendingSubCluster, partition: pendingPartition })
|
||||
}}>Reset</Button
|
||||
>
|
||||
{/if}
|
||||
|
||||
@@ -28,31 +28,29 @@
|
||||
} = $props();
|
||||
|
||||
/* Const */
|
||||
const minEnergyPreset = 1;
|
||||
const minEnergyPreset = 0;
|
||||
const maxEnergyPreset = 100;
|
||||
|
||||
/* Derived */
|
||||
// Pending
|
||||
let pendingEnergyState = $derived({
|
||||
from: presetEnergy?.from ? presetEnergy.from : minEnergyPreset,
|
||||
to: !(presetEnergy.to == null || presetEnergy.to == 0) ? presetEnergy.to : maxEnergyPreset,
|
||||
from: presetEnergy?.from || minEnergyPreset,
|
||||
to: (presetEnergy.to == 0) ? null : presetEnergy.to,
|
||||
});
|
||||
// Changable
|
||||
let energyState = $derived({
|
||||
from: presetEnergy?.from ? presetEnergy.from : minEnergyPreset,
|
||||
to: !(presetEnergy.to == null || presetEnergy.to == 0) ? presetEnergy.to : maxEnergyPreset,
|
||||
from: presetEnergy?.from || minEnergyPreset,
|
||||
to: (presetEnergy.to == 0) ? null : presetEnergy.to,
|
||||
});
|
||||
|
||||
const energyActive = $derived(!(JSON.stringify(energyState) === JSON.stringify({ from: minEnergyPreset, to: maxEnergyPreset })));
|
||||
// Block Apply if null
|
||||
const disableApply = $derived(energyState.from === null || energyState.to === null);
|
||||
const energyActive = $derived(!(JSON.stringify(energyState) === JSON.stringify({ from: minEnergyPreset, to: null })));
|
||||
|
||||
/* Function */
|
||||
function setEnergy() {
|
||||
if (energyActive) {
|
||||
pendingEnergyState = {
|
||||
from: energyState.from,
|
||||
to: (energyState.to == maxEnergyPreset) ? 0 : energyState.to
|
||||
from: (!energyState?.from) ? 0 : energyState.from,
|
||||
to: (energyState.to === null) ? 0 : energyState.to
|
||||
};
|
||||
} else {
|
||||
pendingEnergyState = { from: null, to: null};
|
||||
@@ -86,7 +84,6 @@
|
||||
<ModalFooter>
|
||||
<Button
|
||||
color="primary"
|
||||
disabled={disableApply}
|
||||
onclick={() => {
|
||||
isOpen = false;
|
||||
setEnergy();
|
||||
|
||||
@@ -98,44 +98,38 @@
|
||||
// Pending
|
||||
let pendingNumNodes = $derived({
|
||||
from: presetNumNodes.from,
|
||||
to: (presetNumNodes.to == 0) ? maxNumNodes : presetNumNodes.to
|
||||
to: (presetNumNodes.to == 0) ? null : presetNumNodes.to
|
||||
});
|
||||
let pendingNumHWThreads = $derived({
|
||||
from: presetNumHWThreads.from,
|
||||
to: (presetNumHWThreads.to == 0) ? maxNumHWThreads : presetNumHWThreads.to
|
||||
to: (presetNumHWThreads.to == 0) ? null : presetNumHWThreads.to
|
||||
});
|
||||
let pendingNumAccelerators = $derived({
|
||||
from: presetNumAccelerators.from,
|
||||
to: (presetNumAccelerators.to == 0) ? maxNumAccelerators : presetNumAccelerators.to
|
||||
to: (presetNumAccelerators.to == 0) ? null : presetNumAccelerators.to
|
||||
});
|
||||
let pendingNamedNode = $derived(presetNamedNode);
|
||||
let pendingNodeMatch = $derived(presetNodeMatch);
|
||||
// Changable States
|
||||
let nodesState = $derived({
|
||||
from: presetNumNodes.from,
|
||||
to: (presetNumNodes.to == 0) ? maxNumNodes : presetNumNodes.to
|
||||
from: presetNumNodes?.from || 0,
|
||||
to: (presetNumNodes.to == 0) ? null : presetNumNodes.to
|
||||
});
|
||||
let threadState = $derived({
|
||||
from: presetNumHWThreads.from,
|
||||
to: (presetNumHWThreads.to == 0) ? maxNumHWThreads : presetNumHWThreads.to
|
||||
from: presetNumHWThreads?.from || 0,
|
||||
to: (presetNumHWThreads.to == 0) ? null : presetNumHWThreads.to
|
||||
});
|
||||
let accState = $derived({
|
||||
from: presetNumAccelerators.from,
|
||||
to: (presetNumAccelerators.to == 0) ? maxNumAccelerators : presetNumAccelerators.to
|
||||
from: presetNumAccelerators?.from || 0,
|
||||
to: (presetNumAccelerators.to == 0) ? null : presetNumAccelerators.to
|
||||
});
|
||||
|
||||
const initialized = $derived(getContext("initialized") || false);
|
||||
const clusterInfos = $derived($initialized ? getContext("clusters") : null);
|
||||
// Is Selection Active
|
||||
const nodesActive = $derived(!(JSON.stringify(nodesState) === JSON.stringify({ from: 1, to: maxNumNodes })));
|
||||
const threadActive = $derived(!(JSON.stringify(threadState) === JSON.stringify({ from: 1, to: maxNumHWThreads })));
|
||||
const accActive = $derived(!(JSON.stringify(accState) === JSON.stringify({ from: 1, to: maxNumAccelerators })));
|
||||
// Block Apply if null
|
||||
const disableApply = $derived(
|
||||
nodesState.from === null || nodesState.to === null ||
|
||||
threadState.from === null || threadState.to === null ||
|
||||
accState.from === null || accState.to === null
|
||||
);
|
||||
const nodesActive = $derived(!(JSON.stringify(nodesState) === JSON.stringify({ from: 0, to: null })));
|
||||
const threadActive = $derived(!(JSON.stringify(threadState) === JSON.stringify({ from: 0, to: null })));
|
||||
const accActive = $derived(!(JSON.stringify(accState) === JSON.stringify({ from: 0, to: null })));
|
||||
|
||||
/* Reactive Effects | Svelte 5 onMount */
|
||||
$effect(() => {
|
||||
@@ -153,58 +147,28 @@
|
||||
}
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
if (
|
||||
$initialized &&
|
||||
pendingNumNodes.from == null &&
|
||||
pendingNumNodes.to == null
|
||||
) {
|
||||
nodesState = { from: 1, to: maxNumNodes };
|
||||
}
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
if (
|
||||
$initialized &&
|
||||
pendingNumHWThreads.from == null &&
|
||||
pendingNumHWThreads.to == null
|
||||
) {
|
||||
threadState = { from: 1, to: maxNumHWThreads };
|
||||
}
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
if (
|
||||
$initialized &&
|
||||
pendingNumAccelerators.from == null &&
|
||||
pendingNumAccelerators.to == null
|
||||
) {
|
||||
accState = { from: 1, to: maxNumAccelerators };
|
||||
}
|
||||
});
|
||||
|
||||
/* Functions */
|
||||
function setResources() {
|
||||
if (nodesActive) {
|
||||
pendingNumNodes = {
|
||||
from: nodesState.from,
|
||||
to: (nodesState.to == maxNumNodes) ? 0 : nodesState.to
|
||||
from: (!nodesState?.from) ? 0 : nodesState.from,
|
||||
to: (nodesState.to === null) ? 0 : nodesState.to
|
||||
};
|
||||
} else {
|
||||
pendingNumNodes = { from: null, to: null};
|
||||
};
|
||||
if (threadActive) {
|
||||
pendingNumHWThreads = {
|
||||
from: threadState.from,
|
||||
to: (threadState.to == maxNumHWThreads) ? 0 : threadState.to
|
||||
from: (!threadState?.from) ? 0 : threadState.from,
|
||||
to: (threadState.to === null) ? 0 : threadState.to
|
||||
};
|
||||
} else {
|
||||
pendingNumHWThreads = { from: null, to: null};
|
||||
};
|
||||
if (accActive) {
|
||||
pendingNumAccelerators = {
|
||||
from: accState.from,
|
||||
to: (accState.to == maxNumAccelerators) ? 0 : accState.to
|
||||
from: (!accState?.from) ? 0 : accState.from,
|
||||
to: (accState.to === null) ? 0 : accState.to
|
||||
};
|
||||
} else {
|
||||
pendingNumAccelerators = { from: null, to: null};
|
||||
@@ -249,7 +213,7 @@
|
||||
nodesState.from = detail[0];
|
||||
nodesState.to = detail[1];
|
||||
}}
|
||||
sliderMin={1}
|
||||
sliderMin={0}
|
||||
sliderMax={maxNumNodes}
|
||||
fromPreset={nodesState.from}
|
||||
toPreset={nodesState.to}
|
||||
@@ -269,7 +233,7 @@
|
||||
threadState.from = detail[0];
|
||||
threadState.to = detail[1];
|
||||
}}
|
||||
sliderMin={1}
|
||||
sliderMin={0}
|
||||
sliderMax={maxNumHWThreads}
|
||||
fromPreset={threadState.from}
|
||||
toPreset={threadState.to}
|
||||
@@ -289,7 +253,7 @@
|
||||
accState.from = detail[0];
|
||||
accState.to = detail[1];
|
||||
}}
|
||||
sliderMin={1}
|
||||
sliderMin={0}
|
||||
sliderMax={maxNumAccelerators}
|
||||
fromPreset={accState.from}
|
||||
toPreset={accState.to}
|
||||
@@ -300,7 +264,6 @@
|
||||
<ModalFooter>
|
||||
<Button
|
||||
color="primary"
|
||||
disabled={disableApply}
|
||||
onclick={() => {
|
||||
isOpen = false;
|
||||
setResources();
|
||||
|
||||
@@ -34,7 +34,8 @@
|
||||
function setRanges() {
|
||||
for (let as of availableStats) {
|
||||
if (as.enabled) {
|
||||
as.to = (as.to == as.peak) ? 0 : as.to
|
||||
as.from = (!as?.from) ? 0 : as.from,
|
||||
as.to = (as.to == null) ? 0 : as.to
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -42,8 +43,8 @@
|
||||
function resetRanges() {
|
||||
for (let as of availableStats) {
|
||||
as.enabled = false
|
||||
as.from = 1
|
||||
as.to = as.peak
|
||||
as.from = null
|
||||
as.to = null
|
||||
};
|
||||
}
|
||||
</script>
|
||||
@@ -66,13 +67,13 @@
|
||||
changeRange={(detail) => {
|
||||
aStat.from = detail[0];
|
||||
aStat.to = detail[1];
|
||||
if (aStat.from == 1 && aStat.to == aStat.peak) {
|
||||
if (aStat.from == 0 && aStat.to === null) {
|
||||
aStat.enabled = false;
|
||||
} else {
|
||||
aStat.enabled = true;
|
||||
}
|
||||
}}
|
||||
sliderMin={1}
|
||||
sliderMin={0}
|
||||
sliderMax={aStat.peak}
|
||||
fromPreset={aStat.from}
|
||||
toPreset={aStat.to}
|
||||
|
||||
@@ -228,7 +228,7 @@
|
||||
{/each}
|
||||
{#if job?.metaData?.message}
|
||||
<hr class="mt-1 mb-2" />
|
||||
{@html job.metaData.message}
|
||||
<span style="white-space: pre-wrap">{job.metaData.message}</span>
|
||||
{/if}
|
||||
</CardBody>
|
||||
</Card>
|
||||
|
||||
@@ -287,12 +287,12 @@
|
||||
} else if (nodesData[i]?.schedulerState == "allocated") {
|
||||
//u.ctx.strokeStyle = "rgb(0, 255, 0)";
|
||||
u.ctx.fillStyle = "rgba(0, 255, 0, 0.5)";
|
||||
} else if (nodesData[i]?.schedulerState == "notindb") {
|
||||
} else if (nodesData[i]?.schedulerState == "mixed") {
|
||||
//u.ctx.strokeStyle = "rgb(0, 0, 0)";
|
||||
u.ctx.fillStyle = "rgba(0, 0, 0, 0.5)";
|
||||
} else { // Fallback: All other DEFINED states
|
||||
//u.ctx.strokeStyle = "rgb(255, 0, 0)";
|
||||
u.ctx.fillStyle = "rgba(255, 0, 0, 0.5)";
|
||||
} else { // Fallback: All other states: Reserved, Down, Notindb
|
||||
//u.ctx.strokeStyle = "rgb(255, 0, 0)";
|
||||
u.ctx.fillStyle = "rgba(0, 0, 0, 0.5)";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -450,10 +450,10 @@
|
||||
tooltip.style.borderColor = "rgb(0, 0, 255)";
|
||||
} else if (nodesData[i]?.schedulerState == "allocated") {
|
||||
tooltip.style.borderColor = "rgb(0, 255, 0)";
|
||||
} else if (nodesData[i]?.schedulerState == "notindb") { // Missing from DB table
|
||||
tooltip.style.borderColor = "rgb(0, 0, 0)";
|
||||
} else { // Fallback: All other DEFINED states
|
||||
} else if (nodesData[i]?.schedulerState == "mixed") {
|
||||
tooltip.style.borderColor = "rgb(255, 0, 0)";
|
||||
} else { // Fallback: All other DEFINED states
|
||||
tooltip.style.borderColor = "rgb(0, 0, 0)";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -904,7 +904,7 @@
|
||||
if (jobsData) {
|
||||
const posX = u.valToPos(0.1, "x", true)
|
||||
const posXLimit = u.valToPos(100, "x", true)
|
||||
const posY = u.valToPos(17500.0, "y", true)
|
||||
const posY = 7 // u.valToPos(17500.0, "y", true)
|
||||
u.ctx.fillStyle = 'black'
|
||||
u.ctx.fillText('0 Hours', posX, posY)
|
||||
const start = posX + 10
|
||||
@@ -921,16 +921,16 @@
|
||||
|
||||
// Nodes: The Colors Of NodeStates
|
||||
if (nodesData) {
|
||||
const posY = u.valToPos(17500.0, "y", true)
|
||||
const posY = 7 // u.valToPos(17500.0, "y", true)
|
||||
|
||||
const posAllocDot = u.valToPos(0.03, "x", true)
|
||||
const posAllocText = posAllocDot + 60
|
||||
const posIdleDot = u.valToPos(0.3, "x", true)
|
||||
const posIdleText = posIdleDot + 30
|
||||
const posOtherDot = u.valToPos(3, "x", true)
|
||||
const posIdleDot = u.valToPos(1, "x", true)
|
||||
const posIdleText = posIdleDot + 28
|
||||
const posMixedDot = u.valToPos(7, "x", true)
|
||||
const posMixedText = posMixedDot + 40
|
||||
const posOtherDot = u.valToPos(100, "x", true)
|
||||
const posOtherText = posOtherDot + 40
|
||||
const posMissingDot = u.valToPos(30, "x", true)
|
||||
const posMissingText = posMissingDot + 80
|
||||
|
||||
u.ctx.fillStyle = "rgb(0, 255, 0)"
|
||||
u.ctx.beginPath()
|
||||
@@ -948,16 +948,16 @@
|
||||
|
||||
u.ctx.fillStyle = "rgb(255, 0, 0)"
|
||||
u.ctx.beginPath()
|
||||
u.ctx.arc(posOtherDot, posY, 3, 0, Math.PI * 2, false)
|
||||
u.ctx.arc(posMixedDot, posY, 3, 0, Math.PI * 2, false)
|
||||
u.ctx.fill()
|
||||
u.ctx.fillStyle = 'black'
|
||||
u.ctx.fillText('Other', posOtherText, posY)
|
||||
u.ctx.fillText('Mixed', posMixedText, posY)
|
||||
|
||||
u.ctx.fillStyle = 'black'
|
||||
u.ctx.beginPath()
|
||||
u.ctx.arc(posMissingDot, posY, 3, 0, Math.PI * 2, false)
|
||||
u.ctx.arc(posOtherDot, posY, 3, 0, Math.PI * 2, false)
|
||||
u.ctx.fill()
|
||||
u.ctx.fillText('Missing in DB', posMissingText, posY)
|
||||
u.ctx.fillText('Other', posOtherText, posY)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -338,7 +338,7 @@
|
||||
// The Color Scale For Time Information
|
||||
const posX = u.valToPos(0.1, "x", true)
|
||||
const posXLimit = u.valToPos(100, "x", true)
|
||||
const posY = u.valToPos(14000.0, "y", true)
|
||||
const posY = 7 // u.valToPos(((subCluster?.flopRateSimd?.value || 10000) + 5000), "y", true)
|
||||
u.ctx.fillStyle = 'black'
|
||||
u.ctx.fillText('Start', posX, posY)
|
||||
const start = posX + 10
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
let {
|
||||
sliderMin,
|
||||
sliderMax,
|
||||
fromPreset = 1,
|
||||
fromPreset = 0,
|
||||
toPreset = 100,
|
||||
changeRange
|
||||
} = $props();
|
||||
@@ -33,9 +33,9 @@
|
||||
/* Derived */
|
||||
let pendingValues = $derived([fromPreset, toPreset]);
|
||||
let sliderFrom = $derived(Math.max(((fromPreset == null ? sliderMin : fromPreset) - sliderMin) / (sliderMax - sliderMin), 0.));
|
||||
let sliderTo = $derived(Math.min(((toPreset == null ? sliderMin : toPreset) - sliderMin) / (sliderMax - sliderMin), 1.));
|
||||
let inputFieldFrom = $derived(fromPreset ? fromPreset.toString() : null);
|
||||
let inputFieldTo = $derived(toPreset ? toPreset.toString() : null);
|
||||
let sliderTo = $derived(Math.min(((toPreset == null ? sliderMax : toPreset) - sliderMin) / (sliderMax - sliderMin), 1.));
|
||||
let inputFieldFrom = $derived(fromPreset != null ? fromPreset.toString() : null);
|
||||
let inputFieldTo = $derived(toPreset != null ? toPreset.toString() : null);
|
||||
|
||||
/* Var Init */
|
||||
let timeoutId = null;
|
||||
@@ -79,17 +79,22 @@
|
||||
evt.preventDefault()
|
||||
evt.stopPropagation()
|
||||
const newV = Number.parseInt(evt.target.value);
|
||||
const newP = clamp((newV - sliderMin) / (sliderMax - sliderMin), 0., 1.)
|
||||
const newP = clamp((newV - sliderMin) / (sliderMax - sliderMin), 0., 1., target)
|
||||
updateStates(newV, newP, target);
|
||||
}
|
||||
|
||||
function clamp(x, testMin, testMax) {
|
||||
return x < testMin
|
||||
? testMin
|
||||
: (x > testMax
|
||||
? testMax
|
||||
: x
|
||||
);
|
||||
function clamp(x, testMin, testMax, target) {
|
||||
if (isNaN(x)) {
|
||||
if (target == 'from') return testMin
|
||||
else if (target == 'to') return testMax
|
||||
} else {
|
||||
return x < testMin
|
||||
? testMin
|
||||
: (x > testMax
|
||||
? testMax
|
||||
: x
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function draggable(node) {
|
||||
@@ -159,23 +164,23 @@
|
||||
|
||||
<div class="double-range-container">
|
||||
<div class="header">
|
||||
<input class="form-control" type="text" placeholder="from..." value={inputFieldFrom}
|
||||
<input class="form-control" type="text" placeholder={`${sliderMin} ...`} value={inputFieldFrom}
|
||||
oninput={(e) => {
|
||||
inputChanged(e, 'from');
|
||||
}}
|
||||
/>
|
||||
|
||||
{#if inputFieldFrom != sliderMin?.toString() && inputFieldTo != sliderMax?.toString() }
|
||||
{#if (inputFieldFrom && inputFieldFrom != sliderMin?.toString()) && inputFieldTo != null }
|
||||
<span>Selected: Range <b> {inputFieldFrom} </b> - <b> {inputFieldTo} </b></span>
|
||||
{:else if inputFieldFrom != sliderMin?.toString() && inputFieldTo == sliderMax?.toString() }
|
||||
<span>Selected: More than <b> {inputFieldFrom} </b> </span>
|
||||
{:else if inputFieldFrom == sliderMin?.toString() && inputFieldTo != sliderMax?.toString() }
|
||||
<span>Selected: Less than <b> {inputFieldTo} </b></span>
|
||||
{:else if (inputFieldFrom && inputFieldFrom != sliderMin?.toString()) && inputFieldTo == null }
|
||||
<span>Selected: More Than Equal <b> {inputFieldFrom} </b> </span>
|
||||
{:else if (!inputFieldFrom || inputFieldFrom == sliderMin?.toString()) && inputFieldTo != null }
|
||||
<span>Selected: Less Than Equal <b> {inputFieldTo} </b></span>
|
||||
{:else}
|
||||
<span><i>No Selection</i></span>
|
||||
{/if}
|
||||
|
||||
<input class="form-control" type="text" placeholder="to..." value={inputFieldTo}
|
||||
<input class="form-control" type="text" placeholder={`... ${sliderMax} ...`} value={inputFieldTo}
|
||||
oninput={(e) => {
|
||||
inputChanged(e, 'to');
|
||||
}}
|
||||
|
||||
@@ -347,8 +347,8 @@ export function getStatsItems(presetStats = []) {
|
||||
field: presetEntry.field,
|
||||
text: `${gm.name} (${gm.footprint})`,
|
||||
metric: gm.name,
|
||||
from: presetEntry.from,
|
||||
to: (presetEntry.to == 0) ? mc.peak : presetEntry.to,
|
||||
from: presetEntry?.from || 0,
|
||||
to: (presetEntry.to == 0) ? null : presetEntry.to,
|
||||
peak: mc.peak,
|
||||
enabled: true,
|
||||
unit: `${gm?.unit?.prefix ? gm.unit.prefix : ''}${gm.unit.base}`
|
||||
@@ -358,8 +358,8 @@ export function getStatsItems(presetStats = []) {
|
||||
field: `${gm.name}_${gm.footprint}`,
|
||||
text: `${gm.name} (${gm.footprint})`,
|
||||
metric: gm.name,
|
||||
from: 1,
|
||||
to: mc.peak,
|
||||
from: 0,
|
||||
to: null,
|
||||
peak: mc.peak,
|
||||
enabled: false,
|
||||
unit: `${gm?.unit?.prefix ? gm.unit.prefix : ''}${gm.unit.base}`
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
|
||||
{#if subClusters?.length > 1}
|
||||
{#each subClusters.map(sc => sc.name) as scn}
|
||||
<TabPane tabId="{scn}-usage-dash" tab="{scn.charAt(0).toUpperCase() + scn.slice(1)} Usage">
|
||||
<TabPane tabId="{scn}-usage-dash" tab="{scn} Usage">
|
||||
<CardBody>
|
||||
<UsageDash {presetCluster} presetSubCluster={scn} {useCbColors} loadMe={(activeTab === `${scn}-usage-dash`)}></UsageDash>
|
||||
</CardBody>
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
const filter = $derived([
|
||||
{ cluster: { eq: cluster } },
|
||||
{ state: ["running"] },
|
||||
{ node: { contains: nodeData.host } },
|
||||
{ node: { eq: nodeData.host } },
|
||||
]);
|
||||
const nodeJobsData = $derived(queryStore({
|
||||
client: client,
|
||||
|
||||
Reference in New Issue
Block a user