ui: prettify js files

This commit is contained in:
Jai Bhagat 2021-12-28 11:08:12 -05:00
parent 3cf01877a0
commit 3a9057a89c
291 changed files with 6362 additions and 2145 deletions

View File

@ -14,7 +14,11 @@ module.exports = {
shippedProposals: true,
useBuiltIns: 'usage',
corejs: '3',
targets: ['last 1 Chrome versions', 'last 1 Firefox versions', 'last 1 Safari versions'],
targets: [
'last 1 Chrome versions',
'last 1 Firefox versions',
'last 1 Safari versions',
],
},
],
],
@ -27,7 +31,10 @@ module.exports = {
],
['@babel/plugin-proposal-class-properties', { loose: true }],
'@babel/plugin-syntax-dynamic-import',
['@babel/plugin-proposal-object-rest-spread', { loose: true, useBuiltIns: true }],
[
'@babel/plugin-proposal-object-rest-spread',
{ loose: true, useBuiltIns: true },
],
'babel-plugin-macros',
['emotion', { sourceMap: true, autoLabel: true }],
[

View File

@ -26,17 +26,26 @@ export default class Abstract extends Ability {
get rulesForNamespace() {
let namespace = this._namespace;
return (this.get('token.selfTokenPolicies') || []).toArray().reduce((rules, policy) => {
let policyNamespaces = get(policy, 'rulesJSON.Namespaces') || [];
return (this.get('token.selfTokenPolicies') || [])
.toArray()
.reduce((rules, policy) => {
let policyNamespaces = get(policy, 'rulesJSON.Namespaces') || [];
let matchingNamespace = this._findMatchingNamespace(policyNamespaces, namespace);
let matchingNamespace = this._findMatchingNamespace(
policyNamespaces,
namespace
);
if (matchingNamespace) {
rules.push(policyNamespaces.find((namespace) => namespace.Name === matchingNamespace));
}
if (matchingNamespace) {
rules.push(
policyNamespaces.find(
(namespace) => namespace.Name === matchingNamespace
)
);
}
return rules;
}, []);
return rules;
}, []);
}
@computed('token.selfTokenPolicies.[]')
@ -44,9 +53,11 @@ export default class Abstract extends Ability {
return (this.get('token.selfTokenPolicies') || [])
.toArray()
.reduce((allCapabilities, policy) => {
(get(policy, 'rulesJSON.Namespaces') || []).forEach(({ Capabilities }) => {
allCapabilities = allCapabilities.concat(Capabilities);
});
(get(policy, 'rulesJSON.Namespaces') || []).forEach(
({ Capabilities }) => {
allCapabilities = allCapabilities.concat(Capabilities);
}
);
return allCapabilities;
}, []);
}
@ -76,12 +87,16 @@ export default class Abstract extends Ability {
return namespace;
}
let globNamespaceNames = namespaceNames.filter((namespaceName) => namespaceName.includes('*'));
let globNamespaceNames = namespaceNames.filter((namespaceName) =>
namespaceName.includes('*')
);
let matchingNamespaceName = globNamespaceNames.reduce(
(mostMatching, namespaceName) => {
// Convert * wildcards to .* for regex matching
let namespaceNameRegExp = new RegExp(namespaceName.replace(/\*/g, '.*'));
let namespaceNameRegExp = new RegExp(
namespaceName.replace(/\*/g, '.*')
);
let characterDifference = namespace.length - namespaceName.length;
if (
@ -96,7 +111,10 @@ export default class Abstract extends Ability {
return mostMatching;
}
},
{ mostMatchingNamespaceName: null, mostMatchingCharacterDifference: Number.MAX_SAFE_INTEGER }
{
mostMatchingNamespaceName: null,
mostMatchingCharacterDifference: Number.MAX_SAFE_INTEGER,
}
).mostMatchingNamespaceName;
if (matchingNamespaceName) {

View File

@ -3,7 +3,11 @@ import { computed, get } from '@ember/object';
import { or } from '@ember/object/computed';
export default class Client extends AbstractAbility {
@or('bypassAuthorization', 'selfTokenIsManagement', 'policiesIncludeAgentReadOrWrite')
@or(
'bypassAuthorization',
'selfTokenIsManagement',
'policiesIncludeAgentReadOrWrite'
)
canRead;
@computed('token.selfTokenPolicies.[]')

View File

@ -10,17 +10,26 @@ export default class Client extends AbstractAbility {
@or('bypassAuthorization', 'selfTokenIsManagement', 'policiesIncludeNodeRead')
canRead;
@or('bypassAuthorization', 'selfTokenIsManagement', 'policiesIncludeNodeWrite')
@or(
'bypassAuthorization',
'selfTokenIsManagement',
'policiesIncludeNodeWrite'
)
canWrite;
@computed('token.selfTokenPolicies.[]')
get policiesIncludeNodeRead() {
return policiesIncludePermissions(this.get('token.selfTokenPolicies'), ['read', 'write']);
return policiesIncludePermissions(this.get('token.selfTokenPolicies'), [
'read',
'write'
]);
}
@computed('token.selfTokenPolicies.[]')
get policiesIncludeNodeWrite() {
return policiesIncludePermissions(this.get('token.selfTokenPolicies'), ['write']);
return policiesIncludePermissions(this.get('token.selfTokenPolicies'), [
'write'
]);
}
}

View File

@ -20,7 +20,11 @@ export default class Job extends AbstractAbility {
@or('bypassAuthorization', 'selfTokenIsManagement')
canListAll;
@or('bypassAuthorization', 'selfTokenIsManagement', 'policiesSupportDispatching')
@or(
'bypassAuthorization',
'selfTokenIsManagement',
'policiesSupportDispatching'
)
canDispatch;
@computed('rulesForNamespace.@each.capabilities')

View File

@ -6,7 +6,11 @@ export default class Recommendation extends AbstractAbility {
@and('dynamicApplicationSizingIsPresent', 'hasPermissions')
canAccept;
@or('bypassAuthorization', 'selfTokenIsManagement', 'policiesSupportAcceptingOnAnyNamespace')
@or(
'bypassAuthorization',
'selfTokenIsManagement',
'policiesSupportAcceptingOnAnyNamespace'
)
hasPermissions;
@computed('capabilitiesForAllNamespaces.[]')

View File

@ -14,13 +14,17 @@ export default class AllocationAdapter extends Watchable {
ls(model, path) {
return this.token
.authorizedRequest(`/v1/client/fs/ls/${model.id}?path=${encodeURIComponent(path)}`)
.authorizedRequest(
`/v1/client/fs/ls/${model.id}?path=${encodeURIComponent(path)}`
)
.then(handleFSResponse);
}
stat(model, path) {
return this.token
.authorizedRequest(`/v1/client/fs/stat/${model.id}?path=${encodeURIComponent(path)}`)
.authorizedRequest(
`/v1/client/fs/stat/${model.id}?path=${encodeURIComponent(path)}`
)
.then(handleFSResponse);
}
}
@ -40,7 +44,10 @@ async function handleFSResponse(response) {
function adapterAction(path, verb = 'POST') {
return function (allocation) {
const url = addToPath(this.urlForFindRecord(allocation.id, 'allocation'), path);
const url = addToPath(
this.urlForFindRecord(allocation.id, 'allocation'),
path
);
return this.ajax(url, verb);
};
}

View File

@ -125,5 +125,7 @@ export default class ApplicationAdapter extends RESTAdapter {
}
function associateRegion(url, region) {
return url.indexOf('?') !== -1 ? `${url}&region=${region}` : `${url}?region=${region}`;
return url.indexOf('?') !== -1
? `${url}&region=${region}`
: `${url}?region=${region}`;
}

View File

@ -13,7 +13,10 @@ export default class DeploymentAdapter extends Watchable {
promote(deployment) {
const id = deployment.get('id');
const url = urlForAction(this.urlForFindRecord(id, 'deployment'), '/promote');
const url = urlForAction(
this.urlForFindRecord(id, 'deployment'),
'/promote'
);
return this.ajax(url, 'POST', {
data: {
DeploymentId: id,

View File

@ -5,7 +5,10 @@ export default class JobVersionAdapter extends ApplicationAdapter {
revertTo(jobVersion) {
const jobAdapter = this.store.adapterFor('job');
const url = addToPath(jobAdapter.urlForFindRecord(jobVersion.get('job.id'), 'job'), '/revert');
const url = addToPath(
jobAdapter.urlForFindRecord(jobVersion.get('job.id'), 'job'),
'/revert'
);
const [jobName] = JSON.parse(jobVersion.get('job.id'));
return this.ajax(url, 'POST', {

View File

@ -14,7 +14,10 @@ export default class JobAdapter extends WatchableNamespaceIDs {
forcePeriodic(job) {
if (job.get('periodic')) {
const url = addToPath(this.urlForFindRecord(job.get('id'), 'job'), '/periodic/force');
const url = addToPath(
this.urlForFindRecord(job.get('id'), 'job'),
'/periodic/force'
);
return this.ajax(url, 'POST');
}
}
@ -71,7 +74,10 @@ export default class JobAdapter extends WatchableNamespaceIDs {
}
scale(job, group, count, message) {
const url = addToPath(this.urlForFindRecord(job.get('id'), 'job'), '/scale');
const url = addToPath(
this.urlForFindRecord(job.get('id'), 'job'),
'/scale'
);
return this.ajax(url, 'POST', {
data: {
Count: count,
@ -87,7 +93,10 @@ export default class JobAdapter extends WatchableNamespaceIDs {
}
dispatch(job, meta, payload) {
const url = addToPath(this.urlForFindRecord(job.get('id'), 'job'), '/dispatch');
const url = addToPath(
this.urlForFindRecord(job.get('id'), 'job'),
'/dispatch'
);
return this.ajax(url, 'POST', {
data: {
Payload: base64EncodeString(payload),

View File

@ -11,7 +11,10 @@ export default class NodeAdapter extends Watchable {
}
setEligibility(node, isEligible) {
const url = addToPath(this.urlForFindRecord(node.id, 'node'), '/eligibility');
const url = addToPath(
this.urlForFindRecord(node.id, 'node'),
'/eligibility'
);
return this.ajax(url, 'POST', {
data: {
NodeID: node.id,

View File

@ -9,13 +9,20 @@ export default class RecommendationSummaryAdapter extends ApplicationAdapter {
}
updateRecord(store, type, snapshot) {
const url = `${super.urlForCreateRecord('recommendations', snapshot)}/apply`;
const url = `${super.urlForCreateRecord(
'recommendations',
snapshot
)}/apply`;
const allRecommendationIds = snapshot.hasMany('recommendations').mapBy('id');
const excludedRecommendationIds = (snapshot.hasMany('excludedRecommendations') || []).mapBy(
'id'
const allRecommendationIds = snapshot
.hasMany('recommendations')
.mapBy('id');
const excludedRecommendationIds = (
snapshot.hasMany('excludedRecommendations') || []
).mapBy('id');
const includedRecommendationIds = allRecommendationIds.removeObjects(
excludedRecommendationIds
);
const includedRecommendationIds = allRecommendationIds.removeObjects(excludedRecommendationIds);
const data = {
Apply: includedRecommendationIds,

View File

@ -30,7 +30,10 @@ export default class TokenAdapter extends ApplicationAdapter {
tokens: [token],
});
return store.peekRecord('token', store.normalize('token', token).data.id);
return store.peekRecord(
'token',
store.normalize('token', token).data.id
);
})
.catch(() => {
throw new OTTExchangeError();

View File

@ -26,7 +26,8 @@ export default class WatchableNamespaceIDs extends Watchable {
findRecord(store, type, id, snapshot) {
const [, namespace] = JSON.parse(id);
const namespaceQuery = namespace && namespace !== 'default' ? { namespace } : {};
const namespaceQuery =
namespace && namespace !== 'default' ? { namespace } : {};
return super.findRecord(store, type, id, snapshot, namespaceQuery);
}

View File

@ -40,7 +40,10 @@ export default class Watchable extends ApplicationAdapter {
params.index = this.watchList.getIndexFor(url);
}
const signal = get(snapshotRecordArray || {}, 'adapterOptions.abortController.signal');
const signal = get(
snapshotRecordArray || {},
'adapterOptions.abortController.signal'
);
return this.ajax(url, 'GET', {
signal,
data: params,
@ -48,9 +51,18 @@ export default class Watchable extends ApplicationAdapter {
}
findRecord(store, type, id, snapshot, additionalParams = {}) {
const originalUrl = this.buildURL(type.modelName, id, snapshot, 'findRecord');
const originalUrl = this.buildURL(
type.modelName,
id,
snapshot,
'findRecord'
);
let [url, params] = originalUrl.split('?');
params = assign(queryString.parse(params) || {}, this.buildQuery(), additionalParams);
params = assign(
queryString.parse(params) || {},
this.buildQuery(),
additionalParams
);
if (get(snapshot || {}, 'adapterOptions.watch')) {
params.index = this.watchList.getIndexFor(originalUrl);
@ -68,15 +80,29 @@ export default class Watchable extends ApplicationAdapter {
});
}
query(store, type, query, snapshotRecordArray, options, additionalParams = {}) {
query(
store,
type,
query,
snapshotRecordArray,
options,
additionalParams = {}
) {
const url = this.buildURL(type.modelName, null, null, 'query', query);
let [urlPath, params] = url.split('?');
params = assign(queryString.parse(params) || {}, this.buildQuery(), additionalParams, query);
params = assign(
queryString.parse(params) || {},
this.buildQuery(),
additionalParams,
query
);
if (get(options, 'adapterOptions.watch')) {
// The intended query without additional blocking query params is used
// to track the appropriate query index.
params.index = this.watchList.getIndexFor(`${urlPath}?${queryString.stringify(query)}`);
params.index = this.watchList.getIndexFor(
`${urlPath}?${queryString.stringify(query)}`
);
}
const signal = get(options, 'adapterOptions.abortController.signal');
@ -88,7 +114,9 @@ export default class Watchable extends ApplicationAdapter {
// Query params may not necessarily map one-to-one to attribute names.
// Adapters are responsible for declaring param mappings.
const queryParamsToAttrs = Object.keys(adapter.queryParamsToAttrs || {}).map((key) => ({
const queryParamsToAttrs = Object.keys(
adapter.queryParamsToAttrs || {}
).map((key) => ({
queryParam: key,
attr: adapter.queryParamsToAttrs[key],
}));
@ -110,7 +138,11 @@ export default class Watchable extends ApplicationAdapter {
});
}
reloadRelationship(model, relationshipName, options = { watch: false, abortController: null }) {
reloadRelationship(
model,
relationshipName,
options = { watch: false, abortController: null }
) {
const { watch, abortController } = options;
const relationship = model.relationshipFor(relationshipName);
if (relationship.kind !== 'belongsTo' && relationship.kind !== 'hasMany') {
@ -146,7 +178,11 @@ export default class Watchable extends ApplicationAdapter {
: 'normalizeFindHasManyResponse';
const serializer = store.serializerFor(relationship.type);
const modelClass = store.modelFor(relationship.type);
const normalizedData = serializer[normalizeMethod](store, modelClass, json);
const normalizedData = serializer[normalizeMethod](
store,
modelClass,
json
);
store.push(normalizedData);
},
(error) => {

View File

@ -85,7 +85,9 @@ async function qualifyAllocation() {
// Make sure the allocation is a complete record and not a partial so we
// can show information such as preemptions and rescheduled allocation.
if (allocation.isPartial) {
await this.store.findRecord('allocation', allocation.id, { backgroundReload: false });
await this.store.findRecord('allocation', allocation.id, {
backgroundReload: false,
});
}
if (allocation.get('job.isPending')) {

View File

@ -42,8 +42,10 @@ export default class AllocationStat extends Component {
@computed('metric', 'statsTracker.{reservedMemory,reservedCPU}')
get formattedReserved() {
if (this.metric === 'memory') return formatBytes(this.statsTracker.reservedMemory, 'MiB');
if (this.metric === 'cpu') return formatHertz(this.statsTracker.reservedCPU, 'MHz');
if (this.metric === 'memory')
return formatBytes(this.statsTracker.reservedMemory, 'MiB');
if (this.metric === 'cpu')
return formatHertz(this.statsTracker.reservedCPU, 'MHz');
return undefined;
}
}

View File

@ -7,7 +7,9 @@ export default class ChartPrimitiveArea extends Component {
get colorClass() {
if (this.args.colorClass) return this.args.colorClass;
if (this.args.colorScale && this.args.index != null)
return `${this.args.colorScale} ${this.args.colorScale}-${this.args.index + 1}`;
return `${this.args.colorScale} ${this.args.colorScale}-${
this.args.index + 1
}`;
return 'is-primary';
}

View File

@ -16,10 +16,22 @@ export default class ChildrenStatusBar extends DistributionBar {
return [];
}
const children = this.job.getProperties('pendingChildren', 'runningChildren', 'deadChildren');
const children = this.job.getProperties(
'pendingChildren',
'runningChildren',
'deadChildren'
);
return [
{ label: 'Pending', value: children.pendingChildren, className: 'queued' },
{ label: 'Running', value: children.runningChildren, className: 'running' },
{
label: 'Pending',
value: children.pendingChildren,
className: 'queued',
},
{
label: 'Running',
value: children.runningChildren,
className: 'running',
},
{ label: 'Dead', value: children.deadChildren, className: 'complete' },
];
}

View File

@ -10,7 +10,9 @@ import classic from 'ember-classic-decorator';
@classic
@tagName('tr')
@classNames('client-node-row', 'is-interactive')
export default class ClientNodeRow extends Component.extend(WithVisibilityDetection) {
export default class ClientNodeRow extends Component.extend(
WithVisibilityDetection
) {
@service store;
node = null;

View File

@ -4,7 +4,8 @@ import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
export default class DasDismissedComponent extends Component {
@localStorageProperty('nomadRecommendationDismssalUnderstood', false) explanationUnderstood;
@localStorageProperty('nomadRecommendationDismssalUnderstood', false)
explanationUnderstood;
@tracked dismissInTheFuture = false;

View File

@ -13,7 +13,9 @@ export default class DasRecommendationAccordionComponent extends Component {
@(task(function* () {
this.closing = true;
this.animationContainerStyle = htmlSafe(`height: ${this.accordionElement.clientHeight}px`);
this.animationContainerStyle = htmlSafe(
`height: ${this.accordionElement.clientHeight}px`
);
yield timeout(10);

View File

@ -93,35 +93,39 @@ export default class DasRecommendationCardComponent extends Component {
get taskToggleRows() {
const taskNameToTaskToggles = {};
return this.args.summary.recommendations.reduce((taskToggleRows, recommendation) => {
let taskToggleRow = taskNameToTaskToggles[recommendation.task.name];
return this.args.summary.recommendations.reduce(
(taskToggleRows, recommendation) => {
let taskToggleRow = taskNameToTaskToggles[recommendation.task.name];
if (!taskToggleRow) {
taskToggleRow = {
recommendations: [],
task: recommendation.task,
if (!taskToggleRow) {
taskToggleRow = {
recommendations: [],
task: recommendation.task,
};
taskNameToTaskToggles[recommendation.task.name] = taskToggleRow;
taskToggleRows.push(taskToggleRow);
}
const isCpu = recommendation.resource === 'CPU';
const rowResourceProperty = isCpu ? 'cpu' : 'memory';
taskToggleRow[rowResourceProperty] = {
recommendation,
isActive:
!this.args.summary.excludedRecommendations.includes(recommendation),
};
taskNameToTaskToggles[recommendation.task.name] = taskToggleRow;
taskToggleRows.push(taskToggleRow);
}
if (isCpu) {
taskToggleRow.recommendations.unshift(recommendation);
} else {
taskToggleRow.recommendations.push(recommendation);
}
const isCpu = recommendation.resource === 'CPU';
const rowResourceProperty = isCpu ? 'cpu' : 'memory';
taskToggleRow[rowResourceProperty] = {
recommendation,
isActive: !this.args.summary.excludedRecommendations.includes(recommendation),
};
if (isCpu) {
taskToggleRow.recommendations.unshift(recommendation);
} else {
taskToggleRow.recommendations.push(recommendation);
}
return taskToggleRows;
}, []);
return taskToggleRows;
},
[]
);
}
get showToggleAllToggles() {
@ -129,23 +133,30 @@ export default class DasRecommendationCardComponent extends Component {
}
get allCpuToggleDisabled() {
return !this.args.summary.recommendations.filterBy('resource', 'CPU').length;
return !this.args.summary.recommendations.filterBy('resource', 'CPU')
.length;
}
get allMemoryToggleDisabled() {
return !this.args.summary.recommendations.filterBy('resource', 'MemoryMB').length;
return !this.args.summary.recommendations.filterBy('resource', 'MemoryMB')
.length;
}
get cannotAccept() {
return (
this.args.summary.excludedRecommendations.length == this.args.summary.recommendations.length
this.args.summary.excludedRecommendations.length ==
this.args.summary.recommendations.length
);
}
get copyButtonLink() {
const path = this.router.urlFor('optimize.summary', this.args.summary.slug, {
queryParams: { namespace: this.args.summary.jobNamespace },
});
const path = this.router.urlFor(
'optimize.summary',
this.args.summary.slug,
{
queryParams: { namespace: this.args.summary.jobNamespace },
}
);
const { origin } = window.location;
return `${origin}${path}`;
@ -185,7 +196,9 @@ export default class DasRecommendationCardComponent extends Component {
@action
dismiss() {
this.storeCardHeight();
this.args.summary.excludedRecommendations.pushObjects(this.args.summary.recommendations);
this.args.summary.excludedRecommendations.pushObjects(
this.args.summary.recommendations
);
this.args.summary
.save()
.then(

View File

@ -64,10 +64,12 @@ export default class RecommendationChartComponent extends Component {
edgeTickHeight = 23;
centerTickOffset = 6;
centerY = this.tickTextHeight + this.centerTickOffset + this.edgeTickHeight / 2;
centerY =
this.tickTextHeight + this.centerTickOffset + this.edgeTickHeight / 2;
edgeTickY1 = this.tickTextHeight + this.centerTickOffset;
edgeTickY2 = this.tickTextHeight + this.edgeTickHeight + this.centerTickOffset;
edgeTickY2 =
this.tickTextHeight + this.edgeTickHeight + this.centerTickOffset;
deltaTextY = this.edgeTickY2;
@ -129,7 +131,10 @@ export default class RecommendationChartComponent extends Component {
},
rect: {
x: this.gutterWidthLeft,
y: (this.edgeTickHeight - rectHeight) / 2 + this.centerTickOffset + this.tickTextHeight,
y:
(this.edgeTickHeight - rectHeight) / 2 +
this.centerTickOffset +
this.tickTextHeight,
width: rectWidth,
height: rectHeight,
},
@ -145,7 +150,10 @@ export default class RecommendationChartComponent extends Component {
}
get maximumX() {
return Math.max(this.higherValue, get(this.args.stats, 'max') || Number.MIN_SAFE_INTEGER);
return Math.max(
this.higherValue,
get(this.args.stats, 'max') || Number.MIN_SAFE_INTEGER
);
}
get lowerValue() {
@ -153,7 +161,9 @@ export default class RecommendationChartComponent extends Component {
}
get xScale() {
return scaleLinear().domain([0, this.maximumX]).rangeRound([0, this.barWidth]);
return scaleLinear()
.domain([0, this.maximumX])
.rangeRound([0, this.barWidth]);
}
get lowerValueWidth() {
@ -210,9 +220,13 @@ export default class RecommendationChartComponent extends Component {
let translateX;
if (this.shown) {
translateX = this.isIncrease ? this.higherValueWidth : this.lowerValueWidth;
translateX = this.isIncrease
? this.higherValueWidth
: this.lowerValueWidth;
} else {
translateX = this.isIncrease ? this.lowerValueWidth : this.higherValueWidth;
translateX = this.isIncrease
? this.lowerValueWidth
: this.higherValueWidth;
}
return {
@ -220,7 +234,9 @@ export default class RecommendationChartComponent extends Component {
points: `
0,${this.center.y1}
0,${this.center.y1 - this.deltaTriangleHeight / 2}
${(directionXMultiplier * this.deltaTriangleHeight) / 2},${this.center.y1}
${(directionXMultiplier * this.deltaTriangleHeight) / 2},${
this.center.y1
}
0,${this.center.y1 + this.deltaTriangleHeight / 2}
`,
};
@ -234,7 +250,9 @@ export default class RecommendationChartComponent extends Component {
},
delta: {
style: htmlSafe(
`transform: translateX(${this.shown ? this.higherValueWidth : this.lowerValueWidth}px)`
`transform: translateX(${
this.shown ? this.higherValueWidth : this.lowerValueWidth
}px)`
),
},
};
@ -245,7 +263,9 @@ export default class RecommendationChartComponent extends Component {
},
delta: {
style: htmlSafe(
`transform: translateX(${this.shown ? this.lowerValueWidth : this.higherValueWidth}px)`
`transform: translateX(${
this.shown ? this.lowerValueWidth : this.higherValueWidth
}px)`
),
},
};
@ -269,7 +289,8 @@ export default class RecommendationChartComponent extends Component {
};
const percentText = formatPercent(
(this.args.recommendedValue - this.args.currentValue) / this.args.currentValue
(this.args.recommendedValue - this.args.currentValue) /
this.args.currentValue
);
const percent = {
@ -314,7 +335,10 @@ export default class RecommendationChartComponent extends Component {
};
return Object.keys(statsWithCurrentAndRecommended)
.map((key) => ({ label: statsKeyToLabel[key], value: statsWithCurrentAndRecommended[key] }))
.map((key) => ({
label: statsKeyToLabel[key],
value: statsWithCurrentAndRecommended[key],
}))
.sortBy('value');
} else {
return [];

View File

@ -34,17 +34,20 @@ export default class DistributionBar extends Component.extend(WindowResizable) {
const data = copy(this.data, true);
const sum = data.mapBy('value').reduce(sumAggregate, 0);
return data.map(({ label, value, className, layers, legendLink, help }, index) => ({
label,
value,
className,
layers,
legendLink,
help,
index,
percent: value / sum,
offset: data.slice(0, index).mapBy('value').reduce(sumAggregate, 0) / sum,
}));
return data.map(
({ label, value, className, layers, legendLink, help }, index) => ({
label,
value,
className,
layers,
legendLink,
help,
index,
percent: value / sum,
offset:
data.slice(0, index).mapBy('value').reduce(sumAggregate, 0) / sum,
})
);
}
didInsertElement() {
@ -60,7 +63,10 @@ export default class DistributionBar extends Component.extend(WindowResizable) {
run(() => {
this.set('isActive', false);
this.set('activeDatum', null);
chart.selectAll('g').classed('active', false).classed('inactive', false);
chart
.selectAll('g')
.classed('active', false)
.classed('inactive', false);
});
});

View File

@ -31,7 +31,9 @@ export default class TaskGroupParent extends Component {
@computed('taskGroup.allocations.@each.clientStatus')
get hasPendingAllocations() {
return this.taskGroup.allocations.any((allocation) => allocation.clientStatus === 'pending');
return this.taskGroup.allocations.any(
(allocation) => allocation.clientStatus === 'pending'
);
}
@mapBy('taskGroup.allocations', 'states') allocationTaskStatesRecordArrays;
@ -39,7 +41,10 @@ export default class TaskGroupParent extends Component {
get allocationTaskStates() {
const flattenRecordArrays = (accumulator, recordArray) =>
accumulator.concat(recordArray.toArray());
return this.allocationTaskStatesRecordArrays.reduce(flattenRecordArrays, []);
return this.allocationTaskStatesRecordArrays.reduce(
flattenRecordArrays,
[]
);
}
@filterBy('allocationTaskStates', 'isActive') activeTaskStates;
@ -56,11 +61,16 @@ export default class TaskGroupParent extends Component {
get tasksWithRunningStates() {
const activeTaskStateNames = this.activeTaskStates
.filter((taskState) => {
return taskState.task && taskState.task.taskGroup.name === this.taskGroup.name;
return (
taskState.task &&
taskState.task.taskGroup.name === this.taskGroup.name
);
})
.mapBy('name');
return this.taskGroup.tasks.filter((task) => activeTaskStateNames.includes(task.name));
return this.taskGroup.tasks.filter((task) =>
activeTaskStateNames.includes(task.name)
);
}
taskSorting = ['name'];

View File

@ -18,7 +18,9 @@ export default class FlexMasonry extends Component {
// There's nothing to do if there is no element
if (!this.element) return;
const items = this.element.querySelectorAll(':scope > .flex-masonry-item');
const items = this.element.querySelectorAll(
':scope > .flex-masonry-item'
);
// Clear out specified order and flex-basis values in case this was once a multi-column layout
if (this.args.columns === 1 || !this.args.columns) {
@ -62,10 +64,12 @@ export default class FlexMasonry extends Component {
// beteen the height of the column and the previous column, then flexbox will naturally place the first
// item at the end of the previous column).
columns.forEach((column, index) => {
const nextHeight = index < columns.length - 1 ? columns[index + 1].height : 0;
const nextHeight =
index < columns.length - 1 ? columns[index + 1].height : 0;
const item = column.elements.lastObject;
if (item) {
item.style.flexBasis = item.clientHeight + Math.max(0, nextHeight - column.height) + 'px';
item.style.flexBasis =
item.clientHeight + Math.max(0, nextHeight - column.height) + 'px';
}
});

View File

@ -39,11 +39,18 @@ export default class Browser extends Component {
@filterBy('directoryEntries', 'IsDir') directories;
@filterBy('directoryEntries', 'IsDir', false) files;
@computed('directories', 'directoryEntries.[]', 'files', 'sortDescending', 'sortProperty')
@computed(
'directories',
'directoryEntries.[]',
'files',
'sortDescending',
'sortProperty'
)
get sortedDirectoryEntries() {
const sortProperty = this.sortProperty;
const directorySortProperty = sortProperty === 'Size' ? 'Name' : sortProperty;
const directorySortProperty =
sortProperty === 'Size' ? 'Name' : sortProperty;
const sortedDirectories = this.directories.sortBy(directorySortProperty);
const sortedFiles = this.files.sortBy(sortProperty);

View File

@ -39,7 +39,10 @@ export default class File extends Component {
if (contentType.startsWith('image/')) {
return 'image';
} else if (contentType.startsWith('text/') || contentType.startsWith('application/json')) {
} else if (
contentType.startsWith('text/') ||
contentType.startsWith('application/json')
) {
return 'stream';
} else {
return 'unknown';
@ -108,7 +111,14 @@ export default class File extends Component {
}
}
@computed('clientTimeout', 'fileParams', 'fileUrl', 'mode', 'serverTimeout', 'useServer')
@computed(
'clientTimeout',
'fileParams',
'fileUrl',
'mode',
'serverTimeout',
'useServer'
)
get logger() {
// The cat and readat APIs are in plainText while the stream API is always encoded.
const plainText = this.mode === 'head' || this.mode === 'tail';

View File

@ -43,14 +43,17 @@ export default class GlobalSearchControl extends Component {
}
@task(function* (string) {
const searchResponse = yield this.token.authorizedRequest('/v1/search/fuzzy', {
method: 'POST',
body: JSON.stringify({
Text: string,
Context: 'all',
Namespace: '*',
}),
});
const searchResponse = yield this.token.authorizedRequest(
'/v1/search/fuzzy',
{
method: 'POST',
body: JSON.stringify({
Text: string,
Context: 'all',
Namespace: '*',
}),
}
);
const results = yield searchResponse.json();
@ -95,11 +98,13 @@ export default class GlobalSearchControl extends Component {
label: `${namespace} > ${jobId} > ${id}`,
}));
const csiPluginResults = allCSIPluginResults.slice(0, MAXIMUM_RESULTS).map(({ ID: id }) => ({
type: 'plugin',
id,
label: id,
}));
const csiPluginResults = allCSIPluginResults
.slice(0, MAXIMUM_RESULTS)
.map(({ ID: id }) => ({
type: 'plugin',
id,
label: id,
}));
const {
jobs: jobsTruncated,
@ -111,11 +116,21 @@ export default class GlobalSearchControl extends Component {
return [
{
groupName: resultsGroupLabel('Jobs', jobResults, allJobResults, jobsTruncated),
groupName: resultsGroupLabel(
'Jobs',
jobResults,
allJobResults,
jobsTruncated
),
options: jobResults,
},
{
groupName: resultsGroupLabel('Clients', nodeResults, allNodeResults, nodesTruncated),
groupName: resultsGroupLabel(
'Clients',
nodeResults,
allNodeResults,
nodesTruncated
),
options: nodeResults,
},
{
@ -191,10 +206,14 @@ export default class GlobalSearchControl extends Component {
openOnClickOrTab(select, { target }) {
// Bypass having to press enter to access search after clicking/tabbing
const targetClassList = target.classList;
const targetIsTrigger = targetClassList.contains('ember-power-select-trigger');
const targetIsTrigger = targetClassList.contains(
'ember-power-select-trigger'
);
// Allow tabbing out of search
const triggerIsNotActive = !targetClassList.contains('ember-power-select-trigger--active');
const triggerIsNotActive = !targetClassList.contains(
'ember-power-select-trigger--active'
);
if (targetIsTrigger && triggerIsNotActive) {
debounce(this, this.open, 150);

View File

@ -44,7 +44,9 @@ export default class GutterMenu extends Component {
// an intent to reset context, but where to reset to depends on where the namespace
// is being switched from. Jobs take precedence, but if the namespace is switched from
// a storage-related page, context should be reset to volumes.
const destination = this.router.currentRouteName.startsWith('csi.') ? 'csi.volumes' : 'jobs';
const destination = this.router.currentRouteName.startsWith('csi.')
? 'csi.volumes'
: 'jobs';
this.router.transitionTo(destination, {
queryParams: { namespace: namespace.get('id') },

View File

@ -12,8 +12,16 @@ export default class JobClientStatusBar extends DistributionBar {
@computed('job.namespace', 'jobClientStatus.byStatus')
get data() {
const { queued, starting, running, complete, degraded, failed, lost, notScheduled } =
this.jobClientStatus.byStatus;
const {
queued,
starting,
running,
complete,
degraded,
failed,
lost,
notScheduled,
} = this.jobClientStatus.byStatus;
return [
{

View File

@ -5,7 +5,11 @@ import classic from 'ember-classic-decorator';
@classic
@classNames('job-diff')
@classNameBindings('isEdited:is-edited', 'isAdded:is-added', 'isDeleted:is-deleted')
@classNameBindings(
'isEdited:is-edited',
'isAdded:is-added',
'isDeleted:is-deleted'
)
export default class JobDiff extends Component {
diff = null;

View File

@ -59,8 +59,14 @@ export default class JobDispatch extends Component {
);
// Fetch the different types of parameters.
const required = mapper(this.args.job.parameterizedDetails.MetaRequired || [], true);
const optional = mapper(this.args.job.parameterizedDetails.MetaOptional || [], false);
const required = mapper(
this.args.job.parameterizedDetails.MetaRequired || [],
true
);
const optional = mapper(
this.args.job.parameterizedDetails.MetaOptional || [],
false
);
// Merge them, required before optional.
this.metaFields = required.concat(optional);

View File

@ -25,7 +25,10 @@ export default class JobEditor extends Component {
set context(value) {
const allowedValues = ['new', 'edit'];
assert(`context must be one of: ${allowedValues.join(', ')}`, allowedValues.includes(value));
assert(
`context must be one of: ${allowedValues.join(', ')}`,
allowedValues.includes(value)
);
this.set('_context', value);
}

View File

@ -31,7 +31,9 @@ export default class JobVersion extends Component {
return (
fieldChanges(diff) +
taskGroups.reduce(arrayOfFieldChanges, 0) +
(taskGroups.mapBy('Tasks') || []).reduce(flatten, []).reduce(arrayOfFieldChanges, 0)
(taskGroups.mapBy('Tasks') || [])
.reduce(flatten, [])
.reduce(arrayOfFieldChanges, 0)
);
}
@ -58,7 +60,8 @@ export default class JobVersion extends Component {
this.handleError({
level: 'warn',
title: 'Reversion Had No Effect',
description: 'Reverting to an identical older version doesnt produce a new version',
description:
'Reverting to an identical older version doesnt produce a new version',
});
} else {
const job = this.get('version.job');
@ -79,7 +82,8 @@ export default class JobVersion extends Component {
}
const flatten = (accumulator, array) => accumulator.concat(array);
const countChanges = (total, field) => (changeTypes.includes(field.Type) ? total + 1 : total);
const countChanges = (total, field) =>
changeTypes.includes(field.Type) ? total + 1 : total;
function fieldChanges(diff) {
return (

View File

@ -24,7 +24,9 @@ export default class JobVersionsStream extends Component {
meta.showDate = true;
} else {
const previousVersion = versions.objectAt(index - 1);
const previousStart = moment(previousVersion.get('submitTime')).startOf('day');
const previousStart = moment(previousVersion.get('submitTime')).startOf(
'day'
);
const currentStart = moment(version.get('submitTime')).startOf('day');
if (previousStart.diff(currentStart, 'days') > 0) {
meta.showDate = true;

View File

@ -92,7 +92,9 @@ export default class LineChart extends Component {
@action
xFormat(timeseries) {
if (this.args.xFormat) return this.args.xFormat;
return timeseries ? d3TimeFormat.timeFormat('%b %d, %H:%M') : d3Format.format(',');
return timeseries
? d3TimeFormat.timeFormat('%b %d, %H:%M')
: d3Format.format(',');
}
@action
@ -153,7 +155,11 @@ export default class LineChart extends Component {
get xAxis() {
const formatter = this.xFormat(this.args.timeseries);
return d3Axis.axisBottom().scale(this.xScale).ticks(5).tickFormat(formatter);
return d3Axis
.axisBottom()
.scale(this.xScale)
.ticks(5)
.tickFormat(formatter);
}
get yTicks() {
@ -167,7 +173,11 @@ export default class LineChart extends Component {
get yAxis() {
const formatter = this.yFormat();
return d3Axis.axisRight().scale(this.yScale).tickValues(this.yTicks).tickFormat(formatter);
return d3Axis
.axisRight()
.scale(this.yScale)
.tickValues(this.yTicks)
.tickFormat(formatter);
}
get yGridlines() {
@ -297,7 +307,11 @@ export default class LineChart extends Component {
// Of the selected data, determine which is closest
const closestDatum = activeData
.slice()
.sort((a, b) => Math.abs(a.datum.datum[xProp] - x) - Math.abs(b.datum.datum[xProp] - x))[0];
.sort(
(a, b) =>
Math.abs(a.datum.datum[xProp] - x) -
Math.abs(b.datum.datum[xProp] - x)
)[0];
// If any other selected data are beyond a distance threshold, drop them from the list
// xScale is used here to measure distance in screen-space rather than data-space.
@ -340,7 +354,9 @@ export default class LineChart extends Component {
if (!this.isDestroyed && !this.isDestroying) {
d3.select(this.element.querySelector('.x-axis')).call(this.xAxis);
d3.select(this.element.querySelector('.y-axis')).call(this.yAxis);
d3.select(this.element.querySelector('.y-gridlines')).call(this.yGridlines);
d3.select(this.element.querySelector('.y-gridlines')).call(
this.yGridlines
);
}
}

View File

@ -60,8 +60,12 @@ export default class MultiSelectDropdown extends Component {
dropdown.actions.open(e);
e.preventDefault();
} else if (this.isOpen && (e.keyCode === TAB || e.keyCode === ARROW_DOWN)) {
const optionsId = this.element.querySelector('.dropdown-trigger').getAttribute('aria-owns');
const firstElement = document.querySelector(`#${optionsId} .dropdown-option`);
const optionsId = this.element
.querySelector('.dropdown-trigger')
.getAttribute('aria-owns');
const firstElement = document.querySelector(
`#${optionsId} .dropdown-option`
);
if (firstElement) {
firstElement.focus();

View File

@ -49,7 +49,9 @@ export default class PopoverMenu extends Component {
dropdown.actions.open(e);
e.preventDefault();
} else if (this.isOpen && (e.keyCode === TAB || e.keyCode === ARROW_DOWN)) {
const optionsId = this.element.querySelector('.popover-trigger').getAttribute('aria-owns');
const optionsId = this.element
.querySelector('.popover-trigger')
.getAttribute('aria-owns');
const popoverContentEl = document.querySelector(`#${optionsId}`);
const firstFocusableElement = popoverContentEl.querySelector(FOCUSABLE);

View File

@ -4,7 +4,10 @@ import { task, timeout } from 'ember-concurrency';
import { assert } from '@ember/debug';
import { inject as service } from '@ember/service';
import { action, get } from '@ember/object';
import { formatScheduledBytes, formatScheduledHertz } from 'nomad-ui/utils/units';
import {
formatScheduledBytes,
formatScheduledHertz,
} from 'nomad-ui/utils/units';
export default class NodePrimaryMetric extends Component {
@service('stats-trackers-registry') statsTrackersRegistry;

View File

@ -53,7 +53,9 @@ export default class TaskPrimaryMetric extends Component {
@action
start() {
this.taskState = this.args.taskState;
this.tracker = this.statsTrackersRegistry.getTracker(this.args.taskState.allocation);
this.tracker = this.statsTrackersRegistry.getTracker(
this.args.taskState.allocation
);
this.poller.perform();
}

View File

@ -40,7 +40,10 @@ export default class ScaleEventsChart extends Component {
}
toggleEvent(ev) {
if (this.activeEvent && get(this.activeEvent, 'event.uid') === get(ev, 'event.uid')) {
if (
this.activeEvent &&
get(this.activeEvent, 'event.uid') === get(ev, 'event.uid')
) {
this.closeEventDetails();
} else {
this.activeEvent = ev;

View File

@ -3,7 +3,11 @@ import { alias } from '@ember/object/computed';
import Component from '@ember/component';
import { computed } from '@ember/object';
import { lazyClick } from '../helpers/lazy-click';
import { classNames, classNameBindings, tagName } from '@ember-decorators/component';
import {
classNames,
classNameBindings,
tagName,
} from '@ember-decorators/component';
import classic from 'ember-classic-decorator';
@classic
@ -38,7 +42,8 @@ export default class ServerAgentRow extends Component {
}
click() {
const transition = () => this.router.transitionTo('servers.server', this.agent);
const transition = () =>
this.router.transitionTo('servers.server', this.agent);
lazyClick([transition, event]);
}
}

View File

@ -39,14 +39,18 @@ export default class StatsTimeSeries extends Component {
const [low, high] = d3Array.extent(data, (d) => d.timestamp);
const minLow = moment(high).subtract(5, 'minutes').toDate();
const extent = data.length ? [Math.min(low, minLow), high] : [minLow, new Date()];
const extent = data.length
? [Math.min(low, minLow), high]
: [minLow, new Date()];
scale.rangeRound([10, yAxisOffset]).domain(extent);
return scale;
}
yScale(data, xAxisOffset) {
const yValues = (data || []).mapBy(this.args.dataProp ? 'percentStack' : 'percent');
const yValues = (data || []).mapBy(
this.args.dataProp ? 'percentStack' : 'percent'
);
let [low, high] = [0, 1];
if (yValues.compact().length) {

View File

@ -9,7 +9,12 @@ const ESC = 27;
@classic
@classNames('stepper-input')
@classNameBindings('class', 'disabled:is-disabled', 'disabled:tooltip', 'disabled:multiline')
@classNameBindings(
'class',
'disabled:is-disabled',
'disabled:tooltip',
'disabled:multiline'
)
export default class StepperInput extends Component {
min = 0;
max = 10;
@ -41,7 +46,9 @@ export default class StepperInput extends Component {
@action
setValue(e) {
if (e.target.value !== '') {
const newValue = Math.floor(Math.min(this.max, Math.max(this.min, e.target.value)));
const newValue = Math.floor(
Math.min(this.max, Math.max(this.min, e.target.value))
);
this.set('internalValue', newValue);
this.update(this.internalValue);
} else {

View File

@ -59,7 +59,10 @@ export default class StreamingFile extends Component.extend(WindowResizable) {
if (this.requestFrame) {
window.requestAnimationFrame(() => {
// If the scroll position is close enough to the bottom, autoscroll to the bottom
this.set('follow', cli.scrollHeight - cli.scrollTop - cli.clientHeight < 20);
this.set(
'follow',
cli.scrollHeight - cli.scrollTop - cli.clientHeight < 20
);
this.requestFrame = true;
});
}
@ -105,7 +108,9 @@ export default class StreamingFile extends Component.extend(WindowResizable) {
// of having the log window fill available height is worth the hack.
const margins = 30; // Account for padding and margin on either side of the CLI
const cliWindow = this.element;
cliWindow.style.height = `${window.innerHeight - cliWindow.offsetTop - margins}px`;
cliWindow.style.height = `${
window.innerHeight - cliWindow.offsetTop - margins
}px`;
}
@task(function* () {

View File

@ -27,7 +27,8 @@ export default class TaskGroupRow extends Component {
get tooltipText() {
if (this.can.cannot('scale job', null, { namespace: this.namespace }))
return "You aren't allowed to scale task groups";
if (this.runningDeployment) return 'You cannot scale task groups during a deployment';
if (this.runningDeployment)
return 'You cannot scale task groups during a deployment';
return undefined;
}

View File

@ -58,7 +58,9 @@ export default class TaskLog extends Component {
// If the log request can't settle in one second, the client
// must be unavailable and the server should be used instead
const aborter = window.AbortController ? new AbortController() : new MockAbortController();
const aborter = window.AbortController
? new AbortController()
: new MockAbortController();
const timing = this.useServer ? this.serverTimeout : this.clientTimeout;
// Capture the state of useServer at logger create time to avoid a race

View File

@ -1,5 +1,9 @@
import Component from '@ember/component';
import { classNames, classNameBindings, tagName } from '@ember-decorators/component';
import {
classNames,
classNameBindings,
tagName,
} from '@ember-decorators/component';
import classic from 'ember-classic-decorator';
@classic

View File

@ -8,7 +8,9 @@ export default class Tooltip extends Component {
}
const prefix = inputText.substr(0, 15).trim();
const suffix = inputText.substr(inputText.length - 10, inputText.length).trim();
const suffix = inputText
.substr(inputText.length - 10, inputText.length)
.trim();
return `${prefix}...${suffix}`;
}
}

View File

@ -26,11 +26,14 @@ export default class TopoViz extends Component {
@styleStringProperty('tooltipProps') tooltipStyle;
get isSingleColumn() {
if (this.topology.datacenters.length <= 1 || this.viewportColumns === 1) return true;
if (this.topology.datacenters.length <= 1 || this.viewportColumns === 1)
return true;
// Compute the coefficient of variance to determine if it would be
// better to stack datacenters or place them in columns
const nodeCounts = this.topology.datacenters.map((datacenter) => datacenter.nodes.length);
const nodeCounts = this.topology.datacenters.map(
(datacenter) => datacenter.nodes.length
);
const variationCoefficient = deviation(nodeCounts) / mean(nodeCounts);
// The point at which the varation is too extreme for a two column layout
@ -43,7 +46,10 @@ export default class TopoViz extends Component {
// If there are enough nodes, use two columns of nodes within
// a single column layout of datacenters to increase density.
if (this.viewportColumns === 1) return true;
return !this.isSingleColumn || (this.isSingleColumn && this.args.nodes.length <= 20);
return (
!this.isSingleColumn ||
(this.isSingleColumn && this.args.nodes.length <= 20)
);
}
// Once a cluster is large enough, the exact details of a node are
@ -110,7 +116,10 @@ export default class TopoViz extends Component {
// Ignore orphaned allocations and allocations on nodes with an old Nomad agent version.
if (!nodeContainer) return;
const allocationContainer = this.dataForAllocation(allocation, nodeContainer);
const allocationContainer = this.dataForAllocation(
allocation,
nodeContainer
);
nodeContainer.allocations.push(allocationContainer);
const key = allocationContainer.groupKey;
@ -119,11 +128,15 @@ export default class TopoViz extends Component {
});
// Group nodes into datacenters
const datacentersMap = nodeContainers.reduce((datacenters, nodeContainer) => {
if (!datacenters[nodeContainer.datacenter]) datacenters[nodeContainer.datacenter] = [];
datacenters[nodeContainer.datacenter].push(nodeContainer);
return datacenters;
}, {});
const datacentersMap = nodeContainers.reduce(
(datacenters, nodeContainer) => {
if (!datacenters[nodeContainer.datacenter])
datacenters[nodeContainer.datacenter] = [];
datacenters[nodeContainer.datacenter].push(nodeContainer);
return datacenters;
},
{}
);
// Turn hash of datacenters into a sorted array
const datacenters = Object.keys(datacentersMap)
@ -191,7 +204,8 @@ export default class TopoViz extends Component {
this.activeEdges = [];
if (this.topology.selectedKey) {
const selectedAllocations = this.topology.allocationIndex[this.topology.selectedKey];
const selectedAllocations =
this.topology.allocationIndex[this.topology.selectedKey];
if (selectedAllocations) {
selectedAllocations.forEach((allocation) => {
set(allocation, 'isSelected', false);
@ -205,7 +219,8 @@ export default class TopoViz extends Component {
}
this.activeNode = null;
this.activeAllocation = allocation;
const selectedAllocations = this.topology.allocationIndex[this.topology.selectedKey];
const selectedAllocations =
this.topology.allocationIndex[this.topology.selectedKey];
if (selectedAllocations) {
selectedAllocations.forEach((allocation) => {
set(allocation, 'isSelected', false);
@ -213,7 +228,8 @@ export default class TopoViz extends Component {
}
set(this.topology, 'selectedKey', allocation.groupKey);
const newAllocations = this.topology.allocationIndex[this.topology.selectedKey];
const newAllocations =
this.topology.allocationIndex[this.topology.selectedKey];
if (newAllocations) {
newAllocations.forEach((allocation) => {
set(allocation, 'isSelected', true);
@ -221,14 +237,19 @@ export default class TopoViz extends Component {
}
// Only show the lines if the selected allocations are sparse (low count relative to the client count or low count generally).
if (newAllocations.length < 10 || newAllocations.length < this.args.nodes.length * 0.75) {
if (
newAllocations.length < 10 ||
newAllocations.length < this.args.nodes.length * 0.75
) {
this.computedActiveEdges();
} else {
this.activeEdges = [];
}
}
if (this.args.onAllocationSelect)
this.args.onAllocationSelect(this.activeAllocation && this.activeAllocation.allocation);
this.args.onAllocationSelect(
this.activeAllocation && this.activeAllocation.allocation
);
if (this.args.onNodeSelect) this.args.onNodeSelect(this.activeNode);
}
@ -251,11 +272,15 @@ export default class TopoViz extends Component {
const path = line().curve(curveBasis);
// 1. Get the active element
const allocation = this.activeAllocation.allocation;
const activeEl = this.element.querySelector(`[data-allocation-id="${allocation.id}"]`);
const activeEl = this.element.querySelector(
`[data-allocation-id="${allocation.id}"]`
);
const activePoint = centerOfBBox(activeEl.getBoundingClientRect());
// 2. Collect the mem and cpu pairs for all selected allocs
const selectedMem = Array.from(this.element.querySelectorAll('.memory .bar.is-selected'));
const selectedMem = Array.from(
this.element.querySelectorAll('.memory .bar.is-selected')
);
const selectedPairs = selectedMem.map((mem) => {
const id = mem.closest('[data-allocation-id]').dataset.allocationId;
const cpu = mem
@ -283,8 +308,14 @@ export default class TopoViz extends Component {
const stepsSecondary = [0.8, 1.0];
selectedPoints.forEach((points) => {
curves.push(
curveFromPoints(...pointsAlongPath(activePoint, points[2], stepsMain), points[0]),
curveFromPoints(...pointsAlongPath(activePoint, points[2], stepsSecondary), points[1])
curveFromPoints(
...pointsAlongPath(activePoint, points[2], stepsMain),
points[0]
),
curveFromPoints(
...pointsAlongPath(activePoint, points[2], stepsSecondary),
points[1]
)
);
});

View File

@ -3,7 +3,8 @@ import Component from '@glimmer/component';
export default class TopoVizDatacenter extends Component {
get scheduledAllocations() {
return this.args.datacenter.nodes.reduce(
(all, node) => all.concat(node.allocations.filterBy('allocation.isScheduled')),
(all, node) =>
all.concat(node.allocations.filterBy('allocation.isScheduled')),
[]
);
}

View File

@ -10,7 +10,9 @@ export default class TopoVizNode extends Component {
@tracked activeAllocation = null;
get height() {
return this.args.heightScale ? this.args.heightScale(this.args.node.memory) : 15;
return this.args.heightScale
? this.args.heightScale(this.args.node.memory)
: 15;
}
get labelHeight() {
@ -57,11 +59,13 @@ export default class TopoVizNode extends Component {
get allocations() {
// Sort by the delta between memory and cpu percent. This creates the least amount of
// drift between the positional alignment of an alloc's cpu and memory representations.
return this.args.node.allocations.filterBy('allocation.isScheduled').sort((a, b) => {
const deltaA = Math.abs(a.memoryPercent - a.cpuPercent);
const deltaB = Math.abs(b.memoryPercent - b.cpuPercent);
return deltaA - deltaB;
});
return this.args.node.allocations
.filterBy('allocation.isScheduled')
.sort((a, b) => {
const deltaA = Math.abs(a.memoryPercent - a.cpuPercent);
const deltaB = Math.abs(b.memoryPercent - b.cpuPercent);
return deltaA - deltaB;
});
}
@action
@ -91,7 +95,8 @@ export default class TopoVizNode extends Component {
@action
highlightAllocation(allocation, { target }) {
this.activeAllocation = allocation;
this.args.onAllocationFocus && this.args.onAllocationFocus(allocation, target);
this.args.onAllocationFocus &&
this.args.onAllocationFocus(allocation, target);
}
@action

View File

@ -9,7 +9,10 @@ import classic from 'ember-classic-decorator';
@classic
@classNames('two-step-button')
@classNameBindings('inlineText:has-inline-text', 'fadingBackground:has-fading-background')
@classNameBindings(
'inlineText:has-inline-text',
'fadingBackground:has-fading-background'
)
export default class TwoStepButton extends Component {
idleText = '';
cancelText = '';

View File

@ -10,11 +10,17 @@ import intersection from 'lodash.intersection';
import Sortable from 'nomad-ui/mixins/sortable';
import Searchable from 'nomad-ui/mixins/searchable';
import messageFromAdapterError from 'nomad-ui/utils/message-from-adapter-error';
import { serialize, deserializedQueryParam as selection } from 'nomad-ui/utils/qp-serialize';
import {
serialize,
deserializedQueryParam as selection,
} from 'nomad-ui/utils/qp-serialize';
import classic from 'ember-classic-decorator';
@classic
export default class ClientController extends Controller.extend(Sortable, Searchable) {
export default class ClientController extends Controller.extend(
Sortable,
Searchable
) {
queryParams = [
{
currentPage: 'page',
@ -66,18 +72,32 @@ export default class ClientController extends Controller.extend(Sortable, Search
return this.onlyPreemptions ? this.preemptions : this.model.allocations;
}
@computed('visibleAllocations.[]', 'selectionNamespace', 'selectionJob', 'selectionStatus')
@computed(
'visibleAllocations.[]',
'selectionNamespace',
'selectionJob',
'selectionStatus'
)
get filteredAllocations() {
const { selectionNamespace, selectionJob, selectionStatus } = this;
return this.visibleAllocations.filter((alloc) => {
if (selectionNamespace.length && !selectionNamespace.includes(alloc.get('namespace'))) {
if (
selectionNamespace.length &&
!selectionNamespace.includes(alloc.get('namespace'))
) {
return false;
}
if (selectionJob.length && !selectionJob.includes(alloc.get('plainJobId'))) {
if (
selectionJob.length &&
!selectionJob.includes(alloc.get('plainJobId'))
) {
return false;
}
if (selectionStatus.length && !selectionStatus.includes(alloc.clientStatus)) {
if (
selectionStatus.length &&
!selectionStatus.includes(alloc.clientStatus)
) {
return false;
}
return true;
@ -217,12 +237,17 @@ export default class ClientController extends Controller.extend(Sortable, Search
@computed('model.allocations.[]', 'selectionNamespace')
get optionsNamespace() {
const ns = Array.from(new Set(this.model.allocations.mapBy('namespace'))).compact();
const ns = Array.from(
new Set(this.model.allocations.mapBy('namespace'))
).compact();
// Update query param when the list of namespaces changes.
scheduleOnce('actions', () => {
// eslint-disable-next-line ember/no-side-effects
this.set('qpNamespace', serialize(intersection(ns, this.selectionNamespace)));
this.set(
'qpNamespace',
serialize(intersection(ns, this.selectionNamespace))
);
});
return ns.sort().map((n) => ({ key: n, label: n }));

View File

@ -7,7 +7,10 @@ import { scheduleOnce } from '@ember/runloop';
import intersection from 'lodash.intersection';
import SortableFactory from 'nomad-ui/mixins/sortable-factory';
import Searchable from 'nomad-ui/mixins/searchable';
import { serialize, deserializedQueryParam as selection } from 'nomad-ui/utils/qp-serialize';
import {
serialize,
deserializedQueryParam as selection,
} from 'nomad-ui/utils/qp-serialize';
import classic from 'ember-classic-decorator';
@classic
@ -83,7 +86,10 @@ export default class IndexController extends Controller.extend(
// Remove any invalid node classes from the query param/selection
scheduleOnce('actions', () => {
// eslint-disable-next-line ember/no-side-effects
this.set('qpClass', serialize(intersection(classes, this.selectionClass)));
this.set(
'qpClass',
serialize(intersection(classes, this.selectionClass))
);
});
return classes.sort().map((dc) => ({ key: dc, label: dc }));
@ -102,12 +108,17 @@ export default class IndexController extends Controller.extend(
@computed('nodes.[]', 'selectionDatacenter')
get optionsDatacenter() {
const datacenters = Array.from(new Set(this.nodes.mapBy('datacenter'))).compact();
const datacenters = Array.from(
new Set(this.nodes.mapBy('datacenter'))
).compact();
// Remove any invalid datacenters from the query param/selection
scheduleOnce('actions', () => {
// eslint-disable-next-line ember/no-side-effects
this.set('qpDatacenter', serialize(intersection(datacenters, this.selectionDatacenter)));
this.set(
'qpDatacenter',
serialize(intersection(datacenters, this.selectionDatacenter))
);
});
return datacenters.sort().map((dc) => ({ key: dc, label: dc }));
@ -120,7 +131,10 @@ export default class IndexController extends Controller.extend(
// Remove any invalid versions from the query param/selection
scheduleOnce('actions', () => {
// eslint-disable-next-line ember/no-side-effects
this.set('qpVersion', serialize(intersection(versions, this.selectionVersion)));
this.set(
'qpVersion',
serialize(intersection(versions, this.selectionVersion))
);
});
return versions.sort().map((v) => ({ key: v, label: v }));
@ -135,7 +149,10 @@ export default class IndexController extends Controller.extend(
scheduleOnce('actions', () => {
// eslint-disable-next-line ember/no-side-effects
this.set('qpVolume', serialize(intersection(volumes, this.selectionVolume)));
this.set(
'qpVolume',
serialize(intersection(volumes, this.selectionVolume))
);
});
return volumes.sort().map((volume) => ({ key: volume, label: volume }));
@ -165,11 +182,18 @@ export default class IndexController extends Controller.extend(
const statuses = states.without('ineligible').without('draining');
return this.nodes.filter((node) => {
if (classes.length && !classes.includes(node.get('nodeClass'))) return false;
if (statuses.length && !statuses.includes(node.get('status'))) return false;
if (datacenters.length && !datacenters.includes(node.get('datacenter'))) return false;
if (versions.length && !versions.includes(node.get('version'))) return false;
if (volumes.length && !node.hostVolumes.find((volume) => volumes.includes(volume.name)))
if (classes.length && !classes.includes(node.get('nodeClass')))
return false;
if (statuses.length && !statuses.includes(node.get('status')))
return false;
if (datacenters.length && !datacenters.includes(node.get('datacenter')))
return false;
if (versions.length && !versions.includes(node.get('version')))
return false;
if (
volumes.length &&
!node.hostVolumes.find((volume) => volumes.includes(volume.name))
)
return false;
if (onlyIneligible && node.get('isEligible')) return false;

View File

@ -59,6 +59,9 @@ export default class IndexController extends Controller.extend(
@action
gotoPlugin(plugin, event) {
lazyClick([() => this.transitionToRoute('csi.plugins.plugin', plugin.plainId), event]);
lazyClick([
() => this.transitionToRoute('csi.plugins.plugin', plugin.plainId),
event,
]);
}
}

View File

@ -4,7 +4,10 @@ import { action, computed } from '@ember/object';
import { alias, readOnly } from '@ember/object/computed';
import SortableFactory from 'nomad-ui/mixins/sortable-factory';
import { lazyClick } from 'nomad-ui/helpers/lazy-click';
import { serialize, deserializedQueryParam as selection } from 'nomad-ui/utils/qp-serialize';
import {
serialize,
deserializedQueryParam as selection,
} from 'nomad-ui/utils/qp-serialize';
import classic from 'ember-classic-decorator';
@classic
@ -82,7 +85,8 @@ export default class AllocationsController extends Controller.extend(
listToFilter = this.model.nodes;
}
if (healths.length === 1 && healths[0] === 'true') return listToFilter.filterBy('healthy');
if (healths.length === 1 && healths[0] === 'true')
return listToFilter.filterBy('healthy');
if (healths.length === 1 && healths[0] === 'false')
return listToFilter.filterBy('healthy', false);
return listToFilter;
@ -103,6 +107,9 @@ export default class AllocationsController extends Controller.extend(
@action
gotoAllocation(allocation, event) {
lazyClick([() => this.transitionToRoute('allocations.allocation', allocation), event]);
lazyClick([
() => this.transitionToRoute('allocations.allocation', allocation),
event,
]);
}
}

View File

@ -25,18 +25,25 @@ export default class ExecController extends Controller {
@computed('model.allocations.@each.clientStatus')
get pendingAndRunningAllocations() {
return this.model.allocations.filter(
(allocation) => allocation.clientStatus === 'pending' || allocation.clientStatus === 'running'
(allocation) =>
allocation.clientStatus === 'pending' ||
allocation.clientStatus === 'running'
);
}
@mapBy('pendingAndRunningAllocations', 'taskGroup') pendingAndRunningTaskGroups;
@mapBy('pendingAndRunningAllocations', 'taskGroup')
pendingAndRunningTaskGroups;
@uniq('pendingAndRunningTaskGroups') uniquePendingAndRunningTaskGroups;
taskGroupSorting = ['name'];
@sort('uniquePendingAndRunningTaskGroups', 'taskGroupSorting') sortedTaskGroups;
@sort('uniquePendingAndRunningTaskGroups', 'taskGroupSorting')
sortedTaskGroups;
setUpTerminal(Terminal) {
this.terminal = new Terminal({ fontFamily: 'monospace', fontWeight: '400' });
this.terminal = new Terminal({
fontFamily: 'monospace',
fontWeight: '400',
});
window.execTerminal = this.terminal; // Issue to improve: https://github.com/hashicorp/nomad/issues/7457
this.terminal.write(ANSI_UI_GRAY_400);
@ -64,7 +71,10 @@ export default class ExecController extends Controller {
allocation = this.allocations.findBy('shortId', this.allocationShortId);
} else {
allocation = this.allocations.find((allocation) =>
allocation.states.filterBy('isActive').mapBy('name').includes(this.taskName)
allocation.states
.filterBy('isActive')
.mapBy('name')
.includes(this.taskName)
);
}
@ -94,7 +104,9 @@ export default class ExecController extends Controller {
this.terminal.writeln('');
}
this.terminal.writeln('Customize your command, then hit return to run.');
this.terminal.writeln(
'Customize your command, then hit return to run.'
);
this.terminal.writeln('');
this.terminal.write(
`$ nomad alloc exec -i -t -task ${escapeTaskName(taskName)} ${
@ -126,7 +138,9 @@ export default class ExecController extends Controller {
new ExecSocketXtermAdapter(this.terminal, this.socket, this.token.secret);
} else {
this.terminal.writeln(`Failed to open a socket because task ${this.taskName} is not active.`);
this.terminal.writeln(
`Failed to open a socket because task ${this.taskName} is not active.`
);
}
}
}

View File

@ -8,11 +8,17 @@ import { scheduleOnce } from '@ember/runloop';
import intersection from 'lodash.intersection';
import Sortable from 'nomad-ui/mixins/sortable';
import Searchable from 'nomad-ui/mixins/searchable';
import { serialize, deserializedQueryParam as selection } from 'nomad-ui/utils/qp-serialize';
import {
serialize,
deserializedQueryParam as selection,
} from 'nomad-ui/utils/qp-serialize';
import classic from 'ember-classic-decorator';
@classic
export default class IndexController extends Controller.extend(Sortable, Searchable) {
export default class IndexController extends Controller.extend(
Sortable,
Searchable
) {
@service system;
@service userSettings;
@ -100,7 +106,9 @@ export default class IndexController extends Controller.extend(Sortable, Searcha
@computed('selectionDatacenter', 'visibleJobs.[]')
get optionsDatacenter() {
const flatten = (acc, val) => acc.concat(val);
const allDatacenters = new Set(this.visibleJobs.mapBy('datacenters').reduce(flatten, []));
const allDatacenters = new Set(
this.visibleJobs.mapBy('datacenters').reduce(flatten, [])
);
// Remove any invalid datacenters from the query param/selection
const availableDatacenters = Array.from(allDatacenters).compact();
@ -144,7 +152,10 @@ export default class IndexController extends Controller.extend(Sortable, Searcha
const availablePrefixes = prefixes.mapBy('prefix');
scheduleOnce('actions', () => {
// eslint-disable-next-line ember/no-side-effects
this.set('qpPrefix', serialize(intersection(availablePrefixes, this.selectionPrefix)));
this.set(
'qpPrefix',
serialize(intersection(availablePrefixes, this.selectionPrefix))
);
});
// Sort, format, and include the count in the label
@ -216,12 +227,18 @@ export default class IndexController extends Controller.extend(Sortable, Searcha
return false;
}
if (datacenters.length && !job.get('datacenters').find((dc) => datacenters.includes(dc))) {
if (
datacenters.length &&
!job.get('datacenters').find((dc) => datacenters.includes(dc))
) {
return false;
}
const name = job.get('name');
if (prefixes.length && !prefixes.find((prefix) => name.startsWith(prefix))) {
if (
prefixes.length &&
!prefixes.find((prefix) => name.startsWith(prefix))
) {
return false;
}

View File

@ -7,7 +7,10 @@ import intersection from 'lodash.intersection';
import Sortable from 'nomad-ui/mixins/sortable';
import Searchable from 'nomad-ui/mixins/searchable';
import WithNamespaceResetting from 'nomad-ui/mixins/with-namespace-resetting';
import { serialize, deserializedQueryParam as selection } from 'nomad-ui/utils/qp-serialize';
import {
serialize,
deserializedQueryParam as selection,
} from 'nomad-ui/utils/qp-serialize';
import classic from 'ember-classic-decorator';
@classic
@ -61,18 +64,32 @@ export default class AllocationsController extends Controller.extend(
return this.get('model.allocations') || [];
}
@computed('allocations.[]', 'selectionStatus', 'selectionClient', 'selectionTaskGroup')
@computed(
'allocations.[]',
'selectionStatus',
'selectionClient',
'selectionTaskGroup'
)
get filteredAllocations() {
const { selectionStatus, selectionClient, selectionTaskGroup } = this;
return this.allocations.filter((alloc) => {
if (selectionStatus.length && !selectionStatus.includes(alloc.clientStatus)) {
if (
selectionStatus.length &&
!selectionStatus.includes(alloc.clientStatus)
) {
return false;
}
if (selectionClient.length && !selectionClient.includes(alloc.get('node.shortId'))) {
if (
selectionClient.length &&
!selectionClient.includes(alloc.get('node.shortId'))
) {
return false;
}
if (selectionTaskGroup.length && !selectionTaskGroup.includes(alloc.taskGroupName)) {
if (
selectionTaskGroup.length &&
!selectionTaskGroup.includes(alloc.taskGroupName)
) {
return false;
}
return true;
@ -104,12 +121,17 @@ export default class AllocationsController extends Controller.extend(
@computed('model.allocations.[]', 'selectionClient')
get optionsClients() {
const clients = Array.from(new Set(this.model.allocations.mapBy('node.shortId'))).compact();
const clients = Array.from(
new Set(this.model.allocations.mapBy('node.shortId'))
).compact();
// Update query param when the list of clients changes.
scheduleOnce('actions', () => {
// eslint-disable-next-line ember/no-side-effects
this.set('qpClient', serialize(intersection(clients, this.selectionClient)));
this.set(
'qpClient',
serialize(intersection(clients, this.selectionClient))
);
});
return clients.sort().map((c) => ({ key: c, label: c }));
@ -117,12 +139,17 @@ export default class AllocationsController extends Controller.extend(
@computed('model.allocations.[]', 'selectionTaskGroup')
get optionsTaskGroups() {
const taskGroups = Array.from(new Set(this.model.allocations.mapBy('taskGroupName'))).compact();
const taskGroups = Array.from(
new Set(this.model.allocations.mapBy('taskGroupName'))
).compact();
// Update query param when the list of task groups changes.
scheduleOnce('actions', () => {
// eslint-disable-next-line ember/no-side-effects
this.set('qpTaskGroup', serialize(intersection(taskGroups, this.selectionTaskGroup)));
this.set(
'qpTaskGroup',
serialize(intersection(taskGroups, this.selectionTaskGroup))
);
});
return taskGroups.sort().map((tg) => ({ key: tg, label: tg }));

View File

@ -8,7 +8,10 @@ import SortableFactory from 'nomad-ui/mixins/sortable-factory';
import Searchable from 'nomad-ui/mixins/searchable';
import WithNamespaceResetting from 'nomad-ui/mixins/with-namespace-resetting';
import jobClientStatus from 'nomad-ui/utils/properties/job-client-status';
import { serialize, deserializedQueryParam as selection } from 'nomad-ui/utils/qp-serialize';
import {
serialize,
deserializedQueryParam as selection,
} from 'nomad-ui/utils/qp-serialize';
import classic from 'ember-classic-decorator';
@classic
@ -96,7 +99,10 @@ export default class ClientsController extends Controller.extend(
return this.nodes
.filter((node) => {
if (statuses.length && !statuses.includes(this.jobClientStatus.byNode[node.id])) {
if (
statuses.length &&
!statuses.includes(this.jobClientStatus.byNode[node.id])
) {
return false;
}
if (datacenters.length && !datacenters.includes(node.datacenter)) {
@ -109,7 +115,9 @@ export default class ClientsController extends Controller.extend(
return true;
})
.map((node) => {
const allocations = this.job.allocations.filter((alloc) => alloc.get('node.id') == node.id);
const allocations = this.job.allocations.filter(
(alloc) => alloc.get('node.id') == node.id
);
return {
node,
@ -137,12 +145,17 @@ export default class ClientsController extends Controller.extend(
@computed('selectionDatacenter', 'nodes')
get optionsDatacenter() {
const datacenters = Array.from(new Set(this.nodes.mapBy('datacenter'))).compact();
const datacenters = Array.from(
new Set(this.nodes.mapBy('datacenter'))
).compact();
// Update query param when the list of datacenters changes.
scheduleOnce('actions', () => {
// eslint-disable-next-line ember/no-side-effects
this.set('qpDatacenter', serialize(intersection(datacenters, this.selectionDatacenter)));
this.set(
'qpDatacenter',
serialize(intersection(datacenters, this.selectionDatacenter))
);
});
return datacenters.sort().map((dc) => ({ key: dc, label: dc }));
@ -150,15 +163,22 @@ export default class ClientsController extends Controller.extend(
@computed('selectionClientClass', 'nodes')
get optionsClientClass() {
const clientClasses = Array.from(new Set(this.nodes.mapBy('nodeClass'))).compact();
const clientClasses = Array.from(
new Set(this.nodes.mapBy('nodeClass'))
).compact();
// Update query param when the list of datacenters changes.
scheduleOnce('actions', () => {
// eslint-disable-next-line ember/no-side-effects
this.set('qpClientClass', serialize(intersection(clientClasses, this.selectionClientClass)));
this.set(
'qpClientClass',
serialize(intersection(clientClasses, this.selectionClientClass))
);
});
return clientClasses.sort().map((clientClass) => ({ key: clientClass, label: clientClass }));
return clientClasses
.sort()
.map((clientClass) => ({ key: clientClass, label: clientClass }));
}
@action

View File

@ -4,7 +4,9 @@ import { alias } from '@ember/object/computed';
import classic from 'ember-classic-decorator';
@classic
export default class DefinitionController extends Controller.extend(WithNamespaceResetting) {
export default class DefinitionController extends Controller.extend(
WithNamespaceResetting
) {
@alias('model.job') job;
@alias('model.definition') definition;

View File

@ -4,6 +4,8 @@ import { alias } from '@ember/object/computed';
import classic from 'ember-classic-decorator';
@classic
export default class DeploymentsController extends Controller.extend(WithNamespaceResetting) {
export default class DeploymentsController extends Controller.extend(
WithNamespaceResetting
) {
@alias('model') job;
}

View File

@ -6,7 +6,9 @@ import { action } from '@ember/object';
import classic from 'ember-classic-decorator';
@classic
export default class IndexController extends Controller.extend(WithNamespaceResetting) {
export default class IndexController extends Controller.extend(
WithNamespaceResetting
) {
@service system;
queryParams = [
@ -38,7 +40,11 @@ export default class IndexController extends Controller.extend(WithNamespaceRese
@action
gotoTaskGroup(taskGroup) {
this.transitionToRoute('jobs.job.task-group', taskGroup.get('job'), taskGroup);
this.transitionToRoute(
'jobs.job.task-group',
taskGroup.get('job'),
taskGroup
);
}
@action

View File

@ -9,7 +9,10 @@ import { qpBuilder } from 'nomad-ui/utils/classes/query-params';
import Sortable from 'nomad-ui/mixins/sortable';
import Searchable from 'nomad-ui/mixins/searchable';
import WithNamespaceResetting from 'nomad-ui/mixins/with-namespace-resetting';
import { serialize, deserializedQueryParam as selection } from 'nomad-ui/utils/qp-serialize';
import {
serialize,
deserializedQueryParam as selection,
} from 'nomad-ui/utils/qp-serialize';
import classic from 'ember-classic-decorator';
@classic
@ -65,10 +68,16 @@ export default class TaskGroupController extends Controller.extend(
const { selectionStatus, selectionClient } = this;
return this.allocations.filter((alloc) => {
if (selectionStatus.length && !selectionStatus.includes(alloc.clientStatus)) {
if (
selectionStatus.length &&
!selectionStatus.includes(alloc.clientStatus)
) {
return false;
}
if (selectionClient.length && !selectionClient.includes(alloc.get('node.shortId'))) {
if (
selectionClient.length &&
!selectionClient.includes(alloc.get('node.shortId'))
) {
return false;
}
@ -94,15 +103,23 @@ export default class TaskGroupController extends Controller.extend(
@computed('sortedScaleEvents.@each.hasCount', function () {
const countEventsCount = this.sortedScaleEvents.filterBy('hasCount').length;
return countEventsCount > 1 && countEventsCount >= this.sortedScaleEvents.length / 2;
return (
countEventsCount > 1 &&
countEventsCount >= this.sortedScaleEvents.length / 2
);
})
shouldShowScaleEventTimeline;
@computed('model.job.{namespace,runningDeployment}')
get tooltipText() {
if (this.can.cannot('scale job', null, { namespace: this.model.job.namespace.get('name') }))
if (
this.can.cannot('scale job', null, {
namespace: this.model.job.namespace.get('name'),
})
)
return "You aren't allowed to scale task groups";
if (this.model.job.runningDeployment) return 'You cannot scale task groups during a deployment';
if (this.model.job.runningDeployment)
return 'You cannot scale task groups during a deployment';
return undefined;
}
@ -128,12 +145,17 @@ export default class TaskGroupController extends Controller.extend(
@computed('model.allocations.[]', 'selectionClient')
get optionsClients() {
const clients = Array.from(new Set(this.model.allocations.mapBy('node.shortId'))).compact();
const clients = Array.from(
new Set(this.model.allocations.mapBy('node.shortId'))
).compact();
// Update query param when the list of clients changes.
scheduleOnce('actions', () => {
// eslint-disable-next-line ember/no-side-effects
this.set('qpClient', serialize(intersection(clients, this.selectionClient)));
this.set(
'qpClient',
serialize(intersection(clients, this.selectionClient))
);
});
return clients.sort().map((dc) => ({ key: dc, label: dc }));

View File

@ -12,14 +12,18 @@ const errorLevelToAlertClass = {
};
@classic
export default class VersionsController extends Controller.extend(WithNamespaceResetting) {
export default class VersionsController extends Controller.extend(
WithNamespaceResetting
) {
error = null;
@alias('model') job;
@computed('error.level')
get errorLevelClass() {
return errorLevelToAlertClass[this.get('error.level')] || alertClassFallback;
return (
errorLevelToAlertClass[this.get('error.level')] || alertClassFallback
);
}
onDismiss() {

View File

@ -7,7 +7,10 @@ import { inject as service } from '@ember/service';
import { scheduleOnce } from '@ember/runloop';
import { task } from 'ember-concurrency';
import intersection from 'lodash.intersection';
import { serialize, deserializedQueryParam as selection } from 'nomad-ui/utils/qp-serialize';
import {
serialize,
deserializedQueryParam as selection,
} from 'nomad-ui/utils/qp-serialize';
import EmberObject, { computed } from '@ember/object';
import { alias } from '@ember/object/computed';
@ -104,13 +107,17 @@ export default class OptimizeController extends Controller {
get optionsDatacenter() {
const flatten = (acc, val) => acc.concat(val);
const allDatacenters = new Set(this.summaries.mapBy('job.datacenters').reduce(flatten, []));
const allDatacenters = new Set(
this.summaries.mapBy('job.datacenters').reduce(flatten, [])
);
// Remove any invalid datacenters from the query param/selection
const availableDatacenters = Array.from(allDatacenters).compact();
scheduleOnce('actions', () => {
// eslint-disable-next-line ember/no-side-effects
this.qpDatacenter = serialize(intersection(availableDatacenters, this.selectionDatacenter));
this.qpDatacenter = serialize(
intersection(availableDatacenters, this.selectionDatacenter)
);
});
return availableDatacenters.sort().map((dc) => ({ key: dc, label: dc }));
@ -144,7 +151,9 @@ export default class OptimizeController extends Controller {
const availablePrefixes = prefixes.mapBy('prefix');
scheduleOnce('actions', () => {
// eslint-disable-next-line ember/no-side-effects
this.qpPrefix = serialize(intersection(availablePrefixes, this.selectionPrefix));
this.qpPrefix = serialize(
intersection(availablePrefixes, this.selectionPrefix)
);
});
// Sort, format, and include the count in the label
@ -171,7 +180,10 @@ export default class OptimizeController extends Controller {
return false;
}
if (this.qpNamespace !== '*' && job.get('namespace.name') !== this.qpNamespace) {
if (
this.qpNamespace !== '*' &&
job.get('namespace.name') !== this.qpNamespace
) {
return false;
}
@ -183,12 +195,18 @@ export default class OptimizeController extends Controller {
return false;
}
if (datacenters.length && !job.get('datacenters').find((dc) => datacenters.includes(dc))) {
if (
datacenters.length &&
!job.get('datacenters').find((dc) => datacenters.includes(dc))
) {
return false;
}
const name = job.get('name');
if (prefixes.length && !prefixes.find((prefix) => name.startsWith(prefix))) {
if (
prefixes.length &&
!prefixes.find((prefix) => name.startsWith(prefix))
) {
return false;
}
@ -207,8 +225,12 @@ export default class OptimizeController extends Controller {
// This is a task because the accordion uses timeouts for animation
// eslint-disable-next-line require-yield
@(task(function* () {
const currentSummaryIndex = this.filteredSummaries.indexOf(this.activeRecommendationSummary);
const nextSummary = this.filteredSummaries.objectAt(currentSummaryIndex + 1);
const currentSummaryIndex = this.filteredSummaries.indexOf(
this.activeRecommendationSummary
);
const nextSummary = this.filteredSummaries.objectAt(
currentSummaryIndex + 1
);
if (nextSummary) {
this.transitionToSummary(nextSummary);

View File

@ -31,13 +31,17 @@ export default class TopologyControllers extends Controller {
@computed('model.nodes.@each.resources')
get totalMemory() {
const mibs = this.model.nodes.mapBy('resources.memory').reduce(sumAggregator, 0);
const mibs = this.model.nodes
.mapBy('resources.memory')
.reduce(sumAggregator, 0);
return mibs * 1024 * 1024;
}
@computed('model.nodes.@each.resources')
get totalCPU() {
return this.model.nodes.mapBy('resources.cpu').reduce((sum, cpu) => sum + (cpu || 0), 0);
return this.model.nodes
.mapBy('resources.cpu')
.reduce((sum, cpu) => sum + (cpu || 0), 0);
}
@computed('totalMemory')
@ -70,7 +74,9 @@ export default class TopologyControllers extends Controller {
@computed('scheduledAllocations.@each.allocatedResources')
get totalReservedCPU() {
return this.scheduledAllocations.mapBy('allocatedResources.cpu').reduce(sumAggregator, 0);
return this.scheduledAllocations
.mapBy('allocatedResources.cpu')
.reduce(sumAggregator, 0);
}
@computed('totalMemory', 'totalReservedMemory')
@ -85,23 +91,35 @@ export default class TopologyControllers extends Controller {
return this.totalReservedCPU / this.totalCPU;
}
@computed('activeAllocation.taskGroupName', 'scheduledAllocations.@each.{job,taskGroupName}')
@computed(
'activeAllocation.taskGroupName',
'scheduledAllocations.@each.{job,taskGroupName}'
)
get siblingAllocations() {
if (!this.activeAllocation) return [];
const taskGroup = this.activeAllocation.taskGroupName;
const jobId = this.activeAllocation.belongsTo('job').id();
return this.scheduledAllocations.filter((allocation) => {
return allocation.taskGroupName === taskGroup && allocation.belongsTo('job').id() === jobId;
return (
allocation.taskGroupName === taskGroup &&
allocation.belongsTo('job').id() === jobId
);
});
}
@computed('activeNode')
get nodeUtilization() {
const node = this.activeNode;
const [formattedMemory, memoryUnits] = reduceBytes(node.memory * 1024 * 1024);
const totalReservedMemory = node.allocations.mapBy('memory').reduce(sumAggregator, 0);
const totalReservedCPU = node.allocations.mapBy('cpu').reduce(sumAggregator, 0);
const [formattedMemory, memoryUnits] = reduceBytes(
node.memory * 1024 * 1024
);
const totalReservedMemory = node.allocations
.mapBy('memory')
.reduce(sumAggregator, 0);
const totalReservedCPU = node.allocations
.mapBy('cpu')
.reduce(sumAggregator, 0);
return {
totalMemoryFormatted: formattedMemory.toFixed(2),

View File

@ -9,7 +9,10 @@ import { assert } from '@ember/debug';
* Returns a version of a function bound to the template target (e.g., component or controller)
*/
export function bind([func, target]) {
assert('A function is required as the first argument', typeof func === 'function');
assert(
'A function is required as the first argument',
typeof func === 'function'
);
assert('A context is required as the second argument', target);
return func.bind(target);
}

View File

@ -1,7 +1,8 @@
import Helper from '@ember/component/helper';
export function isObject([value]) {
const isObject = !Array.isArray(value) && value !== null && typeof value === 'object';
const isObject =
!Array.isArray(value) && value !== null && typeof value === 'object';
return isObject;
}

View File

@ -13,7 +13,9 @@ import SVGs from '../svgs';
*/
export function xIcon(params, options) {
const name = params[0];
const classes = [options.class, 'icon', `icon-is-${name}`].compact().join(' ');
const classes = [options.class, 'icon', `icon-is-${name}`]
.compact()
.join(' ');
return inlineSvg(SVGs, name, { class: classes });
}

View File

@ -95,7 +95,11 @@ export default Mixin.create({
if (this.exactMatchEnabled) {
results.push(
...exactMatchSearch(searchTerm, this.listToSearch, this.exactMatchSearchProps)
...exactMatchSearch(
searchTerm,
this.listToSearch,
this.exactMatchSearchProps
)
);
}
@ -114,7 +118,9 @@ export default Mixin.create({
}
if (this.regexEnabled) {
results.push(...regexSearch(searchTerm, this.listToSearch, this.regexSearchProps));
results.push(
...regexSearch(searchTerm, this.listToSearch, this.regexSearchProps)
);
}
return results.uniq();
@ -134,7 +140,9 @@ function regexSearch(term, list, keys) {
const regex = new RegExp(term, 'i');
// Test the value of each key for each object against the regex
// All that match are returned.
return list.filter((item) => keys.some((key) => regex.test(get(item, key))));
return list.filter((item) =>
keys.some((key) => regex.test(get(item, key)))
);
} catch (e) {
// Swallow the error; most likely due to an eager search of an incomplete regex
}

View File

@ -19,7 +19,9 @@ import { warn } from '@ember/debug';
- listSorted: a copy of listToSort that has been sorted
*/
export default function sortableFactory(properties, fromSortableMixin) {
const eachProperties = properties.map((property) => `listToSort.@each.${property}`);
const eachProperties = properties.map(
(property) => `listToSort.@each.${property}`
);
// eslint-disable-next-line ember/no-new-mixins
return Mixin.create({
@ -44,10 +46,13 @@ export default function sortableFactory(properties, fromSortableMixin) {
'Using SortableFactory without property keys means the list will only sort when the members change, not when any of their properties change.';
if (fromSortableMixin) {
message += ' The Sortable mixin is deprecated in favor of SortableFactory.';
message +=
' The Sortable mixin is deprecated in favor of SortableFactory.';
}
warn(message, properties.length > 0, { id: 'nomad.no-sortable-properties' });
warn(message, properties.length > 0, {
id: 'nomad.no-sortable-properties',
});
// eslint-disable-next-line ember/no-side-effects
this.set('_sortableFactoryWarningPrinted', true);
}

View File

@ -6,7 +6,10 @@ import { on } from '@ember/object/evented';
// eslint-disable-next-line ember/no-new-mixins
export default Mixin.create({
windowResizeHandler() {
assert('windowResizeHandler needs to be overridden in the Component', false);
assert(
'windowResizeHandler needs to be overridden in the Component',
false
);
},
setupWindowResize: on('didInsertElement', function () {

View File

@ -36,7 +36,10 @@ export default Mixin.create(WithVisibilityDetection, {
actions: {
willTransition(transition) {
// Don't cancel watchers if transitioning into a sub-route
if (!transition.intent.name || !transition.intent.name.startsWith(this.routeName)) {
if (
!transition.intent.name ||
!transition.intent.name.startsWith(this.routeName)
) {
this.cancelAllWatchers();
}

View File

@ -77,8 +77,10 @@ export default class Allocation extends Model {
@belongsTo('allocation', { inverse: 'nextAllocation' }) previousAllocation;
@belongsTo('allocation', { inverse: 'previousAllocation' }) nextAllocation;
@hasMany('allocation', { inverse: 'preemptedByAllocation' }) preemptedAllocations;
@belongsTo('allocation', { inverse: 'preemptedAllocations' }) preemptedByAllocation;
@hasMany('allocation', { inverse: 'preemptedByAllocation' })
preemptedAllocations;
@belongsTo('allocation', { inverse: 'preemptedAllocations' })
preemptedByAllocation;
@attr('boolean') wasPreempted;
@belongsTo('evaluation') followUpEvaluation;
@ -135,7 +137,11 @@ export default class Allocation extends Model {
return this.get('rescheduleEvents.length') > 0 || this.nextAllocation;
}
@computed('clientStatus', 'followUpEvaluation.content', 'nextAllocation.content')
@computed(
'clientStatus',
'followUpEvaluation.content',
'nextAllocation.content'
)
get hasStoppedRescheduling() {
return (
!this.get('nextAllocation.content') &&

View File

@ -24,7 +24,10 @@ export default class Deployment extends Model {
this.status === 'running' &&
this.taskGroupSummaries
.toArray()
.some((summary) => summary.get('requiresPromotion') && !summary.get('promoted'))
.some(
(summary) =>
summary.get('requiresPromotion') && !summary.get('promoted')
)
);
}
@ -38,7 +41,10 @@ export default class Deployment extends Model {
@computed('versionNumber', 'job.versions.content.@each.number')
get version() {
return (this.get('job.versions') || []).findBy('number', this.versionNumber);
return (this.get('job.versions') || []).findBy(
'number',
this.versionNumber
);
}
// Dependent keys can only go one level past an @each so an alias is needed
@ -65,7 +71,10 @@ export default class Deployment extends Model {
}
promote() {
assert('A deployment needs to requirePromotion to be promoted', this.requiresPromotion);
assert(
'A deployment needs to requirePromotion to be promoted',
this.requiresPromotion
);
return this.store.adapterFor('deployment').promote(this);
}

View File

@ -11,7 +11,8 @@ export default class Evaluation extends Model {
@attr('string') triggeredBy;
@attr('string') status;
@attr('string') statusDescription;
@fragmentArray('placement-failure', { defaultValue: () => [] }) failedTGAllocs;
@fragmentArray('placement-failure', { defaultValue: () => [] })
failedTGAllocs;
@bool('failedTGAllocs.length') hasPlacementFailures;
@equal('status', 'blocked') isBlocked;

View File

@ -5,6 +5,7 @@ import { hasMany } from '@ember-data/model';
export default class JobPlan extends Model {
@attr() diff;
@fragmentArray('placement-failure', { defaultValue: () => [] }) failedTGAllocs;
@fragmentArray('placement-failure', { defaultValue: () => [] })
failedTGAllocs;
@hasMany('allocation') preemptions;
}

View File

@ -51,7 +51,9 @@ export default class Job extends Model {
// The parent job name is prepended to child launch job names
@computed('name', 'parent.content')
get trimmedName() {
return this.get('parent.content') ? this.name.replace(/.+?\//, '') : this.name;
return this.get('parent.content')
? this.name.replace(/.+?\//, '')
: this.name;
}
// A composite of type and other job attributes to determine
@ -69,7 +71,12 @@ export default class Job extends Model {
// A composite of type and other job attributes to determine
// type for templating rather than scheduling
@computed('type', 'periodic', 'parameterized', 'parent.{periodic,parameterized}')
@computed(
'type',
'periodic',
'parameterized',
'parent.{periodic,parameterized}'
)
get templateType() {
const type = this.type;
@ -158,7 +165,9 @@ export default class Job extends Model {
@computed('evaluations.@each.isBlocked')
get hasBlockedEvaluation() {
return this.evaluations.toArray().some((evaluation) => evaluation.get('isBlocked'));
return this.evaluations
.toArray()
.some((evaluation) => evaluation.get('isBlocked'));
}
@and('latestFailureEvaluation', 'hasBlockedEvaluation') hasPlacementFailures;
@ -256,7 +265,8 @@ export default class Job extends Model {
}
scale(group, count, message) {
if (message == null) message = `Manually scaled to ${count} from the Nomad UI`;
if (message == null)
message = `Manually scaled to ${count} from the Nomad UI`;
return this.store.adapterFor('job').scale(this, group, count, message);
}
@ -278,7 +288,10 @@ export default class Job extends Model {
}
resetId() {
this.set('id', JSON.stringify([this.plainId, this.get('namespace.name') || 'default']));
this.set(
'id',
JSON.stringify([this.plainId, this.get('namespace.name') || 'default'])
);
}
@computed('status')

View File

@ -63,7 +63,9 @@ export default class Node extends Model {
@computed('allocations.@each.{isMigrating,isRunning}')
get migratingAllocations() {
return this.allocations.filter((alloc) => alloc.isRunning && alloc.isMigrating);
return this.allocations.filter(
(alloc) => alloc.isRunning && alloc.isMigrating
);
}
@computed('allocations.@each.{isMigrating,isRunning,modifyTime}')

View File

@ -5,7 +5,8 @@ import { action } from '@ember/object';
export default class RecommendationSummary extends Model {
@hasMany('recommendation') recommendations;
@hasMany('recommendation', { defaultValue: () => [] }) excludedRecommendations;
@hasMany('recommendation', { defaultValue: () => [] })
excludedRecommendations;
@belongsTo('job') job;
@attr('string') jobId;
@ -30,7 +31,8 @@ export default class RecommendationSummary extends Model {
@action
toggleRecommendation(recommendation) {
if (this.excludedRecommendations.includes(recommendation)) {
this.excludedRecommendations = this.excludedRecommendations.removeObject(recommendation);
this.excludedRecommendations =
this.excludedRecommendations.removeObject(recommendation);
} else {
this.excludedRecommendations.pushObject(recommendation);
}
@ -39,9 +41,14 @@ export default class RecommendationSummary extends Model {
@action
toggleAllRecommendationsForResource(resource, enabled) {
if (enabled) {
this.excludedRecommendations = this.excludedRecommendations.rejectBy('resource', resource);
this.excludedRecommendations = this.excludedRecommendations.rejectBy(
'resource',
resource
);
} else {
this.excludedRecommendations.pushObjects(this.recommendations.filterBy('resource', resource));
this.excludedRecommendations.pushObjects(
this.recommendations.filterBy('resource', resource)
);
}
}

View File

@ -4,7 +4,8 @@ import { get } from '@ember/object';
export default class Recommendation extends Model {
@belongsTo('job') job;
@belongsTo('recommendation-summary', { inverse: 'recommendations' }) recommendationSummary;
@belongsTo('recommendation-summary', { inverse: 'recommendations' })
recommendationSummary;
@attr('date') submitTime;
@ -22,7 +23,8 @@ export default class Recommendation extends Model {
@attr('number') value;
get currentValue() {
const resourceProperty = this.resource === 'CPU' ? 'reservedCPU' : 'reservedMemory';
const resourceProperty =
this.resource === 'CPU' ? 'reservedCPU' : 'reservedMemory';
return get(this, `task.${resourceProperty}`);
}

View File

@ -1,7 +1,10 @@
import { computed } from '@ember/object';
import Fragment from 'ember-data-model-fragments/fragment';
import { attr } from '@ember-data/model';
import { fragmentOwner, fragmentArray } from 'ember-data-model-fragments/attributes';
import {
fragmentOwner,
fragmentArray,
} from 'ember-data-model-fragments/attributes';
export default class TaskGroupScale extends Fragment {
@fragmentOwner() jobScale;

View File

@ -1,7 +1,11 @@
import { computed } from '@ember/object';
import Fragment from 'ember-data-model-fragments/fragment';
import { attr } from '@ember-data/model';
import { fragmentOwner, fragmentArray, fragment } 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';
@ -39,7 +43,10 @@ export default class TaskGroup extends Fragment {
@computed('job.allocations.@each.taskGroup', 'name')
get allocations() {
return maybe(this.get('job.allocations')).filterBy('taskGroupName', this.name);
return maybe(this.get('job.allocations')).filterBy(
'taskGroupName',
this.name
);
}
@sumAggregation('tasks', 'reservedCPU') reservedCPU;
@ -57,13 +64,17 @@ export default class TaskGroup extends Fragment {
@computed('job.latestFailureEvaluation.failedTGAllocs.[]', 'name')
get placementFailures() {
const placementFailures = this.get('job.latestFailureEvaluation.failedTGAllocs');
const placementFailures = this.get(
'job.latestFailureEvaluation.failedTGAllocs'
);
return placementFailures && placementFailures.findBy('name', this.name);
}
@computed('summary.{queuedAllocs,startingAllocs}')
get queuedOrStartingAllocs() {
return this.get('summary.queuedAllocs') + this.get('summary.startingAllocs');
return (
this.get('summary.queuedAllocs') + this.get('summary.startingAllocs')
);
}
@computed('job.taskGroupSummaries.[]', 'name')
@ -73,7 +84,10 @@ export default class TaskGroup extends Fragment {
@computed('job.scaleState.taskGroupScales.[]', 'name')
get scaleState() {
return maybe(this.get('job.scaleState.taskGroupScales')).findBy('name', this.name);
return maybe(this.get('job.scaleState.taskGroupScales')).findBy(
'name',
this.name
);
}
scale(count, message) {

View File

@ -2,7 +2,11 @@ import { computed } from '@ember/object';
import { alias, none, and } from '@ember/object/computed';
import Fragment from 'ember-data-model-fragments/fragment';
import { attr } from '@ember-data/model';
import { fragment, fragmentOwner, fragmentArray } from 'ember-data-model-fragments/attributes';
import {
fragment,
fragmentOwner,
fragmentArray,
} from 'ember-data-model-fragments/attributes';
import classic from 'ember-classic-decorator';
@classic

View File

@ -1,6 +1,10 @@
import { attr } from '@ember-data/model';
import Fragment from 'ember-data-model-fragments/fragment';
import { fragment, fragmentArray, fragmentOwner } from 'ember-data-model-fragments/attributes';
import {
fragment,
fragmentArray,
fragmentOwner,
} from 'ember-data-model-fragments/attributes';
import { computed } from '@ember/object';
export default class Task extends Fragment {

View File

@ -14,7 +14,10 @@ export default class Volume extends Model {
@computed('writeAllocations.[]', 'readAllocations.[]')
get allocations() {
return [...this.writeAllocations.toArray(), ...this.readAllocations.toArray()];
return [
...this.writeAllocations.toArray(),
...this.readAllocations.toArray(),
];
}
@attr('number') currentWriters;

View File

@ -15,7 +15,9 @@ export default class FsRoute extends Route {
return RSVP.hash({
path: decodedPath,
allocation,
directoryEntries: allocation.ls(decodedPath).catch(notifyError(this)),
directoryEntries: allocation
.ls(decodedPath)
.catch(notifyError(this)),
isFile: false,
});
} else {
@ -30,8 +32,17 @@ export default class FsRoute extends Route {
.catch(notifyError(this));
}
setupController(controller, { path, allocation, directoryEntries, isFile, stat } = {}) {
setupController(
controller,
{ path, allocation, directoryEntries, isFile, stat } = {}
) {
super.setupController(...arguments);
controller.setProperties({ path, allocation, directoryEntries, isFile, stat });
controller.setProperties({
path,
allocation,
directoryEntries,
isFile,
stat,
});
}
}

View File

@ -4,7 +4,8 @@ export default class IndexRoute extends Route {
setupController(controller, model) {
// Suppress the preemptedByAllocation fetch error in the event it's a 404
if (model) {
const setPreempter = () => controller.set('preempter', model.preemptedByAllocation);
const setPreempter = () =>
controller.set('preempter', model.preemptedByAllocation);
model.preemptedByAllocation.then(setPreempter, setPreempter);
}

View File

@ -16,7 +16,9 @@ export default class TaskRoute extends Route {
const task = allocation.get('states').findBy('name', name);
if (!task) {
const err = new EmberError(`Task ${name} not found for allocation ${allocation.get('id')}`);
const err = new EmberError(
`Task ${name} not found for allocation ${allocation.get('id')}`
);
err.code = '404';
this.controllerFor('application').set('error', err);
}

View File

@ -14,13 +14,18 @@ export default class FsRoute extends Route {
decodedPath.startsWith('/') ? '' : '/'
}${decodedPath}`;
return RSVP.all([allocation.stat(pathWithTaskName), taskState.get('allocation.node')])
return RSVP.all([
allocation.stat(pathWithTaskName),
taskState.get('allocation.node'),
])
.then(([statJson]) => {
if (statJson.IsDir) {
return RSVP.hash({
path: decodedPath,
taskState,
directoryEntries: allocation.ls(pathWithTaskName).catch(notifyError(this)),
directoryEntries: allocation
.ls(pathWithTaskName)
.catch(notifyError(this)),
isFile: false,
});
} else {
@ -35,8 +40,17 @@ export default class FsRoute extends Route {
.catch(notifyError(this));
}
setupController(controller, { path, taskState, directoryEntries, isFile, stat } = {}) {
setupController(
controller,
{ path, taskState, directoryEntries, isFile, stat } = {}
) {
super.setupController(...arguments);
controller.setProperties({ path, taskState, directoryEntries, isFile, stat });
controller.setProperties({
path,
taskState,
directoryEntries,
isFile,
stat,
});
}
}

View File

@ -50,13 +50,17 @@ export default class ApplicationRoute extends Route {
this.controllerFor('application').set('error', e);
}
const fetchSelfTokenAndPolicies = this.get('token.fetchSelfTokenAndPolicies')
const fetchSelfTokenAndPolicies = this.get(
'token.fetchSelfTokenAndPolicies'
)
.perform()
.catch();
const fetchLicense = this.get('system.fetchLicense').perform().catch();
const checkFuzzySearchPresence = this.get('system.checkFuzzySearchPresence')
const checkFuzzySearchPresence = this.get(
'system.checkFuzzySearchPresence'
)
.perform()
.catch();

View File

@ -1,7 +1,10 @@
import { inject as service } from '@ember/service';
import Route from '@ember/routing/route';
import { collect } from '@ember/object/computed';
import { watchRecord, watchRelationship } from 'nomad-ui/utils/properties/watch';
import {
watchRecord,
watchRelationship,
} from 'nomad-ui/utils/properties/watch';
import WithWatchers from 'nomad-ui/mixins/with-watchers';
export default class ClientRoute extends Route.extend(WithWatchers) {

View File

@ -7,6 +7,8 @@ export default class PluginsRoute extends Route.extend(WithForbiddenState) {
@service store;
model() {
return this.store.query('plugin', { type: 'csi' }).catch(notifyForbidden(this));
return this.store
.query('plugin', { type: 'csi' })
.catch(notifyForbidden(this));
}
}

View File

@ -11,6 +11,8 @@ export default class PluginRoute extends Route {
}
model(params) {
return this.store.findRecord('plugin', `csi/${params.plugin_name}`).catch(notifyError(this));
return this.store
.findRecord('plugin', `csi/${params.plugin_name}`)
.catch(notifyError(this));
}
}

View File

@ -7,7 +7,10 @@ import WithWatchers from 'nomad-ui/mixins/with-watchers';
import notifyForbidden from 'nomad-ui/utils/notify-forbidden';
import WithForbiddenState from 'nomad-ui/mixins/with-forbidden-state';
export default class IndexRoute extends Route.extend(WithWatchers, WithForbiddenState) {
export default class IndexRoute extends Route.extend(
WithWatchers,
WithForbiddenState
) {
@service store;
queryParams = {
@ -29,7 +32,10 @@ export default class IndexRoute extends Route.extend(WithWatchers, WithForbidden
controller.set('namespacesWatch', this.watchNamespaces.perform());
controller.set(
'modelWatch',
this.watchVolumes.perform({ type: 'csi', namespace: controller.qpNamespace })
this.watchVolumes.perform({
type: 'csi',
namespace: controller.qpNamespace,
})
);
}

Some files were not shown because too many files have changed in this diff Show More