@david-xpn/llm-ui-feedback 0.1.14 → 0.1.16
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/dist/index.js +97 -20
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +103 -26
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/components/FeedbackWidget.tsx
|
|
2
|
-
import { useReducer, useCallback as useCallback4, useEffect as useEffect5, useMemo, useRef as
|
|
2
|
+
import { useReducer, useCallback as useCallback4, useEffect as useEffect5, useMemo, useRef as useRef4 } from "react";
|
|
3
3
|
import { createPortal } from "react-dom";
|
|
4
4
|
|
|
5
5
|
// src/utils/color.ts
|
|
@@ -16,7 +16,7 @@ function getContrastColor(hexColor) {
|
|
|
16
16
|
|
|
17
17
|
// src/components/FloatingButton.tsx
|
|
18
18
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
19
|
-
function FloatingButton({ onPickClick, onPanelToggle, draftCount, panelOpen, position, buttonColor }) {
|
|
19
|
+
function FloatingButton({ onPickClick, onPanelToggle, draftCount, panelOpen, position, buttonColor, authenticated }) {
|
|
20
20
|
const isBottom = position.includes("bottom");
|
|
21
21
|
const isRight = position.includes("right");
|
|
22
22
|
const anchor = {
|
|
@@ -30,7 +30,7 @@ function FloatingButton({ onPickClick, onPanelToggle, draftCount, panelOpen, pos
|
|
|
30
30
|
gap: 8
|
|
31
31
|
};
|
|
32
32
|
return /* @__PURE__ */ jsxs("div", { style: anchor, children: [
|
|
33
|
-
|
|
33
|
+
authenticated && /* @__PURE__ */ jsxs(
|
|
34
34
|
"button",
|
|
35
35
|
{
|
|
36
36
|
onClick: onPanelToggle,
|
|
@@ -60,7 +60,7 @@ function FloatingButton({ onPickClick, onPanelToggle, draftCount, panelOpen, pos
|
|
|
60
60
|
/* @__PURE__ */ jsx("rect", { x: "2", y: "13", width: "2", height: "2", rx: "0.5", fill: "currentColor" }),
|
|
61
61
|
/* @__PURE__ */ jsx("rect", { x: "6", y: "13", width: "10", height: "2", rx: "0.5", fill: "currentColor" })
|
|
62
62
|
] }),
|
|
63
|
-
/* @__PURE__ */ jsx(
|
|
63
|
+
draftCount > 0 && /* @__PURE__ */ jsx(
|
|
64
64
|
"span",
|
|
65
65
|
{
|
|
66
66
|
style: {
|
|
@@ -513,7 +513,7 @@ function SidePanel({
|
|
|
513
513
|
"Feedback Session",
|
|
514
514
|
/* @__PURE__ */ jsxs4("span", { style: { fontSize: 11, fontWeight: 400, color: "#9ca3af", marginLeft: 6 }, children: [
|
|
515
515
|
"v",
|
|
516
|
-
"0.1.
|
|
516
|
+
"0.1.16"
|
|
517
517
|
] })
|
|
518
518
|
] }),
|
|
519
519
|
/* @__PURE__ */ jsx4(
|
|
@@ -933,7 +933,7 @@ Comment: ${comment.trim()}`] : []
|
|
|
933
933
|
}
|
|
934
934
|
|
|
935
935
|
// src/components/SubmitModal.tsx
|
|
936
|
-
import { useState as useState5, useEffect as useEffect3 } from "react";
|
|
936
|
+
import { useState as useState5, useEffect as useEffect3, useRef as useRef2 } from "react";
|
|
937
937
|
import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
938
938
|
function SubmitModal({ count, onSubmit, onCancel, onDone, submitting, submittedUrl, api }) {
|
|
939
939
|
const [title, setTitle] = useState5("");
|
|
@@ -946,6 +946,10 @@ function SubmitModal({ count, onSubmit, onCancel, onDone, submitting, submittedU
|
|
|
946
946
|
const [projects, setProjects] = useState5([]);
|
|
947
947
|
const [labels, setLabels] = useState5([]);
|
|
948
948
|
const [selectedProjectId, setSelectedProjectId] = useState5("");
|
|
949
|
+
const [projectSearch, setProjectSearch] = useState5("");
|
|
950
|
+
const [projectDropdownOpen, setProjectDropdownOpen] = useState5(false);
|
|
951
|
+
const projectInputRef = useRef2(null);
|
|
952
|
+
const projectDropdownRef = useRef2(null);
|
|
949
953
|
const [selectedLabelIds, setSelectedLabelIds] = useState5([]);
|
|
950
954
|
const [linearError, setLinearError] = useState5(null);
|
|
951
955
|
useEffect3(() => {
|
|
@@ -962,7 +966,9 @@ function SubmitModal({ count, onSubmit, onCancel, onDone, submitting, submittedU
|
|
|
962
966
|
if (cancelled) return;
|
|
963
967
|
setProjects(p);
|
|
964
968
|
setLabels(l);
|
|
965
|
-
if (p.length > 0)
|
|
969
|
+
if (p.length > 0) {
|
|
970
|
+
setSelectedProjectId(p[0].id);
|
|
971
|
+
}
|
|
966
972
|
setLinearLoading(false);
|
|
967
973
|
});
|
|
968
974
|
}).catch((err) => {
|
|
@@ -979,6 +985,25 @@ function SubmitModal({ count, onSubmit, onCancel, onDone, submitting, submittedU
|
|
|
979
985
|
useEffect3(() => {
|
|
980
986
|
if (!ticketTitleEdited) setTicketTitle(title);
|
|
981
987
|
}, [title, ticketTitleEdited]);
|
|
988
|
+
useEffect3(() => {
|
|
989
|
+
function handleClickOutside(e) {
|
|
990
|
+
if (projectDropdownRef.current && !projectDropdownRef.current.contains(e.target) && projectInputRef.current && !projectInputRef.current.contains(e.target)) {
|
|
991
|
+
setProjectDropdownOpen(false);
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
995
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
996
|
+
}, []);
|
|
997
|
+
const filteredProjects = projects.filter(
|
|
998
|
+
(p) => p.name.toLowerCase().includes(projectSearch.toLowerCase())
|
|
999
|
+
);
|
|
1000
|
+
const selectedProject = projects.find((p) => p.id === selectedProjectId);
|
|
1001
|
+
const projectDisplayName = (p) => p.name + (p.teams[0] ? ` \u2014 ${p.teams[0].key}` : "");
|
|
1002
|
+
const handleProjectSelect = (p) => {
|
|
1003
|
+
setSelectedProjectId(p.id);
|
|
1004
|
+
setProjectSearch("");
|
|
1005
|
+
setProjectDropdownOpen(false);
|
|
1006
|
+
};
|
|
982
1007
|
const handleSubmit = () => {
|
|
983
1008
|
if (!title.trim() || submitting) return;
|
|
984
1009
|
if (createTicket && linearConfigured && ticketTitle.trim()) {
|
|
@@ -1010,7 +1035,8 @@ function SubmitModal({ count, onSubmit, onCancel, onDone, submitting, submittedU
|
|
|
1010
1035
|
border: "1px solid #d1d5db",
|
|
1011
1036
|
fontSize: 14,
|
|
1012
1037
|
boxSizing: "border-box",
|
|
1013
|
-
background: "#fff"
|
|
1038
|
+
background: "#fff",
|
|
1039
|
+
color: "#111827"
|
|
1014
1040
|
};
|
|
1015
1041
|
return /* @__PURE__ */ jsx6(
|
|
1016
1042
|
"div",
|
|
@@ -1194,21 +1220,71 @@ function SubmitModal({ count, onSubmit, onCancel, onDone, submitting, submittedU
|
|
|
1194
1220
|
}
|
|
1195
1221
|
)
|
|
1196
1222
|
] }),
|
|
1197
|
-
/* @__PURE__ */ jsxs6("div", { children: [
|
|
1223
|
+
/* @__PURE__ */ jsxs6("div", { style: { position: "relative" }, children: [
|
|
1198
1224
|
/* @__PURE__ */ jsx6("label", { style: { display: "block", fontSize: 12, color: "#6b7280", marginBottom: 4 }, children: "Project" }),
|
|
1199
|
-
/* @__PURE__ */
|
|
1200
|
-
"
|
|
1225
|
+
/* @__PURE__ */ jsx6(
|
|
1226
|
+
"input",
|
|
1227
|
+
{
|
|
1228
|
+
ref: projectInputRef,
|
|
1229
|
+
type: "text",
|
|
1230
|
+
value: projectDropdownOpen ? projectSearch : selectedProject ? projectDisplayName(selectedProject) : "",
|
|
1231
|
+
onChange: (e) => {
|
|
1232
|
+
setProjectSearch(e.target.value);
|
|
1233
|
+
setProjectDropdownOpen(true);
|
|
1234
|
+
},
|
|
1235
|
+
onFocus: () => {
|
|
1236
|
+
setProjectSearch("");
|
|
1237
|
+
setProjectDropdownOpen(true);
|
|
1238
|
+
},
|
|
1239
|
+
placeholder: "Search projects\u2026",
|
|
1240
|
+
style: inputStyle
|
|
1241
|
+
}
|
|
1242
|
+
),
|
|
1243
|
+
projectDropdownOpen && /* @__PURE__ */ jsx6(
|
|
1244
|
+
"div",
|
|
1201
1245
|
{
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1246
|
+
ref: projectDropdownRef,
|
|
1247
|
+
style: {
|
|
1248
|
+
position: "absolute",
|
|
1249
|
+
top: "100%",
|
|
1250
|
+
left: 0,
|
|
1251
|
+
right: 0,
|
|
1252
|
+
maxHeight: 160,
|
|
1253
|
+
overflowY: "auto",
|
|
1254
|
+
background: "#fff",
|
|
1255
|
+
border: "1px solid #d1d5db",
|
|
1256
|
+
borderRadius: 8,
|
|
1257
|
+
boxShadow: "0 4px 12px rgba(0,0,0,0.12)",
|
|
1258
|
+
zIndex: 10,
|
|
1259
|
+
marginTop: 2
|
|
1260
|
+
},
|
|
1261
|
+
children: filteredProjects.length === 0 ? /* @__PURE__ */ jsx6("div", { style: { padding: "8px 12px", fontSize: 13, color: "#9ca3af" }, children: "No matching projects" }) : filteredProjects.map((p) => /* @__PURE__ */ jsxs6(
|
|
1262
|
+
"div",
|
|
1263
|
+
{
|
|
1264
|
+
onClick: () => handleProjectSelect(p),
|
|
1265
|
+
style: {
|
|
1266
|
+
padding: "8px 12px",
|
|
1267
|
+
fontSize: 13,
|
|
1268
|
+
cursor: "pointer",
|
|
1269
|
+
background: p.id === selectedProjectId ? "#eff6ff" : "#fff",
|
|
1270
|
+
color: "#111827"
|
|
1271
|
+
},
|
|
1272
|
+
onMouseEnter: (e) => {
|
|
1273
|
+
e.currentTarget.style.background = "#f3f4f6";
|
|
1274
|
+
},
|
|
1275
|
+
onMouseLeave: (e) => {
|
|
1276
|
+
e.currentTarget.style.background = p.id === selectedProjectId ? "#eff6ff" : "#fff";
|
|
1277
|
+
},
|
|
1278
|
+
children: [
|
|
1279
|
+
p.name,
|
|
1280
|
+
p.teams[0] && /* @__PURE__ */ jsxs6("span", { style: { color: "#9ca3af" }, children: [
|
|
1281
|
+
" \u2014 ",
|
|
1282
|
+
p.teams[0].key
|
|
1283
|
+
] })
|
|
1284
|
+
]
|
|
1285
|
+
},
|
|
1286
|
+
p.id
|
|
1287
|
+
))
|
|
1212
1288
|
}
|
|
1213
1289
|
)
|
|
1214
1290
|
] }),
|
|
@@ -1383,7 +1459,7 @@ ${propsStr}`);
|
|
|
1383
1459
|
}
|
|
1384
1460
|
|
|
1385
1461
|
// src/hooks/useSession.ts
|
|
1386
|
-
import { useState as useState6, useEffect as useEffect4, useCallback as useCallback3, useRef as
|
|
1462
|
+
import { useState as useState6, useEffect as useEffect4, useCallback as useCallback3, useRef as useRef3 } from "react";
|
|
1387
1463
|
var SESSION_TOKEN_KEY = "llm_feedback_session_token";
|
|
1388
1464
|
var USER_KEY = "llm_feedback_user";
|
|
1389
1465
|
var AUTH_BYPASS = !!(typeof globalThis !== "undefined" && globalThis.__FEEDBACK_AUTH_BYPASS__);
|
|
@@ -1400,7 +1476,7 @@ var BYPASS_USER = {
|
|
|
1400
1476
|
function useSession(apiUrl, clientId) {
|
|
1401
1477
|
const [status, setStatus] = useState6(AUTH_BYPASS ? "authenticated" : "loading");
|
|
1402
1478
|
const [user, setUser] = useState6(AUTH_BYPASS ? BYPASS_USER : null);
|
|
1403
|
-
const pendingAuthRef =
|
|
1479
|
+
const pendingAuthRef = useRef3(false);
|
|
1404
1480
|
useEffect4(() => {
|
|
1405
1481
|
if (AUTH_BYPASS) return;
|
|
1406
1482
|
let cancelled = false;
|
|
@@ -1683,7 +1759,7 @@ function FeedbackWidget({
|
|
|
1683
1759
|
}) {
|
|
1684
1760
|
const session = useSession(apiUrl, clientId);
|
|
1685
1761
|
const [state, dispatch] = useReducer(widgetReducer, initialState);
|
|
1686
|
-
const pendingOpenRef =
|
|
1762
|
+
const pendingOpenRef = useRef4(false);
|
|
1687
1763
|
const api = useMemo(
|
|
1688
1764
|
() => createApiClient(apiUrl, clientId),
|
|
1689
1765
|
[apiUrl, clientId]
|
|
@@ -1828,7 +1904,7 @@ function FeedbackWidget({
|
|
|
1828
1904
|
});
|
|
1829
1905
|
}
|
|
1830
1906
|
}, [api]);
|
|
1831
|
-
const submittedDraftIdsRef =
|
|
1907
|
+
const submittedDraftIdsRef = useRef4([]);
|
|
1832
1908
|
const handleSubmit = useCallback4(async (title, linearTicket) => {
|
|
1833
1909
|
dispatch({ type: "SET_SUBMITTING", submitting: true });
|
|
1834
1910
|
const draftIds = Array.from(state.selectedDraftIds);
|
|
@@ -1861,7 +1937,8 @@ function FeedbackWidget({
|
|
|
1861
1937
|
draftCount: state.drafts.length,
|
|
1862
1938
|
panelOpen: state.panelOpen,
|
|
1863
1939
|
position,
|
|
1864
|
-
buttonColor
|
|
1940
|
+
buttonColor,
|
|
1941
|
+
authenticated: session.status === "authenticated"
|
|
1865
1942
|
}
|
|
1866
1943
|
),
|
|
1867
1944
|
state.picking && /* @__PURE__ */ jsx7(PickOverlay, { onPick: handlePick, onCancel: handleCancelPicking }),
|