refactor: complete application rewrite with modern UI

This commit is contained in:
sokol
2026-02-19 22:55:26 +03:00
parent 271b530fa1
commit a6cc5a9827
26 changed files with 3036 additions and 794 deletions

View File

@@ -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>
);
}