-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
UI: Task Group Scaling Controls #8207
Merged
Merged
Changes from all commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
29ff3f9
Model the scaling properties of a task group as a fragment
DingoEatingFuzz e28efc6
LazyClick should also get interrupted by buttons
DingoEatingFuzz 4e7b844
New xsmall button size
DingoEatingFuzz 0137f8d
When an icon is intended as text, it shouldn't have pointer events
DingoEatingFuzz 158f776
Extend button-bar support to buttons
DingoEatingFuzz 461980d
Additional button-bar treatments for use in a table row
DingoEatingFuzz 6b57adc
Prevent inline definition key/value pairs from breaking the key and v…
DingoEatingFuzz 2e1adbc
Add the min/max and policy y/n of a task group to the details ribbon
DingoEatingFuzz ed6c414
Add the elements of the manual scaling actions to the task-group-row …
DingoEatingFuzz 3768a63
Make sure buttons in a button bar have a very visible focus state
DingoEatingFuzz 8567439
Create new AbortController with each tick of the ec task loops
DingoEatingFuzz 149dcda
New scale action for jobs (and a convenience task group method)
DingoEatingFuzz 9a344e4
Wire up the +/- buttons in task group rows to the job scale action
DingoEatingFuzz a1f1079
Mirage updates for task group scaling and scaling post endpoint
DingoEatingFuzz 7fec4d8
Add canScale ability for jobs
DingoEatingFuzz 1182203
Disable scale buttons when a deployment is running or ACL forbids it
DingoEatingFuzz 469b107
Test coverage for the task group row scale actions
DingoEatingFuzz 0b0be1b
Slow the debounce time.
DingoEatingFuzz 2b88651
Barebones StepperInput component
DingoEatingFuzz ed63958
StepperInput story
DingoEatingFuzz 140f9f6
Add count StepperInput to the task group page
DingoEatingFuzz 6bde0e5
Style the StepperInput component
DingoEatingFuzz 110f491
Test coverage for the StepperInput
DingoEatingFuzz 2227f24
Integrate the stepper input with the task group page
DingoEatingFuzz eb901b5
Wire up the scale action on the task group page
DingoEatingFuzz 72161b0
Watch the latest deployment relationship to disable the stepper appro…
DingoEatingFuzz 61042e0
Acceptance tests for task group scaling
DingoEatingFuzz c70ea97
Remove superfluous property from the StepperInput page object
DingoEatingFuzz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,26 @@ | ||
import AbstractAbility from './abstract'; | ||
import { computed, get } from '@ember/object'; | ||
import { computed } from '@ember/object'; | ||
import { or } from '@ember/object/computed'; | ||
|
||
export default class Job extends AbstractAbility { | ||
@or('bypassAuthorization', 'selfTokenIsManagement', 'policiesSupportRunning') | ||
canRun; | ||
|
||
@or( | ||
'bypassAuthorization', | ||
'selfTokenIsManagement', | ||
'policiesSupportRunning', | ||
'policiesSupportScaling' | ||
) | ||
canScale; | ||
|
||
@computed('[email protected]') | ||
get policiesSupportRunning() { | ||
return this.rulesForActiveNamespace.some(rules => { | ||
let capabilities = get(rules, 'Capabilities') || []; | ||
return capabilities.includes('submit-job'); | ||
}); | ||
return this.activeNamespaceIncludesCapability('submit-job'); | ||
} | ||
|
||
@computed('[email protected]') | ||
get policiesSupportScaling() { | ||
return this.activeNamespaceIncludesCapability('scale-job'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -68,4 +68,20 @@ export default class JobAdapter extends WatchableNamespaceIDs { | |
}, | ||
}); | ||
} | ||
|
||
scale(job, group, count, reason) { | ||
const url = addToPath(this.urlForFindRecord(job.get('id'), 'job'), '/scale'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I hadn’t known about |
||
return this.ajax(url, 'POST', { | ||
data: { | ||
Count: count, | ||
Reason: reason, | ||
Target: { | ||
Group: group, | ||
}, | ||
Meta: { | ||
Source: 'nomad-ui', | ||
}, | ||
}, | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import Component from '@ember/component'; | ||
import { action } from '@ember/object'; | ||
import { debounce } from '@ember/runloop'; | ||
import { oneWay } from '@ember/object/computed'; | ||
import { classNames, classNameBindings } from '@ember-decorators/component'; | ||
import classic from 'ember-classic-decorator'; | ||
|
||
const ESC = 27; | ||
|
||
@classic | ||
@classNames('stepper-input') | ||
@classNameBindings('class', 'disabled:is-disabled') | ||
export default class StepperInput extends Component { | ||
min = 0; | ||
max = 10; | ||
value = 0; | ||
debounce = 500; | ||
onChange() {} | ||
|
||
// Internal value changes immediately for instant visual feedback. | ||
// Value is still the public API and is expected to mutate and re-render | ||
// On onChange which is debounced. | ||
@oneWay('value') internalValue; | ||
|
||
@action | ||
increment() { | ||
if (this.internalValue < this.max) { | ||
this.incrementProperty('internalValue'); | ||
this.update(this.internalValue); | ||
} | ||
} | ||
|
||
@action | ||
decrement() { | ||
if (this.internalValue > this.min) { | ||
this.decrementProperty('internalValue'); | ||
this.update(this.internalValue); | ||
} | ||
} | ||
|
||
@action | ||
setValue(e) { | ||
const newValue = Math.min(this.max, Math.max(this.min, e.target.value)); | ||
this.set('internalValue', newValue); | ||
this.update(this.internalValue); | ||
} | ||
|
||
@action | ||
resetTextInput(e) { | ||
if (e.keyCode === ESC) { | ||
e.target.value = this.internalValue; | ||
} | ||
} | ||
|
||
update(value) { | ||
debounce(this, sendUpdateAction, value, this.debounce); | ||
} | ||
} | ||
|
||
function sendUpdateAction(value) { | ||
return this.onChange(value); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,64 @@ | ||
import Component from '@ember/component'; | ||
import { lazyClick } from '../helpers/lazy-click'; | ||
import { computed, action } from '@ember/object'; | ||
import { alias, oneWay } from '@ember/object/computed'; | ||
import { debounce } from '@ember/runloop'; | ||
import { classNames, tagName } from '@ember-decorators/component'; | ||
import classic from 'ember-classic-decorator'; | ||
import { lazyClick } from '../helpers/lazy-click'; | ||
|
||
@classic | ||
@tagName('tr') | ||
@classNames('task-group-row', 'is-interactive') | ||
export default class TaskGroupRow extends Component { | ||
taskGroup = null; | ||
debounce = 500; | ||
|
||
@oneWay('taskGroup.count') count; | ||
@alias('taskGroup.job.runningDeployment') runningDeployment; | ||
|
||
onClick() {} | ||
|
||
click(event) { | ||
lazyClick([this.onClick, event]); | ||
} | ||
|
||
@computed('count', 'taskGroup.scaling.min') | ||
get isMinimum() { | ||
const scaling = this.taskGroup.scaling; | ||
if (!scaling || scaling.min == null) return false; | ||
return this.count <= scaling.min; | ||
} | ||
|
||
@computed('count', 'taskGroup.scaling.max') | ||
get isMaximum() { | ||
const scaling = this.taskGroup.scaling; | ||
if (!scaling || scaling.max == null) return false; | ||
return this.count >= scaling.max; | ||
} | ||
|
||
@action | ||
countUp() { | ||
const scaling = this.taskGroup.scaling; | ||
if (!scaling || scaling.max == null || this.count < scaling.max) { | ||
this.incrementProperty('count'); | ||
this.scale(this.count); | ||
} | ||
} | ||
|
||
@action | ||
countDown() { | ||
const scaling = this.taskGroup.scaling; | ||
if (!scaling || scaling.min == null || this.count > scaling.min) { | ||
this.decrementProperty('count'); | ||
this.scale(this.count); | ||
} | ||
} | ||
|
||
scale(count) { | ||
debounce(this, sendCountAction, count, this.debounce); | ||
} | ||
} | ||
|
||
function sendCountAction(count) { | ||
return this.taskGroup.scale(count); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import Fragment from 'ember-data-model-fragments/fragment'; | ||
import attr from 'ember-data/attr'; | ||
import { fragmentOwner } from 'ember-data-model-fragments/attributes'; | ||
import classic from 'ember-classic-decorator'; | ||
|
||
@classic | ||
export default class TaskGroup extends Fragment { | ||
@fragmentOwner() taskGroup; | ||
|
||
@attr('boolean') enabled; | ||
@attr('number') max; | ||
@attr('number') min; | ||
|
||
@attr() policy; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
import { computed } from '@ember/object'; | ||
import Fragment from 'ember-data-model-fragments/fragment'; | ||
import attr from 'ember-data/attr'; | ||
import { fragmentOwner, fragmentArray } from 'ember-data-model-fragments/attributes'; | ||
import { fragmentOwner, fragmentArray, fragment } from 'ember-data-model-fragments/attributes'; | ||
import sumAggregation from '../utils/properties/sum-aggregation'; | ||
import classic from 'ember-classic-decorator'; | ||
|
||
|
@@ -20,6 +20,8 @@ export default class TaskGroup extends Fragment { | |
|
||
@fragmentArray('volume-definition') volumes; | ||
|
||
@fragment('group-scaling') scaling; | ||
|
||
@computed('[email protected]') | ||
get drivers() { | ||
return this.tasks.mapBy('driver').uniq(); | ||
|
@@ -51,4 +53,8 @@ export default class TaskGroup extends Fragment { | |
get summary() { | ||
return maybe(this.get('job.taskGroupSummaries')).findBy('name', this.name); | ||
} | ||
|
||
scale(count, reason) { | ||
return this.job.scale(this.name, count, reason); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like that we are slowly building up useful abstractions here as appropriate 🤩