kui-shell
Version:
This is the monorepo for Kui, the hybrid command-line/GUI electron-based Kubernetes tool
292 lines • 11.5 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const strip_ansi_1 = require("strip-ansi");
const table_1 = require("../models/table");
const pretty_print_1 = require("./pretty-print");
const i18n_1 = require("../../util/i18n");
const strings = i18n_1.default('core');
const isAnsi = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-PRZcf-nqry=><]/;
function indexOf(haystack, needle, startIdx) {
const idx = haystack.indexOf(needle, startIdx);
if (idx !== -1) {
return { startIdx, endIdx: idx + needle.length };
}
let hidx = startIdx;
let nidx = 0;
while (hidx < haystack.length && nidx < needle.length) {
const h = haystack.charAt(hidx);
const n = needle.charAt(nidx);
if (h === '\x1b') {
do {
hidx++;
} while (hidx < haystack.length && !(haystack.charAt(hidx) === 'm'));
hidx++;
}
else if (nidx > 0 && isAnsi.test(h)) {
hidx++;
}
else if (h !== n) {
hidx++;
nidx = 0;
}
else {
hidx++;
nidx++;
}
}
if (nidx === needle.length) {
return { startIdx, endIdx: hidx };
}
else {
return { startIdx, endIdx: startIdx + needle.length };
}
}
function maybeURL(str) {
try {
const url = new URL(str);
if (url.host) {
const link = document.createElement('a');
link.target = '_blank';
link.innerText = strings('link');
link.title = str;
link.href = str;
return link;
}
}
catch (err) {
}
}
const split = (str, splits, headerCells) => __awaiter(void 0, void 0, void 0, function* () {
const stripped = strip_ansi_1.default(str);
let lastEnd = 0;
return Promise.all(splits.map((splitIndex, idx) => __awaiter(void 0, void 0, void 0, function* () {
const plain = stripped.substring(splitIndex, splits[idx + 1] || stripped.length).trim();
const { startIdx, endIdx } = indexOf(str, plain, lastEnd);
const value = str.slice(startIdx, endIdx).trim();
const valueDom = maybeURL(plain) || (yield pretty_print_1.default([value], false));
lastEnd = endIdx;
return {
key: headerCells && headerCells[idx],
value: plain,
valueDom,
css: ''
};
})));
});
exports.preprocessTable = (raw) => __awaiter(void 0, void 0, void 0, function* () {
return Promise.all(raw.map((table) => __awaiter(void 0, void 0, void 0, function* () {
const firstNewlineIdx = table.indexOf('\n');
let header = strip_ansi_1.default(table.substring(0, firstNewlineIdx).replace(/\t/g, ' '));
if (header.trim().length === 0) {
table = table.slice(firstNewlineIdx + 1);
const secondNewlineIdx = table.indexOf('\n');
header = strip_ansi_1.default(table.substring(0, secondNewlineIdx).replace(/\t/g, ' '));
}
const headerCells = yield header
.split(/(\t|\s\s)+\s?/)
.filter(x => x && !x.match(/(\t|\s\s)/))
.map(_ => _.trim());
const columnStarts = [];
for (let idx = 0, jdx = 0; idx < headerCells.length; idx++) {
const { offset, prefix } = idx === 0 ? { offset: 0, prefix: '' } : { offset: 1, prefix: ' ' };
const newJdx = header.indexOf(prefix + headerCells[idx] + ' ', jdx);
if (newJdx < 0) {
jdx = header.indexOf(' ' + headerCells[idx], jdx);
}
else {
jdx = newJdx;
}
columnStarts.push(jdx + offset);
jdx = newJdx + headerCells[idx].length;
}
const tinyColumns = columnStarts.reduce((yup, start, idx) => {
return yup && (idx > 0 && start - columnStarts[idx - 1] <= 2);
}, true);
if (columnStarts.length <= 1 || tinyColumns) {
return {
trailingString: table
};
}
else {
const possibleRows = table.split(/\n/);
const endOfTable = possibleRows.map(strip_ansi_1.default).findIndex(row => {
const nope = columnStarts.findIndex(idx => {
return idx > 0 && !/\s/.test(row[idx - 1]);
});
return nope !== -1;
});
const rows = endOfTable === -1 ? possibleRows : possibleRows.slice(0, endOfTable);
const preprocessed = (yield Promise.all(rows.map(line => {
return split(line, columnStarts, headerCells);
}))).filter(x => x);
const trailingString = endOfTable !== -1 && possibleRows.slice(endOfTable).join('\n');
return {
trailingString,
rows: preprocessed
};
}
})));
});
const capitalize = (str) => {
return str.length === 0 ? str : str[0].toUpperCase() + str.slice(1).toLowerCase();
};
exports.outerCSSForKey = {
NAME: 'entity-name-group',
READY: 'a-few-numbers-wide',
KIND: 'max-width-id-like entity-kind',
NAMESPACE: 'entity-name-group entity-name-group-narrow',
DISPLAY: 'hide-with-sidecar',
TYPE: 'hide-with-sidecar',
ENDPOINT: 'hide-with-sidecar',
CLUSTER: 'entity-name-group entity-name-group-narrow hide-with-sidecar',
AUTHINFO: 'entity-name-group entity-name-group-narrow hide-with-sidecar',
REFERENCE: 'entity-name-group entity-name-group-narrow hide-with-sidecar',
CREATED: 'hide-with-sidecar',
'CREATED AT': 'hide-with-sidecar',
ID: 'max-width-id-like',
CURRENT: 'entity-name-group entity-name-group-extra-narrow text-center',
DESIRED: 'entity-name-group entity-name-group-extra-narrow text-center',
RESTARTS: 'very-narrow',
'LAST SEEN': 'hide-with-sidecar entity-name-group-extra-narrow',
'FIRST SEEN': 'hide-with-sidecar entity-name-group-extra-narrow',
UPDATED: 'min-width-date-like',
REVISION: 'hide-with-sidecar',
AGE: 'hide-with-sidecar very-narrow',
'PORT(S)': 'entity-name-group entity-name-group-narrow hide-with-sidecar',
SUBOBJECT: 'entity-name-group entity-name-group-extra-narrow'
};
const fillTo = (length, maxColumns) => {
if (length >= maxColumns) {
return [];
}
else {
return new Array(maxColumns - length).fill('');
}
};
exports.cssForKey = {
NAME: 'entity-name',
SOURCE: 'lighter-text smaller-text',
SUBOBJECT: 'lighter-text smaller-text',
'CREATED AT': 'lighter-text smaller-text',
AGE: 'slightly-deemphasize',
'APP VERSION': 'pre-wrap slightly-deemphasize',
UPDATED: 'slightly-deemphasize somewhat-smaller-text'
};
const tagForKey = {
PHASE: 'badge',
STATE: 'badge',
STATUS: 'badge'
};
exports.cssForValue = {
NORMAL: 'green-background',
Normal: 'green-background',
normal: 'green-background',
UNKNOWN: '',
DEPLOYED: 'green-background',
DELETED: '',
SUPERSEDED: 'yellow-background',
FAILED: 'red-background',
DELETING: 'yellow-background',
'Init:0/1': 'yellow-background',
PodScheduled: 'yellow-background',
PodInitializing: 'yellow-background',
Initialized: 'yellow-background',
Terminating: 'yellow-background',
CrashLoopBackOff: 'red-background',
Error: 'red-background',
Failed: 'red-background',
Running: 'green-background',
Pending: 'yellow-background',
Completed: 'gray-background',
Unknown: '',
Ready: 'green-background',
ProvisionedSuccessfully: 'green-background',
Active: 'green-background',
Online: 'green-background',
NodeReady: 'green-background',
Pulled: 'green-background',
Rebooted: 'green-background',
Started: 'green-background',
Created: 'green-background',
Succeeded: 'green-background',
SuccessfulCreate: 'green-background',
SuccessfulMountVol: 'green-background',
ContainerCreating: 'yellow-background',
Starting: 'yellow-background',
NodeNotReady: 'yellow-background',
Killing: 'yellow-background',
Deleting: 'yellow-background',
Pulling: 'yellow-background',
BackOff: 'yellow-background',
FailedScheduling: 'red-background',
FailedKillPod: 'red-background'
};
exports.formatTable = (entityType, lines) => {
const nameColumnIdx = Math.max(0, lines[0].findIndex(({ key }) => key === 'NAME'));
const maxColumns = lines.reduce((max, columns) => Math.max(max, columns.length), 0);
const keyForFirstColumn = lines[0][nameColumnIdx].key.replace(/:/g, '').toUpperCase();
const allRows = lines.map((columns, idx) => {
const nameForDisplay = columns[0].value;
const firstColumnCSS = idx === 0 || columns[0].key !== 'CURRENT' ? '' : 'selected-entity';
const rowIsSelected = columns[0].key === 'CURRENT' && nameForDisplay === '*';
const rowCSS = [rowIsSelected ? 'selected-row' : ''];
const attributes = columns
.slice(1)
.map(({ key, value: column, valueDom, css }) => ({
key,
value: idx > 0 && /STATUS|STATE/i.test(key) ? capitalize(column) : column,
valueDom,
css
}))
.map(({ key, value: column, valueDom, css }, colIdx) => ({
key,
tag: (idx > 0 && tagForKey[key]) || undefined,
onclick: false,
outerCSS: (exports.outerCSSForKey[key] || '') +
(colIdx <= 1 || colIdx === nameColumnIdx - 1 || /STATUS/i.test(key) ? '' : ' hide-with-sidecar'),
css: css +
(column.length > 20 ? ' pretty-wide' : '') +
' ' +
((idx > 0 && exports.cssForKey[key]) || '') +
' ' +
(exports.cssForValue[column] || ''),
valueDom,
value: column
}))
.concat(fillTo(columns.length, maxColumns));
const row = {
key: keyForFirstColumn,
name: nameForDisplay,
nameDom: columns[0].valueDom,
fontawesome: idx !== 0 && columns[0].key === 'CURRENT' && 'fas fa-network-wired',
onclick: false,
css: firstColumnCSS,
rowCSS,
outerCSS: exports.outerCSSForKey[columns[0].key] || '',
attributes
};
return row;
});
const hasHeader = !/[:/]/.test(allRows[0].name);
const header = hasHeader ? allRows[0] : undefined;
const body = hasHeader ? allRows.slice(1) : allRows;
const style = !header ? table_1.TableStyle.Light : table_1.TableStyle.Medium;
const model = {
title: entityType,
header,
body,
style,
noSort: true
};
return model;
};
//# sourceMappingURL=ascii-to-table.js.map