Gegevens tabel
Een krachtindeling is slecht in drie dingen die mensen voortdurend doen: exacte waarden lezen, selecteren op schaal en uitzoeken waar te beginnen. UI.table splitst een datadock uit de onderkant van het canvas om alle drie te beantwoorden: de rijen van de grafiek, sorteerbaar en selecteerbaar.
De lus is tabel om te vinden, canvas om te begrijpen, zijbalk om te lezen:
- De tabel wordt gesorteerd op verzoeken geopend, dus de drukste service is de eerste rij.
- Klik op een kop om opnieuw te sorteren; klik nogmaals om terug te keren.
- Klik op een rij om deze te selecteren,
Ctrl+Clickom er een toe te voegen, ofShift+Clickom een bereik ** te nemen in de weergegeven volgorde** — en handel vervolgens op het perceel met de bulkacties in de zijbalk. - Plak in plaats daarvan een groep op het canvas en de bijpassende rijen lichten op.
- Verklein de rijen vanaf de kopteksten: het besturingselement volgt de kolom: typ in Service, kies uit Kind, stel grenzen in op Verzoeken / dag. Dat raakt nooit het canvas: het eigen filter van de grafiek blijft bij het filterpaneel, dus de twee kunnen niet vechten.
- Nodes / Edges wisselen wat er wordt vermeld. CSV en JSON schrijf precies op wat staat op het scherm: dit tabblad, deze kolommen, dit soort, dit filter.
Het dock vermeldt ook knooppunten waarvan de grafiek momenteel verbergt, met een kolom Visibility zeggen of een filter of handmatig verbergen verantwoordelijk is - dus "23 knooppunten verborgen" is iets dat u kunt inspecteren in plaats van op vertrouwen te vertrouwen.
Versleep de scheidingslijn om de grootte ervan te wijzigen, of vouw deze met de punthaak naar de kopbalk. Geen van beide beweegt de grafiek: de simulatie stemt zichzelf af op de container, niet op het canvas, dus chroom openen en sluiten kan nooit een lay-out veranderen.
Zie Gegevenstabel voor de volledige optieset.
// import { ColorPaletteMapper, tableColumns } from 'pivotick'
//
// The data dock comes with `mode: 'full'`, folded to its header bar — click the chevron
// or press Shift+T. `open: true` below starts it expanded instead. Everything here is
// optional; `UI: { mode: 'full' }` alone gets you a dock.
//
// Columns are derived when you don't declare any: the graph-aware ones lead (Label,
// Degree, Visibility) and the data keys follow, ordered by how many nodes carry them.
// They are declared here instead, to put `requests` on the right and give three columns
// a row filter — one of each kind, since the control follows the column's `type`.
// `tableColumns` holds the graph-aware ones — clone one to relabel it.
const options = {
UI: {
mode: 'full',
// Full mode's minimap would sit in the corner this card wants for the dock,
// and the dock is the subject — see the Minimap card for that one.
minimap: false,
// Top-left, because this embed is 560px tall and the dock takes 42% of it: the
// canvas that's left is shorter than the mode rail, so the bottom-left corner has
// no column to give. A bottom-left legend would shrink to its header here.
legend: { position: 'top-left' },
table: {
open: true,
height: 0.42,
// Busiest first — the question you actually arrive with.
sort: { key: 'requests', direction: 'desc' },
columns: [
{ ...tableColumns.label, label: 'Service', filterable: true },
{ key: 'kind', label: 'Kind', type: 'select', filterable: true },
{ key: 'owner', label: 'Owner', type: 'select' },
{ key: 'tier', label: 'Tier', type: 'select' },
{ key: 'requests', label: 'Requests / day', type: 'numberRange', align: 'right', filterable: true },
{ ...tableColumns.degree, label: 'Links' },
],
},
},
// Colour by the same `kind` the table shows, so a row and a dot can be matched by
// eye. Declaring `nodeTypeAccessor` is also what earns the canvas its legend.
render: {
nodeTypeAccessor: (node) => node.getData().kind,
defaultNodeStyle: {
color: (node) => palette.getColor(node.getData().kind),
},
},
}const data = {
nodes: [
{ id: 'api', data: { label: 'api-gateway', kind: 'service', owner: 'Platform', requests: 48200, tier: 'edge' } },
{ id: 'auth', data: { label: 'auth-service', kind: 'service', owner: 'Identity', requests: 31400, tier: 'core' } },
{ id: 'billing', data: { label: 'billing-service', kind: 'service', owner: 'Payments', requests: 8600, tier: 'core' } },
{ id: 'search', data: { label: 'search-service', kind: 'service', owner: 'Discovery', requests: 22750, tier: 'core' } },
{ id: 'users-db', data: { label: 'users-db', kind: 'datastore', owner: 'Identity', requests: 39900, tier: 'data' } },
{ id: 'orders-db', data: { label: 'orders-db', kind: 'datastore', owner: 'Payments', requests: 12300, tier: 'data' } },
{ id: 'index', data: { label: 'search-index', kind: 'datastore', owner: 'Discovery', requests: 20100, tier: 'data' } },
{ id: 'cache', data: { label: 'edge-cache', kind: 'datastore', owner: 'Platform', requests: 51000, tier: 'edge' } },
{ id: 'mailer', data: { label: 'mailer', kind: 'worker', owner: 'Payments', requests: 1450, tier: 'async' } },
{ id: 'reindexer', data: { label: 'reindexer', kind: 'worker', owner: 'Discovery', requests: 980, tier: 'async' } },
],
edges: [
{ from: 'api', to: 'auth', data: { label: 'authenticates' } },
{ from: 'api', to: 'search', data: { label: 'queries' } },
{ from: 'api', to: 'billing', data: { label: 'charges' } },
{ from: 'api', to: 'cache', data: { label: 'reads' } },
{ from: 'auth', to: 'users-db', data: { label: 'reads' } },
{ from: 'billing', to: 'orders-db', data: { label: 'writes' } },
{ from: 'billing', to: 'mailer', data: { label: 'enqueues' } },
{ from: 'search', to: 'index', data: { label: 'reads' } },
{ from: 'reindexer', to: 'index', data: { label: 'writes' } },
{ from: 'reindexer', to: 'orders-db', data: { label: 'reads' } },
],
}