Studio - Add Feedback modal to Studio header - #4223
Conversation
Adds a "Feedback" entry point to the Studio header that opens a modal for submitting freeform feedback, plus silently-captured context (user email, instance ZUID, active page, interaction mode). Delivered via the existing sendEmail cloud function to the configured Slack channel. Refs #4042
QA Review — ✅ PASSValidates #4042: Studio - Feedback Modal
Suggested Cypress coverage
|
Send feedback as a plain-text raw email instead of building an HTML body, dropping the now-unused instanceZUID/model/item/interactionMode props and their pass-through. Updates specs and SLACK_FEEDBACK_EMAIL formatting accordingly. Refs #4042
|
This is currently blocked, waiting for cloud function updates. |
Code Review — ✅ No blockers · 🟡 1 warning(s) — see inline comments |
|
Failing QA Review |
Code Review — ✅ No blockers · 🟡 2 warning(s) — see inline comments |
…scape message Re-adds the ZUID/name, active page, and interaction mode the issue asked for, bolds each label, and joins lines with <br> since the raw template renders as HTML. Escapes all interpolated values (message, email, instance, page, mode) to close the HTML-injection risk that reintroducing HTML formatting would otherwise reopen. Refs #4042
Code Review — 🔴 1 blocker(s) · 🟡 1 warning(s) — see inline comments |
Fixes the "undefined" literal in the email subject when lastName isn't yet loaded, adds a comment justifying the sendEmail mutation's any return type, and adds Cypress coverage for the layout-mode Mode field. Refs #4042
Code Review — ✅ No blockers · 🟡 2 warning(s) — see inline comments |
Replaces the any placeholder with the actual 200-response shape, now that the cloud function's source confirms it always echoes mailgun-js's send() callback body under msg on success. Refs #4042
escapeHtml() threw a TypeError on undefined, which instance.name/ZUID genuinely are until FETCHING_INSTANCE_SUCCESS fires (instance is any at the state layer, so callers silently bypassed the string prop contract). Coalesce inside escapeHtml so every call site is covered. Refs #4042
Code Review — 🔴 1 blocker(s) — see inline comments |
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Code Review — ✅ No blockers · 🟡 2 warnings — see inline comments |
Code Review — ✅ No blockers · 🟡 2 warning(s) — see inline comments |
|
@geodem127 please address the negative QA blocker: #4223 (comment) |
Note: the second click in the reported double-click sequence is landing on the |
Code Review — 🔴 1 blocker(s) — see inline comments |
…tudio-feedback-modal
…test Ignore backdropClick in handleClose so a fast double-click on the header's Feedback button (open, then a second click landing on the now-covering backdrop) doesn't immediately close the modal it just opened. Escape the email subject the same as the body, closing the gap where user-controlled name/email reached Slack unescaped. In the Cypress spec, stub the staff flag and reload before driving the mode toggle (it only renders for staff users), and correct the default-mode assertion in the plain submit test to "full" — the CI account is entitled to both content and layout, so a fresh load promotes to full mode, not content.
Code Review — ✅ No blockers · 🟡 3 warning(s) — see inline comments |
MUI's Dialog backdrop already sits behind the trigger button, so a second click can't land on it in the same gesture — the guard was solving a problem that doesn't occur.
Code Review — ✅ No blockers · 🟡 2 warning(s) — see inline comments |
Code Review — ✅ No blockers · 🟡 1 warning(s) — see inline comments |
Code Review — ✅ No blockers |
Summary
Adds a "Feedback" entry point to the Studio header that opens a "Share Feedback" modal. Users type freeform feedback, which is submitted via the existing
sendEmailcloud function to the team's configured Slack feedback channel, tagged with the user's email, instance, active page, and edit mode — per the issue's requirement.Changes
sendEmailmutation ({to, from, subject, body, template}) tocloudFunctionsApiStudioFeedbackModalcomponent with copy/layout per approved design referenceStudioHeader, wire state/handlers inStudioWrapperSLACK_FEEDBACK_EMAILto all four environment configs and its type declarationChanges since initial review
sendEmailcloud function'stemplate: "raw"mode<br>-separated line with a bold labelrawtemplate renders HTML (confirmed via live send — bold labels displayed correctly), so every interpolated value (message, email, instance name/ZUID, page, mode) is HTML-escaped before being placed in the body, closing the injection risk that reintroducing HTML formatting would otherwise reopen. A Cypress test asserts a<img onerror=...>payload in the message is escaped rather than sent raw.sendEmailcloud function's session check rejects otherwise-valid dev-auth tokens, which blocked live send verification in the local dev sandbox — tracked at zesty-io/gcp-cf#242feedbackName/email) the same as the body — it was previously left unescaped while the body was fully escapedStudioModeToggleOption-layoutwithout stubbing the staff flag first, so it always timed out for the non-staff CI account (the toggle only renders for staff, matching the pattern instudio-mode.spec.js). Also corrected the plain submit test's default-mode assertion fromcontenttofull— the CI account is entitled to both content and layout, so a fresh page load promotes to full mode, not content (same behaviorstudio-mode.spec.jsdocuments for a staff account).Testing
npx tsc --noEmit: no new errors introduced by this branch/verifyconfirms the same token). Recommend a maintainer with stage/production access do one live click-through before merge to confirm delivery and bold/line-break rendering in the destination Slack channel.Related
Refs #4042
🤖 Generated with Claude Code