@cccsaurora/howler-ui 2.15.0-dev.327 → 2.15.0-dev.333

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,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Close, Edit, SavedSearch } from '@mui/icons-material';
2
+ import { Close, Edit, Language, Lock, OpenInNew, Person, Refresh, SavedSearch } from '@mui/icons-material';
3
3
  import { Alert, IconButton, Stack, Tooltip, Typography } from '@mui/material';
4
4
  import { HitSearchContext } from '@cccsaurora/howler-ui/components/app/providers/HitSearchProvider';
5
5
  import { ParameterContext } from '@cccsaurora/howler-ui/components/app/providers/ParameterProvider';
@@ -15,6 +15,7 @@ const ViewLink = () => {
15
15
  const sort = useContextSelector(ParameterContext, ctx => ctx.sort);
16
16
  const span = useContextSelector(ParameterContext, ctx => ctx.span);
17
17
  const viewId = useContextSelector(HitSearchContext, ctx => ctx.viewId);
18
+ const search = useContextSelector(HitSearchContext, ctx => ctx.search);
18
19
  const viewsReady = useContextSelector(ViewContext, ctx => has(ctx.views, viewId));
19
20
  const selectedView = useContextSelector(ViewContext, ctx => ctx.views[viewId]);
20
21
  const viewUrl = useMemo(() => {
@@ -33,10 +34,14 @@ const ViewLink = () => {
33
34
  }
34
35
  return keys.length > 0 ? `/views/create?${keys.join('&')}` : '/views/create';
35
36
  }, [query, sort, span, viewId]);
36
- const viewButton = useMemo(() => (_jsx(Tooltip, { title: viewId ? t('route.views.edit') : t('route.views.create'), children: _jsx(IconButton, { size: "small", component: Link, disabled: (!viewId && !query) || span?.endsWith('custom'), to: viewUrl, children: viewId ? _jsx(Edit, { fontSize: "small" }) : _jsx(SavedSearch, {}) }) })), [query, span, t, viewId, viewUrl]);
37
+ const viewButton = useMemo(() => (_jsx(Tooltip, { title: viewId ? t('route.views.edit') : t('route.views.create'), children: _jsx(IconButton, { "aria-label": viewId ? t('route.views.edit') : t('route.views.create'), size: "small", component: Link, disabled: (!viewId && !query) || span?.endsWith('custom'), to: viewUrl, role: "link", children: viewId ? _jsx(Edit, { fontSize: "small" }) : _jsx(SavedSearch, {}) }) })), [query, span, t, viewId, viewUrl]);
37
38
  if (!viewId) {
38
39
  return null;
39
40
  }
40
- return selectedView ? (_jsxs(Stack, { direction: "row", spacing: 1, alignItems: "center", children: [_jsx(Tooltip, { title: selectedView.query, children: _jsx(Typography, { sx: { color: 'text.primary' }, variant: "body1", component: Link, to: `/views/${selectedView.view_id}/edit`, children: t(selectedView.title) }) }), viewButton] })) : (viewsReady && (_jsx(Alert, { variant: "outlined", severity: "error", action: _jsx(IconButton, { size: "small", component: Link, to: "/search", children: _jsx(Close, { fontSize: "small" }) }), children: t('view.notfound') })));
41
+ return selectedView ? (_jsxs(Stack, { direction: "row", spacing: 1, alignItems: "center", children: [_jsx(Tooltip, { title: t(`route.views.manager.${selectedView.type}`), children: {
42
+ readonly: _jsx(Lock, { fontSize: "small", "aria-label": t(`route.views.manager.${selectedView.type}`) }),
43
+ global: _jsx(Language, { fontSize: "small", "aria-label": t(`route.views.manager.${selectedView.type}`) }),
44
+ personal: _jsx(Person, { fontSize: "small", "aria-label": t(`route.views.manager.${selectedView.type}`) })
45
+ }[selectedView.type] }), _jsx(Tooltip, { title: selectedView.query, children: _jsx(Typography, { role: "link", sx: { color: 'text.primary' }, variant: "body1", component: Link, to: `/views/${selectedView.view_id}/edit`, "aria-label": `${t(selectedView.title)} - ${selectedView.query ?? t('unknown')}`, children: t(selectedView.title) }) }), viewButton, _jsx(Tooltip, { title: t('view.refresh'), children: _jsx(IconButton, { size: "small", onClick: () => search(query), "aria-label": t('view.refresh'), children: _jsx(Refresh, { fontSize: "small" }) }) }), _jsx(Tooltip, { title: t('view.open'), children: _jsx(IconButton, { size: "small", component: Link, to: `/search?query=${selectedView.query}`, "aria-label": t('view.open'), role: "link", children: _jsx(OpenInNew, { fontSize: "small" }) }) })] })) : (viewsReady && (_jsx(Alert, { role: "alert", variant: "outlined", severity: "error", "aria-live": "assertive", "aria-atomic": "true", action: _jsx(IconButton, { size: "small", component: Link, to: "/search", children: _jsx(Close, { fontSize: "small" }) }), children: t('view.notfound') })));
41
46
  };
