Skip to content

Commit 364b8f5

Browse files
authored
StatsHouse UI: feature confirm change raw tag (#1967)
1 parent 6d66ac9 commit 364b8f5

File tree

2 files changed

+94
-3
lines changed

2 files changed

+94
-3
lines changed

statshouse-ui/src/admin/pages/FormPage.tsx

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ import { queryClient } from '@/common/queryClient';
2929
import { API_HISTORY } from '@/api/history';
3030
import { HistoryList } from '@/components2/HistoryList';
3131
import { HistoryDashboardLabel } from '@/components2/HistoryDashboardLabel';
32+
import { ConfirmButton } from '@/components/UI/ConfirmButton';
33+
import { useStateBoolean } from '@/hooks';
3234

3335
const METRIC_TYPE_KEYS: MetricType[] = Object.values(METRIC_TYPE) as MetricType[];
3436
const PATH_VERSION_PARAM = '?mv';
@@ -180,6 +182,26 @@ export function EditForm(props: { isReadonly: boolean; adminMode: boolean; isHis
180182
return false;
181183
}, [values.resolution]);
182184

185+
const [confirmRaw, setConfirmRaw] = useStateBoolean(false);
186+
187+
const confirm = useMemo(() => {
188+
if (confirmRaw) {
189+
return (
190+
<div>
191+
<div>Enabling the Raw option for a tag can make your previous data for this tag uninterpretable.</div>
192+
<div>Please ensure that you have not sent data for this tag before.</div>
193+
</div>
194+
);
195+
}
196+
return undefined;
197+
}, [confirmRaw]);
198+
199+
useEffect(() => {
200+
if (success) {
201+
setConfirmRaw.off();
202+
}
203+
}, [setConfirmRaw, setConfirmRaw.off, success]);
204+
183205
return (
184206
<form key={values.version}>
185207
<div className="row mb-3">
@@ -374,7 +396,12 @@ export function EditForm(props: { isReadonly: boolean; adminMode: boolean; isHis
374396
key={ind}
375397
tagNumber={ind}
376398
value={tag}
377-
onChange={(v) => dispatch({ type: 'alias', pos: ind, tag: v })}
399+
onChange={(v) => {
400+
dispatch({ type: 'alias', pos: ind, tag: v });
401+
if (v.isRaw != null || v.raw_kind != null) {
402+
setConfirmRaw.on();
403+
}
404+
}}
378405
onChangeCustomMapping={(pos, from, to) => dispatch({ type: 'customMapping', tag: ind, pos, from, to })}
379406
disabled={isReadonly}
380407
/>
@@ -648,9 +675,19 @@ export function EditForm(props: { isReadonly: boolean; adminMode: boolean; isHis
648675
</div>
649676

650677
<div>
651-
<button type="button" disabled={isRunning || isReadonly} className="btn btn-primary me-3" onClick={onSubmit}>
678+
{/*<button type="button" disabled={isRunning || isReadonly} className="btn btn-primary me-3" onClick={onSubmit}>*/}
679+
{/* Save*/}
680+
{/*</button>*/}
681+
<ConfirmButton
682+
type="button"
683+
disabled={isRunning || isReadonly}
684+
className="btn btn-primary me-3"
685+
confirmHeader={<div className="fw-bold">Warning!</div>}
686+
confirm={confirm}
687+
onClick={onSubmit}
688+
>
652689
Save
653-
</button>
690+
</ConfirmButton>
654691
{isRunning ? (
655692
<div className="spinner-border spinner-border-sm" role="status">
656693
<span className="visually-hidden">Loading...</span>
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright 2025 V Kontakte LLC
2+
//
3+
// This Source Code Form is subject to the terms of the Mozilla Public
4+
// License, v. 2.0. If a copy of the MPL was not distributed with this
5+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
6+
7+
import { Button, type ButtonProps } from '@/components/UI/Button';
8+
import { Dialog } from '@/components/UI/Dialog';
9+
import { useStateBoolean } from '@/hooks';
10+
import { type ReactNode, useCallback } from 'react';
11+
12+
export type ConfirmButtonProps = {
13+
confirm?: ReactNode;
14+
confirmHeader?: ReactNode;
15+
children?: ReactNode;
16+
onClick?: () => void;
17+
} & Omit<ButtonProps, 'ref' | 'onClick'>;
18+
19+
export function ConfirmButton({ confirm, confirmHeader, children, onClick, ...props }: ConfirmButtonProps) {
20+
const [open, setOpen] = useStateBoolean(false);
21+
const onOpen = useCallback(() => {
22+
if (confirm == null) {
23+
onClick?.();
24+
setOpen.off();
25+
} else {
26+
setOpen.on();
27+
}
28+
}, [confirm, onClick, setOpen]);
29+
const onConfirm = useCallback(() => {
30+
onClick?.();
31+
setOpen.off();
32+
}, [onClick, setOpen]);
33+
return (
34+
<>
35+
<Button type="button" onClick={onOpen} {...props}>
36+
{children}
37+
</Button>
38+
<Dialog open={open} onClose={setOpen.off}>
39+
<div className="card">
40+
<div className="card-header">{confirmHeader ?? 'Confirm ?'}</div>
41+
<div className="card-body">{confirm}</div>
42+
<div className="card-footer d-flex gap-2 justify-content-end">
43+
<Button className="btn btn-primary" type="button" onClick={onConfirm}>
44+
Confirm
45+
</Button>
46+
<Button className="btn btn-outline-primary" type="button" onClick={setOpen.off}>
47+
Cancel
48+
</Button>
49+
</div>
50+
</div>
51+
</Dialog>
52+
</>
53+
);
54+
}

0 commit comments

Comments
 (0)