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