mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-07 00:09:51 +03:00
show download button instead of dialog
This commit is contained in:
@@ -109,73 +109,49 @@ const Version = () => {
|
||||
|
||||
useLayoutTitle('EMS-ESP Firmware');
|
||||
|
||||
// see if we have internet access
|
||||
const internet_live =
|
||||
latestDevVersion !== undefined && latestVersion !== undefined;
|
||||
|
||||
// check for older boards where auto-upgrade is not supported
|
||||
const download_only = data && !data.psram;
|
||||
|
||||
const renderUploadDialog = () => {
|
||||
if (!internet_live) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
sx={dialogStyle}
|
||||
open={openDialog}
|
||||
onClose={() => setOpenDialog(false)}
|
||||
>
|
||||
<DialogTitle>
|
||||
{(download_only ? LL.DOWNLOAD(0) : LL.INSTALL('')) + ' ' + ' Firmware'}
|
||||
</DialogTitle>
|
||||
<DialogContent dividers>
|
||||
<Typography mb={2}>
|
||||
{LL.INSTALL_VERSION(
|
||||
download_only ? LL.DOWNLOAD(1) : LL.INSTALL(''),
|
||||
useDev ? latestDevVersion : latestVersion
|
||||
)}
|
||||
</Typography>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
startIcon={<CancelIcon />}
|
||||
variant="outlined"
|
||||
onClick={() => setOpenDialog(false)}
|
||||
color="secondary"
|
||||
>
|
||||
{LL.CANCEL()}
|
||||
</Button>
|
||||
<Button
|
||||
startIcon={<DownloadIcon />}
|
||||
variant="outlined"
|
||||
onClick={() => setOpenDialog(false)}
|
||||
const renderUploadDialog = () => (
|
||||
<Dialog sx={dialogStyle} open={openDialog} onClose={() => setOpenDialog(false)}>
|
||||
<DialogTitle>{LL.INSTALL('') + ' ' + ' Firmware'}</DialogTitle>
|
||||
<DialogContent dividers>
|
||||
<Typography mb={2}>
|
||||
{LL.INSTALL_VERSION(useDev ? latestDevVersion : latestVersion)}
|
||||
</Typography>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
startIcon={<CancelIcon />}
|
||||
variant="outlined"
|
||||
onClick={() => setOpenDialog(false)}
|
||||
color="secondary"
|
||||
>
|
||||
{LL.CANCEL()}
|
||||
</Button>
|
||||
<Button
|
||||
startIcon={<DownloadIcon />}
|
||||
variant="outlined"
|
||||
onClick={() => setOpenDialog(false)}
|
||||
color="primary"
|
||||
>
|
||||
<Link
|
||||
underline="none"
|
||||
target="_blank"
|
||||
href={getBinURL(useDev)}
|
||||
color="primary"
|
||||
>
|
||||
<Link
|
||||
underline="none"
|
||||
target="_blank"
|
||||
href={getBinURL(useDev)}
|
||||
color="primary"
|
||||
>
|
||||
{LL.DOWNLOAD(1)}
|
||||
</Link>
|
||||
</Button>
|
||||
{!download_only && (
|
||||
<Button
|
||||
startIcon={<WarningIcon color="warning" />}
|
||||
variant="outlined"
|
||||
onClick={() => installFirmwareURL(getBinURL(useDev))}
|
||||
color="primary"
|
||||
>
|
||||
{LL.INSTALL('')}
|
||||
</Button>
|
||||
)}
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
{LL.DOWNLOAD(1)}
|
||||
</Link>
|
||||
</Button>
|
||||
<Button
|
||||
startIcon={<WarningIcon color="warning" />}
|
||||
variant="outlined"
|
||||
onClick={() => installFirmwareURL(getBinURL(useDev))}
|
||||
color="primary"
|
||||
>
|
||||
{LL.INSTALL('')}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
|
||||
const showFirmwareDialog = (useDevVersion: boolean) => {
|
||||
if (useDevVersion || data.emsesp_version.includes('dev')) {
|
||||
@@ -190,6 +166,17 @@ const Version = () => {
|
||||
}
|
||||
|
||||
const isDev = data.emsesp_version.includes('dev');
|
||||
// const isDev = false; // for testing
|
||||
// const isDev = true; // for testing
|
||||
|
||||
// check for older versions where auto-upgrade is not supported. These are bbqkees boards with no psram.
|
||||
const canUpload = upgradeAvailable && data && data.psram;
|
||||
// const canUpload = true as boolean; // for testing
|
||||
// const canUpload = false as boolean; // for testing
|
||||
|
||||
// see if we have internet access
|
||||
const internet_live =
|
||||
latestDevVersion !== undefined && latestVersion !== undefined;
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -260,7 +247,7 @@ const Version = () => {
|
||||
<Link target="_blank" href={STABLE_RELNOTES_URL} color="primary">
|
||||
(changelog)
|
||||
</Link>
|
||||
{!isDev && upgradeAvailable && (
|
||||
{!isDev && canUpload && (
|
||||
<Button
|
||||
sx={{ ml: 2 }}
|
||||
variant="outlined"
|
||||
@@ -268,7 +255,26 @@ const Version = () => {
|
||||
size="small"
|
||||
onClick={() => showFirmwareDialog(false)}
|
||||
>
|
||||
Upgrade…
|
||||
{LL.UPGRADE()}…
|
||||
</Button>
|
||||
)}
|
||||
{!isDev && !canUpload && (
|
||||
<Button
|
||||
startIcon={<DownloadIcon />}
|
||||
variant="outlined"
|
||||
onClick={() => setOpenDialog(false)}
|
||||
color="warning"
|
||||
size="small"
|
||||
sx={{ ml: 2 }}
|
||||
>
|
||||
<Link
|
||||
underline="none"
|
||||
target="_blank"
|
||||
href={getBinURL(useDev)}
|
||||
color="warning"
|
||||
>
|
||||
{LL.DOWNLOAD(1)}
|
||||
</Link>
|
||||
</Button>
|
||||
)}
|
||||
</Typography>
|
||||
@@ -277,7 +283,7 @@ const Version = () => {
|
||||
<Link target="_blank" href={DEV_RELNOTES_URL} color="primary">
|
||||
(changelog)
|
||||
</Link>
|
||||
{isDev && upgradeAvailable && (
|
||||
{isDev && canUpload && (
|
||||
<Button
|
||||
sx={{ ml: 2 }}
|
||||
variant="outlined"
|
||||
@@ -285,7 +291,26 @@ const Version = () => {
|
||||
size="small"
|
||||
onClick={() => showFirmwareDialog(false)}
|
||||
>
|
||||
Upgrade…
|
||||
{LL.UPGRADE()}…
|
||||
</Button>
|
||||
)}
|
||||
{isDev && !canUpload && (
|
||||
<Button
|
||||
startIcon={<DownloadIcon />}
|
||||
variant="outlined"
|
||||
onClick={() => setOpenDialog(false)}
|
||||
color="warning"
|
||||
size="small"
|
||||
sx={{ ml: 2 }}
|
||||
>
|
||||
<Link
|
||||
underline="none"
|
||||
target="_blank"
|
||||
href={getBinURL(useDev)}
|
||||
color="warning"
|
||||
>
|
||||
{LL.DOWNLOAD(1)}
|
||||
</Link>
|
||||
</Button>
|
||||
)}
|
||||
</Typography>
|
||||
|
||||
@@ -58,7 +58,7 @@ const LayoutAppBar = ({ title, onToggleDrawer }: LayoutAppBarProps) => {
|
||||
>
|
||||
<Typography variant="h6">
|
||||
{pathnames[0] === 'status' ? LL.STATUS_OF('') : LL.SETTINGS(0)}
|
||||
<span style={{ color: '#90caf9' }}> | </span>
|
||||
<span style={{ color: '#90caf9' }}> | </span>
|
||||
</Typography>
|
||||
</Link>
|
||||
</>
|
||||
|
||||
@@ -331,7 +331,7 @@ const cz: Translation = {
|
||||
ALLVALUES: 'Všechny hodnoty',
|
||||
SPECIAL_FUNCTIONS: 'Speciální funkce',
|
||||
WAIT_FIRMWARE: 'Firmware se nahrává a instaluje',
|
||||
INSTALL_VERSION: 'Tímto se {0} verze {1}. Jste si jistí?',
|
||||
INSTALL_VERSION: 'Tímto se instalovat verze {0}. Jste si jistí?',
|
||||
SWITCH_DEV: 'přepnout na vývojovou verzi',
|
||||
UPGRADE_AVAILABLE: 'Je k dispozici aktualizace firmwaru!',
|
||||
LATEST_VERSION: 'Používáte nejnovější verzi firmwaru.',
|
||||
@@ -342,7 +342,8 @@ const cz: Translation = {
|
||||
DASHBOARD: 'Dashboard',
|
||||
NO_DATA: 'Žádná data nejsou k dispozici',
|
||||
DASHBOARD_1: 'Přizpůsobte si dashboard označením EMS entit jako Oblíbené pomocí modulu Přizpůsobení',
|
||||
DEVELOPER_MODE: 'Režim vývojáře'
|
||||
DEVELOPER_MODE: 'Režim vývojáře',
|
||||
UPGRADE: 'Upgrade' // TODO translate
|
||||
};
|
||||
|
||||
export default cz;
|
||||
|
||||
@@ -331,7 +331,7 @@ const de: Translation = {
|
||||
ALLVALUES: 'Alle Werte',
|
||||
SPECIAL_FUNCTIONS: 'Sonderfunktionen',
|
||||
WAIT_FIRMWARE: 'Die Firmware wird hochgeladen und installiert.',
|
||||
INSTALL_VERSION: 'Dadurch wird die Version {1} heruntergeladen. Sind Sie sicher?',
|
||||
INSTALL_VERSION: 'Dadurch wird die Version {0} heruntergeladen. Sind Sie sicher?',
|
||||
SWITCH_DEV: 'Wechseln Sie zur Entwicklungsversion!',
|
||||
UPGRADE_AVAILABLE: 'Es ist ein Firmware-Upgrade verfügbar.',
|
||||
LATEST_VERSION: 'Sie verwenden die neueste Firmware-Version.',
|
||||
@@ -342,7 +342,8 @@ const de: Translation = {
|
||||
DASHBOARD: 'Dashboard',
|
||||
NO_DATA: 'Keine Daten verfügbar',
|
||||
DASHBOARD_1: 'Passen Sie Ihr Dashboard an, indem Sie EMS-Entitäten mithilfe des Moduls „Anpassungen“ als Favorit markieren',
|
||||
DEVELOPER_MODE: 'Entwicklermodus'
|
||||
DEVELOPER_MODE: 'Entwicklermodus',
|
||||
UPGRADE: 'Upgrade' // TODO translate
|
||||
};
|
||||
|
||||
export default de;
|
||||
|
||||
@@ -331,7 +331,7 @@ const en: Translation = {
|
||||
ALLVALUES: 'All Values',
|
||||
SPECIAL_FUNCTIONS: 'Special Functions',
|
||||
WAIT_FIRMWARE: 'Firmware is uploading and installing',
|
||||
INSTALL_VERSION: 'This will {0} version {1}. Are you sure?',
|
||||
INSTALL_VERSION: 'This will install version {0}. Are you sure?',
|
||||
SWITCH_DEV: 'switch to the development version',
|
||||
UPGRADE_AVAILABLE: 'There is a firmware upgrade available!',
|
||||
LATEST_VERSION: 'You are using the latest firmware version.',
|
||||
@@ -342,7 +342,8 @@ const en: Translation = {
|
||||
DASHBOARD: 'Dashboard',
|
||||
NO_DATA: 'No data available',
|
||||
DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module',
|
||||
DEVELOPER_MODE: 'Developer Mode'
|
||||
DEVELOPER_MODE: 'Developer Mode',
|
||||
UPGRADE: 'Upgrade'
|
||||
};
|
||||
|
||||
export default en;
|
||||
|
||||
@@ -331,7 +331,7 @@ const fr: Translation = {
|
||||
ALLVALUES: 'All Values', // TODO translate
|
||||
SPECIAL_FUNCTIONS: 'Special Functions',
|
||||
WAIT_FIRMWARE: 'Firmware is uploading and installing', // TODO translate
|
||||
INSTALL_VERSION: 'This will {0} version {1}. Are you sure?', // TODO translate
|
||||
INSTALL_VERSION: 'This will install version {0}. Are you sure?', // TODO translate
|
||||
SWITCH_DEV: 'switch to the development version', // TODO translate
|
||||
UPGRADE_AVAILABLE: 'There is a firmware upgrade available!', // TODO translate
|
||||
LATEST_VERSION: 'You are using the latest firmware version.', // TODO translate
|
||||
@@ -342,7 +342,8 @@ const fr: Translation = {
|
||||
DASHBOARD: 'Dashboard', // TODO translate
|
||||
NO_DATA: 'No data available', // TODO translate
|
||||
DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module', // TODO translate
|
||||
DEVELOPER_MODE: 'Developer Mode' // TODO translate
|
||||
DEVELOPER_MODE: 'Developer Mode', // TODO translate
|
||||
UPGRADE: 'Upgrade' // TODO translate
|
||||
};
|
||||
|
||||
export default fr;
|
||||
|
||||
@@ -331,7 +331,7 @@ const it: Translation = {
|
||||
ALLVALUES: 'All Values', // TODO translate
|
||||
SPECIAL_FUNCTIONS: 'Special Functions', // TODO translate
|
||||
WAIT_FIRMWARE: 'Firmware is uploading and installing', // TODO translate
|
||||
INSTALL_VERSION: 'This will {0} version {1}. Are you sure?', // TODO translate
|
||||
INSTALL_VERSION: 'This will install version {0}. Are you sure?', // TODO translate
|
||||
SWITCH_DEV: 'switch to the development version', // TODO translate
|
||||
UPGRADE_AVAILABLE: 'There is a firmware upgrade available!', // TODO translate
|
||||
LATEST_VERSION: 'You are using the latest firmware version.', // TODO translate
|
||||
@@ -342,7 +342,8 @@ const it: Translation = {
|
||||
DASHBOARD: 'Dashboard', // TODO translate
|
||||
NO_DATA: 'No data available', // TODO translate
|
||||
DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module', // TODO translate
|
||||
DEVELOPER_MODE: 'Developer Mode' // TODO translate
|
||||
DEVELOPER_MODE: 'Developer Mode', // TODO translate
|
||||
UPGRADE: 'Upgrade' // TODO translate
|
||||
};
|
||||
|
||||
export default it;
|
||||
|
||||
@@ -331,7 +331,7 @@ const nl: Translation = {
|
||||
ALLVALUES: 'All Values', // TODO translate
|
||||
SPECIAL_FUNCTIONS: 'Special Functions', // TODO translate
|
||||
WAIT_FIRMWARE: 'Firmware is uploading and installing', // TODO translate
|
||||
INSTALL_VERSION: 'This will {0} version {1}. Are you sure?', // TODO translate
|
||||
INSTALL_VERSION: 'This will install version {0}. Are you sure?', // TODO translate
|
||||
SWITCH_DEV: 'switch to the development version', // TODO translate
|
||||
UPGRADE_AVAILABLE: 'There is a firmware upgrade available!', // TODO translate
|
||||
LATEST_VERSION: 'You are using the latest firmware version.', // TODO translate
|
||||
@@ -342,7 +342,8 @@ const nl: Translation = {
|
||||
DASHBOARD: 'Dashboard', // TODO translate
|
||||
NO_DATA: 'No data available', // TODO translate
|
||||
DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module', // TODO translate
|
||||
DEVELOPER_MODE: 'Developer Mode' // TODO translate
|
||||
DEVELOPER_MODE: 'Developer Mode', // TODO translate
|
||||
UPGRADE: 'Upgrade' // TODO translate
|
||||
};
|
||||
|
||||
export default nl;
|
||||
|
||||
@@ -331,7 +331,7 @@ const no: Translation = {
|
||||
ALLVALUES: 'All Values', // TODO translate
|
||||
SPECIAL_FUNCTIONS: 'Special Functions', // TODO translate
|
||||
WAIT_FIRMWARE: 'Firmware is uploading and installing', // TODO translate
|
||||
INSTALL_VERSION: 'This will {0} version {1}. Are you sure?', // TODO translate
|
||||
INSTALL_VERSION: 'This will install version {0}. Are you sure?', // TODO translate
|
||||
SWITCH_DEV: 'switch to the development version', // TODO translate
|
||||
UPGRADE_AVAILABLE: 'There is a firmware upgrade available!', // TODO translate
|
||||
LATEST_VERSION: 'You are using the latest firmware version.', // TODO translate
|
||||
@@ -342,7 +342,8 @@ const no: Translation = {
|
||||
DASHBOARD: 'Dashboard', // TODO translate
|
||||
NO_DATA: 'No data available', // TODO translate
|
||||
DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module', // TODO translate
|
||||
DEVELOPER_MODE: 'Developer Mode' // TODO translate
|
||||
DEVELOPER_MODE: 'Developer Mode', // TODO translate
|
||||
UPGRADE: 'Upgrade' // TODO translate
|
||||
};
|
||||
|
||||
export default no;
|
||||
|
||||
@@ -331,7 +331,7 @@ const pl: BaseTranslation = {
|
||||
ALLVALUES: 'All Values', // TODO translate
|
||||
SPECIAL_FUNCTIONS: 'Special Functions', // TODO translate
|
||||
WAIT_FIRMWARE: 'Firmware is uploading and installing', // TODO translate
|
||||
INSTALL_VERSION: 'This will {0} version {1}. Are you sure?', // TODO translate
|
||||
INSTALL_VERSION: 'This will install version {0}. Are you sure?', // TODO translate
|
||||
SWITCH_DEV: 'switch to the development version', // TODO translate
|
||||
UPGRADE_AVAILABLE: 'There is a firmware upgrade available!', // TODO translate
|
||||
LATEST_VERSION: 'You are using the latest firmware version.', // TODO translate
|
||||
@@ -342,7 +342,8 @@ const pl: BaseTranslation = {
|
||||
DASHBOARD: 'Dashboard', // TODO translate
|
||||
NO_DATA: 'No data available', // TODO translate
|
||||
DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module', // TODO translate
|
||||
DEVELOPER_MODE: 'Developer Mode' // TODO translate
|
||||
DEVELOPER_MODE: 'Developer Mode', // TODO translate
|
||||
UPGRADE: 'Upgrade' // TODO translate
|
||||
};
|
||||
|
||||
export default pl;
|
||||
|
||||
@@ -331,7 +331,7 @@ const sk: Translation = {
|
||||
ALLVALUES: 'Všetky hodnoty',
|
||||
SPECIAL_FUNCTIONS: 'Špeciálne funkcie',
|
||||
WAIT_FIRMWARE: 'Firmvér sa nahráva a inštaluje',
|
||||
INSTALL_VERSION: 'Týmto sa {0} verzia {1}. Si si istý?',
|
||||
INSTALL_VERSION: 'Týmto sa inštalovať verzia {0}. Si si istý?',
|
||||
SWITCH_DEV: 'prejsť na vývojovú verziu',
|
||||
UPGRADE_AVAILABLE: 'K dispozícii je aktualizácia firmvéru!',
|
||||
LATEST_VERSION: 'Používate poslednú verziu firmvéru.',
|
||||
@@ -342,7 +342,8 @@ const sk: Translation = {
|
||||
DASHBOARD: 'Panel',
|
||||
NO_DATA: 'Nie sú k dispozícii žiadne údaje',
|
||||
DASHBOARD_1: 'Prispôsobte si svoj informačný panel tak, že označíte entity EMS ako Obľúbené pomocou modulu Prispôsobenia',
|
||||
DEVELOPER_MODE: 'Developer Mode' // TODO translate
|
||||
DEVELOPER_MODE: 'Developer Mode', // TODO translate
|
||||
UPGRADE: 'Upgrade' // TODO translate
|
||||
};
|
||||
|
||||
export default sk;
|
||||
|
||||
@@ -331,7 +331,7 @@ const sv: Translation = {
|
||||
ALLVALUES: 'All Values', // TODO translate
|
||||
SPECIAL_FUNCTIONS: 'Special Functions', // TODO translate
|
||||
WAIT_FIRMWARE: 'Firmware is uploading and installing', // TODO translate
|
||||
INSTALL_VERSION: 'This will {0} version {1}. Are you sure?', // TODO translate
|
||||
INSTALL_VERSION: 'This will install version {0}. Are you sure?', // TODO translate
|
||||
SWITCH_DEV: 'switch to the development version', // TODO translate
|
||||
UPGRADE_AVAILABLE: 'There is a firmware upgrade available!', // TODO translate
|
||||
LATEST_VERSION: 'You are using the latest firmware version.', // TODO translate
|
||||
@@ -342,7 +342,8 @@ const sv: Translation = {
|
||||
DASHBOARD: 'Dashboard', // TODO translate
|
||||
NO_DATA: 'No data available', // TODO translate
|
||||
DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module', // TODO translate
|
||||
DEVELOPER_MODE: 'Developer Mode' // TODO translate
|
||||
DEVELOPER_MODE: 'Developer Mode', // TODO translate
|
||||
UPGRADE: 'Upgrade' // TODO translate
|
||||
};
|
||||
|
||||
export default sv;
|
||||
|
||||
@@ -331,7 +331,7 @@ const tr: Translation = {
|
||||
ALLVALUES: 'All Values', // TODO translate
|
||||
SPECIAL_FUNCTIONS: 'Special Functions', // TODO translate
|
||||
WAIT_FIRMWARE: 'Firmware is uploading and installing', // TODO translate
|
||||
INSTALL_VERSION: 'This will {0} version {1}. Are you sure?', // TODO translate
|
||||
INSTALL_VERSION: 'This will install version {0}. Are you sure?', // TODO translate
|
||||
SWITCH_DEV: 'switch to the development version', // TODO translate
|
||||
UPGRADE_AVAILABLE: 'There is a firmware upgrade available!', // TODO translate
|
||||
LATEST_VERSION: 'You are using the latest firmware version.', // TODO translate
|
||||
@@ -342,7 +342,8 @@ const tr: Translation = {
|
||||
DASHBOARD: 'Dashboard', // TODO translate
|
||||
NO_DATA: 'No data available', // TODO translate
|
||||
DASHBOARD_1: 'Customize your dashboard by marking EMS entities as Favorite using the Customizations module', // TODO translate
|
||||
DEVELOPER_MODE: 'Developer Mode' // TODO translate
|
||||
DEVELOPER_MODE: 'Developer Mode', // TODO translate
|
||||
UPGRADE: 'Upgrade' // TODO translate
|
||||
};
|
||||
|
||||
export default tr;
|
||||
|
||||
@@ -30,14 +30,14 @@ const headers = {
|
||||
};
|
||||
|
||||
// Versions - all without the 'v'
|
||||
let THIS_VERSION = '3.7.1';
|
||||
let THIS_VERSION = '3.7.0';
|
||||
let LATEST_STABLE_VERSION = '3.7.0';
|
||||
let LATEST_DEV_VERSION = '3.7.1-dev.4';
|
||||
let LATEST_DEV_VERSION = '3.7.1-dev.1';
|
||||
let VERSION_IS_UPGRADEABLE = false;
|
||||
|
||||
// for testing - scenario 1
|
||||
// THIS_VERSION = '3.7.1-dev.1';
|
||||
// VERSION_IS_UPGRADEABLE = true;
|
||||
THIS_VERSION = '3.7.1-dev.1';
|
||||
VERSION_IS_UPGRADEABLE = true;
|
||||
|
||||
// for testing - scenario 2
|
||||
// THIS_VERSION = '3.6.5';
|
||||
|
||||
Reference in New Issue
Block a user