Unverified 提交 6a5efb94 authored 作者: Will Chen's avatar Will Chen 提交者: GitHub

Fix stale UI (#2027)

<!-- CURSOR_SUMMARY --> > [!NOTE] > Addresses stale UI by ensuring key data refreshes immediately after user actions and upgrades. > > - **Token usage refresh**: `ChatInput` toggling the token bar now invalidates `TOKEN_COUNT_QUERY_KEY` to recompute percentages > - **Versions refresh after upgrades**: `AppUpgrades` invalidates `['versions', appId]` on successful upgrade > - **Templates loading**: `useTemplates` uses `placeholderData` (replacing `initialData`) to avoid sticky outdated results > - **Null safety**: `hub.tsx` guards template lookup with optional chaining when passing to `CreateAppDialog` > - **E2E**: `supabase_branch.spec.ts` re-opens the token bar before assertions to validate refreshed counts > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 06c5b8796906ae1dfdf8afda36caa62870781564. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Fixes stale UI by refreshing queries when toggling the token bar and after app upgrades, and by using placeholder data for templates. Users now see up-to-date token counts, versions, and templates. - **Bug Fixes** - Token bar toggle now invalidates the token count query to refresh percentages after branch changes. - App upgrades invalidate the versions query so the latest status shows immediately. - Templates query uses placeholderData instead of initialData to avoid sticky, outdated results. - E2E test updated to reopen the token bar and assert refreshed token counts. - Create app dialog guards against undefined templates to prevent a null error. <sup>Written for commit 06c5b8796906ae1dfdf8afda36caa62870781564. Summary will update automatically on new commits.</sup> <!-- End of auto-generated description by cubic. --> --------- Co-authored-by: 's avatarclaude[bot] <209825114+claude[bot]@users.noreply.github.com>
上级 64b36f4e
...@@ -13,6 +13,8 @@ testSkipIfWindows("supabase branch selection works", async ({ po }) => { ...@@ -13,6 +13,8 @@ testSkipIfWindows("supabase branch selection works", async ({ po }) => {
await po.page.getByTestId("token-bar-toggle").click(); await po.page.getByTestId("token-bar-toggle").click();
// The default branch has a small context. // The default branch has a small context.
await expect(po.page.getByTestId("token-bar")).toContainText("6% of 128K"); await expect(po.page.getByTestId("token-bar")).toContainText("6% of 128K");
// We hide the token bar so we re-open it later to refresh the token count.
await po.page.getByTestId("token-bar-toggle").click();
await po.getTitleBarAppNameButton().click(); await po.getTitleBarAppNameButton().click();
await po.page.getByTestId("supabase-branch-select").click(); await po.page.getByTestId("supabase-branch-select").click();
...@@ -21,5 +23,6 @@ testSkipIfWindows("supabase branch selection works", async ({ po }) => { ...@@ -21,5 +23,6 @@ testSkipIfWindows("supabase branch selection works", async ({ po }) => {
await po.clickBackButton(); await po.clickBackButton();
// The test branch has a large context (200k tokens) so it'll hit the 100% limit. // The test branch has a large context (200k tokens) so it'll hit the 100% limit.
// This is to make sure we're connecting to the right supabase project for the branch. // This is to make sure we're connecting to the right supabase project for the branch.
await po.page.getByTestId("token-bar-toggle").click();
await expect(po.page.getByTestId("token-bar")).toContainText("100% of 128K"); await expect(po.page.getByTestId("token-bar")).toContainText("100% of 128K");
}); });
...@@ -46,6 +46,7 @@ export function AppUpgrades({ appId }: { appId: number | null }) { ...@@ -46,6 +46,7 @@ export function AppUpgrades({ appId }: { appId: number | null }) {
// query to show the new status. // query to show the new status.
queryClient.invalidateQueries({ queryKey: ["is-capacitor", appId] }); queryClient.invalidateQueries({ queryKey: ["is-capacitor", appId] });
} }
queryClient.invalidateQueries({ queryKey: ["versions", appId] });
}, },
}); });
......
...@@ -78,6 +78,8 @@ import { LexicalChatInput } from "./LexicalChatInput"; ...@@ -78,6 +78,8 @@ import { LexicalChatInput } from "./LexicalChatInput";
import { useChatModeToggle } from "@/hooks/useChatModeToggle"; import { useChatModeToggle } from "@/hooks/useChatModeToggle";
import { VisualEditingChangesDialog } from "@/components/preview_panel/VisualEditingChangesDialog"; import { VisualEditingChangesDialog } from "@/components/preview_panel/VisualEditingChangesDialog";
import { useUserBudgetInfo } from "@/hooks/useUserBudgetInfo"; import { useUserBudgetInfo } from "@/hooks/useUserBudgetInfo";
import { useQueryClient } from "@tanstack/react-query";
import { TOKEN_COUNT_QUERY_KEY } from "@/hooks/useCountTokens";
const showTokenBarAtom = atom(false); const showTokenBarAtom = atom(false);
...@@ -96,10 +98,11 @@ export function ChatInput({ chatId }: { chatId?: number }) { ...@@ -96,10 +98,11 @@ export function ChatInput({ chatId }: { chatId?: number }) {
const setMessagesById = useSetAtom(chatMessagesByIdAtom); const setMessagesById = useSetAtom(chatMessagesByIdAtom);
const setIsPreviewOpen = useSetAtom(isPreviewOpenAtom); const setIsPreviewOpen = useSetAtom(isPreviewOpenAtom);
const [showTokenBar, setShowTokenBar] = useAtom(showTokenBarAtom); const [showTokenBar, setShowTokenBar] = useAtom(showTokenBarAtom);
const toggleShowTokenBar = useCallback( const queryClient = useQueryClient();
() => setShowTokenBar((prev) => !prev), const toggleShowTokenBar = useCallback(() => {
[setShowTokenBar], setShowTokenBar((prev) => !prev);
); queryClient.invalidateQueries({ queryKey: TOKEN_COUNT_QUERY_KEY });
}, [setShowTokenBar, queryClient]);
const [selectedComponents, setSelectedComponents] = useAtom( const [selectedComponents, setSelectedComponents] = useAtom(
selectedComponentsPreviewAtom, selectedComponentsPreviewAtom,
); );
......
...@@ -9,7 +9,7 @@ export function useTemplates() { ...@@ -9,7 +9,7 @@ export function useTemplates() {
const ipcClient = IpcClient.getInstance(); const ipcClient = IpcClient.getInstance();
return ipcClient.getTemplates(); return ipcClient.getTemplates();
}, },
initialData: localTemplatesData, placeholderData: localTemplatesData,
meta: { meta: {
showErrorToast: true, showErrorToast: true,
}, },
......
...@@ -96,7 +96,7 @@ const HubPage: React.FC = () => { ...@@ -96,7 +96,7 @@ const HubPage: React.FC = () => {
<CreateAppDialog <CreateAppDialog
open={isCreateDialogOpen} open={isCreateDialogOpen}
onOpenChange={setIsCreateDialogOpen} onOpenChange={setIsCreateDialogOpen}
template={templates.find((t) => t.id === settings?.selectedTemplateId)} template={templates?.find((t) => t.id === settings?.selectedTemplateId)}
/> />
</div> </div>
); );
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论