github.com/hernad/nomad@v1.6.112/ui/app/templates/jobs/job/task-group.hbs (about) 1 {{! 2 Copyright (c) HashiCorp, Inc. 3 SPDX-License-Identifier: MPL-2.0 4 ~}} 5 6 <Breadcrumb @crumb={{this.breadcrumb}} /> 7 {{page-title "Task group " this.model.name " - Job " this.model.job.name}} 8 <div class="tabs is-subnav"> 9 <ul> 10 <li> 11 <LinkTo 12 @route="jobs.job.task-group" 13 @models={{array this.model.job this.model}} 14 @activeClass="is-active" 15 > 16 Overview 17 </LinkTo> 18 </li> 19 </ul> 20 </div> 21 <section class="section"> 22 <h1 class="title with-flex"> 23 <span> 24 {{this.model.name}} 25 </span> 26 <div> 27 <Exec::OpenButton @job={{this.model.job}} @taskGroup={{this.model}} /> 28 {{#if this.model.scaling}} 29 <StepperInput 30 data-test-task-group-count-stepper 31 aria-label={{this.tooltipText}} 32 @min={{this.model.scaling.min}} 33 @max={{this.model.scaling.max}} 34 @value={{this.model.count}} 35 @class="is-primary is-small" 36 @disabled={{or 37 this.model.job.runningDeployment 38 (cannot "scale job" namespace=this.model.job.namespace.name) 39 }} 40 @onChange={{action "scaleTaskGroup"}} 41 > 42 Count 43 </StepperInput> 44 {{/if}} 45 </div> 46 </h1> 47 <div class="boxed-section is-small"> 48 <div class="boxed-section-body inline-definitions"> 49 <span class="label"> 50 Task Group Details 51 </span> 52 <span class="pair" data-test-task-group-tasks> 53 <span class="term"> 54 # Tasks 55 </span> 56 {{this.model.tasks.length}} 57 </span> 58 <span class="pair" data-test-task-group-cpu> 59 <span class="term"> 60 Reserved CPU 61 </span> 62 {{format-scheduled-hertz this.model.reservedCPU}} 63 </span> 64 <span class="pair" data-test-task-group-mem> 65 <span class="term"> 66 Reserved Memory 67 </span> 68 {{format-scheduled-bytes this.model.reservedMemory start="MiB"}} 69 {{#if (gt this.model.reservedMemoryMax this.model.reservedMemory)}} 70 ({{format-scheduled-bytes this.model.reservedMemoryMax start="MiB"}}Max) 71 {{/if}} 72 </span> 73 <span class="pair" data-test-task-group-disk> 74 <span class="term"> 75 Reserved Disk 76 </span> 77 {{format-scheduled-bytes this.model.reservedEphemeralDisk start="MiB"}} 78 </span> 79 <span class="pair"> 80 <span class="term"> 81 Namespace 82 </span> 83 {{this.model.job.namespace.name}} 84 </span> 85 {{#if this.model.scaling}} 86 <span class="pair" data-test-task-group-min> 87 <span class="term"> 88 Count Range 89 </span> 90 {{this.model.scaling.min}} 91 to 92 {{this.model.scaling.max}} 93 </span> 94 <span class="pair" data-test-task-group-max> 95 <span class="term"> 96 Scaling Policy? 97 </span> 98 {{if this.model.scaling.policy "Yes" "No"}} 99 </span> 100 {{/if}} 101 {{#if (and (can "list variables") this.model.pathLinkedVariable)}} 102 <span class="pair" data-test-task-group-stat="variables"> 103 <LinkTo @route="variables.variable" @model={{this.model.pathLinkedVariable.id}}>Variables</LinkTo> 104 </span> 105 {{/if}} 106 </div> 107 </div> 108 <div class="boxed-section"> 109 <div class="boxed-section-head"> 110 <div> 111 Allocation Status 112 <span class="badge is-white"> 113 {{this.allocations.length}} 114 </span> 115 </div> 116 </div> 117 <div class="boxed-section-body"> 118 <AllocationStatusBar 119 @allocationContainer={{this.model.summary}} 120 @class="split-view" as |chart| 121 > 122 <ol class="legend"> 123 {{#each chart.data as |datum index|}} 124 <li 125 class="{{datum.className}} 126 127 {{if (eq datum.label chart.activeDatum.label) "is-active"}} 128 129 {{if (eq datum.value 0) "is-empty"}}" 130 > 131 <JobPage::Parts::SummaryLegendItem @datum={{datum}} @index={{index}} /> 132 </li> 133 {{/each}} 134 </ol> 135 </AllocationStatusBar> 136 </div> 137 </div> 138 <div class="boxed-section"> 139 <div class="boxed-section-head"> 140 Allocations 141 <div class="pull-right is-subsection"> 142 <MultiSelectDropdown 143 data-test-allocation-status-facet 144 @label="Status" 145 @options={{this.optionsAllocationStatus}} 146 @selection={{this.selectionStatus}} 147 @onSelect={{action this.setFacetQueryParam "qpStatus"}} 148 /> 149 <MultiSelectDropdown 150 data-test-allocation-client-facet 151 @label="Client" 152 @options={{this.optionsClients}} 153 @selection={{this.selectionClient}} 154 @onSelect={{action this.setFacetQueryParam "qpClient"}} 155 /> 156 <SearchBox 157 @searchTerm={{mut this.searchTerm}} 158 @placeholder="Search allocations..." 159 @onChange={{action this.resetPagination}} 160 @class="is-padded" 161 @inputClass="is-compact" 162 /> 163 <span class="is-padded is-one-line"> 164 <Toggle 165 @isActive={{this.showSubTasks}} 166 @onToggle={{this.toggleShowSubTasks}} 167 title="Show tasks of allocations" 168 > 169 Show Tasks 170 </Toggle> 171 </span> 172 </div> 173 </div> 174 <div class="boxed-section-body is-full-bleed"> 175 {{#if this.sortedAllocations}} 176 <ListPagination 177 @source={{this.sortedAllocations}} 178 @size={{this.pageSize}} 179 @page={{this.currentPage}} 180 @class="allocations" as |p| 181 > 182 <ListTable 183 @source={{p.list}} 184 @sortProperty={{this.sortProperty}} 185 @sortDescending={{this.sortDescending}} 186 @class="with-foot {{if this.showSubTasks "with-collapsed-borders"}}" as |t| 187 > 188 <t.head> 189 <th class="is-narrow"></th> 190 <t.sort-by @prop="shortId"> 191 ID 192 </t.sort-by> 193 <t.sort-by @prop="createIndex" @title="Create Index"> 194 Created 195 </t.sort-by> 196 <t.sort-by @prop="modifyIndex" @title="Modify Index"> 197 Modified 198 </t.sort-by> 199 <t.sort-by @prop="statusIndex"> 200 Status 201 </t.sort-by> 202 <t.sort-by @prop="jobVersion"> 203 Version 204 </t.sort-by> 205 <t.sort-by @prop="node.shortId"> 206 Client 207 </t.sort-by> 208 <th> 209 Volume 210 </th> 211 <th> 212 CPU 213 </th> 214 <th> 215 Memory 216 </th> 217 </t.head> 218 <t.body @key="model.id" as |row|> 219 <AllocationRow 220 {{keyboard-shortcut 221 enumerated=true 222 action=(action "gotoAllocation" row.model) 223 }} 224 @data-test-allocation={{row.model.id}} 225 @allocation={{row.model}} 226 @context="taskGroup" 227 @onClick={{action "gotoAllocation" row.model}} 228 /> 229 {{#if this.showSubTasks}} 230 {{#each row.model.states as |task|}} 231 <TaskSubRow @namespan="8" @taskState={{task}} @active={{eq this.activeTask (concat task.allocation.id "-" task.name)}} @onSetActiveTask={{action 'setActiveTaskQueryParam'}} /> 232 {{/each}} 233 {{/if}} 234 </t.body> 235 </ListTable> 236 <div class="table-foot"> 237 <PageSizeSelect @onChange={{action this.resetPagination}} /> 238 <nav class="pagination"> 239 <div class="pagination-numbers"> 240 {{p.startsAt}} 241 – 242 {{p.endsAt}} 243 of 244 {{this.sortedAllocations.length}} 245 </div> 246 <p.prev @class="pagination-previous"> 247 {{x-icon "chevron-left"}} 248 </p.prev> 249 <p.next @class="pagination-next"> 250 {{x-icon "chevron-right"}} 251 </p.next> 252 <ul class="pagination-list"></ul> 253 </nav> 254 </div> 255 </ListPagination> 256 {{else if this.allocations.length}} 257 <div class="boxed-section-body"> 258 <div class="empty-message" data-test-empty-allocations-list> 259 <h3 class="empty-message-headline" data-test-empty-allocations-list-headline> 260 No Matches 261 </h3> 262 <p class="empty-message-body"> 263 No allocations match the term 264 <strong> 265 {{this.searchTerm}} 266 </strong> 267 </p> 268 </div> 269 </div> 270 {{else}} 271 <div class="boxed-section-body"> 272 <div class="empty-message" data-test-empty-allocations-list> 273 <h3 class="empty-message-headline" data-test-empty-allocations-list-headline> 274 No Allocations 275 </h3> 276 <p class="empty-message-body"> 277 No allocations have been placed. 278 </p> 279 </div> 280 </div> 281 {{/if}} 282 </div> 283 </div> 284 <LifecycleChart @tasks={{this.model.tasks}} /> 285 {{#if this.model.scaleState.isVisible}} 286 {{#if this.shouldShowScaleEventTimeline}} 287 <div data-test-scaling-timeline class="boxed-section"> 288 <div class="boxed-section-head is-hollow"> 289 Scaling Timeline 290 </div> 291 <div class="boxed-section-body"> 292 <ScaleEventsChart @events={{this.sortedScaleEvents}} /> 293 </div> 294 </div> 295 {{/if}} 296 <div data-test-scaling-events class="boxed-section"> 297 <div class="boxed-section-head"> 298 Recent Scaling Events 299 </div> 300 <div class="boxed-section-body"> 301 <ScaleEventsAccordion @events={{this.sortedScaleEvents}} /> 302 </div> 303 </div> 304 {{/if}} 305 {{#if this.model.volumes.length}} 306 <div data-test-volumes class="boxed-section"> 307 <div class="boxed-section-head"> 308 Volume Requirements 309 </div> 310 <div class="boxed-section-body is-full-bleed"> 311 <ListTable @source={{this.model.volumes}} as |t|> 312 <t.head> 313 <th> 314 Name 315 </th> 316 <th> 317 Type 318 </th> 319 <th> 320 Source 321 </th> 322 <th> 323 Permissions 324 </th> 325 </t.head> 326 <t.body as |row|> 327 <tr data-test-volume> 328 <td data-test-volume-name> 329 {{#if row.model.isCSI}} 330 {{!-- if volume is per_alloc=true, there's no one specific volume. So, link to the volumes index with an active query --}} 331 {{#if row.model.perAlloc}} 332 <LinkTo @route="csi.volumes.index" @query={{hash search=row.model.source}}>{{row.model.name}}</LinkTo> 333 {{else}} 334 <LinkTo 335 @route="csi.volumes.volume" 336 @model={{concat row.model.source "@" row.model.namespace.id}} 337 > 338 {{row.model.name}} 339 </LinkTo> 340 {{/if}} 341 {{else}} 342 {{row.model.name}} 343 {{/if}} 344 </td> 345 <td data-test-volume-type> 346 {{row.model.type}} 347 </td> 348 <td data-test-volume-source> 349 {{row.model.source}} 350 </td> 351 <td data-test-volume-permissions> 352 {{if row.model.readOnly "Read" "Read/Write"}} 353 </td> 354 </tr> 355 </t.body> 356 </ListTable> 357 </div> 358 </div> 359 {{/if}} 360 </section>