Skip to content

[MAIN-IMP] Add job-focused proxy link dialog and fix dropdown stacking interactions#107

Open
moda20 wants to merge 4 commits into
masterfrom
Improvement/Add-proxy-links-dialog-to-the-job-action-dropdown
Open

[MAIN-IMP] Add job-focused proxy link dialog and fix dropdown stacking interactions#107
moda20 wants to merge 4 commits into
masterfrom
Improvement/Add-proxy-links-dialog-to-the-job-action-dropdown

Conversation

@moda20

@moda20 moda20 commented Jun 14, 2026

Copy link
Copy Markdown
Owner

Improvements:

  • [Improvement] Added "Linked Proxies" action (⌘⇧P) in job dropdown to manage proxy-to-job linking via dedicated dialog
  • [refactoring] Extracted ProxyUpdateSchema and ProxyConfigUpdateType to shared models/proxies.ts
  • [code quality] Disabled pointer events on job dropdown and search bar when another dialog is stacked on top

Notes

  • [Note] Introduces two new backend endpoint usages: getJobProxies and addProxiesToJob
  • [Impact] Scoped DrawerMenuConfigurator hotkeys to only fire when drawer is open, this was a bug.

How Has This Been Tested?

Related Issues

Screenshots (if applicable)

Additional Context

Summary by CodeRabbit

  • New Features
    • Added job proxy linking/editing from the jobs table action dropdown.
    • Introduced a new job proxy link dialog to manage proxy strategy and unlink all linked proxies.
  • Bug Fixes
    • Keyboard shortcuts now work only when the relevant dialog is open.
    • Improved stacked-dialog interaction so non-top dialogs no longer capture pointer input.
    • Updated the “Custom run” keyboard shortcut.
  • Improvements
    • Enhanced selection/dialog trigger behavior for Enter key usage.
    • Added shared input building blocks for consistent form controls.
  • Chores
    • Updated package name and dependency versions.

disabling pointer events on job dropdown when another dialog is on top of it (same for the search bar)
@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds end-to-end job-proxy linking: new Zod schemas and ProxyActions.LINK_TO_JOBS in the proxy model, two new SystemService endpoints, a useProxies mutation, a new JobProxyLinkDialog component, a forwardRef-upgraded ManagedSelect, a new InputBase UI primitive, and integration into the jobs table ActionDropdown. Several components gain stack-aware pointer-events and hotkey guards. A new safeJsonParse utility safely handles JSON parsing.

Changes

Job-Proxy Linking Feature

