Skip to content

feat: feedback record directories#7592

Merged
jobenjada merged 6 commits into
epic/v5from
feat/feedback-record-directories
Mar 27, 2026
Merged

feat: feedback record directories#7592
jobenjada merged 6 commits into
epic/v5from
feat/feedback-record-directories

Conversation

@pandeymangg
Copy link
Copy Markdown
Contributor

@pandeymangg pandeymangg commented Mar 25, 2026

What does this PR do?

Adds the FeedbackRecordDirectory feature for Formbricks 5.0. Organizations can now create and manage multiple feedback record directories (representing Hub tenants) at the org level, with explicit workspace access assignments.

Changes:

  • Data model: Added FeedbackRecordDirectory and FeedbackRecordDirectoryProject (join table) Prisma models with migration
  • CRUD: Full create, update, archive/unarchive flow with server actions, authorization (owner/manager only), and audit logging
  • UI: New "Feedback Directories" org settings page with table, create modal, edit modal (workspace assignment management), and archive/unarchive support
  • Navigation: Added entry to both the org settings navbar and the org breadcrumb dropdown
  • DeleteDialog: Extended with optional title and buttonLabel props to support non-delete confirmation dialogs (e.g. archive)

How should this be tested?

  • Log in as an org owner or manager
  • Navigate to Organization Settings → "Feedback Directories" tab
  • Create a new directory → verify it appears in the list
  • Edit the directory → change name, add/remove workspace assignments → verify save works
  • Archive a directory → verify it disappears from the default list
  • Toggle "Show archived" → verify archived directory appears with "Archived" badge
  • Unarchive an archived directory → verify it returns to active state
  • Log in as a member → verify the "Feedback Directories" tab is hidden in both the navbar and the breadcrumb dropdown
  • Verify the archive confirmation dialog shows "Archive Directory" title and "Archive" button (not "Delete")

Checklist

Required

  • Filled out the "How to test" section in this PR
  • Read How we Code at Formbricks
  • Self-reviewed my own code
  • Commented on my code in hard-to-understand bits
  • Ran pnpm build
  • Checked for warnings, there are none
  • Removed all console.logs
  • Merged the latest changes from main onto my branch with git pull origin main
  • My changes don't cause any responsiveness issues
  • First PR at Formbricks? Please sign the CLA! Without it we wont be able to merge it 🙏

Appreciated

  • If a UI change was made: Added a screen recording or screenshots to this PR
  • Updated the Formbricks Docs if changes were necessary

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 25, 2026

🚨 PR Size Warning

This PR has approximately 1389 lines of changes (1346 additions, 43 deletions across 22 files).

Large PRs (>800 lines) are significantly harder to review and increase the chance of merge conflicts. Consider splitting this into smaller, self-contained PRs.

💡 Suggestions:

  • Split by feature or module - Break down into logical, independent pieces
  • Create a sequence of PRs - Each building on the previous one
  • Branch off PR branches - Don't wait for reviews to continue dependent work

📊 What was counted:

  • ✅ Source files, stylesheets, configuration files
  • ❌ Excluded 15 files (tests, locales, locks, generated files)

📚 Guidelines:

  • Ideal: 300-500 lines per PR
  • Warning: 500-800 lines
  • Critical: 800+ lines ⚠️

If this large PR is unavoidable (e.g., migration, dependency update, major refactor), please explain in the PR description why it couldn't be split.

@pandeymangg pandeymangg marked this pull request as ready for review March 26, 2026 05:59
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 26, 2026

Walkthrough

