From e250bd38f8a9a97254cdc4beecc7b7ef417f724b Mon Sep 17 00:00:00 2001 From: Charles Date: Fri, 15 Mar 2024 17:51:59 +0100 Subject: [PATCH] [WIFI-13515] Supporting deviceTypes in lowercase Signed-off-by: Charles --- package-lock.json | 4 +- package.json | 2 +- .../MultiSelectField/FastMultiSelectInput.jsx | 90 ++++++++++++------- .../Form/MultiSelectField/index.jsx | 45 +++++++--- .../List/CreateModal.tsx | 60 +++++++------ .../DefaultConfigurations/List/EditModal.tsx | 61 +++++++------ src/pages/DefaultConfigurations/utils.ts | 2 +- 7 files changed, 160 insertions(+), 104 deletions(-) diff --git a/package-lock.json b/package-lock.json index a4f1119..df74b86 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ucentral-client", - "version": "3.0.2(8)", + "version": "3.0.2(9)", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ucentral-client", - "version": "3.0.2(8)", + "version": "3.0.2(9)", "license": "ISC", "dependencies": { "@chakra-ui/anatomy": "^2.1.1", diff --git a/package.json b/package.json index 01fedfa..0b119b6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ucentral-client", - "version": "3.0.2(8)", + "version": "3.0.2(9)", "description": "", "private": true, "main": "index.tsx", diff --git a/src/components/Form/MultiSelectField/FastMultiSelectInput.jsx b/src/components/Form/MultiSelectField/FastMultiSelectInput.jsx index 35f8007..0471fe7 100644 --- a/src/components/Form/MultiSelectField/FastMultiSelectInput.jsx +++ b/src/components/Form/MultiSelectField/FastMultiSelectInput.jsx @@ -1,6 +1,6 @@ import React from 'react'; import { FormControl, FormErrorMessage, FormLabel } from '@chakra-ui/react'; -import { Select } from 'chakra-react-select'; +import { CreatableSelect, Select } from 'chakra-react-select'; import PropTypes from 'prop-types'; import isEqual from 'react-fast-compare'; import { useTranslation } from 'react-i18next'; @@ -25,6 +25,7 @@ const propTypes = { isHidden: PropTypes.bool, isPortal: PropTypes.bool.isRequired, definitionKey: PropTypes.string, + isCreatable: PropTypes.bool, }; const defaultProps = { @@ -36,6 +37,7 @@ const defaultProps = { isDisabled: false, isHidden: false, definitionKey: null, + isCreatable: false, }; const FastMultiSelectInput = ({ @@ -50,6 +52,7 @@ const FastMultiSelectInput = ({ isRequired, isDisabled, isHidden, + isCreatable, isPortal, definitionKey, }) => { @@ -61,35 +64,62 @@ const FastMultiSelectInput = ({ {label} - ({ + ...provided, + borderRadius: '15px', + opacity: isControlDisabled ? '0.8 !important' : '1', + border: '2px solid', + }), + dropdownIndicator: (provided) => ({ + ...provided, + backgroundColor: 'unset', + border: 'unset', + }), + }} + classNamePrefix={isPortal ? 'chakra-react-select' : ''} + menuPortalTarget={isPortal ? document.body : undefined} + isMulti + closeMenuOnSelect={false} + options={canSelectAll ? [{ value: '*', label: t('common.all') }, ...options] : options} + value={ + value?.map((val) => { + if (val === '*') return { value: val, label: t('common.all') }; + return options.find((opt) => opt.value === val); + }) ?? [] + } + onChange={onChange} + onBlur={onBlur} + isDisabled={isDisabled} + /> + )} {error} ); diff --git a/src/components/Form/MultiSelectField/index.jsx b/src/components/Form/MultiSelectField/index.jsx index 6206a32..5c29814 100644 --- a/src/components/Form/MultiSelectField/index.jsx +++ b/src/components/Form/MultiSelectField/index.jsx @@ -20,6 +20,7 @@ const propTypes = { canSelectAll: PropTypes.bool, isPortal: PropTypes.bool, definitionKey: PropTypes.string, + isCreatable: PropTypes.bool, }; const defaultProps = { @@ -31,6 +32,7 @@ const defaultProps = { canSelectAll: false, isPortal: false, definitionKey: null, + isCreatable: false, }; const MultiSelectField = ({ @@ -43,25 +45,39 @@ const MultiSelectField = ({ emptyIsUndefined, canSelectAll, hasVirtualAll, + isCreatable, isPortal, definitionKey, }) => { const [{ value }, { touched, error }, { setValue, setTouched }] = useField(name); - const onChange = useCallback((option) => { - const allIndex = option.findIndex((opt) => opt.value === '*'); - if (option.length === 0 && emptyIsUndefined) { - setValue(undefined); - } else if (allIndex === 0 && option.length > 1) { - const newValues = option.slice(1); - setValue(newValues.map((val) => val.value)); - } else if (allIndex >= 0) { - if (!hasVirtualAll) setValue(['*']); - else setValue(options.map(({ value: v }) => v)); - } else if (option.length > 0) setValue(option.map((val) => val.value)); - else setValue([]); - setTouched(true); - }, []); + const onChange = useCallback( + (option) => { + if (isCreatable) { + if (typeof option === 'string') { + setValue([...value, option]); + } else { + setValue(option); + } + + // setValue([...value, option]); + } else { + const allIndex = option.findIndex((opt) => opt.value === '*'); + if (option.length === 0 && emptyIsUndefined) { + setValue(undefined); + } else if (allIndex === 0 && option.length > 1) { + const newValues = option.slice(1); + setValue(newValues.map((val) => val.value)); + } else if (allIndex >= 0) { + if (!hasVirtualAll) setValue(['*']); + else setValue(options.map(({ value: v }) => v)); + } else if (option.length > 0) setValue(option.map((val) => val.value)); + else setValue([]); + setTouched(true); + } + }, + [value], + ); const onFieldBlur = useCallback(() => { setTouched(true); @@ -82,6 +98,7 @@ const MultiSelectField = ({ isHidden={isHidden} isPortal={isPortal} definitionKey={definitionKey} + isCreatable={isCreatable} /> ); }; diff --git a/src/pages/DefaultConfigurations/List/CreateModal.tsx b/src/pages/DefaultConfigurations/List/CreateModal.tsx index 2cdabd7..3a36e81 100644 --- a/src/pages/DefaultConfigurations/List/CreateModal.tsx +++ b/src/pages/DefaultConfigurations/List/CreateModal.tsx @@ -69,35 +69,38 @@ const CreateDefaultConfigurationModal = () => { key={formKey} validationSchema={DefaultConfigurationSchema(t)} onSubmit={(data, { setSubmitting, resetForm }) => { - createConfig.mutateAsync(data, { - onSuccess: () => { - toast({ - id: `config-create-success`, - title: t('common.success'), - description: t('controller.configurations.create_success'), - status: 'success', - duration: 5000, - isClosable: true, - position: 'top-right', - }); - setSubmitting(false); - resetForm(); - modalProps.onClose(); + createConfig.mutateAsync( + { ...data, modelIds: data.modelIds.map((v) => v.value) }, + { + onSuccess: () => { + toast({ + id: `config-create-success`, + title: t('common.success'), + description: t('controller.configurations.create_success'), + status: 'success', + duration: 5000, + isClosable: true, + position: 'top-right', + }); + setSubmitting(false); + resetForm(); + modalProps.onClose(); + }, + onError: (error) => { + const e = error as AxiosError; + toast({ + id: `config-create-error`, + title: t('common.error'), + description: e?.response?.data?.ErrorDescription, + status: 'error', + duration: 5000, + isClosable: true, + position: 'top-right', + }); + setSubmitting(false); + }, }, - onError: (error) => { - const e = error as AxiosError; - toast({ - id: `config-create-error`, - title: t('common.error'), - description: e?.response?.data?.ErrorDescription, - status: 'error', - duration: 5000, - isClosable: true, - position: 'top-right', - }); - setSubmitting(false); - }, - }); + ); }} > @@ -133,6 +136,7 @@ const CreateDefaultConfigurationModal = () => { value: devType, })) ?? [] } + isCreatable isRequired /> diff --git a/src/pages/DefaultConfigurations/List/EditModal.tsx b/src/pages/DefaultConfigurations/List/EditModal.tsx index d85d54c..3295656 100644 --- a/src/pages/DefaultConfigurations/List/EditModal.tsx +++ b/src/pages/DefaultConfigurations/List/EditModal.tsx @@ -70,40 +70,44 @@ const EditDefaultConfiguration = ({ modalProps, config }: Props) => { innerRef={formRef as React.Ref>} initialValues={{ ...config, + modelIds: config.modelIds.map((v) => ({ label: v, value: v })), configuration: JSON.stringify(config.configuration, null, 2), }} key={formKey} validationSchema={DefaultConfigurationSchema(t)} onSubmit={(data, { setSubmitting, resetForm }) => { - updateConfig.mutateAsync(data, { - onSuccess: () => { - toast({ - id: `config-edit-success`, - title: t('common.success'), - description: t('controller.configurations.update_success'), - status: 'success', - duration: 5000, - isClosable: true, - position: 'top-right', - }); - setSubmitting(false); - resetForm(); - modalProps.onClose(); + updateConfig.mutateAsync( + { ...data, modelIds: data.modelIds.map((v) => v.value) }, + { + onSuccess: () => { + toast({ + id: `config-edit-success`, + title: t('common.success'), + description: t('controller.configurations.update_success'), + status: 'success', + duration: 5000, + isClosable: true, + position: 'top-right', + }); + setSubmitting(false); + resetForm(); + modalProps.onClose(); + }, + onError: (error) => { + const e = error as AxiosError; + toast({ + id: `config-edit-error`, + title: t('common.error'), + description: e?.response?.data?.ErrorDescription, + status: 'error', + duration: 5000, + isClosable: true, + position: 'top-right', + }); + setSubmitting(false); + }, }, - onError: (error) => { - const e = error as AxiosError; - toast({ - id: `config-edit-error`, - title: t('common.error'), - description: e?.response?.data?.ErrorDescription, - status: 'error', - duration: 5000, - isClosable: true, - position: 'top-right', - }); - setSubmitting(false); - }, - }); + ); }} > @@ -139,6 +143,7 @@ const EditDefaultConfiguration = ({ modalProps, config }: Props) => { value: devType, })) ?? [] } + isCreatable isRequired /> string) => .shape({ name: Yup.string().required(t('form.required')), description: Yup.string(), - modelIds: Yup.array().of(Yup.string()).required(t('form.required')).min(1, t('form.required')), + modelIds: Yup.array().of(Yup.object()).required(t('form.required')).min(1, t('form.required')), platform: Yup.string().oneOf(['ap', 'switch']).required(t('form.required')), configuration: Yup.string() .required(t('form.required'))