Skip to content

Commit 6066938

Browse files
committed
Nicer code
1 parent ce27790 commit 6066938

File tree

2 files changed

+58
-42
lines changed
  • apps/webapp/app

2 files changed

+58
-42
lines changed

apps/webapp/app/components/code/AIQueryInput.tsx

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,16 @@ interface AIQueryInputProps {
3232
onQueryGenerated: (query: string) => void;
3333
/** Set this to a prompt to auto-populate and immediately submit */
3434
autoSubmitPrompt?: string;
35+
/** Change this to force re-submission even if prompt is the same */
36+
autoSubmitKey?: number;
3537
/** Get the current query in the editor (used for edit mode) */
3638
getCurrentQuery?: () => string;
3739
}
3840

3941
export function AIQueryInput({
4042
onQueryGenerated,
4143
autoSubmitPrompt,
44+
autoSubmitKey,
4245
getCurrentQuery,
4346
}: AIQueryInputProps) {
4447
const [prompt, setPrompt] = useState("");
@@ -50,7 +53,7 @@ export function AIQueryInput({
5053
const [lastResult, setLastResult] = useState<"success" | "error" | null>(null);
5154
const textareaRef = useRef<HTMLTextAreaElement>(null);
5255
const abortControllerRef = useRef<AbortController | null>(null);
53-
const lastAutoSubmitRef = useRef<string | null>(null);
56+
const lastAutoSubmitRef = useRef<{ prompt: string; key?: number } | null>(null);
5457

5558
const organization = useOrganization();
5659
const project = useProject();
@@ -197,19 +200,22 @@ export function AIQueryInput({
197200
[prompt, submitQuery]
198201
);
199202

200-
// Auto-submit when autoSubmitPrompt changes
203+
// Auto-submit when autoSubmitPrompt or autoSubmitKey changes
201204
useEffect(() => {
202-
if (
203-
autoSubmitPrompt &&
204-
autoSubmitPrompt.trim() &&
205-
autoSubmitPrompt !== lastAutoSubmitRef.current &&
206-
!isLoading
207-
) {
208-
lastAutoSubmitRef.current = autoSubmitPrompt;
205+
if (!autoSubmitPrompt || !autoSubmitPrompt.trim() || isLoading) {
206+
return;
207+
}
208+
209+
const last = lastAutoSubmitRef.current;
210+
const isDifferent =
211+
last === null || autoSubmitPrompt !== last.prompt || autoSubmitKey !== last.key;
212+
213+
if (isDifferent) {
214+
lastAutoSubmitRef.current = { prompt: autoSubmitPrompt, key: autoSubmitKey };
209215
setPrompt(autoSubmitPrompt);
210216
submitQuery(autoSubmitPrompt);
211217
}
212-
}, [autoSubmitPrompt, isLoading, submitQuery]);
218+
}, [autoSubmitPrompt, autoSubmitKey, isLoading, submitQuery]);
213219

214220
// Cleanup on unmount
215221
useEffect(() => {

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/route.tsx

Lines changed: 42 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,12 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
118118
const user = await requireUser(request);
119119
const { projectParam, organizationSlug, envParam } = EnvironmentParamSchema.parse(params);
120120

121-
const canAccess = await hasQueryAccess(user.id, user.admin, user.isImpersonating, organizationSlug);
121+
const canAccess = await hasQueryAccess(
122+
user.id,
123+
user.admin,
124+
user.isImpersonating,
125+
organizationSlug
126+
);
122127
if (!canAccess) {
123128
throw redirect("/");
124129
}
@@ -159,7 +164,12 @@ export const action = async ({ request, params }: ActionFunctionArgs) => {
159164
const user = await requireUser(request);
160165
const { projectParam, organizationSlug, envParam } = EnvironmentParamSchema.parse(params);
161166

162-
const canAccess = await hasQueryAccess(user.id, user.admin, user.isImpersonating, organizationSlug);
167+
const canAccess = await hasQueryAccess(
168+
user.id,
169+
user.admin,
170+
user.isImpersonating,
171+
organizationSlug
172+
);
163173
if (!canAccess) {
164174
return typedjson(
165175
{ error: "Unauthorized", rows: null, columns: null, stats: null },
@@ -341,21 +351,16 @@ export default function Page() {
341351
const [prettyFormatting, setPrettyFormatting] = useState(true);
342352
const [resultsView, setResultsView] = useState<"table" | "graph">("table");
343353
const [chartConfig, setChartConfig] = useState<ChartConfiguration>(defaultChartConfig);
344-
const [helpTab, setHelpTab] = useState<string>("ai");
345-
const [errorFixPrompt, setErrorFixPrompt] = useState<string | undefined>();
346-
347-
const handleTryFixError = useCallback(
348-
(errorMessage: string) => {
349-
// Switch to AI tab and trigger an error fix prompt
350-
setHelpTab("ai");
351-
// Clear any previous prompt first to ensure re-trigger
352-
setErrorFixPrompt(undefined);
353-
setTimeout(() => {
354-
setErrorFixPrompt(`Fix this query error: ${errorMessage}`);
355-
}, 0);
356-
},
357-
[]
358-
);
354+
const [sidebarTab, setSidebarTab] = useState<string>("ai");
355+
const [aiFixRequest, setAiFixRequest] = useState<{ prompt: string; key: number } | null>(null);
356+
357+
const handleTryFixError = useCallback((errorMessage: string) => {
358+
setSidebarTab("ai");
359+
setAiFixRequest((prev) => ({
360+
prompt: `Fix this query error: ${errorMessage}`,
361+
key: (prev?.key ?? 0) + 1,
362+
}));
363+
}, []);
359364

360365
const isLoading = navigation.state === "submitting" || navigation.state === "loading";
361366

@@ -518,9 +523,9 @@ export default function Page() {
518523
editorRef.current?.setQuery(formatted);
519524
}}
520525
getCurrentQuery={() => editorRef.current?.getQuery() ?? ""}
521-
activeTab={helpTab}
522-
onTabChange={setHelpTab}
523-
errorFixPrompt={errorFixPrompt}
526+
activeTab={sidebarTab}
527+
onTabChange={setSidebarTab}
528+
aiFixRequest={aiFixRequest}
524529
/>
525530
</ResizablePanel>
526531
</ResizablePanelGroup>
@@ -643,14 +648,14 @@ function QueryHelpSidebar({
643648
getCurrentQuery,
644649
activeTab,
645650
onTabChange,
646-
errorFixPrompt,
651+
aiFixRequest,
647652
}: {
648653
onTryExample: (query: string, scope: QueryScope) => void;
649654
onQueryGenerated: (query: string) => void;
650655
getCurrentQuery: () => string;
651656
activeTab: string;
652657
onTabChange: (tab: string) => void;
653-
errorFixPrompt?: string;
658+
aiFixRequest: { prompt: string; key: number } | null;
654659
}) {
655660
return (
656661
<div className="grid h-full max-h-full grid-rows-[auto_1fr] overflow-hidden bg-background-bright">
@@ -682,7 +687,7 @@ function QueryHelpSidebar({
682687
<AITabContent
683688
onQueryGenerated={onQueryGenerated}
684689
getCurrentQuery={getCurrentQuery}
685-
errorFixPrompt={errorFixPrompt}
690+
aiFixRequest={aiFixRequest}
686691
/>
687692
</ClientTabsContent>
688693
<ClientTabsContent
@@ -711,16 +716,19 @@ function QueryHelpSidebar({
711716
function AITabContent({
712717
onQueryGenerated,
713718
getCurrentQuery,
714-
errorFixPrompt,
719+
aiFixRequest,
715720
}: {
716721
onQueryGenerated: (query: string) => void;
717722
getCurrentQuery: () => string;
718-
errorFixPrompt?: string;
723+
aiFixRequest: { prompt: string; key: number } | null;
719724
}) {
720-
const [autoSubmitPrompt, setAutoSubmitPrompt] = useState<string | undefined>();
725+
const [examplePromptRequest, setExamplePromptRequest] = useState<{
726+
prompt: string;
727+
key: number;
728+
} | null>(null);
721729

722-
// Combine internal autoSubmitPrompt with external errorFixPrompt
723-
const effectiveAutoSubmitPrompt = errorFixPrompt ?? autoSubmitPrompt;
730+
// Use aiFixRequest if present, otherwise use example prompt request
731+
const activeRequest = aiFixRequest ?? examplePromptRequest;
724732

725733
const examplePrompts = [
726734
"Show me failed runs by hour for the past 7 days",
@@ -734,7 +742,8 @@ function AITabContent({
734742
<div className="space-y-2">
735743
<AIQueryInput
736744
onQueryGenerated={onQueryGenerated}
737-
autoSubmitPrompt={effectiveAutoSubmitPrompt}
745+
autoSubmitPrompt={activeRequest?.prompt}
746+
autoSubmitKey={activeRequest?.key}
738747
getCurrentQuery={getCurrentQuery}
739748
/>
740749

@@ -746,9 +755,10 @@ function AITabContent({
746755
key={example}
747756
type="button"
748757
onClick={() => {
749-
// Use a unique key to ensure re-trigger even if same prompt clicked twice
750-
setAutoSubmitPrompt(undefined);
751-
setTimeout(() => setAutoSubmitPrompt(example), 0);
758+
setExamplePromptRequest((prev) => ({
759+
prompt: example,
760+
key: (prev?.key ?? 0) + 1,
761+
}));
752762
}}
753763
className="block w-full rounded-md border border-grid-dimmed bg-charcoal-800 px-3 py-2 text-left text-sm text-text-dimmed transition-colors hover:border-grid-bright hover:bg-charcoal-750 hover:text-text-bright"
754764
>

0 commit comments

Comments
 (0)