aboutsummaryrefslogtreecommitdiffstats
path: root/src/components
diff options
context:
space:
mode:
authorLibravatar Muhamed <unknown>2022-11-08 07:40:02 +0530
committerLibravatar Vijay Aravamudhan <vraravam@users.noreply.github.com>2022-11-08 17:25:27 +0530
commit570d26baf9e4ad87a8c0752b5edfb5c441bf9d80 (patch)
treeee0a0e6bec7d10ec438b5269537905fee80c377b /src/components
parentrefactor: remove toggle component's duplicate (diff)
downloadferdium-app-570d26baf9e4ad87a8c0752b5edfb5c441bf9d80.tar.gz
ferdium-app-570d26baf9e4ad87a8c0752b5edfb5c441bf9d80.tar.zst
ferdium-app-570d26baf9e4ad87a8c0752b5edfb5c441bf9d80.zip
fix: slack issue caused by input TS conversion
Diffstat (limited to 'src/components')
-rw-r--r--src/components/settings/services/EditServiceForm.tsx (renamed from src/components/settings/services/EditServiceForm.js)94
-rw-r--r--src/components/ui/imageUpload/index.tsx (renamed from src/components/ui/ImageUpload.tsx)100
-rw-r--r--src/components/ui/toggle/index.tsx17
3 files changed, 109 insertions, 102 deletions
diff --git a/src/components/settings/services/EditServiceForm.js b/src/components/settings/services/EditServiceForm.tsx
index eb18b57eb..b594fcd40 100644
--- a/src/components/settings/services/EditServiceForm.js
+++ b/src/components/settings/services/EditServiceForm.tsx
@@ -1,25 +1,24 @@
1import { Component } from 'react'; 1import { Component, FormEvent, ReactElement } from 'react';
2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 2import { observer } from 'mobx-react';
4import { Link } from 'react-router-dom'; 3import { Link } from 'react-router-dom';
5import { defineMessages, injectIntl } from 'react-intl'; 4import { defineMessages, injectIntl, WrappedComponentProps } from 'react-intl';
6import normalizeUrl from 'normalize-url'; 5import normalizeUrl from 'normalize-url';
7import { mdiInformation } from '@mdi/js'; 6import { mdiInformation } from '@mdi/js';
8import Form from '../../../lib/Form'; 7import Form from '../../../lib/Form';
9import Recipe from '../../../models/Recipe';
10import Service from '../../../models/Service';
11import Tabs from '../../ui/Tabs/Tabs'; 8import Tabs from '../../ui/Tabs/Tabs';
12import TabItem from '../../ui/Tabs/TabItem'; 9import TabItem from '../../ui/Tabs/TabItem';
13import Input from '../../ui/input/index'; 10import Input from '../../ui/input/index';
14import Toggle from '../../ui/toggle'; 11import Toggle from '../../ui/toggle';
15import Slider from '../../ui/Slider'; 12import Slider from '../../ui/Slider';
16import Button from '../../ui/button'; 13import Button from '../../ui/button';
17import ImageUpload from '../../ui/ImageUpload'; 14import ImageUpload from '../../ui/imageUpload';
18import Select from '../../ui/Select'; 15import Select from '../../ui/Select';
19import { isMac } from '../../../environment'; 16import { isMac } from '../../../environment';
20import globalMessages from '../../../i18n/globalMessages'; 17import globalMessages from '../../../i18n/globalMessages';
21import Icon from '../../ui/icon'; 18import Icon from '../../ui/icon';
22import { H3 } from '../../ui/headline'; 19import { H3 } from '../../ui/headline';
20import { IRecipe } from '../../../models/Recipe';
21import Service from '../../../models/Service';
23 22
24const messages = defineMessages({ 23const messages = defineMessages({
25 saveService: { 24 saveService: {
@@ -149,36 +148,34 @@ const messages = defineMessages({
149 }, 148 },
150}); 149});
151 150
152class EditServiceForm extends Component { 151interface IProps extends WrappedComponentProps {
153 static propTypes = { 152 recipe: IRecipe;
154 recipe: PropTypes.instanceOf(Recipe).isRequired, 153 service: Service | null;
155 service(props, propName) { 154 action?: string;
156 if (props.action === 'edit' && !(props[propName] instanceof Service)) { 155 form: Form;
157 return new Error(`'${propName}'' is expected to be of type 'Service' 156 onSubmit: (...args: any[]) => void;
158 when editing a Service`); 157 onDelete: () => void;
159 } 158 openRecipeFile: (recipeFile: string) => void;
159 isSaving: boolean;
160 isDeleting: boolean;
161 isProxyFeatureEnabled: boolean;
162}
160 163
161 return null; 164interface IState {
162 }, 165 isValidatingCustomUrl: boolean;
163 action: PropTypes.string.isRequired, 166}
164 form: PropTypes.instanceOf(Form).isRequired,
165 onSubmit: PropTypes.func.isRequired,
166 onDelete: PropTypes.func.isRequired,
167 openRecipeFile: PropTypes.func.isRequired,
168 isSaving: PropTypes.bool.isRequired,
169 isDeleting: PropTypes.bool.isRequired,
170 isProxyFeatureEnabled: PropTypes.bool.isRequired,
171 };
172 167
173 static defaultProps = { 168@observer
174 service: {}, 169class EditServiceForm extends Component<IProps, IState> {
175 }; 170 constructor(props: IProps) {
171 super(props);
176 172
177 state = { 173 this.state = {
178 isValidatingCustomUrl: false, 174 isValidatingCustomUrl: false,
179 }; 175 };
176 }
180 177
181 submit(e) { 178 submit(e: FormEvent): void {
182 const { recipe } = this.props; 179 const { recipe } = this.props;
183 180
184 e.preventDefault(); 181 e.preventDefault();
@@ -189,7 +186,8 @@ class EditServiceForm extends Component {
189 186
190 const { files } = form.$('customIcon'); 187 const { files } = form.$('customIcon');
191 if (files) { 188 if (files) {
192 values.iconFile = files[0]; 189 const [iconFile] = files;
190 values.iconFile = iconFile;
193 } 191 }
194 192
195 if (recipe.validateUrl && values.customUrl) { 193 if (recipe.validateUrl && values.customUrl) {
@@ -219,20 +217,19 @@ class EditServiceForm extends Component {
219 }); 217 });
220 } 218 }
221 219
222 render() { 220 render(): ReactElement {
223 const { 221 const {
224 recipe, 222 recipe,
225 service, 223 service = {} as Service,
226 action, 224 action = '',
227 form, 225 form,
228 isSaving, 226 isSaving,
229 isDeleting, 227 isDeleting,
230 onDelete, 228 onDelete,
231 openRecipeFile, 229 openRecipeFile,
232 isProxyFeatureEnabled, 230 isProxyFeatureEnabled,
231 intl,
233 } = this.props; 232 } = this.props;
234 const { intl } = this.props;
235
236 const { isValidatingCustomUrl } = this.state; 233 const { isValidatingCustomUrl } = this.state;
237 234
238 const deleteButton = isDeleting ? ( 235 const deleteButton = isDeleting ? (
@@ -283,7 +280,8 @@ class EditServiceForm extends Component {
283 name: recipe.name, 280 name: recipe.name,
284 }) 281 })
285 : intl.formatMessage(messages.editServiceHeadline, { 282 : intl.formatMessage(messages.editServiceHeadline, {
286 name: service.name !== '' ? service.name : recipe.name, 283 name:
284 service && service.name !== '' ? service.name : recipe.name,
287 })} 285 })}
288 </span> 286 </span>
289 </div> 287 </div>
@@ -295,23 +293,29 @@ class EditServiceForm extends Component {
295 {(recipe.hasTeamId || recipe.hasCustomUrl) && ( 293 {(recipe.hasTeamId || recipe.hasCustomUrl) && (
296 <Tabs active={activeTabIndex}> 294 <Tabs active={activeTabIndex}>
297 {recipe.hasHostedOption && ( 295 {recipe.hasHostedOption && (
298 <TabItem title={recipe.name}> 296 <TabItem
297 // title={recipe.name} // TODO - [TS DEBT] property not used inside TabItem need to check it
298 >
299 {intl.formatMessage(messages.useHostedService, { 299 {intl.formatMessage(messages.useHostedService, {
300 name: recipe.name, 300 name: recipe.name,
301 })} 301 })}
302 </TabItem> 302 </TabItem>
303 )} 303 )}
304 {recipe.hasTeamId && ( 304 {recipe.hasTeamId && (
305 <TabItem title={intl.formatMessage(messages.tabHosted)}> 305 <TabItem
306 // title={intl.formatMessage(messages.tabHosted)} // TODO - [TS DEBT] property not used inside TabItem need to check it
307 >
306 <Input 308 <Input
307 field={form.$('team')} 309 {...form.$('team').bind()}
308 prefix={recipe.urlInputPrefix} 310 prefix={recipe.urlInputPrefix}
309 suffix={recipe.urlInputSuffix} 311 suffix={recipe.urlInputSuffix}
310 /> 312 />
311 </TabItem> 313 </TabItem>
312 )} 314 )}
313 {recipe.hasCustomUrl && ( 315 {recipe.hasCustomUrl && (
314 <TabItem title={intl.formatMessage(messages.tabOnPremise)}> 316 <TabItem
317 // title={intl.formatMessage(messages.tabOnPremise)} // TODO - [TS DEBT] property not used inside TabItem need to check it
318 >
315 <Input {...form.$('customUrl').bind()} /> 319 <Input {...form.$('customUrl').bind()} />
316 {form.error === 'url-validation-error' && ( 320 {form.error === 'url-validation-error' && (
317 <p className="franz-form__error"> 321 <p className="franz-form__error">
@@ -404,7 +408,7 @@ class EditServiceForm extends Component {
404 </div> 408 </div>
405 <div className="service-icon"> 409 <div className="service-icon">
406 <ImageUpload 410 <ImageUpload
407 field={form.$('customIcon')} 411 {...form.$('customIcon').bind()}
408 textDelete={intl.formatMessage(messages.iconDelete)} 412 textDelete={intl.formatMessage(messages.iconDelete)}
409 textUpload={intl.formatMessage(messages.iconUpload)} 413 textUpload={intl.formatMessage(messages.iconUpload)}
410 maxSize={2_097_152} 414 maxSize={2_097_152}
@@ -533,4 +537,4 @@ class EditServiceForm extends Component {
533 } 537 }
534} 538}
535 539
536export default injectIntl(observer(EditServiceForm)); 540export default injectIntl(EditServiceForm);
diff --git a/src/components/ui/ImageUpload.tsx b/src/components/ui/imageUpload/index.tsx
index 7732928f8..7a2ca747f 100644
--- a/src/components/ui/ImageUpload.tsx
+++ b/src/components/ui/imageUpload/index.tsx
@@ -1,15 +1,15 @@
1import { Component } from 'react'; 1import { Component, InputHTMLAttributes } from 'react';
2import { observer } from 'mobx-react'; 2import { observer } from 'mobx-react';
3import { Field } from 'mobx-react-form';
4import classnames from 'classnames'; 3import classnames from 'classnames';
5import Dropzone from 'react-dropzone'; 4import Dropzone from 'react-dropzone';
6import { mdiDelete, mdiFileImage } from '@mdi/js'; 5import { mdiDelete, mdiFileImage } from '@mdi/js';
7import prettyBytes from 'pretty-bytes'; 6import prettyBytes from 'pretty-bytes';
8import { isWindows } from '../../environment'; 7import { noop } from 'lodash';
9import Icon from './icon'; 8import { isWindows } from '../../../environment';
9import Icon from '../icon';
10import { IFormField } from '../typings/generic';
10 11
11type Props = { 12interface IProps extends InputHTMLAttributes<HTMLInputElement>, IFormField {
12 field: typeof Field;
13 className: string; 13 className: string;
14 multiple: boolean; 14 multiple: boolean;
15 textDelete: string; 15 textDelete: string;
@@ -19,39 +19,43 @@ type Props = {
19 maxSize?: number; 19 maxSize?: number;
20 maxFiles?: number; 20 maxFiles?: number;
21 messages: any; 21 messages: any;
22}; 22 set?: (value: string) => void;
23}
23 24
24// Should this file be converted into the coding style similar to './toggle/index.tsx'? 25interface IState {
25class ImageUpload extends Component<Props> { 26 path: string | null;
26 static defaultProps = { 27 errorState: boolean;
27 multiple: false, 28 errorMessage: { message: string };
28 maxSize: Number.POSITIVE_INFINITY, 29}
29 maxFiles: 0,
30 };
31 30
32 state = { 31// TODO - drag and drop image for recipe add/edit not working from 6.2.0 need to look at it
33 path: null, 32@observer
34 errorState: false, 33class ImageUpload extends Component<IProps, IState> {
35 }; 34 constructor(props: IProps) {
35 super(props);
36 36
37 errorMessage = { 37 this.state = {
38 message: '', 38 path: null,
39 }; 39 errorState: false,
40 errorMessage: {
41 message: '',
42 },
43 };
44 }
40 45
41 onDropAccepted(acceptedFiles) { 46 onDropAccepted(acceptedFiles): void {
42 const { field } = this.props; 47 const { onDrop = noop, set = noop } = this.props;
43 this.setState({ errorState: false }); 48 this.setState({ errorState: false });
44 49
45 for (const file of acceptedFiles) { 50 for (const file of acceptedFiles) {
46 const imgPath = isWindows ? file.path.replace(/\\/g, '/') : file.path; 51 const imgPath: string = isWindows
47 this.setState({ 52 ? file.path.replace(/\\/g, '/')
48 path: imgPath, 53 : file.path;
49 }); 54 this.setState({ path: imgPath });
50 55 onDrop(file);
51 this.props.field.onDrop(file);
52 } 56 }
53 57
54 field.set(''); 58 set('');
55 } 59 }
56 60
57 onDropRejected(rejectedFiles): void { 61 onDropRejected(rejectedFiles): void {
@@ -59,11 +63,11 @@ class ImageUpload extends Component<Props> {
59 for (const error of file.errors) { 63 for (const error of file.errors) {
60 if (error.code === 'file-too-large') { 64 if (error.code === 'file-too-large') {
61 this.setState({ errorState: true }); 65 this.setState({ errorState: true });
62 this.setState( 66 this.setState({
63 (this.errorMessage = { 67 errorMessage: {
64 message: this.props.textMaxFileSizeError, 68 message: this.props.textMaxFileSizeError,
65 }), 69 },
66 ); 70 });
67 } 71 }
68 } 72 }
69 } 73 }
@@ -71,14 +75,16 @@ class ImageUpload extends Component<Props> {
71 75
72 render() { 76 render() {
73 const { 77 const {
74 field,
75 className, 78 className,
76 multiple, 79 multiple = false,
77 textDelete, 80 textDelete,
78 textUpload, 81 textUpload,
79 textMaxFileSize, 82 textMaxFileSize,
80 maxSize, 83 value,
81 maxFiles, 84 maxSize = Number.POSITIVE_INFINITY,
85 maxFiles = 0,
86 label = '',
87 set = noop,
82 } = this.props; 88 } = this.props;
83 89
84 const cssClasses = classnames({ 90 const cssClasses = classnames({
@@ -94,27 +100,25 @@ class ImageUpload extends Component<Props> {
94 return ( 100 return (
95 <div className="image-upload-wrapper"> 101 <div className="image-upload-wrapper">
96 <label className="franz-form__label" htmlFor="iconUpload"> 102 <label className="franz-form__label" htmlFor="iconUpload">
97 {field.label} 103 {label}
98 </label> 104 </label>
99 <div className="image-upload"> 105 <div className="image-upload">
100 {(field.value && field.value !== 'delete') || this.state.path ? ( 106 {(value && value !== 'delete') || this.state.path ? (
101 <> 107 <>
102 <div 108 <div
103 className="image-upload__preview" 109 className="image-upload__preview"
104 style={{ 110 style={{
105 backgroundImage: `url("${this.state.path || field.value}")`, 111 backgroundImage: `url("${this.state.path || value}")`,
106 }} 112 }}
107 /> 113 />
108 <div className="image-upload__action"> 114 <div className="image-upload__action">
109 <button 115 <button
110 type="button" 116 type="button"
111 onClick={() => { 117 onClick={() => {
112 if (field.value) { 118 if (value) {
113 field.set('delete'); 119 set('delete');
114 } else { 120 } else {
115 this.setState({ 121 this.setState({ path: null });
116 path: null,
117 });
118 } 122 }
119 }} 123 }}
120 > 124 >
@@ -152,7 +156,7 @@ class ImageUpload extends Component<Props> {
152 )} 156 )}
153 {this.state.errorState && ( 157 {this.state.errorState && (
154 <span className="image-upload-wrapper__file-size-error"> 158 <span className="image-upload-wrapper__file-size-error">
155 {this.errorMessage.message} 159 {this.state.errorMessage.message}
156 </span> 160 </span>
157 )} 161 )}
158 </div> 162 </div>
@@ -160,4 +164,4 @@ class ImageUpload extends Component<Props> {
160 } 164 }
161} 165}
162 166
163export default observer(ImageUpload); 167export default ImageUpload;
diff --git a/src/components/ui/toggle/index.tsx b/src/components/ui/toggle/index.tsx
index fee8adbc7..828941886 100644
--- a/src/components/ui/toggle/index.tsx
+++ b/src/components/ui/toggle/index.tsx
@@ -1,7 +1,7 @@
1import classnames from 'classnames'; 1import classnames from 'classnames';
2import { Property } from 'csstype'; 2import { Property } from 'csstype';
3import { noop } from 'lodash'; 3import { noop } from 'lodash';
4import { Component, InputHTMLAttributes } from 'react'; 4import { Component, InputHTMLAttributes, ReactElement } from 'react';
5import withStyles, { WithStylesProps } from 'react-jss'; 5import withStyles, { WithStylesProps } from 'react-jss';
6import { Theme } from '../../../themes'; 6import { Theme } from '../../../themes';
7import Error from '../error'; 7import Error from '../error';
@@ -10,11 +10,10 @@ import { IFormField } from '../typings/generic';
10import Wrapper from '../wrapper'; 10import Wrapper from '../wrapper';
11 11
12interface IProps 12interface IProps
13 extends Omit<InputHTMLAttributes<HTMLInputElement>, 'value'>, 13 extends InputHTMLAttributes<HTMLInputElement>,
14 IFormField, 14 IFormField,
15 WithStylesProps<typeof styles> { 15 WithStylesProps<typeof styles> {
16 className?: string; 16 className?: string;
17 value: boolean | undefined; // due to type capability between InputHTMLAttributes and mobx-react-form
18} 17}
19 18
20const buttonTransition: string = 19const buttonTransition: string =
@@ -62,8 +61,8 @@ const styles = (theme: Theme) => ({
62 }, 61 },
63}); 62});
64 63
65class ToggleComponent extends Component<IProps> { 64class Toggle extends Component<IProps> {
66 render() { 65 render(): ReactElement {
67 const { 66 const {
68 classes, 67 classes,
69 className, 68 className,
@@ -71,7 +70,7 @@ class ToggleComponent extends Component<IProps> {
71 name = '', 70 name = '',
72 label = '', 71 label = '',
73 error = '', 72 error = '',
74 value = false, 73 checked = false,
75 showLabel = true, 74 showLabel = true,
76 disabled = false, 75 disabled = false,
77 onChange = noop, 76 onChange = noop,
@@ -94,14 +93,14 @@ class ToggleComponent extends Component<IProps> {
94 <div 93 <div
95 className={classnames({ 94 className={classnames({
96 [`${classes.button}`]: true, 95 [`${classes.button}`]: true,
97 [`${classes.buttonActive}`]: value, 96 [`${classes.buttonActive}`]: checked,
98 })} 97 })}
99 /> 98 />
100 <input 99 <input
101 type="checkbox" 100 type="checkbox"
102 id={id} 101 id={id}
103 name={name} 102 name={name}
104 checked={value as boolean | undefined} 103 checked={checked}
105 className={classes.input} 104 className={classes.input}
106 onChange={onChange} 105 onChange={onChange}
107 disabled={disabled} 106 disabled={disabled}
@@ -114,4 +113,4 @@ class ToggleComponent extends Component<IProps> {
114 } 113 }
115} 114}
116 115
117export default withStyles(styles, { injectTheme: true })(ToggleComponent); 116export default withStyles(styles, { injectTheme: true })(Toggle);