Skip to content

Studio - Add Feedback modal to Studio header - #4223

Open
geodem127 wants to merge 31 commits into
devfrom
feat/4042-studio-feedback-modal
Open

Studio - Add Feedback modal to Studio header#4223
geodem127 wants to merge 31 commits into
devfrom
feat/4042-studio-feedback-modal

Conversation

@geodem127

@geodem127 geodem127 commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

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 sendEmail cloud 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

  • Add sendEmail mutation ({to, from, subject, body, template}) to cloudFunctionsApi
  • Add StudioFeedbackModal component with copy/layout per approved design reference
  • Add "Feedback" button to StudioHeader, wire state/handlers in StudioWrapper
  • Add SLACK_FEEDBACK_EMAIL to all four environment configs and its type declaration
  • Add Cypress spec covering open/disabled/enabled/cancel/submit/error/escaping behavior

Changes since initial review

  • Addressed review comment: switched the email body from a hand-built HTML string with the message interpolated raw (HTML-injection risk) to the sendEmail cloud function's template: "raw" mode
  • Restored the instance ZUID/name, active page, and interaction mode fields to the email body (the issue explicitly asks to "track the user email, instance, the active page & mode that is being edited") — each field is now on its own <br>-separated line with a bold label
  • The raw template 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.
  • Note (unrelated cloud-function bug, not fixed by this PR): the sendEmail cloud 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#242
  • Escaped the email subject line (feedbackName/email) the same as the body — it was previously left unescaped while the body was fully escaped
  • Fixed a Cypress spec bug: the mode-toggle test drove StudioModeToggleOption-layout without 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 in studio-mode.spec.js). Also corrected the plain submit test's default-mode assertion from content to full — the CI account is entitled to both content and layout, so a fresh page load promotes to full mode, not content (same behavior studio-mode.spec.js documents for a staff account).

Testing

  • Cypress: full spec passing locally (7/7), including the corrected mode-toggle and default-mode assertions
  • npx tsc --noEmit: no new errors introduced by this branch
  • Manual Playwright walkthrough of the acceptance steps against the local dev server: button placement/copy, disabled/enabled states, brand color, and cancel/reset behavior all verified. Live Slack delivery could not be verified end-to-end from the local dev sandbox due to zesty-io/gcp-cf#242 (dev-auth tokens rejected by the cloud function's session check even though the app's own /verify confirms 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

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
@github-actions

github-actions Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

QA Review — ✅ PASS

Validates #4042: Studio - Feedback Modal

  1. ✅ Feedback entry point is scoped to the Studio Appbar only, matching the maintainer's explicit "Studio header only" decision — the Feedback button is added solely in StudioHeader.tsx and wired through StudioWrapper.tsx, with no button added to the global topbar.
  2. ✅ Feedback modal matches the requested flow: opens on click, disables submit until text is entered, shows an inline error and preserves the message on failure, and resets/closes on cancel or success.
  3. ✅ Captured payload includes user email, instance (ZUID + name), active page, and interaction mode, satisfying the "track user email, instance, page & mode" requirement.
  4. ⚠️ Delivery mechanism — the issue asked for a Slack channel post with an email fallback to bobby@zesty.io; the thread never confirmed which of the three proposed options (webhook, bot token, or channel-email) was chosen. The PR implements channel-email delivery (SLACK_FEEDBACK_EMAIL in app.config.js) to a Slack channel email address plus bobby@content.one — a plausible read of the unresolved "Option C" proposal, but the exact recipient (content.one vs. the issue's literal zesty.io) and mechanism weren't explicitly ratified in the thread, so this can't be confirmed as intentional from the code alone.
Suggested Cypress coverage

cypress/e2e/studio/studio-feedback-modal.spec.js is already added in this PR and covers the core flow well: opening the modal with expected copy, submit-button disabling until text is entered, cancel resetting the textarea without sending, a successful submit asserting the payload shape (user/instance/page/mode/message), mode capture in both content and layout interaction modes, HTML-escaping of the message body, and an inline error with form re-enablement on a failed send. This looks like solid coverage for the described acceptance criteria; no additional cases are needed beyond what's already in the spec.

@geodem127 geodem127 linked an issue Jul 27, 2026 that may be closed by this pull request
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
@geodem127

Copy link
Copy Markdown
Contributor Author

This is currently blocked, waiting for cloud function updates.

@geodem127 geodem127 self-assigned this Aug 3, 2026
@geodem127 geodem127 added the feature Additional functionality that should be added to Zesty label Aug 3, 2026
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Code Review — ✅ No blockers · 🟡 1 warning(s) — see inline comments

@agalin920

Copy link
Copy Markdown
Contributor

Failing QA Review

Comment thread src/shell/services/cloudFunctions.ts Outdated
Comment thread src/shell/app.config.js
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

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
Comment thread src/apps/studio/components/StudioFeedbackModal.tsx
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

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
Comment thread src/apps/studio/components/StudioFeedbackModal.tsx
Comment thread src/shell/app.config.js
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

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
Comment thread cypress/e2e/studio/studio-feedback-modal.spec.js
Comment thread cypress/e2e/studio/studio-feedback-modal.spec.js
@github-actions

Copy link
Copy Markdown
Contributor

Code Review — 🔴 1 blocker(s) — see inline comments

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Comment thread src/apps/studio/components/StudioFeedbackModal.tsx Outdated
Comment thread src/shell/app.config.js
@github-actions

Copy link
Copy Markdown
Contributor

Code Review — ✅ No blockers · 🟡 2 warnings — see inline comments

Comment thread src/apps/studio/components/StudioFeedbackModal.tsx
Comment thread src/shell/app.config.js
@github-actions

Copy link
Copy Markdown
Contributor

Code Review — ✅ No blockers · 🟡 2 warning(s) — see inline comments

@finnar-bin

Copy link
Copy Markdown
Contributor

@geodem127 please address the negative QA blocker: #4223 (comment)

@geodem127

geodem127 commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

@geodem127 please address the negative QA blocker: #4223 (comment)

  • done. updated prop type

Note: the second click in the reported double-click sequence is landing on the MuiBackdrop, which by default MUI behaviour closes the dialog via onClose. This is normal MUI Backdrop/Dialog behaviour, not a regression specific to this PR.

Comment thread cypress/e2e/studio/studio-feedback-modal.spec.js
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Code Review — 🔴 1 blocker(s) — see inline comments

…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.
Comment thread src/apps/studio/components/StudioFeedbackModal.tsx
Comment thread src/shell/services/cloudFunctions.ts
Comment thread src/shell/app.config.js
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

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.
Comment thread src/apps/studio/components/StudioFeedbackModal.tsx
Comment thread src/apps/studio/components/StudioFeedbackModal.tsx
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Code Review — ✅ No blockers · 🟡 2 warning(s) — see inline comments

Comment thread src/shell/app.config.js
@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Code Review — ✅ No blockers · 🟡 1 warning(s) — see inline comments

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Code Review — ✅ No blockers

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Additional functionality that should be added to Zesty

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Studio - Feedback Modal

3 participants