@cccsaurora/howler-ui 3.0.6-dev.1470 → 3.0.7-dev.1472

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.
@@ -28,16 +28,15 @@ import RecordRelated from '@cccsaurora/howler-ui/components/elements/record/Reco
28
28
  import RecordWorklog from '@cccsaurora/howler-ui/components/elements/record/RecordWorklog';
29
29
  import useMyUserList from '@cccsaurora/howler-ui/components/hooks/useMyUserList';
30
30
  import ErrorBoundary from '@cccsaurora/howler-ui/components/routes/ErrorBoundary';
31
- import howlerPluginStore from '@cccsaurora/howler-ui/plugins/store';
32
31
  import { useContext, useEffect, useMemo, useState } from 'react';
33
32
  import { useTranslation } from 'react-i18next';
34
- import { usePluginStore } from 'react-pluggable';
35
33
  import { useLocation } from 'react-router-dom';
36
34
  import { useContextSelector } from 'use-context-selector';
37
35
  import { getUserList } from '@cccsaurora/howler-ui/utils/recordFunctions';
38
36
  import { validateRegex } from '@cccsaurora/howler-ui/utils/stringUtils';
39
37
  import { isHit } from '@cccsaurora/howler-ui/utils/typeUtils';
40
38
  import { tryParse } from '@cccsaurora/howler-ui/utils/utils';
39
+ import PluginViewing from '../shared/PluginViewing';
41
40
  import LeadRenderer from '../view/LeadRenderer';
