@cccsaurora/howler-ui 2.13.0-dev.129 → 2.13.0-dev.132
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,15 +1,18 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Autocomplete, Box, Button, CircularProgress, Divider, FormControl, LinearProgress, Stack, TextField, Tooltip, useTheme } from '@mui/material';
|
|
2
|
+
import { Autocomplete, Box, Button, CircularProgress, Divider, FormControl, LinearProgress, Stack, TextField, ThemeProvider, ToggleButton, ToggleButtonGroup, Tooltip, useTheme } from '@mui/material';
|
|
3
3
|
import api from '@cccsaurora/howler-ui/api';
|
|
4
4
|
import PageCenter from '@cccsaurora/howler-ui/commons/components/pages/PageCenter';
|
|
5
5
|
import { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
|
6
6
|
import { useTranslation } from 'react-i18next';
|
|
7
|
-
import { Check, Delete, SsidChart } from '@mui/icons-material';
|
|
7
|
+
import { Check, DarkMode, Delete, SsidChart, WbSunny } from '@mui/icons-material';
|
|
8
|
+
import { useApp } from '@cccsaurora/howler-ui/commons/components/app/hooks';
|
|
8
9
|
import AppInfoPanel from '@cccsaurora/howler-ui/commons/components/display/AppInfoPanel';
|
|
10
|
+
import useThemeBuilder from '@cccsaurora/howler-ui/commons/components/utils/hooks/useThemeBuilder';
|
|
9
11
|
import { AnalyticContext } from '@cccsaurora/howler-ui/components/app/providers/AnalyticProvider';
|
|
10
12
|
import { OverviewContext } from '@cccsaurora/howler-ui/components/app/providers/OverviewProvider';
|
|
11
13
|
import HitOverview from '@cccsaurora/howler-ui/components/elements/hit/HitOverview';
|
|
12
14
|
import useMyApi from '@cccsaurora/howler-ui/components/hooks/useMyApi';
|
|
15
|
+
import useMyTheme from '@cccsaurora/howler-ui/components/hooks/useMyTheme';
|
|
13
16
|
import { useSearchParams } from 'react-router-dom';
|
|
14
17
|
import hitsData from '@cccsaurora/howler-ui/utils/hit.json';
|
|
15
18
|
import { sanitizeLuceneQuery } from '@cccsaurora/howler-ui/utils/stringUtils';
|
|
@@ -17,6 +20,8 @@ import OverviewEditor from './OverviewEditor';
|
|
|
17
20
|
import { useStartingTemplate } from './startingTemplate';
|
|
18
21
|
const OverviewViewer = () => {
|
|
19
22
|
const theme = useTheme();
|
|
23
|
+
const app = useApp();
|
|
24
|
+
const { lightTheme, darkTheme } = useThemeBuilder(useMyTheme());
|
|
20
25
|
const { t } = useTranslation();
|
|
21
26
|
const [params, setParams] = useSearchParams();
|
|
22
27
|
const { getOverviews } = useContext(OverviewContext);
|
|
@@ -24,6 +29,7 @@ const OverviewViewer = () => {
|
|
|
24
29
|
const [overviewList, setOverviewList] = useState([]);
|
|
25
30
|
const [selectedOverview, setSelectedOverview] = useState(null);
|
|
26
31
|
const [content, setContent] = useState('');
|
|
32
|
+
const [chosenTheme, setChosenTheme] = useState(app.theme);
|
|
27
33
|
const [analytics, setAnalytics] = useState([]);
|
|
28
34
|
const [detections, setDetections] = useState([]);
|
|
29
35
|
const [analytic, setAnalytic] = useState(params.get('analytic') ?? '');
|
|
@@ -173,7 +179,8 @@ const OverviewViewer = () => {
|
|
|
173
179
|
}, [onMouseMove, onMouseUp]);
|
|
174
180
|
const analyticOrDetectionMissing = useMemo(() => !analytic || !detection, [analytic, detection]);
|
|
175
181
|
const noChange = useMemo(() => selectedOverview?.content === content, [content, selectedOverview?.content]);
|
|
176
|
-
|
|
182
|
+
const activeTheme = chosenTheme === 'light' ? lightTheme : darkTheme;
|
|
183
|
+
return (_jsxs(PageCenter, { maxWidth: "100%", width: "100%", textAlign: "left", height: "100%", children: [_jsx(LinearProgress, { sx: { mb: 1, opacity: +loading } }), _jsxs(Stack, { direction: "column", spacing: 2, divider: _jsx(Divider, { orientation: "horizontal", flexItem: true }), height: "100%", children: [_jsxs(Stack, { direction: "row", spacing: 2, mb: 2, alignItems: "stretch", children: [_jsx(FormControl, { sx: { maxWidth: { sm: '300px', lg: '450px' }, width: '100%' }, children: _jsx(Autocomplete, { id: "analytic", options: analytics.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase())), getOptionLabel: option => option.name, value: analytics.find(a => a.name === analytic) || null, onChange: (_event, newValue) => setAnalytic(newValue ? newValue.name : ''), renderInput: autocompleteAnalyticParams => (_jsx(TextField, { ...autocompleteAnalyticParams, label: t('route.overviews.analytic'), size: "small" })) }) }), !analytics.find(_analytic => _analytic.name === analytic)?.rule ? (_jsx(FormControl, { sx: { minWidth: { sm: '200px' } }, disabled: !analytic, children: _jsx(Autocomplete, { id: "detection", options: ['ANY', ...detections.sort()], getOptionLabel: option => option, value: detection ?? '', onChange: (_event, newValue) => setDetection(newValue), renderInput: autocompleteDetectionParams => (_jsx(TextField, { ...autocompleteDetectionParams, label: t('route.overviews.detection'), size: "small" })) }) })) : (_jsx(Tooltip, { title: t('route.overviews.rule.explanation'), children: _jsx(SsidChart, { color: "info", sx: { alignSelf: 'center' } }) })), selectedOverview && (_jsx(Button, { variant: "outlined", startIcon: _jsx(Delete, {}), onClick: onDelete, children: t('button.delete') })), _jsx(Button, { variant: "outlined", disabled: analyticOrDetectionMissing || noChange, startIcon: overviewLoading ? _jsx(CircularProgress, { size: 16 }) : _jsx(Check, {}), onClick: onSave, children: t(!analyticOrDetectionMissing && !noChange ? 'button.save' : 'button.saved') }), _jsx("div", { style: { flex: 1 } }), _jsxs(ToggleButtonGroup, { exclusive: true, value: chosenTheme, onChange: (_event, value) => setChosenTheme(value), sx: { maxHeight: '40px' }, children: [_jsx(Tooltip, { title: t('route.overviews.theme.light'), children: _jsx(ToggleButton, { value: "light", children: _jsx(WbSunny, {}) }) }), _jsx(Tooltip, { title: t('route.overviews.theme.dark'), children: _jsx(ToggleButton, { value: "dark", children: _jsx(DarkMode, {}) }) })] })] }), analyticOrDetectionMissing ? (_jsx(AppInfoPanel, { i18nKey: "route.overviews.select", sx: { width: '100%', alignSelf: 'start' } })) : (_jsxs(Stack, { ref: wrapper, direction: "row", spacing: 1, height: "100%", onKeyDown: e => {
|
|
177
184
|
if (e.ctrlKey && e.key === 's') {
|
|
178
185
|
if (!noChange) {
|
|
179
186
|
onSave();
|
|
@@ -199,20 +206,22 @@ const OverviewViewer = () => {
|
|
|
199
206
|
transform: `translateX(${x}px)`,
|
|
200
207
|
zIndex: 1000,
|
|
201
208
|
borderRadius: theme.shape.borderRadius
|
|
202
|
-
}, onMouseDown: onMouseDown }), _jsx(Box, { flex: 1, px: 2, sx: {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
209
|
+
}, onMouseDown: onMouseDown }), _jsx(ThemeProvider, { theme: activeTheme, children: _jsx(Box, { flex: 1, px: 2, sx: {
|
|
210
|
+
position: 'absolute',
|
|
211
|
+
top: 0,
|
|
212
|
+
left: `calc(50% + 7px + ${x}px)`,
|
|
213
|
+
bottom: 0,
|
|
214
|
+
right: 0,
|
|
215
|
+
display: 'flex',
|
|
216
|
+
alignItems: 'stretch',
|
|
217
|
+
justifyContent: 'stretch',
|
|
218
|
+
px: 1,
|
|
219
|
+
pt: 1,
|
|
220
|
+
mt: -1,
|
|
221
|
+
'& > *': { width: '100%' },
|
|
222
|
+
'& > div > :first-child': { mt: 0 },
|
|
223
|
+
backgroundColor: activeTheme.palette.background.default,
|
|
224
|
+
color: activeTheme.palette.text.primary
|
|
225
|
+
}, children: _jsx(HitOverview, { content: content || startingTemplate, hit: exampleHit }) }) })] }))] })] }));
|
|
217
226
|
};
|
|
218
227
|
export default OverviewViewer;
|
|
@@ -39,7 +39,7 @@ const ViewsBase = () => {
|
|
|
39
39
|
const [phrase, setPhrase] = useState('');
|
|
40
40
|
const [offset, setOffset] = useState(parseInt(searchParams.get('offset')) || 0);
|
|
41
41
|
const [response, setResponse] = useState(null);
|
|
42
|
-
const [
|
|
42
|
+
const [type, setType] = useState(searchParams.get('type') || null);
|
|
43
43
|
const [hasError, setHasError] = useState(false);
|
|
44
44
|
const [searching, setSearching] = useState(false);
|
|
45
45
|
const [favouritesOnly, setFavouritesOnly] = useState(false);
|
|
@@ -58,7 +58,7 @@ const ViewsBase = () => {
|
|
|
58
58
|
setSearchParams(searchParams, { replace: true });
|
|
59
59
|
const searchTerm = phrase ? `*${sanitizeLuceneQuery(phrase)}*` : '*';
|
|
60
60
|
const phraseQuery = FIELDS_TO_SEARCH.map(_field => `${_field}:${searchTerm}`).join(' OR ');
|
|
61
|
-
const typeQuery = `(type:global OR owner:(${user.username} OR none)) AND type:(${
|
|
61
|
+
const typeQuery = `(type:global OR owner:(${user.username} OR none)) AND type:(${type ?? '*'}${type === 'personal' ? ' OR readonly' : ''})`;
|
|
62
62
|
const favouritesQuery = favouritesOnly && user.favourite_views.length > 0 ? ` AND view_id:(${user.favourite_views.join(' OR ')})` : '';
|
|
63
63
|
setResponse(await dispatchApi(api.search.view.post({
|
|
64
64
|
query: `(${phraseQuery}) AND ${typeQuery}${favouritesQuery}`,
|
|
@@ -78,7 +78,7 @@ const ViewsBase = () => {
|
|
|
78
78
|
searchParams,
|
|
79
79
|
user.username,
|
|
80
80
|
user.favourite_views,
|
|
81
|
-
|
|
81
|
+
type,
|
|
82
82
|
favouritesOnly,
|
|
83
83
|
dispatchApi,
|
|
84
84
|
pageCount,
|
|
@@ -132,9 +132,29 @@ const ViewsBase = () => {
|
|
|
132
132
|
setDefaultViewLoading(false);
|
|
133
133
|
}
|
|
134
134
|
}, [fetchViews]);
|
|
135
|
+
const onTypeChange = useCallback(async (_type) => {
|
|
136
|
+
setType(_type);
|
|
137
|
+
if (_type) {
|
|
138
|
+
searchParams.delete('type');
|
|
139
|
+
searchParams.set('type', _type);
|
|
140
|
+
setSearchParams(searchParams, { replace: true });
|
|
141
|
+
}
|
|
142
|
+
else if (searchParams.has('type')) {
|
|
143
|
+
searchParams.delete('type');
|
|
144
|
+
setSearchParams(searchParams, { replace: true });
|
|
145
|
+
}
|
|
146
|
+
}, [searchParams, setSearchParams]);
|
|
135
147
|
useEffect(() => {
|
|
148
|
+
let changed = false;
|
|
136
149
|
if (!searchParams.has('offset')) {
|
|
137
150
|
searchParams.set('offset', '0');
|
|
151
|
+
changed = true;
|
|
152
|
+
}
|
|
153
|
+
if (searchParams.has('type') && !['personal', 'global'].includes(searchParams.get('type'))) {
|
|
154
|
+
searchParams.delete('type');
|
|
155
|
+
changed = true;
|
|
156
|
+
}
|
|
157
|
+
if (changed) {
|
|
138
158
|
setSearchParams(searchParams, { replace: true });
|
|
139
159
|
}
|
|
140
160
|
}, [searchParams, setSearchParams]);
|
|
@@ -150,12 +170,8 @@ const ViewsBase = () => {
|
|
|
150
170
|
onSearch();
|
|
151
171
|
}
|
|
152
172
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
153
|
-
}, [offset, favouritesOnly,
|
|
154
|
-
return (_jsx(ItemManager, { onSearch: onSearch, onPageChange: onPageChange, phrase: phrase, setPhrase: setPhrase, hasError: hasError, searching: searching, searchFilters: _jsx(Stack, { direction: "row", spacing: 1, alignItems: "center", children: _jsxs(ToggleButtonGroup, { sx: { display: 'grid', gridTemplateColumns: '1fr 1fr' }, size: "small", value:
|
|
155
|
-
if (_types) {
|
|
156
|
-
setTypes(_types.length < 2 ? _types : []);
|
|
157
|
-
}
|
|
158
|
-
}, children: [_jsx(ToggleButton, { value: "personal", "aria-label": "personal", children: t('route.views.manager.personal') }), _jsx(ToggleButton, { value: "global", "aria-label": "global", children: t('route.views.manager.global') })] }) }), aboveSearch: _jsx(Typography, { sx: theme => ({ fontStyle: 'italic', color: theme.palette.text.disabled, mb: 0.5 }), variant: "body2", children: t('route.views.search.prompt') }), afterSearch: size(views) > 0 ? (_jsx(Autocomplete, { open: defaultViewOpen, loading: defaultViewLoading, onOpen: onDefaultViewOpen, onClose: () => setDefaultViewOpen(false), options: Object.values(omitBy(views, isNull)), renderOption: ({ key, ...props }, o) => (_createElement("li", { ...props, key: key },
|
|
173
|
+
}, [offset, favouritesOnly, type]);
|
|
174
|
+
return (_jsx(ItemManager, { onSearch: onSearch, onPageChange: onPageChange, phrase: phrase, setPhrase: setPhrase, hasError: hasError, searching: searching, searchFilters: _jsx(Stack, { direction: "row", spacing: 1, alignItems: "center", children: _jsxs(ToggleButtonGroup, { sx: { display: 'grid', gridTemplateColumns: '1fr 1fr' }, size: "small", value: type, exclusive: true, onChange: (__, _type) => onTypeChange(_type), children: [_jsx(ToggleButton, { value: "personal", "aria-label": "personal", children: t('route.views.manager.personal') }), _jsx(ToggleButton, { value: "global", "aria-label": "global", children: t('route.views.manager.global') })] }) }), aboveSearch: _jsx(Typography, { sx: theme => ({ fontStyle: 'italic', color: theme.palette.text.disabled, mb: 0.5 }), variant: "body2", children: t('route.views.search.prompt') }), afterSearch: size(views) > 0 ? (_jsx(Autocomplete, { open: defaultViewOpen, loading: defaultViewLoading, onOpen: onDefaultViewOpen, onClose: () => setDefaultViewOpen(false), options: Object.values(omitBy(views, isNull)), renderOption: ({ key, ...props }, o) => (_createElement("li", { ...props, key: key },
|
|
159
175
|
_jsxs(Stack, { children: [_jsx(Typography, { variant: "body1", children: t(o.title) }), _jsx(Typography, { variant: "caption", children: _jsx("code", { children: o.query }) })] }))), renderInput: params => (_jsx(TextField, { ...params, label: t('route.views.manager.default'), sx: { minWidth: '300px' } })), filterOptions: (_views, { inputValue }) => _views.filter(v => t(v.title).toLowerCase().includes(inputValue.toLowerCase()) ||
|
|
160
176
|
v.query.toLowerCase().includes(inputValue.toLowerCase())), getOptionLabel: (v) => t(v.title), isOptionEqualToValue: (view, value) => view.view_id === value.view_id, value: views[defaultView] ?? null, onChange: (_, option) => setDefaultView(option?.view_id) })) : (_jsx(Skeleton, { variant: "rounded", width: "300px", height: "initial" })), belowSearch: _jsxs(Stack, { direction: "row", spacing: 1, alignItems: "center", children: [_jsx(Checkbox, { size: "small", disabled: user.favourite_views?.length < 1, checked: favouritesOnly, onChange: (_, checked) => setFavouritesOnly(checked) }), _jsx(Typography, { variant: "body1", sx: theme => ({ color: theme.palette.text.disabled }), children: t('route.views.manager.favourites') })] }), renderer: ({ item }, classRenderer) => (_jsx(Card, { variant: "outlined", sx: { p: 1, mb: 1, transitionProperty: 'border-color', '&:hover': { borderColor: 'primary.main' } }, className: classRenderer(), children: _jsxs(Stack, { direction: "row", alignItems: "center", spacing: 1, sx: { color: 'inherit', textDecoration: 'none' }, component: Link, to: `/views/${item.item.view_id}`, children: [_jsx(ViewTitle, { ...item.item }), _jsx(FlexOne, {}), ((item.item.owner === user.username && item.item.type !== 'readonly') ||
|
|
161
177
|
(item.item.type === 'global' && user.is_admin)) && (_jsx(Tooltip, { title: t('button.edit'), children: _jsx(IconButton, { component: Link, to: `/views/${item.item.view_id}/edit?query=${item.item.query}`, children: _jsx(Edit, {}) }) })), item.item.owner === user.username && item.item.type !== 'readonly' && (_jsx(Tooltip, { title: t('button.delete'), children: _jsx(IconButton, { onClick: event => onDelete(event, item.item.view_id), children: _jsx(Clear, {}) }) })), item.item.type === 'global' && item.item.owner !== user.username && (_jsx(Tooltip, { title: item.item.owner, children: _jsx("div", { children: _jsx(HowlerAvatar, { sx: { width: 24, height: 24, marginRight: '8px !important', marginLeft: '8px !important' }, userId: item.item.owner }) }) })), _jsx(Tooltip, { title: t('button.pin'), children: _jsx(IconButton, { onClick: e => onFavourite(e, item.item.view_id), children: user.favourite_views?.includes(item.item.view_id) ? _jsx(Star, {}) : _jsx(StarBorder, {}) }) })] }) }, item.item.view_id)), response: response, searchPrompt: "route.views.manager.search", onCreate: () => navigate('/views/create'), createPrompt: "route.views.create", createIcon: _jsx(SavedSearch, { sx: { mr: 1 } }) }));
|
|
@@ -587,6 +587,8 @@
|
|
|
587
587
|
"route.overviews.manager.search": "Search Overviews",
|
|
588
588
|
"route.overviews.manager.delete": "Delete Overview",
|
|
589
589
|
"route.overviews.manager.delete.success": "Overview Removed.",
|
|
590
|
+
"route.overviews.theme.light": "Preview in Light Mode",
|
|
591
|
+
"route.overviews.theme.dark": "Preview in Dark Mode",
|
|
590
592
|
"route.dossiers": "Dossiers",
|
|
591
593
|
"route.dossiers.default": "Default",
|
|
592
594
|
"route.dossiers.search.prompt": "Search by title, query, or owner.",
|
|
@@ -585,7 +585,8 @@
|
|
|
585
585
|
"route.overviews.manager.search": "Rechercher les vues d'ensemble",
|
|
586
586
|
"route.overviews.manager.delete": "Supprimer la vue d'ensemble",
|
|
587
587
|
"route.overviews.manager.delete.success": "Vue d'ensemble Supprimée.",
|
|
588
|
-
"route.overviews.
|
|
588
|
+
"route.overviews.theme.light": "Prévoyez en mode clair",
|
|
589
|
+
"route.overviews.theme.dark": "Prévoyez en mode sombre",
|
|
589
590
|
"route.dossiers": "Dossiers",
|
|
590
591
|
"route.dossiers.default": "Défaut",
|
|
591
592
|
"route.dossiers.search.prompt": "Recherche par titre, requête ou propriétaire.",
|