@xinghunm/ai-chat 1.0.2 → 1.1.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.
- package/dist/index.d.mts +18 -2
- package/dist/index.d.ts +18 -2
- package/dist/index.js +821 -281
- package/dist/index.mjs +840 -296
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -47,7 +47,7 @@ module.exports = __toCommonJS(src_exports);
|
|
|
47
47
|
|
|
48
48
|
// src/components/ai-chat/index.tsx
|
|
49
49
|
var import_styled17 = __toESM(require("@emotion/styled"));
|
|
50
|
-
var
|
|
50
|
+
var import_compass_ui5 = require("@xinghunm/compass-ui");
|
|
51
51
|
|
|
52
52
|
// src/components/ai-chat-provider/index.tsx
|
|
53
53
|
var import_react2 = require("react");
|
|
@@ -68,6 +68,7 @@ var DEFAULT_AI_CHAT_LABELS = {
|
|
|
68
68
|
sendButton: "Send",
|
|
69
69
|
stopButton: "Stop",
|
|
70
70
|
retryButton: "Retry",
|
|
71
|
+
scrollToLatest: "Jump to latest",
|
|
71
72
|
placeholder: "Ask something...",
|
|
72
73
|
modeLabelAsk: "Ask",
|
|
73
74
|
modeLabelPlan: "Plan",
|
|
@@ -89,7 +90,10 @@ var DEFAULT_AI_CHAT_LABELS = {
|
|
|
89
90
|
questionnaireSubmitting: "Submitting...",
|
|
90
91
|
questionnaireSubmitted: "Selection submitted. Waiting for the plan to continue...",
|
|
91
92
|
questionnaireValidationPrefix: "Please complete:",
|
|
92
|
-
questionnaireSubmitFailed: "Failed to submit. Please try again."
|
|
93
|
+
questionnaireSubmitFailed: "Failed to submit. Please try again.",
|
|
94
|
+
questionnaireMultiSelectHint: "Multiple choice",
|
|
95
|
+
questionnaireOtherOptionLabel: "Other",
|
|
96
|
+
questionnaireOtherPlaceholder: "Other"
|
|
93
97
|
};
|
|
94
98
|
|
|
95
99
|
// src/store/chat-store.ts
|
|
@@ -1534,29 +1538,120 @@ var Value = import_styled3.default.span`
|
|
|
1534
1538
|
// src/components/chat-thread/components/questionnaire-card.tsx
|
|
1535
1539
|
var import_react7 = require("react");
|
|
1536
1540
|
var import_styled4 = __toESM(require("@emotion/styled"));
|
|
1537
|
-
var
|
|
1541
|
+
var import_compass_ui = require("@xinghunm/compass-ui");
|
|
1542
|
+
|
|
1543
|
+
// src/components/chat-thread/components/questionnaire-card-helpers.ts
|
|
1538
1544
|
var OTHER_OPTION_VALUE = "__other__";
|
|
1539
|
-
var
|
|
1540
|
-
submitting: "Submitting...",
|
|
1541
|
-
submitted: "Selection submitted. Waiting for the plan to continue...",
|
|
1542
|
-
validationPrefix: "Please complete:",
|
|
1543
|
-
submitFailed: "Failed to submit. Please try again."
|
|
1544
|
-
};
|
|
1545
|
-
var createInitialAnswers = (questionnaire) => ({
|
|
1546
|
-
...questionnaire.answers ?? {}
|
|
1547
|
-
});
|
|
1545
|
+
var getQuestionnaireQuestion = (questionnaire) => questionnaire.question;
|
|
1548
1546
|
var getMultiSelectAnswerValues = (answer) => Array.isArray(answer) ? answer : [];
|
|
1549
|
-
var
|
|
1547
|
+
var getQuestionOptionValues = (question) => new Set(question.options.map((option) => option.value));
|
|
1548
|
+
var extractSingleSelectOtherDraft = (question, answer) => {
|
|
1549
|
+
if (typeof answer !== "string") {
|
|
1550
|
+
return "";
|
|
1551
|
+
}
|
|
1552
|
+
return getQuestionOptionValues(question).has(answer) ? "" : answer;
|
|
1553
|
+
};
|
|
1554
|
+
var extractMultiSelectOtherDraft = (question, answer) => {
|
|
1555
|
+
if (!Array.isArray(answer)) {
|
|
1556
|
+
return "";
|
|
1557
|
+
}
|
|
1558
|
+
const optionValues = getQuestionOptionValues(question);
|
|
1559
|
+
const customValue = answer.find(
|
|
1560
|
+
(value) => typeof value === "string" && value !== OTHER_OPTION_VALUE && !optionValues.has(value)
|
|
1561
|
+
);
|
|
1562
|
+
return typeof customValue === "string" ? customValue : "";
|
|
1563
|
+
};
|
|
1564
|
+
var createInitialAnswers = (questionnaire) => {
|
|
1565
|
+
const initialAnswers = {};
|
|
1566
|
+
const question = getQuestionnaireQuestion(questionnaire);
|
|
1567
|
+
if (!question) {
|
|
1568
|
+
return initialAnswers;
|
|
1569
|
+
}
|
|
1570
|
+
const answer = questionnaire.answers?.[question.id];
|
|
1571
|
+
switch (question.kind) {
|
|
1572
|
+
case "single_select": {
|
|
1573
|
+
if (typeof answer !== "string") {
|
|
1574
|
+
break;
|
|
1575
|
+
}
|
|
1576
|
+
if (getQuestionOptionValues(question).has(answer)) {
|
|
1577
|
+
initialAnswers[question.id] = answer;
|
|
1578
|
+
break;
|
|
1579
|
+
}
|
|
1580
|
+
if (question.allowOther) {
|
|
1581
|
+
initialAnswers[question.id] = OTHER_OPTION_VALUE;
|
|
1582
|
+
}
|
|
1583
|
+
break;
|
|
1584
|
+
}
|
|
1585
|
+
case "multi_select": {
|
|
1586
|
+
if (!Array.isArray(answer)) {
|
|
1587
|
+
break;
|
|
1588
|
+
}
|
|
1589
|
+
const optionValues = getQuestionOptionValues(question);
|
|
1590
|
+
const selectedValues = [];
|
|
1591
|
+
let hasOtherValue = false;
|
|
1592
|
+
for (const value of answer) {
|
|
1593
|
+
if (typeof value !== "string") {
|
|
1594
|
+
continue;
|
|
1595
|
+
}
|
|
1596
|
+
if (optionValues.has(value)) {
|
|
1597
|
+
selectedValues.push(value);
|
|
1598
|
+
continue;
|
|
1599
|
+
}
|
|
1600
|
+
if (question.allowOther && !hasOtherValue) {
|
|
1601
|
+
selectedValues.push(OTHER_OPTION_VALUE);
|
|
1602
|
+
hasOtherValue = true;
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
initialAnswers[question.id] = selectedValues;
|
|
1606
|
+
break;
|
|
1607
|
+
}
|
|
1608
|
+
default:
|
|
1609
|
+
initialAnswers[question.id] = answer;
|
|
1610
|
+
}
|
|
1611
|
+
return initialAnswers;
|
|
1612
|
+
};
|
|
1613
|
+
var createInitialOtherDrafts = (questionnaire) => {
|
|
1614
|
+
const drafts = {};
|
|
1615
|
+
const question = getQuestionnaireQuestion(questionnaire);
|
|
1616
|
+
if (!question) {
|
|
1617
|
+
return drafts;
|
|
1618
|
+
}
|
|
1619
|
+
const answer = questionnaire.answers?.[question.id];
|
|
1620
|
+
switch (question.kind) {
|
|
1621
|
+
case "single_select":
|
|
1622
|
+
if (question.allowOther) {
|
|
1623
|
+
drafts[question.id] = extractSingleSelectOtherDraft(question, answer);
|
|
1624
|
+
}
|
|
1625
|
+
break;
|
|
1626
|
+
case "multi_select":
|
|
1627
|
+
if (question.allowOther) {
|
|
1628
|
+
drafts[question.id] = extractMultiSelectOtherDraft(question, answer);
|
|
1629
|
+
}
|
|
1630
|
+
break;
|
|
1631
|
+
default:
|
|
1632
|
+
break;
|
|
1633
|
+
}
|
|
1634
|
+
return drafts;
|
|
1635
|
+
};
|
|
1636
|
+
var getMultiSelectDraftState = (question, answer, otherDraft) => {
|
|
1637
|
+
const answerValues = getMultiSelectAnswerValues(answer);
|
|
1638
|
+
return {
|
|
1639
|
+
selectedValues: answerValues,
|
|
1640
|
+
otherValue: otherDraft,
|
|
1641
|
+
hasOtherSelected: question.allowOther === true && answerValues.includes(OTHER_OPTION_VALUE)
|
|
1642
|
+
};
|
|
1643
|
+
};
|
|
1644
|
+
var getSingleSelectDraftState = (question, answer, otherDraft) => {
|
|
1550
1645
|
if (typeof answer !== "string") {
|
|
1551
1646
|
return {
|
|
1552
1647
|
selectedValue: void 0,
|
|
1553
|
-
otherValue:
|
|
1648
|
+
otherValue: otherDraft
|
|
1554
1649
|
};
|
|
1555
1650
|
}
|
|
1556
|
-
const matchesOption = question.options.some((option) => option.value === answer);
|
|
1651
|
+
const matchesOption = answer !== OTHER_OPTION_VALUE && question.options.some((option) => option.value === answer);
|
|
1557
1652
|
return {
|
|
1558
1653
|
selectedValue: matchesOption ? answer : question.allowOther ? OTHER_OPTION_VALUE : void 0,
|
|
1559
|
-
otherValue:
|
|
1654
|
+
otherValue: otherDraft
|
|
1560
1655
|
};
|
|
1561
1656
|
};
|
|
1562
1657
|
var updateAnswerValue = (current, questionId, value) => ({
|
|
@@ -1568,6 +1663,17 @@ var toggleMultiSelectAnswer = (current, questionId, optionValue) => {
|
|
|
1568
1663
|
const nextValues = currentValues.includes(optionValue) ? currentValues.filter((value) => value !== optionValue) : [...currentValues, optionValue];
|
|
1569
1664
|
return updateAnswerValue(current, questionId, nextValues);
|
|
1570
1665
|
};
|
|
1666
|
+
var toggleMultiSelectOtherAnswer = (current, question) => {
|
|
1667
|
+
const currentValues = getMultiSelectAnswerValues(current[question.id]);
|
|
1668
|
+
if (currentValues.includes(OTHER_OPTION_VALUE)) {
|
|
1669
|
+
return updateAnswerValue(
|
|
1670
|
+
current,
|
|
1671
|
+
question.id,
|
|
1672
|
+
currentValues.filter((value) => value !== OTHER_OPTION_VALUE)
|
|
1673
|
+
);
|
|
1674
|
+
}
|
|
1675
|
+
return updateAnswerValue(current, question.id, [...currentValues, OTHER_OPTION_VALUE]);
|
|
1676
|
+
};
|
|
1571
1677
|
var getTextInputValue = (answer) => typeof answer === "string" ? String(answer) : "";
|
|
1572
1678
|
var getNumberInputValue = (answer) => typeof answer === "number" || typeof answer === "string" ? String(answer) : "";
|
|
1573
1679
|
var getOptionChoiceLabel = (index) => {
|
|
@@ -1576,20 +1682,49 @@ var getOptionChoiceLabel = (index) => {
|
|
|
1576
1682
|
}
|
|
1577
1683
|
return String(index + 1);
|
|
1578
1684
|
};
|
|
1579
|
-
var
|
|
1580
|
-
|
|
1685
|
+
var normalizeQuestionAnswer = (question, answer, otherDraft = "") => {
|
|
1686
|
+
if (answer === void 0) {
|
|
1687
|
+
return void 0;
|
|
1688
|
+
}
|
|
1581
1689
|
switch (question.kind) {
|
|
1582
|
-
case "boolean":
|
|
1583
|
-
return typeof answer !== "boolean";
|
|
1584
1690
|
case "multi_select":
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1691
|
+
if (!Array.isArray(answer)) {
|
|
1692
|
+
return void 0;
|
|
1693
|
+
}
|
|
1694
|
+
return (() => {
|
|
1695
|
+
const optionValues = getQuestionOptionValues(question);
|
|
1696
|
+
const normalizedOtherDraft = otherDraft.trim();
|
|
1697
|
+
const normalizedValues = answer.flatMap((value) => {
|
|
1698
|
+
if (typeof value !== "string") {
|
|
1699
|
+
return [];
|
|
1700
|
+
}
|
|
1701
|
+
if (optionValues.has(value)) {
|
|
1702
|
+
return [value];
|
|
1703
|
+
}
|
|
1704
|
+
if (!question.allowOther || value !== OTHER_OPTION_VALUE) {
|
|
1705
|
+
return [];
|
|
1706
|
+
}
|
|
1707
|
+
return normalizedOtherDraft === "" ? [] : [normalizedOtherDraft];
|
|
1708
|
+
});
|
|
1709
|
+
return normalizedValues.length > 0 ? normalizedValues : void 0;
|
|
1710
|
+
})();
|
|
1589
1711
|
case "single_select":
|
|
1590
|
-
|
|
1712
|
+
if (answer === OTHER_OPTION_VALUE) {
|
|
1713
|
+
const normalizedOtherDraft = otherDraft.trim();
|
|
1714
|
+
return normalizedOtherDraft === "" ? void 0 : normalizedOtherDraft;
|
|
1715
|
+
}
|
|
1716
|
+
if (typeof answer !== "string" || answer.trim() === "") {
|
|
1717
|
+
return void 0;
|
|
1718
|
+
}
|
|
1719
|
+
return getQuestionOptionValues(question).has(answer) ? answer : void 0;
|
|
1720
|
+
case "text":
|
|
1721
|
+
return typeof answer === "string" && answer.trim() !== "" ? answer : void 0;
|
|
1722
|
+
case "number":
|
|
1723
|
+
return typeof answer === "number" && !Number.isNaN(answer) ? answer : void 0;
|
|
1724
|
+
case "boolean":
|
|
1725
|
+
return typeof answer === "boolean" ? answer : void 0;
|
|
1591
1726
|
default:
|
|
1592
|
-
return
|
|
1727
|
+
return answer;
|
|
1593
1728
|
}
|
|
1594
1729
|
};
|
|
1595
1730
|
var formatQuestionAnswer = (question, answer) => {
|
|
@@ -1617,80 +1752,221 @@ var formatQuestionAnswer = (question, answer) => {
|
|
|
1617
1752
|
return String(answer);
|
|
1618
1753
|
}
|
|
1619
1754
|
};
|
|
1620
|
-
var
|
|
1755
|
+
var buildQuestionSubmissionDetail = (question, answer) => {
|
|
1621
1756
|
if (answer === void 0) {
|
|
1622
1757
|
return void 0;
|
|
1623
1758
|
}
|
|
1624
1759
|
switch (question.kind) {
|
|
1625
|
-
case "
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
return
|
|
1632
|
-
|
|
1633
|
-
|
|
1760
|
+
case "single_select": {
|
|
1761
|
+
if (typeof answer !== "string") {
|
|
1762
|
+
return void 0;
|
|
1763
|
+
}
|
|
1764
|
+
const optionValues = getQuestionOptionValues(question);
|
|
1765
|
+
const trimmedAnswer = answer.trim();
|
|
1766
|
+
return {
|
|
1767
|
+
questionId: question.id,
|
|
1768
|
+
kind: question.kind,
|
|
1769
|
+
value: answer,
|
|
1770
|
+
selectedOptionValues: optionValues.has(answer) ? [answer] : [],
|
|
1771
|
+
otherValue: optionValues.has(answer) || trimmedAnswer === "" ? void 0 : trimmedAnswer
|
|
1772
|
+
};
|
|
1773
|
+
}
|
|
1774
|
+
case "multi_select": {
|
|
1775
|
+
if (!Array.isArray(answer)) {
|
|
1776
|
+
return void 0;
|
|
1777
|
+
}
|
|
1778
|
+
const optionValues = getQuestionOptionValues(question);
|
|
1779
|
+
const selectedOptionValues = answer.filter(
|
|
1780
|
+
(value) => typeof value === "string" && optionValues.has(value)
|
|
1781
|
+
);
|
|
1782
|
+
const otherValue = answer.find(
|
|
1783
|
+
(value) => typeof value === "string" && !optionValues.has(value)
|
|
1784
|
+
);
|
|
1785
|
+
return {
|
|
1786
|
+
questionId: question.id,
|
|
1787
|
+
kind: question.kind,
|
|
1788
|
+
value: answer,
|
|
1789
|
+
selectedOptionValues,
|
|
1790
|
+
otherValue: otherValue?.trim() ? otherValue.trim() : void 0
|
|
1791
|
+
};
|
|
1792
|
+
}
|
|
1634
1793
|
default:
|
|
1635
|
-
return
|
|
1794
|
+
return {
|
|
1795
|
+
questionId: question.id,
|
|
1796
|
+
kind: question.kind,
|
|
1797
|
+
value: answer
|
|
1798
|
+
};
|
|
1636
1799
|
}
|
|
1637
1800
|
};
|
|
1801
|
+
var getMissingRequiredQuestions = (questionnaire, answers, otherDrafts) => {
|
|
1802
|
+
const question = getQuestionnaireQuestion(questionnaire);
|
|
1803
|
+
if (!question || !question.required) {
|
|
1804
|
+
return [];
|
|
1805
|
+
}
|
|
1806
|
+
return normalizeQuestionAnswer(question, answers[question.id], otherDrafts[question.id]) === void 0 ? [question] : [];
|
|
1807
|
+
};
|
|
1808
|
+
var prepareQuestionnaireSubmission = (questionnaire, answers, otherDrafts) => {
|
|
1809
|
+
const question = getQuestionnaireQuestion(questionnaire);
|
|
1810
|
+
if (!question) {
|
|
1811
|
+
return {
|
|
1812
|
+
normalizedAnswers: {},
|
|
1813
|
+
submissionDetails: void 0,
|
|
1814
|
+
content: questionnaire.title ?? "Questionnaire responses"
|
|
1815
|
+
};
|
|
1816
|
+
}
|
|
1817
|
+
const value = normalizeQuestionAnswer(question, answers[question.id], otherDrafts[question.id]);
|
|
1818
|
+
const normalizedAnswers = value === void 0 ? {} : { [question.id]: value };
|
|
1819
|
+
const detail = buildQuestionSubmissionDetail(question, normalizedAnswers[question.id]);
|
|
1820
|
+
const submissionDetails = detail === void 0 ? void 0 : { [question.id]: detail };
|
|
1821
|
+
return {
|
|
1822
|
+
normalizedAnswers,
|
|
1823
|
+
submissionDetails,
|
|
1824
|
+
content: [
|
|
1825
|
+
questionnaire.title ?? "Questionnaire responses",
|
|
1826
|
+
...normalizedAnswers[question.id] === void 0 ? [] : [
|
|
1827
|
+
`- ${question.label}: ${formatQuestionAnswer(question, normalizedAnswers[question.id])}`
|
|
1828
|
+
]
|
|
1829
|
+
].join("\n")
|
|
1830
|
+
};
|
|
1831
|
+
};
|
|
1832
|
+
var getQuestionnaireStateKey = (questionnaire) => JSON.stringify([
|
|
1833
|
+
questionnaire.questionnaireId,
|
|
1834
|
+
questionnaire.blockKey,
|
|
1835
|
+
questionnaire.question,
|
|
1836
|
+
questionnaire.status,
|
|
1837
|
+
questionnaire.statusMessage
|
|
1838
|
+
]);
|
|
1839
|
+
|
|
1840
|
+
// src/components/chat-thread/components/questionnaire-card.tsx
|
|
1841
|
+
var import_jsx_runtime5 = require("@emotion/react/jsx-runtime");
|
|
1842
|
+
var DEFAULT_QUESTIONNAIRE_CARD_LABELS = {
|
|
1843
|
+
submitting: "Submitting...",
|
|
1844
|
+
submitted: "Selection submitted. Waiting for the plan to continue...",
|
|
1845
|
+
validationPrefix: "Please complete:",
|
|
1846
|
+
submitFailed: "Failed to submit. Please try again.",
|
|
1847
|
+
multiSelectHint: "Multiple choice",
|
|
1848
|
+
otherOptionLabel: "Other",
|
|
1849
|
+
otherPlaceholder: "Other"
|
|
1850
|
+
};
|
|
1851
|
+
var stopInputClickPropagation = (event) => {
|
|
1852
|
+
event.stopPropagation();
|
|
1853
|
+
};
|
|
1854
|
+
var stopInputKeyPropagation = (event) => {
|
|
1855
|
+
event.stopPropagation();
|
|
1856
|
+
};
|
|
1857
|
+
var OptionChoice = ({
|
|
1858
|
+
questionId,
|
|
1859
|
+
optionLabel,
|
|
1860
|
+
index,
|
|
1861
|
+
isSelected,
|
|
1862
|
+
isInteractionLocked,
|
|
1863
|
+
onClick,
|
|
1864
|
+
inlineInput,
|
|
1865
|
+
tone = "default"
|
|
1866
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1867
|
+
OptionChoiceItem,
|
|
1868
|
+
{
|
|
1869
|
+
role: "button",
|
|
1870
|
+
tabIndex: isInteractionLocked ? -1 : 0,
|
|
1871
|
+
"aria-pressed": isSelected,
|
|
1872
|
+
"data-selected": isSelected,
|
|
1873
|
+
"data-tone": tone,
|
|
1874
|
+
"data-testid": `question-option-${questionId}-${index}`,
|
|
1875
|
+
onClick: (event) => {
|
|
1876
|
+
if (isInteractionLocked) {
|
|
1877
|
+
return;
|
|
1878
|
+
}
|
|
1879
|
+
if (event.target instanceof HTMLElement && event.target.closest("input")) {
|
|
1880
|
+
return;
|
|
1881
|
+
}
|
|
1882
|
+
onClick();
|
|
1883
|
+
},
|
|
1884
|
+
onKeyDown: (event) => {
|
|
1885
|
+
if (isInteractionLocked) {
|
|
1886
|
+
return;
|
|
1887
|
+
}
|
|
1888
|
+
if (event.key !== "Enter" && event.key !== " ") {
|
|
1889
|
+
return;
|
|
1890
|
+
}
|
|
1891
|
+
event.preventDefault();
|
|
1892
|
+
onClick();
|
|
1893
|
+
},
|
|
1894
|
+
children: [
|
|
1895
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(OptionChoiceMarker, { "data-selected": isSelected, children: getOptionChoiceLabel(index) }),
|
|
1896
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(OptionChoiceContent, { children: [
|
|
1897
|
+
inlineInput ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(OptionChoiceLabel, { children: optionLabel }),
|
|
1898
|
+
inlineInput
|
|
1899
|
+
] })
|
|
1900
|
+
]
|
|
1901
|
+
}
|
|
1902
|
+
);
|
|
1638
1903
|
var QuestionnaireCardInner = ({
|
|
1639
1904
|
questionnaire,
|
|
1640
1905
|
interactive = false,
|
|
1641
1906
|
onSubmit,
|
|
1642
1907
|
labels
|
|
1643
1908
|
}) => {
|
|
1909
|
+
const questionnaireRef = (0, import_react7.useRef)(questionnaire);
|
|
1910
|
+
const otherInputRefs = (0, import_react7.useRef)({});
|
|
1644
1911
|
const [answers, setAnswers] = (0, import_react7.useState)(
|
|
1645
1912
|
() => createInitialAnswers(questionnaire)
|
|
1646
1913
|
);
|
|
1914
|
+
const [otherDrafts, setOtherDrafts] = (0, import_react7.useState)(
|
|
1915
|
+
() => createInitialOtherDrafts(questionnaire)
|
|
1916
|
+
);
|
|
1647
1917
|
const [errorMessage, setErrorMessage] = (0, import_react7.useState)(null);
|
|
1648
1918
|
const [isSubmitting, setIsSubmitting] = (0, import_react7.useState)(false);
|
|
1649
1919
|
const [isSubmitted, setIsSubmitted] = (0, import_react7.useState)(false);
|
|
1920
|
+
const [pendingFocusQuestionId, setPendingFocusQuestionId] = (0, import_react7.useState)(null);
|
|
1650
1921
|
const resolvedLabels = {
|
|
1651
1922
|
...DEFAULT_QUESTIONNAIRE_CARD_LABELS,
|
|
1652
1923
|
...labels
|
|
1653
1924
|
};
|
|
1654
1925
|
const hasExternalFailureStatus = questionnaire.status === "expired" || questionnaire.status === "failed";
|
|
1926
|
+
const question = getQuestionnaireQuestion(questionnaire);
|
|
1655
1927
|
const visibleErrorMessage = questionnaire.statusMessage ?? errorMessage;
|
|
1656
1928
|
const isInteractionLocked = !interactive || isSubmitting || isSubmitted || hasExternalFailureStatus;
|
|
1929
|
+
questionnaireRef.current = questionnaire;
|
|
1930
|
+
(0, import_react7.useEffect)(() => {
|
|
1931
|
+
setAnswers(createInitialAnswers(questionnaireRef.current));
|
|
1932
|
+
setOtherDrafts(createInitialOtherDrafts(questionnaireRef.current));
|
|
1933
|
+
}, [questionnaire.answers]);
|
|
1934
|
+
(0, import_react7.useEffect)(() => {
|
|
1935
|
+
if (!pendingFocusQuestionId || isInteractionLocked) {
|
|
1936
|
+
return;
|
|
1937
|
+
}
|
|
1938
|
+
const inputElement = otherInputRefs.current[pendingFocusQuestionId];
|
|
1939
|
+
if (!inputElement) {
|
|
1940
|
+
return;
|
|
1941
|
+
}
|
|
1942
|
+
inputElement.focus();
|
|
1943
|
+
setPendingFocusQuestionId(null);
|
|
1944
|
+
}, [isInteractionLocked, pendingFocusQuestionId]);
|
|
1657
1945
|
const handleSubmit = async () => {
|
|
1658
1946
|
if (isSubmitting || isSubmitted) {
|
|
1659
1947
|
return;
|
|
1660
1948
|
}
|
|
1661
|
-
const missingQuestions = questionnaire
|
|
1662
|
-
(question) => question.required && isMissingRequiredAnswer(question, answers)
|
|
1663
|
-
);
|
|
1949
|
+
const missingQuestions = getMissingRequiredQuestions(questionnaire, answers, otherDrafts);
|
|
1664
1950
|
if (missingQuestions.length > 0) {
|
|
1665
1951
|
setErrorMessage(
|
|
1666
|
-
`${resolvedLabels.validationPrefix} ${missingQuestions.map((
|
|
1952
|
+
`${resolvedLabels.validationPrefix} ${missingQuestions.map((question2) => question2.label).join(", ")}`
|
|
1667
1953
|
);
|
|
1668
1954
|
return;
|
|
1669
1955
|
}
|
|
1670
1956
|
setErrorMessage(null);
|
|
1671
1957
|
setIsSubmitting(true);
|
|
1672
|
-
const normalizedAnswers =
|
|
1673
|
-
questionnaire
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
})
|
|
1958
|
+
const { normalizedAnswers, submissionDetails, content } = prepareQuestionnaireSubmission(
|
|
1959
|
+
questionnaire,
|
|
1960
|
+
answers,
|
|
1961
|
+
otherDrafts
|
|
1677
1962
|
);
|
|
1678
|
-
const contentLines = [
|
|
1679
|
-
questionnaire.title ?? "Questionnaire responses",
|
|
1680
|
-
...questionnaire.questions.flatMap((question) => {
|
|
1681
|
-
const value = normalizedAnswers[question.id];
|
|
1682
|
-
if (value === void 0) {
|
|
1683
|
-
return [];
|
|
1684
|
-
}
|
|
1685
|
-
return [`- ${question.label}: ${formatQuestionAnswer(question, value)}`];
|
|
1686
|
-
})
|
|
1687
|
-
];
|
|
1688
1963
|
try {
|
|
1689
1964
|
await onSubmit?.({
|
|
1690
1965
|
questionnaireId: questionnaire.questionnaireId,
|
|
1691
1966
|
...questionnaire.blockKey ? { blockKey: questionnaire.blockKey } : {},
|
|
1692
1967
|
answers: normalizedAnswers,
|
|
1693
|
-
|
|
1968
|
+
details: submissionDetails,
|
|
1969
|
+
content
|
|
1694
1970
|
});
|
|
1695
1971
|
setIsSubmitted(true);
|
|
1696
1972
|
} catch (error) {
|
|
@@ -1699,125 +1975,156 @@ var QuestionnaireCardInner = ({
|
|
|
1699
1975
|
setIsSubmitting(false);
|
|
1700
1976
|
}
|
|
1701
1977
|
};
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1978
|
+
if (!question) {
|
|
1979
|
+
return null;
|
|
1980
|
+
}
|
|
1981
|
+
const renderQuestion = (questionToRender) => {
|
|
1982
|
+
switch (questionToRender.kind) {
|
|
1983
|
+
case "multi_select": {
|
|
1984
|
+
const multiSelectDraft = getMultiSelectDraftState(
|
|
1985
|
+
questionToRender,
|
|
1986
|
+
answers[questionToRender.id],
|
|
1987
|
+
otherDrafts[questionToRender.id] ?? ""
|
|
1988
|
+
);
|
|
1989
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QuestionBody, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(OptionList, { children: [
|
|
1990
|
+
questionToRender.options.map((option, index) => {
|
|
1991
|
+
const isSelected = multiSelectDraft.selectedValues.includes(option.value);
|
|
1992
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1993
|
+
OptionChoice,
|
|
1994
|
+
{
|
|
1995
|
+
questionId: questionToRender.id,
|
|
1996
|
+
optionLabel: option.label,
|
|
1997
|
+
index,
|
|
1998
|
+
isSelected,
|
|
1999
|
+
isInteractionLocked,
|
|
2000
|
+
onClick: () => setAnswers(
|
|
2001
|
+
(current) => toggleMultiSelectAnswer(current, questionToRender.id, option.value)
|
|
2002
|
+
)
|
|
2003
|
+
},
|
|
2004
|
+
option.value
|
|
2005
|
+
);
|
|
2006
|
+
}),
|
|
2007
|
+
questionToRender.allowOther ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2008
|
+
OptionChoice,
|
|
2009
|
+
{
|
|
2010
|
+
questionId: questionToRender.id,
|
|
2011
|
+
optionLabel: resolvedLabels.otherOptionLabel,
|
|
2012
|
+
index: questionToRender.options.length,
|
|
2013
|
+
isSelected: multiSelectDraft.hasOtherSelected,
|
|
2014
|
+
isInteractionLocked,
|
|
2015
|
+
tone: "other",
|
|
2016
|
+
onClick: () => {
|
|
2017
|
+
if (!multiSelectDraft.hasOtherSelected) {
|
|
2018
|
+
setPendingFocusQuestionId(questionToRender.id);
|
|
2019
|
+
}
|
|
2020
|
+
setAnswers((current) => toggleMultiSelectOtherAnswer(current, questionToRender));
|
|
2021
|
+
},
|
|
2022
|
+
inlineInput: multiSelectDraft.hasOtherSelected ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2023
|
+
InlineOtherInput,
|
|
2024
|
+
{
|
|
2025
|
+
ref: (node) => {
|
|
2026
|
+
otherInputRefs.current[questionToRender.id] = node;
|
|
2027
|
+
},
|
|
2028
|
+
"data-testid": `question-input-${questionToRender.id}`,
|
|
2029
|
+
type: "text",
|
|
2030
|
+
value: multiSelectDraft.otherValue,
|
|
2031
|
+
placeholder: resolvedLabels.otherPlaceholder,
|
|
2032
|
+
readOnly: isInteractionLocked,
|
|
2033
|
+
onClick: stopInputClickPropagation,
|
|
2034
|
+
onKeyDown: stopInputKeyPropagation,
|
|
2035
|
+
onChange: (event) => {
|
|
2036
|
+
setOtherDrafts((current) => ({
|
|
2037
|
+
...current,
|
|
2038
|
+
[questionToRender.id]: event.target.value
|
|
2039
|
+
}));
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
2042
|
+
) : null
|
|
2043
|
+
},
|
|
2044
|
+
`${questionToRender.id}-other`
|
|
2045
|
+
) : null
|
|
2046
|
+
] }) });
|
|
2047
|
+
}
|
|
1764
2048
|
case "single_select": {
|
|
1765
|
-
const singleSelectDraft = getSingleSelectDraftState(
|
|
2049
|
+
const singleSelectDraft = getSingleSelectDraftState(
|
|
2050
|
+
questionToRender,
|
|
2051
|
+
answers[questionToRender.id],
|
|
2052
|
+
otherDrafts[questionToRender.id] ?? ""
|
|
2053
|
+
);
|
|
1766
2054
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QuestionBody, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(OptionList, { children: [
|
|
1767
|
-
|
|
2055
|
+
questionToRender.options.map((option, index) => {
|
|
1768
2056
|
const isSelected = singleSelectDraft.selectedValue === option.value;
|
|
1769
|
-
return
|
|
1770
|
-
|
|
1771
|
-
optionLabel: option.label,
|
|
1772
|
-
index,
|
|
1773
|
-
isSelected,
|
|
1774
|
-
onClick: () => setAnswers((current) => updateAnswerValue(current, question.id, option.value))
|
|
1775
|
-
});
|
|
1776
|
-
}),
|
|
1777
|
-
question.allowOther ? renderOptionChoice({
|
|
1778
|
-
questionId: question.id,
|
|
1779
|
-
optionLabel: "Other",
|
|
1780
|
-
index: question.options.length,
|
|
1781
|
-
isSelected: singleSelectDraft.selectedValue === OTHER_OPTION_VALUE,
|
|
1782
|
-
tone: "other",
|
|
1783
|
-
onClick: () => setAnswers(
|
|
1784
|
-
(current) => updateAnswerValue(current, question.id, singleSelectDraft.otherValue)
|
|
1785
|
-
),
|
|
1786
|
-
inlineInput: singleSelectDraft.selectedValue === OTHER_OPTION_VALUE ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1787
|
-
InlineOtherInput,
|
|
2057
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2058
|
+
OptionChoice,
|
|
1788
2059
|
{
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
onClick: (
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
2060
|
+
questionId: questionToRender.id,
|
|
2061
|
+
optionLabel: option.label,
|
|
2062
|
+
index,
|
|
2063
|
+
isSelected,
|
|
2064
|
+
isInteractionLocked,
|
|
2065
|
+
onClick: () => setAnswers(
|
|
2066
|
+
(current) => updateAnswerValue(current, questionToRender.id, option.value)
|
|
2067
|
+
)
|
|
2068
|
+
},
|
|
2069
|
+
option.value
|
|
2070
|
+
);
|
|
2071
|
+
}),
|
|
2072
|
+
questionToRender.allowOther ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2073
|
+
OptionChoice,
|
|
2074
|
+
{
|
|
2075
|
+
questionId: questionToRender.id,
|
|
2076
|
+
optionLabel: resolvedLabels.otherOptionLabel,
|
|
2077
|
+
index: questionToRender.options.length,
|
|
2078
|
+
isSelected: singleSelectDraft.selectedValue === OTHER_OPTION_VALUE,
|
|
2079
|
+
isInteractionLocked,
|
|
2080
|
+
tone: "other",
|
|
2081
|
+
onClick: () => {
|
|
2082
|
+
if (singleSelectDraft.selectedValue !== OTHER_OPTION_VALUE) {
|
|
2083
|
+
setPendingFocusQuestionId(questionToRender.id);
|
|
1804
2084
|
}
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
2085
|
+
setAnswers(
|
|
2086
|
+
(current) => updateAnswerValue(current, questionToRender.id, OTHER_OPTION_VALUE)
|
|
2087
|
+
);
|
|
2088
|
+
},
|
|
2089
|
+
inlineInput: singleSelectDraft.selectedValue === OTHER_OPTION_VALUE ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2090
|
+
InlineOtherInput,
|
|
2091
|
+
{
|
|
2092
|
+
ref: (node) => {
|
|
2093
|
+
otherInputRefs.current[questionToRender.id] = node;
|
|
2094
|
+
},
|
|
2095
|
+
"data-testid": `question-input-${questionToRender.id}`,
|
|
2096
|
+
type: "text",
|
|
2097
|
+
value: singleSelectDraft.otherValue,
|
|
2098
|
+
placeholder: resolvedLabels.otherPlaceholder,
|
|
2099
|
+
readOnly: isInteractionLocked,
|
|
2100
|
+
onClick: stopInputClickPropagation,
|
|
2101
|
+
onKeyDown: stopInputKeyPropagation,
|
|
2102
|
+
onChange: (event) => {
|
|
2103
|
+
setOtherDrafts((current) => ({
|
|
2104
|
+
...current,
|
|
2105
|
+
[questionToRender.id]: event.target.value
|
|
2106
|
+
}));
|
|
2107
|
+
}
|
|
2108
|
+
}
|
|
2109
|
+
) : null
|
|
2110
|
+
},
|
|
2111
|
+
`${questionToRender.id}-other`
|
|
2112
|
+
) : null
|
|
1808
2113
|
] }) });
|
|
1809
2114
|
}
|
|
1810
2115
|
case "text":
|
|
1811
2116
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QuestionBody, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1812
2117
|
TextInput,
|
|
1813
2118
|
{
|
|
1814
|
-
"data-testid": `question-input-${
|
|
2119
|
+
"data-testid": `question-input-${questionToRender.id}`,
|
|
1815
2120
|
type: "text",
|
|
1816
|
-
value: getTextInputValue(answers[
|
|
1817
|
-
placeholder:
|
|
2121
|
+
value: getTextInputValue(answers[questionToRender.id]),
|
|
2122
|
+
placeholder: questionToRender.placeholder,
|
|
1818
2123
|
readOnly: isInteractionLocked,
|
|
1819
2124
|
onChange: (event) => {
|
|
1820
|
-
setAnswers(
|
|
2125
|
+
setAnswers(
|
|
2126
|
+
(current) => updateAnswerValue(current, questionToRender.id, event.target.value)
|
|
2127
|
+
);
|
|
1821
2128
|
}
|
|
1822
2129
|
}
|
|
1823
2130
|
) });
|
|
@@ -1826,55 +2133,63 @@ var QuestionnaireCardInner = ({
|
|
|
1826
2133
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1827
2134
|
TextInput,
|
|
1828
2135
|
{
|
|
1829
|
-
"data-testid": `question-input-${
|
|
2136
|
+
"data-testid": `question-input-${questionToRender.id}`,
|
|
1830
2137
|
type: "number",
|
|
1831
|
-
value: getNumberInputValue(answers[
|
|
1832
|
-
placeholder:
|
|
2138
|
+
value: getNumberInputValue(answers[questionToRender.id]),
|
|
2139
|
+
placeholder: questionToRender.placeholder,
|
|
1833
2140
|
readOnly: isInteractionLocked,
|
|
1834
2141
|
onChange: (event) => {
|
|
1835
2142
|
setAnswers(
|
|
1836
2143
|
(current) => updateAnswerValue(
|
|
1837
2144
|
current,
|
|
1838
|
-
|
|
2145
|
+
questionToRender.id,
|
|
1839
2146
|
event.target.value === "" ? void 0 : Number(event.target.value)
|
|
1840
2147
|
)
|
|
1841
2148
|
);
|
|
1842
2149
|
}
|
|
1843
2150
|
}
|
|
1844
2151
|
),
|
|
1845
|
-
|
|
2152
|
+
questionToRender.unit ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Unit, { children: questionToRender.unit }) : null
|
|
1846
2153
|
] }) });
|
|
1847
2154
|
case "boolean":
|
|
1848
2155
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QuestionBody, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(OptionList, { children: [
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
2156
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2157
|
+
OptionChoice,
|
|
2158
|
+
{
|
|
2159
|
+
questionId: questionToRender.id,
|
|
2160
|
+
optionLabel: questionToRender.trueLabel ?? "Yes",
|
|
2161
|
+
index: 0,
|
|
2162
|
+
isSelected: answers[questionToRender.id] === true,
|
|
2163
|
+
isInteractionLocked,
|
|
2164
|
+
onClick: () => setAnswers((current) => updateAnswerValue(current, questionToRender.id, true))
|
|
2165
|
+
}
|
|
2166
|
+
),
|
|
2167
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2168
|
+
OptionChoice,
|
|
2169
|
+
{
|
|
2170
|
+
questionId: questionToRender.id,
|
|
2171
|
+
optionLabel: questionToRender.falseLabel ?? "No",
|
|
2172
|
+
index: 1,
|
|
2173
|
+
isSelected: answers[questionToRender.id] === false,
|
|
2174
|
+
isInteractionLocked,
|
|
2175
|
+
onClick: () => setAnswers((current) => updateAnswerValue(current, questionToRender.id, false))
|
|
2176
|
+
}
|
|
2177
|
+
)
|
|
1863
2178
|
] }) });
|
|
1864
2179
|
default:
|
|
1865
2180
|
return null;
|
|
1866
2181
|
}
|
|
1867
2182
|
};
|
|
1868
2183
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Card4, { "data-testid": "questionnaire-card", children: [
|
|
1869
|
-
questionnaire.title ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Title3, { children: questionnaire.title }) : null,
|
|
1870
2184
|
questionnaire.description ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Description, { children: questionnaire.description }) : null,
|
|
1871
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QuestionList, { children:
|
|
2185
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QuestionList, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(QuestionCard, { children: [
|
|
1872
2186
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(QuestionLabel, { children: [
|
|
1873
2187
|
question.label,
|
|
1874
2188
|
question.required ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Required, { children: "*" }) : null
|
|
1875
2189
|
] }),
|
|
2190
|
+
question.kind === "multi_select" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QuestionHint, { children: resolvedLabels.multiSelectHint }) : null,
|
|
1876
2191
|
renderQuestion(question)
|
|
1877
|
-
] }, question.id)
|
|
2192
|
+
] }, question.id) }),
|
|
1878
2193
|
visibleErrorMessage ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ErrorMessage, { "data-testid": "questionnaire-error", children: visibleErrorMessage }) : null,
|
|
1879
2194
|
isSubmitted ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SuccessMessage, { "data-testid": "questionnaire-success", children: resolvedLabels.submitted }) : interactive && !hasExternalFailureStatus ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1880
2195
|
SubmitButton,
|
|
@@ -1890,12 +2205,6 @@ var QuestionnaireCardInner = ({
|
|
|
1890
2205
|
) : null
|
|
1891
2206
|
] });
|
|
1892
2207
|
};
|
|
1893
|
-
var getQuestionnaireStateKey = (questionnaire) => JSON.stringify([
|
|
1894
|
-
questionnaire.questionnaireId,
|
|
1895
|
-
questionnaire.questions,
|
|
1896
|
-
questionnaire.status,
|
|
1897
|
-
questionnaire.statusMessage
|
|
1898
|
-
]);
|
|
1899
2208
|
var QuestionnaireCard = (props) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QuestionnaireCardInner, { ...props }, getQuestionnaireStateKey(props.questionnaire));
|
|
1900
2209
|
var Card4 = import_styled4.default.section`
|
|
1901
2210
|
display: grid;
|
|
@@ -1905,11 +2214,6 @@ var Card4 = import_styled4.default.section`
|
|
|
1905
2214
|
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
1906
2215
|
background: rgba(255, 255, 255, 0.03);
|
|
1907
2216
|
`;
|
|
1908
|
-
var Title3 = import_styled4.default.strong`
|
|
1909
|
-
color: rgba(255, 255, 255, 0.94);
|
|
1910
|
-
font-size: 16px;
|
|
1911
|
-
line-height: 1.4;
|
|
1912
|
-
`;
|
|
1913
2217
|
var Description = import_styled4.default.p`
|
|
1914
2218
|
margin: 0;
|
|
1915
2219
|
color: rgba(255, 255, 255, 0.72);
|
|
@@ -1928,13 +2232,18 @@ var QuestionCard = import_styled4.default.div`
|
|
|
1928
2232
|
`;
|
|
1929
2233
|
var QuestionLabel = import_styled4.default.div`
|
|
1930
2234
|
color: rgba(255, 255, 255, 0.9);
|
|
1931
|
-
font-size:
|
|
2235
|
+
font-size: 14px;
|
|
1932
2236
|
font-weight: 600;
|
|
1933
2237
|
`;
|
|
1934
2238
|
var Required = import_styled4.default.span`
|
|
1935
2239
|
margin-left: 4px;
|
|
1936
2240
|
color: rgba(255, 122, 122, 0.9);
|
|
1937
2241
|
`;
|
|
2242
|
+
var QuestionHint = import_styled4.default.div`
|
|
2243
|
+
color: rgba(132, 180, 255, 0.9);
|
|
2244
|
+
font-size: 12px;
|
|
2245
|
+
line-height: 1.4;
|
|
2246
|
+
`;
|
|
1938
2247
|
var QuestionBody = import_styled4.default.div`
|
|
1939
2248
|
display: grid;
|
|
1940
2249
|
gap: 10px;
|
|
@@ -1952,7 +2261,7 @@ var OptionChoiceItem = import_styled4.default.div`
|
|
|
1952
2261
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
1953
2262
|
border-radius: 14px;
|
|
1954
2263
|
background: rgba(255, 255, 255, 0.03);
|
|
1955
|
-
padding: 12px
|
|
2264
|
+
padding: 2px 12px;
|
|
1956
2265
|
color: rgba(255, 255, 255, 0.9);
|
|
1957
2266
|
cursor: pointer;
|
|
1958
2267
|
transition:
|
|
@@ -2003,8 +2312,11 @@ var OptionChoiceMarker = import_styled4.default.span`
|
|
|
2003
2312
|
}
|
|
2004
2313
|
`;
|
|
2005
2314
|
var OptionChoiceContent = import_styled4.default.span`
|
|
2006
|
-
display:
|
|
2007
|
-
|
|
2315
|
+
display: flex;
|
|
2316
|
+
flex-direction: column;
|
|
2317
|
+
justify-content: center;
|
|
2318
|
+
gap: 4px;
|
|
2319
|
+
min-height: 40px;
|
|
2008
2320
|
min-width: 0;
|
|
2009
2321
|
flex: 1;
|
|
2010
2322
|
`;
|
|
@@ -2027,8 +2339,37 @@ var TextInput = import_styled4.default.input`
|
|
|
2027
2339
|
color: rgba(255, 255, 255, 0.34);
|
|
2028
2340
|
}
|
|
2029
2341
|
`;
|
|
2030
|
-
var InlineOtherInput = (0, import_styled4.default)(
|
|
2342
|
+
var InlineOtherInput = (0, import_styled4.default)(import_compass_ui.InputField)`
|
|
2343
|
+
width: 100%;
|
|
2031
2344
|
margin-top: 0;
|
|
2345
|
+
|
|
2346
|
+
.compass-input-field-wrapper {
|
|
2347
|
+
min-height: 30px;
|
|
2348
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
2349
|
+
border-radius: 10px;
|
|
2350
|
+
background: rgba(13, 15, 21, 0.55);
|
|
2351
|
+
box-shadow: none;
|
|
2352
|
+
padding: 2px 9px;
|
|
2353
|
+
}
|
|
2354
|
+
|
|
2355
|
+
.compass-input-field-wrapper:hover {
|
|
2356
|
+
border-color: rgba(126, 160, 255, 0.28);
|
|
2357
|
+
}
|
|
2358
|
+
|
|
2359
|
+
.compass-input-field-wrapper:focus-within {
|
|
2360
|
+
border-color: rgba(126, 160, 255, 0.42);
|
|
2361
|
+
box-shadow: 0 0 0 1px rgba(126, 160, 255, 0.14);
|
|
2362
|
+
}
|
|
2363
|
+
|
|
2364
|
+
.compass-input-field-input {
|
|
2365
|
+
color: rgba(255, 255, 255, 0.92);
|
|
2366
|
+
font-size: 13px;
|
|
2367
|
+
line-height: 1.2;
|
|
2368
|
+
}
|
|
2369
|
+
|
|
2370
|
+
.compass-input-field-input::placeholder {
|
|
2371
|
+
color: rgba(255, 255, 255, 0.34);
|
|
2372
|
+
}
|
|
2032
2373
|
`;
|
|
2033
2374
|
var NumberInputRow = import_styled4.default.div`
|
|
2034
2375
|
display: flex;
|
|
@@ -2337,9 +2678,7 @@ var arePlanQuestionsEqual = (previousQuestion, nextQuestion) => {
|
|
|
2337
2678
|
return false;
|
|
2338
2679
|
}
|
|
2339
2680
|
};
|
|
2340
|
-
var areQuestionnairesEqual = (previousQuestionnaire, nextQuestionnaire) => previousQuestionnaire.questionnaireId === nextQuestionnaire.questionnaireId && previousQuestionnaire.title === nextQuestionnaire.title && previousQuestionnaire.description === nextQuestionnaire.description && previousQuestionnaire.submitLabel === nextQuestionnaire.submitLabel && previousQuestionnaire.status === nextQuestionnaire.status && previousQuestionnaire.statusMessage === nextQuestionnaire.statusMessage && previousQuestionnaire.
|
|
2341
|
-
(question, index) => arePlanQuestionsEqual(question, nextQuestionnaire.questions[index])
|
|
2342
|
-
) && areQuestionAnswerMapsEqual(previousQuestionnaire.answers, nextQuestionnaire.answers);
|
|
2681
|
+
var areQuestionnairesEqual = (previousQuestionnaire, nextQuestionnaire) => previousQuestionnaire.questionnaireId === nextQuestionnaire.questionnaireId && previousQuestionnaire.title === nextQuestionnaire.title && previousQuestionnaire.description === nextQuestionnaire.description && previousQuestionnaire.submitLabel === nextQuestionnaire.submitLabel && previousQuestionnaire.status === nextQuestionnaire.status && previousQuestionnaire.statusMessage === nextQuestionnaire.statusMessage && arePlanQuestionsEqual(previousQuestionnaire.question, nextQuestionnaire.question) && areQuestionAnswerMapsEqual(previousQuestionnaire.answers, nextQuestionnaire.answers);
|
|
2343
2682
|
var areMessageBlocksEqual = (previousBlocks, nextBlocks) => {
|
|
2344
2683
|
if (previousBlocks === nextBlocks) {
|
|
2345
2684
|
return true;
|
|
@@ -2493,7 +2832,10 @@ var ChatMessageItemView = ({
|
|
|
2493
2832
|
submitting: labels.questionnaireSubmitting,
|
|
2494
2833
|
submitted: labels.questionnaireSubmitted,
|
|
2495
2834
|
validationPrefix: labels.questionnaireValidationPrefix,
|
|
2496
|
-
submitFailed: labels.questionnaireSubmitFailed
|
|
2835
|
+
submitFailed: labels.questionnaireSubmitFailed,
|
|
2836
|
+
multiSelectHint: labels.questionnaireMultiSelectHint,
|
|
2837
|
+
otherOptionLabel: labels.questionnaireOtherOptionLabel,
|
|
2838
|
+
otherPlaceholder: labels.questionnaireOtherPlaceholder
|
|
2497
2839
|
},
|
|
2498
2840
|
onSubmit: canSubmitQuestionnaire ? (submission) => onQuestionnaireSubmit({
|
|
2499
2841
|
...submission,
|
|
@@ -2752,8 +3094,34 @@ var CollapseToggle = import_styled7.default.button`
|
|
|
2752
3094
|
`;
|
|
2753
3095
|
var Content = import_styled7.default.div`
|
|
2754
3096
|
color: rgba(255, 255, 255, 0.92);
|
|
3097
|
+
font-size: 14px;
|
|
2755
3098
|
line-height: 1.6;
|
|
2756
3099
|
|
|
3100
|
+
h1,
|
|
3101
|
+
h2,
|
|
3102
|
+
h3,
|
|
3103
|
+
h4,
|
|
3104
|
+
h5,
|
|
3105
|
+
h6 {
|
|
3106
|
+
margin: 0;
|
|
3107
|
+
line-height: 2.5;
|
|
3108
|
+
}
|
|
3109
|
+
|
|
3110
|
+
h1 {
|
|
3111
|
+
font-size: 18px;
|
|
3112
|
+
}
|
|
3113
|
+
|
|
3114
|
+
h2 {
|
|
3115
|
+
font-size: 16px;
|
|
3116
|
+
}
|
|
3117
|
+
|
|
3118
|
+
h3,
|
|
3119
|
+
h4,
|
|
3120
|
+
h5,
|
|
3121
|
+
h6 {
|
|
3122
|
+
font-size: 14px;
|
|
3123
|
+
}
|
|
3124
|
+
|
|
2757
3125
|
p {
|
|
2758
3126
|
margin: 0;
|
|
2759
3127
|
}
|
|
@@ -2765,7 +3133,7 @@ var Content = import_styled7.default.div`
|
|
|
2765
3133
|
table {
|
|
2766
3134
|
width: 100%;
|
|
2767
3135
|
border-collapse: collapse;
|
|
2768
|
-
margin: 0;
|
|
3136
|
+
margin: 8px 0 0;
|
|
2769
3137
|
overflow: hidden;
|
|
2770
3138
|
border-radius: 14px;
|
|
2771
3139
|
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
@@ -2789,6 +3157,10 @@ var Content = import_styled7.default.div`
|
|
|
2789
3157
|
tbody tr:last-of-type td {
|
|
2790
3158
|
border-bottom: none;
|
|
2791
3159
|
}
|
|
3160
|
+
ul,
|
|
3161
|
+
ol {
|
|
3162
|
+
margin: 0 0 8px;
|
|
3163
|
+
}
|
|
2792
3164
|
`;
|
|
2793
3165
|
var ContentStack = import_styled7.default.div`
|
|
2794
3166
|
display: flex;
|
|
@@ -2989,6 +3361,8 @@ var HeroSubtitle = import_styled8.default.p`
|
|
|
2989
3361
|
|
|
2990
3362
|
// src/components/chat-thread/index.tsx
|
|
2991
3363
|
var import_jsx_runtime10 = require("@emotion/react/jsx-runtime");
|
|
3364
|
+
var CHAT_THREAD_PINNED_THRESHOLD_PX = 32;
|
|
3365
|
+
var isThreadPinnedToBottom = (container) => container.scrollHeight - container.clientHeight - container.scrollTop <= CHAT_THREAD_PINNED_THRESHOLD_PX;
|
|
2992
3366
|
var renderChatMessage = ({
|
|
2993
3367
|
message,
|
|
2994
3368
|
mode,
|
|
@@ -3062,6 +3436,7 @@ var ChatThreadView = ({
|
|
|
3062
3436
|
streamingMessage,
|
|
3063
3437
|
error,
|
|
3064
3438
|
retryButtonLabel,
|
|
3439
|
+
scrollToLatestLabel,
|
|
3065
3440
|
onRetry,
|
|
3066
3441
|
onConfirmationSubmit,
|
|
3067
3442
|
onQuestionnaireSubmit,
|
|
@@ -3075,9 +3450,15 @@ var ChatThreadView = ({
|
|
|
3075
3450
|
const latestTurn = conversationTurns[conversationTurns.length - 1];
|
|
3076
3451
|
const previousTurns = conversationTurns.slice(0, -1);
|
|
3077
3452
|
const latestUserMessageId = latestTurn?.userMessage?.id;
|
|
3078
|
-
const
|
|
3453
|
+
const latestHistoryMessage = historyMessages[historyMessages.length - 1];
|
|
3454
|
+
const latestTurnRef = (0, import_react11.useRef)(null);
|
|
3079
3455
|
const reservedSpaceFrameRef = (0, import_react11.useRef)(null);
|
|
3456
|
+
const isPinnedRef = (0, import_react11.useRef)(true);
|
|
3457
|
+
const lastHistoryMessageIdRef = (0, import_react11.useRef)(latestHistoryMessage?.id);
|
|
3458
|
+
const lastStreamingMessageIdRef = (0, import_react11.useRef)(streamingMessage?.id);
|
|
3080
3459
|
const [latestTurnMinHeight, setLatestTurnMinHeight] = (0, import_react11.useState)(0);
|
|
3460
|
+
const [isDetached, setIsDetached] = (0, import_react11.useState)(false);
|
|
3461
|
+
const [pendingNewMessageCount, setPendingNewMessageCount] = (0, import_react11.useState)(0);
|
|
3081
3462
|
const measureLatestTurnMinHeight = (0, import_react11.useCallback)(() => {
|
|
3082
3463
|
const container = containerRef.current;
|
|
3083
3464
|
if (!container)
|
|
@@ -3088,26 +3469,86 @@ var ChatThreadView = ({
|
|
|
3088
3469
|
const nextMinHeight = Math.max(0, container.clientHeight - paddingTop - paddingBottom);
|
|
3089
3470
|
setLatestTurnMinHeight((current) => current === nextMinHeight ? current : nextMinHeight);
|
|
3090
3471
|
}, []);
|
|
3091
|
-
const
|
|
3472
|
+
const scrollToBottom = (0, import_react11.useCallback)((force = false) => {
|
|
3092
3473
|
const container = containerRef.current;
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
const
|
|
3098
|
-
|
|
3099
|
-
0,
|
|
3100
|
-
container.scrollTop + (targetRect.top - containerRect.top) - CHAT_THREAD_SCROLL_TOP_GAP
|
|
3101
|
-
);
|
|
3474
|
+
if (!container)
|
|
3475
|
+
return false;
|
|
3476
|
+
if (!force && !isPinnedRef.current)
|
|
3477
|
+
return false;
|
|
3478
|
+
const nextScrollTop = Math.max(0, container.scrollHeight - container.clientHeight);
|
|
3479
|
+
container.scrollTop = nextScrollTop;
|
|
3102
3480
|
if (typeof container.scrollTo === "function") {
|
|
3103
3481
|
container.scrollTo({
|
|
3104
3482
|
top: nextScrollTop,
|
|
3105
3483
|
behavior: "auto"
|
|
3106
3484
|
});
|
|
3485
|
+
}
|
|
3486
|
+
return true;
|
|
3487
|
+
}, []);
|
|
3488
|
+
const markThreadPinned = (0, import_react11.useCallback)(() => {
|
|
3489
|
+
isPinnedRef.current = true;
|
|
3490
|
+
setIsDetached(false);
|
|
3491
|
+
setPendingNewMessageCount(0);
|
|
3492
|
+
}, []);
|
|
3493
|
+
const scrollToBottomAndPin = (0, import_react11.useCallback)(
|
|
3494
|
+
(force = false) => {
|
|
3495
|
+
const didScroll = scrollToBottom(force);
|
|
3496
|
+
if (!didScroll)
|
|
3497
|
+
return;
|
|
3498
|
+
markThreadPinned();
|
|
3499
|
+
},
|
|
3500
|
+
[markThreadPinned, scrollToBottom]
|
|
3501
|
+
);
|
|
3502
|
+
const handleContainerScroll = (0, import_react11.useCallback)(() => {
|
|
3503
|
+
const container = containerRef.current;
|
|
3504
|
+
if (!container)
|
|
3107
3505
|
return;
|
|
3506
|
+
const nextPinned = isThreadPinnedToBottom(container);
|
|
3507
|
+
isPinnedRef.current = nextPinned;
|
|
3508
|
+
setIsDetached(!nextPinned);
|
|
3509
|
+
if (nextPinned) {
|
|
3510
|
+
setPendingNewMessageCount(0);
|
|
3108
3511
|
}
|
|
3109
|
-
container.scrollTop = nextScrollTop;
|
|
3110
3512
|
}, []);
|
|
3513
|
+
(0, import_react11.useLayoutEffect)(() => {
|
|
3514
|
+
const nextHistoryMessageId = latestHistoryMessage?.id;
|
|
3515
|
+
if (lastHistoryMessageIdRef.current === nextHistoryMessageId) {
|
|
3516
|
+
return;
|
|
3517
|
+
}
|
|
3518
|
+
lastHistoryMessageIdRef.current = nextHistoryMessageId;
|
|
3519
|
+
if (!latestHistoryMessage) {
|
|
3520
|
+
return;
|
|
3521
|
+
}
|
|
3522
|
+
if (latestHistoryMessage.role === "user") {
|
|
3523
|
+
window.requestAnimationFrame(() => {
|
|
3524
|
+
if (!scrollToBottom(true)) {
|
|
3525
|
+
return;
|
|
3526
|
+
}
|
|
3527
|
+
markThreadPinned();
|
|
3528
|
+
});
|
|
3529
|
+
return;
|
|
3530
|
+
}
|
|
3531
|
+
if (!isPinnedRef.current && latestHistoryMessage.role === "assistant" && latestHistoryMessage.id !== lastStreamingMessageIdRef.current) {
|
|
3532
|
+
window.requestAnimationFrame(() => {
|
|
3533
|
+
setPendingNewMessageCount((current) => current + 1);
|
|
3534
|
+
});
|
|
3535
|
+
}
|
|
3536
|
+
}, [latestHistoryMessage, markThreadPinned, scrollToBottom]);
|
|
3537
|
+
(0, import_react11.useLayoutEffect)(() => {
|
|
3538
|
+
const nextStreamingMessageId = streamingMessage?.id;
|
|
3539
|
+
if (lastStreamingMessageIdRef.current === nextStreamingMessageId) {
|
|
3540
|
+
return;
|
|
3541
|
+
}
|
|
3542
|
+
lastStreamingMessageIdRef.current = nextStreamingMessageId;
|
|
3543
|
+
if (!streamingMessage || streamingMessage.role !== "assistant") {
|
|
3544
|
+
return;
|
|
3545
|
+
}
|
|
3546
|
+
if (!isPinnedRef.current) {
|
|
3547
|
+
window.requestAnimationFrame(() => {
|
|
3548
|
+
setPendingNewMessageCount((current) => current + 1);
|
|
3549
|
+
});
|
|
3550
|
+
}
|
|
3551
|
+
}, [streamingMessage]);
|
|
3111
3552
|
(0, import_react11.useLayoutEffect)(() => {
|
|
3112
3553
|
if (reservedSpaceFrameRef.current !== null) {
|
|
3113
3554
|
window.cancelAnimationFrame(reservedSpaceFrameRef.current);
|
|
@@ -3117,6 +3558,7 @@ var ChatThreadView = ({
|
|
|
3117
3558
|
reservedSpaceFrameRef.current = window.requestAnimationFrame(() => {
|
|
3118
3559
|
reservedSpaceFrameRef.current = null;
|
|
3119
3560
|
setLatestTurnMinHeight((current) => current === 0 ? current : 0);
|
|
3561
|
+
scrollToBottom();
|
|
3120
3562
|
});
|
|
3121
3563
|
return () => {
|
|
3122
3564
|
if (reservedSpaceFrameRef.current !== null) {
|
|
@@ -3128,7 +3570,7 @@ var ChatThreadView = ({
|
|
|
3128
3570
|
reservedSpaceFrameRef.current = window.requestAnimationFrame(() => {
|
|
3129
3571
|
reservedSpaceFrameRef.current = null;
|
|
3130
3572
|
measureLatestTurnMinHeight();
|
|
3131
|
-
|
|
3573
|
+
scrollToBottom();
|
|
3132
3574
|
});
|
|
3133
3575
|
return () => {
|
|
3134
3576
|
if (reservedSpaceFrameRef.current !== null) {
|
|
@@ -3136,13 +3578,18 @@ var ChatThreadView = ({
|
|
|
3136
3578
|
reservedSpaceFrameRef.current = null;
|
|
3137
3579
|
}
|
|
3138
3580
|
};
|
|
3139
|
-
}, [latestUserMessageId, measureLatestTurnMinHeight,
|
|
3581
|
+
}, [latestTurn, latestUserMessageId, error, measureLatestTurnMinHeight, scrollToBottom]);
|
|
3140
3582
|
(0, import_react11.useLayoutEffect)(() => {
|
|
3141
|
-
if (!
|
|
3583
|
+
if (!latestTurn)
|
|
3142
3584
|
return;
|
|
3143
3585
|
const handleResize = () => {
|
|
3586
|
+
if (!latestUserMessageId) {
|
|
3587
|
+
setLatestTurnMinHeight((current) => current === 0 ? current : 0);
|
|
3588
|
+
scrollToBottom();
|
|
3589
|
+
return;
|
|
3590
|
+
}
|
|
3144
3591
|
measureLatestTurnMinHeight();
|
|
3145
|
-
|
|
3592
|
+
scrollToBottom();
|
|
3146
3593
|
};
|
|
3147
3594
|
const container = containerRef.current;
|
|
3148
3595
|
let resizeObserver = null;
|
|
@@ -3157,57 +3604,101 @@ var ChatThreadView = ({
|
|
|
3157
3604
|
resizeObserver?.disconnect();
|
|
3158
3605
|
window.removeEventListener("resize", handleResize);
|
|
3159
3606
|
};
|
|
3160
|
-
}, [latestUserMessageId, measureLatestTurnMinHeight,
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3607
|
+
}, [latestTurn, latestUserMessageId, measureLatestTurnMinHeight, scrollToBottom]);
|
|
3608
|
+
(0, import_react11.useLayoutEffect)(() => {
|
|
3609
|
+
const latestTurnElement = latestTurnRef.current;
|
|
3610
|
+
if (!latestTurnElement || typeof ResizeObserver === "undefined") {
|
|
3611
|
+
return;
|
|
3612
|
+
}
|
|
3613
|
+
const observer = new ResizeObserver(() => {
|
|
3614
|
+
scrollToBottom();
|
|
3615
|
+
});
|
|
3616
|
+
observer.observe(latestTurnElement);
|
|
3617
|
+
return () => {
|
|
3618
|
+
observer.disconnect();
|
|
3619
|
+
};
|
|
3620
|
+
}, [latestTurn, scrollToBottom]);
|
|
3621
|
+
(0, import_react11.useLayoutEffect)(() => {
|
|
3622
|
+
const latestTurnElement = latestTurnRef.current;
|
|
3623
|
+
if (!latestTurnElement || typeof MutationObserver === "undefined") {
|
|
3624
|
+
return;
|
|
3625
|
+
}
|
|
3626
|
+
const observer = new MutationObserver(() => {
|
|
3627
|
+
scrollToBottom();
|
|
3628
|
+
});
|
|
3629
|
+
observer.observe(latestTurnElement, {
|
|
3630
|
+
childList: true,
|
|
3631
|
+
subtree: true,
|
|
3632
|
+
characterData: true
|
|
3633
|
+
});
|
|
3634
|
+
return () => {
|
|
3635
|
+
observer.disconnect();
|
|
3636
|
+
};
|
|
3637
|
+
}, [latestTurn, scrollToBottom]);
|
|
3638
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(ThreadViewport, { children: [
|
|
3639
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Container, { ref: containerRef, "data-testid": "chat-thread", onScroll: handleContainerScroll, children: [
|
|
3640
|
+
previousTurns.map((turn) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(ConversationTurn, { "data-testid": "chat-thread-turn", children: [
|
|
3641
|
+
turn.userMessage ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MessageSlot, { children: renderChatMessage({
|
|
3642
|
+
message: turn.userMessage,
|
|
3643
|
+
mode: activeSessionMode,
|
|
3644
|
+
onConfirmationSubmit,
|
|
3645
|
+
onQuestionnaireSubmit,
|
|
3646
|
+
renderMessageBlock
|
|
3647
|
+
}) }) : null,
|
|
3648
|
+
turn.responseMessages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MessageSlot, { children: renderChatMessage({
|
|
3649
|
+
message,
|
|
3650
|
+
mode: activeSessionMode,
|
|
3651
|
+
onConfirmationSubmit,
|
|
3652
|
+
onQuestionnaireSubmit,
|
|
3653
|
+
renderMessageBlock
|
|
3654
|
+
}) }, message.id))
|
|
3655
|
+
] }, turn.id)),
|
|
3656
|
+
latestTurn ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
3657
|
+
ConversationTurn,
|
|
3658
|
+
{
|
|
3659
|
+
ref: latestTurnRef,
|
|
3660
|
+
"data-testid": "chat-thread-latest-turn",
|
|
3661
|
+
style: latestTurnMinHeight > 0 ? { minHeight: `${latestTurnMinHeight}px` } : void 0,
|
|
3662
|
+
children: [
|
|
3663
|
+
latestTurn.userMessage ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
3664
|
+
MessageSlot,
|
|
3665
|
+
{
|
|
3666
|
+
"data-testid": "chat-latest-user-anchor",
|
|
3667
|
+
style: { scrollMarginTop: `${CHAT_THREAD_SCROLL_TOP_GAP}px` },
|
|
3668
|
+
children: renderChatMessage({
|
|
3669
|
+
message: latestTurn.userMessage,
|
|
3670
|
+
mode: activeSessionMode,
|
|
3671
|
+
onConfirmationSubmit,
|
|
3672
|
+
onQuestionnaireSubmit,
|
|
3673
|
+
renderMessageBlock
|
|
3674
|
+
})
|
|
3675
|
+
}
|
|
3676
|
+
) : null,
|
|
3677
|
+
latestTurn.responseMessages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MessageSlot, { children: renderChatMessage({
|
|
3678
|
+
message,
|
|
3679
|
+
mode: activeSessionMode,
|
|
3680
|
+
onConfirmationSubmit,
|
|
3681
|
+
onQuestionnaireSubmit,
|
|
3682
|
+
renderMessageBlock
|
|
3683
|
+
}) }, message.id)),
|
|
3684
|
+
error ? renderErrorState({ error, onRetry, retryButtonLabel }) : null
|
|
3685
|
+
]
|
|
3686
|
+
}
|
|
3687
|
+
) : null,
|
|
3688
|
+
!latestTurn && error ? renderErrorState({ error, onRetry, retryButtonLabel }) : null
|
|
3689
|
+
] }),
|
|
3690
|
+
isDetached ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ScrollToLatestOverlay, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
3691
|
+
ScrollToLatestButton,
|
|
3180
3692
|
{
|
|
3181
|
-
|
|
3182
|
-
|
|
3693
|
+
type: "button",
|
|
3694
|
+
"data-testid": "chat-thread-scroll-to-latest",
|
|
3695
|
+
onClick: () => scrollToBottomAndPin(true),
|
|
3183
3696
|
children: [
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
{
|
|
3187
|
-
ref: latestUserMessageRef,
|
|
3188
|
-
"data-testid": "chat-latest-user-anchor",
|
|
3189
|
-
style: { scrollMarginTop: `${CHAT_THREAD_SCROLL_TOP_GAP}px` },
|
|
3190
|
-
children: renderChatMessage({
|
|
3191
|
-
message: latestTurn.userMessage,
|
|
3192
|
-
mode: activeSessionMode,
|
|
3193
|
-
onConfirmationSubmit,
|
|
3194
|
-
onQuestionnaireSubmit,
|
|
3195
|
-
renderMessageBlock
|
|
3196
|
-
})
|
|
3197
|
-
}
|
|
3198
|
-
) : null,
|
|
3199
|
-
latestTurn.responseMessages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MessageSlot, { children: renderChatMessage({
|
|
3200
|
-
message,
|
|
3201
|
-
mode: activeSessionMode,
|
|
3202
|
-
onConfirmationSubmit,
|
|
3203
|
-
onQuestionnaireSubmit,
|
|
3204
|
-
renderMessageBlock
|
|
3205
|
-
}) }, message.id)),
|
|
3206
|
-
error ? renderErrorState({ error, onRetry, retryButtonLabel }) : null
|
|
3697
|
+
scrollToLatestLabel,
|
|
3698
|
+
pendingNewMessageCount > 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ScrollToLatestBadge, { "data-testid": "chat-thread-scroll-to-latest-count", children: pendingNewMessageCount }) : null
|
|
3207
3699
|
]
|
|
3208
3700
|
}
|
|
3209
|
-
) : null
|
|
3210
|
-
!latestTurn && error ? renderErrorState({ error, onRetry, retryButtonLabel }) : null
|
|
3701
|
+
) }) : null
|
|
3211
3702
|
] });
|
|
3212
3703
|
};
|
|
3213
3704
|
var EMPTY_MESSAGES = [];
|
|
@@ -3295,13 +3786,21 @@ var ChatThread = () => {
|
|
|
3295
3786
|
streamingMessage,
|
|
3296
3787
|
error,
|
|
3297
3788
|
retryButtonLabel: labels.retryButton,
|
|
3789
|
+
scrollToLatestLabel: labels.scrollToLatest,
|
|
3298
3790
|
onRetry: handleRetry,
|
|
3299
3791
|
onConfirmationSubmit: handleConfirmation,
|
|
3300
3792
|
onQuestionnaireSubmit: handleQuestionnaireSubmit,
|
|
3301
3793
|
renderMessageBlock
|
|
3302
|
-
}
|
|
3794
|
+
},
|
|
3795
|
+
activeSessionId ?? "chat-thread-empty"
|
|
3303
3796
|
);
|
|
3304
3797
|
};
|
|
3798
|
+
var ThreadViewport = import_styled9.default.div`
|
|
3799
|
+
position: relative;
|
|
3800
|
+
display: flex;
|
|
3801
|
+
flex: 1;
|
|
3802
|
+
min-height: 0;
|
|
3803
|
+
`;
|
|
3305
3804
|
var Container = import_styled9.default.div`
|
|
3306
3805
|
display: flex;
|
|
3307
3806
|
flex: 1;
|
|
@@ -3309,8 +3808,7 @@ var Container = import_styled9.default.div`
|
|
|
3309
3808
|
gap: 18px;
|
|
3310
3809
|
min-height: 0;
|
|
3311
3810
|
overflow: auto;
|
|
3312
|
-
padding: 24px;
|
|
3313
|
-
margin-bottom: 24px;
|
|
3811
|
+
padding: 24px 24px 88px;
|
|
3314
3812
|
overscroll-behavior: contain;
|
|
3315
3813
|
|
|
3316
3814
|
&::-webkit-scrollbar {
|
|
@@ -3362,6 +3860,48 @@ var RetryButton = import_styled9.default.button`
|
|
|
3362
3860
|
background: rgba(255, 255, 255, 0.08);
|
|
3363
3861
|
}
|
|
3364
3862
|
`;
|
|
3863
|
+
var ScrollToLatestOverlay = import_styled9.default.div`
|
|
3864
|
+
position: absolute;
|
|
3865
|
+
right: 24px;
|
|
3866
|
+
bottom: 24px;
|
|
3867
|
+
left: 24px;
|
|
3868
|
+
display: flex;
|
|
3869
|
+
justify-content: center;
|
|
3870
|
+
pointer-events: none;
|
|
3871
|
+
`;
|
|
3872
|
+
var ScrollToLatestButton = import_styled9.default.button`
|
|
3873
|
+
display: inline-flex;
|
|
3874
|
+
align-items: center;
|
|
3875
|
+
gap: 8px;
|
|
3876
|
+
border: 1px solid rgba(255, 255, 255, 0.14);
|
|
3877
|
+
border-radius: 999px;
|
|
3878
|
+
background: rgba(17, 18, 21, 0.92);
|
|
3879
|
+
color: rgba(255, 255, 255, 0.9);
|
|
3880
|
+
font-size: 12px;
|
|
3881
|
+
line-height: 1;
|
|
3882
|
+
padding: 10px 14px;
|
|
3883
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.28);
|
|
3884
|
+
cursor: pointer;
|
|
3885
|
+
z-index: 1;
|
|
3886
|
+
pointer-events: auto;
|
|
3887
|
+
|
|
3888
|
+
&:hover {
|
|
3889
|
+
background: rgba(28, 30, 36, 0.96);
|
|
3890
|
+
}
|
|
3891
|
+
`;
|
|
3892
|
+
var ScrollToLatestBadge = import_styled9.default.span`
|
|
3893
|
+
display: inline-flex;
|
|
3894
|
+
min-width: 18px;
|
|
3895
|
+
height: 18px;
|
|
3896
|
+
align-items: center;
|
|
3897
|
+
justify-content: center;
|
|
3898
|
+
padding: 0 6px;
|
|
3899
|
+
border-radius: 999px;
|
|
3900
|
+
background: rgba(109, 170, 255, 0.2);
|
|
3901
|
+
color: #9ac0ff;
|
|
3902
|
+
font-size: 11px;
|
|
3903
|
+
font-weight: 600;
|
|
3904
|
+
`;
|
|
3365
3905
|
|
|
3366
3906
|
// src/components/chat-composer/index.tsx
|
|
3367
3907
|
var import_react15 = require("react");
|
|
@@ -4087,7 +4627,7 @@ var CloseGlyph = import_styled10.default.span`
|
|
|
4087
4627
|
|
|
4088
4628
|
// src/components/chat-composer/components/chat-model-control.tsx
|
|
4089
4629
|
var import_styled11 = __toESM(require("@emotion/styled"));
|
|
4090
|
-
var
|
|
4630
|
+
var import_compass_ui2 = require("@xinghunm/compass-ui");
|
|
4091
4631
|
var import_jsx_runtime12 = require("@emotion/react/jsx-runtime");
|
|
4092
4632
|
var ChatModelControl = ({
|
|
4093
4633
|
selectedModel,
|
|
@@ -4188,7 +4728,7 @@ var ModelReloadButton = import_styled11.default.button`
|
|
|
4188
4728
|
var ReloadIcon = import_styled11.default.svg`
|
|
4189
4729
|
flex-shrink: 0;
|
|
4190
4730
|
`;
|
|
4191
|
-
var ModelSelect = (0, import_styled11.default)(
|
|
4731
|
+
var ModelSelect = (0, import_styled11.default)(import_compass_ui2.Select)`
|
|
4192
4732
|
&& {
|
|
4193
4733
|
width: auto;
|
|
4194
4734
|
min-width: 0;
|
|
@@ -4209,7 +4749,7 @@ var ModelSelect = (0, import_styled11.default)(import_compass_ui.Select)`
|
|
|
4209
4749
|
|
|
4210
4750
|
// src/components/chat-composer/components/chat-mode-control.tsx
|
|
4211
4751
|
var import_styled12 = __toESM(require("@emotion/styled"));
|
|
4212
|
-
var
|
|
4752
|
+
var import_compass_ui3 = require("@xinghunm/compass-ui");
|
|
4213
4753
|
var import_jsx_runtime13 = require("@emotion/react/jsx-runtime");
|
|
4214
4754
|
var ChatModeControl = ({
|
|
4215
4755
|
value,
|
|
@@ -4232,7 +4772,7 @@ var ChatModeControl = ({
|
|
|
4232
4772
|
}
|
|
4233
4773
|
);
|
|
4234
4774
|
};
|
|
4235
|
-
var ModeSelect = (0, import_styled12.default)(
|
|
4775
|
+
var ModeSelect = (0, import_styled12.default)(import_compass_ui3.Select)`
|
|
4236
4776
|
&& {
|
|
4237
4777
|
flex: 0 1 auto;
|
|
4238
4778
|
width: auto;
|
|
@@ -4254,7 +4794,7 @@ var ModeSelect = (0, import_styled12.default)(import_compass_ui2.Select)`
|
|
|
4254
4794
|
|
|
4255
4795
|
// src/components/chat-composer/components/chat-send-actions.tsx
|
|
4256
4796
|
var import_styled13 = __toESM(require("@emotion/styled"));
|
|
4257
|
-
var
|
|
4797
|
+
var import_compass_ui4 = require("@xinghunm/compass-ui");
|
|
4258
4798
|
var import_jsx_runtime14 = require("@emotion/react/jsx-runtime");
|
|
4259
4799
|
var ArrowUpIcon = () => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
4260
4800
|
"svg",
|
|
@@ -4308,7 +4848,7 @@ var ChatSendActions = ({
|
|
|
4308
4848
|
onClick: () => void onSend()
|
|
4309
4849
|
}
|
|
4310
4850
|
) });
|
|
4311
|
-
var PrimaryButton = (0, import_styled13.default)(
|
|
4851
|
+
var PrimaryButton = (0, import_styled13.default)(import_compass_ui4.Button)`
|
|
4312
4852
|
&& {
|
|
4313
4853
|
min-width: 24px;
|
|
4314
4854
|
width: 24px;
|
|
@@ -4334,7 +4874,7 @@ var PrimaryButton = (0, import_styled13.default)(import_compass_ui3.Button)`
|
|
|
4334
4874
|
}
|
|
4335
4875
|
}
|
|
4336
4876
|
`;
|
|
4337
|
-
var StopButton = (0, import_styled13.default)(
|
|
4877
|
+
var StopButton = (0, import_styled13.default)(import_compass_ui4.Button)`
|
|
4338
4878
|
&& {
|
|
4339
4879
|
min-width: 24px;
|
|
4340
4880
|
width: 24px;
|
|
@@ -4907,7 +5447,7 @@ var ChatConversationList = () => {
|
|
|
4907
5447
|
};
|
|
4908
5448
|
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(Container3, { children: [
|
|
4909
5449
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(Toolbar, { children: [
|
|
4910
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5450
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Title3, { children: "Sessions" }),
|
|
4911
5451
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(CreateButton, { type: "button", "data-testid": "chat-create-session", onClick: handleCreateSession, children: labels.newChat })
|
|
4912
5452
|
] }),
|
|
4913
5453
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(List2, { "data-testid": "chat-session-list", children: sessions.map((session) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
@@ -4936,7 +5476,7 @@ var Toolbar = import_styled16.default.div`
|
|
|
4936
5476
|
flex-direction: column;
|
|
4937
5477
|
gap: 12px;
|
|
4938
5478
|
`;
|
|
4939
|
-
var
|
|
5479
|
+
var Title3 = import_styled16.default.h2`
|
|
4940
5480
|
margin: 0;
|
|
4941
5481
|
font-size: 14px;
|
|
4942
5482
|
color: var(--text-secondary);
|
|
@@ -4961,7 +5501,7 @@ var List2 = import_styled16.default.div`
|
|
|
4961
5501
|
// src/components/ai-chat/index.tsx
|
|
4962
5502
|
var import_jsx_runtime18 = require("@emotion/react/jsx-runtime");
|
|
4963
5503
|
var AiChat = ({ showConversationList = false, ...providerProps }) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
4964
|
-
|
|
5504
|
+
import_compass_ui5.ConfigProvider,
|
|
4965
5505
|
{
|
|
4966
5506
|
theme: {
|
|
4967
5507
|
token: {
|