mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-22 18:35:21 -06:00
fix(ui): expose all automation schedule filters (#126962)
* fix(ui): expose all automation schedule filters Amp-Thread-ID: https://ampcode.com/threads/T-01a021f4-b547-7788-a916-d4a94cbd3e3b * refactor(ui): derive cron filters from protocol Amp-Thread-ID: https://ampcode.com/threads/T-01a021f4-b547-7788-a916-d4a94cbd3e3b --------- Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
committed by
GitHub
parent
e2a48d4b70
commit
2acfc47b7f
@@ -2,6 +2,7 @@
|
||||
import { parseBoolean } from "@openclaw/normalization-core/boolean-coercion";
|
||||
import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce";
|
||||
import {
|
||||
type CronListParams,
|
||||
ErrorCodes,
|
||||
errorShape,
|
||||
GatewayErrorDetailCodes,
|
||||
@@ -488,21 +489,7 @@ export const cronHandlers: GatewayRequestHandlers = {
|
||||
if (!assertValidParams(params, validateCronListParams, "cron.list", respond)) {
|
||||
return;
|
||||
}
|
||||
const p = params as {
|
||||
includeDisabled?: boolean;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
query?: string;
|
||||
enabled?: "all" | "enabled" | "disabled";
|
||||
scheduleKind?: "all" | "at" | "every" | "cron";
|
||||
lastRunStatus?: "all" | "ok" | "error" | "skipped" | "unknown";
|
||||
trigger?: "all" | "conditional" | "unconditional";
|
||||
sortBy?: "nextRunAtMs" | "updatedAtMs" | "name";
|
||||
sortDir?: "asc" | "desc";
|
||||
agentId?: string;
|
||||
compact?: boolean;
|
||||
includeDeliveryPreviews?: boolean;
|
||||
};
|
||||
const p = params as CronListParams;
|
||||
const callerScope = readCronCallerScope(client);
|
||||
const requestedAgentId = p.agentId ? normalizeAgentId(p.agentId) : undefined;
|
||||
if (callerScope && requestedAgentId && requestedAgentId !== callerScope.agentId) {
|
||||
|
||||
@@ -555,6 +555,7 @@ export type {
|
||||
export type CronRunStatus = NonNullable<ProtocolCronRunLogEntry["status"]>;
|
||||
export type CronDeliveryStatus = NonNullable<ProtocolCronRunLogEntry["deliveryStatus"]>;
|
||||
export type CronJobsEnabledFilter = NonNullable<CronListParams["enabled"]>;
|
||||
export type CronJobsScheduleKindFilter = NonNullable<CronListParams["scheduleKind"]>;
|
||||
export type CronJobsTriggerFilter = NonNullable<CronListParams["trigger"]>;
|
||||
export type CronJobsSortBy = NonNullable<CronListParams["sortBy"]>;
|
||||
export type CronRunScope = NonNullable<CronRunsParams["scope"]>;
|
||||
|
||||
@@ -7,6 +7,7 @@ import type {
|
||||
CronJob,
|
||||
CronDeliveryStatus,
|
||||
CronJobsEnabledFilter,
|
||||
CronJobsScheduleKindFilter,
|
||||
CronJobsTriggerFilter,
|
||||
CronJobsListResult,
|
||||
CronJobsSortBy,
|
||||
@@ -191,7 +192,6 @@ export type CronFieldKey =
|
||||
|
||||
export type CronFieldErrors = Partial<Record<CronFieldKey, string>>;
|
||||
|
||||
export type CronJobsScheduleKindFilter = "all" | "at" | "every" | "cron" | "on-exit" | "stream";
|
||||
export type CronJobsLastStatusFilter = "all" | CronRunStatus | "unknown";
|
||||
type CronRunsLoadStatus = "ok" | "error" | "skipped";
|
||||
|
||||
|
||||
@@ -122,9 +122,21 @@ describe("cron view list pane", () => {
|
||||
'[data-test-id="cron-jobs-schedule-filter"]',
|
||||
HTMLSelectElement,
|
||||
);
|
||||
scheduleFilter.value = "cron";
|
||||
scheduleFilter.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
expect(onJobsFiltersChange).toHaveBeenCalledWith({ cronJobsScheduleKindFilter: "cron" });
|
||||
expect(Array.from(scheduleFilter.options, (option) => option.value)).toEqual([
|
||||
"all",
|
||||
"at",
|
||||
"every",
|
||||
"cron",
|
||||
"on-exit",
|
||||
"stream",
|
||||
]);
|
||||
for (const scheduleKind of ["on-exit", "stream"] as const) {
|
||||
scheduleFilter.value = scheduleKind;
|
||||
scheduleFilter.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
expect(onJobsFiltersChange).toHaveBeenCalledWith({
|
||||
cronJobsScheduleKindFilter: scheduleKind,
|
||||
});
|
||||
}
|
||||
|
||||
const lastStatusFilter = getElement(
|
||||
container,
|
||||
|
||||
@@ -17,6 +17,7 @@ import type {
|
||||
CronStatus,
|
||||
CronDeliveryStatus,
|
||||
CronJobsEnabledFilter,
|
||||
CronJobsScheduleKindFilter,
|
||||
CronJobsTriggerFilter,
|
||||
CronRunsStatusValue,
|
||||
CronJobsSortBy,
|
||||
@@ -51,7 +52,6 @@ import type {
|
||||
CronFieldKey,
|
||||
CronFormState,
|
||||
CronJobsLastStatusFilter,
|
||||
CronJobsScheduleKindFilter,
|
||||
} from "../../lib/cron/index.ts";
|
||||
import { formatUiExternalText } from "../../lib/format-error.ts";
|
||||
import { formatRelativeTimestamp, formatMs } from "../../lib/format.ts";
|
||||
@@ -448,6 +448,15 @@ const ENABLED_TABS: Array<{ value: CronJobsEnabledFilter; labelKey: string }> =
|
||||
{ value: "disabled", labelKey: "cron.tabs.paused" },
|
||||
];
|
||||
|
||||
const SCHEDULE_KIND_FILTER_LABELS: Record<CronJobsScheduleKindFilter, string> = {
|
||||
all: "cron.jobs.all",
|
||||
at: "cron.form.at",
|
||||
every: "cron.form.every",
|
||||
cron: "cron.form.cronOption",
|
||||
"on-exit": "cron.form.repeatOnExit",
|
||||
stream: "cron.form.repeatStream",
|
||||
};
|
||||
|
||||
function renderListView(props: CronProps) {
|
||||
const hasAdvancedJobsFilters =
|
||||
props.jobsScheduleKindFilter !== "all" ||
|
||||
@@ -646,12 +655,10 @@ function renderJobsFilterPopover(props: CronProps, active: boolean) {
|
||||
label: t("cron.jobs.schedule"),
|
||||
value: props.jobsScheduleKindFilter,
|
||||
testId: "cron-jobs-schedule-filter",
|
||||
options: [
|
||||
{ value: "all", label: t("cron.jobs.all") },
|
||||
{ value: "at", label: t("cron.form.at") },
|
||||
{ value: "every", label: t("cron.form.every") },
|
||||
{ value: "cron", label: t("cron.form.cronOption") },
|
||||
],
|
||||
options: Object.entries(SCHEDULE_KIND_FILTER_LABELS).map(([value, labelKey]) => ({
|
||||
value,
|
||||
label: t(labelKey),
|
||||
})),
|
||||
})}
|
||||
${renderJobsFilter(props, "cronJobsLastStatusFilter", {
|
||||
label: t("cron.jobs.lastRun"),
|
||||
|
||||
Reference in New Issue
Block a user