feat(admin): Einstellungsseite überarbeitet, auch für das Handy

Verbindung: Probleme vor der Anleitung. Tools: Suche, Filter, Alle ein-/ausklappen, Zurücksetzen je Gruppe.
Divi-Reiter in Klartext mit Statussymbolen. Rollenhinweise, Hilfe-Tab, Reiter als Raster und Karten auf dem Handy,
Kontrast, Tippflächen, einheitliche Du-Anrede. Bestätigungen über data-lit-mcp-confirm statt Inline-onclick.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Jan-Niclas Loosen
2026-11-05 16:36:16 +01:00
co-authored by Claude Sonnet 5.5
parent 165e61d7fe
commit 96fa58188b
16 changed files with 865 additions and 84 deletions
+51 -16
View File
@@ -84,7 +84,7 @@ final class AccessTab implements AdminTab
private static function ownRoleWarning(): string
{
return __(
'Keine Ihrer Rollen ist mehr freigegeben – Sie selbst können LIT MCP nicht mehr nutzen.',
'Keine deiner Rollen ist mehr freigegeben. Du kannst LIT MCP dann selbst nicht mehr nutzen.',
'wp-lit-mcp'
);
}
@@ -105,11 +105,14 @@ final class AccessTab implements AdminTab
);
foreach (wp_roles()->get_names() as $role => $name) {
printf(
'<label><input type="checkbox" name="%s[]" value="%s"%s> %s</label><br>',
'<label><input type="checkbox" name="%1$s[]" value="%2$s"%3$s'
. ' aria-describedby="lit-mcp-role-%2$s"> %4$s</label>'
. ' <span class="description" id="lit-mcp-role-%2$s">(%5$s)</span><br>',
esc_attr(Access::OPTION),
esc_attr((string) $role),
checked(in_array($role, $allowed, true), true, false),
esc_html(translate_user_role((string) $name))
esc_html(translate_user_role((string) $name)),
esc_html(self::roleHint((string) $role))
);
}
echo '</fieldset><p class="description">'
@@ -122,6 +125,19 @@ final class AccessTab implements AdminTab
$this->renderConnections();
}
/** What a role may do in WordPress, in one phrase, so the admin sees whom they are letting in. */
private static function roleHint(string $role): string
{
$caps = (array) (((array) wp_roles()->roles)[$role]['capabilities'] ?? []);
return match (true) {
! empty($caps['manage_options']) => __('verwaltet die Website', 'wp-lit-mcp'),
! empty($caps['edit_others_posts']) => __('bearbeitet auch fremde Inhalte', 'wp-lit-mcp'),
! empty($caps['edit_posts']) || ! empty($caps['edit_pages']) => __('bearbeitet Inhalte', 'wp-lit-mcp'),
default => __('keine Bearbeitungsrechte erkannt', 'wp-lit-mcp'),
};
}
public function handleRevoke(): void
{
$this->action->guard();
@@ -240,17 +256,22 @@ final class AccessTab implements AdminTab
echo '<tr>';
echo '<td class="column-user">' . esc_html($connection['user_login']) . '</td>';
$created = (string) wp_date($dateFormat . ' ' . $timeFormat, $connection['created']);
// The "Verbunden am" column is hidden on phones; the date then shows under the client instead.
printf(
'<td class="column-client"><strong>%s</strong><br><span class="lit-mcp-muted">%s</span></td>',
'<td class="column-client"><strong>%s</strong><br><span class="lit-mcp-muted">%s</span>'
. '<br class="lit-mcp-phone-only"><span class="lit-mcp-muted lit-mcp-phone-only">%s</span></td>',
esc_html($connection['name']),
esc_html($connection['app_id'])
);
printf(
'<td class="column-created">%s</td>',
esc_html((string) wp_date($dateFormat . ' ' . $timeFormat, $connection['created']))
esc_html($connection['app_id']),
esc_html(sprintf(
/* translators: %s: date and time */
__('Verbunden am %s', 'wp-lit-mcp'),
$created
))
);
printf('<td class="column-created">%s</td>', esc_html($created));
$lastUsed = $connection['last_used'] === null
? '–'
? __('Noch nie', 'wp-lit-mcp')
: (string) wp_date($dateFormat, $connection['last_used']);
echo '<td class="column-last-used">' . esc_html($lastUsed) . '</td>';
echo '<td class="column-actions">';
@@ -259,17 +280,31 @@ final class AccessTab implements AdminTab
printf('<input type="hidden" name="user_id" value="%s">', esc_attr((string) $connection['user_id']));
printf('<input type="hidden" name="uuid" value="%s">', esc_attr($connection['uuid']));
wp_nonce_field(self::REVOKE_ACTION . '_' . $connection['uuid']);
$confirm = esc_js(sprintf(
/* translators: %s: client name */
__('Verbindung „%s“ widerrufen? Der Assistent muss sich danach neu anmelden.', 'wp-lit-mcp'),
$connection['name']
));
submit_button(
__('Widerrufen', 'wp-lit-mcp'),
'delete small',
'submit',
false,
['onclick' => "return window.confirm('" . $confirm . "');"]
[
// One id per row: submit_button() would give every button the id "submit".
'id' => 'lit-mcp-revoke-' . $connection['uuid'],
// Starts with the visible word (WCAG 2.5.3) and says whose connection it is.
'aria-label' => sprintf(
/* translators: 1: client name, 2: user login */
__('Widerrufen: %1$s, %2$s', 'wp-lit-mcp'),
$connection['name'],
$connection['user_login']
),
'data-lit-mcp-confirm' => sprintf(
/* translators: 1: client name, 2: user login */
__(
'Verbindung „%1$s“ von %2$s widerrufen? Der Assistent muss sich danach neu anmelden.',
'wp-lit-mcp'
),
$connection['name'],
$connection['user_login']
),
]
);
echo '</form></td></tr>';
}