mirror of
https://github.com/OpenNebula/one.git
synced 2025-01-27 14:03:40 +03:00
parent
11b6f1565e
commit
22143403b6
@ -57,7 +57,7 @@ const FormWithSchema = ({
|
|||||||
const formContext = useFormContext()
|
const formContext = useFormContext()
|
||||||
const { control, watch } = formContext
|
const { control, watch } = formContext
|
||||||
|
|
||||||
const { sx: sxRoot, restOfRootProps } = rootProps ?? {}
|
const { sx: sxRoot, ...restOfRootProps } = rootProps ?? {}
|
||||||
|
|
||||||
const getFields = useMemo(
|
const getFields = useMemo(
|
||||||
() => (typeof fields === 'function' ? fields() : fields),
|
() => (typeof fields === 'function' ? fields() : fields),
|
||||||
|
@ -18,7 +18,7 @@ import PropTypes from 'prop-types'
|
|||||||
import { styled, Typography } from '@mui/material'
|
import { styled, Typography } from '@mui/material'
|
||||||
|
|
||||||
import AdornmentWithTooltip from 'client/components/FormControl/Tooltip'
|
import AdornmentWithTooltip from 'client/components/FormControl/Tooltip'
|
||||||
import { Tr, labelCanBeTranslated } from 'client/components/HOC'
|
import { Translate, labelCanBeTranslated } from 'client/components/HOC'
|
||||||
|
|
||||||
const StyledLegend = styled((props) => (
|
const StyledLegend = styled((props) => (
|
||||||
<Typography variant="subtitle1" component="legend" {...props} />
|
<Typography variant="subtitle1" component="legend" {...props} />
|
||||||
@ -35,7 +35,7 @@ const StyledLegend = styled((props) => (
|
|||||||
const Legend = memo(
|
const Legend = memo(
|
||||||
({ title, tooltip }) => (
|
({ title, tooltip }) => (
|
||||||
<StyledLegend tooltip={tooltip}>
|
<StyledLegend tooltip={tooltip}>
|
||||||
{labelCanBeTranslated(title) ? Tr(title) : title}
|
{labelCanBeTranslated(title) ? <Translate word={title} /> : title}
|
||||||
{!!tooltip && <AdornmentWithTooltip title={tooltip} />}
|
{!!tooltip && <AdornmentWithTooltip title={tooltip} />}
|
||||||
</StyledLegend>
|
</StyledLegend>
|
||||||
),
|
),
|
||||||
|
@ -86,6 +86,7 @@ module.exports = {
|
|||||||
Pin: 'Pin',
|
Pin: 'Pin',
|
||||||
Poweroff: 'Poweroff',
|
Poweroff: 'Poweroff',
|
||||||
PoweroffHard: 'Poweroff hard',
|
PoweroffHard: 'Poweroff hard',
|
||||||
|
PressEscapeToCancel: 'Press Escape to cancel',
|
||||||
Reboot: 'Reboot',
|
Reboot: 'Reboot',
|
||||||
RebootHard: 'Reboot hard',
|
RebootHard: 'Reboot hard',
|
||||||
Recover: 'Recover',
|
Recover: 'Recover',
|
||||||
@ -269,6 +270,9 @@ module.exports = {
|
|||||||
Language: 'Language',
|
Language: 'Language',
|
||||||
DisableDashboardAnimations: 'Disable dashboard animations',
|
DisableDashboardAnimations: 'Disable dashboard animations',
|
||||||
ConfigurationUI: 'Configuration UI',
|
ConfigurationUI: 'Configuration UI',
|
||||||
|
Authentication: 'Authentication',
|
||||||
|
SshPrivateKey: 'SSH private key',
|
||||||
|
SshPassphraseKey: 'SSH private key passphrase',
|
||||||
|
|
||||||
/* sections - system */
|
/* sections - system */
|
||||||
User: 'User',
|
User: 'User',
|
||||||
|
@ -0,0 +1,157 @@
|
|||||||
|
/* ------------------------------------------------------------------------- *
|
||||||
|
* Copyright 2002-2022, OpenNebula Project, OpenNebula Systems *
|
||||||
|
* *
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may *
|
||||||
|
* not use this file except in compliance with the License. You may obtain *
|
||||||
|
* a copy of the License at *
|
||||||
|
* *
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 *
|
||||||
|
* *
|
||||||
|
* Unless required by applicable law or agreed to in writing, software *
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, *
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
|
||||||
|
* See the License for the specific language governing permissions and *
|
||||||
|
* limitations under the License. *
|
||||||
|
* ------------------------------------------------------------------------- */
|
||||||
|
import { ReactElement, useMemo, memo, useState } from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import {
|
||||||
|
Paper,
|
||||||
|
Stack,
|
||||||
|
IconButton,
|
||||||
|
Typography,
|
||||||
|
Skeleton,
|
||||||
|
TextField,
|
||||||
|
} from '@mui/material'
|
||||||
|
import { Edit } from 'iconoir-react'
|
||||||
|
import { useForm } from 'react-hook-form'
|
||||||
|
import { yupResolver } from '@hookform/resolvers/yup'
|
||||||
|
|
||||||
|
import { useAuth } from 'client/features/Auth'
|
||||||
|
import { useUpdateUserMutation } from 'client/features/OneApi/user'
|
||||||
|
import { useGeneralApi } from 'client/features/General'
|
||||||
|
|
||||||
|
import {
|
||||||
|
FIELDS,
|
||||||
|
SCHEMA,
|
||||||
|
} from 'client/containers/Settings/Authentication/schema'
|
||||||
|
import { Translate } from 'client/components/HOC'
|
||||||
|
import { Legend } from 'client/components/Forms'
|
||||||
|
import { jsonToXml } from 'client/models/Helper'
|
||||||
|
import { sanitize } from 'client/utils'
|
||||||
|
import { T } from 'client/constants'
|
||||||
|
|
||||||
|
/** @returns {ReactElement} Settings authentication */
|
||||||
|
const Settings = () => (
|
||||||
|
<Paper variant="outlined" sx={{ py: '1.5em' }}>
|
||||||
|
<Stack gap="1em">
|
||||||
|
{FIELDS.map((field) => (
|
||||||
|
<FieldComponent
|
||||||
|
key={'settings-authentication-field-' + field.name}
|
||||||
|
field={field}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
)
|
||||||
|
|
||||||
|
const FieldComponent = memo(({ field }) => {
|
||||||
|
const [isEnabled, setIsEnabled] = useState(false)
|
||||||
|
const { name, label, tooltip } = field
|
||||||
|
|
||||||
|
const { user, settings } = useAuth()
|
||||||
|
const [updateUser, { isLoading }] = useUpdateUserMutation()
|
||||||
|
const { enqueueError } = useGeneralApi()
|
||||||
|
|
||||||
|
const defaultValues = useMemo(() => SCHEMA.cast(settings), [settings])
|
||||||
|
|
||||||
|
const { watch, register, reset } = useForm({
|
||||||
|
reValidateMode: 'onSubmit',
|
||||||
|
defaultValues,
|
||||||
|
resolver: yupResolver(SCHEMA),
|
||||||
|
})
|
||||||
|
|
||||||
|
const sanitizedValue = useMemo(() => sanitize`${watch(name)}`, [isEnabled])
|
||||||
|
|
||||||
|
const handleUpdateUser = async () => {
|
||||||
|
try {
|
||||||
|
if (isLoading || !isEnabled) return
|
||||||
|
|
||||||
|
const castedData = SCHEMA.cast(watch(), { isSubmit: true })
|
||||||
|
const template = jsonToXml(castedData)
|
||||||
|
|
||||||
|
updateUser({ id: user.ID, template })
|
||||||
|
setIsEnabled(false)
|
||||||
|
} catch {
|
||||||
|
enqueueError(T.SomethingWrong)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleBlur = () => {
|
||||||
|
handleUpdateUser()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleKeyDown = (evt) => {
|
||||||
|
if (evt.key === 'Escape') {
|
||||||
|
reset(defaultValues)
|
||||||
|
setIsEnabled(false)
|
||||||
|
evt.stopPropagation()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (evt.key === 'Enter') {
|
||||||
|
handleUpdateUser()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack component="fieldset" sx={{ minInlineSize: 'auto' }}>
|
||||||
|
<Legend title={label} tooltip={tooltip} />
|
||||||
|
{isEnabled ? (
|
||||||
|
<>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
autoFocus
|
||||||
|
multiline
|
||||||
|
rows={5}
|
||||||
|
variant="outlined"
|
||||||
|
onKeyDown={handleKeyDown}
|
||||||
|
helperText={<Translate word={T.PressEscapeToCancel} />}
|
||||||
|
{...register(field.name, { onBlur: handleBlur })}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<Stack
|
||||||
|
direction="row"
|
||||||
|
justifyContent="space-between"
|
||||||
|
alignItems="center"
|
||||||
|
gap="1em"
|
||||||
|
paddingX={1}
|
||||||
|
>
|
||||||
|
{isLoading ? (
|
||||||
|
<>
|
||||||
|
<Skeleton variant="text" width="100%" height={36} />
|
||||||
|
<Skeleton variant="circular" width={28} height={28} />
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Typography noWrap title={sanitizedValue}>
|
||||||
|
{sanitizedValue}
|
||||||
|
</Typography>
|
||||||
|
<IconButton onClick={() => setIsEnabled(true)}>
|
||||||
|
<Edit />
|
||||||
|
</IconButton>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
FieldComponent.propTypes = {
|
||||||
|
field: PropTypes.object.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
FieldComponent.displayName = 'FieldComponent'
|
||||||
|
|
||||||
|
export default Settings
|
@ -0,0 +1,53 @@
|
|||||||
|
/* ------------------------------------------------------------------------- *
|
||||||
|
* Copyright 2002-2022, OpenNebula Project, OpenNebula Systems *
|
||||||
|
* *
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may *
|
||||||
|
* not use this file except in compliance with the License. You may obtain *
|
||||||
|
* a copy of the License at *
|
||||||
|
* *
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 *
|
||||||
|
* *
|
||||||
|
* Unless required by applicable law or agreed to in writing, software *
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, *
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
|
||||||
|
* See the License for the specific language governing permissions and *
|
||||||
|
* limitations under the License. *
|
||||||
|
* ------------------------------------------------------------------------- */
|
||||||
|
import { object, string } from 'yup'
|
||||||
|
import { getValidationFromFields } from 'client/utils'
|
||||||
|
import { T, INPUT_TYPES } from 'client/constants'
|
||||||
|
|
||||||
|
const PUBLIC_KEY_FIELD = {
|
||||||
|
name: 'SSH_PUBLIC_KEY',
|
||||||
|
label: T.SshPublicKey,
|
||||||
|
tooltip: T.AddUserSshPublicKey,
|
||||||
|
type: INPUT_TYPES.TEXT,
|
||||||
|
validation: string()
|
||||||
|
.trim()
|
||||||
|
.required()
|
||||||
|
.default(() => undefined),
|
||||||
|
}
|
||||||
|
|
||||||
|
const PRIVATE_KEY_FIELD = {
|
||||||
|
name: 'SSH_PRIVATE_KEY',
|
||||||
|
label: T.SshPrivateKey,
|
||||||
|
type: INPUT_TYPES.TEXT,
|
||||||
|
validation: string()
|
||||||
|
.trim()
|
||||||
|
.required()
|
||||||
|
.default(() => undefined),
|
||||||
|
}
|
||||||
|
|
||||||
|
const PASSPHRASE_FIELD = {
|
||||||
|
name: 'SSH_PASSPHRASE',
|
||||||
|
label: T.SshPassphraseKey,
|
||||||
|
type: INPUT_TYPES.TEXT,
|
||||||
|
validation: string()
|
||||||
|
.trim()
|
||||||
|
.required()
|
||||||
|
.default(() => undefined),
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FIELDS = [PUBLIC_KEY_FIELD, PRIVATE_KEY_FIELD, PASSPHRASE_FIELD]
|
||||||
|
|
||||||
|
export const SCHEMA = object(getValidationFromFields(FIELDS))
|
@ -0,0 +1,88 @@
|
|||||||
|
/* ------------------------------------------------------------------------- *
|
||||||
|
* Copyright 2002-2022, OpenNebula Project, OpenNebula Systems *
|
||||||
|
* *
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may *
|
||||||
|
* not use this file except in compliance with the License. You may obtain *
|
||||||
|
* a copy of the License at *
|
||||||
|
* *
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 *
|
||||||
|
* *
|
||||||
|
* Unless required by applicable law or agreed to in writing, software *
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, *
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
|
||||||
|
* See the License for the specific language governing permissions and *
|
||||||
|
* limitations under the License. *
|
||||||
|
* ------------------------------------------------------------------------- */
|
||||||
|
import { ReactElement, useEffect, useMemo, useRef } from 'react'
|
||||||
|
import { Paper, Stack, CircularProgress } from '@mui/material'
|
||||||
|
import { useForm, FormProvider } from 'react-hook-form'
|
||||||
|
import { yupResolver } from '@hookform/resolvers/yup'
|
||||||
|
|
||||||
|
import { useAuth } from 'client/features/Auth'
|
||||||
|
import { useUpdateUserMutation } from 'client/features/OneApi/user'
|
||||||
|
import { useGeneralApi } from 'client/features/General'
|
||||||
|
|
||||||
|
import {
|
||||||
|
FIELDS,
|
||||||
|
SCHEMA,
|
||||||
|
} from 'client/containers/Settings/ConfigurationUI/schema'
|
||||||
|
import { FormWithSchema } from 'client/components/Forms'
|
||||||
|
import { Translate } from 'client/components/HOC'
|
||||||
|
import { jsonToXml } from 'client/models/Helper'
|
||||||
|
import { T } from 'client/constants'
|
||||||
|
|
||||||
|
/** @returns {ReactElement} Settings configuration UI */
|
||||||
|
const Settings = () => {
|
||||||
|
const fieldsetRef = useRef([])
|
||||||
|
const { user, settings } = useAuth()
|
||||||
|
const [updateUser, { isLoading }] = useUpdateUserMutation()
|
||||||
|
const { enqueueError } = useGeneralApi()
|
||||||
|
|
||||||
|
const { watch, ...methods } = useForm({
|
||||||
|
reValidateMode: 'onSubmit',
|
||||||
|
defaultValues: useMemo(() => SCHEMA.cast(settings), [settings]),
|
||||||
|
resolver: yupResolver(SCHEMA),
|
||||||
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
watch((formData) => {
|
||||||
|
try {
|
||||||
|
if (isLoading) return
|
||||||
|
|
||||||
|
const castedData = SCHEMA.cast(formData, { isSubmit: true })
|
||||||
|
const template = jsonToXml(castedData)
|
||||||
|
|
||||||
|
updateUser({ id: user.ID, template })
|
||||||
|
} catch {
|
||||||
|
enqueueError(T.SomethingWrong)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, [watch])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fieldsetRef.current.disabled = isLoading
|
||||||
|
}, [isLoading])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Paper
|
||||||
|
variant="outlined"
|
||||||
|
sx={{ p: '1em', maxWidth: { sm: 'auto', md: 550 } }}
|
||||||
|
>
|
||||||
|
<FormProvider {...methods}>
|
||||||
|
<FormWithSchema
|
||||||
|
cy={'settings-ui'}
|
||||||
|
fields={FIELDS}
|
||||||
|
rootProps={{ ref: fieldsetRef }}
|
||||||
|
legend={
|
||||||
|
<Stack direction="row" alignItems="center" gap="1em">
|
||||||
|
<Translate word={T.ConfigurationUI} />
|
||||||
|
{isLoading && <CircularProgress size={20} color="secondary" />}
|
||||||
|
</Stack>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</FormProvider>
|
||||||
|
</Paper>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Settings
|
@ -13,8 +13,8 @@
|
|||||||
* See the License for the specific language governing permissions and *
|
* See the License for the specific language governing permissions and *
|
||||||
* limitations under the License. *
|
* limitations under the License. *
|
||||||
* ------------------------------------------------------------------------- */
|
* ------------------------------------------------------------------------- */
|
||||||
import { object, boolean, string } from 'yup'
|
import { boolean, string } from 'yup'
|
||||||
import { arrayToOptions, getValidationFromFields } from 'client/utils'
|
import { arrayToOptions, getObjectSchemaFromFields } from 'client/utils'
|
||||||
import {
|
import {
|
||||||
T,
|
T,
|
||||||
INPUT_TYPES,
|
INPUT_TYPES,
|
||||||
@ -25,7 +25,7 @@ import {
|
|||||||
} from 'client/constants'
|
} from 'client/constants'
|
||||||
|
|
||||||
const SCHEME_FIELD = {
|
const SCHEME_FIELD = {
|
||||||
name: 'SCHEME',
|
name: 'FIREEDGE.SCHEME',
|
||||||
label: T.Schema,
|
label: T.Schema,
|
||||||
type: INPUT_TYPES.SELECT,
|
type: INPUT_TYPES.SELECT,
|
||||||
values: [
|
values: [
|
||||||
@ -41,7 +41,7 @@ const SCHEME_FIELD = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const LANG_FIELD = {
|
const LANG_FIELD = {
|
||||||
name: 'LANG',
|
name: 'FIREEDGE.LANG',
|
||||||
label: T.Language,
|
label: T.Language,
|
||||||
type: INPUT_TYPES.SELECT,
|
type: INPUT_TYPES.SELECT,
|
||||||
values: () =>
|
values: () =>
|
||||||
@ -58,7 +58,7 @@ const LANG_FIELD = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const DISABLE_ANIMATIONS_FIELD = {
|
const DISABLE_ANIMATIONS_FIELD = {
|
||||||
name: 'DISABLE_ANIMATIONS',
|
name: 'FIREEDGE.DISABLE_ANIMATIONS',
|
||||||
label: T.DisableDashboardAnimations,
|
label: T.DisableDashboardAnimations,
|
||||||
type: INPUT_TYPES.CHECKBOX,
|
type: INPUT_TYPES.CHECKBOX,
|
||||||
validation: boolean()
|
validation: boolean()
|
||||||
@ -67,6 +67,6 @@ const DISABLE_ANIMATIONS_FIELD = {
|
|||||||
grid: { md: 12 },
|
grid: { md: 12 },
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FORM_FIELDS = [SCHEME_FIELD, LANG_FIELD, DISABLE_ANIMATIONS_FIELD]
|
export const FIELDS = [SCHEME_FIELD, LANG_FIELD, DISABLE_ANIMATIONS_FIELD]
|
||||||
|
|
||||||
export const FORM_SCHEMA = object(getValidationFromFields(FORM_FIELDS))
|
export const SCHEMA = getObjectSchemaFromFields(FIELDS)
|
@ -13,88 +13,29 @@
|
|||||||
* See the License for the specific language governing permissions and *
|
* See the License for the specific language governing permissions and *
|
||||||
* limitations under the License. *
|
* limitations under the License. *
|
||||||
* ------------------------------------------------------------------------- */
|
* ------------------------------------------------------------------------- */
|
||||||
import { ReactElement, useMemo } from 'react'
|
import { ReactElement } from 'react'
|
||||||
import { Container, Paper, Box, Typography, Divider } from '@mui/material'
|
import { Container, Typography, Divider, Stack } from '@mui/material'
|
||||||
import { useForm, FormProvider } from 'react-hook-form'
|
|
||||||
import { yupResolver } from '@hookform/resolvers/yup'
|
|
||||||
|
|
||||||
import FormWithSchema from 'client/components/Forms/FormWithSchema'
|
import { Translate } from 'client/components/HOC'
|
||||||
import SubmitButton from 'client/components/FormControl/SubmitButton'
|
|
||||||
|
|
||||||
import { useAuth } from 'client/features/Auth'
|
|
||||||
import { useLazyGetAuthUserQuery } from 'client/features/AuthApi'
|
|
||||||
import { useUpdateUserMutation } from 'client/features/OneApi/user'
|
|
||||||
import { useGeneralApi } from 'client/features/General'
|
|
||||||
import { Translate, Tr } from 'client/components/HOC'
|
|
||||||
import { T } from 'client/constants'
|
import { T } from 'client/constants'
|
||||||
|
|
||||||
import { FORM_FIELDS, FORM_SCHEMA } from 'client/containers/Settings/schema'
|
import ConfigurationUISection from 'client/containers/Settings/ConfigurationUI'
|
||||||
import * as Helper from 'client/models/Helper'
|
import AuthenticationSection from 'client/containers/Settings/Authentication'
|
||||||
|
|
||||||
/** @returns {ReactElement} Settings container */
|
/** @returns {ReactElement} Settings container */
|
||||||
const Settings = () => {
|
const Settings = () => (
|
||||||
const { user, settings } = useAuth()
|
<Container disableGutters>
|
||||||
const [getAuthUser] = useLazyGetAuthUserQuery()
|
<Typography variant="h5">
|
||||||
const [updateUser] = useUpdateUserMutation()
|
<Translate word={T.Settings} />
|
||||||
const { enqueueError } = useGeneralApi()
|
</Typography>
|
||||||
|
|
||||||
const { handleSubmit, reset, formState, ...methods } = useForm({
|
<Divider sx={{ my: '1em' }} />
|
||||||
reValidateMode: 'onSubmit',
|
|
||||||
defaultValues: useMemo(() => FORM_SCHEMA.cast(settings), [settings]),
|
|
||||||
resolver: yupResolver(FORM_SCHEMA),
|
|
||||||
})
|
|
||||||
|
|
||||||
const onSubmit = async (formData) => {
|
<Stack gap="1em">
|
||||||
try {
|
<ConfigurationUISection />
|
||||||
const data = FORM_SCHEMA.cast(formData, { isSubmit: true })
|
<AuthenticationSection />
|
||||||
const template = Helper.jsonToXml({ FIREEDGE: data })
|
</Stack>
|
||||||
await updateUser({ id: user.ID, template })
|
</Container>
|
||||||
await getAuthUser()
|
)
|
||||||
|
|
||||||
// Reset either the entire form state or part of the form state
|
|
||||||
reset(formData)
|
|
||||||
} catch {
|
|
||||||
enqueueError(T.SomethingWrong)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Container disableGutters>
|
|
||||||
<Typography variant="h5" pt="1em">
|
|
||||||
<Translate word={T.Settings} />
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
<Divider sx={{ my: '1em' }} />
|
|
||||||
|
|
||||||
<Paper
|
|
||||||
variant="outlined"
|
|
||||||
sx={{
|
|
||||||
p: '1em',
|
|
||||||
maxWidth: { sm: 'auto', md: 550 },
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Box component="form" onSubmit={handleSubmit(onSubmit)}>
|
|
||||||
<FormProvider {...methods}>
|
|
||||||
<FormWithSchema
|
|
||||||
cy="settings"
|
|
||||||
fields={FORM_FIELDS}
|
|
||||||
legend={T.ConfigurationUI}
|
|
||||||
/>
|
|
||||||
</FormProvider>
|
|
||||||
<Box py="1em" textAlign="end">
|
|
||||||
<SubmitButton
|
|
||||||
color="secondary"
|
|
||||||
data-cy="settings-submit-button"
|
|
||||||
label={Tr(T.Save)}
|
|
||||||
onClick={handleSubmit}
|
|
||||||
disabled={!formState.isDirty}
|
|
||||||
isSubmitting={formState.isSubmitting}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
</Paper>
|
|
||||||
</Container>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Settings
|
export default Settings
|
||||||
|
@ -72,6 +72,7 @@ export const useAuth = () => {
|
|||||||
SCHEME: DEFAULT_SCHEME,
|
SCHEME: DEFAULT_SCHEME,
|
||||||
LANG: DEFAULT_LANGUAGE,
|
LANG: DEFAULT_LANGUAGE,
|
||||||
DISABLE_ANIMATIONS: 'NO',
|
DISABLE_ANIMATIONS: 'NO',
|
||||||
|
...(user?.TEMPLATE ?? {}),
|
||||||
...(user?.TEMPLATE?.FIREEDGE ?? {}),
|
...(user?.TEMPLATE?.FIREEDGE ?? {}),
|
||||||
},
|
},
|
||||||
isLogged:
|
isLogged:
|
||||||
|
@ -19,6 +19,7 @@ import {
|
|||||||
ONE_RESOURCES,
|
ONE_RESOURCES,
|
||||||
ONE_RESOURCES_POOL,
|
ONE_RESOURCES_POOL,
|
||||||
} from 'client/features/OneApi'
|
} from 'client/features/OneApi'
|
||||||
|
import { authApi } from 'client/features/AuthApi'
|
||||||
import { User } from 'client/constants'
|
import { User } from 'client/constants'
|
||||||
|
|
||||||
const { USER } = ONE_RESOURCES
|
const { USER } = ONE_RESOURCES
|
||||||
@ -109,6 +110,19 @@ const userApi = oneApi.injectEndpoints({
|
|||||||
return { params, command }
|
return { params, command }
|
||||||
},
|
},
|
||||||
invalidatesTags: (_, __, { id }) => [{ type: USER, id }],
|
invalidatesTags: (_, __, { id }) => [{ type: USER, id }],
|
||||||
|
async onQueryStarted({ id }, { queryFulfilled, dispatch, getState }) {
|
||||||
|
try {
|
||||||
|
await queryFulfilled
|
||||||
|
|
||||||
|
if (+id === +getState().auth.user.ID) {
|
||||||
|
dispatch(
|
||||||
|
authApi.endpoints.getAuthUser.initiate(undefined, {
|
||||||
|
forceRefetch: true,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
removeUser: builder.mutation({
|
removeUser: builder.mutation({
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user