@cccsaurora/howler-ui 2.13.0-dev.110 → 2.13.0-dev.129

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.
@@ -1 +1 @@
1
- export default function useAppEnv(key?: string): any;
1
+ export default function useAppEnv(key?: string): string | NodeJS.ProcessEnv;
@@ -5,6 +5,9 @@ import { HitContext } from '../providers/HitProvider';
5
5
  const useMatchers = () => {
6
6
  const getHit = useContextSelector(HitContext, ctx => ctx.getHit);
7
7
  const getMatchingTemplate = useCallback(async (hit) => {
8
+ if (!hit) {
9
+ return null;
10
+ }
8
11
  if (has(hit, '__template')) {
9
12
  return hit.__template;
10
13
  }
@@ -13,6 +16,9 @@ const useMatchers = () => {
13
16
  return (await getHit(hit.howler.id, true)).__template;
14
17
  }, [getHit]);
15
18
  const getMatchingOverview = useCallback(async (hit) => {
19
+ if (!hit) {
20
+ return null;
21
+ }
16
22
  if (has(hit, '__overview')) {
17
23
  return hit.__overview;
18
24
  }
@@ -21,6 +27,9 @@ const useMatchers = () => {
21
27
  return (await getHit(hit.howler.id, true)).__overview;
22
28
  }, [getHit]);
23
29
  const getMatchingDossiers = useCallback(async (hit) => {
30
+ if (!hit) {
31
+ return null;
32
+ }
24
33
  if (has(hit, '__dossiers')) {
25
34
  return hit.__dossiers;
26
35
  }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,237 @@
1
+ import { renderHook } from '@testing-library/react';
2
+ import { useContextSelector } from 'use-context-selector';
3
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
4
+ import { HitContext } from '../providers/HitProvider';
5
+ import useMatchers from './useMatchers';
6
+ // Mock the useContextSelector hook
7
+ vi.mock('use-context-selector', () => ({
8
+ useContextSelector: vi.fn(),
9
+ createContext: vi.fn()
10
+ }));
11
+ // Mock lodash-es has function
12
+ vi.mock('lodash-es', () => ({
13
+ has: vi.fn()
14
+ }));
15
+ // Create mock data
16
+ const mockTemplate = {
17
+ name: 'test-template',
18
+ template: 'Test template content'
19
+ };
20
+ const mockOverview = {
21
+ name: 'test-overview',
22
+ overview: 'Test overview content'
23
+ };
24
+ const mockDossiers = [
25
+ {
26
+ name: 'test-dossier',
27
+ description: 'Test dossier content'
28
+ }
29
+ ];
30
+ const mockHit = {
31
+ howler: {
32
+ id: 'test-hit-id',
33
+ analytic: 'test-analytic',
34
+ data: {}
35
+ }
36
+ };
37
+ const mockHitWithMetadata = {
38
+ ...mockHit,
39
+ __template: mockTemplate,
40
+ __overview: mockOverview,
41
+ __dossiers: mockDossiers
42
+ };
43
+ const mockGetHit = vi.fn();
44
+ describe('useMatchers', () => {
45
+ beforeEach(() => {
46
+ vi.clearAllMocks();
47
+ // Mock useContextSelector to return our mock getHit function
48
+ useContextSelector.mockImplementation((context, selector) => {
49
+ if (context === HitContext) {
50
+ return selector({ getHit: mockGetHit });
51
+ }
52
+ return null;
53
+ });
54
+ });
55
+ describe('getMatchingTemplate', () => {
56
+ it('should return null when hit is null', async () => {
57
+ const { result } = renderHook(() => useMatchers());
58
+ const template = await result.current.getMatchingTemplate(null);
59
+ expect(template).toBeNull();
60
+ });
61
+ it('should return null when hit is undefined', async () => {
62
+ const { result } = renderHook(() => useMatchers());
63
+ const template = await result.current.getMatchingTemplate(undefined);
64
+ expect(template).toBeNull();
65
+ });
66
+ it('should return template from metadata when it exists', async () => {
67
+ const { has } = await import('lodash-es');
68
+ has.mockReturnValue(true);
69
+ const { result } = renderHook(() => useMatchers());
70
+ const template = await result.current.getMatchingTemplate(mockHitWithMetadata);
71
+ expect(template).toBe(mockTemplate);
72
+ expect(mockGetHit).not.toHaveBeenCalled();
73
+ });
74
+ it('should fetch hit with metadata when template is not present', async () => {
75
+ const { has } = await import('lodash-es');
76
+ has.mockReturnValue(false);
77
+ const hitWithFetchedMetadata = { ...mockHit, __template: mockTemplate };
78
+ mockGetHit.mockResolvedValue(hitWithFetchedMetadata);
79
+ const { result } = renderHook(() => useMatchers());
80
+ const template = await result.current.getMatchingTemplate(mockHit);
81
+ expect(template).toBe(mockTemplate);
82
+ expect(mockGetHit).toHaveBeenCalledWith('test-hit-id', true);
83
+ });
84
+ it('should handle getHit rejection gracefully', async () => {
85
+ const { has } = await import('lodash-es');
86
+ has.mockReturnValue(false);
87
+ mockGetHit.mockRejectedValue(new Error('Failed to fetch hit'));
88
+ const { result } = renderHook(() => useMatchers());
89
+ await expect(result.current.getMatchingTemplate(mockHit)).rejects.toThrow('Failed to fetch hit');
90
+ expect(mockGetHit).toHaveBeenCalledWith('test-hit-id', true);
91
+ });
92
+ });
93
+ describe('getMatchingOverview', () => {
94
+ it('should return null when hit is null', async () => {
95
+ const { result } = renderHook(() => useMatchers());
96
+ const overview = await result.current.getMatchingOverview(null);
97
+ expect(overview).toBeNull();
98
+ });
99
+ it('should return null when hit is undefined', async () => {
100
+ const { result } = renderHook(() => useMatchers());
101
+ const overview = await result.current.getMatchingOverview(undefined);
102
+ expect(overview).toBeNull();
103
+ });
104
+ it('should return overview from metadata when it exists', async () => {
105
+ const { has } = await import('lodash-es');
106
+ has.mockReturnValue(true);
107
+ const { result } = renderHook(() => useMatchers());
108
+ const overview = await result.current.getMatchingOverview(mockHitWithMetadata);
109
+ expect(overview).toBe(mockOverview);
110
+ expect(mockGetHit).not.toHaveBeenCalled();
111
+ });
112
+ it('should fetch hit with metadata when overview is not present', async () => {
113
+ const { has } = await import('lodash-es');
114
+ has.mockReturnValue(false);
115
+ const hitWithFetchedMetadata = { ...mockHit, __overview: mockOverview };
116
+ mockGetHit.mockResolvedValue(hitWithFetchedMetadata);
117
+ const { result } = renderHook(() => useMatchers());
118
+ const overview = await result.current.getMatchingOverview(mockHit);
119
+ expect(overview).toBe(mockOverview);
120
+ expect(mockGetHit).toHaveBeenCalledWith('test-hit-id', true);
121
+ });
122
+ it('should handle getHit rejection gracefully', async () => {
123
+ const { has } = await import('lodash-es');
124
+ has.mockReturnValue(false);
125
+ mockGetHit.mockRejectedValue(new Error('Failed to fetch hit'));
126
+ const { result } = renderHook(() => useMatchers());
127
+ await expect(result.current.getMatchingOverview(mockHit)).rejects.toThrow('Failed to fetch hit');
128
+ expect(mockGetHit).toHaveBeenCalledWith('test-hit-id', true);
129
+ });
130
+ });
131
+ describe('getMatchingDossiers', () => {
132
+ it('should return null when hit is null', async () => {
133
+ const { result } = renderHook(() => useMatchers());
134
+ const dossiers = await result.current.getMatchingDossiers(null);
135
+ expect(dossiers).toBeNull();
136
+ });
137
+ it('should return null when hit is undefined', async () => {
138
+ const { result } = renderHook(() => useMatchers());
139
+ const dossiers = await result.current.getMatchingDossiers(undefined);
140
+ expect(dossiers).toBeNull();
141
+ });
142
+ it('should return dossiers from metadata when they exist', async () => {
143
+ const { has } = await import('lodash-es');
144
+ has.mockReturnValue(true);
145
+ const { result } = renderHook(() => useMatchers());
146
+ const dossiers = await result.current.getMatchingDossiers(mockHitWithMetadata);
147
+ expect(dossiers).toBe(mockDossiers);
148
+ expect(mockGetHit).not.toHaveBeenCalled();
149
+ });
150
+ it('should fetch hit with metadata when dossiers are not present', async () => {
151
+ const { has } = await import('lodash-es');
152
+ has.mockReturnValue(false);
153
+ const hitWithFetchedMetadata = { ...mockHit, __dossiers: mockDossiers };
154
+ mockGetHit.mockResolvedValue(hitWithFetchedMetadata);
155
+ const { result } = renderHook(() => useMatchers());
156
+ const dossiers = await result.current.getMatchingDossiers(mockHit);
157
+ expect(dossiers).toBe(mockDossiers);
158
+ expect(mockGetHit).toHaveBeenCalledWith('test-hit-id', true);
159
+ });
160
+ it('should handle getHit rejection gracefully', async () => {
161
+ const { has } = await import('lodash-es');
162
+ has.mockReturnValue(false);
163
+ mockGetHit.mockRejectedValue(new Error('Failed to fetch hit'));
164
+ const { result } = renderHook(() => useMatchers());
165
+ await expect(result.current.getMatchingDossiers(mockHit)).rejects.toThrow('Failed to fetch hit');
166
+ expect(mockGetHit).toHaveBeenCalledWith('test-hit-id', true);
167
+ });
168
+ });
169
+ describe('integration tests', () => {
170
+ it('should correctly handle has function calls for different metadata properties', async () => {
171
+ const { has } = await import('lodash-es');
172
+ // Mock has to return true for __template, false for others
173
+ has.mockImplementation((_obj, prop) => {
174
+ return prop === '__template';
175
+ });
176
+ const hitWithPartialMetadata = {
177
+ ...mockHit,
178
+ __template: mockTemplate
179
+ };
180
+ mockGetHit.mockResolvedValue({
181
+ ...mockHit,
182
+ __overview: mockOverview,
183
+ __dossiers: mockDossiers
184
+ });
185
+ const { result } = renderHook(() => useMatchers());
186
+ // Should return template from metadata
187
+ const template = await result.current.getMatchingTemplate(hitWithPartialMetadata);
188
+ expect(template).toBe(mockTemplate);
189
+ // Should fetch overview
190
+ const overview = await result.current.getMatchingOverview(hitWithPartialMetadata);
191
+ expect(overview).toBe(mockOverview);
192
+ // Should fetch dossiers
193
+ const dossiers = await result.current.getMatchingDossiers(hitWithPartialMetadata);
194
+ expect(dossiers).toBe(mockDossiers);
195
+ // Verify has was called with correct parameters
196
+ expect(has).toHaveBeenCalledWith(hitWithPartialMetadata, '__template');
197
+ expect(has).toHaveBeenCalledWith(hitWithPartialMetadata, '__overview');
198
+ expect(has).toHaveBeenCalledWith(hitWithPartialMetadata, '__dossiers');
199
+ });
200
+ it('should handle empty or undefined metadata gracefully', async () => {
201
+ const { has } = await import('lodash-es');
202
+ has.mockReturnValue(false);
203
+ mockGetHit.mockResolvedValue({
204
+ ...mockHit,
205
+ __template: undefined,
206
+ __overview: null,
207
+ __dossiers: []
208
+ });
209
+ const { result } = renderHook(() => useMatchers());
210
+ const template = await result.current.getMatchingTemplate(mockHit);
211
+ const overview = await result.current.getMatchingOverview(mockHit);
212
+ const dossiers = await result.current.getMatchingDossiers(mockHit);
213
+ expect(template).toBeUndefined();
214
+ expect(overview).toBeNull();
215
+ expect(dossiers).toEqual([]);
216
+ expect(mockGetHit).toHaveBeenCalledTimes(3);
217
+ });
218
+ it('should maintain referential equality of returned functions', () => {
219
+ const { result, rerender } = renderHook(() => useMatchers());
220
+ const firstRender = {
221
+ getMatchingTemplate: result.current.getMatchingTemplate,
222
+ getMatchingOverview: result.current.getMatchingOverview,
223
+ getMatchingDossiers: result.current.getMatchingDossiers
224
+ };
225
+ rerender();
226
+ const secondRender = {
227
+ getMatchingTemplate: result.current.getMatchingTemplate,
228
+ getMatchingOverview: result.current.getMatchingOverview,
229
+ getMatchingDossiers: result.current.getMatchingDossiers
230
+ };
231
+ // Functions should be the same reference due to useCallback
232
+ expect(firstRender.getMatchingTemplate).toBe(secondRender.getMatchingTemplate);
233
+ expect(firstRender.getMatchingOverview).toBe(secondRender.getMatchingOverview);
234
+ expect(firstRender.getMatchingDossiers).toBe(secondRender.getMatchingDossiers);
235
+ });
236
+ });
237
+ });
@@ -6,7 +6,8 @@ const ApiConfigProvider = ({ children }) => {
6
6
  indexes: null,
7
7
  lookups: null,
8
8
  configuration: null,
9
- c12nDef: null
9
+ c12nDef: null,
10
+ mapping: null
10
11
  });
11
12
  const context = useMemo(() => ({
12
13
  config,
@@ -53,7 +53,7 @@ const InformationPane = ({ onClose }) => {
53
53
  const getHit = useContextSelector(HitContext, ctx => ctx.getHit);
54
54
  const [userIds, setUserIds] = useState(new Set());
55
55
  const [analytic, setAnalytic] = useState();
56
- const [overview, setOverview] = useState();
56
+ const [hasOverview, setHasOverview] = useState(false);
57
57
  const [tab, setTab] = useState('overview');
58
58
  const [loading, setLoading] = useState(false);
59
59
  const [dossiers, setDossiers] = useState([]);
@@ -62,6 +62,9 @@ const InformationPane = ({ onClose }) => {
62
62
  howlerPluginStore.plugins.forEach(plugin => {
63
63
  pluginStore.executeFunction(`${plugin}.on`, 'viewing');
64
64
  });
65
+ useEffect(() => {
66
+ getMatchingOverview(hit).then(_overview => setHasOverview(!!_overview));
67
+ }, [getMatchingOverview, hit]);
65
68
  useEffect(() => {
66
69
  if (!selected) {
67
70
  return;
@@ -73,7 +76,6 @@ const InformationPane = ({ onClose }) => {
73
76
  }
74
77
  setUserIds(getUserList(hit));
75
78
  getAnalyticFromName(hit.howler.analytic).then(setAnalytic);
76
- getMatchingOverview(hit).then(setOverview);
77
79
  getMatchingDossiers(hit).then(setDossiers);
78
80
  // eslint-disable-next-line react-hooks/exhaustive-deps
79
81
  }, [getAnalyticFromName, getHit, selected]);
@@ -97,14 +99,14 @@ const InformationPane = ({ onClose }) => {
97
99
  }
98
100
  }, [emit, selected, isOpen]);
99
101
  useEffect(() => {
100
- if (overview && tab === 'details') {
102
+ if (hasOverview && tab === 'details') {
101
103
  setTab('overview');
102
104
  }
103
- else if (!overview && tab === 'overview') {
105
+ else if (!hasOverview && tab === 'overview') {
104
106
  setTab('details');
105
107
  }
106
108
  // eslint-disable-next-line react-hooks/exhaustive-deps
107
- }, [overview]);
109
+ }, [hasOverview]);
108
110
  /**
109
111
  * What to show as the header? If loading a skeleton, then it depends on bundle or not. Bundles don't
110
112
  * show anything while normal hits do
@@ -149,7 +151,7 @@ const InformationPane = ({ onClose }) => {
149
151
  .slice(0, 3)
150
152
  .map(l => _jsx(RelatedLink, { compact: true, ...l }, l.href)), dossiers.flatMap(_dossier => (_dossier.pivots ?? []).map((_pivot, index) => (
151
153
  // eslint-disable-next-line react/no-array-index-key
152
- _jsx(PivotLink, { pivot: _pivot, hit: hit, compact: true }, _dossier.dossier_id + index))))] })), _jsx(VSBoxHeader, { ml: -1, mr: -1, pb: 1, sx: { top: '0px' }, children: _jsxs(Tabs, { value: tab === 'overview' && !overview ? 'details' : tab, sx: {
154
+ _jsx(PivotLink, { pivot: _pivot, hit: hit, compact: true }, _dossier.dossier_id + index))))] })), _jsx(VSBoxHeader, { ml: -1, mr: -1, pb: 1, sx: { top: '0px' }, children: _jsxs(Tabs, { value: tab === 'overview' && !hasOverview ? 'details' : tab, sx: {
153
155
  display: 'flex',
154
156
  flexDirection: 'row',
155
157
  pr: 2,
@@ -178,7 +180,7 @@ const InformationPane = ({ onClose }) => {
178
180
  right: theme.spacing(-0.5)
179
181
  },
180
182
  '& > svg': { zIndex: 2 }
181
- }, badgeContent: hit?.howler.comment?.length ?? 0, children: _jsx(Comment, {}) }) }), value: "hit_comments", onClick: () => setTab('hit_comments') }), hit?.howler?.is_bundle && (_jsx(Tab, { label: t('hit.viewer.aggregate'), value: "hit_aggregate", onClick: () => setTab('hit_aggregate') })), overview && _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
183
+ }, badgeContent: hit?.howler.comment?.length ?? 0, children: _jsx(Comment, {}) }) }), value: "hit_comments", onClick: () => setTab('hit_comments') }), hit?.howler?.is_bundle && (_jsx(Tab, { label: t('hit.viewer.aggregate'), value: "hit_aggregate", onClick: () => setTab('hit_aggregate') })), 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
182
184
  // eslint-disable-next-line react/no-array-index-key
183
185
  , { 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
184
186
  // eslint-disable-next-line react/no-array-index-key
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Close, ErrorOutline, List, TableChart, Terminal } from '@mui/icons-material';
2
+ import { Close, ErrorOutline, List, SavedSearch, TableChart, Terminal } from '@mui/icons-material';
3
3
  import { Box, IconButton, LinearProgress, Stack, ToggleButton, ToggleButtonGroup, Tooltip, Typography, useMediaQuery, useTheme } from '@mui/material';
4
4
  import { grey } from '@mui/material/colors';
5
5
  import AppListEmpty from '@cccsaurora/howler-ui/commons/components/display/AppListEmpty';
@@ -120,7 +120,7 @@ const SearchPane = () => {
120
120
  ], onClick: () => {
121
121
  clearSelectedHits(bundleHit.howler.id);
122
122
  setSelected(bundleHit.howler.id);
123
- }, children: _jsx(HitBanner, { hit: bundleHit, layout: HitLayout.DENSE, useListener: true }) }) }) }) })), _jsxs(Stack, { direction: "row", spacing: 1, alignItems: "center", children: [_jsx(Typography, { sx: { color: 'text.secondary', fontSize: '0.9em', fontStyle: 'italic', mb: 0.5 }, variant: "body2", children: t('hit.search.prompt') }), error && (_jsx(Tooltip, { title: `${t('route.advanced.error')}: ${error}`, children: _jsx(ErrorOutline, { fontSize: "small", color: "error" }) })), _jsx(FlexOne, {}), bundleHit?.howler.bundles.length > 0 && _jsx(BundleParentMenu, { bundle: bundleHit }), bundleHit && (_jsx(Tooltip, { title: t('hit.bundle.close'), children: _jsx(IconButton, { size: "small", onClick: () => navigate('/search'), children: _jsx(Close, {}) }) })), _jsx(Tooltip, { title: t('route.actions.save'), children: _jsx(IconButton, { component: Link, disabled: !query, to: `/action/execute?query=${query}`, children: _jsx(Terminal, {}) }) }), _jsxs(ToggleButtonGroup, { exclusive: true, value: displayType, onChange: (__, value) => setDisplayType(value), size: "small", children: [_jsx(ToggleButton, { value: "list", children: _jsx(List, {}) }), _jsx(ToggleButton, { value: "grid", children: _jsx(TableChart, {}) })] })] })] }), _jsxs(VSBoxHeader, { ml: -3, mr: -3, px: 2, pb: 1, sx: { zIndex: 999 }, children: [_jsxs(Stack, { sx: { pt: 1 }, children: [_jsxs(Stack, { sx: { position: 'relative', flex: 1 }, children: [_jsx(HitQuery, { disabled: viewId && !selectedView, searching: searching, triggerSearch: triggerSearch }), searching && (_jsx(LinearProgress, { sx: theme => ({
123
+ }, children: _jsx(HitBanner, { hit: bundleHit, layout: HitLayout.DENSE, useListener: true }) }) }) }) })), _jsxs(Stack, { direction: "row", spacing: 1, alignItems: "center", children: [_jsx(Typography, { sx: { color: 'text.secondary', fontSize: '0.9em', fontStyle: 'italic', mb: 0.5 }, variant: "body2", children: t('hit.search.prompt') }), error && (_jsx(Tooltip, { title: `${t('route.advanced.error')}: ${error}`, children: _jsx(ErrorOutline, { fontSize: "small", color: "error" }) })), _jsx(FlexOne, {}), bundleHit?.howler.bundles.length > 0 && _jsx(BundleParentMenu, { bundle: bundleHit }), bundleHit && (_jsx(Tooltip, { title: t('hit.bundle.close'), children: _jsx(IconButton, { size: "small", onClick: () => navigate('/search'), children: _jsx(Close, {}) }) })), _jsx(Tooltip, { title: t('route.views.save'), children: _jsx(IconButton, { component: Link, disabled: !query, to: `/views/create?query=${query}`, children: _jsx(SavedSearch, {}) }) }), _jsx(Tooltip, { title: t('route.actions.save'), children: _jsx(IconButton, { component: Link, disabled: !query, to: `/action/execute?query=${query}`, children: _jsx(Terminal, {}) }) }), _jsxs(ToggleButtonGroup, { exclusive: true, value: displayType, onChange: (__, value) => setDisplayType(value), size: "small", children: [_jsx(ToggleButton, { value: "list", children: _jsx(List, {}) }), _jsx(ToggleButton, { value: "grid", children: _jsx(TableChart, {}) })] })] })] }), _jsxs(VSBoxHeader, { ml: -3, mr: -3, px: 2, pb: 1, sx: { zIndex: 999 }, children: [_jsxs(Stack, { sx: { pt: 1 }, children: [_jsxs(Stack, { sx: { position: 'relative', flex: 1 }, children: [_jsx(HitQuery, { disabled: viewId && !selectedView, searching: searching, triggerSearch: triggerSearch }), searching && (_jsx(LinearProgress, { sx: theme => ({
124
124
  position: 'absolute',
125
125
  left: 0,
126
126
  right: 0,
@@ -639,6 +639,7 @@
639
639
  "route.views.manager.search": "Search Views",
640
640
  "route.views.manager.default": "Default View",
641
641
  "route.views.name": "View Name",
642
+ "route.views.save": "Save Query as View",
642
643
  "route.views.saved": "Pinned Views",
643
644
  "route.views.search.prompt": "Search by name, query, or owner.",
644
645
  "search.open": "Open Search",
@@ -635,6 +635,7 @@
635
635
  "route.views.manager.readonly": "Intégré",
636
636
  "route.views.manager.search": "Rechercher les vues",
637
637
  "route.views.manager": "Gérer vue",
638
+ "route.views.save": "Enregistrer cette requête comme vue",
638
639
  "route.views.saved": "Vues épinglées",
639
640
  "route.views.show": "Voir les vues",
640
641
  "route.views": "Vues",
@@ -113,6 +113,7 @@ export interface APIConfiguration {
113
113
  classification: string;
114
114
  }[];
115
115
  };
116
+ mapping: APIMappings;
116
117
  features: {
117
118
  borealis: boolean;
118
119
  notebook: boolean;
@@ -257,9 +258,15 @@ export interface APIC12Ndef {
257
258
  UNRESTRICTED: string;
258
259
  RESTRICTED: string;
259
260
  }
261
+ export interface APIMappings {
262
+ mapping: {
263
+ [index: string]: string;
264
+ };
265
+ }
260
266
  export interface ApiType {
261
267
  indexes: APIIndexes;
262
268
  lookups: APILookups;
263
269
  configuration: APIConfiguration;
264
270
  c12nDef: APIC12Ndef;
271
+ mapping: APIMappings;
265
272
  }
package/package.json CHANGED
@@ -96,162 +96,162 @@
96
96
  "internal-slot": "1.0.7"
97
97
  },
98
98
  "type": "module",
99
- "version": "2.13.0-dev.110",
99
+ "version": "2.13.0-dev.129",
100
100
  "exports": {
101
101
  "./i18n": "./i18n.js",
102
102
  "./index.css": "./index.css",
103
- "./models/*": "./models/*.js",
104
- "./branding/*": "./branding/*.js",
103
+ "./api/*": "./api/*.js",
104
+ "./api": "./api/index.js",
105
105
  "./commons/*": "./commons/*.js",
106
- "./utils/*": "./utils/*.js",
107
- "./utils/*.json": "./utils/*.json",
108
106
  "./rest/*": "./rest/*.js",
109
107
  "./rest": "./rest/index.js",
108
+ "./locales/*.json": "./locales/*.json",
109
+ "./branding/*": "./branding/*.js",
110
110
  "./components/*": "./components/*.js",
111
+ "./models/*": "./models/*.js",
112
+ "./utils/*": "./utils/*.js",
113
+ "./utils/*.json": "./utils/*.json",
111
114
  "./plugins/*": "./plugins/*.js",
112
- "./api/*": "./api/*.js",
113
- "./api": "./api/index.js",
114
- "./locales/*.json": "./locales/*.json",
115
- "./models/socket/*": "./models/socket/*.js",
116
- "./models/entities/*": "./models/entities/*.js",
117
- "./models/entities/generated/*": "./models/entities/generated/*.js",
115
+ "./api/analytic/*": "./api/analytic/*.js",
116
+ "./api/analytic": "./api/analytic/index.js",
117
+ "./api/configs/*": "./api/configs/*.js",
118
+ "./api/configs": "./api/configs/index.js",
119
+ "./api/dossier/*": "./api/dossier/*.js",
120
+ "./api/dossier": "./api/dossier/index.js",
121
+ "./api/user/*": "./api/user/*.js",
122
+ "./api/user": "./api/user/index.js",
123
+ "./api/notebook/*": "./api/notebook/*.js",
124
+ "./api/notebook": "./api/notebook/index.js",
125
+ "./api/action/*": "./api/action/*.js",
126
+ "./api/action": "./api/action/index.js",
127
+ "./api/auth/*": "./api/auth/*.js",
128
+ "./api/auth": "./api/auth/index.js",
129
+ "./api/search/*": "./api/search/*.js",
130
+ "./api/search": "./api/search/index.js",
131
+ "./api/view/*": "./api/view/*.js",
132
+ "./api/view": "./api/view/index.js",
133
+ "./api/overview/*": "./api/overview/*.js",
134
+ "./api/overview": "./api/overview/index.js",
135
+ "./api/hit/*": "./api/hit/*.js",
136
+ "./api/hit": "./api/hit/index.js",
137
+ "./api/template/*": "./api/template/*.js",
138
+ "./api/template": "./api/template/index.js",
139
+ "./api/analytic/notebooks/*": "./api/analytic/notebooks/*.js",
140
+ "./api/analytic/notebooks": "./api/analytic/notebooks/index.js",
141
+ "./api/analytic/comments/*": "./api/analytic/comments/*.js",
142
+ "./api/analytic/comments": "./api/analytic/comments/index.js",
143
+ "./api/user/avatar/*": "./api/user/avatar/*.js",
144
+ "./api/user/avatar": "./api/user/avatar/index.js",
145
+ "./api/search/fields/*": "./api/search/fields/*.js",
146
+ "./api/search/fields": "./api/search/fields/index.js",
147
+ "./api/search/sigma/*": "./api/search/sigma/*.js",
148
+ "./api/search/histogram/*": "./api/search/histogram/*.js",
149
+ "./api/search/histogram": "./api/search/histogram/index.js",
150
+ "./api/search/grouped/*": "./api/search/grouped/*.js",
151
+ "./api/search/grouped": "./api/search/grouped/index.js",
152
+ "./api/search/count/*": "./api/search/count/*.js",
153
+ "./api/search/count": "./api/search/count/index.js",
154
+ "./api/search/eql/*": "./api/search/eql/*.js",
155
+ "./api/search/facet/*": "./api/search/facet/*.js",
156
+ "./api/search/facet": "./api/search/facet/index.js",
157
+ "./api/hit/comments/*": "./api/hit/comments/*.js",
158
+ "./api/hit/comments": "./api/hit/comments/index.js",
118
159
  "./commons/components/*": "./commons/components/*.js",
119
- "./commons/components/notification/*": "./commons/components/notification/*.js",
120
- "./commons/components/notification": "./commons/components/notification/index.js",
121
- "./commons/components/search/*": "./commons/components/search/*.js",
122
- "./commons/components/display/*": "./commons/components/display/*.js",
123
160
  "./commons/components/breadcrumbs/*": "./commons/components/breadcrumbs/*.js",
124
161
  "./commons/components/app/*": "./commons/components/app/*.js",
125
- "./commons/components/utils/*": "./commons/components/utils/*.js",
162
+ "./commons/components/notification/*": "./commons/components/notification/*.js",
163
+ "./commons/components/notification": "./commons/components/notification/index.js",
126
164
  "./commons/components/topnav/*": "./commons/components/topnav/*.js",
127
165
  "./commons/components/pages/*": "./commons/components/pages/*.js",
166
+ "./commons/components/display/*": "./commons/components/display/*.js",
167
+ "./commons/components/utils/*": "./commons/components/utils/*.js",
128
168
  "./commons/components/leftnav/*": "./commons/components/leftnav/*.js",
129
- "./commons/components/notification/elements/*": "./commons/components/notification/elements/*.js",
130
- "./commons/components/notification/elements/item/*": "./commons/components/notification/elements/item/*.js",
131
- "./commons/components/display/hooks/*": "./commons/components/display/hooks/*.js",
169
+ "./commons/components/search/*": "./commons/components/search/*.js",
132
170
  "./commons/components/app/hooks/*": "./commons/components/app/hooks/*.js",
133
171
  "./commons/components/app/hooks": "./commons/components/app/hooks/index.js",
134
172
  "./commons/components/app/providers/*": "./commons/components/app/providers/*.js",
135
- "./commons/components/utils/hooks/*": "./commons/components/utils/hooks/*.js",
173
+ "./commons/components/notification/elements/*": "./commons/components/notification/elements/*.js",
174
+ "./commons/components/notification/elements/item/*": "./commons/components/notification/elements/item/*.js",
136
175
  "./commons/components/pages/hooks/*": "./commons/components/pages/hooks/*.js",
176
+ "./commons/components/display/hooks/*": "./commons/components/display/hooks/*.js",
177
+ "./commons/components/utils/hooks/*": "./commons/components/utils/hooks/*.js",
178
+ "./locales/en/*.json": "./locales/en/*.json",
179
+ "./locales/fr/*.json": "./locales/fr/*.json",
180
+ "./locales/en/help/*.json": "./locales/en/help/*.json",
181
+ "./locales/fr/help/*.json": "./locales/fr/help/*.json",
182
+ "./components/app/*": "./components/app/*.js",
137
183
  "./components/hooks/*": "./components/hooks/*.js",
138
184
  "./components/elements/*": "./components/elements/*.js",
139
- "./components/app/*": "./components/app/*.js",
140
185
  "./components/routes/*": "./components/routes/*.js",
141
186
  "./components/logins/*": "./components/logins/*.js",
187
+ "./components/app/hooks/*": "./components/app/hooks/*.js",
188
+ "./components/app/drawers/*": "./components/app/drawers/*.js",
189
+ "./components/app/providers/*": "./components/app/providers/*.js",
190
+ "./components/elements/addons/*": "./components/elements/addons/*.js",
142
191
  "./components/elements/display/*": "./components/elements/display/*.js",
143
192
  "./components/elements/view/*": "./components/elements/view/*.js",
144
- "./components/elements/addons/*": "./components/elements/addons/*.js",
145
193
  "./components/elements/hit/*": "./components/elements/hit/*.js",
146
- "./components/elements/display/handlebars/*": "./components/elements/display/handlebars/*.js",
147
- "./components/elements/display/features/*": "./components/elements/display/features/*.js",
148
- "./components/elements/display/json/*": "./components/elements/display/json/*.js",
149
- "./components/elements/display/modals/*": "./components/elements/display/modals/*.js",
150
- "./components/elements/display/icons/*": "./components/elements/display/icons/*.js",
151
- "./components/elements/display/markdownPlugins/*.md": "./components/elements/display/markdownPlugins/*.md.js",
152
- "./components/elements/display/icons/svg/*": "./components/elements/display/icons/svg/*.js",
153
- "./components/elements/addons/search/*": "./components/elements/addons/search/*.js",
194
+ "./components/elements/addons/lists/*": "./components/elements/addons/lists/*.js",
195
+ "./components/elements/addons/lists": "./components/elements/addons/lists/index.js",
154
196
  "./components/elements/addons/buttons/*": "./components/elements/addons/buttons/*.js",
155
197
  "./components/elements/addons/buttons": "./components/elements/addons/buttons/index.js",
156
198
  "./components/elements/addons/layout/*": "./components/elements/addons/layout/*.js",
157
- "./components/elements/addons/lists/*": "./components/elements/addons/lists/*.js",
158
- "./components/elements/addons/lists": "./components/elements/addons/lists/index.js",
199
+ "./components/elements/addons/search/*": "./components/elements/addons/search/*.js",
200
+ "./components/elements/addons/lists/hooks/*": "./components/elements/addons/lists/hooks/*.js",
201
+ "./components/elements/addons/lists/table/*": "./components/elements/addons/lists/table/*.js",
202
+ "./components/elements/addons/lists/table": "./components/elements/addons/lists/table/index.js",
203
+ "./components/elements/addons/layout/vsbox/*": "./components/elements/addons/layout/vsbox/*.js",
159
204
  "./components/elements/addons/search/phrase/*": "./components/elements/addons/search/phrase/*.js",
160
205
  "./components/elements/addons/search/phrase": "./components/elements/addons/search/phrase/index.js",
161
206
  "./components/elements/addons/search/phrase/word/*": "./components/elements/addons/search/phrase/word/*.js",
162
207
  "./components/elements/addons/search/phrase/word/consumers/*": "./components/elements/addons/search/phrase/word/consumers/*.js",
163
- "./components/elements/addons/layout/vsbox/*": "./components/elements/addons/layout/vsbox/*.js",
164
- "./components/elements/addons/lists/hooks/*": "./components/elements/addons/lists/hooks/*.js",
165
- "./components/elements/addons/lists/table/*": "./components/elements/addons/lists/table/*.js",
166
- "./components/elements/addons/lists/table": "./components/elements/addons/lists/table/index.js",
167
- "./components/elements/hit/aggregate/*": "./components/elements/hit/aggregate/*.js",
168
- "./components/elements/hit/actions/*": "./components/elements/hit/actions/*.js",
208
+ "./components/elements/display/features/*": "./components/elements/display/features/*.js",
209
+ "./components/elements/display/markdownPlugins/*.md": "./components/elements/display/markdownPlugins/*.md.js",
210
+ "./components/elements/display/icons/*": "./components/elements/display/icons/*.js",
211
+ "./components/elements/display/handlebars/*": "./components/elements/display/handlebars/*.js",
212
+ "./components/elements/display/modals/*": "./components/elements/display/modals/*.js",
213
+ "./components/elements/display/json/*": "./components/elements/display/json/*.js",
214
+ "./components/elements/display/icons/svg/*": "./components/elements/display/icons/svg/*.js",
169
215
  "./components/elements/hit/related/*": "./components/elements/hit/related/*.js",
216
+ "./components/elements/hit/aggregate/*": "./components/elements/hit/aggregate/*.js",
170
217
  "./components/elements/hit/elements/*": "./components/elements/hit/elements/*.js",
218
+ "./components/elements/hit/actions/*": "./components/elements/hit/actions/*.js",
171
219
  "./components/elements/hit/outlines/*": "./components/elements/hit/outlines/*.js",
172
220
  "./components/elements/hit/outlines/al/*": "./components/elements/hit/outlines/al/*.js",
173
- "./components/app/hooks/*": "./components/app/hooks/*.js",
174
- "./components/app/drawers/*": "./components/app/drawers/*.js",
175
- "./components/app/providers/*": "./components/app/providers/*.js",
176
221
  "./components/routes/home/*": "./components/routes/home/*.js",
177
222
  "./components/routes/home": "./components/routes/home/index.js",
178
- "./components/routes/dossiers/*": "./components/routes/dossiers/*.js",
179
223
  "./components/routes/views/*": "./components/routes/views/*.js",
180
- "./components/routes/action/*": "./components/routes/action/*.js",
181
- "./components/routes/overviews/*": "./components/routes/overviews/*.js",
224
+ "./components/routes/hits/*": "./components/routes/hits/*.js",
225
+ "./components/routes/advanced/*": "./components/routes/advanced/*.js",
182
226
  "./components/routes/admin/*": "./components/routes/admin/*.js",
227
+ "./components/routes/dossiers/*": "./components/routes/dossiers/*.js",
228
+ "./components/routes/templates/*": "./components/routes/templates/*.js",
229
+ "./components/routes/action/*": "./components/routes/action/*.js",
183
230
  "./components/routes/settings/*": "./components/routes/settings/*.js",
231
+ "./components/routes/overviews/*": "./components/routes/overviews/*.js",
184
232
  "./components/routes/help/*": "./components/routes/help/*.js",
185
- "./components/routes/hits/*": "./components/routes/hits/*.js",
186
233
  "./components/routes/analytics/*": "./components/routes/analytics/*.js",
187
- "./components/routes/advanced/*": "./components/routes/advanced/*.js",
188
- "./components/routes/templates/*": "./components/routes/templates/*.js",
189
- "./components/routes/action/view/*": "./components/routes/action/view/*.js",
190
- "./components/routes/action/shared/*": "./components/routes/action/shared/*.js",
191
- "./components/routes/action/edit/*": "./components/routes/action/edit/*.js",
192
- "./components/routes/admin/users/*": "./components/routes/admin/users/*.js",
193
- "./components/routes/help/components/*": "./components/routes/help/components/*.js",
194
- "./components/routes/help/markdown/*.md": "./components/routes/help/markdown/*.md.js",
195
- "./components/routes/help/markdown/en/*.md": "./components/routes/help/markdown/en/*.md.js",
196
- "./components/routes/help/markdown/fr/*.md": "./components/routes/help/markdown/fr/*.md.js",
197
234
  "./components/routes/hits/search/*": "./components/routes/hits/search/*.js",
198
235
  "./components/routes/hits/view/*": "./components/routes/hits/view/*.js",
199
236
  "./components/routes/hits/search/grid/*": "./components/routes/hits/search/grid/*.js",
200
237
  "./components/routes/hits/search/shared/*": "./components/routes/hits/search/shared/*.js",
238
+ "./components/routes/admin/users/*": "./components/routes/admin/users/*.js",
239
+ "./components/routes/action/edit/*": "./components/routes/action/edit/*.js",
240
+ "./components/routes/action/shared/*": "./components/routes/action/shared/*.js",
241
+ "./components/routes/action/view/*": "./components/routes/action/view/*.js",
242
+ "./components/routes/help/markdown/*.md": "./components/routes/help/markdown/*.md.js",
243
+ "./components/routes/help/components/*": "./components/routes/help/components/*.js",
244
+ "./components/routes/help/markdown/en/*.md": "./components/routes/help/markdown/en/*.md.js",
245
+ "./components/routes/help/markdown/fr/*.md": "./components/routes/help/markdown/fr/*.md.js",
201
246
  "./components/routes/analytics/widgets/*": "./components/routes/analytics/widgets/*.js",
202
247
  "./components/logins/hooks/*": "./components/logins/hooks/*.js",
203
248
  "./components/logins/auth/*": "./components/logins/auth/*.js",
249
+ "./models/socket/*": "./models/socket/*.js",
250
+ "./models/entities/*": "./models/entities/*.js",
251
+ "./models/entities/generated/*": "./models/entities/generated/*.js",
204
252
  "./plugins/borealis/*": "./plugins/borealis/*.js",
205
253
  "./plugins/borealis": "./plugins/borealis/index.js",
206
- "./plugins/borealis/components/*": "./plugins/borealis/components/*.js",
207
254
  "./plugins/borealis/locales/*": "./plugins/borealis/locales/*.js",
208
- "./api/search/*": "./api/search/*.js",
209
- "./api/search": "./api/search/index.js",
210
- "./api/analytic/*": "./api/analytic/*.js",
211
- "./api/analytic": "./api/analytic/index.js",
212
- "./api/auth/*": "./api/auth/*.js",
213
- "./api/auth": "./api/auth/index.js",
214
- "./api/template/*": "./api/template/*.js",
215
- "./api/template": "./api/template/index.js",
216
- "./api/view/*": "./api/view/*.js",
217
- "./api/view": "./api/view/index.js",
218
- "./api/action/*": "./api/action/*.js",
219
- "./api/action": "./api/action/index.js",
220
- "./api/user/*": "./api/user/*.js",
221
- "./api/user": "./api/user/index.js",
222
- "./api/overview/*": "./api/overview/*.js",
223
- "./api/overview": "./api/overview/index.js",
224
- "./api/configs/*": "./api/configs/*.js",
225
- "./api/configs": "./api/configs/index.js",
226
- "./api/dossier/*": "./api/dossier/*.js",
227
- "./api/dossier": "./api/dossier/index.js",
228
- "./api/hit/*": "./api/hit/*.js",
229
- "./api/hit": "./api/hit/index.js",
230
- "./api/notebook/*": "./api/notebook/*.js",
231
- "./api/notebook": "./api/notebook/index.js",
232
- "./api/search/grouped/*": "./api/search/grouped/*.js",
233
- "./api/search/grouped": "./api/search/grouped/index.js",
234
- "./api/search/sigma/*": "./api/search/sigma/*.js",
235
- "./api/search/histogram/*": "./api/search/histogram/*.js",
236
- "./api/search/histogram": "./api/search/histogram/index.js",
237
- "./api/search/eql/*": "./api/search/eql/*.js",
238
- "./api/search/facet/*": "./api/search/facet/*.js",
239
- "./api/search/facet": "./api/search/facet/index.js",
240
- "./api/search/fields/*": "./api/search/fields/*.js",
241
- "./api/search/fields": "./api/search/fields/index.js",
242
- "./api/search/count/*": "./api/search/count/*.js",
243
- "./api/search/count": "./api/search/count/index.js",
244
- "./api/analytic/notebooks/*": "./api/analytic/notebooks/*.js",
245
- "./api/analytic/notebooks": "./api/analytic/notebooks/index.js",
246
- "./api/analytic/comments/*": "./api/analytic/comments/*.js",
247
- "./api/analytic/comments": "./api/analytic/comments/index.js",
248
- "./api/user/avatar/*": "./api/user/avatar/*.js",
249
- "./api/user/avatar": "./api/user/avatar/index.js",
250
- "./api/hit/comments/*": "./api/hit/comments/*.js",
251
- "./api/hit/comments": "./api/hit/comments/index.js",
252
- "./locales/en/*.json": "./locales/en/*.json",
253
- "./locales/fr/*.json": "./locales/fr/*.json",
254
- "./locales/en/help/*.json": "./locales/en/help/*.json",
255
- "./locales/fr/help/*.json": "./locales/fr/help/*.json"
255
+ "./plugins/borealis/components/*": "./plugins/borealis/components/*.js"
256
256
  }
257
257
  }
@@ -1,10 +1,12 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Typography } from '@mui/material';
3
3
  import { EnrichedTypography, useBorealisEnrichSelector } from 'borealis-ui';
4
- import { memo } from 'react';
4
+ import { ApiConfigContext } from '@cccsaurora/howler-ui/components/app/providers/ApiConfigProvider';
5
+ import { memo, useContext } from 'react';
5
6
  const BorealisTypography = ({ children, value, context, ...props }) => {
6
7
  const guessType = useBorealisEnrichSelector(ctx => ctx.guessType);
7
- const type = guessType(value);
8
+ const { config } = useContext(ApiConfigContext);
9
+ const type = config?.configuration?.mapping?.[value] ?? guessType(value);
8
10
  if (!type) {
9
11
  return _jsx(Typography, { ...props, children: children });
10
12
  }
@@ -0,0 +1 @@
1
+ import '@testing-library/jest-dom/vitest';
package/setupTests.js ADDED
@@ -0,0 +1,8 @@
1
+ /// <reference types="vitest" />
2
+ import * as matchers from '@testing-library/jest-dom/matchers';
3
+ import '@testing-library/jest-dom/vitest';
4
+ import { configure } from '@testing-library/react';
5
+ // Extend vitest with the dom matchers from jest-dom.
6
+ expect.extend(matchers);
7
+ // tell React Testing Library to look for id as the testId.
8
+ configure({ testIdAttribute: 'id' });