B3 — DataForm settings UI#5
Merged
Merged
Conversation
🔍 WordPress Plugin Check Report
📊 Report
|
| 📍 Line | 🔖 Check | 💬 Message |
|---|---|---|
0 |
missing_composer_json_file | The "/vendor" directory using composer exists, but "composer.json" file is missing. |
📁 build/routes.php (12 warnings)
| 📍 Line | 🔖 Check | 💬 Message |
|---|---|---|
14 |
WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound | Global variables defined by a theme/plugin should start with the theme/plugin prefix. Found: "$routes_file". |
19 |
WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound | Global variables defined by a theme/plugin should start with the theme/plugin prefix. Found: "$routes". |
22 |
WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound | Global variables defined by a theme/plugin should start with the theme/plugin prefix. Found: "$routes_by_page". |
23 |
WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound | Global variables defined by a theme/plugin should start with the theme/plugin prefix. Found: "$route". |
24 |
WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound | Global variables defined by a theme/plugin should start with the theme/plugin prefix. Found: "$page_slug". |
26 |
WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound | Global variables defined by a theme/plugin should start with the theme/plugin prefix. Found: "$routes_by_page". |
28 |
WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound | Global variables defined by a theme/plugin should start with the theme/plugin prefix. Found: "$routes_by_page". |
32 |
WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound | Global variables defined by a theme/plugin should start with the theme/plugin prefix. Found: "$page_slug". |
32 |
WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound | Global variables defined by a theme/plugin should start with the theme/plugin prefix. Found: "$page_routes". |
33 |
WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound | Global variables defined by a theme/plugin should start with the theme/plugin prefix. Found: "$page_slug_underscore". |
34 |
WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound | Global variables defined by a theme/plugin should start with the theme/plugin prefix. Found: "$global_name". |
35 |
WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound | Global variables defined by a theme/plugin should start with the theme/plugin prefix. Found: "$$global_name". |
📁 build/build.php (5 warnings)
| 📍 Line | 🔖 Check | 💬 Message |
|---|---|---|
13 |
WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound | Global variables defined by a theme/plugin should start with the theme/plugin prefix. Found: "$modules_file". |
19 |
WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound | Global variables defined by a theme/plugin should start with the theme/plugin prefix. Found: "$scripts_file". |
25 |
WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound | Global variables defined by a theme/plugin should start with the theme/plugin prefix. Found: "$styles_file". |
31 |
WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound | Global variables defined by a theme/plugin should start with the theme/plugin prefix. Found: "$routes_file". |
37 |
WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound | Global variables defined by a theme/plugin should start with the theme/plugin prefix. Found: "$pages_file". |
📁 build/pages/telegram-auth/page-wp-admin.php (1 warning)
| 📍 Line | 🔖 Check | 💬 Message |
|---|---|---|
141 |
WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound | Hook names invoked by a theme/plugin should start with the theme/plugin prefix. Found: "telegram-auth-wp-admin_init". |
📁 build/pages/telegram-auth/page.php (5 warnings)
| 📍 Line | 🔖 Check | 💬 Message |
|---|---|---|
141 |
WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound | Hook names invoked by a theme/plugin should start with the theme/plugin prefix. Found: "telegram-auth_init". |
263 |
WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound | Hook names invoked by a theme/plugin should start with the theme/plugin prefix. Found: "admin_head-{$hook_suffix}". |
270 |
WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound | Hook names invoked by a theme/plugin should start with the theme/plugin prefix. Found: "admin_head". |
284 |
WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound | Hook names invoked by a theme/plugin should start with the theme/plugin prefix. Found: "admin_footer". |
298 |
WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound | Hook names invoked by a theme/plugin should start with the theme/plugin prefix. Found: "admin_footer-{$hook_suffix}". |
🤖 Generated by WordPress Plugin Check Action • Learn more about Plugin Check
manzoorwanijk
added a commit
that referenced
this pull request
May 14, 2026
- Preserve constant-pinned credential values across save: preserveConstants() re-overlays the original (constant-resolved) client_id / client_secret on the REST response, which only returns stored values. Without this, a save flips the disabled credential field from the constant value to the (empty) DB value until reload. - Include the port in the site origin emitted via window.telegramAuthData so Trusted Origins on non-default-port setups (e.g. wp-env's :8888) match what Telegram expects. - Drop the dead Snack.status field — it was set but never threaded through to SnackbarList. - Flatten the "Get it from @Botfather. Read the instructions above." field description into a single translatable string. - Switch the save-error snack to sprintf with a single template, so translators get one string instead of a colon-prefix fragment. - Export diff / preserveConstants / errorMessage and add Jest unit tests covering them. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3d7875b to
584890f
Compare
gmjuhasz
reviewed
May 15, 2026
Contributor
gmjuhasz
left a comment
There was a problem hiding this comment.
This works well, just had some questions/suggestions
A partial REST PATCH from the settings UI should be able to omit a field without blanking the stored value. Merging the incoming payload over defaults — the previous behavior — meant every save had to re-send every field, including the client secret, or it would be silently overwritten. Merge over the currently stored option instead (falling back to defaults when nothing is stored yet). A field omitted from the payload keeps its existing value; an explicit `""` still clears the field. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the placeholder route at routes/telegram-auth/ with a working settings form. The plugin's `register_setting()` already exposes the option through WP core's `/wp/v2/settings`, so saves go through that — no parallel `/telegram-auth/v1/settings` controller. Initial state comes from a `window.telegramAuthData` global Bootstrap inlines at page render. The settings UI reads it synchronously at mount; there's no fetch on load, no spinner, no race window. Save still uses apiFetch since that's a real round-trip, and the response carries the sanitized values back so we can keep the diff baseline accurate. Pieces: - `routes/telegram-auth/types.ts` — TelegramAuthSettings, SettingsMeta, TelegramAuthData, WpSettingsResponse, and the `window.telegramAuthData` global declaration. - `routes/telegram-auth/fields.tsx` — DataForm field set + form layout + the BOT_TOKEN_SHAPE regex. `buildFields(meta)` toggles `isDisabled` on the credential fields when their source is a wp-config constant. - `routes/telegram-auth/settings-app.tsx` — outer guard against missing data global, inner component holds `original` / `draft` state, diffs on every render to drive the Save button, surfaces save/error notices, and shows an inline warning when the entered client_secret matches the Bot API token shape (common BotFather mix-up). - `routes/telegram-auth/stage.tsx` — page chrome that hosts SettingsApp. - `src/Admin/class-settings.php` — splits the source-resolver helper out so `get_client_id_source` (new) and `get_client_secret_source` (renamed from `get_secret_source` for symmetry) share it. Adds `get_all()` returning the full effective settings array with constant overrides applied, so Bootstrap can hand the UI a single source of truth. Drops `'require'` from the email-mode enum — `allow_signups=false` already covers "disable sign-up entirely". - `src/class-bootstrap.php` — `admin_print_scripts-<page>` hook emits the inline data global. wp_json_encode with HEX flags so the inline script is safe regardless of where it lands in the page. Tests: PHPUnit gains coverage for `get_all` (defaults / stored / constant overrides), `get_client_id_source`, and `get_client_secret_source`. Jest smoke covers the fields builder (declaration order, isDisabled toggling per source, BOT_TOKEN_SHAPE match/no-match). Test runner adds a routes/**/__tests__/ glob, picks up `react` as a direct devDep so Jest can resolve `react/jsx-runtime` under the project's `install-strategy=linked` npm setup, and silences ts-jest's node10-moduleResolution deprecation warning (ts-jest forces module=commonjs internally for the Jest runtime). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Walks admins through the OIDC setup with copy-able Redirect URI
and Trusted Origin values, so the existing bot-token-shape warning
("Read the instructions above") has something concrete to point at.
The two values are computed server-side and shipped in the inline
window.telegramAuthData payload.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Splits the DataForm into four card sections (credentials, accounts, permissions, presentation) using the DataForm card layout, wraps the instructions block in its own Card, and adds a subtitle plus a content-width cap so the page no longer reads as a single wall of fields. Moves styling out of inline style props into a route-level SCSS stylesheet picked up by wp-build's route bundler. All inline-axis properties use RTL-aware logical properties (inset-inline-end, padding-inline-start, padding-inline) so the page works in RTL locales unchanged. Save success/error notices now render in a SnackbarList anchored fixed bottom-end, so the Save button (now bottom-start) no longer shifts when a notice appears. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Preserve constant-pinned credential values across save: preserveConstants() re-overlays the original (constant-resolved) client_id / client_secret on the REST response, which only returns stored values. Without this, a save flips the disabled credential field from the constant value to the (empty) DB value until reload. - Include the port in the site origin emitted via window.telegramAuthData so Trusted Origins on non-default-port setups (e.g. wp-env's :8888) match what Telegram expects. - Drop the dead Snack.status field — it was set but never threaded through to SnackbarList. - Flatten the "Get it from @Botfather. Read the instructions above." field description into a single translatable string. - Switch the save-error snack to sprintf with a single template, so translators get one string instead of a colon-prefix fragment. - Export diff / preserveConstants / errorMessage and add Jest unit tests covering them. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Addresses review feedback on #5 (r3246650016): the OIDC client secret shouldn't be readable in window.telegramAuthData, the GET /wp/v2/settings response, or the POST-save echo response, and a save with a blank input or a constant-pinned credential shouldn't be able to overwrite the stored value. Read surfaces: - Settings::get_all() always blanks client_secret regardless of source. - rest_request_after_callbacks filter blanks client_secret on every /wp/v2/settings response (handles both the raw-array shape the settings controller emits and a wrapped WP_REST_Response). - Client Secret field gets a 54-asterisk placeholder so the empty input reads as "something is stored, leave blank to keep". Write guards in Settings::sanitize: - Drop client_secret from the input when it's an empty string — "leave blank to keep" instead of "clear the stored secret". - Drop client_id / client_secret from the input when the matching wp-config constant is defined — managed-elsewhere values must never be persisted to the option row. The auth pipeline still reads the real secret via Settings::get_client_secret() (server-side), so only the UI surfaces are redacted. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Since the secret is redacted on render, leaving the input editable silently invites admins to overwrite the stored value with their own keystrokes. Render the field disabled by default with an "Edit" suffix; clicking Edit enables the input, focuses it, and swaps the suffix for the same eye show/hide toggle DataForm's built-in password control uses (seen/unseen from @wordpress/icons). Also sets autoComplete="new-password" + spellCheck=false so browsers don't autofill or suggest corrections, and updates the non-constant description copy to "Redacted for security. Leave blank to keep the stored value, or click Edit to set a new one." Reorganizes package.json so runtime @wordpress/* and react land under dependencies rather than devDependencies; @wordpress/icons added for the eye toggle. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…anagers After a successful save, bump a savedTick counter that's wired to DataForm's `key` so the form remounts. ClientSecretEdit's internal `editable` state resets to false, restoring the disabled-with-Edit suffix — admins don't see a mysteriously-editable field hanging around after the value has already been stored. Switch autoComplete to "off" and add the well-known per-password- manager opt-out attributes (data-1p-ignore, data-lpignore, data-bwignore, data-form-type="other") so 1Password / LastPass / Bitwarden stop offering autofill on the secret input. Password managers ignore autoComplete="off" on type=password by default, so the data attributes are what actually does the work. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Swaps the Card wrapper for Panel + PanelBody so the BotFather setup walkthrough collapses out of the way once the bot is configured. PanelBody's initialOpen drives the default: open when client_id is empty (fresh install needing setup), closed when it's already populated (admin coming back to tweak unrelated fields). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
584890f to
de5450f
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Completes RSM-3024
Summary
Builds the React/DataForm settings UI for the plugin (RSM-3024).
telegram_auth_settingsoption, grouped into four card sections: bot credentials, new user accounts, optional permissions, sign-in button. Renders synchronously from awindow.telegramAuthDataglobal Bootstrap injects at page render — no fetch on mount. Save batches only the dirty fields to/wp/v2/settings.TELEGRAM_AUTH_CLIENT_IDconstant in PHP" affordance when the wp-config constants are defined. Source flags ride along in the inline payload.Settings::get_all()returns the effective settings with constant overrides applied, so the inline payload is the single source of truth on first render.Look & feel
SnackbarListfixed bottom-end so the button doesn't shift when a notice appears.inset-inline-end,padding-inline-start,padding-inline,padding-block).style.scssthat wp-build's route bundler inlines as a runtime style tag.Test plan
npm run buildSettings → Telegram Authwithout console errors.TELEGRAM_AUTH_CLIENT_ID/TELEGRAM_AUTH_CLIENT_SECRETdefined in wp-config, both credential fields are disabled with the "Managed via … constant in PHP" affordance.123456789:ABC…) into Client Secret shows the inline warning.composer phpcs,composer phpunit,npm run lint:js,npm run lint:css,npm run typecheck,npm test,npm run build.🤖 Generated with Claude Code