tycho-components 0.46.5 → 0.47.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.
@@ -7,6 +7,7 @@ export declare const HeaderTexts: {
7
7
  'label.choose': string;
8
8
  'tooltip.keyboard': string;
9
9
  'tooltip.tutorials': string;
10
+ 'tooltip.assistant': string;
10
11
  'replace.all.tooltip': string;
11
12
  'replace.find.placeholder': string;
12
13
  'replace.placeholder': string;
@@ -29,6 +30,7 @@ export declare const HeaderTexts: {
29
30
  'label.choose': string;
30
31
  'tooltip.keyboard': string;
31
32
  'tooltip.tutorials': string;
33
+ 'tooltip.assistant': string;
32
34
  'replace.all.tooltip': string;
33
35
  'replace.find.placeholder': string;
34
36
  'replace.placeholder': string;
@@ -51,6 +53,7 @@ export declare const HeaderTexts: {
51
53
  'label.choose': string;
52
54
  'tooltip.keyboard': string;
53
55
  'tooltip.tutorials': string;
56
+ 'tooltip.assistant': string;
54
57
  'replace.all.tooltip': string;
55
58
  'replace.find.placeholder': string;
56
59
  'replace.placeholder': string;
@@ -7,6 +7,7 @@ export const HeaderTexts = {
7
7
  'label.choose': 'Choose a corpus',
8
8
  'tooltip.keyboard': 'Open Virtual Keyboard',
9
9
  'tooltip.tutorials': 'Views Tutorials',
10
+ 'tooltip.assistant': 'Ask the CorpusHub assistant',
10
11
  'replace.all.tooltip': 'Replace All',
11
12
  'replace.find.placeholder': 'Find',
12
13
  'replace.placeholder': 'Replace',
@@ -29,6 +30,7 @@ export const HeaderTexts = {
29
30
  'label.choose': 'Escolha um corpus',
30
31
  'tooltip.keyboard': 'Abrir Teclado Virtual',
31
32
  'tooltip.tutorials': 'Ver tutoriais',
33
+ 'tooltip.assistant': 'Perguntar ao assistente CorpusHub',
32
34
  'replace.all.tooltip': 'Substituir Todos',
33
35
  'replace.find.placeholder': 'Procurar',
34
36
  'replace.placeholder': 'Substituir',
@@ -51,6 +53,7 @@ export const HeaderTexts = {
51
53
  'label.choose': 'Scegli un corpus',
52
54
  'tooltip.keyboard': 'Apri tastiera virtuale',
53
55
  'tooltip.tutorials': 'Visualizza i tutorial',
56
+ 'tooltip.assistant': "Chiedi all'assistente CorpusHub",
54
57
  'replace.all.tooltip': 'Sostituisci tutto',
55
58
  'replace.find.placeholder': 'Trova',
56
59
  'replace.placeholder': 'Sostituisci',
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export * from './common';
2
2
  export * from './shell';
3
3
  export { default as HelpButton } from './shell/Header/HelpButton';
4
4
  export type { HelpAction } from './shell/Header/HelpButton/HelpButton';
5
+ export { loadHelpAssistant, openHelpAssistant, isHelpAssistantEnabled, } from './shell/Header/HelpButton/helpAssistant';
5
6
  export * from './configs';
6
7
  export * from './functions';
7
8
  export * from './features';
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './common';
2
2
  export * from './shell';
3
3
  export { default as HelpButton } from './shell/Header/HelpButton';
4
+ export { loadHelpAssistant, openHelpAssistant, isHelpAssistantEnabled, } from './shell/Header/HelpButton/helpAssistant';
4
5
  export * from './configs';
5
6
  export * from './functions';
6
7
  export * from './features';
@@ -3,7 +3,8 @@ import { HelpAction } from '../HelpButton/HelpButton';
3
3
  type Props = {
4
4
  navigateLogout?: () => void;
5
5
  navigateNotLogged: () => void;
6
+ /** @deprecated ignored — the help entry opens the CorpusHub assistant */
6
7
  helpActions?: HelpAction[];
7
8
  };
8
- export default function HeaderUser({ navigateLogout, navigateNotLogged, helpActions, }: Props): import("react").JSX.Element;
9
+ export default function HeaderUser({ navigateLogout, navigateNotLogged, }: Props): import("react").JSX.Element;
9
10
  export {};
@@ -6,12 +6,11 @@ import { useLoggedUtils } from '../../../configs/useLoggedUtils';
6
6
  import UsabilityUtils from '../../../functions/UsabilityUtils';
7
7
  import LanguageSelector from '../../LanguageSelector';
8
8
  import './style.scss';
9
- import HelpModal from '../HelpButton/HelpModal';
10
- export default function HeaderUser({ navigateLogout, navigateNotLogged, helpActions, }) {
9
+ import { isHelpAssistantEnabled, openHelpAssistant, } from '../HelpButton/helpAssistant';
10
+ export default function HeaderUser({ navigateLogout, navigateNotLogged, }) {
11
11
  const { t } = useTranslation('header');
12
12
  const { isLogged, getLogged } = useLoggedUtils();
13
13
  const [open, setOpen] = useState(false);
14
- const [openHelp, setOpenHelp] = useState(false);
15
14
  useEffect(() => {
16
15
  if (!open)
17
16
  return;
@@ -21,8 +20,11 @@ export default function HeaderUser({ navigateLogout, navigateNotLogged, helpActi
21
20
  setOpen(false);
22
21
  window.open(import.meta.env.VITE_APP_RESERVED_URL, '_blank');
23
22
  };
24
- return (_jsxs("div", { className: "profile-container", "data-tour": "header-user", children: [isLogged() ? (_jsx("div", { onClick: () => setOpen(!open), children: _jsx(Avatar, { size: "small", src: getLogged()?.picture, title: getLogged()?.name || getLogged()?.sub }) })) : (_jsx(Button, { text: t('button.sign.in'), size: "small", onClick: navigateNotLogged })), open && isLogged() && (_jsxs("div", { className: "ds-dropdown-list", children: [_jsx("div", { className: "ds-dropdown-itemlist", children: _jsx("span", { className: "label", children: `${t('profile.label.hello')} ${getLogged()?.name || getLogged()?.sub}` }) }), _jsxs("div", { className: "ds-dropdown-itemlist d-none", children: [_jsx(Icon, { name: "colors", size: "x-small" }), _jsx("span", { className: "label", children: t('profile.label.theme') })] }), _jsxs("div", { className: "ds-dropdown-itemlist", onClick: handleProfile, children: [_jsx(Icon, { name: "person", size: "x-small" }), _jsx("span", { className: "label", children: t('profile.label.home') })] }), _jsx(LanguageSelector, { renderMode: "profile-menu", itemLabel: t('profile.label.language') }), _jsxs("div", { className: "ds-dropdown-itemlist", onClick: () => setOpenHelp(true), children: [_jsx(Icon, { name: "live_help", size: "x-small" }), _jsx("span", { className: "label", children: t('profile.label.help') })] }), _jsxs("div", { className: "ds-dropdown-itemlist", onClick: () => {
23
+ return (_jsxs("div", { className: "profile-container", "data-tour": "header-user", children: [isLogged() ? (_jsx("div", { onClick: () => setOpen(!open), children: _jsx(Avatar, { size: "small", src: getLogged()?.picture, title: getLogged()?.name || getLogged()?.sub }) })) : (_jsx(Button, { text: t('button.sign.in'), size: "small", onClick: navigateNotLogged })), open && isLogged() && (_jsxs("div", { className: "ds-dropdown-list", children: [_jsx("div", { className: "ds-dropdown-itemlist", children: _jsx("span", { className: "label", children: `${t('profile.label.hello')} ${getLogged()?.name || getLogged()?.sub}` }) }), _jsxs("div", { className: "ds-dropdown-itemlist d-none", children: [_jsx(Icon, { name: "colors", size: "x-small" }), _jsx("span", { className: "label", children: t('profile.label.theme') })] }), _jsxs("div", { className: "ds-dropdown-itemlist", onClick: handleProfile, children: [_jsx(Icon, { name: "person", size: "x-small" }), _jsx("span", { className: "label", children: t('profile.label.home') })] }), _jsx(LanguageSelector, { renderMode: "profile-menu", itemLabel: t('profile.label.language') }), isHelpAssistantEnabled() && (_jsxs("div", { className: "ds-dropdown-itemlist", onClick: () => {
24
+ setOpen(false);
25
+ openHelpAssistant();
26
+ }, children: [_jsx(Icon, { name: "live_help", size: "x-small" }), _jsx("span", { className: "label", children: t('profile.label.help') })] })), _jsxs("div", { className: "ds-dropdown-itemlist", onClick: () => {
25
27
  setOpen(false);
26
28
  navigateLogout && navigateLogout();
27
- }, children: [_jsx(Icon, { name: "logout", size: "x-small" }), _jsx("span", { className: "label", children: t('profile.label.logout') })] })] })), openHelp && (_jsx(HelpModal, { onClose: () => setOpenHelp(false), helpActions: helpActions }))] }));
29
+ }, children: [_jsx(Icon, { name: "logout", size: "x-small" }), _jsx("span", { className: "label", children: t('profile.label.logout') })] })] }))] }));
28
30
  }
@@ -1,10 +1,15 @@
1
1
  import { ButtonDSModes, ButtonDSSizes, TooltipPlacements } from 'tycho-storybook';
2
+ /**
3
+ * @deprecated The legacy help modal (tutorial actions) was replaced by the CorpusHub assistant.
4
+ * Kept only so existing callers still compile; the actions are ignored.
5
+ */
2
6
  export type HelpAction = {
3
7
  title: string;
4
8
  desc: string;
5
9
  action: () => void;
6
10
  };
7
11
  type Props = {
12
+ /** @deprecated ignored — see HelpAction */
8
13
  helpActions?: HelpAction[];
9
14
  mobile?: boolean;
10
15
  mode?: ButtonDSModes;
@@ -13,5 +18,6 @@ type Props = {
13
18
  tooltipPlacement?: TooltipPlacements;
14
19
  title?: string;
15
20
  };
16
- export default function HelpButton({ helpActions, mobile, mode, size, iconSize, tooltipPlacement, title, }: Props): import("react").JSX.Element;
21
+ /** Opens the CorpusHub help assistant. Renders nothing when the assistant isn't loaded. */
22
+ export default function HelpButton({ mobile, mode, size, iconSize, tooltipPlacement, title, }: Props): import("react").JSX.Element | null;
17
23
  export {};
@@ -1,10 +1,11 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState } from 'react';
1
+ import { jsx as _jsx } from "react/jsx-runtime";
3
2
  import { useTranslation } from 'react-i18next';
4
3
  import { IconButton, } from 'tycho-storybook';
5
- import HelpModal from './HelpModal';
6
- export default function HelpButton({ helpActions, mobile, mode, size = 'large', iconSize, tooltipPlacement, title, }) {
4
+ import { isHelpAssistantEnabled, openHelpAssistant } from './helpAssistant';
5
+ /** Opens the CorpusHub help assistant. Renders nothing when the assistant isn't loaded. */
6
+ export default function HelpButton({ mobile, mode, size = 'large', iconSize, tooltipPlacement, title, }) {
7
7
  const { t } = useTranslation('header');
8
- const [open, setOpen] = useState(false);
9
- return (_jsxs(_Fragment, { children: [_jsx(IconButton, { name: "live_help", size: size, iconSize: iconSize, title: title || t('tooltip.tutorials'), onClick: () => setOpen(true), mode: mode || (mobile ? 'outlined' : 'filled'), tooltipPlacement: tooltipPlacement, "data-tour": "help-button" }), open && (_jsx(HelpModal, { onClose: () => setOpen(false), helpActions: helpActions }))] }));
8
+ if (!isHelpAssistantEnabled())
9
+ return null;
10
+ return (_jsx(IconButton, { name: "live_help", size: size, iconSize: iconSize, title: title || t('tooltip.assistant'), onClick: openHelpAssistant, mode: mode || (mobile ? 'outlined' : 'filled'), tooltipPlacement: tooltipPlacement, "data-tour": "help-button" }));
10
11
  }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * CorpusHub help assistant — offline RAG chat (tycho-brahe/corpushub-rag).
3
+ *
4
+ * The widget is a single implementation served by the RAG API itself (`GET <api>widget.js`), so the
5
+ * fronts never carry a copy: changing the assistant is a RAG deploy, not a front rebuild.
6
+ * Call `loadHelpAssistant(import.meta.env.VITE_APP_HELP_ASSISTANT_API)` once at app start (main.tsx).
7
+ * With no API URL (e.g. production today) nothing is loaded and the Header help button stays hidden.
8
+ */
9
+ type AgentApi = {
10
+ open: () => void;
11
+ close?: () => void;
12
+ toggle?: () => void;
13
+ isOpen?: () => boolean;
14
+ _pendingOpen?: boolean;
15
+ };
16
+ declare global {
17
+ interface Window {
18
+ CorpusHubAgent?: AgentApi;
19
+ }
20
+ }
21
+ type Options = {
22
+ /** 'floating' (default) shows the widget's own corner button; 'none' leaves opening to the app. */
23
+ launcher?: 'floating' | 'none';
24
+ };
25
+ export declare function loadHelpAssistant(api?: string, options?: Options): void;
26
+ export declare function isHelpAssistantEnabled(): boolean;
27
+ export declare function openHelpAssistant(): void;
28
+ export {};
@@ -0,0 +1,29 @@
1
+ const SELECTOR = 'script[data-corpushub-agent]';
2
+ export function loadHelpAssistant(api, options = {}) {
3
+ if (!api || typeof document === 'undefined' || document.querySelector(SELECTOR))
4
+ return;
5
+ const base = api.endsWith('/') ? api : `${api}/`;
6
+ // Stub until the script arrives: an early open() is remembered and honoured by the widget.
7
+ if (!window.CorpusHubAgent) {
8
+ window.CorpusHubAgent = {
9
+ _pendingOpen: false,
10
+ open() {
11
+ this._pendingOpen = true;
12
+ },
13
+ };
14
+ }
15
+ const script = document.createElement('script');
16
+ script.src = `${base}widget.js`;
17
+ script.dataset.api = base;
18
+ script.dataset.corpushubAgent = '';
19
+ if (options.launcher)
20
+ script.dataset.launcher = options.launcher;
21
+ script.defer = true;
22
+ document.head.appendChild(script);
23
+ }
24
+ export function isHelpAssistantEnabled() {
25
+ return typeof document !== 'undefined' && !!document.querySelector(SELECTOR);
26
+ }
27
+ export function openHelpAssistant() {
28
+ window.CorpusHubAgent?.open();
29
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tycho-components",
3
3
  "private": false,
4
- "version": "0.46.5",
4
+ "version": "0.47.0",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "exports": {
@@ -1,8 +0,0 @@
1
- import { HelpAction } from './HelpButton';
2
- import './style.scss';
3
- type Props = {
4
- onClose: () => void;
5
- helpActions?: HelpAction[];
6
- };
7
- export default function HelpModal({ onClose, helpActions }: Props): import("react").JSX.Element;
8
- export {};
@@ -1,76 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState } from 'react';
3
- import { useTranslation } from 'react-i18next';
4
- import { Button } from 'tycho-storybook';
5
- import AppModal from '../../../common/AppModal/AppModal';
6
- import CookieStorage from '../../../configs/CookieStorage';
7
- import ProfileService from '../../../configs/services/ProfileService';
8
- import { useLoggedUtils } from '../../../configs/useLoggedUtils';
9
- import { useTourUtils } from '../../../configs/useTourUtils';
10
- import SecurityUtils from '../../../functions/SecurityUtils';
11
- import './style.scss';
12
- export default function HelpModal({ onClose, helpActions = [] }) {
13
- const { t } = useTranslation('help');
14
- const { turnOn, turnOff, status } = useTourUtils();
15
- const { getLogged, setLogged } = useLoggedUtils();
16
- const [autoOpenEnabled, setAutoOpenEnabled] = useState(() => getLogged()?.liveTour ?? false);
17
- const [updatingLiveTour, setUpdatingLiveTour] = useState(false);
18
- const isTourActive = status();
19
- const currentLiveTour = getLogged()?.liveTour ?? false;
20
- const preferenceChanged = autoOpenEnabled !== currentLiveTour;
21
- const isDisablingAutoOpen = preferenceChanged && !autoOpenEnabled;
22
- const handleTutorials = () => {
23
- const origin = (import.meta.env.VITE_APP_ORIGIN ?? '').replace(/\/+$/, '');
24
- window.open(`${origin}/home/tutorials`, '_blank');
25
- };
26
- const handleTourToggle = () => {
27
- const startTour = () => {
28
- if (isTourActive) {
29
- turnOff();
30
- }
31
- else {
32
- turnOn();
33
- }
34
- onClose();
35
- };
36
- if (!preferenceChanged) {
37
- startTour();
38
- return;
39
- }
40
- setUpdatingLiveTour(true);
41
- ProfileService.updateLiveTour(autoOpenEnabled)
42
- .then((response) => {
43
- CookieStorage.setJwtToken(response.data);
44
- setLogged(SecurityUtils.parseJwt(response.data));
45
- })
46
- .catch((error) => {
47
- console.error(error);
48
- })
49
- .finally(() => {
50
- setUpdatingLiveTour(false);
51
- if (isDisablingAutoOpen) {
52
- onClose();
53
- return;
54
- }
55
- startTour();
56
- });
57
- };
58
- const handleCustomAction = (item) => {
59
- item.action();
60
- onClose();
61
- };
62
- const handleAutoOpenChange = (event) => {
63
- setAutoOpenEnabled(event.target.checked);
64
- };
65
- const actionItems = [
66
- // {
67
- // title: t('title.tutorials'),
68
- // desc: t('description.tutorials'),
69
- // action: handleTutorials,
70
- // },
71
- ...helpActions,
72
- ];
73
- return (_jsxs(AppModal, { title: t('modal.title'), close: onClose, hideFooter: true, className: "help-modal", children: [_jsxs("div", { className: "item item-tour", children: [_jsx("div", { className: "title", children: t('title.tour') }), _jsx("div", { className: "desc", children: t('description.tour') }), _jsxs("label", { className: "help-checkbox-label", children: [_jsx("input", { type: "checkbox", checked: autoOpenEnabled, onChange: handleAutoOpenChange, disabled: updatingLiveTour, className: "help-checkbox" }), _jsx("span", { children: t('checkbox.autoOpen') })] }), _jsx(Button, { text: isDisablingAutoOpen
74
- ? t('button.updateLiveTourPreference')
75
- : t('button.tour'), size: "small", icon: isDisablingAutoOpen ? 'save' : 'keyboard_arrow_right', onClick: handleTourToggle, disabled: updatingLiveTour, "data-tour": "guided-tour-start" })] }), actionItems.map((item, idx) => (_jsxs("div", { className: "item", children: [_jsx("div", { className: "title", children: item.title }), _jsx("div", { className: "desc", children: item.desc }), _jsx(Button, { text: t('button.open'), size: "small", mode: "outlined", icon: "keyboard_arrow_right", onClick: () => handleCustomAction(item) })] }, idx)))] }));
76
- }
@@ -1,80 +0,0 @@
1
- .help-modal {
2
- max-width: 60vw !important;
3
- width: 60vw !important;
4
-
5
- .body {
6
- display: grid;
7
- grid-template-columns: repeat(3, minmax(0, 1fr));
8
- gap: var(--spacing-200);
9
-
10
- .item {
11
- display: flex;
12
- flex-direction: column;
13
- min-width: 0;
14
- padding: 24px 24px 16px;
15
- border: 1px solid var(--border-subtle-2);
16
- border-radius: var(--radius-100);
17
-
18
- > .title {
19
- @include subtitle-small-2;
20
- color: var(--text-primary);
21
- margin-bottom: 4px;
22
- }
23
-
24
- > .desc {
25
- @include body-medium-1;
26
- color: var(--text-secondary);
27
- }
28
-
29
- > .ds-button {
30
- margin-top: auto;
31
- }
32
- }
33
-
34
- .item-tour {
35
- background-color: #ebeff8;
36
-
37
- .help-checkbox-label {
38
- display: flex;
39
- align-items: center;
40
- gap: var(--spacing-100);
41
- cursor: pointer;
42
- margin: 8px 0;
43
-
44
- .help-checkbox {
45
- cursor: pointer;
46
- }
47
- }
48
- }
49
- }
50
- }
51
-
52
- @media (max-width: 1366px) {
53
- .help-modal {
54
- max-width: 80vw !important;
55
- width: 80vw !important;
56
- }
57
- }
58
-
59
- @media (max-width: 768px) {
60
- .help-modal {
61
- max-width: 90vw !important;
62
- width: 90vw !important;
63
-
64
- .body {
65
- grid-template-columns: repeat(2, minmax(0, 1fr));
66
- }
67
- }
68
- }
69
-
70
- @media (max-width: 767px) {
71
- .help-modal {
72
- top: 50% !important;
73
-
74
- .body {
75
- grid-template-columns: repeat(1, minmax(0, 1fr));
76
- max-height: 86vh;
77
- overflow-y: auto;
78
- }
79
- }
80
- }