mirror of https://github.com/rancher/dashboard.git
353 lines
7.9 KiB
JavaScript
353 lines
7.9 KiB
JavaScript
import day from 'dayjs';
|
|
import { insertAt } from '@/utils/array';
|
|
import { ADD_SIDECAR, _FLAGGED, MODE, _STAGE } from '@/config/query-params';
|
|
import { escapeHtml } from '@/utils/string';
|
|
import { DATE_FORMAT, TIME_FORMAT } from '@/store/prefs';
|
|
import { addParams } from '@/utils/url';
|
|
import { PRIVATE } from '@/plugins/norman/resource-proxy';
|
|
|
|
const EMPTY = {};
|
|
|
|
export default {
|
|
app() {
|
|
const spec = this.spec || EMPTY;
|
|
const status = this.status || EMPTY;
|
|
const metadata = this.metadata || EMPTY;
|
|
|
|
return spec.app || status.computedApp || metadata.name;
|
|
},
|
|
|
|
version() {
|
|
const spec = this.spec || EMPTY;
|
|
const status = this.status || EMPTY;
|
|
const uid = ((this.metadata || EMPTY)['uid'] || '').replace(/-.*$/, '');
|
|
|
|
return spec.version || status.computedVersion || uid || '?';
|
|
},
|
|
|
|
nameDisplay() {
|
|
const version = this.version;
|
|
|
|
if ( version === 'v0' ) {
|
|
return this.app;
|
|
}
|
|
|
|
return `${ this.app }@${ this.version }`;
|
|
},
|
|
|
|
namespaceNameDisplay() {
|
|
const namespace = this.metadata.namespace;
|
|
const name = this.metadata.name || this.id;
|
|
|
|
return `${ namespace }:${ name }`;
|
|
},
|
|
|
|
namespaceApp() {
|
|
return `${ this.metadata.namespace }:${ this.app }`;
|
|
},
|
|
|
|
imageDisplay() {
|
|
if ( this.spec.build && !this.spec.image ) {
|
|
return 'Building from Git...';
|
|
}
|
|
|
|
return (this.spec.image || '')
|
|
.replace(/^(index\.)?docker.io\/(library\/)?/i, '')
|
|
.replace(/@sha256:[0-9a-f]+$/i, '')
|
|
.replace(/:latest$/i, '')
|
|
.replace(/localhost:5442\/(.*)/i, '$1 (local)');
|
|
},
|
|
|
|
createdDisplay() {
|
|
const dateFormat = escapeHtml( this.$rootGetters['prefs/get'](DATE_FORMAT));
|
|
const timeFormat = escapeHtml( this.$rootGetters['prefs/get'](TIME_FORMAT));
|
|
|
|
return day(this.metadata.creationTimestamp).format(`${ dateFormat } ${ timeFormat }`);
|
|
},
|
|
|
|
versionWithDateDisplay() {
|
|
return `${ this.version } (${ this.createdDisplay })`;
|
|
},
|
|
|
|
scales() {
|
|
const status = this.status || {};
|
|
const scaleStatus = status.scaleStatus || {};
|
|
const auto = !!this.spec.autoscale;
|
|
const fixed = (typeof this.spec.replicas === 'undefined' ? 1 : this.spec.replicas || 0);
|
|
const available = scaleStatus.available || 0;
|
|
const current = (typeof status.computedReplicas === 'undefined' ? available : status.computedReplicas || 0);
|
|
const unavailable = scaleStatus.unavailable || 0;
|
|
const global = this.spec.global === true;
|
|
|
|
let desired = fixed;
|
|
let min, max;
|
|
|
|
if ( auto ) {
|
|
min = this.spec.autoscale.minReplicas;
|
|
max = this.spec.autoscale.maxReplicas;
|
|
desired = `${ min } - ${ max }`;
|
|
}
|
|
|
|
if ( global ) {
|
|
desired = current;
|
|
} else if ( typeof this[PRIVATE].pendingScale === 'number' ) {
|
|
desired = this[PRIVATE].pendingScale;
|
|
}
|
|
|
|
const missing = Math.max(0, desired - available - unavailable);
|
|
|
|
return {
|
|
global,
|
|
auto,
|
|
min,
|
|
max,
|
|
current,
|
|
desired,
|
|
available,
|
|
unavailable,
|
|
starting: missing > 0 ? missing : 0,
|
|
stopping: missing < 0 ? -1 * missing : 0,
|
|
};
|
|
},
|
|
|
|
showDesiredScale() {
|
|
const scales = this.scales;
|
|
|
|
return !scales.global && scales.current !== scales.desired;
|
|
},
|
|
|
|
complexScale() {
|
|
const { stopping, starting, unavailable } = this.scales;
|
|
|
|
return stopping !== 0 || starting !== 0 || unavailable !== 0;
|
|
},
|
|
|
|
scaleParts() {
|
|
const {
|
|
available, unavailable, starting, stopping
|
|
} = this.scales;
|
|
const out = [
|
|
{
|
|
label: 'Available',
|
|
color: 'bg-success',
|
|
textColor: 'text-success',
|
|
value: available
|
|
},
|
|
|
|
{
|
|
label: 'Unavailable',
|
|
color: 'bg-error',
|
|
textColor: 'text-error',
|
|
value: unavailable
|
|
},
|
|
];
|
|
|
|
if ( starting ) {
|
|
out.push({
|
|
label: 'Starting',
|
|
color: 'bg-info',
|
|
textColor: 'text-info',
|
|
value: starting
|
|
});
|
|
}
|
|
|
|
if ( stopping ) {
|
|
out.push({
|
|
label: 'Stopping',
|
|
color: 'bg-warning',
|
|
textColor: 'text-warning',
|
|
value: stopping
|
|
});
|
|
}
|
|
|
|
return out;
|
|
},
|
|
|
|
scaleUp() {
|
|
return () => {
|
|
let scale;
|
|
|
|
if ( this.scales.global ) {
|
|
return;
|
|
}
|
|
|
|
if ( this[PRIVATE].scaleTimer ) {
|
|
scale = this[PRIVATE].pendingScale;
|
|
} else {
|
|
scale = this.scales.desired;
|
|
}
|
|
|
|
scale = scale || 0;
|
|
|
|
this[PRIVATE].pendingScale = scale + 1;
|
|
this.saveScale();
|
|
};
|
|
},
|
|
|
|
scaleDown() {
|
|
return () => {
|
|
let scale;
|
|
|
|
if ( this.scales.global ) {
|
|
return;
|
|
}
|
|
|
|
if ( this[PRIVATE].scaleTimer ) {
|
|
scale = this[PRIVATE].pendingScale;
|
|
} else {
|
|
scale = this.scales.desired;
|
|
}
|
|
|
|
scale = scale || 1;
|
|
|
|
this[PRIVATE].pendingScale = Math.max(scale - 1, 0);
|
|
this.saveScale();
|
|
};
|
|
},
|
|
|
|
saveScale() {
|
|
return () => {
|
|
if ( this[PRIVATE].scaleTimer ) {
|
|
clearTimeout(this[PRIVATE].scaleTimer);
|
|
}
|
|
|
|
this[PRIVATE].scaleTimer = setTimeout(async() => {
|
|
try {
|
|
await this.patch([{
|
|
op: 'replace',
|
|
path: '/spec/replicas',
|
|
value: this[PRIVATE].pendingScale
|
|
}]);
|
|
} catch (err) {
|
|
this.$dispatch('growl/fromError', { title: 'Error updating scale', err }, { root: true });
|
|
}
|
|
|
|
this[PRIVATE].scaleTimer = null;
|
|
this[PRIVATE].pendingScale = null;
|
|
}, 500);
|
|
};
|
|
},
|
|
|
|
saveWeight() {
|
|
return async(neu) => {
|
|
try {
|
|
await this.patch([{
|
|
op: 'replace',
|
|
path: '/spec/weight',
|
|
value: neu
|
|
}]);
|
|
} catch (err) {
|
|
this.$dispatch('growl/fromError', { title: 'Error updating weight', err }, { root: true });
|
|
}
|
|
};
|
|
},
|
|
|
|
weights() {
|
|
let current = 0;
|
|
let desired = 0;
|
|
const spec = this.spec.weight;
|
|
|
|
if ( !this.status ) {
|
|
return { current, desired };
|
|
}
|
|
|
|
const status = this.status.computedWeight;
|
|
|
|
if ( typeof status === 'number' ) {
|
|
current = status;
|
|
} else if ( typeof spec === 'number' ) {
|
|
current = spec;
|
|
}
|
|
|
|
if ( typeof spec === 'number' ) {
|
|
desired = spec;
|
|
} else if ( typeof status === 'number' ) {
|
|
desired = status;
|
|
}
|
|
|
|
return { current, desired };
|
|
},
|
|
|
|
async pauseOrResume(pause = true) {
|
|
try {
|
|
await this.patch({
|
|
op: 'replace',
|
|
path: '/spec/rollout/pause',
|
|
value: pause
|
|
});
|
|
} catch (err) {
|
|
this.$dispatch('growl/fromError', { title: 'Error updating pause', err }, { root: true });
|
|
}
|
|
},
|
|
|
|
pause() {
|
|
return this.pauseOrResume(true);
|
|
},
|
|
|
|
resume() {
|
|
return this.pauseOrResume(false);
|
|
},
|
|
|
|
goToStage() {
|
|
const router = this.currentRouter();
|
|
|
|
return (moreQuery = {}) => {
|
|
const url = addParams(this.detailUrl, {
|
|
[MODE]: _STAGE,
|
|
...moreQuery
|
|
});
|
|
|
|
router.push({ path: url });
|
|
};
|
|
},
|
|
|
|
_availableActions() {
|
|
const links = this.links || {};
|
|
const out = this._standardActions;
|
|
|
|
let isPaused = false;
|
|
|
|
if ( this.spec.rollout && this.spec.rollout.pause ) {
|
|
isPaused = true;
|
|
}
|
|
|
|
insertAt(out, 2, {
|
|
action: 'pause',
|
|
label: 'Pause Rollout',
|
|
icon: 'icon icon-gear',
|
|
enabled: !!links.update && !isPaused,
|
|
});
|
|
|
|
insertAt(out, 2, {
|
|
action: 'resume',
|
|
label: 'Resume Rollout',
|
|
icon: 'icon icon-gear',
|
|
enabled: !!links.update && isPaused,
|
|
});
|
|
|
|
insertAt(out, 2, {
|
|
action: 'addSidecar',
|
|
label: 'Add a Sidecar',
|
|
icon: 'icon icon-circle-plus',
|
|
enabled: !!links.update,
|
|
});
|
|
|
|
insertAt(out, 2, {
|
|
action: 'goToStage',
|
|
label: 'Stage New Version',
|
|
icon: 'icon icon-copy',
|
|
enabled: !!links.update,
|
|
});
|
|
|
|
insertAt(out, 2, { divider: true });
|
|
|
|
return out;
|
|
},
|
|
|
|
addSidecar() {
|
|
return () => {
|
|
return this.goToEdit({ [ADD_SIDECAR]: _FLAGGED });
|
|
};
|
|
},
|
|
};
|