Layer / File(s) Summary
Proxy model contracts and package dependencies
src/models/proxies.ts, package.json
Adds LINK_TO_JOBS to ProxyActions, ProxyStrategyOptionEnum/ProxyStrategyOptions, ProxyUpdateSchema, JobProxyLinkUpdateSchema with inferred types from zod/v4. Updates package.json name, adds lodash-es, @types/lodash-es, and adjusts Radix UI dependency versions.
SystemService proxy API methods
src/services/SystemService.ts
Updates ProxyConfigUpdateType import source and adds getJobProxies(jobId) (GET /proxies/getJobProxies) and addProxiesToASingleJob(jobId, proxyIds) (POST /proxies/addProxiesToJob) to systemService.
useProxies hook: LINK_TO_JOBS action and derived data
src/hooks/useProxies.tsx
Adds proxyItems memo, jobProxies callback, jobLinkMutation (with toast and cache invalidation), extends proxyActions to route ProxyActions.LINK_TO_JOBS, and expands the hook return object.
InputBase UI primitive component system
src/components/ui/input-base.tsx
Introduces a new context-driven, ref-composable input foundation: InputBaseContextProps, useInputBase, InputBase, InputBaseFlexWrapper, InputBaseControl, InputBaseAdornment, InputBaseAdornmentButton, InputBaseInput, and InputBaseTextarea.
ManagedSelect forwardRef refactor with Enter hotkey
src/components/custom/ManagedSelect.tsx
Converts ManagedSelect to forwardRef, exposes a SelectTrigger-backed ref via useImperativeHandle, adds an "enter" hotkey toggling dialog state, centralizes open/close through handleDialogState, and adds onKeyDownCapture Enter suppression.
ProxyConfigDialog schema import and typo fix
src/components/custom/system/ProxyConfigDialog.tsx
Switches to shared ProxyUpdateSchema from @/models/proxies and corrects props type name from ProxyConffigDialogProps to ProxyConfigDialogProps.
JobProxyLinkDialog new component
src/components/custom/system/JobProxyLinkDialog.tsx
New dialog component with ProxyLinkDialogProps, react-hook-form + JobProxyLinkUpdateSchema, useQuery-fetched proxy list, strategy selection with conditional proxyId input, ComboBox multiselect, "Unlink all proxies" confirmation, and submit via proxyActions LINK_TO_JOBS.
ActionDropdown integration, stack-aware UI guards, and utilities
src/components/custom/jobsTable/actionDropdown.tsx, src/components/custom/SearchBar.tsx, src/components/custom/DrawerMenuConfigurator.tsx, src/utils/generalUtils.ts
Adds safeJsonParse utility using lodash-es for exception-safe JSON parsing. Wires JobProxyLinkDialog with updateProxyStrategy into the jobs table dropdown (new "Linked Proxies" item, meta+shift+p). Adds cn-based pointer-events-none and tabIndex guards to DropdownMenuContent, CommandItem, and DrawerMenuConfigurator hotkeys when not top-of-stack.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant ActionDropdown
  participant JobProxyLinkDialog
  participant useProxies
  participant systemService

  User->>ActionDropdown: clicks "Linked Proxies" (meta+shift+p)
  ActionDropdown->>JobProxyLinkDialog: opens dialog (jobDetails=row)
  JobProxyLinkDialog->>systemService: getJobProxies(jobId) via useQuery
  systemService-->>JobProxyLinkDialog: proxy list
  User->>JobProxyLinkDialog: selects strategy + proxies, submits
  JobProxyLinkDialog->>useProxies: proxyActions(LINK_TO_JOBS, jobProxyLinkData)
  useProxies->>systemService: addProxiesToASingleJob(jobId, proxyIds)
  systemService-->>useProxies: success
  useProxies->>JobProxyLinkDialog: invalidates ["proxies"] cache
  JobProxyLinkDialog->>ActionDropdown: onProxyStrategyChange(strategy, proxyId)
  ActionDropdown->>ActionDropdown: updateProxyStrategy → dispatches jobActions.UPDATE
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • moda20/TypeSchedulerUI#94: Introduced the useProxies hook that this PR directly extends with LINK_TO_JOBS, proxyItems, jobProxies, and the matching SystemService calls.
  • moda20/TypeSchedulerUI#100: Adds new ProxyActions variants to src/models/proxies.ts and routes them through useProxies and SystemService, the same extension pattern used here for LINK_TO_JOBS.
  • moda20/TypeSchedulerUI#103: Modifies hotkey bindings in DrawerMenuConfigurator.tsx via useHotkeys, which this PR further refines by gating both hotkey calls with enabled: open.

Poem

🐇 Hop, hop, link the proxies tight,
A dialog blooms in the stack's soft light,
Enter key captured, forwardRef in place,
Each pointer-event knows its space.
Schemas and mutations dance in a row —
The rabbit wired it all, tip to toe! 🌿

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately captures the two main objectives: introducing a job-focused proxy link dialog and fixing dropdown stacking interactions with dialogs.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch Improvement/Add-proxy-links-dialog-to-the-job-action-dropdown

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

src/components/custom/ManagedSelect.tsx

Parsing error: ESLint was configured to run on <tsconfigRootDir>/src/components/custom/ManagedSelect.tsx using parserOptions.project: /tsconfig.json
However, that TSConfig does not include this file. Either:

src/components/custom/jobsTable/actionDropdown.tsx

Parsing error: ESLint was configured to run on <tsconfigRootDir>/src/components/custom/jobsTable/actionDropdown.tsx using parserOptions.project: /tsconfig.json
However, that TSConfig does not include this file. Either:

src/components/custom/system/JobProxyLinkDialog.tsx

Parsing error: ESLint was configured to run on <tsconfigRootDir>/src/components/custom/system/JobProxyLinkDialog.tsx using parserOptions.project: /tsconfig.json
However, that TSConfig does not include this file. Either:

  • 2 others

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

