@mhosaic/feedback 0.15.1 → 0.15.3

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.
@@ -650,6 +650,12 @@ var DEFAULT_STRINGS = {
650
650
  "detail.compose_sending": "Sending\u2026",
651
651
  "detail.close_cta": "Mark as resolved",
652
652
  "detail.close_busy": "Marking\u2026",
653
+ "detail.teammate_notice": "Viewing a teammate\u2019s report \u2014 replies are private to the submitter.",
654
+ "detail.load_failed.title": "Report not available",
655
+ "detail.load_failed.body": "It may have been deleted, or you no longer have access to it.",
656
+ "detail.load_failed.cta": "Back",
657
+ "detail.send_failed": "Couldn\u2019t send your reply. Try again.",
658
+ "detail.close_failed": "Couldn\u2019t mark as resolved. Try again.",
653
659
  "detail.history": "Status history",
654
660
  "detail.context.submitted_at": "Submitted",
655
661
  "detail.context.page": "Page",
@@ -783,6 +789,12 @@ var FRENCH_STRINGS = {
783
789
  "detail.compose_sending": "Envoi\u2026",
784
790
  "detail.close_cta": "Marquer comme r\xE9solu",
785
791
  "detail.close_busy": "Validation\u2026",
792
+ "detail.teammate_notice": "Vous consultez le rapport d\u2019un co\xE9quipier \u2014 les r\xE9ponses sont priv\xE9es au soumetteur.",
793
+ "detail.load_failed.title": "Rapport indisponible",
794
+ "detail.load_failed.body": "Il a peut-\xEAtre \xE9t\xE9 supprim\xE9, ou vous n\u2019y avez plus acc\xE8s.",
795
+ "detail.load_failed.cta": "Retour",
796
+ "detail.send_failed": "Impossible d\u2019envoyer votre r\xE9ponse. R\xE9essayez.",
797
+ "detail.close_failed": "Impossible de marquer comme r\xE9solu. R\xE9essayez.",
786
798
  "detail.history": "Historique du statut",
787
799
  "detail.context.submitted_at": "Envoy\xE9",
788
800
  "detail.context.page": "Page",
@@ -930,8 +942,9 @@ function ReportDetailView({
930
942
  setDetail(next);
931
943
  setError(null);
932
944
  } catch (err) {
945
+ if (typeof console !== "undefined") console.warn("[mhosaic] getReport:", err);
933
946
  if (!mountedRef.current) return;
934
- setError(err instanceof Error ? err.message : "load_failed");
947
+ setError("load_failed");
935
948
  }
936
949
  };
937
950
  useEffect(() => {
@@ -958,8 +971,9 @@ function ReportDetailView({
958
971
  );
959
972
  void fetchDetail();
960
973
  } catch (err) {
974
+ if (typeof console !== "undefined") console.warn("[mhosaic] addComment:", err);
961
975
  if (!mountedRef.current) return;
962
- setError(err instanceof Error ? err.message : "comment_failed");
976
+ setError(strings["detail.send_failed"]);
963
977
  } finally {
964
978
  if (mountedRef.current) setSending(false);
965
979
  }
@@ -972,8 +986,10 @@ function ReportDetailView({
972
986
  if (!mountedRef.current) return;
973
987
  setDetail(next);
974
988
  } catch (err) {
989
+ if (typeof console !== "undefined")
990
+ console.warn("[mhosaic] closeAsResolved:", err);
975
991
  if (!mountedRef.current) return;
976
- setError(err instanceof Error ? err.message : "close_failed");
992
+ setError(strings["detail.close_failed"]);
977
993
  } finally {
978
994
  if (mountedRef.current) setClosing(false);
979
995
  }
@@ -982,9 +998,18 @@ function ReportDetailView({
982
998
  return /* @__PURE__ */ jsx2("div", { class: "mine-loading", children: strings["mine.loading"] });
983
999
  }
984
1000
  if (!detail) {
985
- return /* @__PURE__ */ jsx2("div", { class: "error", role: "alert", children: error });
1001
+ return /* @__PURE__ */ jsxs2("div", { class: "report-detail-empty-state", role: "alert", children: [
1002
+ /* @__PURE__ */ jsx2("p", { class: "report-detail-empty-state-title", children: strings["detail.load_failed.title"] }),
1003
+ /* @__PURE__ */ jsx2("p", { class: "report-detail-empty-state-body", children: strings["detail.load_failed.body"] }),
1004
+ /* @__PURE__ */ jsxs2("button", { type: "button", class: "btn", onClick: onBack, children: [
1005
+ "\u2190 ",
1006
+ strings["detail.load_failed.cta"]
1007
+ ] })
1008
+ ] });
986
1009
  }
987
- const showCloseCta = canModerate && detail.status === "awaiting_validation";
1010
+ const isMine = detail.is_mine ?? canModerate;
1011
+ const showCloseCta = isMine && detail.status === "awaiting_validation";
1012
+ const showComposeBox = isMine;
988
1013
  return /* @__PURE__ */ jsxs2("div", { class: `report-detail variant-${variant}`, children: [
989
1014
  variant === "modal" && /* @__PURE__ */ jsxs2("div", { class: "report-detail-header", children: [
990
1015
  /* @__PURE__ */ jsxs2("button", { type: "button", class: "btn", onClick: onBack, children: [
@@ -1029,7 +1054,7 @@ function ReportDetailView({
1029
1054
  detail.comments.length === 0 ? /* @__PURE__ */ jsx2("p", { class: "report-detail-empty", children: strings["detail.no_replies"] }) : /* @__PURE__ */ jsx2("ul", { class: "report-comments", children: detail.comments.map((c) => /* @__PURE__ */ jsx2("li", { children: /* @__PURE__ */ jsx2(CommentBubble, { comment: c, strings }) })) }),
1030
1055
  detail.status_history && detail.status_history.length > 0 && /* @__PURE__ */ jsx2(StatusHistorySection, { rows: detail.status_history, strings }),
1031
1056
  detail.technical_context && /* @__PURE__ */ jsx2(TechnicalContextDrawer, { ctx: detail.technical_context, strings }),
1032
- /* @__PURE__ */ jsxs2("div", { class: "report-compose", children: [
1057
+ showComposeBox ? /* @__PURE__ */ jsxs2("div", { class: "report-compose", children: [
1033
1058
  /* @__PURE__ */ jsx2(
1034
1059
  "textarea",
1035
1060
  {
@@ -1061,7 +1086,13 @@ function ReportDetailView({
1061
1086
  }
1062
1087
  )
1063
1088
  ] })
1064
- ] }),
1089
+ ] }) : (
1090
+ // Teammate is reading a project-wide row. Replies are private
1091
+ // to the submitter, so we hide the compose box entirely (action
1092
+ // is genuinely unavailable) and surface a short notice so the
1093
+ // viewer understands why.
1094
+ /* @__PURE__ */ jsx2("p", { class: "report-detail-teammate-notice", role: "note", children: strings["detail.teammate_notice"] })
1095
+ ),
1065
1096
  error && /* @__PURE__ */ jsx2("div", { class: "error", children: error })
1066
1097
  ] })
1067
1098
  ] });
@@ -1706,8 +1737,10 @@ function ChangelogList({ api, externalId, strings, onSelect }) {
1706
1737
  if (!mountedRef.current) return;
1707
1738
  setRows(next);
1708
1739
  } catch (err) {
1740
+ if (typeof console !== "undefined")
1741
+ console.warn("[mhosaic] listChangelog:", err);
1709
1742
  if (!mountedRef.current) return;
1710
- setError(err instanceof Error ? err.message : strings["mine.error"]);
1743
+ setError(strings["mine.error"]);
1711
1744
  } finally {
1712
1745
  if (mountedRef.current) setRefreshing(false);
1713
1746
  }
@@ -2658,8 +2691,9 @@ function MineList({ api, externalId, strings, onSelect }) {
2658
2691
  if (!mountedRef.current) return;
2659
2692
  setRows(next);
2660
2693
  } catch (err) {
2694
+ if (typeof console !== "undefined") console.warn("[mhosaic] listMine:", err);
2661
2695
  if (!mountedRef.current) return;
2662
- setError(err instanceof Error ? err.message : strings["mine.error"]);
2696
+ setError(strings["mine.error"]);
2663
2697
  } finally {
2664
2698
  if (mountedRef.current) setRefreshing(false);
2665
2699
  }
@@ -3684,6 +3718,47 @@ var WIDGET_STYLES = `
3684
3718
  gap: 6px;
3685
3719
  }
3686
3720
 
3721
+ /* v0.15.3 \u2014 teammate-viewing notice. Shown in place of the compose
3722
+ * box when a non-submitter opens a project-wide row from the Board
3723
+ * tab. Replies are private to the submitter; we surface this once
3724
+ * (calm tone, neutral surface) so the viewer understands why no
3725
+ * Reply box appears, instead of leaving them wondering. */
3726
+ .report-detail-teammate-notice {
3727
+ margin: 0;
3728
+ padding: var(--mfb-space-3) var(--mfb-space-4);
3729
+ background: var(--mfb-surface);
3730
+ border: 1px dashed var(--mfb-border);
3731
+ border-radius: var(--mfb-radius);
3732
+ font-size: var(--mfb-text-sm);
3733
+ color: var(--mfb-text-muted);
3734
+ font-style: italic;
3735
+ }
3736
+
3737
+ /* v0.15.3 \u2014 friendly "report not available" empty state. Replaces
3738
+ * the raw API error message (e.g. getReport failed: 404 \u2026) that
3739
+ * used to leak from setError(err.message) straight into the DOM. */
3740
+ .report-detail-empty-state {
3741
+ display: flex;
3742
+ flex-direction: column;
3743
+ align-items: flex-start;
3744
+ gap: var(--mfb-space-3);
3745
+ padding: var(--mfb-space-5);
3746
+ background: var(--mfb-surface);
3747
+ border-radius: var(--mfb-radius);
3748
+ border: 1px solid var(--mfb-border);
3749
+ }
3750
+ .report-detail-empty-state-title {
3751
+ margin: 0;
3752
+ font-size: var(--mfb-text-md);
3753
+ font-weight: 600;
3754
+ color: var(--mfb-text);
3755
+ }
3756
+ .report-detail-empty-state-body {
3757
+ margin: 0;
3758
+ font-size: var(--mfb-text-sm);
3759
+ color: var(--mfb-text-muted);
3760
+ }
3761
+
3687
3762
  /* Status history \u2014 read-only audit trail visible to the submitter.
3688
3763
  Timeline of who flipped the status and when (operator vs. agent vs.
3689
3764
  system). Bordered, neutral surface so it doesn't compete visually
@@ -3976,9 +4051,13 @@ var WIDGET_STYLES = `
3976
4051
  * the breathing room of the default modal \u2014 24px top + 24px bottom +
3977
4052
  * 24px on each side \u2014 so the panel reads as "near-fullscreen with a
3978
4053
  * visible frame" instead of "the whole viewport, content cut off".
3979
- * Was --mfb-space-5 (24px total = 12px each side), which felt
3980
- * claustrophobic and tricked users into expecting more vertical
3981
- * scroll under the viewport edge. */
4054
+ *
4055
+ * The base .modal rule uses the browser default content-box, so
4056
+ * without an override the 24px padding would be ADDED to the
4057
+ * calc(100vh - 48px) height \u2014 the rendered box would exactly equal
4058
+ * the viewport again, defeating the margin. Force border-box so
4059
+ * padding lives INSIDE the height we set. */
4060
+ box-sizing: border-box;
3982
4061
  width: min(1280px, calc(100vw - var(--mfb-space-7)));
3983
4062
  max-height: calc(100vh - var(--mfb-space-7));
3984
4063
  height: calc(100vh - var(--mfb-space-7));
@@ -4443,10 +4522,12 @@ function mountWidget(options) {
4443
4522
  });
4444
4523
  }, 1200);
4445
4524
  } catch (err) {
4525
+ if (typeof console !== "undefined")
4526
+ console.warn("[mhosaic] submit:", err);
4446
4527
  rerender({
4447
4528
  ...currentState,
4448
4529
  status: "error",
4449
- error: err instanceof Error ? err.message : String(err)
4530
+ error: options.strings["form.error"]
4450
4531
  });
4451
4532
  }
4452
4533
  }, []);
@@ -4650,8 +4731,8 @@ function createFeedback(config) {
4650
4731
  capture_method: captureMethod,
4651
4732
  technical_context
4652
4733
  };
4653
- if ("0.15.1") {
4654
- payload.widget_version = "0.15.1";
4734
+ if ("0.15.3") {
4735
+ payload.widget_version = "0.15.3";
4655
4736
  }
4656
4737
  if (manualScreenshot) payload.screenshot = manualScreenshot;
4657
4738
  if (values.synthetic) payload.synthetic = true;
@@ -4737,4 +4818,4 @@ function createFeedback(config) {
4737
4818
  export {
4738
4819
  createFeedback
4739
4820
  };
4740
- //# sourceMappingURL=chunk-3YLD2AJI.mjs.map
4821
+ //# sourceMappingURL=chunk-SRAA5JQN.mjs.map