Skip to content

Commit

Permalink
refactoring to func components
Browse files Browse the repository at this point in the history
  • Loading branch information
strzinek authored and jelly committed Aug 19, 2022
1 parent 2b7d5db commit fc93a54
Show file tree
Hide file tree
Showing 8 changed files with 349 additions and 608 deletions.
3 changes: 2 additions & 1 deletion src/Containers.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,8 @@ class Containers extends React.Component {
};

const createPod = () => {
Dialogs.show(<PodCreateModal user={this.props.user}
Dialogs.show(<PodCreateModal props={this.props}
user={this.props.user}
selinuxAvailable={this.props.selinuxAvailable}
podmanRestartAvailable={this.props.podmanRestartAvailable}
systemServiceAvailable={this.props.systemServiceAvailable}
Expand Down
89 changes: 89 additions & 0 deletions src/DynamicListForm.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
Button,
EmptyState, EmptyStateBody,
FormFieldGroup, FormFieldGroupHeader,
HelperText, HelperTextItem,
} from '@patternfly/react-core';

export class DynamicListForm extends React.Component {
constructor(props) {
super(props);
this.state = {
list: [],
};
this.keyCounter = 0;
this.removeItem = this.removeItem.bind(this);
this.addItem = this.addItem.bind(this);
this.onItemChange = this.onItemChange.bind(this);
}

removeItem(idx, field, value) {
this.setState(state => {
const items = state.list.concat();
items.splice(idx, 1);
return { list: items };
}, () => this.props.onChange(this.state.list.concat()));
}

addItem() {
this.setState(state => {
return { list: [...state.list, Object.assign({ key: this.keyCounter++ }, this.props.default)] };
}, () => this.props.onChange(this.state.list.concat()));
}

onItemChange(idx, field, value) {
this.setState(state => {
const items = state.list.concat();
items[idx][field] = value || null;
return { list: items };
}, () => this.props.onChange(this.state.list.concat()));
}

render () {
const { id, label, actionLabel, formclass, emptyStateString, helperText } = this.props;
const dialogValues = this.state;
return (
<FormFieldGroup header={
<FormFieldGroupHeader
titleText={{ text: label }}
actions={<Button variant="secondary" className="btn-add" onClick={this.addItem}>{actionLabel}</Button>}
/>
} className={"dynamic-form-group " + formclass}>
{
dialogValues.list.length
? <>
{dialogValues.list.map((item, idx) => {
return React.cloneElement(this.props.itemcomponent, {
idx: idx, item: item, id: id + "-" + idx,
key: idx,
onChange: this.onItemChange, removeitem: this.removeItem, additem: this.addItem, options: this.props.options,
itemCount: Object.keys(dialogValues.list).length,
});
})
}
{helperText &&
<HelperText>
<HelperTextItem>{helperText}</HelperTextItem>
</HelperText>
}
</>
: <EmptyState>
<EmptyStateBody>
{emptyStateString}
</EmptyStateBody>
</EmptyState>
}
</FormFieldGroup>
);
}
}
DynamicListForm.propTypes = {
emptyStateString: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
id: PropTypes.string.isRequired,
itemcomponent: PropTypes.object.isRequired,
formclass: PropTypes.string,
options: PropTypes.object,
};
209 changes: 7 additions & 202 deletions src/ImageRunModal.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
Button, Checkbox,
EmptyState, EmptyStateBody,
Form, FormGroup, FormFieldGroup, FormFieldGroupHeader,
Form, FormGroup,
FormSelect, FormSelectOption,
Grid, GridItem,
HelperText, HelperTextItem,
InputGroup, Radio, InputGroupText, InputGroupTextVariant,
Modal, NumberInput, Select, SelectVariant,
Modal, Radio, Select, SelectVariant,
NumberInput, InputGroupTextVariant,
InputGroup, InputGroupText,
SelectOption, SelectGroup,
TextInput, Tabs, Tab, TabTitleText,
ToggleGroup, ToggleGroupItem,
Expand All @@ -19,13 +17,15 @@ import { MinusIcon, OutlinedQuestionCircleIcon } from '@patternfly/react-icons';
import * as dockerNames from 'docker-names';

import { ErrorNotification } from './Notification.jsx';
import { FileAutoComplete } from 'cockpit-components-file-autocomplete.jsx';
import * as utils from './util.js';
import * as client from './client.js';
import rest from './rest.js';
import cockpit from 'cockpit';
import { onDownloadContainer, onDownloadContainerFinished } from './Containers.jsx';
import { DialogsContext } from "dialogs.jsx";
import { PublishPort } from './PublishPort.jsx';
import { DynamicListForm } from './DynamicListForm.jsx';
import { Volume } from './Volume.jsx';

import { debounce } from 'throttle-debounce';

Expand All @@ -50,79 +50,6 @@ const units = {
},
};

const PublishPort = ({ id, item, onChange, idx, removeitem, itemCount }) =>
(
<Grid hasGutter id={id}>
<FormGroup className="pf-m-6-col-on-md"
label={_("IP address")}
fieldId={id + "-ip-address"}
labelIcon={
<Popover aria-label={_("IP address help")}
enableFlip
bodyContent={_("If host IP is set to 0.0.0.0 or not set at all, the port will be bound on all IPs on the host.")}>
<button onClick={e => e.preventDefault()} className="pf-c-form__group-label-help">
<OutlinedQuestionCircleIcon />
</button>
</Popover>
}>
<TextInput id={id + "-ip-address"}
value={item.IP || ''}
onChange={value => onChange(idx, 'IP', value)} />
</FormGroup>
<FormGroup className="pf-m-2-col-on-md"
label={_("Host port")}
fieldId={id + "-host-port"}
labelIcon={
<Popover aria-label={_("Host port help")}
enableFlip
bodyContent={_("If the host port is not set the container port will be randomly assigned a port on the host.")}>
<button onClick={e => e.preventDefault()} className="pf-c-form__group-label-help">
<OutlinedQuestionCircleIcon />
</button>
</Popover>
}>
<TextInput id={id + "-host-port"}
type='number'
step={1}
min={1}
max={65535}
value={item.hostPort || ''}
onChange={value => onChange(idx, 'hostPort', value)} />
</FormGroup>
<FormGroup className="pf-m-2-col-on-md"
label={_("Container port")}
fieldId={id + "-container-port"} isRequired>
<TextInput id={id + "-container-port"}
type='number'
step={1}
min={1}
max={65535}
value={item.containerPort || ''}
onChange={value => onChange(idx, 'containerPort', value)} />
</FormGroup>
<FormGroup className="pf-m-2-col-on-md"
label={_("Protocol")}
fieldId={id + "-protocol"}>
<FormSelect className='pf-c-form-control container-port-protocol'
id={id + "-protocol"}
value={item.protocol}
onChange={value => onChange(idx, 'protocol', value)}>
<FormSelectOption value='tcp' key='tcp' label={_("TCP")} />
<FormSelectOption value='udp' key='udp' label={_("UDP")} />
</FormSelect>
</FormGroup>
<FormGroup className="pf-m-1-col-on-md remove-button-group">
<Button variant='secondary'
className="btn-close"
id={id + "-btn-close"}
isSmall
aria-label={_("Remove item")}
icon={<MinusIcon />}
onClick={() => removeitem(idx)} />
</FormGroup>
</Grid>
);

const handleEnvValue = (key, value, idx, onChange, additem, itemCount) => {
// Allow the input of KEY=VALUE separated value pairs for bulk import
if (value.includes('=')) {
Expand Down Expand Up @@ -171,128 +98,6 @@ const EnvVar = ({ id, item, onChange, idx, removeitem, additem, itemCount }) =>
</Grid>
);

const Volume = ({ id, item, onChange, idx, removeitem, additem, options, itemCount }) =>
(
<Grid hasGutter id={id}>
<FormGroup className="pf-m-4-col-on-md" label={_("Host path")} fieldId={id + "-host-path"}>
<FileAutoComplete id={id + "-host-path"}
value={item.hostPath || ''}
onChange={ value => onChange(idx, 'hostPath', value) } />
</FormGroup>
<FormGroup className="pf-m-3-col-on-md" label={_("Container path")} fieldId={id + "-container-path"}>
<TextInput id={id + "-container-path"}
value={item.containerPath || ''}
onChange={value => onChange(idx, 'containerPath', value)} />
</FormGroup>
<FormGroup className="pf-m-2-col-on-md" label={_("Mode")} fieldId={id + "-mode"}>
<Checkbox id={id + "-mode"}
label={_("Writable")}
isChecked={item.mode == "rw"}
onChange={value => onChange(idx, 'mode', value ? "rw" : "ro")} />
</FormGroup>
{ options && options.selinuxAvailable &&
<FormGroup className="pf-m-3-col-on-md" label={_("SELinux")} fieldId={id + "-selinux"}>
<FormSelect id={id + "-selinux"} className='pf-c-form-control'
value={item.selinux}
onChange={value => onChange(idx, 'selinux', value)}>
<FormSelectOption value='' key='' label={_("No label")} />
<FormSelectOption value='z' key='z' label={_("Shared")} />
<FormSelectOption value='Z' key='Z' label={_("Private")} />
</FormSelect>
</FormGroup> }
<FormGroup className="pf-m-1-col-on-md remove-button-group">
<Button variant='secondary'
className="btn-close"
id={id + "-btn-close"}
aria-label={_("Remove item")}
isSmall
icon={<MinusIcon />}
onClick={() => removeitem(idx)} />
</FormGroup>
</Grid>
);

class DynamicListForm extends React.Component {
constructor(props) {
super(props);
this.state = {
list: [],
};
this.keyCounter = 0;
this.removeItem = this.removeItem.bind(this);
this.addItem = this.addItem.bind(this);
this.onItemChange = this.onItemChange.bind(this);
}

removeItem(idx, field, value) {
this.setState(state => {
const items = state.list.concat();
items.splice(idx, 1);
return { list: items };
}, () => this.props.onChange(this.state.list.concat()));
}

addItem() {
this.setState(state => {
return { list: [...state.list, Object.assign({ key: this.keyCounter++ }, this.props.default)] };
}, () => this.props.onChange(this.state.list.concat()));
}

onItemChange(idx, field, value) {
this.setState(state => {
const items = state.list.concat();
items[idx][field] = value || null;
return { list: items };
}, () => this.props.onChange(this.state.list.concat()));
}

render () {
const { id, label, actionLabel, formclass, emptyStateString, helperText } = this.props;
const dialogValues = this.state;
return (
<FormFieldGroup header={
<FormFieldGroupHeader
titleText={{ text: label }}
actions={<Button variant="secondary" className="btn-add" onClick={this.addItem}>{actionLabel}</Button>}
/>
} className={"dynamic-form-group " + formclass}>
{
dialogValues.list.length
? <>
{dialogValues.list.map((item, idx) => {
return React.cloneElement(this.props.itemcomponent, {
idx: idx, item: item, id: id + "-" + idx,
key: idx,
onChange: this.onItemChange, removeitem: this.removeItem, additem: this.addItem, options: this.props.options,
itemCount: Object.keys(dialogValues.list).length,
});
})
}
{helperText &&
<HelperText>
<HelperTextItem>{helperText}</HelperTextItem>
</HelperText>
}
</>
: <EmptyState>
<EmptyStateBody>
{emptyStateString}
</EmptyStateBody>
</EmptyState>
}
</FormFieldGroup>
);
}
}
DynamicListForm.propTypes = {
emptyStateString: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
id: PropTypes.string.isRequired,
itemcomponent: PropTypes.object.isRequired,
formclass: PropTypes.string,
options: PropTypes.object,
};

export class ImageRunModal extends React.Component {
static contextType = DialogsContext;

Expand Down
Loading

0 comments on commit fc93a54

Please sign in to comment.