@eifi1/ui-kit 0.37.0 → 0.38.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/README.md +11 -4
  2. package/dist/eslint/index.js +1 -1
  3. package/dist/feedback/feedback-comment-thread.d.ts +87 -0
  4. package/dist/feedback/feedback-comment-thread.js +170 -0
  5. package/dist/feedback/feedback-comment-thread.js.map +1 -0
  6. package/dist/feedback/feedback-dialog-labels.js +2 -1
  7. package/dist/feedback/feedback-dialog-labels.js.map +1 -1
  8. package/dist/feedback/feedback-dialog.d.ts +13 -0
  9. package/dist/feedback/feedback-dialog.js +12 -4
  10. package/dist/feedback/feedback-dialog.js.map +1 -1
  11. package/dist/feedback/feedback-labels.d.ts +11 -0
  12. package/dist/feedback/feedback-labels.js +4 -1
  13. package/dist/feedback/feedback-labels.js.map +1 -1
  14. package/dist/feedback/feedback-menu-labels.js +2 -1
  15. package/dist/feedback/feedback-menu-labels.js.map +1 -1
  16. package/dist/feedback/feedback-menu.d.ts +17 -3
  17. package/dist/feedback/feedback-menu.js +11 -1
  18. package/dist/feedback/feedback-menu.js.map +1 -1
  19. package/dist/feedback/feedback-public-labels.d.ts +53 -0
  20. package/dist/feedback/feedback-public-labels.js +27 -0
  21. package/dist/feedback/feedback-public-labels.js.map +1 -0
  22. package/dist/feedback/feedback-public-list.d.ts +139 -0
  23. package/dist/feedback/feedback-public-list.js +299 -0
  24. package/dist/feedback/feedback-public-list.js.map +1 -0
  25. package/dist/feedback/feedback-public-switch.d.ts +51 -0
  26. package/dist/feedback/feedback-public-switch.js +50 -0
  27. package/dist/feedback/feedback-public-switch.js.map +1 -0
  28. package/dist/feedback/feedback-public-types.d.ts +75 -0
  29. package/dist/feedback/feedback-public-types.js +2 -0
  30. package/dist/feedback/feedback-public-types.js.map +1 -0
  31. package/dist/feedback/feedback-record.d.ts +32 -1
  32. package/dist/feedback/feedback-record.js +10 -0
  33. package/dist/feedback/feedback-record.js.map +1 -1
  34. package/dist/feedback/feedback-replies-context.d.ts +7 -0
  35. package/dist/feedback/feedback-replies-context.js +7 -0
  36. package/dist/feedback/feedback-replies-context.js.map +1 -0
  37. package/dist/feedback/feedback-replies.d.ts +97 -0
  38. package/dist/feedback/feedback-replies.js +114 -0
  39. package/dist/feedback/feedback-replies.js.map +1 -0
  40. package/dist/feedback/feedback-row-detail-labels.js +1 -0
  41. package/dist/feedback/feedback-row-detail-labels.js.map +1 -1
  42. package/dist/feedback/feedback-row-detail.d.ts +47 -10
  43. package/dist/feedback/feedback-row-detail.js +51 -50
  44. package/dist/feedback/feedback-row-detail.js.map +1 -1
  45. package/dist/feedback/feedback-submit-dialog.d.ts +3 -1
  46. package/dist/feedback/feedback-submit-dialog.js +6 -1
  47. package/dist/feedback/feedback-submit-dialog.js.map +1 -1
  48. package/dist/feedback/feedback-submit.d.ts +8 -0
  49. package/dist/feedback/feedback-submit.js +3 -2
  50. package/dist/feedback/feedback-submit.js.map +1 -1
  51. package/dist/feedback/feedback-table.d.ts +15 -5
  52. package/dist/feedback/feedback-table.js +46 -5
  53. package/dist/feedback/feedback-table.js.map +1 -1
  54. package/dist/feedback/feedback-thread-parts-labels.d.ts +6 -0
  55. package/dist/feedback/feedback-thread-parts-labels.js +36 -0
  56. package/dist/feedback/feedback-thread-parts-labels.js.map +1 -0
  57. package/dist/feedback/feedback-thread.d.ts +8 -0
  58. package/dist/feedback/feedback-thread.js +7 -2
  59. package/dist/feedback/feedback-thread.js.map +1 -1
  60. package/dist/feedback/feedback-vote-button.d.ts +49 -0
  61. package/dist/feedback/feedback-vote-button.js +72 -0
  62. package/dist/feedback/feedback-vote-button.js.map +1 -0
  63. package/dist/feedback.d.ts +6 -0
  64. package/dist/feedback.js +6 -0
  65. package/dist/feedback.js.map +1 -1
  66. package/dist/i18n/defaults.js +12 -0
  67. package/dist/i18n/defaults.js.map +1 -1
  68. package/dist/i18n/german.js +69 -3
  69. package/dist/i18n/german.js.map +1 -1
  70. package/dist/i18n/kit-labels.d.ts +16 -0
  71. package/dist/i18n/kit-labels.js.map +1 -1
  72. package/dist/i18n/locales/en.js +85 -3
  73. package/dist/i18n/locales/en.js.map +3 -3
  74. package/dist/i18n/locales/es.js +69 -3
  75. package/dist/i18n/locales/es.js.map +1 -1
  76. package/dist/i18n/locales/fr.js +69 -3
  77. package/dist/i18n/locales/fr.js.map +1 -1
  78. package/dist/i18n/locales/hu.js +69 -3
  79. package/dist/i18n/locales/hu.js.map +1 -1
  80. package/dist/i18n/locales/it.js +69 -3
  81. package/dist/i18n/locales/it.js.map +1 -1
  82. package/dist/i18n/locales/zh.js +69 -3
  83. package/dist/i18n/locales/zh.js.map +1 -1
  84. package/dist/i18n/review.js +5 -0
  85. package/dist/i18n/review.js.map +1 -1
  86. package/dist/index.d.ts +2 -0
  87. package/dist/index.js +6 -0
  88. package/dist/index.js.map +1 -1
  89. package/dist/notifications/feedback-notification-types-labels.d.ts +15 -0
  90. package/dist/notifications/feedback-notification-types-labels.js +11 -0
  91. package/dist/notifications/feedback-notification-types-labels.js.map +1 -0
  92. package/dist/notifications/feedback-notification-types.d.ts +28 -0
  93. package/dist/notifications/feedback-notification-types.js +21 -0
  94. package/dist/notifications/feedback-notification-types.js.map +1 -0
  95. package/package.json +1 -1
  96. package/src/feedback/feedback-comment-thread.tsx +277 -0
  97. package/src/feedback/feedback-dialog-labels.ts +1 -0
  98. package/src/feedback/feedback-dialog.tsx +30 -2
  99. package/src/feedback/feedback-labels.ts +14 -0
  100. package/src/feedback/feedback-menu-labels.ts +1 -0
  101. package/src/feedback/feedback-menu.tsx +29 -3
  102. package/src/feedback/feedback-public-labels.ts +80 -0
  103. package/src/feedback/feedback-public-list.tsx +478 -0
  104. package/src/feedback/feedback-public-switch.tsx +102 -0
  105. package/src/feedback/feedback-public-types.ts +82 -0
  106. package/src/feedback/feedback-record.ts +39 -1
  107. package/src/feedback/feedback-replies-context.ts +9 -0
  108. package/src/feedback/feedback-replies.tsx +235 -0
  109. package/src/feedback/feedback-row-detail-labels.ts +1 -0
  110. package/src/feedback/feedback-row-detail.tsx +115 -74
  111. package/src/feedback/feedback-submit-dialog.tsx +9 -0
  112. package/src/feedback/feedback-submit.tsx +10 -1
  113. package/src/feedback/feedback-table.tsx +73 -6
  114. package/src/feedback/feedback-thread-parts-labels.ts +41 -0
  115. package/src/feedback/feedback-thread.tsx +18 -1
  116. package/src/feedback/feedback-vote-button.tsx +123 -0
  117. package/src/feedback.ts +10 -0
  118. package/src/i18n/defaults.ts +12 -0
  119. package/src/i18n/german.ts +66 -0
  120. package/src/i18n/kit-labels.tsx +16 -0
  121. package/src/i18n/locales/en.ts +8 -0
  122. package/src/i18n/locales/es.ts +66 -0
  123. package/src/i18n/locales/fr.ts +66 -0
  124. package/src/i18n/locales/hu.ts +66 -0
  125. package/src/i18n/locales/it.ts +66 -0
  126. package/src/i18n/locales/zh.ts +66 -0
  127. package/src/i18n/review.ts +5 -0
  128. package/src/index.ts +9 -0
  129. package/src/notifications/feedback-notification-types-labels.ts +24 -0
  130. package/src/notifications/feedback-notification-types.ts +46 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/feedback/feedback-labels.ts"],"sourcesContent":["import { useKitLabels, type LabelOverride } from \"../i18n/kit-labels\";\nimport type { FeedbackCategory, FeedbackStatus } from \"./feedback-vocabulary\";\n\n/**\n * The words of a report's status and category, and the toasts a feedback page shows —\n * three `<UiKitProvider labels>` namespaces (0.27.0).\n *\n * Until 0.27 every app kept its own map from the enum to a translation key (keksdose\n * `STATUS_LABEL` and `categoryLabelKey`, \"the package has no translations\"), and the\n * three German maps had drifted apart: Kurvenschmiede said \"In Arbeit\", \"In Prüfung\",\n * \"Test auf der Live-Umgebung\" where keksdose and kastlan said \"In Bearbeitung\",\n * \"Zur Prüfung\", \"Live testen\". Marcel's feedback round (2026-10-04,\n * docs/feedback-harmonization.md §2.4) made keksdose's wording the canon and the kit its\n * owner, in all seven languages. The English defaults below are keksdose's\n * `frontend/src/shared/i18n/locales/en.json` (`feedback.*`); the de-CH canon for the\n * catalogues is noted on each key (keksdose `de-CH.json` — ss, never ß).\n *\n * `FeedbackStatusBadge`, `FeedbackCategoryBadge` and `FeedbackStatusTransitions` read\n * the first two by default, so an app drops its own maps; a `label` passed to them still\n * wins.\n */\n\n/**\n * `feedbackStatus` — one word per status, keyed by the enum value so\n * `labels[row.status]` is the whole lookup.\n *\n * de-CH canon: OPEN \"Offen\" · READY \"Bereit zur Umsetzung\" · IN_PROGRESS \"In Bearbeitung\" · IN_EVALUATION \"Zur Prüfung\"\n * · NEEDS_LIVE_TEST \"Live testen\" · POSTPONED \"Zurückgestellt\" · DONE \"Erledigt\" ·\n * WONT_DO \"Wird nicht umgesetzt\".\n */\nexport type FeedbackStatusLabels = Record<FeedbackStatus, string>;\n\nexport const DEFAULT_FEEDBACK_STATUS_LABELS: FeedbackStatusLabels = {\n OPEN: \"Open\",\n READY: \"Ready to implement\",\n IN_PROGRESS: \"In progress\",\n IN_EVALUATION: \"In evaluation\",\n NEEDS_LIVE_TEST: \"Test when live\",\n POSTPONED: \"Postponed\",\n DONE: \"Done\",\n WONT_DO: \"Won't do\",\n};\n\n/**\n * `feedbackCategory` — one word per category, keyed by the enum value. `CRASH` is never\n * pickable, but it is shown: on the badge, in the filter, in a row's detail.\n *\n * de-CH canon: CRASH \"Absturz\" · BUG \"Fehler\" · IDEA \"Idee\" · QUESTION \"Frage\" ·\n * OTHER \"Sonstiges\".\n */\nexport type FeedbackCategoryLabels = Record<FeedbackCategory, string>;\n\nexport const DEFAULT_FEEDBACK_CATEGORY_LABELS: FeedbackCategoryLabels = {\n CRASH: \"Crash\",\n BUG: \"Bug\",\n IDEA: \"Idea\",\n QUESTION: \"Question\",\n OTHER: \"Other\",\n};\n\n/**\n * `feedbackToast` — what the submit dialog, a failed save and a status change say in a\n * toast (§4.2, §4.4, §4.5 of the contract). A server's `detail` sentence, when it sent\n * one, wins over `submitFailed` and `updateFailed` (§3.7); that choice is the caller's.\n */\nexport interface FeedbackToastLabels {\n /** A report was filed. de-CH: \"Danke für Ihr Feedback!\" */\n submitted: string;\n /** `POST /feedback` failed with no `detail` of its own.\n * de-CH: \"Feedback konnte nicht gesendet werden\" */\n submitFailed: string;\n /** A picked file is not an image, a PDF or a text file (§3.5).\n * de-CH: \"Nur Bilder, PDF- oder Textdateien sind erlaubt\" */\n attachmentUnsupported: string;\n /** A picked file is over the 10 MB the contract allows (§3.5).\n * de-CH: \"Datei ist grösser als 10 MB\" */\n attachmentTooLarge: string;\n /** More files were picked than fit; `count` is how many fit.\n * de-CH: \"Es passen nur {{count}} Anhänge – die übrigen wurden weggelassen.\" */\n attachmentTooMany: (count: number) => string;\n /** The screenshot capture failed (or its optional peer is not installed).\n * de-CH: \"Screenshot konnte nicht aufgenommen werden\" */\n captureFailed: string;\n /** A `PATCH /feedback/{id}` failed with no `detail` of its own (§4.4).\n * de-CH: \"Änderung konnte nicht gespeichert werden.\" */\n updateFailed: string;\n /** A status change landed — the 8 s Undo toast (§4.5). `status` is the NEW status's\n * label, `title` the report's title. de-CH: \"Auf „{{status}}“ gesetzt: {{title}}\" */\n statusChanged: (status: string, title: string) => string;\n /** That toast's action. de-CH: \"Rückgängig\" */\n statusUndo: string;\n /** The Undo landed — `status` is the RESTORED status's label.\n * de-CH: \"Zurück auf „{{status}}“: {{title}}\" */\n statusRestored: (status: string, title: string) => string;\n}\n\nexport const DEFAULT_FEEDBACK_TOAST_LABELS: FeedbackToastLabels = {\n submitted: \"Thanks for the feedback!\",\n submitFailed: \"Could not submit feedback\",\n attachmentUnsupported: \"Only images, PDF or text files are allowed\",\n attachmentTooLarge: \"File is larger than 10 MB\",\n attachmentTooMany: (count) =>\n count === 1\n ? \"Only 1 attachment fits — the rest were left out.\"\n : `Only ${count} attachments fit — the rest were left out.`,\n captureFailed: \"Could not capture a screenshot\",\n updateFailed: \"Could not save that change.\",\n statusChanged: (status, title) => `Set to “${status}”: ${title}`,\n statusUndo: \"Undo\",\n statusRestored: (status, title) => `Back to “${status}”: ${title}`,\n};\n\n/** `feedbackStatus` resolved: English, then `<UiKitProvider labels>`, then `labels`. For\n * the places that need a status's name outside the kit's own parts — a filter's options,\n * `feedbackSwipePlan`'s panels, an app's overview tile. */\nexport function useFeedbackStatusLabels(labels?: LabelOverride<FeedbackStatusLabels>): FeedbackStatusLabels {\n return useKitLabels(\"feedbackStatus\", DEFAULT_FEEDBACK_STATUS_LABELS, labels);\n}\n\n/** `feedbackCategory` resolved: English, then the provider, then `labels`. */\nexport function useFeedbackCategoryLabels(labels?: LabelOverride<FeedbackCategoryLabels>): FeedbackCategoryLabels {\n return useKitLabels(\"feedbackCategory\", DEFAULT_FEEDBACK_CATEGORY_LABELS, labels);\n}\n\n/** `feedbackToast` resolved: English, then the provider, then `labels`. */\nexport function useFeedbackToastLabels(labels?: LabelOverride<FeedbackToastLabels>): FeedbackToastLabels {\n return useKitLabels(\"feedbackToast\", DEFAULT_FEEDBACK_TOAST_LABELS, labels);\n}\n"],"mappings":";AAAA,SAAS,oBAAwC;AAgC1C,MAAM,iCAAuD;AAAA,EAClE,MAAM;AAAA,EACN,OAAO;AAAA,EACP,aAAa;AAAA,EACb,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB,WAAW;AAAA,EACX,MAAM;AAAA,EACN,SAAS;AACX;AAWO,MAAM,mCAA2D;AAAA,EACtE,OAAO;AAAA,EACP,KAAK;AAAA,EACL,MAAM;AAAA,EACN,UAAU;AAAA,EACV,OAAO;AACT;AAsCO,MAAM,gCAAqD;AAAA,EAChE,WAAW;AAAA,EACX,cAAc;AAAA,EACd,uBAAuB;AAAA,EACvB,oBAAoB;AAAA,EACpB,mBAAmB,CAAC,UAClB,UAAU,IACN,0DACA,QAAQ,KAAK;AAAA,EACnB,eAAe;AAAA,EACf,cAAc;AAAA,EACd,eAAe,CAAC,QAAQ,UAAU,gBAAW,MAAM,WAAM,KAAK;AAAA,EAC9D,YAAY;AAAA,EACZ,gBAAgB,CAAC,QAAQ,UAAU,iBAAY,MAAM,WAAM,KAAK;AAClE;AAKO,SAAS,wBAAwB,QAAoE;AAC1G,SAAO,aAAa,kBAAkB,gCAAgC,MAAM;AAC9E;AAGO,SAAS,0BAA0B,QAAwE;AAChH,SAAO,aAAa,oBAAoB,kCAAkC,MAAM;AAClF;AAGO,SAAS,uBAAuB,QAAkE;AACvG,SAAO,aAAa,iBAAiB,+BAA+B,MAAM;AAC5E;","names":[]}
