fix logs and stats validation error
Some checks failed
build / test (macOS-latest) (push) Has been cancelled
build / test (ubuntu-latest) (push) Has been cancelled
build / test (windows-latest) (push) Has been cancelled
lint / go-lint (push) Has been cancelled
lint / eslint (push) Has been cancelled
build / build-release (push) Has been cancelled
build / notify (push) Has been cancelled
lint / notify (push) Has been cancelled

This commit is contained in:
Ildar Kamalov 2026-07-09 12:08:24 +03:00
parent 852dfefc01
commit 707f6b39c2
5 changed files with 71 additions and 7 deletions

View file

@ -1,7 +1,8 @@
import { createSignal, createEffect } from 'solid-js';
import { createSignal, createEffect, createMemo } from 'solid-js';
import intl from 'panel/common/intl';
import { QUERY_LOG_INTERVALS_DAYS, RETENTION_CUSTOM } from 'panel/helpers/constants';
import { QUERY_LOG_INTERVALS_DAYS, RETENTION_CUSTOM, RETENTION_RANGE } from 'panel/helpers/constants';
import { validateBetween } from 'panel/helpers/validators';
import { RadioGroup } from 'panel/common/ui/SettingsGroup';
import { getIntervalTitle, getDefaultInterval } from '../helpers';
@ -16,6 +17,7 @@ type Props = {
initialValues: Partial<FormValues>;
processing: boolean;
onValuesChange: (values: FormValues) => void;
submitted?: boolean;
};
export const Form = (props: Props) => {
@ -35,6 +37,18 @@ export const Form = (props: Props) => {
}
};
// Validate customInterval when Custom is selected
const customIntervalError = createMemo(() => {
const val = customInterval();
if (intervalValue() !== RETENTION_CUSTOM) {
return undefined;
}
if (val == null) {
return props.submitted ? intl.getMessage('form_error_required') : undefined;
}
return validateBetween(val, RETENTION_RANGE.MIN, RETENTION_RANGE.MAX);
});
// Notify parent of value changes for dirty tracking
createEffect(() => {
const values: FormValues = {
@ -68,6 +82,7 @@ export const Form = (props: Props) => {
inputId="logs_config_custom_interval"
inputLabel={intl.getMessage('settings_log_rotation_hours')}
placeholder={intl.getMessage('settings_rotation_placeholder')}
error={customIntervalError()}
/>
</RadioGroup>
</>

View file

@ -8,6 +8,8 @@ import { setLogsConfig, queryLogsState } from 'panel/stores/queryLogs';
import { Form, FormValues } from './Form';
import { addSuccessToast } from 'panel/stores/toasts';
import { RETENTION_CUSTOM, RETENTION_RANGE } from 'panel/helpers/constants';
import { validateBetween } from 'panel/helpers/validators';
export type LogsConfigPayload = {
interval: number;
@ -28,11 +30,14 @@ export const LogsConfig = (props: Props) => {
});
const [confirmConfig, setConfirmConfig] = createSignal<LogsConfigPayload | null>(null);
const [submitted, setSubmitted] = createSignal(false);
createEffect(
on(
() => props.modalOpen,
(open) => {
if (!open) return;
setSubmitted(false);
setFormValues({
interval: props.interval,
customInterval: props.customInterval,
@ -42,11 +47,22 @@ export const LogsConfig = (props: Props) => {
);
const handleFormChange = (values: FormValues) => {
setSubmitted(false);
setFormValues(values);
};
const handleSave = () => {
const values = formValues();
// Validate custom interval when Custom is selected
if (values.interval === RETENTION_CUSTOM) {
const val = values.customInterval;
if (val == null || validateBetween(val, RETENTION_RANGE.MIN, RETENTION_RANGE.MAX)) {
setSubmitted(true);
return;
}
}
const newInterval = resolveInterval(values.interval, values.customInterval);
// If decreasing retention, show confirmation
@ -100,6 +116,7 @@ export const LogsConfig = (props: Props) => {
}}
processing={props.processing}
onValuesChange={handleFormChange}
submitted={submitted()}
/>
</ConfigDialog>

View file

@ -2,7 +2,7 @@ import { createEffect, untrack } from 'solid-js';
import theme from 'panel/lib/theme';
import { Input } from 'panel/common/controls/Input';
import { RETENTION_CUSTOM, RETENTION_RANGE } from 'panel/helpers/constants';
import { RETENTION_CUSTOM } from 'panel/helpers/constants';
import { toNumber } from 'panel/helpers/form';
type Props = {
@ -48,8 +48,8 @@ export const RetentionCustomInput = (props: Props) => {
}}
disabled={props.processing || props.intervals.includes(props.intervalValue)}
error={!!props.error}
min={RETENTION_RANGE.MIN}
max={RETENTION_RANGE.MAX}
errorMessage={props.error}
size="large"
/>
</div>
);

View file

@ -1,10 +1,11 @@
import { createSignal, createEffect } from 'solid-js';
import { createSignal, createEffect, createMemo } from 'solid-js';
import intl from 'panel/common/intl';
import { RadioGroup } from 'panel/common/ui/SettingsGroup';
import { getIntervalTitle, getDefaultInterval } from '../helpers';
import { STATS_INTERVALS_DAYS, RETENTION_CUSTOM } from 'panel/helpers/constants';
import { STATS_INTERVALS_DAYS, RETENTION_CUSTOM, RETENTION_RANGE } from 'panel/helpers/constants';
import { validateBetween } from 'panel/helpers/validators';
import { RetentionCustomInput } from '../RetentionCustomInput';
export type FormValues = {
@ -16,6 +17,7 @@ type Props = {
initialValues: Partial<FormValues>;
processing: boolean;
onValuesChange: (values: FormValues) => void;
submitted?: boolean;
};
export const Form = (props: Props) => {
@ -35,6 +37,18 @@ export const Form = (props: Props) => {
}
};
// Validate customInterval when Custom is selected
const customIntervalError = createMemo(() => {
const val = customInterval();
if (intervalValue() !== RETENTION_CUSTOM) {
return undefined;
}
if (val == null) {
return props.submitted ? intl.getMessage('form_error_required') : undefined;
}
return validateBetween(val, RETENTION_RANGE.MIN, RETENTION_RANGE.MAX);
});
// Notify parent of value changes for dirty tracking
createEffect(() => {
const values: FormValues = {
@ -68,6 +82,7 @@ export const Form = (props: Props) => {
inputId="stats_config_custom_interval"
inputLabel={intl.getMessage('settings_statistics_retention_hours')}
placeholder={intl.getMessage('settings_rotation_placeholder')}
error={customIntervalError()}
/>
</RadioGroup>
</>

View file

@ -9,6 +9,8 @@ import { setStatsConfig, statsState } from 'panel/stores/stats';
import { Form, FormValues } from './Form';
import { addSuccessToast } from 'panel/stores/toasts';
import { RETENTION_CUSTOM, RETENTION_RANGE } from 'panel/helpers/constants';
import { validateBetween } from 'panel/helpers/validators';
export type StatsConfigPayload = {
interval: number;
@ -29,11 +31,14 @@ export const StatsConfig = (props: Props) => {
});
const [confirmConfig, setConfirmConfig] = createSignal<StatsConfigPayload | null>(null);
const [submitted, setSubmitted] = createSignal(false);
createEffect(
on(
() => props.modalOpen,
(open) => {
if (!open) return;
setSubmitted(false);
setFormValues({
interval: props.interval,
customInterval: props.customInterval,
@ -43,11 +48,22 @@ export const StatsConfig = (props: Props) => {
);
const handleFormChange = (values: FormValues) => {
setSubmitted(false);
setFormValues(values);
};
const handleSave = () => {
const values = formValues();
// Validate custom interval when Custom is selected
if (values.interval === RETENTION_CUSTOM) {
const val = values.customInterval;
if (val == null || validateBetween(val, RETENTION_RANGE.MIN, RETENTION_RANGE.MAX)) {
setSubmitted(true);
return;
}
}
const newInterval = resolveInterval(values.interval, values.customInterval);
// If decreasing retention, show confirmation
@ -99,6 +115,7 @@ export const StatsConfig = (props: Props) => {
}}
processing={props.processing}
onValuesChange={handleFormChange}
submitted={submitted()}
/>
</ConfigDialog>