moda20 added 2 commits June 18, 2026 08:52
Update managedSelect component to better handle keyboard shortcuts and disabled prop

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/custom/jobsTable/actionDropdown.tsx`:
- Around line 174-186: The updateProxyStrategy callback function uses
JSON.parse() without error handling on row.param, which can throw an exception
if the param contains invalid JSON and break the proxy strategy update action.
Wrap the JSON.parse(row.param || "{}") call in a try-catch block to safely
handle parsing errors, falling back to an empty object {} if the parse fails,
ensuring the function continues execution and properly updates the proxyConfig
regardless of the param validity.

In `@src/components/custom/system/JobProxyLinkDialog.tsx`:
- Around line 69-72: The JSON.parse call in the useMemo hook for proxyConfig
lacks error handling and will throw an exception if jobDetails.param contains
malformed JSON, breaking the dialog render. Wrap the JSON.parse statement in a
try-catch block in the useMemo function to defensively handle parsing errors,
and return an empty object {} as the fallback when parsing fails. This will
ensure the dialog can still open even with invalid param data.
- Around line 164-168: The callback function passed to form.handleSubmit is not
returning the Promise from the handleSubmit(v) call, which causes async failures
and submission state to not propagate correctly. In the onSubmit handler within
the form.handleSubmit callback, return the Promise from handleSubmit(v) so that
the async operation completes and any errors are properly handled by the form
submission chain. This ensures that submission state remains accurate and
failures propagate as expected.
- Around line 75-87: The form.setValue() call in the select callback of useQuery
executes before the form object is declared, which will cause a runtime error.
Move the useForm hook initialization (with JobProxyLinkUpdateSchema) above the
useQuery hook so form is available. Then remove the form.setValue side effect
from the select callback entirely. Create a separate useEffect hook that watches
the jobProxyList data and calls form.setValue when the data changes. Finally,
add an enabled condition to the useQuery to check that jobDetails?.id exists
before executing the query, preventing unnecessary API calls when the job ID is
missing.

In `@src/models/proxies.ts`:
- Around line 79-84: The JobProxyLinkUpdateSchema has a contract mismatch
between the schema definition and its usage. The proxies field is marked as
optional with z.array(z.any()).optional() but the consumer code in useProxies
assumes it's always present and directly calls .map() on it, creating a
potential runtime error. Additionally, strategy accepts any string but the form
enforces ProxyStrategyOptionEnum values. Remove the .optional() modifier from
the proxies field to make it required since JobProxyLinkDialog always provides a
proxies array, and replace the z.string().optional() for strategy with a
z.enum() or z.union() constraint that validates only the allowed
ProxyStrategyOptionEnum values, ensuring the schema accurately reflects the
actual contract between the form producer and consumer hook.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: c94580f5-1115-40da-b5e6-87fa5d141787

📥 Commits

Reviewing files that changed from the base of the PR and between 8b1cd2c and a861050.

📒 Files selected for processing (11)
  • package.json
  • src/components/custom/DrawerMenuConfigurator.tsx
  • src/components/custom/ManagedSelect.tsx
  • src/components/custom/SearchBar.tsx
  • src/components/custom/jobsTable/actionDropdown.tsx
  • src/components/custom/system/JobProxyLinkDialog.tsx
  • src/components/custom/system/ProxyConfigDialog.tsx
  • src/components/ui/input-base.tsx
  • src/hooks/useProxies.tsx
  • src/models/proxies.ts
  • src/services/SystemService.ts

Comment thread src/components/custom/jobsTable/actionDropdown.tsx
Comment on lines +69 to +72
const proxyConfig = useMemo(() => {
const jobParams = JSON.parse(jobDetails?.param ?? "{}")
return jobParams["proxyConfig"]
}, [jobDetails])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard JSON parsing for jobDetails.param (Line 70).

A malformed param payload will throw during render and break opening this dialog. Parse defensively and fall back to {}.

Proposed fix
-  const proxyConfig = useMemo(() => {
-    const jobParams = JSON.parse(jobDetails?.param ?? "{}")
-    return jobParams["proxyConfig"]
-  }, [jobDetails])
+  const proxyConfig = useMemo(() => {
+    try {
+      const jobParams = JSON.parse(jobDetails?.param ?? "{}")
+      return jobParams?.proxyConfig
+    } catch {
+      return undefined
+    }
+  }, [jobDetails?.param])
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const proxyConfig = useMemo(() => {
const jobParams = JSON.parse(jobDetails?.param ?? "{}")
return jobParams["proxyConfig"]
}, [jobDetails])
const proxyConfig = useMemo(() => {
try {
const jobParams = JSON.parse(jobDetails?.param ?? "{}")
return jobParams?.proxyConfig
} catch {
return undefined
}
}, [jobDetails?.param])
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/custom/system/JobProxyLinkDialog.tsx` around lines 69 - 72,
The JSON.parse call in the useMemo hook for proxyConfig lacks error handling and
will throw an exception if jobDetails.param contains malformed JSON, breaking
the dialog render. Wrap the JSON.parse statement in a try-catch block in the
useMemo function to defensively handle parsing errors, and return an empty
object {} as the fallback when parsing fails. This will ensure the dialog can
still open even with invalid param data.