1
+ {"version":3,"sources":["../../src/feedback/feedback-labels.ts"],"sourcesContent":["import { useKitLabels, type LabelOverride } from \"../i18n/kit-labels\";\nimport type { FeedbackCategory, FeedbackStatus } from \"./feedback-vocabulary\";\n\n/**\n * The words of a report's status and category, and the toasts a feedback page shows —\n * three `<UiKitProvider labels>` namespaces (0.27.0).\n *\n * Until 0.27 every app kept its own map from the enum to a translation key (keksdose\n * `STATUS_LABEL` and `categoryLabelKey`, \"the package has no translations\"), and the\n * three German maps had drifted apart: Kurvenschmiede said \"In Arbeit\", \"In Prüfung\",\n * \"Test auf der Live-Umgebung\" where keksdose and kastlan said \"In Bearbeitung\",\n * \"Zur Prüfung\", \"Live testen\". Marcel's feedback round (2026-10-04,\n * docs/feedback-harmonization.md §2.4) made keksdose's wording the canon and the kit its\n * owner, in all seven languages. The English defaults below are keksdose's\n * `frontend/src/shared/i18n/locales/en.json` (`feedback.*`); the de-CH canon for the\n * catalogues is noted on each key (keksdose `de-CH.json` — ss, never ß).\n *\n * `FeedbackStatusBadge`, `FeedbackCategoryBadge` and `FeedbackStatusTransitions` read\n * the first two by default, so an app drops its own maps; a `label` passed to them still\n * wins.\n */\n\n/**\n * `feedbackStatus` — one word per status, keyed by the enum value so\n * `labels[row.status]` is the whole lookup.\n *\n * de-CH canon: OPEN \"Offen\" · READY \"Bereit zur Umsetzung\" · IN_PROGRESS \"In Bearbeitung\" · IN_EVALUATION \"Zur Prüfung\"\n * · NEEDS_LIVE_TEST \"Live testen\" · POSTPONED \"Zurückgestellt\" · DONE \"Erledigt\" ·\n * WONT_DO \"Wird nicht umgesetzt\".\n */\nexport type FeedbackStatusLabels = Record<FeedbackStatus, string>;\n\nexport const DEFAULT_FEEDBACK_STATUS_LABELS: FeedbackStatusLabels = {\n OPEN: \"Open\",\n READY: \"Ready to implement\",\n IN_PROGRESS: \"In progress\",\n IN_EVALUATION: \"In evaluation\",\n NEEDS_LIVE_TEST: \"Test when live\",\n POSTPONED: \"Postponed\",\n DONE: \"Done\",\n WONT_DO: \"Won't do\",\n};\n\n/**\n * `feedbackCategory` — one word per category, keyed by the enum value. `CRASH` is never\n * pickable, but it is shown: on the badge, in the filter, in a row's detail.\n *\n * de-CH canon: CRASH \"Absturz\" · BUG \"Fehler\" · IDEA \"Idee\" · QUESTION \"Frage\" ·\n * OTHER \"Sonstiges\".\n */\nexport type FeedbackCategoryLabels = Record<FeedbackCategory, string>;\n\nexport const DEFAULT_FEEDBACK_CATEGORY_LABELS: FeedbackCategoryLabels = {\n CRASH: \"Crash\",\n BUG: \"Bug\",\n IDEA: \"Idea\",\n QUESTION: \"Question\",\n OTHER: \"Other\",\n};\n\n/**\n * `feedbackToast` — what the submit dialog, a failed save and a status change say in a\n * toast (§4.2, §4.4, §4.5 of the contract). A server's `detail` sentence, when it sent\n * one, wins over `submitFailed` and `updateFailed` (§3.7); that choice is the caller's.\n */\nexport interface FeedbackToastLabels {\n /** A report was filed. de-CH: \"Danke für Ihr Feedback!\" */\n submitted: string;\n /** `POST /feedback` failed with no `detail` of its own.\n * de-CH: \"Feedback konnte nicht gesendet werden\" */\n submitFailed: string;\n /** A picked file is not an image, a PDF or a text file (§3.5).\n * de-CH: \"Nur Bilder, PDF- oder Textdateien sind erlaubt\" */\n attachmentUnsupported: string;\n /** A picked file is over the 10 MB the contract allows (§3.5).\n * de-CH: \"Datei ist grösser als 10 MB\" */\n attachmentTooLarge: string;\n /** More files were picked than fit; `count` is how many fit.\n * de-CH: \"Es passen nur {{count}} Anhänge – die übrigen wurden weggelassen.\" */\n attachmentTooMany: (count: number) => string;\n /** The screenshot capture failed (or its optional peer is not installed).\n * de-CH: \"Screenshot konnte nicht aufgenommen werden\" */\n captureFailed: string;\n /** A `PATCH /feedback/{id}` failed with no `detail` of its own (§4.4).\n * de-CH: \"Änderung konnte nicht gespeichert werden.\" */\n updateFailed: string;\n /** A status change landed — the 8 s Undo toast (§4.5). `status` is the NEW status's\n * label, `title` the report's title. de-CH: \"Auf „{{status}}“ gesetzt: {{title}}\" */\n statusChanged: (status: string, title: string) => string;\n /** That toast's action. de-CH: \"Rückgängig\" */\n statusUndo: string;\n /** The Undo landed — `status` is the RESTORED status's label.\n * de-CH: \"Zurück auf „{{status}}“: {{title}}\" */\n statusRestored: (status: string, title: string) => string;\n /** 0.38.1: `POST /feedback/{id}/comments` failed with no `detail` of its own — for\n * `FeedbackCommentThread`'s `onComment`. de-CH: \"Kommentar konnte nicht gesendet\n * werden.\" */\n commentFailed: string;\n /** 0.38.1: `PUT` / `DELETE /feedback/{id}/vote` failed with no `detail` of its own —\n * for `FeedbackVoteButton`'s `onVote` (the button rolls back; the app toasts).\n * de-CH: \"Stimme konnte nicht gespeichert werden.\" */\n voteFailed: string;\n /** 0.38.1: `POST /feedback/{id}/replies` failed with no `detail` of its own — for\n * `FeedbackRowDetail`'s `onReply`. de-CH: \"Antwort konnte nicht gesendet werden.\" */\n replyFailed: string;\n}\n\nexport const DEFAULT_FEEDBACK_TOAST_LABELS: FeedbackToastLabels = {\n submitted: \"Thanks for the feedback!\",\n submitFailed: \"Could not submit feedback\",\n attachmentUnsupported: \"Only images, PDF or text files are allowed\",\n attachmentTooLarge: \"File is larger than 10 MB\",\n attachmentTooMany: (count) =>\n count === 1\n ? \"Only 1 attachment fits — the rest were left out.\"\n : `Only ${count} attachments fit — the rest were left out.`,\n captureFailed: \"Could not capture a screenshot\",\n updateFailed: \"Could not save that change.\",\n statusChanged: (status, title) => `Set to “${status}”: ${title}`,\n statusUndo: \"Undo\",\n statusRestored: (status, title) => `Back to “${status}”: ${title}`,\n commentFailed: \"Could not post the comment.\",\n voteFailed: \"Could not save your vote.\",\n replyFailed: \"Could not send the reply.\",\n};\n\n/** `feedbackStatus` resolved: English, then `<UiKitProvider labels>`, then `labels`. For\n * the places that need a status's name outside the kit's own parts — a filter's options,\n * `feedbackSwipePlan`'s panels, an app's overview tile. */\nexport function useFeedbackStatusLabels(labels?: LabelOverride<FeedbackStatusLabels>): FeedbackStatusLabels {\n return useKitLabels(\"feedbackStatus\", DEFAULT_FEEDBACK_STATUS_LABELS, labels);\n}\n\n/** `feedbackCategory` resolved: English, then the provider, then `labels`. */\nexport function useFeedbackCategoryLabels(labels?: LabelOverride<FeedbackCategoryLabels>): FeedbackCategoryLabels {\n return useKitLabels(\"feedbackCategory\", DEFAULT_FEEDBACK_CATEGORY_LABELS, labels);\n}\n\n/** `feedbackToast` resolved: English, then the provider, then `labels`. */\nexport function useFeedbackToastLabels(labels?: LabelOverride<FeedbackToastLabels>): FeedbackToastLabels {\n return useKitLabels(\"feedbackToast\", DEFAULT_FEEDBACK_TOAST_LABELS, labels);\n}\n"],"mappings":";AAAA,SAAS,oBAAwC;AAgC1C,MAAM,iCAAuD;AAAA,EAClE,MAAM;AAAA,EACN,OAAO;AAAA,EACP,aAAa;AAAA,EACb,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB,WAAW;AAAA,EACX,MAAM;AAAA,EACN,SAAS;AACX;AAWO,MAAM,mCAA2D;AAAA,EACtE,OAAO;AAAA,EACP,KAAK;AAAA,EACL,MAAM;AAAA,EACN,UAAU;AAAA,EACV,OAAO;AACT;AAiDO,MAAM,gCAAqD;AAAA,EAChE,WAAW;AAAA,EACX,cAAc;AAAA,EACd,uBAAuB;AAAA,EACvB,oBAAoB;AAAA,EACpB,mBAAmB,CAAC,UAClB,UAAU,IACN,0DACA,QAAQ,KAAK;AAAA,EACnB,eAAe;AAAA,EACf,cAAc;AAAA,EACd,eAAe,CAAC,QAAQ,UAAU,gBAAW,MAAM,WAAM,KAAK;AAAA,EAC9D,YAAY;AAAA,EACZ,gBAAgB,CAAC,QAAQ,UAAU,iBAAY,MAAM,WAAM,KAAK;AAAA,EAChE,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,aAAa;AACf;AAKO,SAAS,wBAAwB,QAAoE;AAC1G,SAAO,aAAa,kBAAkB,gCAAgC,MAAM;AAC9E;AAGO,SAAS,0BAA0B,QAAwE;AAChH,SAAO,aAAa,oBAAoB,kCAAkC,MAAM;AAClF;AAGO,SAAS,uBAAuB,QAAkE;AACvG,SAAO,aAAa,iBAAiB,+BAA+B,MAAM;AAC5E;","names":[]}
@@ -2,7 +2,8 @@
2
2
  const DEFAULT_FEEDBACK_MENU_LABELS = {
3
3
  trigger: "Send feedback",
4
4
  myFeedback: "My feedback",
5
- viewFeedback: "View feedback"
5
+ viewFeedback: "View feedback",
6
+ allFeedback: "All feedback"
6
7
  };
