Skip to content

Commit

Permalink
Finalizing pipeline submission (making global adjustments to submit b…
Browse files Browse the repository at this point in the history
…utton and submit error reporting).
  • Loading branch information
krulis-martin committed Dec 29, 2021
1 parent 4bf684b commit 23bd230
Show file tree
Hide file tree
Showing 14 changed files with 367 additions and 131 deletions.
11 changes: 10 additions & 1 deletion src/components/Pipelines/BoxesTable/BoxesTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import { injectIntl, FormattedMessage } from 'react-intl';
import { Table } from 'react-bootstrap';
import { defaultMemoize } from 'reselect';
import classnames from 'classnames';

import BoxesTableRow from './BoxesTableRow';
import { arrayToObject } from '../../../helpers/common';
Expand All @@ -23,13 +24,19 @@ const BoxesTable = ({
secondarySelections = null,
selectedVariable = null,
removeBox = null,
pending = false,
intl: { locale },
...rowProps
}) => {
const selectionIndex = secondarySelections && prepareSelectionIndex(secondarySelections);
const variable = selectedVariable && variables && variables.find(v => v.name === selectedVariable);
return (
<Table className={boxes.length > 0 ? 'tbody-hover' : ''} size="sm">
<Table
className={classnames({
'half-opaque': pending,
'tbody-hover': boxes.length > 0 && !pending,
})}
size="sm">
<thead>
<tr>
<th>
Expand Down Expand Up @@ -62,6 +69,7 @@ const BoxesTable = ({
selectedVariable={variable}
secondarySelections={selectionIndex}
removeBox={removeBox}
pending={pending}
{...rowProps}
/>
))}
Expand Down Expand Up @@ -90,6 +98,7 @@ BoxesTable.propTypes = {
removeBox: PropTypes.func,
secondarySelections: PropTypes.array,
selectedVariable: PropTypes.string,
pending: PropTypes.bool,
intl: PropTypes.shape({ locale: PropTypes.string.isRequired }).isRequired,
};

Expand Down
12 changes: 8 additions & 4 deletions src/components/Pipelines/BoxesTable/BoxesTableRow.js
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ const BoxesTableRow = ({
editBox = null,
removeBox = null,
assignVariable = null,
pending = false,
}) => {
const [firstPort, ...ports] = [
...transformPorts(box, 'portsIn', boxTypes),
Expand All @@ -229,10 +230,10 @@ const BoxesTableRow = ({

return (
<tbody
onClick={selectBox ? () => selectBox(box.name) : null}
onDoubleClick={editBox ? () => editBox(box.name) : null}
onClick={selectBox && !pending ? () => selectBox(box.name) : null}
onDoubleClick={editBox && !pending ? () => editBox(box.name) : null}
className={classnames({
clickable: editBox || selectBox,
clickable: (editBox || selectBox) && !pending,
[styles.primarySelection]: primarySelection === box.name,
[styles.secondarySelection]: secondarySelections && secondarySelections[box.name],
})}>
Expand Down Expand Up @@ -282,7 +283,9 @@ const BoxesTableRow = ({
timid
onClick={ev => {
ev.stopPropagation();
removeBox(box.name);
if (!pending) {
removeBox(box.name);
}
}}
/>
</td>
Expand Down Expand Up @@ -314,6 +317,7 @@ BoxesTableRow.propTypes = {
editBox: PropTypes.func,
removeBox: PropTypes.func,
assignVariable: PropTypes.func,
pending: PropTypes.bool,
};

export default BoxesTableRow;
20 changes: 13 additions & 7 deletions src/components/Pipelines/PipelineGraph/PipelineGraph.js
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ const PipelineGraph = ({
editBox = null,
selectVariable = null,
editVariable = null,
pending = false,
}) => {
if (canUseDOM) {
const [svg, setSvg] = useState(null);
Expand All @@ -271,7 +272,7 @@ const PipelineGraph = ({
}, [boxes, variables, utilization, selectedBox, selectedVariable]);

return (
<InsetPanel className="m-0 p-0">
<InsetPanel className={`m-0 p-0 ${pending ? 'half-opaque' : ''}`}>
{canUseDOM && svg ? (
<div
className={styles.pipelineGraph}
Expand All @@ -280,14 +281,18 @@ const PipelineGraph = ({
}}
onContextMenu={ev => {
ev.preventDefault();
const { box, variable } = preprocessClickEvent(ev, boxIds, variableIds);
box && selectBox && selectBox(box);
variable && selectVariable && selectVariable(variable);
if (!pending) {
const { box, variable } = preprocessClickEvent(ev, boxIds, variableIds);
box && selectBox && selectBox(box);
variable && selectVariable && selectVariable(variable);
}
}}
onClick={ev => {
const { box, variable } = preprocessClickEvent(ev, boxIds, variableIds);
box && editBox && editBox(box);
variable && editVariable && editVariable(variable);
if (!pending) {
const { box, variable } = preprocessClickEvent(ev, boxIds, variableIds);
box && editBox && editBox(box);
variable && editVariable && editVariable(variable);
}
}}
/>
) : (
Expand All @@ -312,6 +317,7 @@ PipelineGraph.propTypes = {
editBox: PropTypes.func,
selectVariable: PropTypes.func,
editVariable: PropTypes.func,
pending: PropTypes.bool,
};

export default PipelineGraph;
14 changes: 9 additions & 5 deletions src/components/Pipelines/VariablesTable/VariablesTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,13 @@ const VariablesTable = ({
selectVariable = null,
editVariable = null,
removeVariable = null,
pending = false,
intl: { locale },
}) => {
const secondarySelectionsIndexed = secondarySelections && prepareSelectionIndex(secondarySelections);

return (
<Table hover={variables.length > 0} size="sm">
<Table hover={variables.length > 0 && !pending} className={pending ? 'half-opaque' : ''} size="sm">
<thead>
<tr>
{utilization && <th />}
Expand All @@ -58,10 +59,10 @@ const VariablesTable = ({
return (
<tr
key={`${variable.name}-${portsIn}-${portsOut}`}
onClick={selectVariable ? () => selectVariable(variable.name) : null}
onDoubleClick={editVariable ? () => editVariable(variable.name) : null}
onClick={selectVariable && !pending ? () => selectVariable(variable.name) : null}
onDoubleClick={editVariable && !pending ? () => editVariable(variable.name) : null}
className={classnames({
clickable: selectVariable || editVariable,
clickable: (selectVariable || editVariable) && !pending,
[styles.primarySelection]: primarySelection === variable.name,
[styles.secondarySelection]: secondarySelectionsIndexed && secondarySelectionsIndexed[variable.name],
})}>
Expand Down Expand Up @@ -158,7 +159,9 @@ const VariablesTable = ({
timid
onClick={ev => {
ev.stopPropagation();
removeVariable(variable.name);
if (!pending) {
removeVariable(variable.name);
}
}}
/>
</td>
Expand Down Expand Up @@ -192,6 +195,7 @@ VariablesTable.propTypes = {
selectVariable: PropTypes.func,
editVariable: PropTypes.func,
removeVariable: PropTypes.func,
pending: PropTypes.bool,
intl: PropTypes.shape({ locale: PropTypes.string.isRequired }).isRequired,
};

Expand Down
7 changes: 0 additions & 7 deletions src/components/forms/EditPipelineForm/EditPipelineForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { Container, Row, Col } from 'react-bootstrap';

import { TextField, MarkdownTextAreaField, CheckboxField } from '../Fields';
import { SaveIcon } from '../../icons';
import Callout from '../../widgets/Callout';
import FormBox from '../../widgets/FormBox';
import SubmitButton from '../SubmitButton';

Expand Down Expand Up @@ -45,12 +44,6 @@ class EditPipelineForm extends Component {
/>
</div>
}>
{submitFailed && (
<Callout variant="danger">
<FormattedMessage id="generic.savingFailed" defaultMessage="Saving failed. Please try again later." />
</Callout>
)}

<Container fluid>
<Row>
<Col lg={12}>
Expand Down
98 changes: 73 additions & 25 deletions src/components/forms/SubmitButton/SubmitButton.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { FormattedMessage, injectIntl } from 'react-intl';
import { Popover, OverlayTrigger } from 'react-bootstrap';
import { defaultMemoize } from 'reselect';

import Button from '../../widgets/TheButton';
import { SendIcon, LoadingIcon, SuccessIcon, WarningIcon } from '../../icons';
import Confirm from '../Confirm';
import { getErrorMessage } from '../../../locales/apiErrorMessages';

const getIcons = defaultMemoize(defaultIcon => ({
submit: defaultIcon || <SendIcon gapRight />,
Expand Down Expand Up @@ -33,7 +35,7 @@ const getMessages = defaultMemoize(messages => {
});

class SubmitButton extends Component {
state = { saved: false };
state = { saved: false, lastError: null };

componentWillUnmount() {
this.unmounted = true;
Expand All @@ -46,22 +48,32 @@ class SubmitButton extends Component {

submit = () => {
const { handleSubmit, onSubmit = null } = this.props;

// reset button internal state
this.setState({ saved: false, lastError: null });

onSubmit && onSubmit();
return handleSubmit().then(res => {
if (!this.unmounted) {
this.setState({ saved: true });
this.resetAfterSomeTime = setTimeout(this.reset, 2000);
} else {
const { reset } = this.props;
reset && reset(); // the redux form must be still reset

return handleSubmit().then(
res => {
if (!this.unmounted) {
this.setState({ saved: true });
this.resetAfterSomeTime = setTimeout(this.reset, 2000);
} else {
const { reset } = this.props;
reset && reset(); // the redux form must be still reset
}
return res;
},
lastError => {
this.setState({ lastError });
}
return res;
});
);
};

reset = () => {
const { reset } = this.props;
this.setState({ saved: false });
this.setState({ saved: false, lastError: null });
reset && reset();
};

Expand All @@ -74,32 +86,68 @@ class SubmitButton extends Component {
return 'submit';
};

getButtonVariant() {
const { submitting, hasFailed, invalid } = this.props;
return hasFailed && !submitting
? 'danger'
: this.state.saved || submitting
? 'success'
: invalid
? 'warning'
: 'success';
}

isButtonDisabled() {
const { submitting, invalid, asyncValidating = false, disabled = false } = this.props;
return invalid || asyncValidating !== false || submitting || disabled;
}

render() {
const {
submitting,
id,
hasFailed,
invalid,
asyncValidating = false,
confirmQuestion = '',
noIcons = false,
defaultIcon = null,
disabled = false,
confirmQuestion = '',
noShadow = false,
messages = {},
intl: { formatMessage },
} = this.props;
const { saved: hasSucceeded } = this.state;

const buttonState = this.getButtonState();
const icons = getIcons(defaultIcon);
const formattedMessages = getMessages(messages);

return (
<Confirm id="confirm-submit" onConfirmed={this.submit} question={confirmQuestion} disabled={!confirmQuestion}>
return hasFailed && this.state.lastError ? (
<OverlayTrigger
placement="top"
overlay={
<Popover id={`error-popover-${id}`}>
<Popover.Title className="bg-danger">
<FormattedMessage id="app.submitButton.lastError.title" defaultMessage="An error occured" />
</Popover.Title>
<Popover.Content className="text-center">
{getErrorMessage(formatMessage)(this.state.lastError)}
</Popover.Content>
</Popover>
}>
<Button
type="submit"
variant={hasSucceeded ? 'success' : hasFailed ? 'danger' : invalid ? 'warning' : 'success'}
disabled={invalid || asyncValidating !== false || submitting || disabled}
noShadow={noShadow}>
variant={this.getButtonVariant()}
disabled={this.isButtonDisabled()}
noShadow={noShadow}
onClick={this.submit}>
{!noIcons && icons[buttonState]}
{formattedMessages[buttonState]}
</Button>
</OverlayTrigger>
) : (
<Confirm
id={`confirm-submit-${id}`}
onConfirmed={this.submit}
question={confirmQuestion}
disabled={!confirmQuestion}>
<Button type="submit" variant={this.getButtonVariant()} disabled={this.isButtonDisabled()} noShadow={noShadow}>
{!noIcons && icons[buttonState]}
{formattedMessages[buttonState]}
</Button>
Expand All @@ -112,7 +160,6 @@ SubmitButton.propTypes = {
id: PropTypes.string.isRequired,
handleSubmit: PropTypes.func.isRequired,
submitting: PropTypes.bool,
hasSucceeded: PropTypes.bool,
hasFailed: PropTypes.bool,
asyncValidating: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
noIcons: PropTypes.bool,
Expand All @@ -129,6 +176,7 @@ SubmitButton.propTypes = {
}),
confirmQuestion: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
noShadow: PropTypes.bool,
intl: PropTypes.object,
};

export default SubmitButton;
export default injectIntl(SubmitButton);
Loading

0 comments on commit 23bd230

Please sign in to comment.