feat: Divi tree editor and quality warnings
TreeEditor (position/insert/move/remove/duplicate on the BlockTree) and Warnings (post-write quality checks), plus S18's outline breadth limit on the 2a Outline/DiviOutlineAbility. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
This commit is contained in:
@@ -7,21 +7,44 @@ namespace LIT\MCP\Integrations\Divi\BlockTree;
|
||||
/**
|
||||
* The page tree as rows and as compact text (lit-divi-outline, spec §5.3/§5.7; also the
|
||||
* "outline" of write results). Preset IDs are shown with their names when known.
|
||||
*
|
||||
* Ruling S18: a page can have far more nodes at one level than are useful to show (e.g. a
|
||||
* 200-item slider). rows() therefore caps the number of *direct* children shown per parent
|
||||
* (breadth, not depth) at $limit; the parent whose children got cut is marked
|
||||
* 'truncated' => true. wasTruncated() additionally reports whether ANY cap fired, including at
|
||||
* the top level (the page root has no row of its own to mark).
|
||||
*/
|
||||
final class Outline
|
||||
{
|
||||
/** Sane default breadth cap per parent when no explicit limit is given. */
|
||||
public const DEFAULT_LIMIT = 50;
|
||||
|
||||
private bool $truncated = false;
|
||||
|
||||
/** @param array<string, string> $presetNames Preset ID => name. */
|
||||
public function __construct(private array $presetNames = [])
|
||||
{
|
||||
}
|
||||
|
||||
/** Whether the last rows() call cut off any children (at any level, including the top). */
|
||||
public function wasTruncated(): bool
|
||||
{
|
||||
return $this->truncated;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<array{id: string, type: string, label: string, excerpt: string, info: string,
|
||||
* presets: list<string>, children: int, editable: bool, depth: int}>
|
||||
* presets: list<string>, children: int, editable: bool, depth: int, truncated: bool}>
|
||||
*/
|
||||
public function rows(NodeIndex $index, ?string $rootId = null, ?int $maxDepth = null): array
|
||||
public function rows(NodeIndex $index, ?string $rootId = null, ?int $maxDepth = null, ?int $limit = null): array
|
||||
{
|
||||
$limit = $limit ?? self::DEFAULT_LIMIT;
|
||||
$this->truncated = false;
|
||||
|
||||
$rows = [];
|
||||
$rowIndexById = [];
|
||||
$counts = [];
|
||||
$skipped = [];
|
||||
$baseDepth = null;
|
||||
foreach ($index->entries() as $entry) {
|
||||
$id = $entry['id'];
|
||||
@@ -29,12 +52,30 @@ final class Outline
|
||||
continue;
|
||||
}
|
||||
|
||||
$parentId = $index->parentId($entry['block']);
|
||||
if ($parentId !== null && isset($skipped[$parentId])) {
|
||||
$skipped[$id] = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
$baseDepth ??= $entry['depth'];
|
||||
$depth = $entry['depth'] - $baseDepth;
|
||||
if ($maxDepth !== null && $depth > $maxDepth) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$parentKey = $parentId ?? '';
|
||||
$counts[$parentKey] = ($counts[$parentKey] ?? 0) + 1;
|
||||
if ($counts[$parentKey] > $limit) {
|
||||
$this->truncated = true;
|
||||
$skipped[$id] = true;
|
||||
if ($parentId !== null && isset($rowIndexById[$parentId])) {
|
||||
$rows[$rowIndexById[$parentId]]['truncated'] = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$rowIndexById[$id] = count($rows);
|
||||
$rows[] = $this->row($entry['block'], $id, $depth);
|
||||
}
|
||||
|
||||
@@ -52,6 +93,7 @@ final class Outline
|
||||
$line .= $row['presets'] !== [] ? ' {Preset: ' . implode(', ', $row['presets']) . '}' : '';
|
||||
$line .= $row['excerpt'] !== '' ? ' – ' . $row['excerpt'] : '';
|
||||
$line .= $row['editable'] ? '' : ' (nur lesbar)';
|
||||
$line .= ($row['truncated'] ?? false) ? ' (weitere Kinder abgeschnitten)' : '';
|
||||
$lines[] = $line;
|
||||
}
|
||||
|
||||
@@ -60,7 +102,7 @@ final class Outline
|
||||
|
||||
/**
|
||||
* @return array{id: string, type: string, label: string, excerpt: string, info: string,
|
||||
* presets: list<string>, children: int, editable: bool, depth: int}
|
||||
* presets: list<string>, children: int, editable: bool, depth: int, truncated: bool}
|
||||
*/
|
||||
private function row(Block $block, string $id, int $depth): array
|
||||
{
|
||||
@@ -79,6 +121,7 @@ final class Outline
|
||||
'children' => $editable ? count($block->children()) : 0,
|
||||
'editable' => $editable,
|
||||
'depth' => $depth,
|
||||
'truncated' => false,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user