mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-14 09:25:43 +01:00
Fix validation in "Add Entry" components (#1625)
This commit is contained in:
2
gradle/changelog/addentrytotablefield_validation.yaml
Normal file
2
gradle/changelog/addentrytotablefield_validation.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
- type: fixed
|
||||
description: Validation in "Add Entry" components for configuration table ([#1625](https://github.com/scm-manager/scm-manager/pull/1625))
|
||||
@@ -29,6 +29,7 @@ import { createAttributesForTesting } from "../devBuild";
|
||||
|
||||
export type ButtonProps = {
|
||||
label?: string;
|
||||
title?: string;
|
||||
loading?: boolean;
|
||||
disabled?: boolean;
|
||||
action?: (event: MouseEvent) => void;
|
||||
@@ -43,7 +44,6 @@ export type ButtonProps = {
|
||||
|
||||
type Props = ButtonProps &
|
||||
RouteComponentProps & {
|
||||
title?: string;
|
||||
type?: "button" | "submit" | "reset";
|
||||
color?: string;
|
||||
};
|
||||
|
||||
@@ -21,24 +21,20 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
import React, { MouseEvent } from "react";
|
||||
import React, { FC, useState, MouseEvent } from "react";
|
||||
import styled from "styled-components";
|
||||
import Level from "../layout/Level";
|
||||
import InputField from "./InputField";
|
||||
import AddButton from "../buttons/AddButton";
|
||||
import InputField from "./InputField";
|
||||
|
||||
type Props = {
|
||||
addEntry: (p: string) => void;
|
||||
disabled: boolean;
|
||||
disabled?: boolean;
|
||||
buttonLabel: string;
|
||||
fieldLabel: string;
|
||||
errorMessage: string;
|
||||
helpText?: string;
|
||||
validateEntry?: (p: string) => boolean;
|
||||
};
|
||||
|
||||
type State = {
|
||||
entryToAdd: string;
|
||||
errorMessage: string;
|
||||
};
|
||||
|
||||
const StyledLevel = styled(Level)`
|
||||
@@ -46,46 +42,62 @@ const StyledLevel = styled(Level)`
|
||||
margin-bottom: 1rem !important; // same margin as field
|
||||
`;
|
||||
|
||||
const StyledInputField = styled(InputField)`
|
||||
const FullWidthInputField = styled(InputField)`
|
||||
width: 100%;
|
||||
margin-right: 1.5rem;
|
||||
`;
|
||||
|
||||
const StyledField = styled.div.attrs(props => ({
|
||||
const StyledField = styled.div.attrs(() => ({
|
||||
className: "field"
|
||||
}))`
|
||||
align-self: flex-end;
|
||||
`;
|
||||
|
||||
class AddEntryToTableField extends React.Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
entryToAdd: ""
|
||||
};
|
||||
}
|
||||
const AddEntryToTableField: FC<Props> = ({
|
||||
addEntry,
|
||||
disabled,
|
||||
buttonLabel,
|
||||
fieldLabel,
|
||||
helpText,
|
||||
validateEntry,
|
||||
errorMessage
|
||||
}) => {
|
||||
const [entryToAdd, setEntryToAdd] = useState("");
|
||||
|
||||
isValid = () => {
|
||||
const { validateEntry } = this.props;
|
||||
if (!this.state.entryToAdd || this.state.entryToAdd === "" || !validateEntry) {
|
||||
const handleAddEntryChange = (entryName: string) => {
|
||||
setEntryToAdd(entryName);
|
||||
};
|
||||
|
||||
const addButtonClicked = (event: MouseEvent) => {
|
||||
event.preventDefault();
|
||||
appendEntry();
|
||||
};
|
||||
|
||||
const appendEntry = () => {
|
||||
if (!disabled && entryToAdd !== "" && isValid()) {
|
||||
addEntry(entryToAdd);
|
||||
setEntryToAdd("");
|
||||
}
|
||||
};
|
||||
|
||||
const isValid = () => {
|
||||
if (entryToAdd === "" || !validateEntry) {
|
||||
return true;
|
||||
} else {
|
||||
return validateEntry(this.state.entryToAdd);
|
||||
return validateEntry(entryToAdd);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { disabled, buttonLabel, fieldLabel, errorMessage, helpText } = this.props;
|
||||
return (
|
||||
<StyledLevel
|
||||
children={
|
||||
<StyledInputField
|
||||
<FullWidthInputField
|
||||
label={fieldLabel}
|
||||
errorMessage={errorMessage}
|
||||
onChange={this.handleAddEntryChange}
|
||||
validationError={!this.isValid()}
|
||||
value={this.state.entryToAdd}
|
||||
onReturnPressed={this.appendEntry}
|
||||
onChange={handleAddEntryChange}
|
||||
validationError={!isValid()}
|
||||
value={entryToAdd}
|
||||
onReturnPressed={appendEntry}
|
||||
disabled={disabled}
|
||||
helpText={helpText}
|
||||
/>
|
||||
@@ -94,35 +106,13 @@ class AddEntryToTableField extends React.Component<Props, State> {
|
||||
<StyledField>
|
||||
<AddButton
|
||||
label={buttonLabel}
|
||||
action={this.addButtonClicked}
|
||||
disabled={disabled || this.state.entryToAdd === "" || !this.isValid()}
|
||||
action={addButtonClicked}
|
||||
disabled={disabled || entryToAdd === "" || !isValid()}
|
||||
/>
|
||||
</StyledField>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
addButtonClicked = (event: MouseEvent) => {
|
||||
event.preventDefault();
|
||||
this.appendEntry();
|
||||
};
|
||||
|
||||
appendEntry = () => {
|
||||
const { entryToAdd } = this.state;
|
||||
this.props.addEntry(entryToAdd);
|
||||
this.setState({
|
||||
...this.state,
|
||||
entryToAdd: ""
|
||||
});
|
||||
};
|
||||
|
||||
handleAddEntryChange = (entryname: string) => {
|
||||
this.setState({
|
||||
...this.state,
|
||||
entryToAdd: entryname
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export default AddEntryToTableField;
|
||||
|
||||
@@ -21,16 +21,16 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
import React, { MouseEvent } from "react";
|
||||
import React, { FC, useState, MouseEvent } from "react";
|
||||
import styled from "styled-components";
|
||||
import { SelectValue } from "@scm-manager/ui-types";
|
||||
import Level from "../layout/Level";
|
||||
import Autocomplete from "../Autocomplete";
|
||||
import AddButton from "../buttons/AddButton";
|
||||
import Autocomplete from "../Autocomplete";
|
||||
|
||||
type Props = {
|
||||
addEntry: (p: SelectValue) => void;
|
||||
disabled: boolean;
|
||||
disabled?: boolean;
|
||||
buttonLabel: string;
|
||||
fieldLabel: string;
|
||||
helpText?: string;
|
||||
@@ -40,24 +40,13 @@ type Props = {
|
||||
noOptionsMessage?: string;
|
||||
};
|
||||
|
||||
type State = {
|
||||
selectedValue?: SelectValue;
|
||||
};
|
||||
|
||||
const StyledAutocomplete = styled(Autocomplete)`
|
||||
const FullWidthAutocomplete = styled(Autocomplete)`
|
||||
width: 100%;
|
||||
margin-right: 1.5rem;
|
||||
`;
|
||||
|
||||
class AutocompleteAddEntryToTableField extends React.Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
selectedValue: undefined
|
||||
};
|
||||
}
|
||||
render() {
|
||||
const {
|
||||
const AutocompleteAddEntryToTableField: FC<Props> = ({
|
||||
addEntry,
|
||||
disabled,
|
||||
buttonLabel,
|
||||
fieldLabel,
|
||||
@@ -66,16 +55,33 @@ class AutocompleteAddEntryToTableField extends React.Component<Props, State> {
|
||||
placeholder,
|
||||
loadingMessage,
|
||||
noOptionsMessage
|
||||
} = this.props;
|
||||
}) => {
|
||||
const [selectedValue, setSelectedValue] = useState<SelectValue | undefined>(undefined);
|
||||
|
||||
const handleAddEntryChange = (selection: SelectValue) => {
|
||||
setSelectedValue(selection);
|
||||
};
|
||||
|
||||
const addButtonClicked = (event: MouseEvent) => {
|
||||
event.preventDefault();
|
||||
appendEntry();
|
||||
};
|
||||
|
||||
const appendEntry = () => {
|
||||
if (disabled || !selectedValue) {
|
||||
return;
|
||||
}
|
||||
addEntry(selectedValue);
|
||||
setSelectedValue(undefined);
|
||||
};
|
||||
|
||||
const { selectedValue } = this.state;
|
||||
return (
|
||||
<Level
|
||||
children={
|
||||
<StyledAutocomplete
|
||||
<FullWidthAutocomplete
|
||||
label={fieldLabel}
|
||||
loadSuggestions={loadSuggestions}
|
||||
valueSelected={this.handleAddEntryChange}
|
||||
valueSelected={handleAddEntryChange}
|
||||
helpText={helpText}
|
||||
value={selectedValue}
|
||||
placeholder={placeholder}
|
||||
@@ -86,40 +92,11 @@ class AutocompleteAddEntryToTableField extends React.Component<Props, State> {
|
||||
}
|
||||
right={
|
||||
<div className="field">
|
||||
<AddButton label={buttonLabel} action={this.addButtonClicked} disabled={disabled} />
|
||||
<AddButton label={buttonLabel} action={addButtonClicked} disabled={disabled} />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
addButtonClicked = (event: MouseEvent) => {
|
||||
event.preventDefault();
|
||||
this.appendEntry();
|
||||
};
|
||||
|
||||
appendEntry = () => {
|
||||
const { selectedValue } = this.state;
|
||||
if (!selectedValue) {
|
||||
return;
|
||||
}
|
||||
this.setState(
|
||||
// @ts-ignore
|
||||
{
|
||||
...this.state,
|
||||
// @ts-ignore null is needed to clear the selection; undefined does not work
|
||||
selectedValue: null
|
||||
},
|
||||
() => this.props.addEntry(selectedValue)
|
||||
);
|
||||
};
|
||||
|
||||
handleAddEntryChange = (selection: SelectValue) => {
|
||||
this.setState({
|
||||
...this.state,
|
||||
selectedValue: selection
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export default AutocompleteAddEntryToTableField;
|
||||
|
||||
Reference in New Issue
Block a user