mirror of
https://github.com/ClusterCockpit/cc-backend
synced 2025-07-23 04:51:39 +02:00
feat: Add tag scopes to front and backend, initial commit
This commit is contained in:
@@ -2,9 +2,9 @@
|
||||
@component Main single job display component; displays plots for every metric as well as various information
|
||||
|
||||
Properties:
|
||||
- `dbid Number`: The jobs DB ID
|
||||
- `username String`: Empty string if auth. is disabled, otherwise the username as string
|
||||
- `authlevel Number`: The current users authentication level
|
||||
- `clusters [String]`: List of cluster names
|
||||
- `roles [Number]`: Enum containing available roles
|
||||
-->
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
import MetricSelection from "./generic/select/MetricSelection.svelte";
|
||||
|
||||
export let dbid;
|
||||
export let username;
|
||||
export let authlevel;
|
||||
export let roles;
|
||||
|
||||
@@ -58,8 +59,7 @@
|
||||
selectedScopes = [];
|
||||
|
||||
let plots = {},
|
||||
jobTags,
|
||||
statsTable
|
||||
jobTags
|
||||
|
||||
let missingMetrics = [],
|
||||
missingHosts = [],
|
||||
@@ -322,7 +322,7 @@
|
||||
<Row class="mb-3">
|
||||
<Col xs="auto">
|
||||
{#if $initq.data}
|
||||
<TagManagement job={$initq.data.job} bind:jobTags />
|
||||
<TagManagement job={$initq.data.job} {username} {authlevel} {roles} bind:jobTags />
|
||||
{/if}
|
||||
</Col>
|
||||
<Col xs="auto">
|
||||
@@ -418,7 +418,6 @@
|
||||
{#if $jobMetrics?.data?.jobMetrics}
|
||||
{#key $jobMetrics.data.jobMetrics}
|
||||
<StatsTable
|
||||
bind:this={statsTable}
|
||||
job={$initq.data.job}
|
||||
jobMetrics={$jobMetrics.data.jobMetrics}
|
||||
/>
|
||||
|
@@ -27,7 +27,7 @@
|
||||
import {
|
||||
init,
|
||||
checkMetricDisabled,
|
||||
} from "./utils.js";
|
||||
} from "./generic/utils.js";
|
||||
import PlotTable from "./generic/PlotTable.svelte";
|
||||
import MetricPlot from "./generic/plots/MetricPlot.svelte";
|
||||
import TimeSelection from "./generic/select/TimeSelection.svelte";
|
||||
|
@@ -81,6 +81,7 @@
|
||||
id
|
||||
type
|
||||
name
|
||||
scope
|
||||
}
|
||||
userData {
|
||||
name
|
||||
|
@@ -37,7 +37,13 @@
|
||||
|
||||
<a target={clickable ? "_blank" : null} href={clickable ? `/monitoring/jobs/?tag=${id}` : null}>
|
||||
{#if tag}
|
||||
<span class="badge bg-warning text-dark">{tag.type}: {tag.name}</span>
|
||||
{#if tag?.scope === "global"}
|
||||
<span style="background-color:#9e9e9e;" class="badge text-dark">{tag.type}: {tag.name}</span>
|
||||
{:else if tag.scope === "admin"}
|
||||
<span style="background-color:#80deea;" class="badge text-dark">{tag.type}: {tag.name}</span>
|
||||
{:else}
|
||||
<span class="badge bg-warning text-dark">{tag.type}: {tag.name}</span>
|
||||
{/if}
|
||||
{:else}
|
||||
Loading...
|
||||
{/if}
|
||||
|
@@ -77,7 +77,7 @@ export function init(extraInitQuery = "") {
|
||||
footprint
|
||||
}
|
||||
}
|
||||
tags { id, name, type }
|
||||
tags { id, name, type, scope }
|
||||
globalMetrics {
|
||||
name
|
||||
scope
|
||||
|
@@ -5,6 +5,7 @@ new Job({
|
||||
target: document.getElementById('svelte-app'),
|
||||
props: {
|
||||
dbid: jobInfos.id,
|
||||
username: username,
|
||||
authlevel: authlevel,
|
||||
roles: roles
|
||||
},
|
||||
|
@@ -4,6 +4,9 @@
|
||||
Properties:
|
||||
- `job Object`: The job object
|
||||
- `jobTags [Number]`: The array of currently designated tags
|
||||
- `username String`: Empty string if auth. is disabled, otherwise the username as string
|
||||
- `authlevel Number`: The current users authentication level
|
||||
- `roles [Number]`: Enum containing available roles
|
||||
-->
|
||||
<script>
|
||||
import { getContext } from "svelte";
|
||||
@@ -25,30 +28,35 @@
|
||||
|
||||
export let job;
|
||||
export let jobTags = job.tags;
|
||||
export let username;
|
||||
export let authlevel;
|
||||
export let roles;
|
||||
|
||||
let allTags = getContext("tags"),
|
||||
initialized = getContext("initialized");
|
||||
let newTagType = "",
|
||||
newTagName = "";
|
||||
newTagName = "",
|
||||
newTagScope = username;
|
||||
let filterTerm = "";
|
||||
let pendingChange = false;
|
||||
let isOpen = false;
|
||||
|
||||
const client = getContextClient();
|
||||
|
||||
const createTagMutation = ({ type, name }) => {
|
||||
const createTagMutation = ({ type, name, scope }) => {
|
||||
return mutationStore({
|
||||
client: client,
|
||||
query: gql`
|
||||
mutation ($type: String!, $name: String!) {
|
||||
createTag(type: $type, name: $name) {
|
||||
mutation ($type: String!, $name: String!, $scope: String!) {
|
||||
createTag(type: $type, name: $name, scope: $scope) {
|
||||
id
|
||||
type
|
||||
name
|
||||
scope
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: { type, name },
|
||||
variables: { type, name, scope },
|
||||
});
|
||||
};
|
||||
|
||||
@@ -61,6 +69,7 @@
|
||||
id
|
||||
type
|
||||
name
|
||||
scope
|
||||
}
|
||||
}
|
||||
`,
|
||||
@@ -77,6 +86,7 @@
|
||||
id
|
||||
type
|
||||
name
|
||||
scope
|
||||
}
|
||||
}
|
||||
`,
|
||||
@@ -103,9 +113,9 @@
|
||||
return true;
|
||||
}
|
||||
|
||||
function createTag(type, name) {
|
||||
function createTag(type, name, scope) {
|
||||
pendingChange = true;
|
||||
createTagMutation({ type: type, name: name }).subscribe((res) => {
|
||||
createTagMutation({ type: type, name: name, scope: scope }).subscribe((res) => {
|
||||
if (res.fetching === false && !res.error) {
|
||||
pendingChange = false;
|
||||
allTags = [...allTags, res.data.createTag];
|
||||
@@ -206,16 +216,30 @@
|
||||
</ul>
|
||||
<br />
|
||||
{#if newTagType && newTagName && isNewTag(newTagType, newTagName)}
|
||||
<Button
|
||||
outline
|
||||
color="success"
|
||||
on:click={(e) => (
|
||||
e.preventDefault(), createTag(newTagType, newTagName)
|
||||
)}
|
||||
>
|
||||
Create & Add Tag:
|
||||
<Tag tag={{ type: newTagType, name: newTagName }} clickable={false} />
|
||||
</Button>
|
||||
<div class="d-flex">
|
||||
<Button
|
||||
style="margin-right: 10px;"
|
||||
outline
|
||||
color="success"
|
||||
on:click={(e) => (
|
||||
e.preventDefault(), createTag(newTagType, newTagName, newTagScope)
|
||||
)}
|
||||
>
|
||||
Create & Add Tag:
|
||||
<Tag tag={{ type: newTagType, name: newTagName, scope: newTagScope }} clickable={false}/>
|
||||
</Button>
|
||||
{#if roles && authlevel >= roles.admin}
|
||||
<select
|
||||
style="max-width: 175px;"
|
||||
class="form-select"
|
||||
bind:value={newTagScope}
|
||||
>
|
||||
<option value={username}>Scope: Private</option>
|
||||
<option value={"global"}>Scope: Global</option>
|
||||
<option value={"admin"}>Scope: Admin</option>
|
||||
</select>
|
||||
{/if}
|
||||
</div>
|
||||
{:else if allTagsFiltered.length == 0}
|
||||
<Alert>Search Term is not a valid Tag (<code>type: name</code>)</Alert>
|
||||
{/if}
|
||||
|
@@ -11,6 +11,7 @@
|
||||
id: "{{ .Infos.id }}",
|
||||
};
|
||||
const clusterCockpitConfig = {{ .Config }};
|
||||
const username = {{ .User.Username }};
|
||||
const authlevel = {{ .User.GetAuthLevel }};
|
||||
const roles = {{ .Roles }};
|
||||
</script>
|
||||
|
@@ -7,8 +7,16 @@
|
||||
{{ $tagType }}
|
||||
</div>
|
||||
{{ range $tagList }}
|
||||
<a class="btn btn-lg btn-warning" href="/monitoring/jobs/?tag={{ .id }}" role="button">
|
||||
{{ .name }} <span class="badge bg-light text-dark">{{ .count }}</span> </a>
|
||||
{{if eq .scope "global"}}
|
||||
<a style="background-color:#9e9e9e;" class="btn btn-lg" href="/monitoring/jobs/?tag={{ .id }}" role="button">
|
||||
{{ .name }} <span class="badge bg-light text-dark">{{ .count }}</span> </a>
|
||||
{{else if eq .scope "admin"}}
|
||||
<a style="background-color:#80deea;" class="btn btn-lg" href="/monitoring/jobs/?tag={{ .id }}" role="button">
|
||||
{{ .name }} <span class="badge bg-light text-dark">{{ .count }}</span> </a>
|
||||
{{else}}
|
||||
<a class="btn btn-lg btn-warning" href="/monitoring/jobs/?tag={{ .id }}" role="button">
|
||||
{{ .name }} <span class="badge bg-light text-dark">{{ .count }}</span> </a>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
|
Reference in New Issue
Block a user