42
41
  const InformationPane = ({ onClose, selected: _selected }) => {
43
42
  const { t, i18n } = useTranslation();
@@ -46,7 +45,6 @@ const InformationPane = ({ onClose, selected: _selected }) => {
46
45
  const { emit, open } = useContext(SocketContext);
47
46
  const { getMatchingOverview, getMatchingDossiers, getMatchingAnalytic } = useMatchers();
48
47
  const selected = useContextSelector(ParameterContext, ctx => ctx?.selected) ?? _selected;
49
- const pluginStore = usePluginStore();
50
48
  const getRecord = useContextSelector(RecordContext, ctx => ctx.getRecord);
51
49
  const [userIds, setUserIds] = useState(new Set());
52
50
  const [analytic, setAnalytic] = useState();
@@ -59,14 +57,6 @@ const InformationPane = ({ onClose, selected: _selected }) => {
59
57
  const dossiers = useMemo(() => _dossiers ?? [], [_dossiers]);
60
58
  const users = useMyUserList(userIds);
61
59
  const record = useContextSelector(RecordContext, ctx => ctx.records[selected]);
62
- useEffect(() => {
63
- if (!selected) {
64
- return;
65
- }
66
- howlerPluginStore.plugins.forEach(plugin => {
67
- pluginStore.executeFunction(`${plugin}.on`, 'viewing');
68
- });
69
- }, [pluginStore.executeFunction, selected]);
70
60
  useEffect(() => {
71
61
  if (!selected) {
72
62
  return;
@@ -154,7 +144,7 @@ const InformationPane = ({ onClose, selected: _selected }) => {
154
144
  }[tab]?.();
155
145
  }, [dossiers, filter, record, loading, tab, users]);
156
146
  const hasError = useMemo(() => !validateRegex(filter), [filter]);
157
- return (_jsxs(VSBox, { top: 10, sx: { height: '100%', flex: 1 }, children: [_jsxs(Stack, { direction: "column", flex: 1, sx: { overflowY: 'auto', flexGrow: 1 }, position: "relative", spacing: 1, ml: 2, children: [_jsxs(Stack, { direction: "row", alignItems: "center", spacing: 0.5, flexShrink: 0, pr: 2, children: [_jsx(FlexOne, {}), onClose && !location.pathname.startsWith('/bundles') && (_jsx(TuiIconButton, { size: "small", onClick: onClose, tooltip: t('hit.panel.details.exit'), children: _jsx(Clear, {}) })), _jsx(SocketBadge, { size: "small" }), analytic && (_jsx(TuiIconButton, { size: "small", tooltip: t('analytic.open'), disabled: !analytic || loading, route: `/analytics/${analytic.analytic_id}`, children: _jsx(QueryStats, {}) })), !!record && (_jsx(TuiIconButton, { tooltip: t(`${record.__index}.open`), href: `/${record.__index}s/${selected}`, disabled: !record || loading, size: "small", target: "_blank", children: _jsx(OpenInNew, {}) }))] }), isHit(record) && (_jsxs(_Fragment, { children: [_jsx(Box, { pr: 2, children: _jsx(HitBanner, { layout: HitLayout.DENSE, hit: record }) }), !loading && (_jsxs(_Fragment, { children: [_jsx(HitOutline, { hit: record, layout: HitLayout.DENSE, forceAllFields: true }), _jsx(HitLabels, { hit: record })] })), _jsx(HitLinks, { hit: record, analytic: analytic, dossiers: dossiers })] })), loading && (_jsxs(_Fragment, { children: [_jsx(Skeleton, { variant: "rounded", height: 152 }), _jsx(Skeleton, { height: 124 })] })), _jsxs(VSBoxHeader, { ml: -1, mr: -1, pb: 1, sx: { top: '0px' }, children: [_jsxs(Tabs, { value: tab === 'overview' && !hasOverview ? 'details' : tab, sx: {
147
+ return (_jsxs(VSBox, { top: 10, sx: { height: '100%', flex: 1 }, children: [isHit(record) && _jsx(PluginViewing, { hit: record }), _jsxs(Stack, { direction: "column", flex: 1, sx: { overflowY: 'auto', flexGrow: 1 }, position: "relative", spacing: 1, ml: 2, children: [_jsxs(Stack, { direction: "row", alignItems: "center", spacing: 0.5, flexShrink: 0, pr: 2, children: [_jsx(FlexOne, {}), onClose && !location.pathname.startsWith('/bundles') && (_jsx(TuiIconButton, { size: "small", onClick: onClose, tooltip: t('hit.panel.details.exit'), children: _jsx(Clear, {}) })), _jsx(SocketBadge, { size: "small" }), analytic && (_jsx(TuiIconButton, { size: "small", tooltip: t('analytic.open'), disabled: !analytic || loading, route: `/analytics/${analytic.analytic_id}`, children: _jsx(QueryStats, {}) })), !!record && (_jsx(TuiIconButton, { tooltip: t(`${record.__index}.open`), href: `/${record.__index}s/${selected}`, disabled: !record || loading, size: "small", target: "_blank", children: _jsx(OpenInNew, {}) }))] }), isHit(record) && (_jsxs(_Fragment, { children: [_jsx(Box, { pr: 2, children: _jsx(HitBanner, { layout: HitLayout.DENSE, hit: record }) }), !loading && (_jsxs(_Fragment, { children: [_jsx(HitOutline, { hit: record, layout: HitLayout.DENSE, forceAllFields: true }), _jsx(HitLabels, { hit: record })] })), _jsx(HitLinks, { hit: record, analytic: analytic, dossiers: dossiers })] })), loading && (_jsxs(_Fragment, { children: [_jsx(Skeleton, { variant: "rounded", height: 152 }), _jsx(Skeleton, { height: 124 })] })), _jsxs(VSBoxHeader, { ml: -1, mr: -1, pb: 1, sx: { top: '0px' }, children: [_jsxs(Tabs, { value: tab === 'overview' && !hasOverview ? 'details' : tab, sx: {
158
148
  display: 'flex',
159
149
  flexDirection: 'row',
160
150
  pr: 2,
@@ -0,0 +1,10 @@
1
+ import type { Hit } from '@cccsaurora/howler-ui/models/entities/generated/Hit';
2
+ import { type FC } from 'react';
3
+ /**
4
+ * Plugin viewing handlers must be rendered because plugin implementations may use React hooks.
5
+ * Memoization prevents them from running again when the surrounding hit view rerenders unchanged.
6
+ */
7
+ declare const PluginViewing: FC<{
8
+ hit: Hit;
9
+ }>;
10
+ export default PluginViewing;
@@ -0,0 +1,13 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ import howlerPluginStore from '@cccsaurora/howler-ui/plugins/store';
3
+ import { memo } from 'react';
4
+ import { usePluginStore } from 'react-pluggable';
5
+ /**
6
+ * Plugin viewing handlers must be rendered because plugin implementations may use React hooks.
7
+ * Memoization prevents them from running again when the surrounding hit view rerenders unchanged.
8
+ */
9
+ const PluginViewing = memo(({ hit }) => {
10
+ const pluginStore = usePluginStore();
11
+ return _jsx(_Fragment, { children: howlerPluginStore.plugins.map(plugin => pluginStore.executeFunction(`${plugin}.on`, 'viewing', hit)) });
12
+ });
13
+ export default PluginViewing;
@@ -23,15 +23,14 @@ import RecordRelated from '@cccsaurora/howler-ui/components/elements/record/Reco
23
23
  import RecordWorklog from '@cccsaurora/howler-ui/components/elements/record/RecordWorklog';
24
24
  import { useMyLocalStorageItem } from '@cccsaurora/howler-ui/components/hooks/useMyLocalStorage';
25
25
  import useMyUserList from '@cccsaurora/howler-ui/components/hooks/useMyUserList';
26
- import howlerPluginStore from '@cccsaurora/howler-ui/plugins/store';
27
26
  import { useCallback, useContext, useEffect, useMemo, useState } from 'react';
28
27
  import { useTranslation } from 'react-i18next';
29
- import { usePluginStore } from 'react-pluggable';
30
28
  import { useNavigate, useParams } from 'react-router-dom';
31
29
  import { useContextSelector } from 'use-context-selector';
32
30
  import { StorageKey } from '@cccsaurora/howler-ui/utils/constants';
33
31
  import { getUserList } from '@cccsaurora/howler-ui/utils/recordFunctions';
34
32
  import { tryParse } from '@cccsaurora/howler-ui/utils/utils';
33
+ import PluginViewing from '../shared/PluginViewing';
35
34
  import LeadRenderer from './LeadRenderer';
36
35
  export var Orientation;
37
36
  (function (Orientation) {
@@ -47,7 +46,6 @@ const HitViewer = () => {
47
46
  const [orientation, setOrientation] = useMyLocalStorageItem(StorageKey.VIEWER_ORIENTATION, Orientation.VERTICAL);
48
47
  const { getMatchingOverview, getMatchingDossiers, getMatchingAnalytic } = useMatchers();
49
48
  const { emit, open } = useContext(SocketContext);
50
- const pluginStore = usePluginStore();
51
49
  const getHit = useContextSelector(RecordContext, ctx => ctx.getRecord);
52
50
  const hit = useContextSelector(RecordContext, ctx => ctx.records[params.id]);
53
51
  const [userIds, setUserIds] = useState(new Set());
@@ -76,14 +74,6 @@ const HitViewer = () => {
76
74
  setOrientation(Orientation.HORIZONTAL);
77
75
  }
78
76
  }, [isUnderLg, setOrientation]);
79
- useEffect(() => {
80
- if (!hit) {
81
- return;
82
- }
83
- howlerPluginStore.plugins.forEach(plugin => {
84
- pluginStore.executeFunction(`${plugin}.on`, 'viewing');
85
- });
86
- }, [pluginStore.executeFunction, hit]);
87
77
  useEffect(() => {
88
78
  void fetchData();
89
79
  }, [params.id, fetchData, hit]);
@@ -145,37 +135,37 @@ const HitViewer = () => {
145
135
  if (!hit) {
146
136
  return (_jsx(PageCenter, { children: _jsx(Skeleton, { variant: "rounded", height: "520px" }) }));
147
137
  }
148
- return (_jsx(PageCenter, { maxWidth: "1500px", children: _jsxs(Box, { sx: {
149
- display: 'grid',
150
- position: 'relative',
151
- gridTemplateColumns: `1fr ${orientation === 'vertical' ? '300px' : '0px'}`,
152
- alignItems: 'stretch',
153
- gap: theme.spacing(2),
154
- transition: `${theme.transitions.duration.standard}ms`,
155
- mb: 1
156
- }, textAlign: "left", children: [_jsx(Collapse, { sx: { gridColumn: '1 / span 2', '& [class*=MuiStack-root]': { padding: '0 !important' } }, in: orientation === 'horizontal', children: _jsx(HitActions, { hit: hit, orientation: "horizontal" }) }), _jsxs(Box, { sx: {
157
- display: 'flex',
158
- '& > .MuiPaper-root': { flex: 1 },
159
- mr: orientation === 'vertical' ? 0 : -2
160
- }, children: [_jsx(HowlerCard, { tabIndex: 0, sx: { position: 'relative' }, children: _jsxs(CardContent, { children: [_jsx(HitBanner, { hit: hit, layout: HitLayout.COMFY, useListener: true }), _jsx(HitOutline, { hit: hit, layout: HitLayout.COMFY, forceAllFields: true }), _jsx(HitLabels, { hit: hit }), _jsx(HitLinks, { hit: hit, analytic: analytic, dossiers: dossiers })] }) }), !isUnderLg && (_jsxs(Stack, { spacing: 1, sx: {
161
- position: 'absolute',
162
- top: theme.spacing(2),
163
- right: theme.spacing(-6)
164
- }, children: [_jsx(Tooltip, { title: t('hit.panel.view.layout'), children: _jsx(IconButton, { onClick: onOrientationChange, children: _jsx(ViewAgenda, { sx: { transition: 'rotate 250ms', rotate: orientation === 'vertical' ? '90deg' : '0deg' } }) }) }), _jsx(SocketBadge, { size: "medium" }), analytic && (_jsx(Tooltip, { title: t('analytic.open'), children: _jsx(IconButton, { onClick: () => navigate(`/analytics/${analytic.analytic_id}`), children: _jsx(QueryStats, {}) }) }))] }))] }), _jsx(HowlerCard, { sx: [orientation === 'horizontal' && { height: '0px' }], children: _jsx(CardContent, { sx: { padding: 1, position: 'relative' }, children: _jsx(HitActions, { hit: hit, orientation: "vertical" }) }) }), _jsx(Box, { sx: { gridColumn: '1 / span 2', mb: 1 }, children: _jsxs(Tabs, { value: tab === 'overview' && !hasOverview ? 'details' : tab, sx: { display: 'flex', flexDirection: 'row', pr: 2, alignItems: 'center' }, children: [hasOverview && (_jsx(Tab, { label: t('hit.viewer.overview'), value: "overview", onClick: () => setTab('overview') })), _jsx(Tab, { label: t('hit.viewer.details'), value: "details", onClick: () => setTab('details') }), hit?.howler.dossier?.map((lead, index) => (_jsx(Tab
165
- // eslint-disable-next-line react/no-array-index-key
166
- , { label: _jsxs(Stack, { direction: "row", spacing: 0.5, children: [lead.icon && _jsx(Icon, { icon: lead.icon }), _jsx("span", { children: i18n.language === 'en' ? lead.label.en : lead.label.fr })] }), value: 'lead:' + index, onClick: () => setTab('lead:' + index) }, 'lead:' + index))), dossiers.flatMap((_dossier, dossierIndex) => (_dossier.leads ?? []).map((_lead, leadIndex) => (_jsx(Tab
167
- // eslint-disable-next-line react/no-array-index-key
168
- , { label: _jsxs(Stack, { direction: "row", spacing: 0.5, children: [_lead.icon && _jsx(Icon, { icon: _lead.icon }), _jsx("span", { children: i18n.language === 'en' ? _lead.label.en : _lead.label.fr })] }), value: `external-lead:${dossierIndex}:${leadIndex}`, onClick: () => setTab(`external-lead:${dossierIndex}:${leadIndex}`) }, `external-lead:${dossierIndex}:${leadIndex}`)))), _jsx(FlexOne, {}), _jsx(Tab, { sx: { px: 2, minWidth: 0 }, label: _jsx(Tooltip, { title: t('hit.viewer.data'), children: _jsx(DataObject, {}) }), value: "hit_data", onClick: () => setTab('hit_data'), disabled: !hit?.howler?.data }), _jsx(Tab, { sx: { px: 2, minWidth: 0 }, label: _jsx(Tooltip, { title: t('hit.viewer.json'), children: _jsx(Code, {}) }), value: "hit_raw", onClick: () => setTab('hit_raw') }), _jsx(Tab, { sx: { px: 2, minWidth: 0 }, label: _jsx(Tooltip, { title: t('hit.viewer.comments'), children: _jsx(Badge, { sx: {
169
- '& > .MuiBadge-badge': {
170
- backgroundColor: theme.palette.divider,
171
- zIndex: 1,
172
- right: theme.spacing(-0.5)
173
- },
174
- '& > svg': { zIndex: 2 }
175
- }, badgeContent: hit?.howler.comment?.length ?? 0, children: _jsx(Comment, {}) }) }), value: "hit_comments", onClick: () => setTab('hit_comments') }), _jsx(Tab, { sx: { px: 2, minWidth: 0 }, label: _jsx(Tooltip, { title: t('hit.viewer.worklog'), children: _jsx(History, {}) }), value: "hit_worklog", onClick: () => setTab('hit_worklog') }), _jsx(Tab, { sx: { px: 2, minWidth: 0 }, label: _jsx(Tooltip, { title: t('hit.viewer.related'), children: _jsx(LinkSharp, {}) }), value: "hit_related", onClick: () => setTab('hit_related') })] }) }), _jsx(Box, { sx: {
176
- gridColumn: '1 / span 2',
177
- '& > div': { padding: 0 },
178
- '& .react-json-view': { backgroundColor: 'transparent !important' }
179
- }, children: tabContent })] }) }));
138
+ return (_jsxs(PageCenter, { maxWidth: "1500px", children: [_jsx(PluginViewing, { hit: hit }), _jsxs(Box, { sx: {
139
+ display: 'grid',
140
+ position: 'relative',
141
+ gridTemplateColumns: `1fr ${orientation === 'vertical' ? '300px' : '0px'}`,
142
+ alignItems: 'stretch',
143
+ gap: theme.spacing(2),
144
+ transition: `${theme.transitions.duration.standard}ms`,
145
+ mb: 1
146
+ }, textAlign: "left", children: [_jsx(Collapse, { sx: { gridColumn: '1 / span 2', '& [class*=MuiStack-root]': { padding: '0 !important' } }, in: orientation === 'horizontal', children: _jsx(HitActions, { hit: hit, orientation: "horizontal" }) }), _jsxs(Box, { sx: {
147
+ display: 'flex',
148
+ '& > .MuiPaper-root': { flex: 1 },
149
+ mr: orientation === 'vertical' ? 0 : -2
150
+ }, children: [_jsx(HowlerCard, { tabIndex: 0, sx: { position: 'relative' }, children: _jsxs(CardContent, { children: [_jsx(HitBanner, { hit: hit, layout: HitLayout.COMFY, useListener: true }), _jsx(HitOutline, { hit: hit, layout: HitLayout.COMFY, forceAllFields: true }), _jsx(HitLabels, { hit: hit }), _jsx(HitLinks, { hit: hit, analytic: analytic, dossiers: dossiers })] }) }), !isUnderLg && (_jsxs(Stack, { spacing: 1, sx: {
151
+ position: 'absolute',
152
+ top: theme.spacing(2),
153
+ right: theme.spacing(-6)
154
+ }, children: [_jsx(Tooltip, { title: t('hit.panel.view.layout'), children: _jsx(IconButton, { onClick: onOrientationChange, children: _jsx(ViewAgenda, { sx: { transition: 'rotate 250ms', rotate: orientation === 'vertical' ? '90deg' : '0deg' } }) }) }), _jsx(SocketBadge, { size: "medium" }), analytic && (_jsx(Tooltip, { title: t('analytic.open'), children: _jsx(IconButton, { onClick: () => navigate(`/analytics/${analytic.analytic_id}`), children: _jsx(QueryStats, {}) }) }))] }))] }), _jsx(HowlerCard, { sx: [orientation === 'horizontal' && { height: '0px' }], children: _jsx(CardContent, { sx: { padding: 1, position: 'relative' }, children: _jsx(HitActions, { hit: hit, orientation: "vertical" }) }) }), _jsx(Box, { sx: { gridColumn: '1 / span 2', mb: 1 }, children: _jsxs(Tabs, { value: tab === 'overview' && !hasOverview ? 'details' : tab, sx: { display: 'flex', flexDirection: 'row', pr: 2, alignItems: 'center' }, children: [hasOverview && (_jsx(Tab, { label: t('hit.viewer.overview'), value: "overview", onClick: () => setTab('overview') })), _jsx(Tab, { label: t('hit.viewer.details'), value: "details", onClick: () => setTab('details') }), hit?.howler.dossier?.map((lead, index) => (_jsx(Tab
155
+ // eslint-disable-next-line react/no-array-index-key
156
+ , { label: _jsxs(Stack, { direction: "row", spacing: 0.5, children: [lead.icon && _jsx(Icon, { icon: lead.icon }), _jsx("span", { children: i18n.language === 'en' ? lead.label.en : lead.label.fr })] }), value: 'lead:' + index, onClick: () => setTab('lead:' + index) }, 'lead:' + index))), dossiers.flatMap((_dossier, dossierIndex) => (_dossier.leads ?? []).map((_lead, leadIndex) => (_jsx(Tab
157
+ // eslint-disable-next-line react/no-array-index-key
158
+ , { label: _jsxs(Stack, { direction: "row", spacing: 0.5, children: [_lead.icon && _jsx(Icon, { icon: _lead.icon }), _jsx("span", { children: i18n.language === 'en' ? _lead.label.en : _lead.label.fr })] }), value: `external-lead:${dossierIndex}:${leadIndex}`, onClick: () => setTab(`external-lead:${dossierIndex}:${leadIndex}`) }, `external-lead:${dossierIndex}:${leadIndex}`)))), _jsx(FlexOne, {}), _jsx(Tab, { sx: { px: 2, minWidth: 0 }, label: _jsx(Tooltip, { title: t('hit.viewer.data'), children: _jsx(DataObject, {}) }), value: "hit_data", onClick: () => setTab('hit_data'), disabled: !hit?.howler?.data }), _jsx(Tab, { sx: { px: 2, minWidth: 0 }, label: _jsx(Tooltip, { title: t('hit.viewer.json'), children: _jsx(Code, {}) }), value: "hit_raw", onClick: () => setTab('hit_raw') }), _jsx(Tab, { sx: { px: 2, minWidth: 0 }, label: _jsx(Tooltip, { title: t('hit.viewer.comments'), children: _jsx(Badge, { sx: {
159
+ '& > .MuiBadge-badge': {
160
+ backgroundColor: theme.palette.divider,
161
+ zIndex: 1,
162
+ right: theme.spacing(-0.5)
163
+ },
164
+ '& > svg': { zIndex: 2 }
165
+ }, badgeContent: hit?.howler.comment?.length ?? 0, children: _jsx(Comment, {}) }) }), value: "hit_comments", onClick: () => setTab('hit_comments') }), _jsx(Tab, { sx: { px: 2, minWidth: 0 }, label: _jsx(Tooltip, { title: t('hit.viewer.worklog'), children: _jsx(History, {}) }), value: "hit_worklog", onClick: () => setTab('hit_worklog') }), _jsx(Tab, { sx: { px: 2, minWidth: 0 }, label: _jsx(Tooltip, { title: t('hit.viewer.related'), children: _jsx(LinkSharp, {}) }), value: "hit_related", onClick: () => setTab('hit_related') })] }) }), _jsx(Box, { sx: {
166
+ gridColumn: '1 / span 2',
167
+ '& > div': { padding: 0 },
168
+ '& .react-json-view': { backgroundColor: 'transparent !important' }
169
+ }, children: tabContent })] })] }));
180
170
  };
181
171
  export default HitViewer;
@@ -182,7 +182,7 @@ describe('HitViewer', () => {
182
182
  });
183
183
  expect(screen.getByText('details-content')).toBeInTheDocument();
184
184
  expect(mockExecutePlugin).toHaveBeenCalledTimes(1);
185
- expect(mockExecutePlugin).toHaveBeenCalledWith('test-plugin.on', 'viewing');
185
+ expect(mockExecutePlugin).toHaveBeenCalledWith('test-plugin.on', 'viewing', hit);
186
186
  });
187
187
  it('emits viewing and stop_viewing socket events', async () => {
188
188
  const { unmount } = renderViewer();
package/package.json CHANGED
@@ -93,7 +93,7 @@
93
93
  "url": "https://github.com/CybercentreCanada/howler"
94
94
  },
95
95
  "type": "module",
96
- "version": "3.0.6-dev.1470",
96
+ "version": "3.0.7-dev.1472",
97
97
  "exports": {
98
98
  "./i18n": "./i18n.js",
99
99
  "./index.css": "./index.css",
@@ -245,6 +245,7 @@
245
245
  "./components/routes/overviews/template/*": "./components/routes/overviews/template/*.js",
246
246
  "./components/routes/hits/search/*": "./components/routes/hits/search/*.js",
247
247
  "./components/routes/hits/view/*": "./components/routes/hits/view/*.js",
248
+ "./components/routes/hits/shared/*": "./components/routes/hits/shared/*.js",
248
249
  "./components/routes/hits/search/shared/*": "./components/routes/hits/search/shared/*.js",
249
250
  "./components/routes/hits/search/grid/*": "./components/routes/hits/search/grid/*.js",
250
251
  "./components/routes/analytics/widgets/*": "./components/routes/analytics/widgets/*.js",