mirror of
https://github.com/traccar/traccar-web.git
synced 2025-01-09 04:37:33 +08:00
Configurable device share expiration
This commit is contained in:
parent
89a40e4825
commit
c76be61cef
@ -55,6 +55,7 @@ import DeviceConnectionsPage from './settings/DeviceConnectionsPage';
|
||||
import GroupConnectionsPage from './settings/GroupConnectionsPage';
|
||||
import UserConnectionsPage from './settings/UserConnectionsPage';
|
||||
import LogsPage from './reports/LogsPage';
|
||||
import SharePage from './settings/SharePage';
|
||||
|
||||
const Navigation = () => {
|
||||
const navigate = useNavigate();
|
||||
@ -122,6 +123,7 @@ const Navigation = () => {
|
||||
<Route path="devices" element={<DevicesPage />} />
|
||||
<Route path="device/:id/connections" element={<DeviceConnectionsPage />} />
|
||||
<Route path="device/:id/command" element={<CommandDevicePage />} />
|
||||
<Route path="device/:id/share" element={<SharePage />} />
|
||||
<Route path="device/:id" element={<DevicePage />} />
|
||||
<Route path="device" element={<DevicePage />} />
|
||||
<Route path="drivers" element={<DriversPage />} />
|
||||
|
@ -1,7 +1,6 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import dayjs from 'dayjs';
|
||||
import Draggable from 'react-draggable';
|
||||
import {
|
||||
Card,
|
||||
@ -16,11 +15,6 @@ import {
|
||||
Menu,
|
||||
MenuItem,
|
||||
CardMedia,
|
||||
Dialog,
|
||||
TextField,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
Button,
|
||||
} from '@mui/material';
|
||||
import makeStyles from '@mui/styles/makeStyles';
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
@ -138,7 +132,6 @@ const StatusCard = ({ deviceId, position, onClose, disableActions, desktopPaddin
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
|
||||
const [removing, setRemoving] = useState(false);
|
||||
const [shared, setShared] = useState(null);
|
||||
|
||||
const handleRemove = useCatch(async (removed) => {
|
||||
if (removed) {
|
||||
@ -178,20 +171,6 @@ const StatusCard = ({ deviceId, position, onClose, disableActions, desktopPaddin
|
||||
}
|
||||
}, [navigate, position]);
|
||||
|
||||
const handleShare = useCatchCallback(async () => {
|
||||
const expiration = dayjs().add(1, 'week').toISOString();
|
||||
const response = await fetch('/api/devices/share', {
|
||||
method: 'POST',
|
||||
body: new URLSearchParams(`deviceId=${deviceId}&expiration=${expiration}`),
|
||||
});
|
||||
if (response.ok) {
|
||||
const token = await response.text();
|
||||
setShared(`${window.location.origin}?token=${token}`);
|
||||
} else {
|
||||
throw Error(await response.text());
|
||||
}
|
||||
}, [deviceId, setShared]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={classes.root}>
|
||||
@ -293,7 +272,7 @@ const StatusCard = ({ deviceId, position, onClose, disableActions, desktopPaddin
|
||||
<MenuItem component="a" target="_blank" href={`https://www.google.com/maps/search/?api=1&query=${position.latitude}%2C${position.longitude}`}>{t('linkGoogleMaps')}</MenuItem>
|
||||
<MenuItem component="a" target="_blank" href={`http://maps.apple.com/?ll=${position.latitude},${position.longitude}`}>{t('linkAppleMaps')}</MenuItem>
|
||||
<MenuItem component="a" target="_blank" href={`https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=${position.latitude}%2C${position.longitude}&heading=${position.course}`}>{t('linkStreetView')}</MenuItem>
|
||||
{!shareDisabled && !user.temporary && <MenuItem onClick={handleShare}>{t('deviceShare')}</MenuItem>}
|
||||
{!shareDisabled && !user.temporary && <MenuItem onClick={() => navigate(`/settings/device/${deviceId}/share`)}>{t('deviceShare')}</MenuItem>}
|
||||
</Menu>
|
||||
)}
|
||||
<RemoveDialog
|
||||
@ -302,15 +281,6 @@ const StatusCard = ({ deviceId, position, onClose, disableActions, desktopPaddin
|
||||
itemId={deviceId}
|
||||
onResult={(removed) => handleRemove(removed)}
|
||||
/>
|
||||
<Dialog open={Boolean(shared)} onClose={() => setShared(null)}>
|
||||
<DialogContent>
|
||||
<TextField value={shared} onFocus={e => e.target.select()} />
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={() => setShared(null)}>{t('sharedCancel')}</Button>
|
||||
<Button onClick={() => navigator.clipboard?.writeText(shared)}>{t('sharedCopy')}</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -101,6 +101,7 @@
|
||||
"sharedColumns": "Columns",
|
||||
"sharedDropzoneText": "Drag and drop a file here or click",
|
||||
"sharedLogs": "Logs",
|
||||
"sharedLink": "Link",
|
||||
"calendarSimple": "Simple",
|
||||
"calendarRecurrence": "Recurrence",
|
||||
"calendarOnce": "Once",
|
||||
|
109
modern/src/settings/SharePage.jsx
Normal file
109
modern/src/settings/SharePage.jsx
Normal file
@ -0,0 +1,109 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import dayjs from 'dayjs';
|
||||
import {
|
||||
Accordion,
|
||||
AccordionSummary,
|
||||
AccordionDetails,
|
||||
Typography,
|
||||
Container,
|
||||
TextField,
|
||||
Button,
|
||||
} from '@mui/material';
|
||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
||||
import { useTranslation } from '../common/components/LocalizationProvider';
|
||||
import PageLayout from '../common/components/PageLayout';
|
||||
import SettingsMenu from './components/SettingsMenu';
|
||||
import { useCatchCallback } from '../reactHelper';
|
||||
import useSettingsStyles from './common/useSettingsStyles';
|
||||
|
||||
const SharePage = () => {
|
||||
const navigate = useNavigate();
|
||||
const classes = useSettingsStyles();
|
||||
const t = useTranslation();
|
||||
|
||||
const { id } = useParams();
|
||||
|
||||
const device = useSelector((state) => state.devices.items[id]);
|
||||
|
||||
const [expiration, setExpiration] = useState(dayjs().add(1, 'week').locale('en').format('YYYY-MM-DD'));
|
||||
const [link, setLink] = useState();
|
||||
|
||||
const handleShare = useCatchCallback(async () => {
|
||||
const expirationTime = dayjs(expiration).toISOString();
|
||||
const response = await fetch('/api/devices/share', {
|
||||
method: 'POST',
|
||||
body: new URLSearchParams(`deviceId=${id}&expiration=${expirationTime}`),
|
||||
});
|
||||
if (response.ok) {
|
||||
const token = await response.text();
|
||||
setLink(`${window.location.origin}?token=${token}`);
|
||||
} else {
|
||||
throw Error(await response.text());
|
||||
}
|
||||
}, [id, expiration, setLink]);
|
||||
|
||||
return (
|
||||
<PageLayout menu={<SettingsMenu />} breadcrumbs={['deviceShare']}>
|
||||
<Container maxWidth="xs" className={classes.container}>
|
||||
<Accordion defaultExpanded>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
<Typography variant="subtitle1">
|
||||
{t('sharedRequired')}
|
||||
</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails className={classes.details}>
|
||||
<TextField
|
||||
value={device.name}
|
||||
label={t('sharedDevice')}
|
||||
disabled
|
||||
/>
|
||||
<TextField
|
||||
label={t('userExpirationTime')}
|
||||
type="date"
|
||||
value={(expiration && dayjs(expiration).locale('en').format('YYYY-MM-DD')) || '2099-01-01'}
|
||||
onChange={(e) => setExpiration(dayjs(e.target.value, 'YYYY-MM-DD').locale('en').format())}
|
||||
/>
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
onClick={handleShare}
|
||||
>
|
||||
{t('reportShow')}
|
||||
</Button>
|
||||
<TextField
|
||||
value={link || ''}
|
||||
onChange={(e) => setLink(e.target.value)}
|
||||
label={t('sharedLink')}
|
||||
InputProps={{
|
||||
readOnly: true,
|
||||
}}
|
||||
/>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
<div className={classes.buttons}>
|
||||
<Button
|
||||
type="button"
|
||||
color="primary"
|
||||
variant="outlined"
|
||||
onClick={() => navigate(-1)}
|
||||
>
|
||||
{t('sharedCancel')}
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
color="primary"
|
||||
variant="contained"
|
||||
onClick={() => navigator.clipboard?.writeText(link)}
|
||||
disabled={!link}
|
||||
>
|
||||
{t('sharedCopy')}
|
||||
</Button>
|
||||
</div>
|
||||
</Container>
|
||||
</PageLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default SharePage;
|
Loading…
Reference in New Issue
Block a user