Comment on lines +75 to +87
const { data: jobProxyList, isLoading } = useQuery({
queryKey: ["proxies", jobDetails?.id],
queryFn: () => jobProxies(Number(jobDetails?.id)),
placeholderData: [],
select: data => {
form.setValue(
"proxies",
data.map(e => String(e.proxy_id)),
)
return data
},
})
const form = useForm<z.infer<typeof JobProxyLinkUpdateSchema>>({

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

In TanStack Query v5, can the selectcallback execute duringuseQueryresult derivation on initial render whenplaceholderData or cached data exists?

💡 Result:

Yes, in TanStack Query v5, the select callback does execute during the result derivation on the initial render when placeholderData or existing cached data is present [1][2]. When a query is initialized, TanStack Query processes the available data—whether it comes from the cache or is provided via placeholderData—through the select transformation if one is defined [1][2]. This ensures that the data returned by the useQuery hook consistently matches the expected shape dictated by your selector [3][2]. Key points regarding this behavior: 1. Consistency: The select function is applied to placeholderData just as it is to regular query results [1][2]. This ensures that components receive transformed data immediately, even while the query is in a pending or fetching state [1]. 2. Memoization: Because the select function can execute during render phases, you should memoize it (e.g., using useCallback or by defining it outside the component) to prevent unnecessary re-executions on every render, unless the selector's dependencies or the underlying data have changed [4][5][6]. 3. Performance: TanStack Query only re-runs the select function if the source data has changed or if the reference to the select function itself changes [4][6]. If neither has changed, it will return the previously calculated result [4].

Citations:


🏁 Script executed:

find . -type f -name "JobProxyLinkDialog.tsx" | head -5

Repository: moda20/TypeSchedulerUI

Length of output: 120


🏁 Script executed:

cat -n ./src/components/custom/system/JobProxyLinkDialog.tsx | sed -n '70,95p'

Repository: moda20/TypeSchedulerUI

Length of output: 1086


Move form initialization before useQuery and move select side effects to useEffect (Lines 75-95).

The select callback executes during initial render when placeholderData is set, causing form.setValue() to be called before form is declared. This will fail at runtime. Additionally, the query should not execute when jobDetails.id is missing.

Proposed fix
   const form = useForm<z.infer<typeof JobProxyLinkUpdateSchema>>({
     resolver: zodResolver(JobProxyLinkUpdateSchema),
     defaultValues: {
       id: jobDetails?.id ?? "",
-      proxies: jobProxyList?.map(e => String(e.proxy_id)) ?? [],
+      proxies: [],
       strategy: proxyConfig?.proxyStrategy,
       proxyId: proxyConfig?.targetProxyId,
     },
   })
+  const { data: jobProxyList = [], isLoading } = useQuery({
+    queryKey: ["proxies", jobDetails?.id],
+    queryFn: () => jobProxies(Number(jobDetails!.id)),
+    placeholderData: [],
+    enabled: jobDetails?.id !== undefined && jobDetails?.id !== null,
+  })
+
+  useEffect(() => {
+    form.setValue(
+      "proxies",
+      jobProxyList.map(e => String(e.proxy_id)),
+    )
+  }, [form, jobProxyList])
-  const { data: jobProxyList, isLoading } = useQuery({
-    queryKey: ["proxies", jobDetails?.id],
-    queryFn: () => jobProxies(Number(jobDetails?.id)),
-    placeholderData: [],
-    select: data => {
-      form.setValue(
-        "proxies",
-        data.map(e => String(e.proxy_id)),
-      )
-      return data
-    },
-  })
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/custom/system/JobProxyLinkDialog.tsx` around lines 75 - 87,
The form.setValue() call in the select callback of useQuery executes before the
form object is declared, which will cause a runtime error. Move the useForm hook
initialization (with JobProxyLinkUpdateSchema) above the useQuery hook so form
is available. Then remove the form.setValue side effect from the select callback
entirely. Create a separate useEffect hook that watches the jobProxyList data
and calls form.setValue when the data changes. Finally, add an enabled condition
to the useQuery to check that jobDetails?.id exists before executing the query,
preventing unnecessary API calls when the job ID is missing.

Comment on lines +164 to +168
onSubmit={form.handleSubmit(
(v, event) => {
event.preventDefault()
handleSubmit(v)
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Return the async submit chain from form.handleSubmit (Lines 164-168).

The current callback drops the Promise from handleSubmit(v). Return/await it so failures propagate and submission state remains accurate.

Proposed fix
-            onSubmit={form.handleSubmit(
-              (v, event) => {
-                event.preventDefault()
-                handleSubmit(v)
-              },
+            onSubmit={form.handleSubmit(
+              async (v, event) => {
+                event?.preventDefault()
+                await handleSubmit(v)
+              },
               err => {
                 console.log(err)
               },
             )}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onSubmit={form.handleSubmit(
(v, event) => {
event.preventDefault()
handleSubmit(v)
},
onSubmit={form.handleSubmit(
async (v, event) => {
event?.preventDefault()
await handleSubmit(v)
},
err => {
console.log(err)
},
)}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/custom/system/JobProxyLinkDialog.tsx` around lines 164 - 168,
The callback function passed to form.handleSubmit is not returning the Promise
from the handleSubmit(v) call, which causes async failures and submission state
to not propagate correctly. In the onSubmit handler within the form.handleSubmit
callback, return the Promise from handleSubmit(v) so that the async operation
completes and any errors are properly handled by the form submission chain. This
ensures that submission state remains accurate and failures propagate as
expected.

Comment thread src/models/proxies.ts
Comment on lines +79 to +84
export const JobProxyLinkUpdateSchema = z.object({
id: z.union([z.number(), z.string()]),
proxies: z.array(z.any()).optional(),
strategy: z.string().optional(),
proxyId: z.string().optional(),
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify all producers/consumers of the LINK_TO_JOBS payload before tightening schema.
rg -nP --type=ts --type=tsx -C3 '\bJobProxyLinkUpdateSchema\b|\bJobProxyLinkUpdateType\b|\bProxyActions\.LINK_TO_JOBS\b|jobProxyLinkData!?\.proxies|onProxyStrategyChange\s*\(' src

Repository: moda20/TypeSchedulerUI

Length of output: 94


🏁 Script executed:

#!/bin/bash
# Fixed: search for schema, enum, and action definitions and usages
rg -n '(JobProxyLinkUpdateSchema|JobProxyLinkUpdateType|LINK_TO_JOBS|jobProxyLinkData.*proxies|ProxyStrategyOptionEnum|onProxyStrategyChange)' --type-list | head -20

Repository: moda20/TypeSchedulerUI

Length of output: 456


🏁 Script executed:

#!/bin/bash
# Search for JobProxyLinkUpdateSchema definition and usage
rg -n 'JobProxyLinkUpdateSchema' src -A2 -B2

Repository: moda20/TypeSchedulerUI

Length of output: 1487


🏁 Script executed:

#!/bin/bash
# Search for ProxyStrategyOptionEnum and strategy-related code
rg -n 'ProxyStrategyOptionEnum|ProxyStrategy' src -A1 -B1

Repository: moda20/TypeSchedulerUI

Length of output: 3942


🏁 Script executed:

#!/bin/bash
# Check useProxies.tsx at line 198 area
fd 'useProxies.tsx' src -x cat -n {} | sed -n '190,210p'

Repository: moda20/TypeSchedulerUI

Length of output: 782


🏁 Script executed:

#!/bin/bash
# Search for jobProxyLinkData initialization and form submissions
rg -n 'jobProxyLinkData\s*=' src -B2 -A2

Repository: moda20/TypeSchedulerUI

Length of output: 48


🏁 Script executed:

#!/bin/bash
# Search for defaultValues in JobProxyLinkDialog and any other uses of JobProxyLinkUpdateSchema
rg -n 'defaultValues|JobProxyLinkUpdateType|ProxyActions\.LINK_TO_JOBS' src -B1 -A3

Repository: moda20/TypeSchedulerUI

Length of output: 10172


🏁 Script executed:

#!/bin/bash
# Check mutations that consume JobProxyLinkUpdateType payload
rg -n 'jobLinkMutation|LINK_TO_JOBS' src -B2 -A2

Repository: moda20/TypeSchedulerUI

Length of output: 1356


🏁 Script executed:

#!/bin/bash
# Find all calls to proxyActions with LINK_TO_JOBS
rg -n 'proxyActions.*LINK_TO_JOBS|ProxyActions\.LINK_TO_JOBS' src

Repository: moda20/TypeSchedulerUI

Length of output: 224


🏁 Script executed:

#!/bin/bash
# Check if JobProxyLinkUpdateType is used anywhere else besides JobProxyLinkDialog and type definitions
rg -n 'JobProxyLinkUpdateType' src

Repository: moda20/TypeSchedulerUI

Length of output: 595


Tighten JobProxyLinkUpdateSchema to eliminate data integrity risk in LINK_TO_JOBS payloads.

The schema at lines 79-84 declares proxies as z.array(z.any()).optional() and strategy as z.string().optional(), but the consumer at src/hooks/useProxies.tsx line 198 assumes proxies is always present: jobProxyLinkData!.proxies.map(e => Number(e)). This mismatch creates a contract violation—the form always provides a proxies array (line 91 of JobProxyLinkDialog.tsx defaults to []), but the schema permits undefined, leaving a runtime trap.

Additionally, strategy accepts any string while JobProxyLinkDialog enforces ProxyStrategyOptionEnum values in the form. Tighten the schema to match the actual contract:

Proposed schema fix
 export const JobProxyLinkUpdateSchema = z.object({
-  id: z.union([z.number(), z.string()]),
-  proxies: z.array(z.any()).optional(),
-  strategy: z.string().optional(),
+  id: z.coerce.number().int().positive(),
+  proxies: z.array(z.coerce.number().int().positive()).default([]),
+  strategy: z.nativeEnum(ProxyStrategyOptionEnum).optional(),
   proxyId: z.string().optional(),
 })
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/models/proxies.ts` around lines 79 - 84, The JobProxyLinkUpdateSchema has
a contract mismatch between the schema definition and its usage. The proxies
field is marked as optional with z.array(z.any()).optional() but the consumer
code in useProxies assumes it's always present and directly calls .map() on it,
creating a potential runtime error. Additionally, strategy accepts any string
but the form enforces ProxyStrategyOptionEnum values. Remove the .optional()
modifier from the proxies field to make it required since JobProxyLinkDialog
always provides a proxies array, and replace the z.string().optional() for
strategy with a z.enum() or z.union() constraint that validates only the allowed
ProxyStrategyOptionEnum values, ensuring the schema accurately reflects the
actual contract between the form producer and consumer hook.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/components/custom/system/JobProxyLinkDialog.tsx (2)

97-105: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

Missing dependencies in handlePickingStrategy callback.

The callback references form.setValue and strategySelectRef.current but has an empty dependency array. While form from useForm is typically stable, the explicit empty array [] can be misleading. Consider adding form to deps for clarity.

Suggested fix
     },
-    [],
+    [form],
   )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/custom/system/JobProxyLinkDialog.tsx` around lines 97 - 105,
The handlePickingStrategy callback function uses the form.setValue method but
has an empty dependency array. Add the form object to the dependency array of
the useCallback hook for clarity and to properly declare all dependencies used
within the callback. This ensures the callback correctly tracks its external
dependencies and prevents potential issues if the form reference were to change.

107-134: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Incorrect and missing dependencies in handleSubmit callback.

The dependency array includes isDialogOpen which is not used in the callback body, while missing several identifiers that are used: proxyActions, onProxyStrategyChange, and setDialogState. This can cause stale closure bugs.

Proposed fix
     },
-    [onChange, isDialogOpen, proxyConfig],
+    [onChange, proxyActions, proxyConfig, onProxyStrategyChange, setDialogState],
   )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/custom/system/JobProxyLinkDialog.tsx` around lines 107 - 134,
The dependency array for the handleSubmit useCallback is incomplete and includes
an unused dependency. Remove isDialogOpen from the dependency array since it is
not used in the callback body. Add the missing dependencies that are actually
used within the callback: proxyActions which is invoked to link jobs,
onProxyStrategyChange which is called conditionally based on strategy changes,
and setDialogState which is called to close the dialog. This will prevent stale
closure bugs and ensure the callback is properly memoized.
src/components/custom/jobsTable/actionDropdown.tsx (1)

176-196: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Logic continues after parse error, corrupting data.

When safeJsonParse returns an error, oldParam contains the Error object (not a parsed result). The code then calls set(oldParam, ...) on the Error object and serializes it with JSON.stringify, sending corrupted data to the backend. The function should return early on error or reset oldParam to {}.

Proposed fix
   const updateProxyStrategy = useCallback(
     (newStrategy?: string, specificProxyId?: string) => {
-      const { data: oldParam, error } = safeJsonParse(row.param || "{}")
+      let { data: oldParam, error } = safeJsonParse(row.param || "{}")
       if (error) {
         toast({
           title: "Failed to parse Job params. this is a JSON parsing issue.",
-          description: oldParam?.toString(),
+          description: (oldParam as Error)?.message,
           variant: "destructive",
         })
+        oldParam = {} // Reset to empty object to avoid corrupting data
       }
       set(oldParam, "proxyConfig.proxyStrategy", newStrategy)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/custom/jobsTable/actionDropdown.tsx` around lines 176 - 196,
In the updateProxyStrategy function, when safeJsonParse detects an error,
oldParam is set to the Error object instead of the parsed data, but the code
continues to process it with the set() and unset() calls, causing corrupted data
to be serialized. Add an early return statement immediately after the error
toast is shown to prevent further processing when JSON parsing fails, or
alternatively reset oldParam to an empty object {} when an error is detected so
that subsequent operations work on valid data.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/components/custom/jobsTable/actionDropdown.tsx`:
- Around line 176-196: In the updateProxyStrategy function, when safeJsonParse
detects an error, oldParam is set to the Error object instead of the parsed
data, but the code continues to process it with the set() and unset() calls,
causing corrupted data to be serialized. Add an early return statement
immediately after the error toast is shown to prevent further processing when
JSON parsing fails, or alternatively reset oldParam to an empty object {} when
an error is detected so that subsequent operations work on valid data.

In `@src/components/custom/system/JobProxyLinkDialog.tsx`:
- Around line 97-105: The handlePickingStrategy callback function uses the
form.setValue method but has an empty dependency array. Add the form object to
the dependency array of the useCallback hook for clarity and to properly declare
all dependencies used within the callback. This ensures the callback correctly
tracks its external dependencies and prevents potential issues if the form
reference were to change.
- Around line 107-134: The dependency array for the handleSubmit useCallback is
incomplete and includes an unused dependency. Remove isDialogOpen from the
dependency array since it is not used in the callback body. Add the missing
dependencies that are actually used within the callback: proxyActions which is
invoked to link jobs, onProxyStrategyChange which is called conditionally based
on strategy changes, and setDialogState which is called to close the dialog.
This will prevent stale closure bugs and ensure the callback is properly
memoized.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 3e10f237-5e7e-4a1f-b269-0fbfcfa09ff9

📥 Commits

Reviewing files that changed from the base of the PR and between a861050 and 79eb656.

📒 Files selected for processing (5)
  • src/components/custom/ManagedSelect.tsx
  • src/components/custom/jobsTable/actionDropdown.tsx
  • src/components/custom/system/JobProxyLinkDialog.tsx
  • src/services/SystemService.ts
  • src/utils/generalUtils.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant