Skip to content

Commit e4a3c33

Browse files
committed
Convert EditWidgetModal
1 parent acbc040 commit e4a3c33

File tree

3 files changed

+141
-145
lines changed

3 files changed

+141
-145
lines changed
Lines changed: 139 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react';
1+
import React, { useEffect, useState } from 'react';
22
import PropTypes from 'prop-types';
33

44
import {
@@ -20,168 +20,164 @@ import { Settings } from '../settings';
2020
import { linkifyDecorator } from './decorators';
2121

2222

23+
const EditWidgetModal = (props) => {
24+
const {
25+
onSave,
26+
onClose,
27+
isOpen,
28+
data,
29+
} = props;
2330

24-
export class EditWidgetModal extends React.Component {
25-
static propTypes = {
26-
onSave: PropTypes.func,
27-
onClose: PropTypes.func,
28-
isOpen: PropTypes.bool,
29-
data: PropTypes.object,
30-
};
31-
32-
constructor(props) {
33-
super(props);
34-
this.state = {
35-
widgetType: null,
36-
title: props.data.title,
37-
params: props.data.params,
38-
weight: props.data.weight,
39-
isTitleValid: true,
40-
areParamsFilled: true,
41-
componentLoaded: false,
42-
};
43-
}
44-
31+
const [widgetType, setWidgetType] = useState({});
32+
const [title, setTitle] = useState();
33+
const [weight, setWeight] = useState();
4534

46-
onNameChange = (name) => {
47-
this.setState({name});
48-
}
35+
// TODO: move the widget params to their own component to better handle validation?
36+
const [componentLoaded, setComponentLoaded] = useState(false);
37+
const [params, setParams] = useState();
4938

50-
onExpiryDateChange = (expiryStr) => {
51-
this.setState({expiryDate: expiryStr});
52-
}
39+
const [isTitleValid, setIsTitleValid] = useState(title !== '');
40+
const [saveButtonDisabled, setSaveButtonDisabled] = useState(false);
5341

54-
onSave = () => {
42+
const onSaveModal = () => {
5543
const updatedWidget = {
56-
title: this.state.title,
57-
params: this.state.params,
58-
weight: parseInt(this.state.weight),
44+
title: title,
45+
params: params,
46+
weight: parseInt(weight) || 0, // 400 if this is null
5947
type: 'widget',
60-
widget: this.props.data.widget
48+
widget: data.widget
6149
}
62-
this.props.onSave(updatedWidget);
63-
this.setState({
64-
widgetType: null,
65-
title: '',
66-
params: {},
67-
weight: 0,
68-
isTitleValid: false,
69-
areParamsFilled: false
70-
});
71-
}
50+
onSave(updatedWidget);
7251

73-
onClose = () => {
74-
this.setState({
75-
title: '',
76-
params: {},
77-
weight: 0,
78-
isTitleValid: false,
79-
areParamsFilled: false,
80-
});
81-
this.props.onClose();
52+
setTitle('');
53+
setParams({});
54+
setWeight(0);
55+
setIsTitleValid(false);
56+
setWidgetType({});
8257
}
8358

84-
onTitleChange = (value) => {
85-
this.setState({title: value, isTitleValid: (value !== '')});
59+
const onCloseModal = () => {
60+
setTitle('');
61+
setParams({});
62+
setWeight(0);
63+
setIsTitleValid(false);
64+
setWidgetType({});
65+
onClose();
8666
}
8767

88-
onWeightChange = (value) => {
89-
this.setState({weight: value});
90-
}
91-
92-
onParamChange = (value, event) => {
93-
const params = this.state.params;
94-
let areParamsFilled = true;
95-
if (event) {
96-
params[event.target.name] = value;
97-
}
98-
this.setState({params: params});
99-
this.state.widgetType.params.forEach(widgetParam => {
100-
if ((widgetParam.required) && (!params[widgetParam.name])) {
101-
areParamsFilled = false;
102-
}
68+
useEffect(() => {
69+
setTitle(data.title);
70+
setWeight(data ? data.weight : 0);
71+
setParams(data.params || {});
72+
}, [data])
73+
74+
useEffect(() => {
75+
let validCheck = (title !== '')
76+
setIsTitleValid(validCheck);
77+
if (validCheck) {setSaveButtonDisabled(false)}
78+
else {setSaveButtonDisabled(true)}
79+
}, [title])
80+
81+
const onParamChange = (value, event) => {
82+
setParams({
83+
...params,
84+
[event.target.name]: value
10385
});
104-
this.setState({areParamsFilled: areParamsFilled});
10586
}
10687

107-
componentDidMount() {
88+
useEffect(() =>{
10889
HttpClient.get([Settings.serverUrl, 'widget', 'types'], {'type': 'widget'})
109-
.then(response => HttpClient.handleResponse(response))
110-
.then(data => {
111-
data.types.forEach(type => {
112-
if (type.id == this.props.data.widget) {
113-
this.setState({widgetType: type});
114-
this.setState({componentLoaded: true});
115-
}
116-
});
90+
.then(response => HttpClient.handleResponse(response))
91+
.then(typesData => {
92+
typesData.types.forEach(type => {
93+
if (type.id == data.widget) {
94+
setWidgetType(type);
95+
setComponentLoaded(true);
96+
}
11797
});
118-
}
119-
120-
render () {
121-
const { widgetType, componentLoaded } = this.state;
122-
return (
123-
<Modal
124-
variant={ModalVariant.small}
125-
title="Edit widget"
126-
isOpen={this.props.isOpen}
127-
onClose={this.onClose}
128-
actions={[
129-
<Button key="save" variant="primary" onClick={this.onSave}>Save</Button>,
130-
<Button key="cancel" variant="link" onClick={this.onClose}>Cancel</Button>
131-
]}
132-
>
133-
<Form>
134-
<FormGroup label="Title" fieldId="widget-title" validated={this.isTitleValid} isRequired>
135-
<TextInput type="text" id="widget-title" name="widget-title" value={this.state.title} onChange={(_event, value) => this.onTitleChange(value)} validated={this.state.isTitleValid} isRequired />
136-
{this.state.isTitleValid !== true && (
137-
<FormHelperText>
138-
<HelperText>
139-
<HelperTextItem icon={<ExclamationCircleIcon />} variant="error">
140-
Please enter a title for this widget
141-
</HelperTextItem>
142-
</HelperText>
143-
</FormHelperText>
144-
)}
145-
</FormGroup>
146-
<FormGroup label="Weight" fieldId="widget-weight">
147-
<TextInput type="number" id="widget-weight" name="widget-weight" value={this.state.weight} onChange={(_event, value) => this.onWeightChange(value)} />
98+
});
99+
}, [data?.widget])
100+
101+
102+
return (
103+
<Modal
104+
variant={ModalVariant.small}
105+
title="Edit widget"
106+
isOpen={isOpen}
107+
onClose={onCloseModal}
108+
actions={[
109+
<Button key="save" variant="primary" onClick={onSaveModal} isDisabled={saveButtonDisabled}>Save</Button>,
110+
<Button key="cancel" variant="link" onClick={onCloseModal}>Cancel</Button>
111+
]}
112+
>
113+
<Form>
114+
<FormGroup label="Title" fieldId="widget-title" validated={isTitleValid.toString()} isRequired>
115+
<TextInput type="text" id="widget-title" name="widget-title" value={title} onChange={(_event, value) => setTitle(value)} validated={isTitleValid.toString()} isRequired />
116+
{isTitleValid !== true && (
148117
<FormHelperText>
149118
<HelperText>
150-
<HelperTextItem variant="default">
151-
How widgets are ordered on the dashboard
119+
<HelperTextItem icon={<ExclamationCircleIcon />} variant="error">
120+
Please enter a title for this widget
152121
</HelperTextItem>
153122
</HelperText>
154123
</FormHelperText>
155-
</FormGroup>
156-
{componentLoaded ? widgetType.params.map(param => (
157-
<React.Fragment key={param.name}>
158-
<FormGroup
159-
label={param.name}
160-
fieldId={param.name}
161-
isRequired={param.required}>
162-
<TextInput
163-
value={this.state.params[param.name]}
164-
type={(param.type === 'integer' || param.type === 'float') ? 'number' : 'text'}
165-
id={param.name}
166-
aria-describedby={`${param.name}-helper`}
167-
name={param.name}
168-
onChange={(event, value) => this.onParamChange(value, event)}
169-
isRequired={param.required}
170-
/>
171-
<FormHelperText>
172-
<HelperText>
173-
<HelperTextItem variant="default">
174-
<Linkify componentDecorator={linkifyDecorator}>
175-
{param.description}
176-
</Linkify>
177-
</HelperTextItem>
178-
</HelperText>
179-
</FormHelperText>
180-
</FormGroup>
181-
</React.Fragment>
182-
)): ''}
183-
</Form>
184-
</Modal>
185-
);
186-
}
124+
)}
125+
</FormGroup>
126+
<FormGroup label="Weight" fieldId="widget-weight">
127+
<TextInput type="number" id="widget-weight" name="widget-weight" value={weight} onChange={(_event, value) => setWeight(value)} />
128+
<FormHelperText>
129+
<HelperText>
130+
<HelperTextItem variant="default">
131+
How widgets are ordered on the dashboard
132+
</HelperTextItem>
133+
</HelperText>
134+
</FormHelperText>
135+
</FormGroup>
136+
{componentLoaded ? widgetType?.params.map(param => (
137+
<React.Fragment key={param.name}>
138+
<FormGroup
139+
label={param.name}
140+
fieldId={param.name}
141+
isRequired={param.required}
142+
// TODO this validation hook isn't working in main branch right now
143+
// TODO some cool things we could do here,
144+
// applying the param default if the user empties a required field
145+
// validated={
146+
// (param.required && (params[param.name] !== '')).toString()
147+
// }
148+
>
149+
<TextInput
150+
value={params[param.name]}
151+
type={(param.type === 'integer' || param.type === 'float') ? 'number' : 'text'}
152+
id={param.name}
153+
aria-describedby={`${param.name}-helper`}
154+
name={param.name}
155+
onChange={(event, value) => onParamChange(value, event)}
156+
isRequired={param.required}
157+
/>
158+
<FormHelperText>
159+
<HelperText>
160+
<HelperTextItem variant="default">
161+
<Linkify componentDecorator={linkifyDecorator}>
162+
{param.description}
163+
</Linkify>
164+
</HelperTextItem>
165+
</HelperText>
166+
</FormHelperText>
167+
</FormGroup>
168+
</React.Fragment>
169+
)): ''}
170+
</Form>
171+
</Modal>
172+
);
173+
187174
}
175+
176+
EditWidgetModal.propTypes = {
177+
onSave: PropTypes.func,
178+
onClose: PropTypes.func,
179+
isOpen: PropTypes.bool,
180+
data: PropTypes.object,
181+
}
182+
183+
export default EditWidgetModal;

frontend/src/components/index.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,3 @@ export { TabTitle } from './tabs';
1414
export { TableEmptyState, TableErrorState } from './tablestates';
1515
export { UserDropdown } from './user-dropdown';
1616
export { View } from './view';
17-
export { EditWidgetModal } from './edit-widget-modal';

frontend/src/dashboard.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ import TimesCircleIcon from '@patternfly/react-icons/dist/esm/icons/times-circle
3232
import { HttpClient } from './services/http';
3333
import { KNOWN_WIDGETS } from './constants';
3434
import { Settings } from './settings';
35-
import { NewDashboardModal, NewWidgetWizard, EditWidgetModal } from './components';
35+
import { NewDashboardModal, NewWidgetWizard } from './components';
36+
import EditWidgetModal from './components/edit-widget-modal.js'
3637
import DeleteModal from './components/delete-modal.js';
3738
import {
3839
GenericAreaWidget,

0 commit comments

Comments
 (0)