feat: add dynamic Slack App management#1710
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
|
|
||||||||||||||||
This comment has been minimized.
This comment has been minimized.
|
|
||||||||||||||||
| useEffect(() => { | ||
| return () => { | ||
| if (debounceRef.current) clearTimeout(debounceRef.current); | ||
| }; | ||
| }, []); |
There was a problem hiding this comment.
🟡 Debounced system prompt save is silently discarded on component unmount
In LeftPanel, when the user edits the system prompt, changes are debounced with an 800ms delay before saving. The useEffect cleanup at line 290-294 clears the pending timeout on unmount, which means the last edit is silently lost if the user navigates away within 800ms.
Root Cause & Impact
At client/dashboard/src/pages/slackapp/SlackAppDetail.tsx:282-288, handlePromptChange sets a debounced timer. At lines 290-294, the cleanup effect cancels any pending timer:
useEffect(() => {
return () => {
if (debounceRef.current) clearTimeout(debounceRef.current);
};
}, []);If the user types in the system prompt and then immediately clicks "Delete App" or navigates away (e.g., via browser back button or clicking another sidebar item), the pending save is cancelled and the change is lost without any warning.
Impact: Users may lose system prompt edits without realizing it. A flush-on-unmount pattern (calling saveSystemPrompt with the current value in the cleanup) would prevent data loss.
Prompt for agents
In client/dashboard/src/pages/slackapp/SlackAppDetail.tsx, the useEffect cleanup at lines 290-294 clears the debounce timer on unmount but does not flush the pending save. To prevent data loss, the cleanup should check if there is a pending timeout and, if so, immediately call saveSystemPrompt with the current systemPrompt value before clearing the timer. You will need to use a ref to track the latest systemPrompt value so the cleanup closure has access to it. For example, add a latestPromptRef that is updated in handlePromptChange, then in the cleanup: if debounceRef.current is set, clear the timeout and call saveSystemPrompt(latestPromptRef.current).
Was this helpful? React with 👍 or 👎 to provide feedback.
6fafbd3 to
b1778cf
Compare
b1778cf to
7c1a08c
Compare
Adds server-side support for creating, configuring, updating, and deleting Slack apps. Apps use a two-state lifecycle (unconfigured/active) with per-app credentials, system prompt, icon, and toolset associations. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds card grid list view, create dialog, and detail page with status-dependent UI (unconfigured: Slack deep link + credentials form, active: MCPs, installations, system prompt, chat logs placeholder). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds server-side support for creating, configuring, updating, and deleting Slack apps. Apps use a two-state lifecycle (unconfigured/active) with per-app credentials, system prompt, icon, and toolset associations. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
7c1a08c to
739f56e
Compare
- Verify each toolset belongs to the same project before attaching - Wrap app creation + toolset attachment in a single DB transaction Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| }, | ||
| ); | ||
| }, | ||
| [app.id, queryClient, updateMutation], |
There was a problem hiding this comment.
🟡 updateMutation in useCallback deps causes saveSystemPrompt to be recreated on every mutation state change
Including updateMutation (the entire UseMutationResult object) in the useCallback dependency array for saveSystemPrompt is incorrect — the mutation result object changes identity on every mutation state transition (idle→pending→success/error→idle), causing saveSystemPrompt to be recreated unnecessarily on each state change.
Detailed Explanation
updateMutation at client/dashboard/src/pages/slackapp/SlackAppDetail.tsx:242 is the return value of useUpdateSlackAppMutation(), which wraps React Query's useMutation. The returned object changes reference whenever the mutation state changes.
At line 279, updateMutation is listed as a dependency:
[app.id, queryClient, updateMutation]This means every time a debounced save fires (calling mutate), the mutation's isPending state change forces saveSystemPrompt to be recreated. While mutate itself is stable per React Query, including the whole result object defeats the purpose of useCallback and could cause subtle issues if the debounce timer fires between re-renders.
The fix is to either remove updateMutation from the dependency array (since mutate is stable), or extract just updateMutation.mutate into a ref.
| [app.id, queryClient, updateMutation], | |
| [app.id, queryClient], |
Was this helpful? React with 👍 or 👎 to provide feedback.
Summary
unconfigured→active), per-app credentials, system prompt, icon, and toolset associationsTest plan
mise run db:reset && mise run db:migrateto apply migrationtsc --noEmitpasses🤖 Generated with Claude Code