fix: Admin-UX aus dem Review – Live-Gruppenfeedback, Protokollfilter, Divi-Hinweis, Rollen-Rückfrage

- Tools: „Ganze Gruppe“ und „Nur lesen“ wirken sofort auf die Zeilen
  (Option „wie Gruppe (…)“, gesperrte Selects mit Hinweis), der Server
  bleibt die Wahrheit; Markup trägt die nötigen data-Attribute.
- Protokoll: Filter in eigenem Block über der Tabelle (Core blendet
  .tablenav .actions auf Telefonen aus); „Protokoll leeren“ nur bei
  Einträgen, rechtsbündig, mit Gesamtzahl über ChangeLog::count().
- Divi: Beschreibung unter „Prüfung starten“, Button primär solange
  ungetestet ohne frischen Bericht.
- Zugriff: Rückfrage vor dem Speichern ohne Rolle oder ohne eigene Rolle.
- Verbindung: HTTPS-Hinweis nicht doppelt neben der Statusliste.
- Mobil: breitere Einstellungs-Spalte im Tools-Reiter.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Jan-Niclas Loosen
2026-10-08 16:39:44 +02:00
co-authored by Claude Fable 5.1
parent cc72f9b946
commit 1b73f0652a
17 changed files with 462 additions and 150 deletions
+23 -5
View File
@@ -184,15 +184,16 @@ final class LogTabTest extends TestCase
self::assertFalse($tab->savePerPage(false, 'other_per_page', '40'));
}
public function testRenderShowsFiltersAndAConfirmProtectedClearButton(): void
public function testRenderShowsTheFiltersAboveTheTableOutsideTheTableNav(): void
{
$html = $this->render(['lit/content-update', 'lit/media-upload-from-url', 'lit/x"><script>']);
self::assertStringContainsString('name="result"', $html);
self::assertStringNotContainsString('<script>', $html);
self::assertStringContainsString('lit_mcp_clear_log', $html);
self::assertStringContainsString('confirm(', $html);
self::assertStringContainsString('nonce-lit_mcp_clear_log', $html);
// Core hides ".tablenav .actions" on phones; the filters live in their own block before the table.
self::assertStringContainsString('<div class="lit-mcp-log-filters">', $html);
self::assertStringNotContainsString('alignleft actions', $html);
self::assertStringNotContainsString('lit_mcp_clear_log', $html, 'nothing to clear in an empty log');
// One intro line; the retention days link to the Limits tab.
self::assertMatchesRegularExpression('#<p class="description">[^<]*<a href="[^"]*tab=limits">90 Tagen</a>#', $html);
@@ -207,6 +208,22 @@ final class LogTabTest extends TestCase
self::assertStringNotContainsString('Filter zurücksetzen', $html, 'no reset without an active filter');
}
public function testClearButtonAppearsOnlyWithEntriesAndNamesTheirCount(): void
{
$two = $this->render([], 2);
self::assertStringContainsString('<div class="lit-mcp-clear-log">', $two);
self::assertStringContainsString('lit_mcp_clear_log', $two);
self::assertStringContainsString('confirm(', $two);
self::assertStringContainsString('nonce-lit_mcp_clear_log', $two);
self::assertStringContainsString('>Protokoll leeren (2 Einträge)</button>', $two);
self::assertStringContainsString('>Protokoll leeren (1 Eintrag)</button>', $this->render([], 1));
// The count is the whole log, not the filtered page (query() above answers with no rows).
$_GET['result'] = 'refused';
self::assertStringContainsString('>Protokoll leeren (2 Einträge)</button>', $this->render([], 2));
}
public function testToolFilterShowsHumanLabelsGroupedByIntegration(): void
{
$_GET['ability'] = 'lit/content-update';
@@ -234,7 +251,7 @@ final class LogTabTest extends TestCase
}
/** @param list<string> $abilities abilities found in the log */
private function render(array $abilities): string
private function render(array $abilities, int $total = 0): string
{
Functions\stubEscapeFunctions();
Functions\stubTranslationFunctions();
@@ -267,6 +284,7 @@ final class LogTabTest extends TestCase
$log = Mockery::mock(ChangeLog::class);
$log->allows('abilities')->andReturn($abilities);
$log->allows('query')->andReturn(['rows' => [], 'total' => 0]);
$log->allows('count')->andReturn($total);
ob_start();
$this->tab($log)->render();