Add an unsaved indicator to editors.
This commit is contained in:
parent
9ee0d2db90
commit
459380cb69
|
@ -20,13 +20,16 @@ type Props = {
|
||||||
saveRedirect: (redirect: Redirect) => void;
|
saveRedirect: (redirect: Redirect) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
type State = RedirectParameters;
|
type State = {
|
||||||
|
hasBeenEdited: boolean;
|
||||||
|
} & RedirectParameters;
|
||||||
|
|
||||||
export default class Editor extends Component<Props, State> {
|
export default class Editor extends Component<Props, State> {
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
|
hasBeenEdited: false,
|
||||||
...props.redirect.parameters,
|
...props.redirect.parameters,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -34,27 +37,37 @@ export default class Editor extends Component<Props, State> {
|
||||||
onInput = (event: Event, input: 'matcher' | 'redirect') => {
|
onInput = (event: Event, input: 'matcher' | 'redirect') => {
|
||||||
const target = event.target as HTMLInputElement;
|
const target = event.target as HTMLInputElement;
|
||||||
const value = target.value;
|
const value = target.value;
|
||||||
|
const newState: Partial<State> = {
|
||||||
|
hasBeenEdited: true,
|
||||||
|
};
|
||||||
|
|
||||||
if (input === 'matcher') {
|
if (input === 'matcher') {
|
||||||
this.setState({matcherValue: value});
|
newState.matcherValue = value;
|
||||||
} else if (input === 'redirect') {
|
} else if (input === 'redirect') {
|
||||||
this.setState({redirectValue: value});
|
newState.redirectValue = value;
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`Unexpected input changed: ${input as string}`);
|
throw new Error(`Unexpected input changed: ${input as string}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.setState(newState);
|
||||||
};
|
};
|
||||||
|
|
||||||
onSelectChange = (event: Event, select: 'matcher' | 'redirect') => {
|
onSelectChange = (event: Event, select: 'matcher' | 'redirect') => {
|
||||||
const target = event.target as HTMLSelectElement;
|
const target = event.target as HTMLSelectElement;
|
||||||
const value = target.value;
|
const value = target.value;
|
||||||
|
const newState: Partial<State> = {
|
||||||
|
hasBeenEdited: true,
|
||||||
|
};
|
||||||
|
|
||||||
if (select === 'matcher' && narrowMatcherType(value)) {
|
if (select === 'matcher' && narrowMatcherType(value)) {
|
||||||
this.setState({matcherType: value});
|
newState.matcherType = value;
|
||||||
} else if (select === 'redirect' && narrowRedirectType(value)) {
|
} else if (select === 'redirect' && narrowRedirectType(value)) {
|
||||||
this.setState({redirectType: value});
|
newState.redirectType = value;
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`${value} is not a valid MatcherType or RedirectType`);
|
throw new Error(`${value} is not a valid MatcherType or RedirectType`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.setState(newState);
|
||||||
};
|
};
|
||||||
|
|
||||||
onMatcherInput = (event: Event) => {
|
onMatcherInput = (event: Event) => {
|
||||||
|
@ -99,6 +112,7 @@ export default class Editor extends Component<Props, State> {
|
||||||
const redirect = this.parseRedirect();
|
const redirect = this.parseRedirect();
|
||||||
await storage.save(redirect);
|
await storage.save(redirect);
|
||||||
this.props.saveRedirect(redirect);
|
this.props.saveRedirect(redirect);
|
||||||
|
this.setState({hasBeenEdited: false});
|
||||||
};
|
};
|
||||||
|
|
||||||
toggleEnabled = async () => {
|
toggleEnabled = async () => {
|
||||||
|
@ -111,8 +125,14 @@ export default class Editor extends Component<Props, State> {
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {enabled, matcherType, matcherValue, redirectType, redirectValue} =
|
const {
|
||||||
this.state;
|
enabled,
|
||||||
|
hasBeenEdited,
|
||||||
|
matcherType,
|
||||||
|
matcherValue,
|
||||||
|
redirectType,
|
||||||
|
redirectValue,
|
||||||
|
} = this.state;
|
||||||
|
|
||||||
const matcherTypeOptions = matcherTypes.map(
|
const matcherTypeOptions = matcherTypes.map(
|
||||||
(value) => html`<option value=${value}>${value}</option>`,
|
(value) => html`<option value=${value}>${value}</option>`,
|
||||||
|
@ -122,7 +142,7 @@ export default class Editor extends Component<Props, State> {
|
||||||
);
|
);
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div class="editor">
|
<div class="editor ${hasBeenEdited ? 'has-been-edited' : ''}">
|
||||||
<select
|
<select
|
||||||
class="select"
|
class="select"
|
||||||
id="matcher-type"
|
id="matcher-type"
|
||||||
|
|
|
@ -30,6 +30,10 @@ export default class Usage extends Component {
|
||||||
|
|
||||||
<p>Editing redirects:</p>
|
<p>Editing redirects:</p>
|
||||||
<ul>
|
<ul>
|
||||||
|
<li>
|
||||||
|
If a redirect has been edited, a yellow border will be shown around
|
||||||
|
it.
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Changes to redirects are only saved when you click the save button.
|
Changes to redirects are only saved when you click the save button.
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
.editor {
|
.editor {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background-color: var(--db-2);
|
background-color: var(--db-2);
|
||||||
|
border: 1px solid transparent;
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
|
|
||||||
|
&.has-been-edited {
|
||||||
|
border: 1px solid var(--da-3);
|
||||||
|
}
|
||||||
|
|
||||||
.arrow-span {
|
.arrow-span {
|
||||||
aspect-ratio: 1;
|
aspect-ratio: 1;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
Loading…
Reference in New Issue