diff --git a/web/src/components/forms/PackForm.tsx b/web/src/components/forms/PackForm.tsx
index 5fc3029..18819a3 100644
--- a/web/src/components/forms/PackForm.tsx
+++ b/web/src/components/forms/PackForm.tsx
@@ -4,7 +4,9 @@ import { useCreatePack, useUpdatePack } from "@/hooks/usePacks";
import type { PackResponse } from "@/api";
import { labelToRef } from "@/lib/format-utils";
import SchemaBuilder from "@/components/common/SchemaBuilder";
-import ParamSchemaForm from "@/components/common/ParamSchemaForm";
+import ParamSchemaForm, {
+ type ParamSchema,
+} from "@/components/common/ParamSchemaForm";
import { RotateCcw } from "lucide-react";
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -603,7 +605,7 @@ export default function PackForm({ pack, onSuccess, onCancel }: PackFormProps) {
= {
+ const formData: Record & Partial = {
pack_ref: selectedPackData?.ref || "",
ref: fullRef,
label: label.trim(),
@@ -232,9 +233,14 @@ export default function RuleForm({ rule, onSuccess, onCancel }: RuleFormProps) {
try {
if (isEditing && rule) {
- await updateRule.mutateAsync({ ref: rule.ref, data: formData });
+ await updateRule.mutateAsync({
+ ref: rule.ref,
+ data: formData as unknown as UpdateRuleRequest,
+ });
} else {
- const newRuleResponse = await createRule.mutateAsync(formData);
+ const newRuleResponse = await createRule.mutateAsync(
+ formData as unknown as CreateRuleRequest,
+ );
if (!onSuccess) {
navigate(`/rules/${newRuleResponse.data.ref}`);
}
diff --git a/web/src/components/forms/TriggerForm.tsx b/web/src/components/forms/TriggerForm.tsx
index 4782b76..93af009 100644
--- a/web/src/components/forms/TriggerForm.tsx
+++ b/web/src/components/forms/TriggerForm.tsx
@@ -68,7 +68,9 @@ export default function TriggerForm({
setPackId(pack.id);
}
// Extract local ref from full ref
- setLocalRef(extractLocalRef(initialData.ref, initialData.pack_ref));
+ setLocalRef(
+ extractLocalRef(initialData.ref, initialData.pack_ref ?? undefined),
+ );
}
}
}, [initialData, packs, isEditing]);
diff --git a/web/src/components/workflows/WorkflowInputsPanel.tsx b/web/src/components/workflows/WorkflowInputsPanel.tsx
index eb8d2d1..9d6cbb1 100644
--- a/web/src/components/workflows/WorkflowInputsPanel.tsx
+++ b/web/src/components/workflows/WorkflowInputsPanel.tsx
@@ -213,7 +213,9 @@ export default function WorkflowInputsPanel({
- setDraftSchema(schema as Record)
+ setDraftSchema(
+ schema as unknown as Record,
+ )
}
placeholder={
modalTarget === "parameters"
diff --git a/web/src/hooks/useArtifactStream.ts b/web/src/hooks/useArtifactStream.ts
index afbe764..a7164b6 100644
--- a/web/src/hooks/useArtifactStream.ts
+++ b/web/src/hooks/useArtifactStream.ts
@@ -1,6 +1,9 @@
import { useCallback } from "react";
import { useQueryClient } from "@tanstack/react-query";
-import { useEntityNotifications } from "@/contexts/WebSocketContext";
+import {
+ useEntityNotifications,
+ type Notification,
+} from "@/contexts/WebSocketContext";
interface UseArtifactStreamOptions {
/**
@@ -62,7 +65,8 @@ export function useArtifactStream(options: UseArtifactStreamOptions = {}) {
const queryClient = useQueryClient();
const handleNotification = useCallback(
- (notification: ArtifactNotification) => {
+ (raw: Notification) => {
+ const notification = raw as unknown as ArtifactNotification;
const payload = notification.payload;
// If we're filtering by execution ID, only process matching artifacts
diff --git a/web/src/hooks/useEnforcementStream.ts b/web/src/hooks/useEnforcementStream.ts
index 23be47e..f023245 100644
--- a/web/src/hooks/useEnforcementStream.ts
+++ b/web/src/hooks/useEnforcementStream.ts
@@ -1,6 +1,9 @@
import { useCallback } from "react";
import { useQueryClient } from "@tanstack/react-query";
-import { useEntityNotifications } from "@/contexts/WebSocketContext";
+import {
+ useEntityNotifications,
+ type Notification,
+} from "@/contexts/WebSocketContext";
import type { EnforcementSummary } from "@/api";
interface UseEnforcementStreamOptions {
@@ -120,7 +123,8 @@ export function useEnforcementStream(
const queryClient = useQueryClient();
const handleNotification = useCallback(
- (notification: EnforcementNotification) => {
+ (raw: Notification) => {
+ const notification = raw as unknown as EnforcementNotification;
// Filter by enforcement ID if specified
if (enforcementId && notification.entity_id !== enforcementId) {
return;
diff --git a/web/src/hooks/useExecutionStream.ts b/web/src/hooks/useExecutionStream.ts
index 2c61b17..4f84cda 100644
--- a/web/src/hooks/useExecutionStream.ts
+++ b/web/src/hooks/useExecutionStream.ts
@@ -1,7 +1,10 @@
import { useCallback } from "react";
import { useQueryClient } from "@tanstack/react-query";
-import { useEntityNotifications } from "@/contexts/WebSocketContext";
-import type { ExecutionSummary } from "@/api";
+import {
+ useEntityNotifications,
+ type Notification,
+} from "@/contexts/WebSocketContext";
+import type { ExecutionSummary, ExecutionStatus } from "@/api";
interface UseExecutionStreamOptions {
/**
@@ -132,10 +135,8 @@ function executionMatchesParams(
return false;
}
- // Check executor filter (may be present)
- if (params.executor !== undefined && execution.executor !== params.executor) {
- return false;
- }
+ // Note: executor is not part of ExecutionSummary so we cannot filter on it
+ // from WebSocket payloads. Executor-filtered queries rely on API refetch.
// Note: rule_ref and trigger_ref are NOT checked here because they may not be
// present in WebSocket payloads (they come from enforcement data which is
@@ -152,7 +153,7 @@ function hasUnsupportedFilters(
params: ExecutionQueryParams | undefined,
): boolean {
if (!params) return false;
- return !!(params.ruleRef || params.triggerRef);
+ return !!(params.ruleRef || params.triggerRef || params.executor);
}
/**
@@ -175,21 +176,23 @@ export function useExecutionStream(options: UseExecutionStreamOptions = {}) {
const queryClient = useQueryClient();
const handleNotification = useCallback(
- (notification: ExecutionNotification) => {
+ (notification: Notification) => {
+ const executionNotification =
+ notification as unknown as ExecutionNotification;
// Filter by execution ID if specified
- if (executionId && notification.entity_id !== executionId) {
+ if (executionId && executionNotification.entity_id !== executionId) {
return;
}
// Extract execution data from notification payload (flat structure).
// Keep raw payload for old_status inspection, but use cleaned data for cache.
- const rawPayload = notification.payload;
+ const rawPayload = executionNotification.payload;
const oldStatus: string | undefined = rawPayload?.old_status;
const executionData = stripNotificationMeta(rawPayload);
// Update specific execution query if it exists
queryClient.setQueryData(
- ["executions", notification.entity_id],
+ ["executions", executionNotification.entity_id],
(old: ExecutionDetailCache | undefined) => {
if (!old) return old;
return {
@@ -223,7 +226,7 @@ export function useExecutionStream(options: UseExecutionStreamOptions = {}) {
// Check if execution already exists in the list
const existingIndex = old.data.findIndex(
- (exec) => exec.id === notification.entity_id,
+ (exec) => exec.id === executionNotification.entity_id,
);
// Merge the updated fields to determine if the execution matches the query
@@ -266,7 +269,7 @@ export function useExecutionStream(options: UseExecutionStreamOptions = {}) {
// not in our local data array, total_items must stay accurate.
const virtualOldExecution = {
...mergedExecution,
- status: oldStatus,
+ status: oldStatus as ExecutionStatus,
};
const oldMatchedQuery = executionMatchesParams(
virtualOldExecution,
diff --git a/web/src/pages/actions/ActionsPage.tsx b/web/src/pages/actions/ActionsPage.tsx
index ab98b8d..1231ef2 100644
--- a/web/src/pages/actions/ActionsPage.tsx
+++ b/web/src/pages/actions/ActionsPage.tsx
@@ -551,11 +551,11 @@ function ActionDetail({ actionRef }: { actionRef: string }) {