This pull request introduces a new Feedback Record Directory management feature. Changes include database schema and migration for FeedbackRecordDirectory and FeedbackRecordDirectoryProject tables, navigation entries in organization settings, and a new settings page route at /environments/{environmentId}/settings/feedback-record-directories. Server-side components include authenticated actions for create, retrieve, and update operations with role-based authorization; CRUD functions using Prisma; and Zod type schemas. Client-side components include a creation modal, settings modal with project assignment, and a directory table with management actions. Audit logging support extends to track feedback record directory operations. Minor updates modify button hover state styling, delete dialog title and label customization, and multi-select container styling.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: feedback record directories' follows Conventional Commits and clearly summarizes the main feature addition without unnecessary detail.
Description check ✅ Passed The PR description comprehensively covers what changes were made, provides detailed testing instructions with step-by-step flows, and includes most required checklist items marked complete.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/web/modules/ee/feedback-record-directory/actions.ts`:
- Around line 16-19: The schema ZCreateFeedbackRecordDirectoryAction uses
z.cuid() for organizationId which is inconsistent with other ID fields that use
the shared ZId schema (see directoryId usage); change organizationId to use ZId
instead of z.cuid() and ensure ZId is imported/available in this file so all ID
validations reuse the same shared logic (update the
ZCreateFeedbackRecordDirectoryAction definition to reference ZId for
organizationId).

In
`@apps/web/modules/ee/feedback-record-directory/components/feedback-record-directory-table.tsx`:
- Around line 60-69: The unarchive flow in handleUnarchiveDirectory lacks a
loading state, so wrap the async call to updateFeedbackRecordDirectoryAction in
a boolean state (e.g., isUnarchiving) that you set to true before the await and
false in a finally block; use that state to disable the unarchive button(s) and
optionally show a spinner while the request runs. Update the component state and
the JSX for the unarchive button(s) (also apply same pattern to the manage
action buttons referenced around lines 129-136) so they read
disabled={isUnarchiving} (or similar) and prevent duplicate submissions, keeping
existing toast.success/toast.error and router.refresh behavior. Ensure the state
variable name and the function handleUnarchiveDirectory and
updateFeedbackRecordDirectoryAction are referenced so it's easy to locate and
change.
- Around line 48-58: The Manage handler (handleManageDirectory) issues async
requests without a loading flag, allowing duplicate clicks; add a piece of
component state e.g. loadingDirectoryId: string | null with setter
setLoadingDirectoryId, set it to directoryId before calling
getFeedbackRecordDirectoryDetailsAction and clear it in a finally block so it is
always reset, and use loadingDirectoryId === directory.id to disable the Manage
button and optionally show a spinner while fetching; apply the same pattern to
the other directory-details fetch handler in this file that follows the same
logic (the second occurrence of the fetch/response/setSelectedDirectory flow).

In
`@apps/web/modules/ee/feedback-record-directory/lib/feedback-record-directory.ts`:
- Around line 196-199: The code redundantly fetches the same directory in
buildProjectAssignmentPayload and updateFeedbackRecordDirectory; refactor by
changing buildProjectAssignmentPayload to accept the already-fetched
directory/details (from getFeedbackRecordDirectoryDetails) instead of calling
getFeedbackRecordDirectoryDetails itself, then update
updateFeedbackRecordDirectory to pass the fetched directory (and its projects if
needed) into buildProjectAssignmentPayload and remove the second
fetch/ResourceNotFoundError there; alternatively, if you prefer minimal change,
remove the existence check and getFeedbackRecordDirectoryDetails call inside
buildProjectAssignmentPayload and rely on updateFeedbackRecordDirectory's
validation before calling it.

In
`@apps/web/modules/ee/feedback-record-directory/types/feedback-record-directory.ts`:
- Around line 28-38: The zod schemas ZFeedbackRecordDirectoryCreateInput and
ZFeedbackRecordDirectoryUpdateInput currently use hardcoded user-facing messages
("Directory name is required" and "Directory name must be at least 1 character
long"); replace those literal messages with translatable error keys or codes
(e.g., "error.directory.name_required" / "error.directory.name_too_short") or
remove the custom message and supply a code via the message object so the UI can
look up translations in FormError; update the z.string().min(...) calls in
ZFeedbackRecordDirectoryCreateInput and ZFeedbackRecordDirectoryUpdateInput to
emit those keys instead of English text so the FormError/translation layer can
render localized strings.

In `@apps/web/modules/ui/components/multi-select/index.tsx`:
- Line 33: The default placeholder in the MultiSelect component is a hardcoded
English string; remove the raw string and use react-i18next instead: import
useTranslation from 'react-i18next', call const { t } = useTranslation() inside
the MultiSelect component, and replace the default placeholder = "Select
options..." with placeholder = t('multiSelect.placeholder') (use that
translation key or the project’s agreed key) so all user-facing text goes
through t().

In `@packages/database/schema.prisma`:
- Around line 1037-1048: The FeedbackRecordDirectory model lacks a standalone
index on organizationId which can improve queries like
getFeedbackRecordDirectories that filter solely by organizationId; add a
dedicated index to the model (e.g., using @@index([organizationId])) so database
query planners can efficiently use that column even though
@@unique([organizationId, name]) creates a composite index.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: c029900a-73b9-4e00-b502-24f78855c54a

📥 Commits

Reviewing files that changed from the base of the PR and between 81272b9 and f83cded.

⛔ Files ignored due to path filters (16)
  • apps/web/i18n.lock is excluded by !**/*.lock
  • apps/web/locales/de-DE.json is excluded by !apps/web/locales/**
  • apps/web/locales/en-US.json is excluded by !apps/web/locales/**
  • apps/web/locales/es-ES.json is excluded by !apps/web/locales/**
  • apps/web/locales/fr-FR.json is excluded by !apps/web/locales/**
  • apps/web/locales/hu-HU.json is excluded by !apps/web/locales/**
  • apps/web/locales/ja-JP.json is excluded by !apps/web/locales/**
  • apps/web/locales/nl-NL.json is excluded by !apps/web/locales/**
  • apps/web/locales/pt-BR.json is excluded by !apps/web/locales/**
  • apps/web/locales/pt-PT.json is excluded by !apps/web/locales/**
  • apps/web/locales/ro-RO.json is excluded by !apps/web/locales/**
  • apps/web/locales/ru-RU.json is excluded by !apps/web/locales/**
  • apps/web/locales/sv-SE.json is excluded by !apps/web/locales/**
  • apps/web/locales/zh-Hans-CN.json is excluded by !apps/web/locales/**
  • apps/web/locales/zh-Hant-TW.json is excluded by !apps/web/locales/**
  • packages/surveys/i18n.lock is excluded by !**/*.lock
📒 Files selected for processing (20)
  • apps/web/app/(app)/environments/[environmentId]/components/organization-breadcrumb.tsx
  • apps/web/app/(app)/environments/[environmentId]/settings/(organization)/components/OrganizationSettingsNavbar.tsx
  • apps/web/app/(app)/environments/[environmentId]/settings/(organization)/feedback-record-directories/page.tsx
  • apps/web/lib/utils/action-client/types/context.ts
  • apps/web/modules/ee/audit-logs/lib/handler.ts
  • apps/web/modules/ee/audit-logs/types/audit-log.ts
  • apps/web/modules/ee/feedback-record-directory/actions.ts
  • apps/web/modules/ee/feedback-record-directory/components/create-feedback-record-directory-modal.tsx
  • apps/web/modules/ee/feedback-record-directory/components/feedback-record-directory-settings/archive-feedback-record-directory.tsx
  • apps/web/modules/ee/feedback-record-directory/components/feedback-record-directory-settings/feedback-record-directory-settings-modal.tsx
  • apps/web/modules/ee/feedback-record-directory/components/feedback-record-directory-table.tsx
  • apps/web/modules/ee/feedback-record-directory/components/feedback-record-directory-view.tsx
  • apps/web/modules/ee/feedback-record-directory/lib/feedback-record-directory.ts
  • apps/web/modules/ee/feedback-record-directory/page.tsx
  • apps/web/modules/ee/feedback-record-directory/types/feedback-record-directory.ts
  • apps/web/modules/ui/components/button/index.tsx
  • apps/web/modules/ui/components/delete-dialog/index.tsx
  • apps/web/modules/ui/components/multi-select/index.tsx
  • packages/database/migration/20260325000000_add_feedback_record_directory/migration.sql
  • packages/database/schema.prisma

Comment thread apps/web/modules/ee/feedback-record-directory/actions.ts
Comment thread apps/web/modules/ee/feedback-record-directory/lib/feedback-record-directory.ts Outdated
Comment thread apps/web/modules/ui/components/multi-select/index.tsx Outdated
Comment thread packages/database/schema.prisma
Copy link
Copy Markdown
Member

@Dhruwang Dhruwang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, left some comments to improve code 🙌

Comment thread apps/web/modules/ee/feedback-record-directory/lib/feedback-record-directory.ts Outdated
Comment thread apps/web/modules/ee/feedback-record-directory/lib/feedback-record-directory.ts Outdated
Comment thread apps/web/modules/ee/feedback-record-directory/actions.ts Outdated
@sonarqubecloud
Copy link
Copy Markdown

@jobenjada jobenjada merged commit 029e069 into epic/v5 Mar 27, 2026
16 checks passed
@jobenjada jobenjada deleted the feat/feedback-record-directories branch March 27, 2026 11:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants