cozy-search 2.6.2 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/components/Assistant/AssistantAvatar.js +3 -1
  2. package/dist/components/Assistant/AssistantContainer.js +3 -1
  3. package/dist/components/Assistant/AssistantMenu.d.ts +16 -0
  4. package/dist/components/Assistant/AssistantMenu.js +160 -0
  5. package/dist/components/Assistant/AssistantSelection.d.ts +12 -1
  6. package/dist/components/Assistant/AssistantSelection.js +55 -115
  7. package/dist/components/Assistant/AssistantSelectionItem.js +3 -1
  8. package/dist/components/Assistant/AssistantSidebarItem.d.ts +9 -0
  9. package/dist/components/Assistant/AssistantSidebarItem.js +108 -0
  10. package/dist/components/Assistant/styles.styl +13 -0
  11. package/dist/components/Conversations/Conversation.js +74 -14
  12. package/dist/components/Conversations/ConversationBar.js +13 -5
  13. package/dist/components/Conversations/ConversationComposer.js +53 -23
  14. package/dist/components/Conversations/ConversationListItem.js +20 -40
  15. package/dist/components/Conversations/ConversationListItemWider.js +14 -11
  16. package/dist/components/Conversations/styles.styl +110 -23
  17. package/dist/components/CozyAssistantRuntimeProvider.js +15 -8
  18. package/dist/components/CreateAssistantSteps/BasicInfoStep.js +37 -1
  19. package/dist/components/CreateAssistantSteps/Provider.js +1 -0
  20. package/dist/components/CreateAssistantSteps/ProviderSelectionStep.js +1 -0
  21. package/dist/components/CreateAssistantSteps/styles.styl +14 -0
  22. package/dist/components/KnowledgeBase/FolderPickerDialog.js +3 -1
  23. package/dist/components/KnowledgeBase/KnowledgeBaseChip.d.ts +7 -5
  24. package/dist/components/KnowledgeBase/KnowledgeBaseChip.js +65 -31
  25. package/dist/components/KnowledgeBase/conversationAssistant.d.ts +2 -1
  26. package/dist/components/KnowledgeBase/conversationAssistant.js +6 -1
  27. package/dist/components/KnowledgeBase/conversationAssistant.spec.js +24 -0
  28. package/dist/components/KnowledgeBase/styles.styl +18 -0
  29. package/dist/components/Messages/AssistantMessage.js +25 -21
  30. package/dist/components/Messages/UserMessage.js +4 -1
  31. package/dist/components/Messages/styles.styl +41 -0
  32. package/dist/components/Search/SearchBarMobile.js +13 -5
  33. package/dist/components/Sidebar/index.js +55 -30
  34. package/dist/components/Sidebar/styles.styl +12 -11
  35. package/dist/components/TwakeKnowledges/SourceButton.d.ts +14 -0
  36. package/dist/components/TwakeKnowledges/SourceButton.js +98 -0
  37. package/dist/components/TwakeKnowledges/TwakeKnowledgeSelector.d.ts +9 -0
  38. package/dist/components/TwakeKnowledges/TwakeKnowledgeSelector.js +75 -50
  39. package/dist/components/TwakeKnowledges/styles.styl +29 -2
  40. package/dist/components/Views/AssistantView.js +9 -1
  41. package/dist/components/Views/CreateAssistantDialog.js +5 -1
  42. package/dist/components/Views/DeleteAssistantDialog.js +1 -0
  43. package/dist/components/Views/EditAssistantDialog.js +5 -1
  44. package/dist/hooks/useConversation.d.ts +2 -2
  45. package/dist/hooks/useConversation.js +25 -4
  46. package/dist/hooks/useConversation.spec.js +14 -2
  47. package/dist/hooks/useConversation.spec.jsx +21 -3
  48. package/dist/locales/en.json +5 -1
  49. package/dist/locales/fr.json +6 -2
  50. package/dist/locales/index.js +21 -5
  51. package/dist/locales/ru.json +5 -1
  52. package/dist/locales/vi.json +5 -1
  53. package/dist/stylesheet.css +253 -30
  54. package/package.json +2 -2
  55. package/dist/components/TwakeKnowledges/TwakeKnowledgeChip.d.ts +0 -13
  56. package/dist/components/TwakeKnowledges/TwakeKnowledgeChip.js +0 -80
  57. package/dist/components/TwakeKnowledges/WebSearchChip.d.ts +0 -5
  58. package/dist/components/TwakeKnowledges/WebSearchChip.js +0 -75
@@ -11,24 +11,44 @@ var _classnames = _interopRequireDefault(require("classnames"));
11
11
 
12
12
  var _react = _interopRequireDefault(require("react"));
13
13
 
14
+ var _twakeIcons = require("@linagora/twake-icons");
15
+
14
16
  var _cozyFlags = _interopRequireDefault(require("cozy-flags"));
15
17
 
16
- var _Typography = _interopRequireDefault(require("cozy-ui/transpiled/react/Typography"));
18
+ var _Chips = _interopRequireDefault(require("cozy-ui/transpiled/react/Chips"));
19
+
20
+ var _Breakpoints = require("cozy-ui/transpiled/react/providers/Breakpoints");
17
21
 
18
22
  var _twakeI18n = require("twake-i18n");
19
23
 
20
- var _TwakeKnowledgeChip = _interopRequireDefault(require("./TwakeKnowledgeChip"));
24
+ var _SourceButton = _interopRequireWildcard(require("./SourceButton"));
21
25
 
22
- var _WebSearchChip = _interopRequireDefault(require("./WebSearchChip"));
26
+ var _KnowledgeBaseChip = _interopRequireDefault(require("../KnowledgeBase/KnowledgeBaseChip"));
23
27
 
24
- var _tdrive = _interopRequireDefault(require("../../assets/tdrive.png"));
28
+ var _useSelectedAssistantKnowledgeBase = require("../KnowledgeBase/useSelectedAssistantKnowledgeBase");
25
29
 
26
- var _tmail = _interopRequireDefault(require("../../assets/tmail.png"));
30
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
27
31
 
28
- var _KnowledgeBaseChip = _interopRequireDefault(require("../KnowledgeBase/KnowledgeBaseChip"));
32
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
29
33
 
30
- var _useSelectedAssistantKnowledgeBase = require("../KnowledgeBase/useSelectedAssistantKnowledgeBase");
34
+ var styles = {
35
+ "source-button": "styles__source-button___9t9wI",
36
+ "source-button-image": "styles__source-button-image___2batD",
37
+ "source-button-image--inactive": "styles__source-button-image--inactive___3hs2C",
38
+ "source-chip": "styles__source-chip___1h51w",
39
+ "source-chip-icon": "styles__source-chip-icon___3-N0x",
40
+ "source-chip-label": "styles__source-chip-label___2mLIx"
41
+ };
31
42
 
43
+ /**
44
+ * The knowledge sources of the composer. The Drive source is always on:
45
+ * on desktop it is a chip named after the knowledge base folder (the
46
+ * whole Drive without one), whose menu opens the folder or changes it;
47
+ * on mobile it is an icon button. Web search (a toggle) and emails are
48
+ * icon buttons behind their flags: emails show on the default assistant
49
+ * always, on a custom assistant once enabled in the wizard. Sources are
50
+ * enabled/disabled from the wizard, never from the composer.
51
+ */
32
52
  var TwakeKnowledgeSelector = function TwakeKnowledgeSelector(_ref) {
33
53
  var className = _ref.className,
34
54
  websearchEnabled = _ref.websearchEnabled,
@@ -37,6 +57,9 @@ var TwakeKnowledgeSelector = function TwakeKnowledgeSelector(_ref) {
37
57
  var _useI18n = (0, _twakeI18n.useI18n)(),
38
58
  t = _useI18n.t;
39
59
 
60
+ var _useBreakpoints = (0, _Breakpoints.useBreakpoints)(),
61
+ isMobile = _useBreakpoints.isMobile;
62
+
40
63
  var _useSelectedAssistant = (0, _useSelectedAssistantKnowledgeBase.useSelectedAssistantKnowledgeBase)(),
41
64
  dirId = _useSelectedAssistant.dirId,
42
65
  folder = _useSelectedAssistant.folder,
@@ -48,54 +71,56 @@ var TwakeKnowledgeSelector = function TwakeKnowledgeSelector(_ref) {
48
71
 
49
72
  var websearchEnabledFlag = (0, _cozyFlags.default)('cozy.assistant.websearch.enabled');
50
73
  var mailSourceEnabledFlag = (0, _cozyFlags.default)('cozy.assistant.source-knowledge.mail.enabled');
51
- var hasKnowledgeBase = !!dirId; // The Drive source is always on and cannot be disabled: a knowledge-base
52
- // folder is rendered as KnowledgeBaseChip (with its own menu); otherwise
53
- // (default assistant, or no folder configured) a static Drive chip stands
54
- // for the whole Drive. The email source (behind its own flag) is shown on
55
- // the default assistant always, and on a custom assistant only once the
56
- // user enabled it in the wizard. The chips are static indicators: sources
57
- // are enabled/disabled from the wizard, never from the composer.
58
-
59
- var twakeKnowledges = [{
60
- id: 'mail',
61
- label: t('assistant.twake_knowledges.mail'),
62
- display: mailSourceEnabledFlag && (!isRealAssistant || hasEmail),
63
- icon: _tmail.default,
64
- isSelected: true
65
- }].filter(function (twakeKnowledge) {
66
- return twakeKnowledge.display;
67
- });
68
- var showSourceChips = twakeKnowledges.length > 0;
69
- return /*#__PURE__*/_react.default.createElement("div", {
70
- className: (0, _classnames.default)('u-flex u-flex-row u-flex-wrap u-flex-items-center u-flex-justify-end', className)
71
- }, /*#__PURE__*/_react.default.createElement(_Typography.default, {
72
- className: "u-mr-half u-fz-tiny u-coolGrey"
73
- }, t('assistant.twake_knowledges.search_in')), websearchEnabledFlag && /*#__PURE__*/_react.default.createElement(_WebSearchChip.default, {
74
- websearchEnabled: websearchEnabled,
75
- onToggleWebsearch: onToggleWebsearch
76
- }), hasKnowledgeBase ? /*#__PURE__*/_react.default.createElement(_KnowledgeBaseChip.default, {
74
+ var showMail = mailSourceEnabledFlag && (!isRealAssistant || hasEmail); // Pointer activation leaves the focus on the button, whose focus style
75
+ // would then differ from the sibling sources until something else takes
76
+ // it. Drop it for pointer activation only (`detail > 0`), so keyboard
77
+ // users keep their focus ring.
78
+
79
+ var handleToggleWebsearch = function handleToggleWebsearch(event) {
80
+ if (event.detail > 0) {
81
+ event.currentTarget.blur();
82
+ }
83
+
84
+ onToggleWebsearch(event);
85
+ };
86
+
87
+ var driveSource = dirId ? /*#__PURE__*/_react.default.createElement(_KnowledgeBaseChip.default, {
88
+ variant: isMobile ? 'icon' : 'chip',
77
89
  dirId: dirId,
78
90
  folder: folder,
79
91
  isRoot: isRoot,
80
92
  isUnavailable: isUnavailable,
81
- isLast: !showSourceChips,
82
93
  onChangeFolder: setKnowledgeBaseFolder
83
- }) : /*#__PURE__*/_react.default.createElement(_TwakeKnowledgeChip.default, {
84
- twakeKnowledge: {
85
- id: 'drive',
86
- label: t('assistant.twake_knowledges.drive'),
87
- icon: _tdrive.default
88
- },
89
- isSelected: true,
90
- isLast: !showSourceChips
91
- }), showSourceChips && twakeKnowledges.map(function (twakeKnowledge, index) {
92
- return /*#__PURE__*/_react.default.createElement(_TwakeKnowledgeChip.default, {
93
- key: twakeKnowledge.id,
94
- twakeKnowledge: twakeKnowledge,
95
- isSelected: twakeKnowledge.isSelected,
96
- onToggle: twakeKnowledge.onToggle,
97
- isLast: index === twakeKnowledges.length - 1
98
- });
94
+ }) : isMobile ? /*#__PURE__*/_react.default.createElement(_SourceButton.default, {
95
+ icon: _twakeIcons.Drive,
96
+ preserveColor: true,
97
+ label: t('assistant.twake_knowledges.drive')
98
+ }) : /*#__PURE__*/_react.default.createElement(_Chips.default, {
99
+ icon: /*#__PURE__*/_react.default.createElement(_twakeIcons.Icon, {
100
+ icon: _twakeIcons.Drive,
101
+ size: 16,
102
+ preserveColor: true
103
+ }),
104
+ label: t('assistant.twake_knowledges.drive'),
105
+ className: styles['source-chip'],
106
+ classes: _SourceButton.CHIP_CLASSES
107
+ });
108
+ return /*#__PURE__*/_react.default.createElement("div", {
109
+ role: "group",
110
+ "aria-label": t('assistant.twake_knowledges.search_in'),
111
+ className: (0, _classnames.default)('u-flex u-flex-items-center', className)
112
+ }, driveSource, websearchEnabledFlag && /*#__PURE__*/_react.default.createElement(_SourceButton.default, {
113
+ icon: _twakeIcons.Globe,
114
+ label: t('assistant.websearch.label'),
115
+ isActive: websearchEnabled,
116
+ "aria-pressed": websearchEnabled,
117
+ onClick: handleToggleWebsearch,
118
+ className: "u-ml-half"
119
+ }), showMail && /*#__PURE__*/_react.default.createElement(_SourceButton.default, {
120
+ icon: _twakeIcons.Mail,
121
+ preserveColor: true,
122
+ label: t('assistant.twake_knowledges.mail'),
123
+ className: "u-ml-half"
99
124
  }));
100
125
  };
101
126
 
@@ -1,4 +1,31 @@
1
- .knowledge-chips-icon
2
- height 16px
1
+ .source-button
2
+ width 32px
3
+ height 32px
4
+ padding 0 !important
5
+ border-radius 100px
6
+
7
+ .source-button-image
8
+ width 20px
9
+ height 20px
10
+
11
+ &--inactive
12
+ opacity 0.6
13
+
14
+ .source-chip
15
+ // The chip of the design: 32px, 12px padding, icon 16px, 4px before the
16
+ // 12px medium label
17
+ height 32px !important
18
+ border-radius 100px !important
19
+ padding 0 12px !important
20
+
21
+ .source-chip-icon
3
22
  width 16px
23
+ height 16px
4
24
  margin 0 !important
25
+
26
+ .source-chip-label
27
+ padding 0 0 0 4px !important
28
+ font-size 12px
29
+ font-weight 500
30
+ line-height 16px
31
+ letter-spacing 0.5px
@@ -15,6 +15,8 @@ var _Breakpoints = require("cozy-ui/transpiled/react/providers/Breakpoints");
15
15
 
16
16
  var _CozyTheme = _interopRequireDefault(require("cozy-ui-plus/dist/providers/CozyTheme"));
17
17
 
18
+ var _twakeI18n = require("twake-i18n");
19
+
18
20
  var _AssistantProvider = _interopRequireWildcard(require("../AssistantProvider"));
19
21
 
20
22
  var _CreateAssistantDialog = _interopRequireDefault(require("./CreateAssistantDialog"));
@@ -23,6 +25,8 @@ var _DeleteAssistantDialog = _interopRequireDefault(require("./DeleteAssistantDi
23
25
 
24
26
  var _EditAssistantDialog = _interopRequireDefault(require("./EditAssistantDialog"));
25
27
 
28
+ var _locales = require("../../locales");
29
+
26
30
  var _AssistantContainer = _interopRequireDefault(require("../Assistant/AssistantContainer"));
27
31
 
28
32
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
@@ -39,6 +43,10 @@ var styles = {
39
43
  };
40
44
 
41
45
  var AssistantView = function AssistantView() {
46
+ // The view is mounted by the app on its own route, without the search
47
+ // bar that otherwise registers the translations of this package.
48
+ (0, _twakeI18n.useExtendI18n)(_locales.locales);
49
+
42
50
  var _useAssistant = (0, _AssistantProvider.useAssistant)(),
43
51
  isOpenCreateAssistant = _useAssistant.isOpenCreateAssistant,
44
52
  setIsOpenCreateAssistant = _useAssistant.setIsOpenCreateAssistant,
@@ -52,7 +60,7 @@ var AssistantView = function AssistantView() {
52
60
 
53
61
  return /*#__PURE__*/_react.default.createElement("div", {
54
62
  className: (0, _classnames.default)('u-w-100 u-flex u-flex-column u-ov-hidden', styles['assistantWrapper'], {
55
- 'u-ph-1-t u-pb-1-t u-bxz': isMobile
63
+ 'u-pb-1-t u-bxz': isMobile
56
64
  })
57
65
  }, /*#__PURE__*/_react.default.createElement(_AssistantContainer.default, null), /*#__PURE__*/_react.default.createElement("div", {
58
66
  className: "u-w-100"
@@ -52,6 +52,7 @@ var styles = {
52
52
  "avatar-container": "styles__avatar-container___kJ_64",
53
53
  "avatar-image": "styles__avatar-image___2Mkxj",
54
54
  "file-input": "styles__file-input___2fB5n",
55
+ "avatar-tooltip": "styles__avatar-tooltip___1o6_5",
55
56
  "ModelSelectionStep": "styles__ModelSelectionStep___1auXB",
56
57
  "grid-container": "styles__grid-container___3wOus",
57
58
  "grid-container--mobile": "styles__grid-container--mobile___uCAg1",
@@ -170,7 +171,10 @@ var CreateAssistantDialog = function CreateAssistantDialog(_ref) {
170
171
  return /*#__PURE__*/_react.default.createElement(_Dialog.default, {
171
172
  open: open,
172
173
  onClose: onClose,
173
- maxWidth: "lg",
174
+ maxWidth: "md",
175
+ classes: {
176
+ paper: 'large'
177
+ },
174
178
  fullScreen: !!isMobile,
175
179
  className: styles.CreateAssistantDialog
176
180
  }, /*#__PURE__*/_react.default.createElement(_Dialog.DialogTitle, {
@@ -46,6 +46,7 @@ var styles = {
46
46
  "avatar-container": "styles__avatar-container___kJ_64",
47
47
  "avatar-image": "styles__avatar-image___2Mkxj",
48
48
  "file-input": "styles__file-input___2fB5n",
49
+ "avatar-tooltip": "styles__avatar-tooltip___1o6_5",
49
50
  "ModelSelectionStep": "styles__ModelSelectionStep___1auXB",
50
51
  "grid-container": "styles__grid-container___3wOus",
51
52
  "grid-container--mobile": "styles__grid-container--mobile___uCAg1",
@@ -60,6 +60,7 @@ var styles = {
60
60
  "avatar-container": "styles__avatar-container___kJ_64",
61
61
  "avatar-image": "styles__avatar-image___2Mkxj",
62
62
  "file-input": "styles__file-input___2fB5n",
63
+ "avatar-tooltip": "styles__avatar-tooltip___1o6_5",
63
64
  "ModelSelectionStep": "styles__ModelSelectionStep___1auXB",
64
65
  "grid-container": "styles__grid-container___3wOus",
65
66
  "grid-container--mobile": "styles__grid-container--mobile___uCAg1",
@@ -227,7 +228,10 @@ var EditAssistantDialog = function EditAssistantDialog(_ref) {
227
228
  return /*#__PURE__*/_react.default.createElement(_Dialog.default, {
228
229
  open: open,
229
230
  onClose: onClose,
230
- maxWidth: "lg",
231
+ maxWidth: "md",
232
+ classes: {
233
+ paper: 'large'
234
+ },
231
235
  fullScreen: !!isMobile,
232
236
  className: styles.CreateAssistantDialog
233
237
  }, /*#__PURE__*/_react.default.createElement(_Dialog.DialogTitle, {
@@ -1,5 +1,5 @@
1
1
  export default useConversation;
2
2
  declare function useConversation(): {
3
- goToConversation: (conversationId: any) => void;
4
- createNewConversation: () => void;
3
+ goToConversation: (conversationId: any, { assistantId }?: any) => void;
4
+ createNewConversation: (assistantId: any) => void;
5
5
  };
@@ -31,23 +31,44 @@ var useConversation = function useConversation() {
31
31
  navigateRef.current = navigate;
32
32
  locationRef.current = location;
33
33
  }, [navigate, location]);
34
+ /**
35
+ * Opens a conversation. `assistantId` is the assistant a new conversation
36
+ * starts on, carried in the history state: without it, a new conversation
37
+ * starts on the configured default.
38
+ */
39
+
34
40
  var goToConversation = (0, _react.useCallback)(function (conversationId) {
35
41
  var _match$;
36
42
 
43
+ var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
44
+ assistantId = _ref.assistantId;
45
+
37
46
  var loc = locationRef.current; // Extract base path safely by identifying the start of '/assistant' if it exists.
38
47
 
39
48
  var match = loc.pathname.match(/^(.*?)(\/assistant(\/|$).*|$)/);
40
49
  var basePath = ((_match$ = match === null || match === void 0 ? void 0 : match[1]) !== null && _match$ !== void 0 ? _match$ : loc.pathname).replace(/\/$/, '');
41
50
  var newPathname = "".concat(basePath, "/assistant/").concat(conversationId);
42
51
  setIsOpenSearchConversation(false);
43
- navigateRef.current({
52
+ var to = {
44
53
  pathname: newPathname,
45
54
  search: loc.search,
46
55
  hash: loc.hash
47
- });
56
+ };
57
+
58
+ if (assistantId) {
59
+ navigateRef.current(to, {
60
+ state: {
61
+ assistantId: assistantId
62
+ }
63
+ });
64
+ } else {
65
+ navigateRef.current(to);
66
+ }
48
67
  }, [setIsOpenSearchConversation]);
49
- var createNewConversation = (0, _react.useCallback)(function () {
50
- goToConversation((0, _helpers.makeConversationId)());
68
+ var createNewConversation = (0, _react.useCallback)(function (assistantId) {
69
+ goToConversation((0, _helpers.makeConversationId)(), {
70
+ assistantId: typeof assistantId === 'string' ? assistantId : undefined
71
+ });
51
72
  }, [goToConversation]);
52
73
  return {
53
74
  goToConversation: goToConversation,
@@ -13,6 +13,7 @@ jest.mock('../components/AssistantProvider');
13
13
  jest.mock('../components/helpers');
14
14
  // Set up mock implementations
15
15
  import * as routerModule from 'react-router-dom';
16
+ import useConversation from './useConversation';
16
17
  import * as assistantModule from '../components/AssistantProvider';
17
18
  import * as helpersModule from '../components/helpers';
18
19
  routerModule.useNavigate.mockImplementation(() => mockNavigate);
@@ -21,8 +22,6 @@ assistantModule.useAssistant.mockImplementation(() => ({
21
22
  setIsOpenSearchConversation: mockSetIsOpenSearchConversation
22
23
  }));
23
24
  helpersModule.makeConversationId.mockImplementation(() => 'mock-id-123');
24
- // Now import the hook after setting up mocks
25
- import useConversation from './useConversation';
26
25
  describe('useConversation', () => {
27
26
  beforeEach(() => {
28
27
  jest.clearAllMocks();
@@ -119,5 +118,18 @@ describe('useConversation', () => {
119
118
  hash: ''
120
119
  });
121
120
  });
121
+ it('carries the picked assistant in the history state', () => {
122
+ mockLocation.pathname = '/docs';
123
+ routerModule.useLocation.mockImplementation(() => mockLocation);
124
+ const { result } = renderHook(() => useConversation());
125
+ act(() => {
126
+ result.current.createNewConversation('meeting');
127
+ });
128
+ expect(mockNavigate).toHaveBeenCalledWith({
129
+ pathname: '/docs/assistant/mock-id-123',
130
+ search: '',
131
+ hash: ''
132
+ }, { state: { assistantId: 'meeting' } });
133
+ });
122
134
  });
123
135
  });
@@ -17,6 +17,8 @@ jest.mock('../components/helpers')
17
17
 
18
18
  // Set up mock implementations
19
19
  import * as routerModule from 'react-router-dom'
20
+
21
+ import useConversation from './useConversation'
20
22
  import * as assistantModule from '../components/AssistantProvider'
21
23
  import * as helpersModule from '../components/helpers'
22
24
 
@@ -27,9 +29,6 @@ assistantModule.useAssistant.mockImplementation(() => ({
27
29
  }))
28
30
  helpersModule.makeConversationId.mockImplementation(() => 'mock-id-123')
29
31
 
30
- // Now import the hook after setting up mocks
31
- import useConversation from './useConversation'
32
-
33
32
  describe('useConversation', () => {
34
33
  beforeEach(() => {
35
34
  jest.clearAllMocks()
@@ -144,5 +143,24 @@ describe('useConversation', () => {
144
143
  hash: ''
145
144
  })
146
145
  })
146
+
147
+ it('carries the picked assistant in the history state', () => {
148
+ mockLocation.pathname = '/docs'
149
+ routerModule.useLocation.mockImplementation(() => mockLocation)
150
+ const { result } = renderHook(() => useConversation())
151
+
152
+ act(() => {
153
+ result.current.createNewConversation('meeting')
154
+ })
155
+
156
+ expect(mockNavigate).toHaveBeenCalledWith(
157
+ {
158
+ pathname: '/docs/assistant/mock-id-123',
159
+ search: '',
160
+ hash: ''
161
+ },
162
+ { state: { assistantId: 'meeting' } }
163
+ )
164
+ })
147
165
  })
148
166
  })
@@ -28,10 +28,11 @@
28
28
  "edited": "Message saved"
29
29
  },
30
30
  "sidebar": {
31
- "create_new": "Create",
31
+ "create_new": "New chat",
32
32
  "toggle_sidebar": "Toggle sidebar",
33
33
  "toggle_search": "Toggle search",
34
34
  "close_sidebar": "Close sidebar",
35
+ "assistant": "Assistant",
35
36
  "recent_chats": "Recent",
36
37
  "conversation": {
37
38
  "actions": {
@@ -47,6 +48,7 @@
47
48
  "yesterday": "Yesterday"
48
49
  },
49
50
  "default_error": "An error occurred during response generation. Please try again",
51
+ "disclaimer": "Twake AI can make mistakes. Please verify important information.",
50
52
  "default_empty_response": "I could not find an answer to your request. Please try rephrasing it",
51
53
  "hide": "Hide",
52
54
  "show": "Show",
@@ -70,6 +72,7 @@
70
72
  },
71
73
  "knowledge_base": {
72
74
  "change_folder": "Change folder…",
75
+ "folder_hint": "The assistant can access all the files stored in this Drive folder",
73
76
  "emails": "Emails",
74
77
  "open_folder": "Open in Drive",
75
78
  "picker_error": "Unable to open the Drive folder picker. Please try again.",
@@ -85,6 +88,7 @@
85
88
  "basic_info": {
86
89
  "description": "Customize your agent. Choose its knowledge base, then its AI model.",
87
90
  "avatar": "Avatar (optional)",
91
+ "upload_photo": "Upload a photo",
88
92
  "name": "Name",
89
93
  "name_placeholder": "Name your agent",
90
94
  "description_label": "Description",
@@ -28,11 +28,12 @@
28
28
  "edited": "Message enregistré"
29
29
  },
30
30
  "sidebar": {
31
- "create_new": "Créer",
31
+ "create_new": "Nouveau chat",
32
32
  "toggle_sidebar": "Basculer la barre latérale",
33
33
  "toggle_search": "Basculer la recherche",
34
34
  "close_sidebar": "Fermer la barre latérale",
35
- "recent_chats": "Récent",
35
+ "assistant": "Assistant",
36
+ "recent_chats": "Récents",
36
37
  "conversation": {
37
38
  "actions": {
38
39
  "delete": "Supprimer",
@@ -47,6 +48,7 @@
47
48
  "yesterday": "Hier"
48
49
  },
49
50
  "default_error": "Une erreur est survenue lors de la génération de la réponse. Veuillez réessayer",
51
+ "disclaimer": "Twake AI peut faire des erreurs. Vérifiez les informations importantes.",
50
52
  "default_empty_response": "Je n'ai pas trouvé de réponse à votre demande. Essayez de reformuler votre question",
51
53
  "hide": "Masquer",
52
54
  "show": "Afficher",
@@ -70,6 +72,7 @@
70
72
  },
71
73
  "knowledge_base": {
72
74
  "change_folder": "Modifier le dossier…",
75
+ "folder_hint": "L'assistant peut accéder à tous les fichiers stockés dans ce dossier Drive",
73
76
  "emails": "Emails",
74
77
  "open_folder": "Ouvrir dans Drive",
75
78
  "picker_error": "Impossible d'ouvrir le sélecteur de dossier Drive. Veuillez réessayer.",
@@ -85,6 +88,7 @@
85
88
  "basic_info": {
86
89
  "description": "Personnalisez votre agent. Choisissez la base de connaissances, puis son modèle d'IA.",
87
90
  "avatar": "Avatar (optionnel)",
91
+ "upload_photo": "Importer une photo",
88
92
  "name": "Nom",
89
93
  "name_placeholder": "Nommez votre agent",
90
94
  "description_label": "Description",
@@ -34,10 +34,11 @@ var en = {
34
34
  edited: "Message saved"
35
35
  },
36
36
  sidebar: {
37
- create_new: "Create",
37
+ create_new: "New chat",
38
38
  toggle_sidebar: "Toggle sidebar",
39
39
  toggle_search: "Toggle search",
40
40
  close_sidebar: "Close sidebar",
41
+ assistant: "Assistant",
41
42
  recent_chats: "Recent",
42
43
  conversation: {
43
44
  actions: {
@@ -53,6 +54,7 @@ var en = {
53
54
  yesterday: "Yesterday"
54
55
  },
55
56
  default_error: "An error occurred during response generation. Please try again",
57
+ disclaimer: "Twake AI can make mistakes. Please verify important information.",
56
58
  default_empty_response: "I could not find an answer to your request. Please try rephrasing it",
57
59
  hide: "Hide",
58
60
  show: "Show",
@@ -76,6 +78,7 @@ var en = {
76
78
  },
77
79
  knowledge_base: {
78
80
  change_folder: "Change folder\u2026",
81
+ folder_hint: "The assistant can access all the files stored in this Drive folder",
79
82
  emails: "Emails",
80
83
  open_folder: "Open in Drive",
81
84
  picker_error: "Unable to open the Drive folder picker. Please try again.",
@@ -91,6 +94,7 @@ var en = {
91
94
  basic_info: {
92
95
  description: "Customize your agent. Choose its knowledge base, then its AI model.",
93
96
  avatar: "Avatar (optional)",
97
+ upload_photo: "Upload a photo",
94
98
  name: "Name",
95
99
  name_placeholder: "Name your agent",
96
100
  description_label: "Description",
@@ -218,11 +222,12 @@ var fr = {
218
222
  edited: "Message enregistr\xE9"
219
223
  },
220
224
  sidebar: {
221
- create_new: "Cr\xE9er",
225
+ create_new: "Nouveau chat",
222
226
  toggle_sidebar: "Basculer la barre lat\xE9rale",
223
227
  toggle_search: "Basculer la recherche",
224
228
  close_sidebar: "Fermer la barre lat\xE9rale",
225
- recent_chats: "R\xE9cent",
229
+ assistant: "Assistant",
230
+ recent_chats: "R\xE9cents",
226
231
  conversation: {
227
232
  actions: {
228
233
  "delete": "Supprimer",
@@ -237,6 +242,7 @@ var fr = {
237
242
  yesterday: "Hier"
238
243
  },
239
244
  default_error: "Une erreur est survenue lors de la g\xE9n\xE9ration de la r\xE9ponse. Veuillez r\xE9essayer",
245
+ disclaimer: "Twake AI peut faire des erreurs. V\xE9rifiez les informations importantes.",
240
246
  default_empty_response: "Je n'ai pas trouv\xE9 de r\xE9ponse \xE0 votre demande. Essayez de reformuler votre question",
241
247
  hide: "Masquer",
242
248
  show: "Afficher",
@@ -260,6 +266,7 @@ var fr = {
260
266
  },
261
267
  knowledge_base: {
262
268
  change_folder: "Modifier le dossier\u2026",
269
+ folder_hint: "L'assistant peut acc\xE9der \xE0 tous les fichiers stock\xE9s dans ce dossier Drive",
263
270
  emails: "Emails",
264
271
  open_folder: "Ouvrir dans Drive",
265
272
  picker_error: "Impossible d'ouvrir le s\xE9lecteur de dossier Drive. Veuillez r\xE9essayer.",
@@ -275,6 +282,7 @@ var fr = {
275
282
  basic_info: {
276
283
  description: "Personnalisez votre agent. Choisissez la base de connaissances, puis son mod\xE8le d'IA.",
277
284
  avatar: "Avatar (optionnel)",
285
+ upload_photo: "Importer une photo",
278
286
  name: "Nom",
279
287
  name_placeholder: "Nommez votre agent",
280
288
  description_label: "Description",
@@ -392,10 +400,11 @@ var ru = {
392
400
  reorganise_files: "\u0420\u0435\u043E\u0440\u0433\u0430\u043D\u0438\u0437\u043E\u0432\u0430\u0442\u044C \u043C\u043E\u0438 \u0444\u0430\u0439\u043B\u044B"
393
401
  },
394
402
  sidebar: {
395
- create_new: "\u0421\u043E\u0437\u0434\u0430\u0442\u044C",
403
+ create_new: "\u041D\u043E\u0432\u044B\u0439 \u0447\u0430\u0442",
396
404
  toggle_sidebar: "\u041F\u0435\u0440\u0435\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u0431\u043E\u043A\u043E\u0432\u0443\u044E \u043F\u0430\u043D\u0435\u043B\u044C",
397
405
  toggle_search: "\u041F\u0435\u0440\u0435\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u043F\u043E\u0438\u0441\u043A",
398
406
  close_sidebar: "\u0417\u0430\u043A\u0440\u044B\u0442\u044C \u0431\u043E\u043A\u043E\u0432\u0443\u044E \u043F\u0430\u043D\u0435\u043B\u044C",
407
+ assistant: "\u0410\u0441\u0441\u0438\u0441\u0442\u0435\u043D\u0442",
399
408
  recent_chats: "\u041D\u0435\u0434\u0430\u0432\u043D\u0438\u0435",
400
409
  conversation: {
401
410
  actions: {
@@ -411,6 +420,7 @@ var ru = {
411
420
  yesterday: "\u0412\u0447\u0435\u0440\u0430"
412
421
  },
413
422
  default_error: "\u041F\u0440\u043E\u0438\u0437\u043E\u0448\u043B\u0430 \u043E\u0448\u0438\u0431\u043A\u0430, \u043F\u043E\u043F\u0440\u043E\u0431\u0443\u0439\u0442\u0435 \u0441\u043D\u043E\u0432\u0430",
423
+ disclaimer: "Twake AI \u043C\u043E\u0436\u0435\u0442 \u043E\u0448\u0438\u0431\u0430\u0442\u044C\u0441\u044F. \u041F\u0440\u043E\u0432\u0435\u0440\u044F\u0439\u0442\u0435 \u0432\u0430\u0436\u043D\u0443\u044E \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044E.",
414
424
  default_empty_response: "\u042F \u043D\u0435 \u0441\u043C\u043E\u0433 \u043D\u0430\u0439\u0442\u0438 \u043E\u0442\u0432\u0435\u0442 \u043D\u0430 \u0432\u0430\u0448 \u0437\u0430\u043F\u0440\u043E\u0441. \u041F\u043E\u043F\u0440\u043E\u0431\u0443\u0439\u0442\u0435 \u043F\u0435\u0440\u0435\u0444\u043E\u0440\u043C\u0443\u043B\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0432\u043E\u043F\u0440\u043E\u0441",
415
425
  hide: "\u0421\u043A\u0440\u044B\u0442\u044C",
416
426
  show: "\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C",
@@ -458,6 +468,7 @@ var ru = {
458
468
  },
459
469
  knowledge_base: {
460
470
  change_folder: "\u0418\u0437\u043C\u0435\u043D\u0438\u0442\u044C \u043F\u0430\u043F\u043A\u0443\u2026",
471
+ folder_hint: "\u0410\u0441\u0441\u0438\u0441\u0442\u0435\u043D\u0442 \u0438\u043C\u0435\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F \u043A\u043E \u0432\u0441\u0435\u043C \u0444\u0430\u0439\u043B\u0430\u043C, \u0445\u0440\u0430\u043D\u044F\u0449\u0438\u043C\u0441\u044F \u0432 \u044D\u0442\u043E\u0439 \u043F\u0430\u043F\u043A\u0435 Drive",
461
472
  emails: "\u041F\u0438\u0441\u044C\u043C\u0430",
462
473
  open_folder: "\u041E\u0442\u043A\u0440\u044B\u0442\u044C \u0432 Drive",
463
474
  picker_error: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043E\u0442\u043A\u0440\u044B\u0442\u044C \u0432\u044B\u0431\u043E\u0440 \u043F\u0430\u043F\u043A\u0438 Drive. \u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u043F\u043E\u043F\u0440\u043E\u0431\u0443\u0439\u0442\u0435 \u0435\u0449\u0451 \u0440\u0430\u0437.",
@@ -476,6 +487,7 @@ var ru = {
476
487
  basic_info: {
477
488
  description: "\u041D\u0430\u0441\u0442\u0440\u043E\u0439\u0442\u0435 \u0432\u0430\u0448\u0435\u0433\u043E \u0430\u0433\u0435\u043D\u0442\u0430. \u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0431\u0430\u0437\u0443 \u0437\u043D\u0430\u043D\u0438\u0439, \u0437\u0430\u0442\u0435\u043C \u043C\u043E\u0434\u0435\u043B\u044C \u0418\u0418.",
478
489
  avatar: "\u0410\u0432\u0430\u0442\u0430\u0440 (\u043D\u0435\u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E)",
490
+ upload_photo: "\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u0444\u043E\u0442\u043E",
479
491
  name: "\u0418\u043C\u044F",
480
492
  name_placeholder: "\u041D\u0430\u0437\u043E\u0432\u0438\u0442\u0435 \u0432\u0430\u0448\u0435\u0433\u043E \u0430\u0433\u0435\u043D\u0442\u0430",
481
493
  description_label: "\u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435",
@@ -600,10 +612,11 @@ var vi = {
600
612
  edited: "\u0110\xE3 l\u01B0u tin nh\u1EAFn"
601
613
  },
602
614
  sidebar: {
603
- create_new: "T\u1EA1o m\u1EDBi",
615
+ create_new: "Cu\u1ED9c tr\xF2 chuy\u1EC7n m\u1EDBi",
604
616
  toggle_sidebar: "B\u1EADt/t\u1EAFt thanh b\xEAn",
605
617
  toggle_search: "B\u1EADt/t\u1EAFt t\xECm ki\u1EBFm",
606
618
  close_sidebar: "\u0110\xF3ng thanh b\xEAn",
619
+ assistant: "Tr\u1EE3 l\xFD",
607
620
  recent_chats: "G\u1EA7n \u0111\xE2y",
608
621
  conversation: {
609
622
  actions: {
@@ -619,6 +632,7 @@ var vi = {
619
632
  yesterday: "H\xF4m qua"
620
633
  },
621
634
  default_error: "\u0110\xE3 x\u1EA3y ra l\u1ED7i, vui l\xF2ng th\u1EED l\u1EA1i",
635
+ disclaimer: "Twake AI c\xF3 th\u1EC3 m\u1EAFc l\u1ED7i. H\xE3y ki\u1EC3m tra l\u1EA1i c\xE1c th\xF4ng tin quan tr\u1ECDng.",
622
636
  default_empty_response: "T\xF4i kh\xF4ng t\xECm th\u1EA5y c\xE2u tr\u1EA3 l\u1EDDi cho y\xEAu c\u1EA7u c\u1EE7a b\u1EA1n. Vui l\xF2ng th\u1EED di\u1EC5n \u0111\u1EA1t l\u1EA1i",
623
637
  hide: "\u1EA8n",
624
638
  show: "Hi\u1EC7n",
@@ -659,6 +673,7 @@ var vi = {
659
673
  },
660
674
  knowledge_base: {
661
675
  change_folder: "Thay \u0111\u1ED5i th\u01B0 m\u1EE5c\u2026",
676
+ folder_hint: "Tr\u1EE3 l\xFD c\xF3 th\u1EC3 truy c\u1EADp t\u1EA5t c\u1EA3 c\xE1c t\u1EC7p \u0111\u01B0\u1EE3c l\u01B0u trong th\u01B0 m\u1EE5c Drive n\xE0y",
662
677
  emails: "Email",
663
678
  open_folder: "M\u1EDF trong Drive",
664
679
  picker_error: "Kh\xF4ng th\u1EC3 m\u1EDF b\u1ED9 ch\u1ECDn th\u01B0 m\u1EE5c Drive. Vui l\xF2ng th\u1EED l\u1EA1i.",
@@ -677,6 +692,7 @@ var vi = {
677
692
  basic_info: {
678
693
  description: "T\xF9y ch\u1EC9nh t\xE1c nh\xE2n c\u1EE7a b\u1EA1n. Ch\u1ECDn c\u01A1 s\u1EDF tri th\u1EE9c, sau \u0111\xF3 l\xE0 m\xF4 h\xECnh AI.",
679
694
  avatar: "\u1EA2nh \u0111\u1EA1i di\u1EC7n (t\xF9y ch\u1ECDn)",
695
+ upload_photo: "T\u1EA3i \u1EA3nh l\xEAn",
680
696
  name: "T\xEAn",
681
697
  name_placeholder: "\u0110\u1EB7t t\xEAn cho t\xE1c nh\xE2n c\u1EE7a b\u1EA1n",
682
698
  description_label: "M\xF4 t\u1EA3",