feat: design-system filters and global module ids in node-get/outline (S19)
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:
@@ -25,7 +25,10 @@ final class NodeSummary
|
|||||||
|
|
||||||
public static function label(Block $block): string
|
public static function label(Block $block): string
|
||||||
{
|
{
|
||||||
$label = AttrMap::desktop($block->attrs(), 'module.meta.adminLabel');
|
$attrs = $block->name() === 'divi/global-layout' && is_array($block->attrs()['localAttrs'] ?? null)
|
||||||
|
? $block->attrs()['localAttrs']
|
||||||
|
: $block->attrs();
|
||||||
|
$label = AttrMap::desktop($attrs, 'module.meta.adminLabel');
|
||||||
if (! is_string($label) || $label === '') {
|
if (! is_string($label) || $label === '') {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
@@ -55,6 +58,29 @@ final class NodeSummary
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Library entry of a global module: a divi/global-layout instance (its root type in blockName)
|
||||||
|
* or a block that carries globalModule itself (Divi 4 conversions). Null for every other block.
|
||||||
|
*
|
||||||
|
* @return array{id: string, block_name: string}|null
|
||||||
|
*/
|
||||||
|
public static function globalRef(Block $block): ?array
|
||||||
|
{
|
||||||
|
if (! $block->isGlobal()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$attrs = $block->attrs();
|
||||||
|
$id = $attrs['globalModule'] ?? null;
|
||||||
|
if (! is_string($id) && ! is_int($id)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$name = $block->name() === 'divi/global-layout' ? ($attrs['blockName'] ?? '') : $block->name();
|
||||||
|
|
||||||
|
return ['id' => (string) $id, 'block_name' => is_string($name) ? $name : ''];
|
||||||
|
}
|
||||||
|
|
||||||
/** @return list<string> */
|
/** @return list<string> */
|
||||||
public static function presetIds(Block $block): array
|
public static function presetIds(Block $block): array
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -59,7 +59,8 @@ final class Outline
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @return list<array{id: string, type: string, label: string, excerpt: string, info: string,
|
* @return list<array{id: string, type: string, label: string, excerpt: string, info: string,
|
||||||
* presets: list<string>, children: int, editable: bool, depth: int, truncated: bool}>
|
* presets: list<string>, children: int, editable: bool, depth: int, truncated: bool,
|
||||||
|
* global_id: ?string}>
|
||||||
*/
|
*/
|
||||||
public function rows(NodeIndex $index, ?string $rootId = null, ?int $maxDepth = null, ?int $limit = null): array
|
public function rows(NodeIndex $index, ?string $rootId = null, ?int $maxDepth = null, ?int $limit = null): array
|
||||||
{
|
{
|
||||||
@@ -114,6 +115,7 @@ final class Outline
|
|||||||
foreach ($rows as $row) {
|
foreach ($rows as $row) {
|
||||||
$line = str_repeat(' ', (int) $row['depth']) . $row['id'] . ' ' . $row['type'];
|
$line = str_repeat(' ', (int) $row['depth']) . $row['id'] . ' ' . $row['type'];
|
||||||
$line .= $row['label'] !== '' ? ' "' . $row['label'] . '"' : '';
|
$line .= $row['label'] !== '' ? ' "' . $row['label'] . '"' : '';
|
||||||
|
$line .= ($row['global_id'] ?? null) !== null ? ' [global ' . $row['global_id'] . ']' : '';
|
||||||
$line .= $row['info'] !== '' ? ' [' . $row['info'] . ']' : '';
|
$line .= $row['info'] !== '' ? ' [' . $row['info'] . ']' : '';
|
||||||
$line .= $row['presets'] !== [] ? ' {Preset: ' . implode(', ', $row['presets']) . '}' : '';
|
$line .= $row['presets'] !== [] ? ' {Preset: ' . implode(', ', $row['presets']) . '}' : '';
|
||||||
$line .= $row['excerpt'] !== '' ? ' – ' . $row['excerpt'] : '';
|
$line .= $row['excerpt'] !== '' ? ' – ' . $row['excerpt'] : '';
|
||||||
@@ -127,15 +129,23 @@ final class Outline
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array{id: string, type: string, label: string, excerpt: string, info: string,
|
* @return array{id: string, type: string, label: string, excerpt: string, info: string,
|
||||||
* presets: list<string>, children: int, editable: bool, depth: int, truncated: bool}
|
* presets: list<string>, children: int, editable: bool, depth: int, truncated: bool,
|
||||||
|
* global_id: ?string}
|
||||||
*/
|
*/
|
||||||
private function row(Block $block, string $id, int $depth): array
|
private function row(Block $block, string $id, int $depth): array
|
||||||
{
|
{
|
||||||
$editable = $block->isDivi() && ! $block->isOpaque();
|
$editable = $block->isDivi() && ! $block->isOpaque();
|
||||||
|
$global = NodeSummary::globalRef($block);
|
||||||
|
$type = $block->isDivi() ? $block->shortName() : $block->name();
|
||||||
|
if ($global !== null && $global['block_name'] !== '') {
|
||||||
|
$type = str_starts_with($global['block_name'], 'divi/')
|
||||||
|
? substr($global['block_name'], 5)
|
||||||
|
: $global['block_name'];
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
'type' => $block->isDivi() ? $block->shortName() : $block->name(),
|
'type' => $type,
|
||||||
'label' => NodeSummary::label($block),
|
'label' => NodeSummary::label($block),
|
||||||
'excerpt' => NodeSummary::excerpt($block),
|
'excerpt' => NodeSummary::excerpt($block),
|
||||||
'info' => $editable ? NodeSummary::info($block) : '',
|
'info' => $editable ? NodeSummary::info($block) : '',
|
||||||
@@ -147,6 +157,7 @@ final class Outline
|
|||||||
'editable' => $editable,
|
'editable' => $editable,
|
||||||
'depth' => $depth,
|
'depth' => $depth,
|
||||||
'truncated' => false,
|
'truncated' => false,
|
||||||
|
'global_id' => $global['id'] ?? null,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,11 @@ defined('ABSPATH') || exit;
|
|||||||
*/
|
*/
|
||||||
final class DiviDesignSystemAbility implements Ability
|
final class DiviDesignSystemAbility implements Ability
|
||||||
{
|
{
|
||||||
|
/** Presets per answer (ruling S19); narrow with "module". */
|
||||||
|
public const PRESET_LIMIT = 200;
|
||||||
|
|
||||||
|
private const PARTS = ['colors', 'variables', 'presets'];
|
||||||
|
|
||||||
public function __construct(private DesignSystemReader $reader)
|
public function __construct(private DesignSystemReader $reader)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -36,12 +41,28 @@ final class DiviDesignSystemAbility implements Ability
|
|||||||
{
|
{
|
||||||
return 'Liest das Designsystem der Website aus Divi: globale Farben, globale Variablen, Theme-Schriften und '
|
return 'Liest das Designsystem der Website aus Divi: globale Farben, globale Variablen, Theme-Schriften und '
|
||||||
. '-Größen, Modul- und Gruppen-Presets – jeweils mit dem Platzhalter ({{color:…}}, {{var:…}}, '
|
. '-Größen, Modul- und Gruppen-Presets – jeweils mit dem Platzhalter ({{color:…}}, {{var:…}}, '
|
||||||
. '{{font:…}}, preset), den neue Inhalte statt fester Werte verwenden sollen.';
|
. '{{font:…}}, preset), den neue Inhalte statt fester Werte verwenden sollen. '
|
||||||
|
. 'Filter: only (colors/variables/presets) und module (Presets eines Moduls).';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function inputSchema(): array
|
public function inputSchema(): array
|
||||||
{
|
{
|
||||||
return ['type' => 'object', 'properties' => [], 'additionalProperties' => false];
|
return [
|
||||||
|
'type' => 'object',
|
||||||
|
'properties' => [
|
||||||
|
'only' => [
|
||||||
|
'type' => 'array',
|
||||||
|
'items' => ['type' => 'string', 'enum' => self::PARTS],
|
||||||
|
'description' => 'Nur diese Teile liefern (Standard: alle). Schriften und Größen sind immer '
|
||||||
|
. 'dabei.',
|
||||||
|
],
|
||||||
|
'module' => [
|
||||||
|
'type' => 'string',
|
||||||
|
'description' => 'Nur Presets dieses Moduls, z. B. "button" oder "divi/button".',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'additionalProperties' => false,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function outputSchema(): ?array
|
public function outputSchema(): ?array
|
||||||
@@ -110,26 +131,52 @@ final class DiviDesignSystemAbility implements Ability
|
|||||||
public function execute(array $input): mixed
|
public function execute(array $input): mixed
|
||||||
{
|
{
|
||||||
$design = $this->reader->read();
|
$design = $this->reader->read();
|
||||||
|
$only = is_array($input['only'] ?? null) && $input['only'] !== []
|
||||||
|
? array_values(array_intersect(self::PARTS, $input['only']))
|
||||||
|
: self::PARTS;
|
||||||
|
$notes = [
|
||||||
|
'Schriften: {{font:heading}} bzw. {{font:body}}; Presets in der Kurzform über "preset": "<Name>".',
|
||||||
|
'Feste Farben oder Schriften nur verwenden, wenn der Nutzer es ausdrücklich möchte.',
|
||||||
|
];
|
||||||
|
$skipped = array_values(array_diff(self::PARTS, $only));
|
||||||
|
if ($skipped !== []) {
|
||||||
|
$notes[] = 'Nicht angefordert: ' . implode(', ', $skipped) . '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
$presets = $design->presets();
|
||||||
|
$module = is_string($input['module'] ?? null) ? trim($input['module']) : '';
|
||||||
|
if ($module !== '') {
|
||||||
|
$name = str_contains($module, '/') ? $module : 'divi/' . $module;
|
||||||
|
$presets = array_values(array_filter(
|
||||||
|
$presets,
|
||||||
|
static fn (array $preset): bool => $preset['module'] === $name
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if (count($presets) > self::PRESET_LIMIT) {
|
||||||
|
$notes[] = sprintf(
|
||||||
|
'%d von %d Presets gezeigt; mit module auf ein Modul eingrenzen.',
|
||||||
|
self::PRESET_LIMIT,
|
||||||
|
count($presets)
|
||||||
|
);
|
||||||
|
$presets = array_slice($presets, 0, self::PRESET_LIMIT);
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'colors' => array_map(
|
'colors' => in_array('colors', $only, true) ? array_map(
|
||||||
static fn (array $color): array => $color + [
|
static fn (array $color): array => $color + [
|
||||||
'placeholder' => DesignSystem::colorPlaceholder($color['id'], $color['label']),
|
'placeholder' => DesignSystem::colorPlaceholder($color['id'], $color['label']),
|
||||||
],
|
],
|
||||||
$design->colors()
|
$design->colors()
|
||||||
),
|
) : [],
|
||||||
'variables' => array_map(
|
'variables' => in_array('variables', $only, true) ? array_map(
|
||||||
static fn (array $variable): array => $variable
|
static fn (array $variable): array => $variable
|
||||||
+ ['placeholder' => '{{var:' . $variable['label'] . '}}'],
|
+ ['placeholder' => '{{var:' . $variable['label'] . '}}'],
|
||||||
$design->variables()
|
$design->variables()
|
||||||
),
|
) : [],
|
||||||
'fonts' => $design->fonts(),
|
'fonts' => $design->fonts(),
|
||||||
'sizes' => $design->sizes(),
|
'sizes' => $design->sizes(),
|
||||||
'presets' => $design->presets(),
|
'presets' => in_array('presets', $only, true) ? $presets : [],
|
||||||
'notes' => [
|
'notes' => $notes,
|
||||||
'Schriften: {{font:heading}} bzw. {{font:body}}; Presets in der Kurzform über "preset": "<Name>".',
|
|
||||||
'Feste Farben oder Schriften nur verwenden, wenn der Nutzer es ausdrücklich möchte.',
|
|
||||||
],
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ final class DiviNodeGetAbility implements Ability
|
|||||||
],
|
],
|
||||||
'builder_version' => ['type' => ['string', 'null']],
|
'builder_version' => ['type' => ['string', 'null']],
|
||||||
'children' => ['type' => 'array', 'items' => ['type' => 'string']],
|
'children' => ['type' => 'array', 'items' => ['type' => 'string']],
|
||||||
|
'global' => ['type' => ['object', 'null']],
|
||||||
],
|
],
|
||||||
'required' => ['post_id', 'tree_rev', 'rev', 'id', 'type', 'editable', 'attrs', 'shortform', 'children'],
|
'required' => ['post_id', 'tree_rev', 'rev', 'id', 'type', 'editable', 'attrs', 'shortform', 'children'],
|
||||||
];
|
];
|
||||||
@@ -128,6 +129,16 @@ final class DiviNodeGetAbility implements Ability
|
|||||||
$editable = $block->isDivi() && ! $block->isOpaque();
|
$editable = $block->isDivi() && ! $block->isOpaque();
|
||||||
$version = $block->attrs()['builderVersion'] ?? null;
|
$version = $block->attrs()['builderVersion'] ?? null;
|
||||||
|
|
||||||
|
$global = NodeSummary::globalRef($block);
|
||||||
|
if ($global !== null) {
|
||||||
|
$global['hint'] = sprintf(
|
||||||
|
'Globales Modul: Inhalt im Bibliothekseintrag %s bearbeiten (lit-divi-outline mit post_id %s); '
|
||||||
|
. 'jede Änderung dort wirkt auf alle Seiten mit diesem Modul.',
|
||||||
|
$global['id'],
|
||||||
|
$global['id']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'post_id' => (int) $page->post->ID,
|
'post_id' => (int) $page->post->ID,
|
||||||
'tree_rev' => $page->treeRev(),
|
'tree_rev' => $page->treeRev(),
|
||||||
@@ -147,6 +158,7 @@ final class DiviNodeGetAbility implements Ability
|
|||||||
'children' => $editable
|
'children' => $editable
|
||||||
? array_values(array_filter(array_map([$page->index, 'idOf'], $block->children())))
|
? array_values(array_filter(array_map([$page->index, 'idOf'], $block->children())))
|
||||||
: [],
|
: [],
|
||||||
|
'global' => $global,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,10 +98,14 @@ final class DiviOutlineAbility implements Ability
|
|||||||
'type' => 'boolean',
|
'type' => 'boolean',
|
||||||
'description' => 'Weitere Kinder dieses Knotens wurden wegen "limit" abgeschnitten.',
|
'description' => 'Weitere Kinder dieses Knotens wurden wegen "limit" abgeschnitten.',
|
||||||
],
|
],
|
||||||
|
'global_id' => [
|
||||||
|
'type' => ['string', 'null'],
|
||||||
|
'description' => 'Bibliotheks-ID eines globalen Moduls.',
|
||||||
|
],
|
||||||
],
|
],
|
||||||
'required' => [
|
'required' => [
|
||||||
'id', 'type', 'label', 'excerpt', 'info', 'presets', 'children', 'editable', 'depth',
|
'id', 'type', 'label', 'excerpt', 'info', 'presets', 'children', 'editable', 'depth',
|
||||||
'truncated',
|
'truncated', 'global_id',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
@@ -187,7 +191,8 @@ final class DiviOutlineAbility implements Ability
|
|||||||
|
|
||||||
if (in_array(false, array_column($rows, 'editable'), true)) {
|
if (in_array(false, array_column($rows, 'editable'), true)) {
|
||||||
$hints[] = 'Knoten mit "nur lesbar" (globale Module, fremde Blöcke) lassen sich nur als Ganzes '
|
$hints[] = 'Knoten mit "nur lesbar" (globale Module, fremde Blöcke) lassen sich nur als Ganzes '
|
||||||
. 'verschieben, duplizieren oder löschen; ihren Inhalt im Divi-Builder bearbeiten.';
|
. 'verschieben, duplizieren oder löschen. Globale Module [global <ID>] im Bibliothekseintrag '
|
||||||
|
. 'bearbeiten: lit-divi-outline mit post_id <ID> – die Änderung wirkt auf alle Seiten.';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $hints;
|
return $hints;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use LIT\MCP\Integrations\Divi\BlockTree\NodeIndex;
|
|||||||
use LIT\MCP\Integrations\Divi\BlockTree\NodeSummary;
|
use LIT\MCP\Integrations\Divi\BlockTree\NodeSummary;
|
||||||
use LIT\MCP\Integrations\Divi\BlockTree\Outline;
|
use LIT\MCP\Integrations\Divi\BlockTree\Outline;
|
||||||
use LIT\MCP\Integrations\Divi\BlockTree\Parser;
|
use LIT\MCP\Integrations\Divi\BlockTree\Parser;
|
||||||
|
use LIT\MCP\Tests\Support\DiviFixtures;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use stdClass;
|
use stdClass;
|
||||||
|
|
||||||
@@ -26,7 +27,7 @@ final class OutlineTest extends TestCase
|
|||||||
self::assertSame(
|
self::assertSame(
|
||||||
['id' => 's0.r0.c1.m0', 'type' => 'heading', 'label' => '', 'excerpt' => 'Willkommen bei Müller & Söhne',
|
['id' => 's0.r0.c1.m0', 'type' => 'heading', 'label' => '', 'excerpt' => 'Willkommen bei Müller & Söhne',
|
||||||
'info' => '', 'presets' => ['Hero-Titel'], 'children' => 0, 'editable' => true, 'depth' => 3,
|
'info' => '', 'presets' => ['Hero-Titel'], 'children' => 0, 'editable' => true, 'depth' => 3,
|
||||||
'truncated' => false],
|
'truncated' => false, 'global_id' => null],
|
||||||
$rows[5]
|
$rows[5]
|
||||||
);
|
);
|
||||||
self::assertSame('Spalten 8_24+16_24', $rows[1]['info']);
|
self::assertSame('Spalten 8_24+16_24', $rows[1]['info']);
|
||||||
@@ -40,6 +41,22 @@ final class OutlineTest extends TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testGlobalInstancesShowTheirLibraryIdAndRootType(): void
|
||||||
|
{
|
||||||
|
$content = DiviFixtures::markup('stage3/page--globale-instanzen.html');
|
||||||
|
$outline = new Outline();
|
||||||
|
$rows = $outline->rows(NodeIndex::build((new Parser())->parse($content)));
|
||||||
|
|
||||||
|
$byId = array_column($rows, null, 'id');
|
||||||
|
self::assertSame('1058', $byId['g0']['global_id']);
|
||||||
|
self::assertSame('section', $byId['g0']['type']);
|
||||||
|
self::assertFalse($byId['g0']['editable']);
|
||||||
|
self::assertSame('1059', $byId['s0.r0.c0.g0']['global_id']);
|
||||||
|
self::assertSame('text', $byId['s0.r0.c0.g0']['type']);
|
||||||
|
self::assertNull($byId['s0']['global_id']);
|
||||||
|
self::assertStringContainsString('g0 section "Global Abschnitt" [global 1058]', $outline->text($rows));
|
||||||
|
}
|
||||||
|
|
||||||
public function testSubtreeAndDepthLimit(): void
|
public function testSubtreeAndDepthLimit(): void
|
||||||
{
|
{
|
||||||
$index = NodeIndex::build((new Parser())->parse($this->fixture('synthetic-basic.html')));
|
$index = NodeIndex::build((new Parser())->parse($this->fixture('synthetic-basic.html')));
|
||||||
@@ -104,7 +121,7 @@ final class OutlineTest extends TestCase
|
|||||||
$text = (new Outline())->text((new Outline())->rows($index));
|
$text = (new Outline())->text((new Outline())->rows($index));
|
||||||
|
|
||||||
self::assertStringContainsString('x0 core/paragraph (nur lesbar)', $text);
|
self::assertStringContainsString('x0 core/paragraph (nur lesbar)', $text);
|
||||||
self::assertStringContainsString('s1.g1 row "Globale Zeile" (nur lesbar)', $text);
|
self::assertStringContainsString('s1.g1 row "Globale Zeile" [global 913] (nur lesbar)', $text);
|
||||||
self::assertStringContainsString('s0 section [specialty]', $text);
|
self::assertStringContainsString('s0 section [specialty]', $text);
|
||||||
self::assertStringContainsString('s0.c1.r0 row-inner [Spalten 1_2+1_2]', $text);
|
self::assertStringContainsString('s0.c1.r0 row-inner [Spalten 1_2+1_2]', $text);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||||||
namespace LIT\MCP\Tests\Unit\Integrations\Divi\Design;
|
namespace LIT\MCP\Tests\Unit\Integrations\Divi\Design;
|
||||||
|
|
||||||
use Brain\Monkey\Functions;
|
use Brain\Monkey\Functions;
|
||||||
|
use LIT\MCP\Integrations\Divi\Design\DesignSystem;
|
||||||
use LIT\MCP\Integrations\Divi\Design\DesignSystemReader;
|
use LIT\MCP\Integrations\Divi\Design\DesignSystemReader;
|
||||||
use LIT\MCP\Integrations\Divi\Design\DiviDesignSystemAbility;
|
use LIT\MCP\Integrations\Divi\Design\DiviDesignSystemAbility;
|
||||||
use LIT\MCP\Tests\Support\DiviFixtures;
|
use LIT\MCP\Tests\Support\DiviFixtures;
|
||||||
@@ -41,4 +42,38 @@ final class DiviDesignSystemAbilityTest extends TestCase
|
|||||||
|
|
||||||
self::assertToolError($result, 'forbidden');
|
self::assertToolError($result, 'forbidden');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testFiltersPartsAndPresetsOfOneModule(): void
|
||||||
|
{
|
||||||
|
Functions\when('current_user_can')->justReturn(true);
|
||||||
|
$reader = Mockery::mock(DesignSystemReader::class);
|
||||||
|
$reader->allows('read')->andReturn(DiviFixtures::designSystem());
|
||||||
|
$ability = new DiviDesignSystemAbility($reader);
|
||||||
|
|
||||||
|
$result = $ability->execute(['only' => ['presets'], 'module' => 'button']);
|
||||||
|
|
||||||
|
self::assertSame([], $result['colors']);
|
||||||
|
self::assertSame([], $result['variables']);
|
||||||
|
self::assertSame(['p-1', 'p-2'], array_column($result['presets'], 'id'));
|
||||||
|
self::assertSame(['divi/button'], array_values(array_unique(array_column($result['presets'], 'module'))));
|
||||||
|
self::assertNotEmpty($result['fonts']['heading']);
|
||||||
|
self::assertContains('Nicht angefordert: colors, variables.', $result['notes']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCapsThePresetList(): void
|
||||||
|
{
|
||||||
|
Functions\when('current_user_can')->justReturn(true);
|
||||||
|
$items = [];
|
||||||
|
for ($i = 0; $i < 250; ++$i) {
|
||||||
|
$items['p' . $i] = ['id' => 'p' . $i, 'name' => 'Preset ' . $i, 'moduleName' => 'divi/text'];
|
||||||
|
}
|
||||||
|
$design = DesignSystem::fromDivi([], [], ['module' => ['divi/text' => ['default' => '', 'items' => $items]]], []);
|
||||||
|
$reader = Mockery::mock(DesignSystemReader::class);
|
||||||
|
$reader->allows('read')->andReturn($design);
|
||||||
|
|
||||||
|
$result = (new DiviDesignSystemAbility($reader))->execute([]);
|
||||||
|
|
||||||
|
self::assertCount(DiviDesignSystemAbility::PRESET_LIMIT, $result['presets']);
|
||||||
|
self::assertContains('200 von 250 Presets gezeigt; mit module auf ein Modul eingrenzen.', $result['notes']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,4 +123,19 @@ final class DiviReadAbilitiesTest extends TestCase
|
|||||||
self::assertToolError($ability->execute(['post_id' => 7, 'id' => 'hero']), 'validation_failed');
|
self::assertToolError($ability->execute(['post_id' => 7, 'id' => 'hero']), 'validation_failed');
|
||||||
self::assertToolError($ability->execute(['post_id' => 7, 'id' => 's5.r0']), 'not_found');
|
self::assertToolError($ability->execute(['post_id' => 7, 'id' => 's5.r0']), 'not_found');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testNodeGetNamesTheLibraryEntryOfAGlobalModule(): void
|
||||||
|
{
|
||||||
|
DiviFixtures::givenPost(DiviFixtures::markup('stage3/page--globale-instanzen.html'));
|
||||||
|
$ability = new DiviNodeGetAbility(new DiviPageLoader(DiviFixtures::schema()), $this->design());
|
||||||
|
|
||||||
|
$global = $ability->execute(['post_id' => 7, 'id' => 'g0']);
|
||||||
|
$plain = $ability->execute(['post_id' => 7, 'id' => 's0']);
|
||||||
|
|
||||||
|
self::assertSame('1058', $global['global']['id']);
|
||||||
|
self::assertSame('divi/section', $global['global']['block_name']);
|
||||||
|
self::assertStringContainsString('post_id 1058', $global['global']['hint']);
|
||||||
|
self::assertFalse($global['editable']);
|
||||||
|
self::assertNull($plain['global']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user