42
47
  export default memo(ViewLink);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,375 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /* eslint-disable react/jsx-no-literals */
3
+ /* eslint-disable import/imports-first */
4
+ /// <reference types="vitest" />
5
+ import { fireEvent, render, screen } from '@testing-library/react';
6
+ import userEvent, {} from '@testing-library/user-event';
7
+ import React, { createContext, useContext } from 'react';
8
+ import { vi } from 'vitest';
9
+ globalThis.IS_REACT_ACT_ENVIRONMENT = true;
10
+ // Mock use-context-selector
11
+ vi.mock('use-context-selector', async () => {
12
+ return {
13
+ createContext,
14
+ useContextSelector: (context, selector) => {
15
+ return selector(useContext(context));
16
+ }
17
+ };
18
+ });
19
+ // Mock react-router-dom
20
+ vi.mock('react-router-dom', async () => {
21
+ const actual = await vi.importActual('react-router-dom');
22
+ return {
23
+ ...actual,
24
+ Link: React.forwardRef(({ to, children, ...props }, ref) => (_jsx("a", { ref: ref, href: to, ...props, children: children })))
25
+ };
26
+ });
27
+ // Import component after mocks
28
+ import { HitSearchContext } from '@cccsaurora/howler-ui/components/app/providers/HitSearchProvider';
29
+ import { ParameterContext } from '@cccsaurora/howler-ui/components/app/providers/ParameterProvider';
30
+ import { ViewContext } from '@cccsaurora/howler-ui/components/app/providers/ViewProvider';
31
+ import i18n from '@cccsaurora/howler-ui/i18n';
32
+ import { I18nextProvider } from 'react-i18next';
33
+ import { createMockView } from '@cccsaurora/howler-ui/tests/utils';
34
+ import ViewLink from './ViewLink';
35
+ // Mock contexts
36
+ const mockSearch = vi.fn();
37
+ let mockParameterContext = {
38
+ query: 'howler.id:*',
39
+ sort: 'event.created desc',
40
+ span: 'date.range.1.month',
41
+ setQuery: vi.fn(),
42
+ setSort: vi.fn(),
43
+ setSpan: vi.fn()
44
+ };
45
+ let mockHitSearchContext = {
46
+ viewId: 'test-view-id',
47
+ search: mockSearch
48
+ };
49
+ let mockViewContext = {
50
+ views: {
51
+ 'test-view-id': createMockView()
52
+ }
53
+ };
54
+ // Test wrapper
55
+ const Wrapper = ({ children }) => {
56
+ return (_jsx(I18nextProvider, { i18n: i18n, children: _jsx(ParameterContext.Provider, { value: mockParameterContext, children: _jsx(HitSearchContext.Provider, { value: mockHitSearchContext, children: _jsx(ViewContext.Provider, { value: mockViewContext, children: children }) }) }) }));
57
+ };
58
+ describe('ViewLink', () => {
59
+ let user;
60
+ beforeEach(() => {
61
+ user = userEvent.setup();
62
+ vi.clearAllMocks();
63
+ // Reset mock contexts to defaults
64
+ mockHitSearchContext.viewId = 'test-view-id';
65
+ mockParameterContext.query = 'howler.id:*';
66
+ mockParameterContext.sort = 'event.created desc';
67
+ mockParameterContext.span = 'date.range.1.month';
68
+ mockViewContext.views = {
69
+ 'test-view-id': createMockView()
70
+ };
71
+ });
72
+ describe('Rendering Conditions', () => {
73
+ it('should return null when viewId is not set', () => {
74
+ mockHitSearchContext.viewId = null;
75
+ const { container } = render(_jsx(ViewLink, {}), { wrapper: Wrapper });
76
+ expect(container.firstChild).toBeNull();
77
+ });
78
+ it('should return null when viewId is undefined', () => {
79
+ mockHitSearchContext.viewId = undefined;
80
+ const { container } = render(_jsx(ViewLink, {}), { wrapper: Wrapper });
81
+ expect(container.firstChild).toBeNull();
82
+ });
83
+ it('should render selected view UI when viewId exists and view is found', () => {
84
+ render(_jsx(ViewLink, {}), { wrapper: Wrapper });
85
+ expect(screen.getByText('Test View')).toBeInTheDocument();
86
+ });
87
+ it('should render error alert when viewId exists but view is not found', () => {
88
+ mockHitSearchContext = { ...mockHitSearchContext, viewId: 'non-existent-view' };
89
+ mockViewContext = {
90
+ ...mockViewContext,
91
+ views: {
92
+ ...mockViewContext.views,
93
+ 'non-existent-view': null
94
+ }
95
+ };
96
+ render(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
97
+ const alert = screen.getByRole('alert');
98
+ expect(alert).toBeInTheDocument();
99
+ expect(alert).toHaveAttribute('aria-live', 'assertive');
100
+ });
101
+ it('should not render error alert when views object is empty (not ready)', () => {
102
+ mockHitSearchContext.viewId = 'non-existent-view';
103
+ mockViewContext.views = {};
104
+ render(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
105
+ expect(screen.queryByRole('alert')).not.toBeInTheDocument();
106
+ });
107
+ });
108
+ describe('UI Element Display', () => {
109
+ it('should display view title as link with correct href', () => {
110
+ render(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
111
+ const titleLink = screen.getByText('Test View').closest('a');
112
+ expect(titleLink).toHaveAttribute('href', '/views/test-view-id/edit');
113
+ });
114
+ it('should display tooltip with view query on title', () => {
115
+ render(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
116
+ const tooltip = screen.getByText('Test View');
117
+ expect(tooltip).toHaveAttribute('aria-label', 'Test View - howler.status:open');
118
+ });
119
+ it('should display translated view title', () => {
120
+ mockViewContext.views['test-view-id'] = createMockView({
121
+ title: 'view.assigned_to_me'
122
+ });
123
+ render(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
124
+ // The i18n mock should translate this key
125
+ expect(screen.getByText(/assigned/i)).toBeInTheDocument();
126
+ });
127
+ it('should display edit icon when viewId exists', () => {
128
+ render(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
129
+ // Edit icon should be present (MUI Edit icon)
130
+ const editButton = screen.getByRole('link', { name: /edit /i });
131
+ expect(editButton).toBeInTheDocument();
132
+ });
133
+ it('should display refresh button when viewId exists', () => {
134
+ render(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
135
+ const refreshButton = screen.getByRole('button');
136
+ expect(refreshButton).toBeInTheDocument();
137
+ });
138
+ it('should display open button when viewId exists', () => {
139
+ render(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
140
+ const openLink = screen.getByRole('link', { name: /open /i });
141
+ expect(openLink).toBeInTheDocument();
142
+ expect(openLink).toHaveAttribute('href', '/search?query=howler.status:open');
143
+ });
144
+ it('should not display refresh button when viewId is null', () => {
145
+ mockHitSearchContext.viewId = null;
146
+ render(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
147
+ expect(screen.queryByRole('button')).not.toBeInTheDocument();
148
+ });
149
+ it('should not display open button when viewId is null', () => {
150
+ mockHitSearchContext.viewId = null;
151
+ render(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
152
+ expect(screen.queryByRole('link', { name: /open /i })).not.toBeInTheDocument();
153
+ });
154
+ });
155
+ describe('Button States & Interactions', () => {
156
+ it('should call search function when refresh button is clicked', async () => {
157
+ render(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
158
+ const refreshButton = screen.getByRole('button');
159
+ await user.click(refreshButton);
160
+ expect(mockSearch).toHaveBeenCalledWith('howler.id:*');
161
+ });
162
+ it('should navigate to search when open button is clicked', () => {
163
+ render(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
164
+ const openLink = screen.getByRole('link', { name: /open /i });
165
+ expect(openLink).toHaveAttribute('href', '/search?query=howler.status:open');
166
+ });
167
+ it('should navigate to /search when error alert close button is clicked', () => {
168
+ mockHitSearchContext = { ...mockHitSearchContext, viewId: 'non-existent-view' };
169
+ mockViewContext = {
170
+ ...mockViewContext,
171
+ views: {
172
+ ...mockViewContext.views,
173
+ 'non-existent-view': null
174
+ }
175
+ };
176
+ render(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
177
+ const closeButton = screen.getByRole('alert').querySelector('a');
178
+ expect(closeButton).toHaveAttribute('href', '/search');
179
+ });
180
+ it('should have correct tooltip on refresh button', () => {
181
+ render(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
182
+ const tooltip = screen.getByRole('button');
183
+ expect(tooltip).toHaveAttribute('aria-label', expect.stringContaining('Refresh'));
184
+ });
185
+ it('should have correct tooltip on open button', () => {
186
+ render(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
187
+ const openLink = screen.getByRole('link', { name: /open /i });
188
+ expect(openLink).toHaveAttribute('aria-label', expect.stringContaining('Open'));
189
+ });
190
+ });
191
+ describe('URL Generation (viewUrl)', () => {
192
+ it('should generate edit URL when viewId exists', () => {
193
+ render(_jsx(ViewLink, {}), { wrapper: Wrapper });
194
+ const editButton = screen.getByRole('link', { name: /edit/i });
195
+ expect(editButton).toHaveAttribute('href', '/views/test-view-id/edit');
196
+ });
197
+ it('should have edit tooltip when viewId exists', () => {
198
+ render(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
199
+ const editButton = screen.getByRole('link', { name: /edit/i });
200
+ expect(editButton).toHaveAttribute('aria-label', expect.stringContaining('Edit'));
201
+ });
202
+ });
203
+ describe('Edge Cases', () => {
204
+ it('should handle selectedView with missing title', () => {
205
+ mockViewContext.views['test-view-id'] = createMockView({
206
+ title: undefined
207
+ });
208
+ const { container } = render(_jsx(ViewLink, {}), { wrapper: Wrapper });
209
+ expect(container).toBeInTheDocument();
210
+ // Component should still render without crashing
211
+ });
212
+ it('should handle selectedView with missing query', () => {
213
+ mockViewContext.views['test-view-id'] = createMockView({
214
+ query: undefined
215
+ });
216
+ const { container } = render(_jsx(ViewLink, {}), { wrapper: Wrapper });
217
+ expect(container).toBeInTheDocument();
218
+ // Query tooltip should be empty or undefined
219
+ const tooltip = screen.getByText('Test View');
220
+ expect(tooltip).toHaveAttribute('aria-label', 'Test View - Unknown');
221
+ });
222
+ it('should handle rapid context changes', () => {
223
+ const { rerender } = render(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
224
+ // Change viewId
225
+ mockHitSearchContext = { ...mockHitSearchContext, viewId: 'another-view-id' };
226
+ mockViewContext = {
227
+ ...mockViewContext,
228
+ views: {
229
+ ...mockViewContext.views,
230
+ 'another-view-id': createMockView({
231
+ view_id: 'another-view-id',
232
+ title: 'Another View'
233
+ })
234
+ }
235
+ };
236
+ rerender(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
237
+ expect(screen.getByText('Another View')).toBeInTheDocument();
238
+ // Change back
239
+ mockHitSearchContext = { ...mockHitSearchContext, viewId: 'test-view-id' };
240
+ rerender(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
241
+ expect(screen.getByText('Test View')).toBeInTheDocument();
242
+ });
243
+ it('should handle undefined query in parameter context', () => {
244
+ mockParameterContext.query = undefined;
245
+ render(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
246
+ const refreshButton = screen.getByRole('button');
247
+ fireEvent.click(refreshButton);
248
+ expect(mockSearch).toHaveBeenCalledWith(undefined);
249
+ });
250
+ it('should handle null sort in parameter context', () => {
251
+ mockParameterContext.sort = null;
252
+ const { container } = render(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
253
+ expect(container).toBeInTheDocument();
254
+ });
255
+ it('should handle null span in parameter context', () => {
256
+ mockParameterContext.span = null;
257
+ const { container } = render(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
258
+ expect(container).toBeInTheDocument();
259
+ });
260
+ it('should handle view with all optional fields missing', () => {
261
+ mockViewContext.views['test-view-id'] = {
262
+ view_id: 'test-view-id'
263
+ };
264
+ const { container } = render(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
265
+ expect(container).toBeInTheDocument();
266
+ });
267
+ it('should handle empty views object', () => {
268
+ mockViewContext.views = {};
269
+ mockHitSearchContext.viewId = 'test-view-id';
270
+ render(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
271
+ // Should not render error alert because viewsReady is false
272
+ expect(screen.queryByRole('alert')).not.toBeInTheDocument();
273
+ });
274
+ });
275
+ describe('Integration Tests', () => {
276
+ it('should work with all three contexts simultaneously', () => {
277
+ render(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
278
+ // Should use values from ParameterContext
279
+ const refreshButton = screen.getByRole('button');
280
+ fireEvent.click(refreshButton);
281
+ expect(mockSearch).toHaveBeenCalledWith('howler.id:*');
282
+ // Should use values from ViewContext
283
+ expect(screen.getByText('Test View')).toBeInTheDocument();
284
+ // Should use values from HitSearchContext
285
+ const editButton = screen.getByRole('link', { name: /edit/i });
286
+ expect(editButton).toHaveAttribute('href', '/views/test-view-id/edit');
287
+ });
288
+ it('should render correctly with different view types', () => {
289
+ const viewTypes = ['personal', 'global', 'readonly'];
290
+ const { rerender } = render(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
291
+ viewTypes.forEach(type => {
292
+ mockViewContext = {
293
+ ...mockViewContext,
294
+ views: {
295
+ ...mockViewContext.views,
296
+ 'test-view-id': createMockView({ type })
297
+ }
298
+ };
299
+ rerender(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
300
+ expect(screen.getByLabelText(i18n.t(`route.views.manager.${type}`))).toBeInTheDocument();
301
+ });
302
+ });
303
+ it('should handle multiple view IDs correctly', () => {
304
+ mockViewContext.views = {
305
+ 'view-1': createMockView({ view_id: 'view-1', title: 'View 1' }),
306
+ 'view-2': createMockView({ view_id: 'view-2', title: 'View 2' }),
307
+ 'view-3': createMockView({ view_id: 'view-3', title: 'View 3' })
308
+ };
309
+ mockHitSearchContext.viewId = 'view-2';
310
+ render(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
311
+ expect(screen.getByText('View 2')).toBeInTheDocument();
312
+ expect(screen.queryByText('View 1')).not.toBeInTheDocument();
313
+ expect(screen.queryByText('View 3')).not.toBeInTheDocument();
314
+ });
315
+ });
316
+ describe('Accessibility', () => {
317
+ it('should have tooltips for all icon buttons', () => {
318
+ render(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
319
+ const editButton = screen.getByRole('link', { name: /edit /i });
320
+ const refreshButton = screen.getByRole('button');
321
+ const openButton = screen.getByRole('link', { name: /open /i });
322
+ expect(editButton).toHaveAttribute('aria-label');
323
+ expect(refreshButton).toHaveAttribute('aria-label');
324
+ expect(openButton).toHaveAttribute('aria-label');
325
+ });
326
+ it('should have proper role for error alert', () => {
327
+ mockHitSearchContext.viewId = 'non-existent-view';
328
+ mockViewContext.views = {
329
+ 'non-existent-view': null,
330
+ 'test-view-id': createMockView()
331
+ };
332
+ render(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
333
+ const alert = screen.getByRole('alert');
334
+ expect(alert).toBeInTheDocument();
335
+ });
336
+ it('should have accessible link text for view title', () => {
337
+ render(_jsx(ViewLink, {}), { wrapper: Wrapper });
338
+ const titleLink = screen.getByText('Test View').closest('a');
339
+ expect(titleLink).toHaveAttribute('href', '/views/test-view-id/edit');
340
+ expect(titleLink.textContent).toBe('Test View');
341
+ });
342
+ });
343
+ describe('Memoization', () => {
344
+ it('should not re-render unnecessarily when unrelated context values change', () => {
345
+ const { rerender } = render(_jsx(ViewLink, {}), { wrapper: Wrapper });
346
+ // Change an unrelated value
347
+ mockParameterContext.setQuery = vi.fn();
348
+ rerender(_jsx(ViewLink, {}));
349
+ const secondRenderButton = screen.getByRole('button');
350
+ // Components should still be present
351
+ expect(secondRenderButton).toBeInTheDocument();
352
+ });
353
+ it('should update when viewId changes', () => {
354
+ const { rerender } = render(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
355
+ expect(screen.getByText('Test View')).toBeInTheDocument();
356
+ mockHitSearchContext = { ...mockHitSearchContext, viewId: 'another-view' };
357
+ mockViewContext.views['another-view'] = createMockView({
358
+ view_id: 'another-view',
359
+ title: 'Another View'
360
+ });
361
+ rerender(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
362
+ expect(screen.getByText('Another View')).toBeInTheDocument();
363
+ });
364
+ it('should update when query changes', () => {
365
+ const { rerender } = render(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
366
+ const refreshButton = screen.getByRole('button');
367
+ fireEvent.click(refreshButton);
368
+ expect(mockSearch).toHaveBeenCalledWith('howler.id:*');
369
+ mockParameterContext = { ...mockParameterContext, query: 'howler.status:closed' };
370
+ rerender(_jsx(Wrapper, { children: _jsx(ViewLink, {}) }));
371
+ fireEvent.click(refreshButton);
372
+ expect(mockSearch).toHaveBeenCalledWith('howler.status:closed');
373
+ });
374
+ });
375
+ });
@@ -700,7 +700,9 @@
700
700
  "usermenu.logout": "Logout",
701
701
  "usermenu.settings": "Settings",
702
702
  "view.assigned_to_me": "Assigned to Me",
703
- "view.notfound": "This view is not availiable to you, or does not exist.",
703
+ "view.notfound": "This view is not available to you, or does not exist.",
704
+ "view.open": "Open View Query",
705
+ "view.refresh": "Refresh View",
704
706
  "view.settings.advance_on_triage": "Advance to next hit on triage",
705
707
  "view.settings.advance_on_triage.description": "If this is enabled, triaging a hit on this view will automatically move to the next hit in line, making rapid triage of hits easier.",
706
708
  "tui.query.save.alert": "Load a saved view or save the current query as a view",
@@ -700,6 +700,8 @@
700
700
  "usermenu.settings": "Paramètres",
701
701
  "view.assigned_to_me": "Assigné à moi",
702
702
  "view.notfound": "Cette vue n'est pas disponible pour vous, ou n'existe pas.",
703
+ "view.open": "Ouvrir requête de la vue",
704
+ "view.refresh": "Rafraîchir la vue",
703
705
  "view.settings.advance_on_triage": "Passer à la hit suivant lors du triage",
704
706
  "view.settings.advance_on_triage.description": "Si cette option est activée, le triage d'une hit sur cette vue passera automatiquement à la hit suivant, ce qui facilitera le triage rapide des résultats.",
705
707
  "Unclassified//Official Use Only": "Non classé//Réservé à des fins officielles",
package/package.json CHANGED
@@ -96,7 +96,7 @@
96
96
  "internal-slot": "1.0.7"
97
97
  },
98
98
  "type": "module",
99
- "version": "2.15.0-dev.327",
99
+ "version": "2.15.0-dev.333",
100
100
  "exports": {
101
101
  "./i18n": "./i18n.js",
102
102
  "./index.css": "./index.css",
package/tests/utils.d.ts CHANGED
@@ -2,6 +2,7 @@ import type { Action } from '@cccsaurora/howler-ui/models/entities/generated/Act
2
2
  import type { Analytic } from '@cccsaurora/howler-ui/models/entities/generated/Analytic';
3
3
  import type { Hit } from '@cccsaurora/howler-ui/models/entities/generated/Hit';
4
4
  import type { Template } from '@cccsaurora/howler-ui/models/entities/generated/Template';
5
+ import type { View } from '@cccsaurora/howler-ui/models/entities/generated/View';
5
6
  type RecursivePartial<T> = {
6
7
  [P in keyof T]?: T[P] extends (infer U)[] ? RecursivePartial<U>[] : T[P] extends object | undefined ? RecursivePartial<T[P]> : T[P];
7
8
  };
@@ -9,4 +10,5 @@ export declare const createMockHit: (overrides?: RecursivePartial<Hit>) => Hit;
9
10
  export declare const createMockAnalytic: (overrides?: Partial<Analytic>) => Analytic;
10
11
  export declare const createMockTemplate: (overrides?: Partial<Template>) => Template;
11
12
  export declare const createMockAction: (overrides?: Partial<Action>) => Action;
13
+ export declare const createMockView: (overrides?: Partial<View>) => View;
12
14
  export {};
package/tests/utils.js CHANGED
@@ -39,3 +39,16 @@ export const createMockAction = (overrides) => ({
39
39
  ],
40
40
  ...overrides
41
41
  });
42
+ export const createMockView = (overrides) => ({
43
+ view_id: 'test-view-id',
44
+ title: 'Test View',
45
+ query: 'howler.status:open',
46
+ sort: 'event.created desc',
47
+ span: 'date.range.1.month',
48
+ type: 'personal',
49
+ owner: 'testuser',
50
+ settings: {
51
+ advance_on_triage: false
52
+ },
53
+ ...overrides
54
+ });