Skip to content

Commit 8264b8b

Browse files
committed
feat(config): local edits in ConfigServicesEditor
1 parent 1ea12b5 commit 8264b8b

1 file changed

Lines changed: 41 additions & 22 deletions

File tree

cookiefarm/server/frontend/src/features/config/ConfigServicesEditor.tsx

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { useEffect, useRef, useState } from "react";
12
import { Button } from "@cloudflare/kumo/components/button";
23
import { Input } from "@cloudflare/kumo/components/input";
34
import { MinusIcon, PlusIcon } from "@phosphor-icons/react";
@@ -6,6 +7,19 @@ export function ConfigServicesEditor(props: Readonly<{
67
services: Array<[string, number]>;
78
onChange: (services: Array<[string, number]>) => void;
89
}>) {
10+
const [localEntries, setLocalEntries] = useState<Array<[string, number]>>(
11+
() => props.services,
12+
);
13+
14+
const ownLengthRef = useRef(props.services.length);
15+
16+
useEffect(() => {
17+
if (props.services.length !== ownLengthRef.current) {
18+
ownLengthRef.current = props.services.length;
19+
setLocalEntries(props.services);
20+
}
21+
}, [props.services]);
22+
923
return (
1024
<div className="space-y-3">
1125
<div className="flex items-center justify-between gap-3">
@@ -20,10 +34,13 @@ export function ConfigServicesEditor(props: Readonly<{
2034
size="sm"
2135
variant="secondary"
2236
onClick={() => {
23-
props.onChange([
24-
...props.services,
25-
["", 8080],
26-
]);
37+
const newEntries: Array<[string, number]> = [
38+
...localEntries,
39+
["service_name", 8080],
40+
];
41+
ownLengthRef.current = newEntries.length;
42+
setLocalEntries(newEntries);
43+
props.onChange(newEntries);
2744
}}
2845
>
2946
<PlusIcon size={16} />
@@ -32,22 +49,24 @@ export function ConfigServicesEditor(props: Readonly<{
3249
</div>
3350

3451
<div className="space-y-3">
35-
{props.services.map(([name, port], index) => (
52+
{localEntries.map(([name, port], index) => (
3653
<div
37-
key={`${name}-${index}`}
54+
key={index}
3855
className="grid gap-3 rounded-xl border border-kumo-line bg-kumo-overlay p-3 md:grid-cols-[minmax(0,1fr)_180px_auto]"
3956
>
4057
<Input
4158
label="Name"
4259
value={name}
60+
{...(name === "" ? { error: "Name is required" } : {})}
4361
onChange={(event) => {
44-
props.onChange(
45-
props.services.map((currentService, currentIndex) =>
46-
currentIndex === index
47-
? [event.target.value, currentService[1]]
48-
: currentService,
49-
),
62+
const newName = event.target.value;
63+
const newEntries = localEntries.map((entry, i) =>
64+
i === index ? [newName, entry[1]] as [string, number] : entry,
5065
);
66+
setLocalEntries(newEntries);
67+
if (newName.trim() !== "") {
68+
props.onChange(newEntries);
69+
}
5170
}}
5271
/>
5372

@@ -58,13 +77,12 @@ export function ConfigServicesEditor(props: Readonly<{
5877
max={65535}
5978
value={port}
6079
onChange={(event) => {
61-
props.onChange(
62-
props.services.map((currentService, currentIndex) =>
63-
currentIndex === index
64-
? [currentService[0], Number(event.target.value)]
65-
: currentService,
66-
),
80+
const newPort = Number(event.target.value);
81+
const newEntries = localEntries.map((entry, i) =>
82+
i === index ? [entry[0], newPort] as [string, number] : entry,
6783
);
84+
setLocalEntries(newEntries);
85+
props.onChange(newEntries);
6886
}}
6987
/>
7088

@@ -73,11 +91,12 @@ export function ConfigServicesEditor(props: Readonly<{
7391
type="button"
7492
size="sm"
7593
variant="secondary"
76-
disabled={props.services.length === 1}
94+
disabled={localEntries.length === 1}
7795
onClick={() => {
78-
props.onChange(
79-
props.services.filter((_, currentIndex) => currentIndex !== index),
80-
);
96+
const newEntries = localEntries.filter((_, i) => i !== index);
97+
ownLengthRef.current = newEntries.length;
98+
setLocalEntries(newEntries);
99+
props.onChange(newEntries);
81100
}}
82101
>
83102
<MinusIcon size={16} />

0 commit comments

Comments
 (0)