7
8
  export {
8
9
  DEFAULT_FEEDBACK_MENU_LABELS
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/feedback/feedback-menu-labels.ts"],"sourcesContent":["// The English words of ./feedback-menu, in a module with no component code: the English\n// catalogue (src/i18n/defaults.ts) imports them without the component, so `en` loads as one\n// chunk like the other languages (0.34, KS U8). ./feedback-menu re-exports them.\n\nimport type { FeedbackMenuLabels } from \"./feedback-menu\";\n\nexport const DEFAULT_FEEDBACK_MENU_LABELS: FeedbackMenuLabels = {\n trigger: \"Send feedback\",\n myFeedback: \"My feedback\",\n viewFeedback: \"View feedback\",\n};\n"],"mappings":";AAMO,MAAM,+BAAmD;AAAA,EAC9D,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,cAAc;AAChB;","names":[]}
1
+ {"version":3,"sources":["../../src/feedback/feedback-menu-labels.ts"],"sourcesContent":["// The English words of ./feedback-menu, in a module with no component code: the English\n// catalogue (src/i18n/defaults.ts) imports them without the component, so `en` loads as one\n// chunk like the other languages (0.34, KS U8). ./feedback-menu re-exports them.\n\nimport type { FeedbackMenuLabels } from \"./feedback-menu\";\n\nexport const DEFAULT_FEEDBACK_MENU_LABELS: FeedbackMenuLabels = {\n trigger: \"Send feedback\",\n myFeedback: \"My feedback\",\n viewFeedback: \"View feedback\",\n allFeedback: \"All feedback\",\n};\n"],"mappings":";AAMO,MAAM,+BAAmD;AAAA,EAC9D,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,aAAa;AACf;","names":[]}
@@ -19,6 +19,10 @@ export interface FeedbackMenuLabels {
19
19
  /** The link to the inbox — an admin's one list link, in place of "My feedback".
20
20
  * keksdose `feedback.view_all`. */
21
21
  viewFeedback: string;
22
+ /** The link to every public report, {@link FeedbackMenuProps.publicHref} (0.38,
23
+ * docs/feedback-harmonization.md §9.2 decision 21). Optional, so a complete
24
+ * `UiKitLabels` typed before 0.38 still compiles. de-CH "Alle Rückmeldungen". */
25
+ allFeedback?: string;
22
26
  }
23
27
  export { DEFAULT_FEEDBACK_MENU_LABELS };
24
28
  export interface FeedbackMenuProps {
@@ -34,7 +38,7 @@ export interface FeedbackMenuProps {
34
38
  * `Sparkles` Help assistant → `/assistant` and `MessagesSquare` Support chat →
35
39
  * `/support` with its unread chip. Any {@link TopBarMenuEntry}; keep their `key`s clear
36
40
  * of the menu's own (`BUG`, `IDEA`, `QUESTION`, `OTHER`, `feedback-divider`,
37
- * `my-feedback`, `view-feedback`).
41
+ * `all-feedback`, `my-feedback`, `view-feedback`).
38
42
  */
39
43
  extraEntries?: TopBarMenuEntry[];
40
44
  /** The user's own reports, linked for everyone but an admin. Default `"/my-feedback"`
@@ -42,6 +46,15 @@ export interface FeedbackMenuProps {
42
46
  myFeedbackHref?: string;
43
47
  /** The admin inbox, linked for an admin. Default `"/feedback"` (§2.3). */
44
48
  inboxHref?: string;
49
+ /**
50
+ * The public list (0.38, docs/feedback-harmonization.md §9.2 decision 21): when passed,
51
+ * an **All feedback** row (`Users`, key `all-feedback`) above the list link, for
52
+ * everyone — the admin too, who reads what the others read there. keksdose:
53
+ * `"/all-feedback"`; "My feedback" stays as it is. Leave it out where the app has no
54
+ * public parts (kastlan) or the viewer may not see them (a Kurvenschmiede customer, a
55
+ * demo — §9.2 decisions 7, 8).
56
+ */
57
+ publicHref?: string;
45
58
  /** A dot on the trigger — keksdose's unread support replies (`tone: "danger"`). Its
46
59
  * `label` joins the trigger's name ("Send feedback 2 unread"). The words are the app's. */
47
60
  iconBadge?: UserAvatarBadge | null;
@@ -60,7 +73,8 @@ export interface FeedbackMenuProps {
60
73
  * the category badges' own glyphs), each calling `onFile(category)`;
61
74
  * 3. a divider, always;
62
75
  * 4. the app's `extraEntries`;
63
- * 5. ONE list link, `Inbox`: an admin's is "View feedback" → `/feedback`, everyone
76
+ * 5. with `publicHref` (0.38), **All feedback** → the public list, for everyone;
77
+ * 6. ONE list link, `Inbox`: an admin's is "View feedback" → `/feedback`, everyone
64
78
  * else's "My feedback" → `/my-feedback` — keksdose's (`top-bar.tsx:205-214`, feedback
65
79
  * #331: admins get the management view, everyone else their own submissions).
66
80
  *
@@ -80,4 +94,4 @@ export interface FeedbackMenuProps {
80
94
  * tour anchor (`data-tour="feedback-menu"`) stays on a wrapping `<span>`. Needs a router,
81
95
  * as every `TopBarActionMenu` with link rows does.
82
96
  */
83
- export declare function FeedbackMenu({ onFile, isAdmin, extraEntries, myFeedbackHref, inboxHref, iconBadge, labels: labelsProp, align, }: FeedbackMenuProps): import("react").JSX.Element;
97
+ export declare function FeedbackMenu({ onFile, isAdmin, extraEntries, myFeedbackHref, inboxHref, publicHref, iconBadge, labels: labelsProp, align, }: FeedbackMenuProps): import("react").JSX.Element;
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { jsx } from "react/jsx-runtime";
3
- import { Inbox, MessageSquare } from "lucide-react";
3
+ import { Inbox, MessageSquare, Users } from "lucide-react";
4
4
  import { useKitLabels } from "../i18n/kit-labels.js";
5
5
  import { TopBarActionMenu } from "../shell/topbar-action-menu.js";
6
6
  import { FEEDBACK_CATEGORY_META } from "./feedback-vocabulary.js";
@@ -13,6 +13,7 @@ function FeedbackMenu({
13
13
  extraEntries,
14
14
  myFeedbackHref = "/my-feedback",
15
15
  inboxHref = "/feedback",
16
+ publicHref,
16
17
  iconBadge,
17
18
  labels: labelsProp,
18
19
  align
@@ -31,6 +32,15 @@ function FeedbackMenu({
31
32
  }),
32
33
  { kind: "divider", key: "feedback-divider" },
33
34
  ...extraEntries ?? [],
35
+ ...publicHref ? [
36
+ {
37
+ kind: "link",
38
+ key: "all-feedback",
39
+ to: publicHref,
40
+ icon: /* @__PURE__ */ jsx(Users, { className: "size-4" }),
41
+ label: labels.allFeedback ?? DEFAULT_FEEDBACK_MENU_LABELS.allFeedback
42
+ }
43
+ ] : [],
34
44
  {
35
45
  kind: "link",
36
46
  key: isAdmin ? "view-feedback" : "my-feedback",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/feedback/feedback-menu.tsx"],"sourcesContent":["import { Inbox, MessageSquare } from \"lucide-react\";\nimport type { UserAvatarBadge } from \"../components/user-avatar\";\nimport { useKitLabels, type LabelOverride } from \"../i18n/kit-labels\";\nimport { TopBarActionMenu, type TopBarMenuEntry } from \"../shell/topbar-action-menu\";\nimport type { HoverMenuProps } from \"../components/hover-menu\";\n// The vocabulary module, not the inbox: this menu is in every app's top bar, the inbox\n// is a page (MOD-1).\nimport { FEEDBACK_CATEGORY_META, type FeedbackCategory } from \"./feedback-vocabulary\";\nimport { useFeedbackCategoryLabels } from \"./feedback-labels\";\nimport { FEEDBACK_PICKABLE_CATEGORIES } from \"./feedback-record\";\nimport { DEFAULT_FEEDBACK_MENU_LABELS } from \"./feedback-menu-labels\";\n\n/**\n * `feedbackMenu` — the top-bar feedback menu's own words (0.27.0). The four category rows\n * are `feedbackCategory`'s, shared with the badges and the dialog's picker. de-CH canon\n * (keksdose `de-CH.json`): `trigger` \"Feedback senden\", `myFeedback` \"Mein Feedback\",\n * `viewFeedback` \"Feedback ansehen\".\n */\nexport interface FeedbackMenuLabels {\n /** The trigger's accessible name, and the menu's. keksdose `feedback.send`. */\n trigger: string;\n /** The link to the reporter's own reports — everyone but an admin. keksdose\n * `feedback.my_title`. */\n myFeedback: string;\n /** The link to the inbox — an admin's one list link, in place of \"My feedback\".\n * keksdose `feedback.view_all`. */\n viewFeedback: string;\n}\n\n// Defined in ./feedback-menu-labels, which holds no component code (0.34, KS U8).\nexport { DEFAULT_FEEDBACK_MENU_LABELS };\n\nexport interface FeedbackMenuProps {\n /** A category row was chosen — open the submit dialog on it (`useFeedbackSubmit`'s\n * `open`). Never called with `CRASH`: there is no row for it. */\n onFile: (category: FeedbackCategory) => void;\n /** The list link is \"View feedback\" → {@link inboxHref} INSTEAD of \"My feedback\" (§4.1,\n * keksdose `top-bar.tsx:205-214`). The admin check is the app's (kastlan's is\n * company-scoped). Default `false`. */\n isAdmin?: boolean;\n /**\n * Rows of the app's own, between the divider and the list link — keksdose's\n * `Sparkles` Help assistant → `/assistant` and `MessagesSquare` Support chat →\n * `/support` with its unread chip. Any {@link TopBarMenuEntry}; keep their `key`s clear\n * of the menu's own (`BUG`, `IDEA`, `QUESTION`, `OTHER`, `feedback-divider`,\n * `my-feedback`, `view-feedback`).\n */\n extraEntries?: TopBarMenuEntry[];\n /** The user's own reports, linked for everyone but an admin. Default `\"/my-feedback\"`\n * (§2.3). */\n myFeedbackHref?: string;\n /** The admin inbox, linked for an admin. Default `\"/feedback\"` (§2.3). */\n inboxHref?: string;\n /** A dot on the trigger — keksdose's unread support replies (`tone: \"danger\"`). Its\n * `label` joins the trigger's name (\"Send feedback 2 unread\"). The words are the app's. */\n iconBadge?: UserAvatarBadge | null;\n /** Prop > `<UiKitProvider labels={{ feedbackMenu }}>` > English. */\n labels?: LabelOverride<FeedbackMenuLabels>;\n /** Which edge of the trigger the panel lines up with, `start` or `end` in the reading\n * direction (see `HoverMenu`, whose type this is). Default `end`. */\n align?: HoverMenuProps[\"align\"];\n}\n\n/**\n * The top-bar feedback menu, the same in every app (0.27.0, docs/feedback-harmonization.md\n * §4.1) — keksdose `frontend/src/app/top-bar.tsx:156` on the kit's `TopBarActionMenu`:\n *\n * 1. a `MessageSquare` trigger named \"Send feedback\", with an optional `iconBadge`;\n * 2. Bug · Idea · Question · Other (`Bug`, `Lightbulb`, `HelpCircle`, `MoreHorizontal` —\n * the category badges' own glyphs), each calling `onFile(category)`;\n * 3. a divider, always;\n * 4. the app's `extraEntries`;\n * 5. ONE list link, `Inbox`: an admin's is \"View feedback\" → `/feedback`, everyone\n * else's \"My feedback\" → `/my-feedback` — keksdose's (`top-bar.tsx:205-214`, feedback\n * #331: admins get the management view, everyone else their own submissions).\n *\n * WHY A PRESET. Three apps had drawn three menus on the same primitive and they disagreed:\n * kastlan headed it \"New submission\", Kurvenschmiede \"Send feedback\" with a single link\n * that changed its words by role, keksdose had no heading and one link by role. keksdose\n * is the source (§2.4, §7.11): no heading, one link — the inbox for an admin, who reaches\n * their own reports there too — and the kit draws it, so the row order, the icons and the\n * words cannot drift again. Where the menu sits in the bar stays each app's.\n *\n * `CRASH` has no row and never will: crash reports are filed by the error boundary with\n * the stack and a fingerprint (keksdose feedback #160), and a hand-filed \"crash\" would sort\n * to the top like one with none of what makes it actionable. The server refuses it with a\n * 422 anyway (§3.4).\n *\n * The menu forwards nothing to its trigger, as `TopBarActionMenu` does not: keksdose's\n * tour anchor (`data-tour=\"feedback-menu\"`) stays on a wrapping `<span>`. Needs a router,\n * as every `TopBarActionMenu` with link rows does.\n */\nexport function FeedbackMenu({\n onFile,\n isAdmin = false,\n extraEntries,\n myFeedbackHref = \"/my-feedback\",\n inboxHref = \"/feedback\",\n iconBadge,\n labels: labelsProp,\n align,\n}: FeedbackMenuProps) {\n const labels = useKitLabels(\"feedbackMenu\", DEFAULT_FEEDBACK_MENU_LABELS, labelsProp);\n const categoryLabels = useFeedbackCategoryLabels();\n const entries: TopBarMenuEntry[] = [\n ...FEEDBACK_PICKABLE_CATEGORIES.map((category): TopBarMenuEntry => {\n const Icon = FEEDBACK_CATEGORY_META[category].icon;\n return {\n key: category,\n icon: <Icon className=\"size-4\" />,\n label: categoryLabels[category],\n onSelect: () => onFile(category),\n };\n }),\n { kind: \"divider\", key: \"feedback-divider\" },\n ...(extraEntries ?? []),\n {\n kind: \"link\",\n key: isAdmin ? \"view-feedback\" : \"my-feedback\",\n to: isAdmin ? inboxHref : myFeedbackHref,\n icon: <Inbox className=\"size-4\" />,\n label: isAdmin ? labels.viewFeedback : labels.myFeedback,\n },\n ];\n return (\n <TopBarActionMenu\n icon={<MessageSquare className=\"size-5\" />}\n iconBadge={iconBadge}\n aria-label={labels.trigger}\n entries={entries}\n align={align}\n />\n );\n}\n"],"mappings":";AA6Gc;AA7Gd,SAAS,OAAO,qBAAqB;AAErC,SAAS,oBAAwC;AACjD,SAAS,wBAA8C;AAIvD,SAAS,8BAAqD;AAC9D,SAAS,iCAAiC;AAC1C,SAAS,oCAAoC;AAC7C,SAAS,oCAAoC;AAkFtC,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA,iBAAiB;AAAA,EACjB,YAAY;AAAA,EACZ;AAAA,EACA,QAAQ;AAAA,EACR;AACF,GAAsB;AACpB,QAAM,SAAS,aAAa,gBAAgB,8BAA8B,UAAU;AACpF,QAAM,iBAAiB,0BAA0B;AACjD,QAAM,UAA6B;AAAA,IACjC,GAAG,6BAA6B,IAAI,CAAC,aAA8B;AACjE,YAAM,OAAO,uBAAuB,QAAQ,EAAE;AAC9C,aAAO;AAAA,QACL,KAAK;AAAA,QACL,MAAM,oBAAC,QAAK,WAAU,UAAS;AAAA,QAC/B,OAAO,eAAe,QAAQ;AAAA,QAC9B,UAAU,MAAM,OAAO,QAAQ;AAAA,MACjC;AAAA,IACF,CAAC;AAAA,IACD,EAAE,MAAM,WAAW,KAAK,mBAAmB;AAAA,IAC3C,GAAI,gBAAgB,CAAC;AAAA,IACrB;AAAA,MACE,MAAM;AAAA,MACN,KAAK,UAAU,kBAAkB;AAAA,MACjC,IAAI,UAAU,YAAY;AAAA,MAC1B,MAAM,oBAAC,SAAM,WAAU,UAAS;AAAA,MAChC,OAAO,UAAU,OAAO,eAAe,OAAO;AAAA,IAChD;AAAA,EACF;AACA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,oBAAC,iBAAc,WAAU,UAAS;AAAA,MACxC;AAAA,MACA,cAAY,OAAO;AAAA,MACnB;AAAA,MACA;AAAA;AAAA,EACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../src/feedback/feedback-menu.tsx"],"sourcesContent":["import { Inbox, MessageSquare, Users } from \"lucide-react\";\nimport type { UserAvatarBadge } from \"../components/user-avatar\";\nimport { useKitLabels, type LabelOverride } from \"../i18n/kit-labels\";\nimport { TopBarActionMenu, type TopBarMenuEntry } from \"../shell/topbar-action-menu\";\nimport type { HoverMenuProps } from \"../components/hover-menu\";\n// The vocabulary module, not the inbox: this menu is in every app's top bar, the inbox\n// is a page (MOD-1).\nimport { FEEDBACK_CATEGORY_META, type FeedbackCategory } from \"./feedback-vocabulary\";\nimport { useFeedbackCategoryLabels } from \"./feedback-labels\";\nimport { FEEDBACK_PICKABLE_CATEGORIES } from \"./feedback-record\";\nimport { DEFAULT_FEEDBACK_MENU_LABELS } from \"./feedback-menu-labels\";\n\n/**\n * `feedbackMenu` — the top-bar feedback menu's own words (0.27.0). The four category rows\n * are `feedbackCategory`'s, shared with the badges and the dialog's picker. de-CH canon\n * (keksdose `de-CH.json`): `trigger` \"Feedback senden\", `myFeedback` \"Mein Feedback\",\n * `viewFeedback` \"Feedback ansehen\".\n */\nexport interface FeedbackMenuLabels {\n /** The trigger's accessible name, and the menu's. keksdose `feedback.send`. */\n trigger: string;\n /** The link to the reporter's own reports — everyone but an admin. keksdose\n * `feedback.my_title`. */\n myFeedback: string;\n /** The link to the inbox — an admin's one list link, in place of \"My feedback\".\n * keksdose `feedback.view_all`. */\n viewFeedback: string;\n /** The link to every public report, {@link FeedbackMenuProps.publicHref} (0.38,\n * docs/feedback-harmonization.md §9.2 decision 21). Optional, so a complete\n * `UiKitLabels` typed before 0.38 still compiles. de-CH \"Alle Rückmeldungen\". */\n allFeedback?: string;\n}\n\n// Defined in ./feedback-menu-labels, which holds no component code (0.34, KS U8).\nexport { DEFAULT_FEEDBACK_MENU_LABELS };\n\nexport interface FeedbackMenuProps {\n /** A category row was chosen — open the submit dialog on it (`useFeedbackSubmit`'s\n * `open`). Never called with `CRASH`: there is no row for it. */\n onFile: (category: FeedbackCategory) => void;\n /** The list link is \"View feedback\" → {@link inboxHref} INSTEAD of \"My feedback\" (§4.1,\n * keksdose `top-bar.tsx:205-214`). The admin check is the app's (kastlan's is\n * company-scoped). Default `false`. */\n isAdmin?: boolean;\n /**\n * Rows of the app's own, between the divider and the list link — keksdose's\n * `Sparkles` Help assistant → `/assistant` and `MessagesSquare` Support chat →\n * `/support` with its unread chip. Any {@link TopBarMenuEntry}; keep their `key`s clear\n * of the menu's own (`BUG`, `IDEA`, `QUESTION`, `OTHER`, `feedback-divider`,\n * `all-feedback`, `my-feedback`, `view-feedback`).\n */\n extraEntries?: TopBarMenuEntry[];\n /** The user's own reports, linked for everyone but an admin. Default `\"/my-feedback\"`\n * (§2.3). */\n myFeedbackHref?: string;\n /** The admin inbox, linked for an admin. Default `\"/feedback\"` (§2.3). */\n inboxHref?: string;\n /**\n * The public list (0.38, docs/feedback-harmonization.md §9.2 decision 21): when passed,\n * an **All feedback** row (`Users`, key `all-feedback`) above the list link, for\n * everyone — the admin too, who reads what the others read there. keksdose:\n * `\"/all-feedback\"`; \"My feedback\" stays as it is. Leave it out where the app has no\n * public parts (kastlan) or the viewer may not see them (a Kurvenschmiede customer, a\n * demo — §9.2 decisions 7, 8).\n */\n publicHref?: string;\n /** A dot on the trigger — keksdose's unread support replies (`tone: \"danger\"`). Its\n * `label` joins the trigger's name (\"Send feedback 2 unread\"). The words are the app's. */\n iconBadge?: UserAvatarBadge | null;\n /** Prop > `<UiKitProvider labels={{ feedbackMenu }}>` > English. */\n labels?: LabelOverride<FeedbackMenuLabels>;\n /** Which edge of the trigger the panel lines up with, `start` or `end` in the reading\n * direction (see `HoverMenu`, whose type this is). Default `end`. */\n align?: HoverMenuProps[\"align\"];\n}\n\n/**\n * The top-bar feedback menu, the same in every app (0.27.0, docs/feedback-harmonization.md\n * §4.1) — keksdose `frontend/src/app/top-bar.tsx:156` on the kit's `TopBarActionMenu`:\n *\n * 1. a `MessageSquare` trigger named \"Send feedback\", with an optional `iconBadge`;\n * 2. Bug · Idea · Question · Other (`Bug`, `Lightbulb`, `HelpCircle`, `MoreHorizontal` —\n * the category badges' own glyphs), each calling `onFile(category)`;\n * 3. a divider, always;\n * 4. the app's `extraEntries`;\n * 5. with `publicHref` (0.38), **All feedback** → the public list, for everyone;\n * 6. ONE list link, `Inbox`: an admin's is \"View feedback\" → `/feedback`, everyone\n * else's \"My feedback\" → `/my-feedback` — keksdose's (`top-bar.tsx:205-214`, feedback\n * #331: admins get the management view, everyone else their own submissions).\n *\n * WHY A PRESET. Three apps had drawn three menus on the same primitive and they disagreed:\n * kastlan headed it \"New submission\", Kurvenschmiede \"Send feedback\" with a single link\n * that changed its words by role, keksdose had no heading and one link by role. keksdose\n * is the source (§2.4, §7.11): no heading, one link — the inbox for an admin, who reaches\n * their own reports there too — and the kit draws it, so the row order, the icons and the\n * words cannot drift again. Where the menu sits in the bar stays each app's.\n *\n * `CRASH` has no row and never will: crash reports are filed by the error boundary with\n * the stack and a fingerprint (keksdose feedback #160), and a hand-filed \"crash\" would sort\n * to the top like one with none of what makes it actionable. The server refuses it with a\n * 422 anyway (§3.4).\n *\n * The menu forwards nothing to its trigger, as `TopBarActionMenu` does not: keksdose's\n * tour anchor (`data-tour=\"feedback-menu\"`) stays on a wrapping `<span>`. Needs a router,\n * as every `TopBarActionMenu` with link rows does.\n */\nexport function FeedbackMenu({\n onFile,\n isAdmin = false,\n extraEntries,\n myFeedbackHref = \"/my-feedback\",\n inboxHref = \"/feedback\",\n publicHref,\n iconBadge,\n labels: labelsProp,\n align,\n}: FeedbackMenuProps) {\n const labels = useKitLabels(\"feedbackMenu\", DEFAULT_FEEDBACK_MENU_LABELS, labelsProp);\n const categoryLabels = useFeedbackCategoryLabels();\n const entries: TopBarMenuEntry[] = [\n ...FEEDBACK_PICKABLE_CATEGORIES.map((category): TopBarMenuEntry => {\n const Icon = FEEDBACK_CATEGORY_META[category].icon;\n return {\n key: category,\n icon: <Icon className=\"size-4\" />,\n label: categoryLabels[category],\n onSelect: () => onFile(category),\n };\n }),\n { kind: \"divider\", key: \"feedback-divider\" },\n ...(extraEntries ?? []),\n ...(publicHref\n ? [\n {\n kind: \"link\",\n key: \"all-feedback\",\n to: publicHref,\n icon: <Users className=\"size-4\" />,\n label: labels.allFeedback ?? DEFAULT_FEEDBACK_MENU_LABELS.allFeedback!,\n } satisfies TopBarMenuEntry,\n ]\n : []),\n {\n kind: \"link\",\n key: isAdmin ? \"view-feedback\" : \"my-feedback\",\n to: isAdmin ? inboxHref : myFeedbackHref,\n icon: <Inbox className=\"size-4\" />,\n label: isAdmin ? labels.viewFeedback : labels.myFeedback,\n },\n ];\n return (\n <TopBarActionMenu\n icon={<MessageSquare className=\"size-5\" />}\n iconBadge={iconBadge}\n aria-label={labels.trigger}\n entries={entries}\n align={align}\n />\n );\n}\n"],"mappings":";AA4Hc;AA5Hd,SAAS,OAAO,eAAe,aAAa;AAE5C,SAAS,oBAAwC;AACjD,SAAS,wBAA8C;AAIvD,SAAS,8BAAqD;AAC9D,SAAS,iCAAiC;AAC1C,SAAS,oCAAoC;AAC7C,SAAS,oCAAoC;AAgGtC,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA,iBAAiB;AAAA,EACjB,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR;AACF,GAAsB;AACpB,QAAM,SAAS,aAAa,gBAAgB,8BAA8B,UAAU;AACpF,QAAM,iBAAiB,0BAA0B;AACjD,QAAM,UAA6B;AAAA,IACjC,GAAG,6BAA6B,IAAI,CAAC,aAA8B;AACjE,YAAM,OAAO,uBAAuB,QAAQ,EAAE;AAC9C,aAAO;AAAA,QACL,KAAK;AAAA,QACL,MAAM,oBAAC,QAAK,WAAU,UAAS;AAAA,QAC/B,OAAO,eAAe,QAAQ;AAAA,QAC9B,UAAU,MAAM,OAAO,QAAQ;AAAA,MACjC;AAAA,IACF,CAAC;AAAA,IACD,EAAE,MAAM,WAAW,KAAK,mBAAmB;AAAA,IAC3C,GAAI,gBAAgB,CAAC;AAAA,IACrB,GAAI,aACA;AAAA,MACE;AAAA,QACE,MAAM;AAAA,QACN,KAAK;AAAA,QACL,IAAI;AAAA,QACJ,MAAM,oBAAC,SAAM,WAAU,UAAS;AAAA,QAChC,OAAO,OAAO,eAAe,6BAA6B;AAAA,MAC5D;AAAA,IACF,IACA,CAAC;AAAA,IACL;AAAA,MACE,MAAM;AAAA,MACN,KAAK,UAAU,kBAAkB;AAAA,MACjC,IAAI,UAAU,YAAY;AAAA,MAC1B,MAAM,oBAAC,SAAM,WAAU,UAAS;AAAA,MAChC,OAAO,UAAU,OAAO,eAAe,OAAO;AAAA,IAChD;AAAA,EACF;AACA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,oBAAC,iBAAc,WAAU,UAAS;AAAA,MACxC;AAAA,MACA,cAAY,OAAO;AAAA,MACnB;AAAA,MACA;AAAA;AAAA,EACF;AAEJ;","names":[]}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * `feedbackPublic` — the words of the pages every user reads (§9.3, §9.9): the list's
3
+ * sort, search and count, the detail's sections and the "Visible to others" switch. The
4
+ * table's column names that the inbox already has (#, Date, Category, Subject, Status)
5
+ * stay `feedbackPage`'s, so the two lists cannot disagree; the vote button's words are
6
+ * `feedbackVote`'s, the thread's `feedbackComments`'.
7
+ *
8
+ * de-CH canon (§9.2, §9.5): `title` "Alle Rückmeldungen", `anonymous` "Eine Person".
9
+ */
10
+ export interface FeedbackPublicLabels {
11
+ /** The page's heading — keksdose's `/all-feedback`, the menu's "All feedback". */
12
+ title: string;
13
+ /** The sort toggle's accessible name. */
14
+ sort: string;
15
+ /** `sort=newest`, the server's default. */
16
+ sortNewest: string;
17
+ /** `sort=votes`: most votes, then newest. */
18
+ sortVotes: string;
19
+ /** `sort=updated`. */
20
+ sortUpdated: string;
21
+ /** The search box's accessible name: it searches titles only (§9.9). */
22
+ search: string;
23
+ /** The Votes column's header. */
24
+ columnVotes: string;
25
+ /** How many reports the server has for this query (`total`). */
26
+ total: (count: number) => string;
27
+ /** A row's visible comments, the chip beside its title. */
28
+ comments: (count: number) => string;
29
+ /** A row's votes, the count on a phone card (the button is in the opened report). */
30
+ votes: (count: number) => string;
31
+ /** A `null` name (§9.5): an incomplete or erased account. */
32
+ anonymous: string;
33
+ /** Who filed it, with the server's first name (or {@link anonymous}). */
34
+ filedBy: (name: string) => string;
35
+ /** The detail's public body section. */
36
+ body: string;
37
+ /** The detail's merged replies and comments (§9.8, "Order"). */
38
+ conversation: string;
39
+ /** While the list or the comments load. */
40
+ loading: string;
41
+ /** No public report (yet, or for this search). */
42
+ empty: string;
43
+ /** `FeedbackPublicSwitch`'s label (§9.3, decision 6). */
44
+ visibleToOthers: string;
45
+ /** The line under it: what others see, and what never. */
46
+ visibleHint: string;
47
+ /** Why the author cannot flip it now: the report is past its open window (§9.3). */
48
+ visibleLocked: string;
49
+ /** 0.38.1: the pager's "where am I" — `page` counts from 1. The server answers no
50
+ * total, so there is no "of N". */
51
+ page: (page: number) => string;
52
+ }
53
+ export declare const DEFAULT_FEEDBACK_PUBLIC_LABELS: FeedbackPublicLabels;
@@ -0,0 +1,27 @@
1
+ "use client";
2
+ const DEFAULT_FEEDBACK_PUBLIC_LABELS = {
3
+ title: "All feedback",
4
+ sort: "Sort",
5
+ sortNewest: "Newest",
6
+ sortVotes: "Most wanted",
7
+ sortUpdated: "Recently updated",
8
+ search: "Search titles",
9
+ columnVotes: "Votes",
10
+ total: (count) => count === 1 ? "1 report" : `${count} reports`,
11
+ comments: (count) => count === 1 ? "1 comment" : `${count} comments`,
12
+ votes: (count) => count === 1 ? "1 vote" : `${count} votes`,
13
+ anonymous: "A user",
14
+ filedBy: (name) => `From ${name}`,
15
+ body: "Description",
16
+ conversation: "Answers and comments",
17
+ loading: "Loading\u2026",
18
+ empty: "No reports yet",
19
+ visibleToOthers: "Visible to others",
20
+ visibleHint: "Other users see the title and text, never your screenshots or files.",
21
+ visibleLocked: "Only while the report is still open.",
22
+ page: (page) => `Page ${page}`
23
+ };
24
+ export {
25
+ DEFAULT_FEEDBACK_PUBLIC_LABELS
26
+ };
27
+ //# sourceMappingURL=feedback-public-labels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/feedback/feedback-public-labels.ts"],"sourcesContent":["// The English words of the public feedback pages (round 0.38, docs/feedback-harmonization.md\n// §9.15) — `FeedbackPublicList`, `FeedbackPublicDetail` and `FeedbackPublicSwitch` — in a\n// module with no component code: the English catalogue (src/i18n/defaults.ts) imports\n// them without the components, as every `*-labels.ts` (0.34, KS U8).\n\n/**\n * `feedbackPublic` — the words of the pages every user reads (§9.3, §9.9): the list's\n * sort, search and count, the detail's sections and the \"Visible to others\" switch. The\n * table's column names that the inbox already has (#, Date, Category, Subject, Status)\n * stay `feedbackPage`'s, so the two lists cannot disagree; the vote button's words are\n * `feedbackVote`'s, the thread's `feedbackComments`'.\n *\n * de-CH canon (§9.2, §9.5): `title` \"Alle Rückmeldungen\", `anonymous` \"Eine Person\".\n */\nexport interface FeedbackPublicLabels {\n /** The page's heading — keksdose's `/all-feedback`, the menu's \"All feedback\". */\n title: string;\n /** The sort toggle's accessible name. */\n sort: string;\n /** `sort=newest`, the server's default. */\n sortNewest: string;\n /** `sort=votes`: most votes, then newest. */\n sortVotes: string;\n /** `sort=updated`. */\n sortUpdated: string;\n /** The search box's accessible name: it searches titles only (§9.9). */\n search: string;\n /** The Votes column's header. */\n columnVotes: string;\n /** How many reports the server has for this query (`total`). */\n total: (count: number) => string;\n /** A row's visible comments, the chip beside its title. */\n comments: (count: number) => string;\n /** A row's votes, the count on a phone card (the button is in the opened report). */\n votes: (count: number) => string;\n /** A `null` name (§9.5): an incomplete or erased account. */\n anonymous: string;\n /** Who filed it, with the server's first name (or {@link anonymous}). */\n filedBy: (name: string) => string;\n /** The detail's public body section. */\n body: string;\n /** The detail's merged replies and comments (§9.8, \"Order\"). */\n conversation: string;\n /** While the list or the comments load. */\n loading: string;\n /** No public report (yet, or for this search). */\n empty: string;\n /** `FeedbackPublicSwitch`'s label (§9.3, decision 6). */\n visibleToOthers: string;\n /** The line under it: what others see, and what never. */\n visibleHint: string;\n /** Why the author cannot flip it now: the report is past its open window (§9.3). */\n visibleLocked: string;\n /** 0.38.1: the pager's \"where am I\" — `page` counts from 1. The server answers no\n * total, so there is no \"of N\". */\n page: (page: number) => string;\n}\n\nexport const DEFAULT_FEEDBACK_PUBLIC_LABELS: FeedbackPublicLabels = {\n title: \"All feedback\",\n sort: \"Sort\",\n sortNewest: \"Newest\",\n sortVotes: \"Most wanted\",\n sortUpdated: \"Recently updated\",\n search: \"Search titles\",\n columnVotes: \"Votes\",\n total: (count) => (count === 1 ? \"1 report\" : `${count} reports`),\n comments: (count) => (count === 1 ? \"1 comment\" : `${count} comments`),\n votes: (count) => (count === 1 ? \"1 vote\" : `${count} votes`),\n anonymous: \"A user\",\n filedBy: (name) => `From ${name}`,\n body: \"Description\",\n conversation: \"Answers and comments\",\n loading: \"Loading…\",\n empty: \"No reports yet\",\n visibleToOthers: \"Visible to others\",\n visibleHint: \"Other users see the title and text, never your screenshots or files.\",\n visibleLocked: \"Only while the report is still open.\",\n page: (page) => `Page ${page}`,\n};\n"],"mappings":";AA0DO,MAAM,iCAAuD;AAAA,EAClE,OAAO;AAAA,EACP,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,aAAa;AAAA,EACb,QAAQ;AAAA,EACR,aAAa;AAAA,EACb,OAAO,CAAC,UAAW,UAAU,IAAI,aAAa,GAAG,KAAK;AAAA,EACtD,UAAU,CAAC,UAAW,UAAU,IAAI,cAAc,GAAG,KAAK;AAAA,EAC1D,OAAO,CAAC,UAAW,UAAU,IAAI,WAAW,GAAG,KAAK;AAAA,EACpD,WAAW;AAAA,EACX,SAAS,CAAC,SAAS,QAAQ,IAAI;AAAA,EAC/B,MAAM;AAAA,EACN,cAAc;AAAA,EACd,SAAS;AAAA,EACT,OAAO;AAAA,EACP,iBAAiB;AAAA,EACjB,aAAa;AAAA,EACb,eAAe;AAAA,EACf,MAAM,CAAC,SAAS,QAAQ,IAAI;AAC9B;","names":[]}
@@ -0,0 +1,139 @@
1
+ import type { ReactNode } from "react";
2
+ import type { CommitScope } from "../components/write-lock.js";
3
+ import { type LabelOverride } from "../i18n/kit-labels.js";
4
+ import { type FeedbackCommentsLabels } from "./feedback-comment-thread.js";
5
+ import { DEFAULT_FEEDBACK_PUBLIC_LABELS, type FeedbackPublicLabels } from "./feedback-public-labels.js";
6
+ import type { FeedbackComment, FeedbackPublicListItem, FeedbackPublicRecord, FeedbackPublicSort, FeedbackVoteState } from "./feedback-public-types.js";
7
+ import { type FeedbackPageLabels, type FeedbackRenderDate } from "./feedback-table.js";
8
+ export { DEFAULT_FEEDBACK_PUBLIC_LABELS };
9
+ export type { FeedbackPublicLabels };
10
+ /** `feedbackPublic` resolved: English, then `<UiKitProvider labels>`, then `labels`. */
11
+ export declare function useFeedbackPublicLabels(labels?: LabelOverride<FeedbackPublicLabels>): FeedbackPublicLabels;
12
+ export interface FeedbackPublicListProps<T extends FeedbackPublicListItem = FeedbackPublicListItem> {
13
+ /** `GET /feedback/public?sort=&q=` — the server's page, in the server's order. */
14
+ rows: T[];
15
+ /** How many the query has in all — the line beside the sort. Left out, no line. */
16
+ total?: number;
17
+ /** The server sorts (§9.6): the toggle only says which way. */
18
+ sort: FeedbackPublicSort;
19
+ onSortChange: (sort: FeedbackPublicSort) => void;
20
+ /** The search box's text (`q`, titles only). */
21
+ search?: string;
22
+ /**
23
+ * The search box is drawn ONLY with this handler: where the app's titles are sealed
24
+ * (Kurvenschmiede, `FeedbackDeps.public_search=False`, §9.9) there is nothing to search
25
+ * on and the server answers `q` with a 422 — so it passes none.
26
+ */
27
+ onSearchChange?: (search: string) => void;
28
+ /** The opened row: the app's {@link FeedbackPublicDetail} with the row's
29
+ * `GET /feedback/public/{id}` and its comments. */
30
+ renderDetail: (row: T) => ReactNode;
31
+ /** `PUT` / `DELETE /feedback/{id}/vote` for a row's button (`next`: the new state);
32
+ * resolve with the answer, reject to roll back. */
33
+ onVote: (row: T, next: boolean) => Promise<FeedbackVoteState>;
34
+ /** The page is loading: the table says so where its rows would be. */
35
+ loading?: boolean;
36
+ /** The opened row's id, when the app keeps it (a `?row=` param). Left out, the list
37
+ * keeps it itself. */
38
+ openId?: number | null;
39
+ onOpenChange?: (id: number | null) => void;
40
+ /**
41
+ * 0.38.1: the opened report when it is NOT on this page — a `?row=` link to an older
42
+ * one (Kurvenschmiede). The app fetches it (`GET /feedback/public/{id}`, a list item's
43
+ * fields and more) and passes it with `openId`; while `openId` is its id it is drawn
44
+ * first, above the page's rows, and opened with `renderDetail` (on the phone, in the
45
+ * full-screen dialog). Closed, it is gone. A row the page has already is never drawn
46
+ * twice: the page's own is opened instead.
47
+ */
48
+ openRow?: T | null;
49
+ /**
50
+ * 0.38.1: the server's page, from 0 — for a pager where `/feedback/public` answers no
51
+ * total (Kurvenschmiede). With {@link onPageChange} a **Previous / Page n / Next**
52
+ * strip stands under the table; Next is off without {@link hasMore}. Left out, no
53
+ * pager: the server's `limit` is all there is.
54
+ */
55
+ page?: number;
56
+ /** 0.38.1: there is a page after this one (e.g. the page came back full). */
57
+ hasMore?: boolean;
58
+ /** 0.38.1: go to another page (`page ± 1`); the app fetches it. Draws the pager. */
59
+ onPageChange?: (page: number) => void;
60
+ /** A vote COMMITS — see Button's `commit`. */
61
+ commit?: CommitScope;
62
+ /** See {@link FeedbackRenderDate}. Default: the kit's, with the weekday. */
63
+ renderDate?: FeedbackRenderDate;
64
+ /** Over the `feedbackPublic` namespace. The shared column names (#, Date, Category,
65
+ * Subject, Status) are `feedbackPage`'s: pass `pageLabels` for those. */
66
+ labels?: LabelOverride<FeedbackPublicLabels>;
67
+ pageLabels?: LabelOverride<FeedbackPageLabels>;
68
+ className?: string;
69
+ }
70
+ /**
71
+ * **All feedback** — the reports every user the app lets in may read (round 0.38,
72
+ * docs/feedback-harmonization.md §9.3, §9.9; keksdose's `/all-feedback`).
73
+ *
74
+ * - **Titles only** (decision 23): #, Date, Category, Subject (with the visible
75
+ * comments), Votes, Status. No body, no submitter, no file — the list item carries
76
+ * none of them (§9.10).
77
+ * - **The server sorts**: the toggle **Newest / Most wanted / Recently updated** sets
78
+ * `sort`, and the columns themselves do not sort (a page of 50 sorted in the browser
79
+ * would not be the 50 the sort asks for).
80
+ * - **The search box only with `onSearchChange`**: an app whose titles are sealed
81
+ * passes none (§9.9).
82
+ * - **Votes** are `FeedbackVoteButton`s, optimistic, the viewer's own report pressed
83
+ * and locked ("Your report", §9.6).
84
+ * - A row opens in place with `renderDetail` — on the phone, in a full-screen dialog.
85
+ * The phone cards carry the title, the status, the category, the date and the two
86
+ * counts; the vote itself is in the opened report (a button inside the card, which is
87
+ * the row's own button, would be two controls in one).
88
+ *
89
+ * No client paging: the server's `limit` is the page, and `total` says how many there
90
+ * are. For more than one page, `page` / `hasMore` / `onPageChange` draw a previous /
91
+ * next strip that needs no total (0.38.1); `openRow` shows a `?row=` report from
92
+ * another page. Needs a router, as every `DataTable` does.
93
+ */
94
+ export declare function FeedbackPublicList<T extends FeedbackPublicListItem = FeedbackPublicListItem>({ rows, total, sort, onSortChange, search, onSearchChange, renderDetail, onVote, loading, openId: openIdProp, onOpenChange, openRow, page: pageIndex, hasMore, onPageChange, commit, renderDate: renderDateProp, labels: labelsProp, pageLabels: pageLabelsProp, className, }: FeedbackPublicListProps<T>): import("react").JSX.Element;
95
+ export interface FeedbackPublicDetailProps {
96
+ /** `GET /feedback/public/{id}`: the public body (attachment URLs already stripped by
97
+ * the server, §9.4) and the replies. */
98
+ row: FeedbackPublicRecord;
99
+ /** `GET /feedback/{id}/comments`, oldest first; `undefined` while it loads. */
100
+ comments: readonly FeedbackComment[] | undefined;
101
+ /** `PUT` / `DELETE /feedback/{id}/vote`; resolve with the answer, reject to roll back. */
102
+ onVote: (next: boolean) => Promise<FeedbackVoteState>;
103
+ /** The viewer is the app's admin: Hide / Unhide on the comments. */
104
+ isAdmin?: boolean;
105
+ /** `POST /feedback/{id}/comments`. Left out — a demo, a reader who may not write — no
106
+ * composer. */
107
+ onComment?: (body: string) => void | Promise<unknown>;
108
+ /** The admin's hide (`PATCH …/comments/{id} {hidden}`). */
109
+ onHide?: (comment: FeedbackComment, hidden: boolean) => void | Promise<unknown>;
110
+ /** The writer's delete (`DELETE …/comments/{id}`), after a confirm. */
111
+ onDelete?: (comment: FeedbackComment) => void | Promise<unknown>;
112
+ /** A comment is being sent. */
113
+ pending?: boolean;
114
+ /** The vote and the thread's buttons COMMIT — see Button's `commit`. */
115
+ commit?: CommitScope;
116
+ /** Voting is off for this viewer (a demo): `true`, or the reason. */
117
+ voteDisabled?: boolean | string;
118
+ /** See {@link FeedbackRenderDate}. */
119
+ renderDate?: FeedbackRenderDate;
120
+ /** "Now" for the thread's relative times — pin it in tests and stories. */
121
+ now?: Date | number;
122
+ /** Over the `feedbackPublic` namespace. */
123
+ labels?: LabelOverride<FeedbackPublicLabels>;
124
+ /** Over the `feedbackComments` namespace, for the thread. */
125
+ commentLabels?: LabelOverride<FeedbackCommentsLabels>;
126
+ className?: string;
127
+ }
128
+ /**
129
+ * One public report opened (round 0.38, docs/feedback-harmonization.md §9.3, §9.10): who
130
+ * filed it — the first name the server sent, else **"A user"** (§9.5) — and when; the
131
+ * **vote**; the **public body**; and the **conversation**, the admin's replies and other
132
+ * people's comments merged oldest first (§9.8, `FeedbackCommentThread`), with the box to
133
+ * add one.
134
+ *
135
+ * What it never draws, because the public record never carries it (§9.10): an address,
136
+ * a last name, a screenshot, a file, the page the report was filed on. The body is the
137
+ * server's `public_body` — the client strips nothing and adds nothing.
138
+ */
139
+ export declare function FeedbackPublicDetail({ row, comments, onVote, isAdmin, onComment, onHide, onDelete, pending, commit, voteDisabled, renderDate: renderDateProp, now, labels: labelsProp, commentLabels, className, }: FeedbackPublicDetailProps): import("react").JSX.Element;