spaps-issue-reporting-react 0.1.3 → 0.1.5
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.
- package/CHANGELOG.md +8 -0
- package/README.md +61 -5
- package/dist/index.d.mts +24 -2
- package/dist/index.d.ts +24 -2
- package/dist/index.js +606 -119
- package/dist/index.mjs +595 -106
- package/package.json +6 -3
package/dist/index.mjs
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
// src/components.tsx
|
|
2
2
|
import * as Dialog from "@radix-ui/react-dialog";
|
|
3
3
|
import * as Popover from "@radix-ui/react-popover";
|
|
4
|
+
import { useScribe } from "@elevenlabs/react";
|
|
4
5
|
import {
|
|
5
6
|
BugBeetle,
|
|
6
7
|
CheckCircle,
|
|
7
8
|
Circle,
|
|
9
|
+
Microphone,
|
|
8
10
|
Spinner,
|
|
11
|
+
TextT,
|
|
9
12
|
X
|
|
10
13
|
} from "@phosphor-icons/react";
|
|
11
14
|
import { formatDistanceToNow } from "date-fns";
|
|
12
|
-
import React2, { useEffect as useEffect2, useMemo as useMemo2, useState as useState2 } from "react";
|
|
15
|
+
import React2, { useCallback as useCallback2, useEffect as useEffect2, useMemo as useMemo2, useState as useState2 } from "react";
|
|
13
16
|
|
|
14
17
|
// src/provider.tsx
|
|
15
18
|
import {
|
|
@@ -41,6 +44,9 @@ import { jsx } from "react/jsx-runtime";
|
|
|
41
44
|
var LIST_LIMIT = 200;
|
|
42
45
|
var NOTE_MIN_LENGTH = 10;
|
|
43
46
|
var NOTE_MAX_LENGTH = 2e3;
|
|
47
|
+
var DEFAULT_INPUT_MODES = ["text"];
|
|
48
|
+
var DEFAULT_VOICE_PROVIDER = "elevenlabs_scribe_realtime";
|
|
49
|
+
var DEFAULT_VOICE_MODEL_ID = "scribe_v2_realtime";
|
|
44
50
|
var initialModalState = {
|
|
45
51
|
isOpen: false,
|
|
46
52
|
mode: "create",
|
|
@@ -133,6 +139,25 @@ function resolveInitialScope(defaultScope, allowTenantScope) {
|
|
|
133
139
|
}
|
|
134
140
|
return "mine";
|
|
135
141
|
}
|
|
142
|
+
function normalizeInputModes(inputModes) {
|
|
143
|
+
if (!inputModes || inputModes.length === 0) {
|
|
144
|
+
return DEFAULT_INPUT_MODES;
|
|
145
|
+
}
|
|
146
|
+
const unique = Array.from(new Set(inputModes));
|
|
147
|
+
const supported = unique.filter(
|
|
148
|
+
(mode) => mode === "text" || mode === "voice"
|
|
149
|
+
);
|
|
150
|
+
if (supported.length === 0) {
|
|
151
|
+
return DEFAULT_INPUT_MODES;
|
|
152
|
+
}
|
|
153
|
+
return supported;
|
|
154
|
+
}
|
|
155
|
+
function resolveDefaultInputMode(defaultInputMode, inputModes) {
|
|
156
|
+
if (defaultInputMode && inputModes.includes(defaultInputMode)) {
|
|
157
|
+
return defaultInputMode;
|
|
158
|
+
}
|
|
159
|
+
return inputModes[0] ?? "text";
|
|
160
|
+
}
|
|
136
161
|
function normalizeTarget(target, getPageUrl) {
|
|
137
162
|
if (typeof target === "string") {
|
|
138
163
|
const normalized = target.trim();
|
|
@@ -391,6 +416,9 @@ function IssueReportingProvider({
|
|
|
391
416
|
defaultScope,
|
|
392
417
|
allowTenantScope = false,
|
|
393
418
|
defaultCreateMode = "general_page",
|
|
419
|
+
inputModes,
|
|
420
|
+
defaultInputMode,
|
|
421
|
+
voice,
|
|
394
422
|
copy,
|
|
395
423
|
children
|
|
396
424
|
}) {
|
|
@@ -412,6 +440,23 @@ function IssueReportingProvider({
|
|
|
412
440
|
const [registeredTargets, setRegisteredTargets] = useState(
|
|
413
441
|
[]
|
|
414
442
|
);
|
|
443
|
+
const resolvedInputModes = useMemo(
|
|
444
|
+
() => normalizeInputModes(inputModes),
|
|
445
|
+
[inputModes]
|
|
446
|
+
);
|
|
447
|
+
const resolvedDefaultInputMode = useMemo(
|
|
448
|
+
() => resolveDefaultInputMode(defaultInputMode, resolvedInputModes),
|
|
449
|
+
[defaultInputMode, resolvedInputModes]
|
|
450
|
+
);
|
|
451
|
+
const resolvedVoiceConfig = useMemo(
|
|
452
|
+
() => ({
|
|
453
|
+
provider: voice?.provider ?? DEFAULT_VOICE_PROVIDER,
|
|
454
|
+
modelId: voice?.modelId ?? DEFAULT_VOICE_MODEL_ID,
|
|
455
|
+
requireMicrophonePermission: voice?.requireMicrophonePermission ?? true,
|
|
456
|
+
microphone: voice?.microphone
|
|
457
|
+
}),
|
|
458
|
+
[voice]
|
|
459
|
+
);
|
|
415
460
|
useEffect(() => {
|
|
416
461
|
setScope(resolveInitialScope(defaultScope, allowTenantScope));
|
|
417
462
|
}, [allowTenantScope, defaultScope]);
|
|
@@ -599,7 +644,10 @@ function IssueReportingProvider({
|
|
|
599
644
|
scope,
|
|
600
645
|
setScope,
|
|
601
646
|
allowTenantScope,
|
|
602
|
-
createMode
|
|
647
|
+
createMode,
|
|
648
|
+
inputModes: resolvedInputModes,
|
|
649
|
+
defaultInputMode: resolvedDefaultInputMode,
|
|
650
|
+
voice: resolvedVoiceConfig
|
|
603
651
|
}),
|
|
604
652
|
[
|
|
605
653
|
allowTenantScope,
|
|
@@ -621,6 +669,9 @@ function IssueReportingProvider({
|
|
|
621
669
|
principalId,
|
|
622
670
|
reporterRoleHint,
|
|
623
671
|
retryModalHydration,
|
|
672
|
+
resolvedDefaultInputMode,
|
|
673
|
+
resolvedInputModes,
|
|
674
|
+
resolvedVoiceConfig,
|
|
624
675
|
scope,
|
|
625
676
|
selectPanel,
|
|
626
677
|
startNewIssue
|
|
@@ -665,6 +716,18 @@ import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
|
665
716
|
function cn(...values) {
|
|
666
717
|
return values.filter(Boolean).join(" ");
|
|
667
718
|
}
|
|
719
|
+
var Z_FLOATING_BUTTON = "z-[65]";
|
|
720
|
+
var Z_BANNER = "z-[70]";
|
|
721
|
+
var Z_POPOVER = "z-[70]";
|
|
722
|
+
var Z_MODAL_OVERLAY = "z-[80]";
|
|
723
|
+
var Z_MODAL_CONTENT = "z-[81]";
|
|
724
|
+
var POPOVER_WIDTH = "w-[360px]";
|
|
725
|
+
var MODAL_WIDTH = "w-[calc(100vw-2rem)]";
|
|
726
|
+
var MODAL_RADIUS = "rounded-[28px]";
|
|
727
|
+
var POPOVER_SHADOW = "shadow-[0_18px_48px_rgba(15,23,42,0.18)]";
|
|
728
|
+
var MODAL_SHADOW = "shadow-[0_28px_80px_rgba(15,23,42,0.24)]";
|
|
729
|
+
var BADGE_TEXT = "text-[11px]";
|
|
730
|
+
var LABEL_TEXT = "text-[11px]";
|
|
668
731
|
function truncate(value, max = 80) {
|
|
669
732
|
if (value.length <= max) {
|
|
670
733
|
return value;
|
|
@@ -685,6 +748,16 @@ function resolveErrorMessage(error, fallback) {
|
|
|
685
748
|
}
|
|
686
749
|
return fallback;
|
|
687
750
|
}
|
|
751
|
+
function getCommittedTranscriptText(committedTranscripts) {
|
|
752
|
+
return committedTranscripts.map((segment) => segment.text.trim()).filter(Boolean).join(" ").trim();
|
|
753
|
+
}
|
|
754
|
+
function appendTranscriptToNote(current, transcript) {
|
|
755
|
+
const normalizedCurrent = current.trim();
|
|
756
|
+
if (!normalizedCurrent) {
|
|
757
|
+
return transcript;
|
|
758
|
+
}
|
|
759
|
+
return `${normalizedCurrent} ${transcript}`;
|
|
760
|
+
}
|
|
688
761
|
function resolveReporterId(issue) {
|
|
689
762
|
return issue.reporter_principal_id ?? issue.reporter_user_id ?? null;
|
|
690
763
|
}
|
|
@@ -717,13 +790,390 @@ function getIssueOriginText(issue, copy) {
|
|
|
717
790
|
const humanName = issue.reporter_display_name?.trim();
|
|
718
791
|
return humanName ? `${copy.originHumanLabel} \xB7 ${humanName}` : copy.originHumanLabel;
|
|
719
792
|
}
|
|
793
|
+
function IssueReportVoicePanel({
|
|
794
|
+
canUseText,
|
|
795
|
+
effectiveInputMode,
|
|
796
|
+
isSubmitting,
|
|
797
|
+
isVoiceActive,
|
|
798
|
+
isVoiceConnecting,
|
|
799
|
+
voice,
|
|
800
|
+
voiceTokenResult,
|
|
801
|
+
committedTranscript,
|
|
802
|
+
voiceError,
|
|
803
|
+
scribeError,
|
|
804
|
+
onSelectText,
|
|
805
|
+
onSelectVoice,
|
|
806
|
+
onStartVoiceInput,
|
|
807
|
+
onStopVoiceInput,
|
|
808
|
+
onAppendTranscript
|
|
809
|
+
}) {
|
|
810
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
811
|
+
canUseText ? /* @__PURE__ */ jsxs("div", { className: "mt-5 flex gap-2", children: [
|
|
812
|
+
/* @__PURE__ */ jsxs(
|
|
813
|
+
"button",
|
|
814
|
+
{
|
|
815
|
+
type: "button",
|
|
816
|
+
className: cn(
|
|
817
|
+
"inline-flex items-center gap-1 rounded-full border px-3 py-1.5 text-xs font-semibold transition",
|
|
818
|
+
effectiveInputMode === "text" ? "border-slate-900 bg-slate-900 text-white" : "border-slate-200 text-slate-700 hover:bg-slate-50"
|
|
819
|
+
),
|
|
820
|
+
onClick: onSelectText,
|
|
821
|
+
disabled: isSubmitting,
|
|
822
|
+
children: [
|
|
823
|
+
/* @__PURE__ */ jsx2(TextT, { className: "h-3.5 w-3.5" }),
|
|
824
|
+
"Text Input"
|
|
825
|
+
]
|
|
826
|
+
}
|
|
827
|
+
),
|
|
828
|
+
/* @__PURE__ */ jsxs(
|
|
829
|
+
"button",
|
|
830
|
+
{
|
|
831
|
+
type: "button",
|
|
832
|
+
className: cn(
|
|
833
|
+
"inline-flex items-center gap-1 rounded-full border px-3 py-1.5 text-xs font-semibold transition",
|
|
834
|
+
effectiveInputMode === "voice" ? "border-slate-900 bg-slate-900 text-white" : "border-slate-200 text-slate-700 hover:bg-slate-50"
|
|
835
|
+
),
|
|
836
|
+
onClick: onSelectVoice,
|
|
837
|
+
disabled: isSubmitting,
|
|
838
|
+
children: [
|
|
839
|
+
/* @__PURE__ */ jsx2(Microphone, { className: "h-3.5 w-3.5" }),
|
|
840
|
+
"Voice Input"
|
|
841
|
+
]
|
|
842
|
+
}
|
|
843
|
+
)
|
|
844
|
+
] }) : null,
|
|
845
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-4 rounded-2xl border border-slate-200 bg-slate-50 px-4 py-3", children: [
|
|
846
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
|
|
847
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
848
|
+
/* @__PURE__ */ jsx2("div", { className: "text-xs font-medium uppercase tracking-wide text-slate-500", children: "Voice Input" }),
|
|
849
|
+
/* @__PURE__ */ jsxs("p", { className: "mt-1 text-xs text-slate-600", children: [
|
|
850
|
+
"Provider: ",
|
|
851
|
+
voiceTokenResult?.provider ?? voice.provider,
|
|
852
|
+
" \xB7 Model:",
|
|
853
|
+
" ",
|
|
854
|
+
voiceTokenResult?.model_id ?? voice.modelId
|
|
855
|
+
] }),
|
|
856
|
+
/* @__PURE__ */ jsx2("p", { className: "mt-1 text-xs text-slate-500", children: voice.requireMicrophonePermission ? "Microphone access is required to transcribe." : "Microphone access policy is optional." })
|
|
857
|
+
] }),
|
|
858
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
859
|
+
isVoiceActive || isVoiceConnecting ? /* @__PURE__ */ jsx2(
|
|
860
|
+
"button",
|
|
861
|
+
{
|
|
862
|
+
type: "button",
|
|
863
|
+
className: "rounded-full border border-slate-300 px-3 py-1.5 text-xs font-medium text-slate-700 transition hover:bg-slate-100",
|
|
864
|
+
onClick: onStopVoiceInput,
|
|
865
|
+
disabled: isSubmitting,
|
|
866
|
+
children: "Stop Voice Input"
|
|
867
|
+
}
|
|
868
|
+
) : /* @__PURE__ */ jsx2(
|
|
869
|
+
"button",
|
|
870
|
+
{
|
|
871
|
+
type: "button",
|
|
872
|
+
className: "rounded-full bg-slate-900 px-3 py-1.5 text-xs font-semibold text-white transition hover:bg-slate-800",
|
|
873
|
+
onClick: onStartVoiceInput,
|
|
874
|
+
disabled: isSubmitting,
|
|
875
|
+
children: "Start Voice Input"
|
|
876
|
+
}
|
|
877
|
+
),
|
|
878
|
+
canUseText ? /* @__PURE__ */ jsx2(
|
|
879
|
+
"button",
|
|
880
|
+
{
|
|
881
|
+
type: "button",
|
|
882
|
+
className: "rounded-full border border-slate-300 px-3 py-1.5 text-xs font-medium text-slate-700 transition hover:bg-slate-100 disabled:cursor-not-allowed disabled:opacity-60",
|
|
883
|
+
onClick: onAppendTranscript,
|
|
884
|
+
disabled: isSubmitting || !committedTranscript.trim(),
|
|
885
|
+
children: "Append Transcript"
|
|
886
|
+
}
|
|
887
|
+
) : null
|
|
888
|
+
] })
|
|
889
|
+
] }),
|
|
890
|
+
/* @__PURE__ */ jsx2("div", { className: "mt-3 rounded-xl border border-slate-200 bg-white px-3 py-2 text-sm text-slate-700", children: committedTranscript ? committedTranscript : /* @__PURE__ */ jsx2("span", { className: "text-slate-500", children: "No committed transcript yet." }) }),
|
|
891
|
+
voiceError || scribeError ? /* @__PURE__ */ jsx2("div", { className: "mt-2 rounded-xl border border-rose-200 bg-rose-50 px-3 py-2 text-xs text-rose-700", children: voiceError ?? scribeError }) : isVoiceConnecting ? /* @__PURE__ */ jsx2("div", { className: "mt-2 text-xs text-slate-500", children: "Connecting voice transcription..." }) : null
|
|
892
|
+
] })
|
|
893
|
+
] });
|
|
894
|
+
}
|
|
895
|
+
function IssueReportNoteEditor({
|
|
896
|
+
canUseText,
|
|
897
|
+
note,
|
|
898
|
+
normalizedNote,
|
|
899
|
+
isSubmitting,
|
|
900
|
+
copy,
|
|
901
|
+
onNoteChange,
|
|
902
|
+
onSubmit
|
|
903
|
+
}) {
|
|
904
|
+
if (!canUseText) {
|
|
905
|
+
return /* @__PURE__ */ jsxs("div", { className: "mt-5 rounded-2xl border border-slate-200 bg-slate-50 px-4 py-3 text-xs text-slate-600", children: [
|
|
906
|
+
/* @__PURE__ */ jsx2("div", { children: getIssueNoteLengthMessage(normalizedNote, copy) }),
|
|
907
|
+
/* @__PURE__ */ jsx2("div", { className: "mt-1", children: "Submit is enabled after a committed transcript reaches 10-2000 characters." })
|
|
908
|
+
] });
|
|
909
|
+
}
|
|
910
|
+
return /* @__PURE__ */ jsxs("div", { className: "mt-5 space-y-2", children: [
|
|
911
|
+
/* @__PURE__ */ jsx2(
|
|
912
|
+
"textarea",
|
|
913
|
+
{
|
|
914
|
+
value: note,
|
|
915
|
+
onChange: (event) => onNoteChange(event.target.value),
|
|
916
|
+
onKeyDown: (event) => {
|
|
917
|
+
if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
|
|
918
|
+
event.preventDefault();
|
|
919
|
+
onSubmit();
|
|
920
|
+
}
|
|
921
|
+
},
|
|
922
|
+
placeholder: copy.notePlaceholder,
|
|
923
|
+
className: "h-36 w-full resize-none rounded-2xl border border-slate-300 px-4 py-3 text-sm text-slate-800 outline-none transition focus:border-slate-500 focus:ring-2 focus:ring-slate-200",
|
|
924
|
+
disabled: isSubmitting,
|
|
925
|
+
autoFocus: true
|
|
926
|
+
}
|
|
927
|
+
),
|
|
928
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs text-slate-500", children: [
|
|
929
|
+
/* @__PURE__ */ jsx2("span", { children: getIssueNoteLengthMessage(note, copy) }),
|
|
930
|
+
/* @__PURE__ */ jsx2("span", { children: copy.keyboardShortcutHint })
|
|
931
|
+
] })
|
|
932
|
+
] });
|
|
933
|
+
}
|
|
934
|
+
function IssueReportModalDescription({
|
|
935
|
+
copy,
|
|
936
|
+
mode,
|
|
937
|
+
target
|
|
938
|
+
}) {
|
|
939
|
+
if (mode === "create" && target) {
|
|
940
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
941
|
+
copy.createDescriptionPrefix,
|
|
942
|
+
" ",
|
|
943
|
+
/* @__PURE__ */ jsx2("code", { className: "rounded bg-slate-100 px-1.5 py-0.5 text-xs text-slate-700", children: target.page_url })
|
|
944
|
+
] });
|
|
945
|
+
}
|
|
946
|
+
return mode === "edit" ? copy.editDescription : copy.replyDescription;
|
|
947
|
+
}
|
|
948
|
+
function IssueReportModalBody({
|
|
949
|
+
copy,
|
|
950
|
+
mode,
|
|
951
|
+
issue,
|
|
952
|
+
isHydrating,
|
|
953
|
+
error,
|
|
954
|
+
canUseVoice,
|
|
955
|
+
canUseText,
|
|
956
|
+
effectiveInputMode,
|
|
957
|
+
note,
|
|
958
|
+
normalizedNote,
|
|
959
|
+
isValid,
|
|
960
|
+
isSubmitting,
|
|
961
|
+
isVoiceActive,
|
|
962
|
+
isVoiceConnecting,
|
|
963
|
+
voice,
|
|
964
|
+
voiceTokenResult,
|
|
965
|
+
committedTranscript,
|
|
966
|
+
voiceError,
|
|
967
|
+
scribeError,
|
|
968
|
+
submitError,
|
|
969
|
+
onRetryHydration,
|
|
970
|
+
onClose,
|
|
971
|
+
onSelectText,
|
|
972
|
+
onSelectVoice,
|
|
973
|
+
onStartVoiceInput,
|
|
974
|
+
onStopVoiceInput,
|
|
975
|
+
onAppendTranscript,
|
|
976
|
+
onNoteChange,
|
|
977
|
+
onSubmit
|
|
978
|
+
}) {
|
|
979
|
+
if (isHydrating) {
|
|
980
|
+
return /* @__PURE__ */ jsxs("div", { className: "mt-5 flex items-center gap-2 rounded-2xl border border-slate-200 bg-slate-50 px-4 py-4 text-sm text-slate-600", children: [
|
|
981
|
+
/* @__PURE__ */ jsx2(Spinner, { className: "h-4 w-4 animate-spin" }),
|
|
982
|
+
/* @__PURE__ */ jsx2("span", { children: copy.hydrateLoading })
|
|
983
|
+
] });
|
|
984
|
+
}
|
|
985
|
+
if (error) {
|
|
986
|
+
return /* @__PURE__ */ jsxs("div", { className: "mt-5 space-y-3 rounded-2xl border border-rose-200 bg-rose-50 px-4 py-4 text-sm text-rose-700", children: [
|
|
987
|
+
/* @__PURE__ */ jsx2("div", { children: error }),
|
|
988
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
989
|
+
/* @__PURE__ */ jsx2(
|
|
990
|
+
"button",
|
|
991
|
+
{
|
|
992
|
+
type: "button",
|
|
993
|
+
className: "rounded-full border border-rose-300 px-3 py-1 font-medium transition hover:bg-rose-100",
|
|
994
|
+
onClick: onRetryHydration,
|
|
995
|
+
children: copy.retryAction
|
|
996
|
+
}
|
|
997
|
+
),
|
|
998
|
+
/* @__PURE__ */ jsx2(
|
|
999
|
+
"button",
|
|
1000
|
+
{
|
|
1001
|
+
type: "button",
|
|
1002
|
+
className: "rounded-full border border-slate-300 px-3 py-1 font-medium text-slate-700 transition hover:bg-slate-50",
|
|
1003
|
+
onClick: onClose,
|
|
1004
|
+
children: copy.cancelAction
|
|
1005
|
+
}
|
|
1006
|
+
)
|
|
1007
|
+
] })
|
|
1008
|
+
] });
|
|
1009
|
+
}
|
|
1010
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1011
|
+
mode === "create" && canUseVoice ? /* @__PURE__ */ jsx2(
|
|
1012
|
+
IssueReportVoicePanel,
|
|
1013
|
+
{
|
|
1014
|
+
canUseText,
|
|
1015
|
+
effectiveInputMode,
|
|
1016
|
+
isSubmitting,
|
|
1017
|
+
isVoiceActive,
|
|
1018
|
+
isVoiceConnecting,
|
|
1019
|
+
voice,
|
|
1020
|
+
voiceTokenResult,
|
|
1021
|
+
committedTranscript,
|
|
1022
|
+
voiceError,
|
|
1023
|
+
scribeError,
|
|
1024
|
+
onSelectText,
|
|
1025
|
+
onSelectVoice,
|
|
1026
|
+
onStartVoiceInput,
|
|
1027
|
+
onStopVoiceInput,
|
|
1028
|
+
onAppendTranscript
|
|
1029
|
+
}
|
|
1030
|
+
) : null,
|
|
1031
|
+
mode === "reply" && issue ? /* @__PURE__ */ jsxs("div", { className: "mt-5 rounded-2xl border border-slate-200 bg-slate-50 px-4 py-3", children: [
|
|
1032
|
+
/* @__PURE__ */ jsx2("div", { className: "text-xs font-medium uppercase tracking-wide text-slate-500", children: copy.originalIssueLabel }),
|
|
1033
|
+
/* @__PURE__ */ jsx2("p", { className: "mt-1 text-sm text-slate-700", children: issue.note })
|
|
1034
|
+
] }) : null,
|
|
1035
|
+
/* @__PURE__ */ jsx2(
|
|
1036
|
+
IssueReportNoteEditor,
|
|
1037
|
+
{
|
|
1038
|
+
canUseText,
|
|
1039
|
+
note,
|
|
1040
|
+
normalizedNote,
|
|
1041
|
+
isSubmitting,
|
|
1042
|
+
copy,
|
|
1043
|
+
onNoteChange,
|
|
1044
|
+
onSubmit
|
|
1045
|
+
}
|
|
1046
|
+
),
|
|
1047
|
+
submitError ? /* @__PURE__ */ jsx2("div", { className: "mt-4 rounded-2xl border border-rose-200 bg-rose-50 px-4 py-3 text-sm text-rose-700", children: submitError }) : null,
|
|
1048
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-6 flex justify-end gap-3", children: [
|
|
1049
|
+
/* @__PURE__ */ jsx2(
|
|
1050
|
+
"button",
|
|
1051
|
+
{
|
|
1052
|
+
type: "button",
|
|
1053
|
+
className: "rounded-full border border-slate-300 px-4 py-2 text-sm font-medium text-slate-700 transition hover:bg-slate-50",
|
|
1054
|
+
onClick: onClose,
|
|
1055
|
+
disabled: isSubmitting,
|
|
1056
|
+
children: copy.cancelAction
|
|
1057
|
+
}
|
|
1058
|
+
),
|
|
1059
|
+
/* @__PURE__ */ jsx2(
|
|
1060
|
+
"button",
|
|
1061
|
+
{
|
|
1062
|
+
type: "button",
|
|
1063
|
+
className: cn(
|
|
1064
|
+
"rounded-full px-4 py-2 text-sm font-semibold text-white transition",
|
|
1065
|
+
isValid && !isSubmitting ? "bg-slate-900 hover:bg-slate-800" : "cursor-not-allowed bg-slate-300"
|
|
1066
|
+
),
|
|
1067
|
+
onClick: onSubmit,
|
|
1068
|
+
disabled: !isValid || isSubmitting,
|
|
1069
|
+
children: isSubmitting ? copy.submittingAction : copy.submitAction
|
|
1070
|
+
}
|
|
1071
|
+
)
|
|
1072
|
+
] })
|
|
1073
|
+
] });
|
|
1074
|
+
}
|
|
1075
|
+
function useIssueReportVoiceCapture({
|
|
1076
|
+
canUseVoice,
|
|
1077
|
+
defaultInputMode,
|
|
1078
|
+
isSubmitting,
|
|
1079
|
+
voice
|
|
1080
|
+
}) {
|
|
1081
|
+
const [inputMode, setInputMode] = useState2(defaultInputMode);
|
|
1082
|
+
const [voiceTokenResult, setVoiceTokenResult] = useState2(null);
|
|
1083
|
+
const [voiceSubmitMetadata, setVoiceSubmitMetadata] = useState2(null);
|
|
1084
|
+
const [voiceError, setVoiceError] = useState2(null);
|
|
1085
|
+
const {
|
|
1086
|
+
status: scribeStatus,
|
|
1087
|
+
isConnected,
|
|
1088
|
+
isTranscribing,
|
|
1089
|
+
committedTranscripts,
|
|
1090
|
+
error: scribeError,
|
|
1091
|
+
connect: connectScribe,
|
|
1092
|
+
disconnect: disconnectScribe
|
|
1093
|
+
} = useScribe({
|
|
1094
|
+
autoConnect: false,
|
|
1095
|
+
modelId: voice.modelId,
|
|
1096
|
+
microphone: voice.microphone
|
|
1097
|
+
});
|
|
1098
|
+
const committedTranscript = useMemo2(
|
|
1099
|
+
() => getCommittedTranscriptText(committedTranscripts),
|
|
1100
|
+
[committedTranscripts]
|
|
1101
|
+
);
|
|
1102
|
+
const isVoiceConnecting = scribeStatus === "connecting";
|
|
1103
|
+
const isVoiceActive = isConnected || isTranscribing;
|
|
1104
|
+
const resetVoiceCapture = useCallback2(() => {
|
|
1105
|
+
disconnectScribe();
|
|
1106
|
+
setInputMode(defaultInputMode);
|
|
1107
|
+
setVoiceTokenResult(null);
|
|
1108
|
+
setVoiceSubmitMetadata(null);
|
|
1109
|
+
setVoiceError(null);
|
|
1110
|
+
}, [defaultInputMode, disconnectScribe]);
|
|
1111
|
+
const startVoiceInput = useCallback2(
|
|
1112
|
+
async (createVoiceToken) => {
|
|
1113
|
+
if (!canUseVoice || isSubmitting || isVoiceActive || isVoiceConnecting) {
|
|
1114
|
+
return;
|
|
1115
|
+
}
|
|
1116
|
+
if (!createVoiceToken) {
|
|
1117
|
+
setVoiceError("Voice input is unavailable for this client.");
|
|
1118
|
+
return;
|
|
1119
|
+
}
|
|
1120
|
+
setVoiceError(null);
|
|
1121
|
+
try {
|
|
1122
|
+
const tokenResult = await createVoiceToken();
|
|
1123
|
+
setVoiceTokenResult(tokenResult);
|
|
1124
|
+
setVoiceSubmitMetadata(tokenResult);
|
|
1125
|
+
await connectScribe({
|
|
1126
|
+
token: tokenResult.token,
|
|
1127
|
+
modelId: tokenResult.model_id,
|
|
1128
|
+
microphone: voice.microphone
|
|
1129
|
+
});
|
|
1130
|
+
setInputMode("voice");
|
|
1131
|
+
} catch (startError) {
|
|
1132
|
+
setVoiceError(resolveErrorMessage(startError, "Failed to start voice input."));
|
|
1133
|
+
}
|
|
1134
|
+
},
|
|
1135
|
+
[
|
|
1136
|
+
canUseVoice,
|
|
1137
|
+
connectScribe,
|
|
1138
|
+
isSubmitting,
|
|
1139
|
+
isVoiceActive,
|
|
1140
|
+
isVoiceConnecting,
|
|
1141
|
+
voice.microphone
|
|
1142
|
+
]
|
|
1143
|
+
);
|
|
1144
|
+
const appendTranscript = useCallback2(
|
|
1145
|
+
(setNote) => {
|
|
1146
|
+
if (!committedTranscript.trim()) {
|
|
1147
|
+
return;
|
|
1148
|
+
}
|
|
1149
|
+
setNote((current) => appendTranscriptToNote(current, committedTranscript));
|
|
1150
|
+
setInputMode("text");
|
|
1151
|
+
},
|
|
1152
|
+
[committedTranscript]
|
|
1153
|
+
);
|
|
1154
|
+
return {
|
|
1155
|
+
inputMode,
|
|
1156
|
+
setInputMode,
|
|
1157
|
+
voiceTokenResult,
|
|
1158
|
+
voiceSubmitMetadata,
|
|
1159
|
+
committedTranscript,
|
|
1160
|
+
voiceError,
|
|
1161
|
+
scribeError,
|
|
1162
|
+
isVoiceConnecting,
|
|
1163
|
+
isVoiceActive,
|
|
1164
|
+
resetVoiceCapture,
|
|
1165
|
+
startVoiceInput,
|
|
1166
|
+
stopVoiceInput: disconnectScribe,
|
|
1167
|
+
appendTranscript
|
|
1168
|
+
};
|
|
1169
|
+
}
|
|
720
1170
|
function IssueReportModeBanner() {
|
|
721
1171
|
const { copy } = useIssueReporting();
|
|
722
1172
|
const reportMode = useReportMode();
|
|
723
1173
|
if (!reportMode?.isReportMode) {
|
|
724
1174
|
return null;
|
|
725
1175
|
}
|
|
726
|
-
return /* @__PURE__ */ jsx2("div", { className: "fixed inset-x-4 top-4
|
|
1176
|
+
return /* @__PURE__ */ jsx2("div", { className: cn("fixed inset-x-4 top-4 flex justify-center", Z_BANNER), children: /* @__PURE__ */ jsx2("div", { className: "max-w-xl rounded-full border border-amber-300 bg-amber-50/95 px-4 py-3 text-sm text-amber-950 shadow-lg backdrop-blur", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-center gap-3", children: [
|
|
727
1177
|
/* @__PURE__ */ jsx2("div", { className: "font-medium", children: copy.reportModeTitle }),
|
|
728
1178
|
/* @__PURE__ */ jsx2("div", { className: "text-amber-900/80", children: copy.reportModeDescription }),
|
|
729
1179
|
/* @__PURE__ */ jsx2(
|
|
@@ -786,13 +1236,14 @@ function IssueList({
|
|
|
786
1236
|
"span",
|
|
787
1237
|
{
|
|
788
1238
|
className: cn(
|
|
789
|
-
"rounded-full px-2 py-0.5
|
|
1239
|
+
"rounded-full px-2 py-0.5 font-medium",
|
|
1240
|
+
BADGE_TEXT,
|
|
790
1241
|
getIssueStatusClassName(issue.status)
|
|
791
1242
|
),
|
|
792
1243
|
children: getIssueStatusBadgeLabel(issue.status)
|
|
793
1244
|
}
|
|
794
1245
|
),
|
|
795
|
-
/* @__PURE__ */ jsx2("span", { className: "rounded-full bg-slate-100 px-2 py-0.5
|
|
1246
|
+
/* @__PURE__ */ jsx2("span", { className: cn("rounded-full bg-slate-100 px-2 py-0.5 font-medium text-slate-600", BADGE_TEXT), children: getIssueOriginText(issue, copy) }),
|
|
796
1247
|
/* @__PURE__ */ jsx2("span", { className: "text-xs text-slate-400", children: formatRelativeTime(issue.updated_at) })
|
|
797
1248
|
] })
|
|
798
1249
|
] }),
|
|
@@ -859,7 +1310,12 @@ function IssueReportPopover({ children }) {
|
|
|
859
1310
|
align: "end",
|
|
860
1311
|
side: "top",
|
|
861
1312
|
sideOffset: 12,
|
|
862
|
-
className:
|
|
1313
|
+
className: cn(
|
|
1314
|
+
"rounded-3xl border border-slate-200 bg-white p-4",
|
|
1315
|
+
Z_POPOVER,
|
|
1316
|
+
POPOVER_WIDTH,
|
|
1317
|
+
POPOVER_SHADOW
|
|
1318
|
+
),
|
|
863
1319
|
children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
864
1320
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
|
|
865
1321
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
@@ -939,7 +1395,7 @@ function IssueReportPopover({ children }) {
|
|
|
939
1395
|
)
|
|
940
1396
|
] }) : null,
|
|
941
1397
|
allowTenantScope ? /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
942
|
-
/* @__PURE__ */ jsx2("div", { className: "
|
|
1398
|
+
/* @__PURE__ */ jsx2("div", { className: cn("font-medium uppercase tracking-wide text-slate-500", LABEL_TEXT), children: copy.scopeLabel }),
|
|
943
1399
|
/* @__PURE__ */ jsx2("div", { className: "flex gap-2", children: [
|
|
944
1400
|
["tenant", copy.scopeTenant],
|
|
945
1401
|
["mine", copy.scopeMine]
|
|
@@ -995,18 +1451,46 @@ function IssueReportPopover({ children }) {
|
|
|
995
1451
|
}
|
|
996
1452
|
function IssueReportModal() {
|
|
997
1453
|
const {
|
|
1454
|
+
client,
|
|
998
1455
|
copy,
|
|
999
1456
|
reporterRoleHint,
|
|
1000
1457
|
modalState,
|
|
1001
1458
|
closeModal,
|
|
1002
|
-
retryModalHydration
|
|
1459
|
+
retryModalHydration,
|
|
1460
|
+
inputModes,
|
|
1461
|
+
defaultInputMode,
|
|
1462
|
+
voice
|
|
1003
1463
|
} = useIssueReporting();
|
|
1004
1464
|
const { createMutation, updateMutation, replyMutation } = useIssueReportingMutations();
|
|
1005
1465
|
const [note, setNote] = useState2("");
|
|
1006
1466
|
const [submitError, setSubmitError] = useState2(null);
|
|
1007
1467
|
const { isOpen, mode, issue, target, isHydrating, error } = modalState;
|
|
1468
|
+
const canUseVoice = mode === "create" && inputModes.includes("voice");
|
|
1469
|
+
const canUseText = mode !== "create" || inputModes.includes("text");
|
|
1470
|
+
const isSubmitting = createMutation.isPending || updateMutation.isPending || replyMutation.isPending;
|
|
1471
|
+
const {
|
|
1472
|
+
inputMode,
|
|
1473
|
+
setInputMode,
|
|
1474
|
+
voiceTokenResult,
|
|
1475
|
+
voiceSubmitMetadata,
|
|
1476
|
+
committedTranscript,
|
|
1477
|
+
voiceError,
|
|
1478
|
+
scribeError,
|
|
1479
|
+
isVoiceConnecting,
|
|
1480
|
+
isVoiceActive,
|
|
1481
|
+
resetVoiceCapture,
|
|
1482
|
+
startVoiceInput,
|
|
1483
|
+
stopVoiceInput,
|
|
1484
|
+
appendTranscript
|
|
1485
|
+
} = useIssueReportVoiceCapture({
|
|
1486
|
+
canUseVoice,
|
|
1487
|
+
defaultInputMode,
|
|
1488
|
+
isSubmitting,
|
|
1489
|
+
voice
|
|
1490
|
+
});
|
|
1008
1491
|
useEffect2(() => {
|
|
1009
1492
|
if (!isOpen) {
|
|
1493
|
+
resetVoiceCapture();
|
|
1010
1494
|
setNote("");
|
|
1011
1495
|
setSubmitError(null);
|
|
1012
1496
|
return;
|
|
@@ -1016,140 +1500,145 @@ function IssueReportModal() {
|
|
|
1016
1500
|
} else {
|
|
1017
1501
|
setNote("");
|
|
1018
1502
|
}
|
|
1503
|
+
resetVoiceCapture();
|
|
1019
1504
|
setSubmitError(null);
|
|
1020
|
-
}, [isOpen, mode,
|
|
1021
|
-
const
|
|
1022
|
-
const
|
|
1505
|
+
}, [isOpen, issue, mode, resetVoiceCapture]);
|
|
1506
|
+
const effectiveInputMode = mode !== "create" ? "text" : canUseVoice && inputMode === "voice" ? "voice" : "text";
|
|
1507
|
+
const normalizedNote = effectiveInputMode === "voice" ? committedTranscript.trim() : note.trim();
|
|
1508
|
+
const isValid = normalizedNote.length >= 10 && normalizedNote.length <= 2e3;
|
|
1023
1509
|
const title = mode === "create" ? `${copy.createTitlePrefix}: ${target?.component_label ?? ""}` : mode === "edit" ? `${copy.editTitlePrefix}: ${target?.component_label ?? ""}` : `${copy.replyTitlePrefix}: ${target?.component_label ?? ""}`;
|
|
1510
|
+
const handleCloseModal = () => {
|
|
1511
|
+
resetVoiceCapture();
|
|
1512
|
+
closeModal();
|
|
1513
|
+
};
|
|
1514
|
+
const handleStartVoiceInput = async () => {
|
|
1515
|
+
await startVoiceInput(client.issueReporting.createVoiceToken);
|
|
1516
|
+
};
|
|
1517
|
+
const handleStopVoiceInput = () => {
|
|
1518
|
+
stopVoiceInput();
|
|
1519
|
+
};
|
|
1520
|
+
const handleAppendTranscript = () => {
|
|
1521
|
+
appendTranscript(setNote);
|
|
1522
|
+
};
|
|
1024
1523
|
const handleSubmit = async () => {
|
|
1025
1524
|
if (!target || !isValid || isSubmitting) {
|
|
1026
1525
|
return;
|
|
1027
1526
|
}
|
|
1028
1527
|
setSubmitError(null);
|
|
1029
1528
|
try {
|
|
1030
|
-
const
|
|
1529
|
+
const noteForSubmit = normalizedNote;
|
|
1530
|
+
const effectiveVoiceMetadata = effectiveInputMode === "voice" ? voiceSubmitMetadata ?? {
|
|
1531
|
+
provider: voice.provider,
|
|
1532
|
+
token: "",
|
|
1533
|
+
model_id: voice.modelId,
|
|
1534
|
+
expires_in_seconds: 0,
|
|
1535
|
+
retain_audio: false,
|
|
1536
|
+
attach_transcript: true
|
|
1537
|
+
} : null;
|
|
1031
1538
|
if (mode === "create") {
|
|
1032
1539
|
await createMutation.mutateAsync({
|
|
1033
|
-
target
|
|
1034
|
-
|
|
1540
|
+
target: effectiveVoiceMetadata && effectiveInputMode === "voice" ? {
|
|
1541
|
+
...target,
|
|
1542
|
+
metadata: {
|
|
1543
|
+
...target.metadata ?? {},
|
|
1544
|
+
capture: {
|
|
1545
|
+
input_mode: "voice",
|
|
1546
|
+
provider: effectiveVoiceMetadata.provider,
|
|
1547
|
+
model_id: effectiveVoiceMetadata.model_id,
|
|
1548
|
+
retain_audio: effectiveVoiceMetadata.retain_audio,
|
|
1549
|
+
attach_transcript: effectiveVoiceMetadata.attach_transcript
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
} : target,
|
|
1553
|
+
note: noteForSubmit,
|
|
1035
1554
|
reporter_role_hint: reporterRoleHint
|
|
1036
1555
|
});
|
|
1037
1556
|
} else if (mode === "edit" && issue) {
|
|
1038
1557
|
await updateMutation.mutateAsync({
|
|
1039
1558
|
issueReportId: issue.id,
|
|
1040
|
-
note:
|
|
1559
|
+
note: noteForSubmit
|
|
1041
1560
|
});
|
|
1042
1561
|
} else if (mode === "reply" && issue) {
|
|
1043
1562
|
await replyMutation.mutateAsync({
|
|
1044
1563
|
issueReportId: issue.id,
|
|
1045
|
-
note:
|
|
1564
|
+
note: noteForSubmit,
|
|
1046
1565
|
reporterRoleHint
|
|
1047
1566
|
});
|
|
1048
1567
|
}
|
|
1568
|
+
resetVoiceCapture();
|
|
1049
1569
|
closeModal();
|
|
1050
1570
|
} catch (submissionError) {
|
|
1051
1571
|
setSubmitError(resolveErrorMessage(submissionError, "Failed to submit issue report"));
|
|
1052
1572
|
}
|
|
1053
1573
|
};
|
|
1054
|
-
return /* @__PURE__ */ jsx2(Dialog.Root, { open: isOpen, onOpenChange: (open) => !open &&
|
|
1055
|
-
/* @__PURE__ */ jsx2(Dialog.Overlay, { className: "fixed inset-0
|
|
1056
|
-
/* @__PURE__ */ jsxs(
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
"button",
|
|
1071
|
-
{
|
|
1072
|
-
type: "button",
|
|
1073
|
-
className: "rounded-full border border-rose-300 px-3 py-1 font-medium transition hover:bg-rose-100",
|
|
1074
|
-
onClick: () => retryModalHydration(),
|
|
1075
|
-
children: copy.retryAction
|
|
1076
|
-
}
|
|
1077
|
-
),
|
|
1078
|
-
/* @__PURE__ */ jsx2(
|
|
1079
|
-
"button",
|
|
1080
|
-
{
|
|
1081
|
-
type: "button",
|
|
1082
|
-
className: "rounded-full border border-slate-300 px-3 py-1 font-medium text-slate-700 transition hover:bg-slate-50",
|
|
1083
|
-
onClick: closeModal,
|
|
1084
|
-
children: copy.cancelAction
|
|
1085
|
-
}
|
|
1086
|
-
)
|
|
1087
|
-
] })
|
|
1088
|
-
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1089
|
-
mode === "reply" && issue ? /* @__PURE__ */ jsxs("div", { className: "mt-5 rounded-2xl border border-slate-200 bg-slate-50 px-4 py-3", children: [
|
|
1090
|
-
/* @__PURE__ */ jsx2("div", { className: "text-xs font-medium uppercase tracking-wide text-slate-500", children: copy.originalIssueLabel }),
|
|
1091
|
-
/* @__PURE__ */ jsx2("p", { className: "mt-1 text-sm text-slate-700", children: issue.note })
|
|
1092
|
-
] }) : null,
|
|
1093
|
-
/* @__PURE__ */ jsxs("div", { className: "mt-5 space-y-2", children: [
|
|
1094
|
-
/* @__PURE__ */ jsx2(
|
|
1095
|
-
"textarea",
|
|
1574
|
+
return /* @__PURE__ */ jsx2(Dialog.Root, { open: isOpen, onOpenChange: (open) => !open && handleCloseModal(), children: /* @__PURE__ */ jsxs(Dialog.Portal, { children: [
|
|
1575
|
+
/* @__PURE__ */ jsx2(Dialog.Overlay, { className: cn("fixed inset-0 bg-slate-950/45 backdrop-blur-sm", Z_MODAL_OVERLAY) }),
|
|
1576
|
+
/* @__PURE__ */ jsxs(
|
|
1577
|
+
Dialog.Content,
|
|
1578
|
+
{
|
|
1579
|
+
className: cn(
|
|
1580
|
+
"fixed left-1/2 top-1/2 max-w-xl -translate-x-1/2 -translate-y-1/2 border border-slate-200 bg-white p-6 focus:outline-none",
|
|
1581
|
+
Z_MODAL_CONTENT,
|
|
1582
|
+
MODAL_WIDTH,
|
|
1583
|
+
MODAL_RADIUS,
|
|
1584
|
+
MODAL_SHADOW
|
|
1585
|
+
),
|
|
1586
|
+
children: [
|
|
1587
|
+
/* @__PURE__ */ jsx2(Dialog.Title, { className: "text-lg font-semibold text-slate-950", children: title }),
|
|
1588
|
+
/* @__PURE__ */ jsx2(Dialog.Description, { className: "mt-2 text-sm text-slate-600", children: /* @__PURE__ */ jsx2(
|
|
1589
|
+
IssueReportModalDescription,
|
|
1096
1590
|
{
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
|
|
1101
|
-
event.preventDefault();
|
|
1102
|
-
void handleSubmit();
|
|
1103
|
-
}
|
|
1104
|
-
},
|
|
1105
|
-
placeholder: copy.notePlaceholder,
|
|
1106
|
-
className: "h-36 w-full resize-none rounded-2xl border border-slate-300 px-4 py-3 text-sm text-slate-800 outline-none transition focus:border-slate-500 focus:ring-2 focus:ring-slate-200",
|
|
1107
|
-
disabled: isSubmitting,
|
|
1108
|
-
autoFocus: true
|
|
1591
|
+
copy,
|
|
1592
|
+
mode,
|
|
1593
|
+
target
|
|
1109
1594
|
}
|
|
1110
|
-
),
|
|
1111
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs text-slate-500", children: [
|
|
1112
|
-
/* @__PURE__ */ jsx2("span", { children: getIssueNoteLengthMessage(note, copy) }),
|
|
1113
|
-
/* @__PURE__ */ jsx2("span", { children: copy.keyboardShortcutHint })
|
|
1114
|
-
] })
|
|
1115
|
-
] }),
|
|
1116
|
-
submitError ? /* @__PURE__ */ jsx2("div", { className: "mt-4 rounded-2xl border border-rose-200 bg-rose-50 px-4 py-3 text-sm text-rose-700", children: submitError }) : null,
|
|
1117
|
-
/* @__PURE__ */ jsxs("div", { className: "mt-6 flex justify-end gap-3", children: [
|
|
1595
|
+
) }),
|
|
1118
1596
|
/* @__PURE__ */ jsx2(
|
|
1119
|
-
|
|
1597
|
+
IssueReportModalBody,
|
|
1120
1598
|
{
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1599
|
+
copy,
|
|
1600
|
+
mode,
|
|
1601
|
+
issue,
|
|
1602
|
+
isHydrating,
|
|
1603
|
+
error,
|
|
1604
|
+
canUseVoice,
|
|
1605
|
+
canUseText,
|
|
1606
|
+
effectiveInputMode,
|
|
1607
|
+
note,
|
|
1608
|
+
normalizedNote,
|
|
1609
|
+
isValid,
|
|
1610
|
+
isSubmitting,
|
|
1611
|
+
isVoiceActive,
|
|
1612
|
+
isVoiceConnecting,
|
|
1613
|
+
voice,
|
|
1614
|
+
voiceTokenResult,
|
|
1615
|
+
committedTranscript,
|
|
1616
|
+
voiceError,
|
|
1617
|
+
scribeError,
|
|
1618
|
+
submitError,
|
|
1619
|
+
onRetryHydration: () => void retryModalHydration(),
|
|
1620
|
+
onClose: handleCloseModal,
|
|
1621
|
+
onSelectText: () => setInputMode("text"),
|
|
1622
|
+
onSelectVoice: () => setInputMode("voice"),
|
|
1623
|
+
onStartVoiceInput: () => void handleStartVoiceInput(),
|
|
1624
|
+
onStopVoiceInput: handleStopVoiceInput,
|
|
1625
|
+
onAppendTranscript: handleAppendTranscript,
|
|
1626
|
+
onNoteChange: setNote,
|
|
1627
|
+
onSubmit: () => void handleSubmit()
|
|
1126
1628
|
}
|
|
1127
1629
|
),
|
|
1128
|
-
/* @__PURE__ */ jsx2(
|
|
1630
|
+
/* @__PURE__ */ jsx2(Dialog.Close, { asChild: true, children: /* @__PURE__ */ jsx2(
|
|
1129
1631
|
"button",
|
|
1130
1632
|
{
|
|
1131
1633
|
type: "button",
|
|
1132
|
-
className:
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
),
|
|
1136
|
-
onClick: () => void handleSubmit(),
|
|
1137
|
-
disabled: !isValid || isSubmitting,
|
|
1138
|
-
children: isSubmitting ? copy.submittingAction : copy.submitAction
|
|
1634
|
+
className: "absolute right-4 top-4 inline-flex h-9 w-9 items-center justify-center rounded-full border border-slate-200 text-slate-500 transition hover:bg-slate-50 hover:text-slate-900",
|
|
1635
|
+
"aria-label": "Close issue report modal",
|
|
1636
|
+
children: /* @__PURE__ */ jsx2(X, { className: "h-4 w-4" })
|
|
1139
1637
|
}
|
|
1140
|
-
)
|
|
1141
|
-
]
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
"button",
|
|
1145
|
-
{
|
|
1146
|
-
type: "button",
|
|
1147
|
-
className: "absolute right-4 top-4 inline-flex h-9 w-9 items-center justify-center rounded-full border border-slate-200 text-slate-500 transition hover:bg-slate-50 hover:text-slate-900",
|
|
1148
|
-
"aria-label": "Close issue report modal",
|
|
1149
|
-
children: /* @__PURE__ */ jsx2(X, { className: "h-4 w-4" })
|
|
1150
|
-
}
|
|
1151
|
-
) })
|
|
1152
|
-
] })
|
|
1638
|
+
) })
|
|
1639
|
+
]
|
|
1640
|
+
}
|
|
1641
|
+
)
|
|
1153
1642
|
] }) });
|
|
1154
1643
|
}
|
|
1155
1644
|
function FloatingIssueReportButton({
|
|
@@ -1171,7 +1660,7 @@ function FloatingIssueReportButton({
|
|
|
1171
1660
|
}
|
|
1172
1661
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1173
1662
|
/* @__PURE__ */ jsx2(IssueReportModeBanner, {}),
|
|
1174
|
-
!isReportMode ? /* @__PURE__ */ jsx2("div", { className: cn("fixed bottom-12 right-4
|
|
1663
|
+
!isReportMode ? /* @__PURE__ */ jsx2("div", { className: cn("fixed bottom-12 right-4", Z_FLOATING_BUTTON, positionClassName), children: /* @__PURE__ */ jsx2(IssueReportPopover, { children: /* @__PURE__ */ jsx2(
|
|
1175
1664
|
"button",
|
|
1176
1665
|
{
|
|
1177
1666
|
type: "button",
|