Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,14 @@ auto-generated per-PR notes; this file is the curated, human-readable history.
each pairing an `onclick: close` backdrop with an `onclick: stopPropagation`
panel. The cell-detail drawer's resize-drag one-shot click-swallow listener
(#101) is superseded by the same general fix. (#110)
- The fullscreen schema graph's rich node card had no overflow cap on its
`idx:` skip-index line — unlike columns (capped at `MAX_COLS` with a "+N
more" row), every skip-index was joined onto one unbounded line. A
heavily-indexed table (e.g. an OTel-style log table with a bloom filter per
Map key/value plus a tokenbf on the body) produced a single line 1700px+
wide, blowing the card — and the whole graph layout — out of proportion.
`buildCardModel` now caps the line at `CARD.MAX_IDX` (6) with a "+N more"
suffix, mirroring the columns' overflow pattern.

## [0.1.5] - 2026-06-29

Expand Down
7 changes: 6 additions & 1 deletion src/core/schema-cards.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ export const CARD = {
BADGE_W: 26, // approx width of one role badge (PK/SK/PARTITION/SAMPLING)
MIN_W: 130,
MAX_COLS: 16,
MAX_IDX: 6, // skip-indices have no dedicated overflow row (unlike columns) — cap the
// single idx: line itself so a heavily-indexed table (bloom filters per
// Map key/value, tokenbf on Body, …) can't blow the card absurdly wide.
MAX_TYPE: 28, // truncate the displayed column type — a big Enum/Tuple/Map would
// otherwise blow the card (and the whole graph) absurdly wide.
};
Expand Down Expand Up @@ -64,8 +67,10 @@ export function buildCardModel(node, tableRow, columns, skipIndices) {
}));
const overflow = Math.max(0, allCols.length - CARD.MAX_COLS);
const idx = skipIndices || [];
const idxOverflow = Math.max(0, idx.length - CARD.MAX_IDX);
const skipLine = idx.length
? 'idx: ' + idx.map((i) => i.name + ' (' + (i.type || '') + ')').join(', ')
? 'idx: ' + idx.slice(0, CARD.MAX_IDX).map((i) => i.name + ' (' + (i.type || '') + ')').join(', ')
+ (idxOverflow ? ', +' + idxOverflow + ' more' : '')
: '';
return { title: n.label || n.id || '', kind: n.kind || 'table', summary, cols, overflow, skipLine };
}
Expand Down
12 changes: 12 additions & 0 deletions tests/unit/schema-cards.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@ describe('buildCardModel', () => {
expect(m.overflow).toBe(1);
expect(m.skipLine).toBe('idx: idx_a (minmax)');
});
it('caps the skip-index line at MAX_IDX with a "+N more" suffix (no dedicated overflow row)', () => {
const idx = Array.from({ length: CARD.MAX_IDX + 2 }, (_, i) => ({ name: 'idx_' + i, type: 'bloom_filter' }));
const m = buildCardModel({ label: 'db.t', kind: 'table' }, {}, [], idx);
const shown = idx.slice(0, CARD.MAX_IDX).map((i) => i.name + ' (bloom_filter)').join(', ');
expect(m.skipLine).toBe('idx: ' + shown + ', +2 more');
});
it('does not append an overflow suffix when the index count is within MAX_IDX', () => {
const idx = Array.from({ length: CARD.MAX_IDX }, (_, i) => ({ name: 'idx_' + i, type: 'set' }));
const m = buildCardModel({ label: 'db.t', kind: 'table' }, {}, [], idx);
expect(m.skipLine).not.toContain('more');
expect(m.skipLine.match(/idx_/g)).toHaveLength(CARD.MAX_IDX);
});
it('degrades to a header-only card for a leaf with no row/columns/indices', () => {
const leaf = buildCardModel({ id: 'ext:mysql', label: 'mysql', kind: 'external' });
expect(leaf.summary).toBe('external · — rows · —'); // engine falls back to kind
Expand Down