in web-console/src/views/services-view/services-view.tsx [387:698]
renderServicesTable() {
const { capabilities, filters, onFiltersChange } = this.props;
const { servicesState, groupServicesBy, visibleColumns } = this.state;
const fillIndicator = (value: number) => {
let formattedValue = (value * 100).toFixed(1);
if (formattedValue === '0.0' && value > 0) formattedValue = '~' + formattedValue;
return (
<div className="fill-indicator">
<div className="bar" style={{ width: `${value * 100}%` }} />
<div className="label">{formattedValue + '%'}</div>
</div>
);
};
const services = servicesState.data || [];
return (
<ReactTable
data={services}
loading={servicesState.loading}
noDataText={
servicesState.isEmpty() ? 'No historicals' : servicesState.getErrorMessage() || ''
}
filterable
filtered={filters}
onFilteredChange={onFiltersChange}
pivotBy={groupServicesBy ? [groupServicesBy] : []}
defaultPageSize={STANDARD_TABLE_PAGE_SIZE}
pageSizeOptions={STANDARD_TABLE_PAGE_SIZE_OPTIONS}
showPagination={services.length > STANDARD_TABLE_PAGE_SIZE}
columns={[
{
Header: 'Service',
show: visibleColumns.shown('Service'),
accessor: 'service',
width: 300,
Cell: this.renderFilterableCell('service'),
Aggregated: () => '',
},
{
Header: 'Type',
show: visibleColumns.shown('Type'),
Filter: suggestibleFilterInput([
'coordinator',
'overlord',
'router',
'broker',
'historical',
'indexer',
'middle_manager',
'peon',
]),
accessor: 'service_type',
width: 150,
Cell: this.renderFilterableCell('service_type'),
},
{
Header: 'Tier',
show: visibleColumns.shown('Tier'),
id: 'tier',
width: 180,
accessor: row => {
if (row.tier) return row.tier;
return deepGet(row, 'workerInfo.worker.category');
},
Cell: this.renderFilterableCell('tier'),
},
{
Header: 'Host',
show: visibleColumns.shown('Host'),
accessor: 'host',
width: 200,
Cell: this.renderFilterableCell('host'),
Aggregated: () => '',
},
{
Header: 'Port',
show: visibleColumns.shown('Port'),
id: 'port',
width: 100,
accessor: row => {
const ports: string[] = [];
if (row.plaintext_port !== -1) {
ports.push(`${row.plaintext_port} (plain)`);
}
if (row.tls_port !== -1) {
ports.push(`${row.tls_port} (TLS)`);
}
return ports.join(', ') || 'No port';
},
Cell: this.renderFilterableCell('port'),
Aggregated: () => '',
},
{
Header: 'Current size',
show: visibleColumns.shown('Current size'),
id: 'curr_size',
width: 100,
filterable: false,
accessor: 'curr_size',
className: 'padded',
Aggregated: ({ subRows }) => {
const originalRows = subRows.map(r => r._original);
if (!originalRows.some(r => r.service_type === 'historical')) return '';
const totalCurr = sum(originalRows, s => s.curr_size);
return formatBytes(totalCurr);
},
Cell: ({ value, aggregated, original }) => {
if (aggregated || original.service_type !== 'historical') return '';
if (value === null) return '';
return formatBytes(value);
},
},
{
Header: 'Max size',
show: visibleColumns.shown('Max size'),
id: 'max_size',
width: 100,
filterable: false,
accessor: 'max_size',
className: 'padded',
Aggregated: ({ subRows }) => {
const originalRows = subRows.map(r => r._original);
if (!originalRows.some(r => r.service_type === 'historical')) return '';
const totalMax = sum(originalRows, s => s.max_size);
return formatBytes(totalMax);
},
Cell: ({ value, aggregated, original }) => {
if (aggregated || original.service_type !== 'historical') return '';
if (value === null) return '';
return formatBytes(value);
},
},
{
Header: 'Usage',
show: visibleColumns.shown('Usage'),
id: 'usage',
width: 140,
filterable: false,
className: 'padded',
accessor: row => {
if (oneOf(row.service_type, 'middle_manager', 'indexer')) {
const { workerInfo } = row;
if (!workerInfo) return 0;
return (
(Number(workerInfo.currCapacityUsed) || 0) / Number(workerInfo.worker?.capacity)
);
} else {
return row.max_size ? Number(row.curr_size) / Number(row.max_size) : null;
}
},
Aggregated: ({ subRows }) => {
const originalRows = subRows.map(r => r._original);
if (originalRows.some(r => r.service_type === 'historical')) {
const totalCurr = sum(originalRows, s => Number(s.curr_size));
const totalMax = sum(originalRows, s => Number(s.max_size));
return fillIndicator(totalCurr / totalMax);
} else if (
originalRows.some(
r => r.service_type === 'indexer' || r.service_type === 'middle_manager',
)
) {
const workerInfos: WorkerInfo[] = filterMap(originalRows, r => r.workerInfo);
if (!workerInfos.length) return '';
const totalCurrCapacityUsed = sum(
workerInfos,
w => Number(w.currCapacityUsed) || 0,
);
const totalWorkerCapacity = sum(
workerInfos,
s => deepGet(s, 'worker.capacity') || 0,
);
return `Slots used: ${totalCurrCapacityUsed} of ${totalWorkerCapacity}`;
} else {
return '';
}
},
Cell: ({ value, aggregated, original }) => {
if (aggregated) return '';
const { service_type } = original;
switch (service_type) {
case 'historical':
return fillIndicator(value);
case 'indexer':
case 'middle_manager': {
if (!deepGet(original, 'workerInfo')) return '';
const currCapacityUsed = deepGet(original, 'workerInfo.currCapacityUsed') || 0;
const capacity = deepGet(original, 'workerInfo.worker.capacity');
if (typeof capacity === 'number') {
return `Slots used: ${currCapacityUsed} of ${capacity}`;
} else {
return 'Slots used: -';
}
}
default:
return '';
}
},
},
{
Header: 'Start time',
show: visibleColumns.shown('Start time'),
accessor: 'start_time',
width: 200,
Cell: this.renderFilterableCell('start_time'),
Aggregated: () => '',
},
{
Header: 'Detail',
show: visibleColumns.shown('Detail'),
id: 'queue',
width: 400,
filterable: false,
className: 'padded',
accessor: row => {
switch (row.service_type) {
case 'middle_manager':
case 'indexer': {
const { workerInfo } = row;
if (!workerInfo) return '';
if (workerInfo.worker.version === '') return 'Disabled';
const details: string[] = [];
if (workerInfo.lastCompletedTaskTime) {
details.push(
`Last completed task: ${prettyFormatIsoDateWithMsIfNeeded(
workerInfo.lastCompletedTaskTime,
)}`,
);
}
if (workerInfo.blacklistedUntil) {
details.push(
`Blacklisted until: ${prettyFormatIsoDateWithMsIfNeeded(
workerInfo.blacklistedUntil,
)}`,
);
}
return details.join(' ');
}
case 'coordinator':
case 'overlord':
return row.is_leader === 1 ? 'Leader' : '';
case 'historical': {
const { loadQueueInfo } = row;
if (!loadQueueInfo) return 0;
return (
(Number(loadQueueInfo.segmentsToLoad) || 0) +
(Number(loadQueueInfo.segmentsToDrop) || 0)
);
}
default:
return 0;
}
},
Cell: ({ value, aggregated, original }) => {
if (aggregated) return '';
const { service_type } = original;
switch (service_type) {
case 'middle_manager':
case 'indexer':
case 'coordinator':
case 'overlord':
return value;
case 'historical': {
const { loadQueueInfo } = original;
return loadQueueInfo ? formatLoadQueueInfo(loadQueueInfo) : '';
}
default:
return '';
}
},
Aggregated: ({ subRows }) => {
const originalRows = subRows.map(r => r._original);
if (!originalRows.some(r => r.service_type === 'historical')) return '';
const loadQueueInfos: LoadQueueInfo[] = filterMap(originalRows, r => r.loadQueueInfo);
return loadQueueInfos.length
? formatLoadQueueInfo(aggregateLoadQueueInfos(loadQueueInfos))
: '';
},
},
{
Header: ACTION_COLUMN_LABEL,
show: capabilities.hasOverlordAccess(),
id: ACTION_COLUMN_ID,
width: ACTION_COLUMN_WIDTH,
accessor: row => row.workerInfo,
filterable: false,
sortable: false,
Cell: ({ value, aggregated }) => {
if (aggregated) return '';
if (!value) return null;
const { worker } = value;
const disabled = worker.version === '';
const workerActions = this.getWorkerActions(worker.host, disabled);
return <ActionCell actions={workerActions} menuTitle={worker.host} />;
},
Aggregated: () => '',
},
]}
/>
);
}