mirror of
				https://github.com/ClusterCockpit/cc-backend
				synced 2025-10-31 16:05:06 +01:00 
			
		
		
		
	Rework tag and tag edit placement, add other feedback
- admin message shown primarily if exists - comment demo summary tab
This commit is contained in:
		| @@ -25,7 +25,6 @@ | |||||||
|     CardHeader, |     CardHeader, | ||||||
|     CardTitle, |     CardTitle, | ||||||
|     Button, |     Button, | ||||||
|     Icon, |  | ||||||
|   } from "@sveltestrap/sveltestrap"; |   } from "@sveltestrap/sveltestrap"; | ||||||
|   import { getContext } from "svelte"; |   import { getContext } from "svelte"; | ||||||
|   import { |   import { | ||||||
| @@ -35,7 +34,6 @@ | |||||||
|     transformDataForRoofline, |     transformDataForRoofline, | ||||||
|   } from "./generic/utils.js"; |   } from "./generic/utils.js"; | ||||||
|   import Metric from "./job/Metric.svelte"; |   import Metric from "./job/Metric.svelte"; | ||||||
|   import TagManagement from "./job/TagManagement.svelte"; |  | ||||||
|   import StatsTable from "./job/StatsTable.svelte"; |   import StatsTable from "./job/StatsTable.svelte"; | ||||||
|   import JobSummary from "./job/JobSummary.svelte"; |   import JobSummary from "./job/JobSummary.svelte"; | ||||||
|   import ConcurrentJobs from "./generic/helper/ConcurrentJobs.svelte"; |   import ConcurrentJobs from "./generic/helper/ConcurrentJobs.svelte"; | ||||||
| @@ -54,12 +52,10 @@ | |||||||
|  const ccconfig = getContext("cc-config") |  const ccconfig = getContext("cc-config") | ||||||
|  |  | ||||||
|  let isMetricsSelectionOpen = false, |  let isMetricsSelectionOpen = false, | ||||||
|     showFootprint = !!ccconfig[`job_view_showFootprint`], |  | ||||||
|     selectedMetrics = [], |     selectedMetrics = [], | ||||||
|     selectedScopes = []; |     selectedScopes = []; | ||||||
|  |  | ||||||
|   let plots = {}, |   let plots = {}, | ||||||
|     jobTags, |  | ||||||
|     roofWidth |     roofWidth | ||||||
|  |  | ||||||
|   let missingMetrics = [], |   let missingMetrics = [], | ||||||
| @@ -240,14 +236,22 @@ | |||||||
|     {:else if $initq.data} |     {:else if $initq.data} | ||||||
|       <Card class="overflow-auto" style="height: 400px;"> |       <Card class="overflow-auto" style="height: 400px;"> | ||||||
|         <TabContent> <!-- on:tab={(e) => (status = e.detail)} --> |         <TabContent> <!-- on:tab={(e) => (status = e.detail)} --> | ||||||
|           <TabPane tabId="meta-info" tab="Job Info" active> |           {#if $initq.data?.job?.metaData?.message} | ||||||
|             <CardBody class="pb-2"> |             <TabPane tabId="admin-msg" tab="Admin Note" active> | ||||||
|               <JobInfo job={$initq.data.job} {jobTags} /> |               <CardBody> | ||||||
|  |                 <Card body class="mb-2" color="warning"> | ||||||
|  |                   <h5>Job {$initq.data?.job?.jobId} ({$initq.data?.job?.cluster})</h5> | ||||||
|  |                   The following note was added by administrators: | ||||||
|  |                 </Card> | ||||||
|  |                 <Card body> | ||||||
|  |                   {@html $initq.data.job.metaData.message} | ||||||
|  |                 </Card> | ||||||
|               </CardBody> |               </CardBody> | ||||||
|             </TabPane> |             </TabPane> | ||||||
|           <TabPane tabId="job-tags" tab="Job Tags"> |           {/if} | ||||||
|             <CardBody> |           <TabPane tabId="meta-info" tab="Job Info" active={$initq.data?.job?.metaData?.message?false:true}> | ||||||
|               <TagManagement job={$initq.data.job} {username} {authlevel} {roles} bind:jobTags renderModal={false}/> |             <CardBody class="pb-2"> | ||||||
|  |               <JobInfo job={$initq.data.job} {username} {authlevel} {roles} showTags={false} showTagedit/> | ||||||
|             </CardBody> |             </CardBody> | ||||||
|           </TabPane> |           </TabPane> | ||||||
|           {#if $initq.data.job.concurrentJobs != null && $initq.data.job.concurrentJobs.items.length != 0} |           {#if $initq.data.job.concurrentJobs != null && $initq.data.job.concurrentJobs.items.length != 0} | ||||||
| @@ -260,15 +264,6 @@ | |||||||
|               </CardBody> |               </CardBody> | ||||||
|             </TabPane> |             </TabPane> | ||||||
|           {/if} |           {/if} | ||||||
|           {#if $initq.data?.job?.metaData?.message} |  | ||||||
|             <TabPane tabId="admin-msg" tab="Admin Note"> |  | ||||||
|               <CardBody> |  | ||||||
|                 <p>This note was added by administrators:</p> |  | ||||||
|                 <hr/> |  | ||||||
|                 <p>{@html $initq.data.job.metaData.message}</p> |  | ||||||
|               </CardBody> |  | ||||||
|             </TabPane> |  | ||||||
|           {/if} |  | ||||||
|         </TabContent> |         </TabContent> | ||||||
|       </Card> |       </Card> | ||||||
|     {:else} |     {:else} | ||||||
| @@ -276,8 +271,7 @@ | |||||||
|     {/if} |     {/if} | ||||||
|   </Col> |   </Col> | ||||||
|  |  | ||||||
|   <!-- If enabled:  Column 2: Job Footprint, Polar Representation, Heuristic Summary --> |   <!-- Column 2: Job Footprint, Polar Representation, Heuristic Summary --> | ||||||
|   {#if showFootprint} |  | ||||||
|   <Col xs={12} md={6} xl={4} xxl={3} class="mb-3 mb-xxl-0"> |   <Col xs={12} md={6} xl={4} xxl={3} class="mb-3 mb-xxl-0"> | ||||||
|     {#if $initq.error} |     {#if $initq.error} | ||||||
|       <Card body color="danger">{$initq.error.message}</Card> |       <Card body color="danger">{$initq.error.message}</Card> | ||||||
| @@ -287,10 +281,9 @@ | |||||||
|       <Spinner secondary /> |       <Spinner secondary /> | ||||||
|     {/if} |     {/if} | ||||||
|   </Col> |   </Col> | ||||||
|   {/if} |  | ||||||
|  |  | ||||||
|   <!-- Column 3: Job Roofline; If footprint Enabled: full width, else half width --> |   <!-- Column 3: Job Roofline; If footprint Enabled: full width, else half width --> | ||||||
|   <Col xs={12} md={showFootprint ? 12 : 6} xl={showFootprint ? 5 : 6} xxl={6}> |   <Col xs={12} md={12} xl={5} xxl={6}> | ||||||
|     {#if $initq.error || $jobMetrics.error} |     {#if $initq.error || $jobMetrics.error} | ||||||
|       <Card body color="danger"> |       <Card body color="danger"> | ||||||
|         <p>Initq Error: {$initq.error?.message}</p> |         <p>Initq Error: {$initq.error?.message}</p> | ||||||
|   | |||||||
| @@ -23,12 +23,22 @@ | |||||||
|         if ($initialized && tag == null) |         if ($initialized && tag == null) | ||||||
|             tag = allTags.find(tag => tag.id == id) |             tag = allTags.find(tag => tag.id == id) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     function getScopeColor(scope) { | ||||||
|  |         switch (scope) { | ||||||
|  |         case "admin": | ||||||
|  |             return "#19e5e6"; | ||||||
|  |         case "global": | ||||||
|  |             return "#c85fc8"; | ||||||
|  |         default: | ||||||
|  |             return "#ffc107"; | ||||||
|  |         } | ||||||
|  |     } | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <style> | <style> | ||||||
|     a { |     a { | ||||||
|         margin-left: 0.5rem; |         margin-right: 0.5rem; | ||||||
|         line-height: 2; |  | ||||||
|     } |     } | ||||||
|     span { |     span { | ||||||
|         font-size: 0.9rem; |         font-size: 0.9rem; | ||||||
| @@ -37,13 +47,7 @@ | |||||||
|  |  | ||||||
| <a target={clickable ? "_blank" : null} href={clickable ? `/monitoring/jobs/?tag=${id}` : null}> | <a target={clickable ? "_blank" : null} href={clickable ? `/monitoring/jobs/?tag=${id}` : null}> | ||||||
|     {#if tag} |     {#if tag} | ||||||
|         {#if tag?.scope === "global"} |         <span style="background-color:{getScopeColor(tag?.scope)};" class="my-1 badge text-dark">{tag.type}: {tag.name}</span> | ||||||
|             <span style="background-color:#c85fc8;" class="badge text-dark">{tag.type}: {tag.name}</span> |  | ||||||
|         {:else if tag?.scope === "admin"} |  | ||||||
|             <span style="background-color:#19e5e6;" class="badge text-dark">{tag.type}: {tag.name}</span> |  | ||||||
|         {:else} |  | ||||||
|             <span class="badge bg-warning text-dark">{tag.type}: {tag.name}</span> |  | ||||||
|         {/if} |  | ||||||
|     {:else} |     {:else} | ||||||
|         Loading... |         Loading... | ||||||
|     {/if} |     {/if} | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| <!-- | <!-- | ||||||
|     @component Job View Subcomponent; allows management of job tags by deletion or new entries |     @component Job Info Subcomponent; allows management of job tags by deletion or new entries | ||||||
| 
 | 
 | ||||||
|     Properties: |     Properties: | ||||||
|     - `job Object`: The job object |     - `job Object`: The job object | ||||||
| @@ -30,8 +30,8 @@ | |||||||
|     Alert, |     Alert, | ||||||
|     Tooltip, |     Tooltip, | ||||||
|   } from "@sveltestrap/sveltestrap"; |   } from "@sveltestrap/sveltestrap"; | ||||||
|   import { fuzzySearchTags } from "../generic/utils.js"; |   import { fuzzySearchTags } from "../utils.js"; | ||||||
|   import Tag from "../generic/helper/Tag.svelte"; |   import Tag from "./Tag.svelte"; | ||||||
| 
 | 
 | ||||||
|   export let job; |   export let job; | ||||||
|   export let jobTags = job.tags; |   export let jobTags = job.tags; | ||||||
| @@ -178,12 +178,7 @@ | |||||||
| {#if renderModal} | {#if renderModal} | ||||||
|   <Modal {isOpen} toggle={() => (isOpen = !isOpen)}> |   <Modal {isOpen} toggle={() => (isOpen = !isOpen)}> | ||||||
|     <ModalHeader> |     <ModalHeader> | ||||||
|       Manage Tags |       Manage Tags <Icon name="tags"/> | ||||||
|       {#if pendingChange !== false} |  | ||||||
|         <Spinner size="sm" secondary /> |  | ||||||
|       {:else} |  | ||||||
|         <Icon name="tags" /> |  | ||||||
|       {/if} |  | ||||||
|     </ModalHeader> |     </ModalHeader> | ||||||
|     <ModalBody> |     <ModalBody> | ||||||
|       <InputGroup class="mb-3"> |       <InputGroup class="mb-3"> | ||||||
| @@ -317,8 +312,8 @@ | |||||||
|     </ModalFooter> |     </ModalFooter> | ||||||
|   </Modal> |   </Modal> | ||||||
| 
 | 
 | ||||||
|   <Button outline on:click={() => (isOpen = true)}> |   <Button outline on:click={() => (isOpen = true)} size="sm" color="primary"> | ||||||
|     Manage Tags <Icon name="tags" /> |     Manage {jobTags?.length ? jobTags.length : ''} Tags | ||||||
|   </Button> |   </Button> | ||||||
| 
 | 
 | ||||||
| {:else} | {:else} | ||||||
| @@ -10,9 +10,14 @@ | |||||||
|   import { Badge, Icon } from "@sveltestrap/sveltestrap"; |   import { Badge, Icon } from "@sveltestrap/sveltestrap"; | ||||||
|   import { scrambleNames, scramble } from "../utils.js"; |   import { scrambleNames, scramble } from "../utils.js"; | ||||||
|   import Tag from "../helper/Tag.svelte"; |   import Tag from "../helper/Tag.svelte"; | ||||||
|  |   import TagManagement from "../helper/TagManagement.svelte"; | ||||||
|  |  | ||||||
|   export let job; |   export let job; | ||||||
|   export let jobTags = job.tags; |   export let jobTags = job.tags; | ||||||
|  |   export let showTagedit = false; | ||||||
|  |   export let username = null; | ||||||
|  |   export let authlevel= null; | ||||||
|  |   export let roles = null; | ||||||
|  |  | ||||||
|   function formatDuration(duration) { |   function formatDuration(duration) { | ||||||
|     const hours = Math.floor(duration / 3600); |     const hours = Math.floor(duration / 3600); | ||||||
| @@ -36,7 +41,7 @@ | |||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <div> | <div> | ||||||
|   <p> |   <p class="mb-2"> | ||||||
|     <span class="fw-bold" |     <span class="fw-bold" | ||||||
|       ><a href="/monitoring/job/{job.id}" target="_blank">{job.jobId}</a> |       ><a href="/monitoring/job/{job.id}" target="_blank">{job.jobId}</a> | ||||||
|       ({job.cluster})</span |       ({job.cluster})</span | ||||||
| @@ -63,7 +68,7 @@ | |||||||
|     {/if} |     {/if} | ||||||
|   </p> |   </p> | ||||||
|  |  | ||||||
|   <p> |   <p class="mb-2"> | ||||||
|     <Icon name="person-fill" /> |     <Icon name="person-fill" /> | ||||||
|     <a class="fst-italic" href="/monitoring/user/{job.user}" target="_blank"> |     <a class="fst-italic" href="/monitoring/user/{job.user}" target="_blank"> | ||||||
|       {scrambleNames ? scramble(job.user) : job.user} |       {scrambleNames ? scramble(job.user) : job.user} | ||||||
| @@ -84,7 +89,7 @@ | |||||||
|     {/if} |     {/if} | ||||||
|   </p> |   </p> | ||||||
|  |  | ||||||
|   <p> |   <p class="mb-2"> | ||||||
|     {#if job.numNodes == 1} |     {#if job.numNodes == 1} | ||||||
|       {job.resources[0].hostname} |       {job.resources[0].hostname} | ||||||
|     {:else} |     {:else} | ||||||
| @@ -104,7 +109,7 @@ | |||||||
|     {job.subCluster} |     {job.subCluster} | ||||||
|   </p> |   </p> | ||||||
|  |  | ||||||
|   <p> |   <p class="mb-2"> | ||||||
|     Start: <span class="fw-bold" |     Start: <span class="fw-bold" | ||||||
|       >{new Date(job.startTime).toLocaleString()}</span |       >{new Date(job.startTime).toLocaleString()}</span | ||||||
|     > |     > | ||||||
| @@ -117,11 +122,25 @@ | |||||||
|     {/if} |     {/if} | ||||||
|   </p> |   </p> | ||||||
|  |  | ||||||
|   <p class="mb-2"> |   {#if showTagedit} | ||||||
|  |     <hr class="mt-0 mb-2"/> | ||||||
|  |     <p class="mb-1"> | ||||||
|  |       <TagManagement bind:jobTags {job} {username} {authlevel} {roles} renderModal/> :  | ||||||
|  |       {#if jobTags?.length > 0} | ||||||
|  |         {#each jobTags as tag} | ||||||
|  |           <Tag {tag}/> | ||||||
|  |         {/each} | ||||||
|  |       {:else} | ||||||
|  |         <span style="font-size: 0.9rem; background-color: lightgray;" class="my-1 badge text-dark">No Tags</span> | ||||||
|  |       {/if} | ||||||
|  |     </p> | ||||||
|  |   {:else} | ||||||
|  |     <p class="mb-1"> | ||||||
|       {#each jobTags as tag} |       {#each jobTags as tag} | ||||||
|         <Tag {tag} /> |         <Tag {tag} /> | ||||||
|       {/each} |       {/each} | ||||||
|     </p> |     </p> | ||||||
|  |   {/if} | ||||||
| </div> | </div> | ||||||
|  |  | ||||||
| <style> | <style> | ||||||
|   | |||||||
| @@ -68,6 +68,7 @@ | |||||||
|   export let height = "400px"; |   export let height = "400px"; | ||||||
|  |  | ||||||
|   const ccconfig = getContext("cc-config") |   const ccconfig = getContext("cc-config") | ||||||
|  |   const showFootprint = !!ccconfig[`job_view_showFootprint`]; | ||||||
|  |  | ||||||
|   const footprintData = job?.footprint?.map((jf) => { |   const footprintData = job?.footprint?.map((jf) => { | ||||||
|     const fmc = getContext("getMetricConfig")(job.cluster, job.subCluster, jf.name); |     const fmc = getContext("getMetricConfig")(job.cluster, job.subCluster, jf.name); | ||||||
| @@ -165,6 +166,7 @@ | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   /* | ||||||
|     function writeSummary(fpd) { |     function writeSummary(fpd) { | ||||||
|       // Hardcoded! Needs to be retrieved from globalMetrics |       // Hardcoded! Needs to be retrieved from globalMetrics | ||||||
|       const performanceMetrics = ['flops_any', 'mem_bw']; |       const performanceMetrics = ['flops_any', 'mem_bw']; | ||||||
| @@ -225,10 +227,12 @@ | |||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     $: summaryMessages = writeSummary(footprintData)  |     $: summaryMessages = writeSummary(footprintData)  | ||||||
|  |   */ | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <Card class="overflow-auto" style="width: {width}; height: {height}"> | <Card class="overflow-auto" style="width: {width}; height: {height}"> | ||||||
|   <TabContent> <!-- on:tab={(e) => (status = e.detail)} --> |   <TabContent> <!-- on:tab={(e) => (status = e.detail)} --> | ||||||
|  |     {#if showFootprint} | ||||||
|       <TabPane tabId="foot" tab="Footprint" active> |       <TabPane tabId="foot" tab="Footprint" active> | ||||||
|         <CardBody> |         <CardBody> | ||||||
|           {#each footprintData as fpd, index} |           {#each footprintData as fpd, index} | ||||||
| @@ -309,7 +313,8 @@ | |||||||
|           {/each} |           {/each} | ||||||
|         </CardBody> |         </CardBody> | ||||||
|       </TabPane> |       </TabPane> | ||||||
|     <TabPane tabId="polar" tab="Polar"> |     {/if} | ||||||
|  |     <TabPane tabId="polar" tab="Polar" active={!showFootprint}> | ||||||
|       <CardBody> |       <CardBody> | ||||||
|         <Polar |         <Polar | ||||||
|           {footprintData} |           {footprintData} | ||||||
| @@ -317,6 +322,7 @@ | |||||||
|         /> |         /> | ||||||
|       </CardBody> |       </CardBody> | ||||||
|     </TabPane> |     </TabPane> | ||||||
|  |     <!-- | ||||||
|       <TabPane tabId="summary" tab="Summary"> |       <TabPane tabId="summary" tab="Summary"> | ||||||
|         <CardBody> |         <CardBody> | ||||||
|           <p>Based on footprint data, this job performs as follows:</p> |           <p>Based on footprint data, this job performs as follows:</p> | ||||||
| @@ -330,6 +336,7 @@ | |||||||
|           </ul> |           </ul> | ||||||
|         </CardBody> |         </CardBody> | ||||||
|       </TabPane> |       </TabPane> | ||||||
|  |     --> | ||||||
|   </TabContent> |   </TabContent> | ||||||
| </Card> | </Card> | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user