refactor: complete application rewrite with modern UI
This commit is contained in:
168
src/componets/env/EnvironmentParam.tsx
vendored
168
src/componets/env/EnvironmentParam.tsx
vendored
@@ -1,68 +1,104 @@
|
||||
import { useState } from "react";
|
||||
import { EnvParam } from "../../models/EnvParam";
|
||||
import { AppEvent } from "../../models/Env";
|
||||
import { useState } from 'react';
|
||||
import { Check, Minus } from 'lucide-react';
|
||||
import { Button, Input } from '../../components/ui';
|
||||
import { EnvParam } from '../../models/EnvParam';
|
||||
import { AddEvent, RemoveEvent, UpdateEvent } from '../../models/Env';
|
||||
|
||||
|
||||
export function EnvironmentParam(props: { param: EnvParam; onChanged: (e: AppEvent<EnvParam>) => void, isNew: boolean }) {
|
||||
const [param, setParam] = useState(props.param);
|
||||
const [isFocused, setIsFocused] = useState(false);
|
||||
|
||||
function doSet(x: string, act: (x: string) => void) {
|
||||
act(x);
|
||||
setParam(param.Changed(true));
|
||||
}
|
||||
|
||||
function handleChange() {
|
||||
if (!param.isChanged)
|
||||
return;
|
||||
|
||||
let newParam = param.Changed(false);
|
||||
if (!props.isNew) {
|
||||
props.onChanged(AppEvent.update(newParam));
|
||||
}
|
||||
|
||||
setParam(newParam);
|
||||
}
|
||||
|
||||
function handleAdd() {
|
||||
props.onChanged(AppEvent.add(param));
|
||||
setParam(new EnvParam(0, "", ""));
|
||||
}
|
||||
|
||||
function handleKeyUp(x: React.KeyboardEvent<HTMLInputElement>) {
|
||||
if (x.key === "Enter") { handleChange(); }
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={"row px-0" + (param.isChanged ? "border border-warning" : "")}
|
||||
style={isFocused ? { backgroundColor: "lightskyblue", padding: "1px 0" } : { padding: "1px 0" }}>
|
||||
<div className="col-4 mx-0 px-0">
|
||||
<input type="text"
|
||||
className="form-control"
|
||||
style={{ backgroundColor: "rgba(170, 170, 247, 0.16)" }}
|
||||
value={param.name}
|
||||
onChange={x => doSet(x.target.value, (v) => param.name = v)}
|
||||
onBlur={() => { handleChange(); setIsFocused(false); }}
|
||||
onFocus={() => setIsFocused(true)}
|
||||
onKeyUp={handleKeyUp}
|
||||
placeholder="name"
|
||||
aria-label="name" />
|
||||
</div>
|
||||
<div className="col mx-0 px-0">
|
||||
<input type="text"
|
||||
className="form-control"
|
||||
value={param.value}
|
||||
onChange={x => doSet(x.target.value, v => param.value = v)}
|
||||
onBlur={() => { handleChange(); setIsFocused(false); }}
|
||||
onFocus={() => setIsFocused(true)}
|
||||
onKeyUp={handleKeyUp}
|
||||
placeholder="value"
|
||||
aria-label="value" />
|
||||
</div>
|
||||
<div className="col-1 mx-0 px-0" >
|
||||
<button className="btn btn-success" hidden={!props.isNew} onClick={handleAdd}>✓</button>
|
||||
<button className="btn btn-warning" hidden={props.isNew} onClick={() => props.onChanged(AppEvent.del(param))} tabIndex={-1}>−</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
interface EnvironmentParamProps {
|
||||
param: EnvParam;
|
||||
onChanged: (event: AddEvent<EnvParam> | RemoveEvent<EnvParam> | UpdateEvent<EnvParam>) => void;
|
||||
isNew: boolean;
|
||||
}
|
||||
|
||||
export function EnvironmentParam({ param, onChanged, isNew }: EnvironmentParamProps) {
|
||||
const [localParam, setLocalParam] = useState(param);
|
||||
const [isFocused, setIsFocused] = useState(false);
|
||||
|
||||
function updateParam(updates: Partial<EnvParam>) {
|
||||
const updated = localParam.update(updates).markChanged(true);
|
||||
setLocalParam(updated);
|
||||
}
|
||||
|
||||
function handleChange() {
|
||||
if (!localParam.isChanged) return;
|
||||
|
||||
const savedParam = localParam.markChanged(false);
|
||||
|
||||
if (!isNew) {
|
||||
onChanged(UpdateEvent.update(savedParam));
|
||||
}
|
||||
|
||||
setLocalParam(savedParam);
|
||||
}
|
||||
|
||||
function handleAdd() {
|
||||
onChanged(AddEvent.add(localParam));
|
||||
setLocalParam(new EnvParam(0, '', ''));
|
||||
}
|
||||
|
||||
function handleKeyUp(event: React.KeyboardEvent<HTMLInputElement>) {
|
||||
if (event.key === 'Enter') {
|
||||
handleChange();
|
||||
}
|
||||
}
|
||||
|
||||
const isChangedClass = localParam.isChanged ? 'ring-2 ring-yellow-400 border-yellow-400' : '';
|
||||
const focusedClass = isFocused ? 'bg-blue-50' : '';
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`
|
||||
grid grid-cols-12 gap-2 p-2 rounded-lg transition-all duration-200
|
||||
${isChangedClass}
|
||||
${focusedClass ? 'bg-blue-50' : 'bg-white'}
|
||||
hover:bg-slate-50
|
||||
`}
|
||||
>
|
||||
<div className="col-span-4">
|
||||
<Input
|
||||
value={localParam.name ?? ''}
|
||||
onChange={(e) => updateParam({ name: e.target.value })}
|
||||
onBlur={() => { handleChange(); setIsFocused(false); }}
|
||||
onFocus={() => setIsFocused(true)}
|
||||
onKeyUp={handleKeyUp}
|
||||
placeholder="Parameter name"
|
||||
className="text-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="col-span-7">
|
||||
<Input
|
||||
value={localParam.value ?? ''}
|
||||
onChange={(e) => updateParam({ value: e.target.value })}
|
||||
onBlur={() => { handleChange(); setIsFocused(false); }}
|
||||
onFocus={() => setIsFocused(true)}
|
||||
onKeyUp={handleKeyUp}
|
||||
placeholder="Parameter value"
|
||||
className="text-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="col-span-1 flex items-center justify-center">
|
||||
{isNew ? (
|
||||
<Button
|
||||
variant="success"
|
||||
size="sm"
|
||||
onClick={handleAdd}
|
||||
title="Add parameter"
|
||||
icon={Check}
|
||||
className="px-2"
|
||||
/>
|
||||
) : (
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
onClick={() => onChanged(new RemoveEvent(localParam))}
|
||||
title="Remove parameter"
|
||||
icon={Minus}
|
||||
className="px-2 text-red-600 hover:text-red-700 hover:bg-red-50"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user