Skip to content

Commit 5f7fcb1

Browse files
committed
Save the query date range
1 parent 9c1ee99 commit 5f7fcb1

File tree

5 files changed

+72
-26
lines changed

5 files changed

+72
-26
lines changed

apps/webapp/app/presenters/v3/QueryPresenter.server.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ export type QueryHistoryItem = {
88
scope: QueryScope;
99
createdAt: Date;
1010
userName: string | null;
11+
/** Time filter settings */
12+
filterPeriod: string | null;
13+
filterFrom: Date | null;
14+
filterTo: Date | null;
1115
};
1216

1317
export class QueryPresenter extends BasePresenter {
@@ -21,6 +25,9 @@ export class QueryPresenter extends BasePresenter {
2125
query: true,
2226
scope: true,
2327
createdAt: true,
28+
filterPeriod: true,
29+
filterFrom: true,
30+
filterTo: true,
2431
user: {
2532
select: { name: true, displayName: true },
2633
},
@@ -36,6 +43,9 @@ export class QueryPresenter extends BasePresenter {
3643
scope: q.scope.toLowerCase() as QueryScope,
3744
createdAt: q.createdAt,
3845
userName: q.user?.displayName ?? q.user?.name ?? null,
46+
filterPeriod: q.filterPeriod,
47+
filterFrom: q.filterFrom,
48+
filterTo: q.filterTo,
3949
})
4050
),
4151
};

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

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { useState } from "react";
22
import { ClockRotateLeftIcon } from "~/assets/icons/ClockRotateLeftIcon";
33
import { Button } from "~/components/primitives/Buttons";
4-
import { DateTime } from "~/components/primitives/DateTime";
54
import { Popover, PopoverContent, PopoverTrigger } from "~/components/primitives/Popover";
65
import type { QueryHistoryItem } from "~/presenters/v3/QueryPresenter.server";
6+
import { formatDateTimeRange, formatTimePeriod } from "./utils";
7+
import { timeFilterRenderValues } from "~/components/runs/v3/SharedFilters";
78

89
const SQL_KEYWORDS = [
910
"SELECT",
@@ -104,28 +105,33 @@ export function QueryHistoryPopover({
104105
>
105106
<div className="max-h-80 overflow-y-auto scrollbar-thin scrollbar-track-transparent scrollbar-thumb-charcoal-600">
106107
<div className="p-1">
107-
{history.map((item) => (
108-
<button
109-
key={item.id}
110-
type="button"
111-
onClick={() => {
112-
onQuerySelected(item);
113-
setIsOpen(false);
114-
}}
115-
className="flex w-full items-center gap-2 rounded-sm px-2 py-2 outline-none transition-colors focus-custom hover:bg-charcoal-900"
116-
>
117-
<div className="flex flex-1 flex-col items-start overflow-hidden">
118-
<p className="line-clamp-2 w-full break-words text-left font-mono text-xs text-[#9b99ff]">
119-
{highlightSQL(item.query)}
120-
</p>
121-
<div className="flex items-center gap-2 text-xs text-text-dimmed">
122-
<DateTime date={item.createdAt} showTooltip={false} />
123-
{item.userName && <span>· {item.userName}</span>}
124-
<span className="capitalize">· {item.scope}</span>
108+
{history.map((item) => {
109+
// Format time filter display
110+
const { valueLabel } = timeFilterRenderValues({ period: item.filterPeriod ?? undefined, from: item.filterFrom ?? undefined, to: item.filterTo ?? undefined });
111+
112+
return (
113+
<button
114+
key={item.id}
115+
type="button"
116+
onClick={() => {
117+
onQuerySelected(item);
118+
setIsOpen(false);
119+
}}
120+
className="flex w-full items-center gap-2 rounded-sm px-2 py-2 outline-none transition-colors focus-custom hover:bg-charcoal-900"
121+
>
122+
<div className="flex flex-1 flex-col items-start overflow-hidden">
123+
<p className="line-clamp-2 w-full break-words text-left font-mono text-xs text-[#9b99ff]">
124+
{highlightSQL(item.query)}
125+
</p>
126+
<div className="flex items-center gap-1.5 text-xs text-text-dimmed">
127+
<span className="capitalize">{item.scope}</span>
128+
{valueLabel && <span>· {valueLabel}</span>}
129+
{item.userName && <span>· {item.userName}</span>}
130+
</div>
125131
</div>
126-
</div>
127-
</button>
128-
))}
132+
</button>
133+
);
134+
})}
129135
</div>
130136
</div>
131137
</PopoverContent>

apps/webapp/app/services/queryService.server.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,15 @@ export type ExecuteQueryOptions<TOut extends z.ZodSchema> = Omit<
7575
userId?: string | null;
7676
/** Skip saving to history (e.g., when impersonating) */
7777
skip?: boolean;
78+
/** Time filter settings to save with the query */
79+
timeFilter?: {
80+
/** Period like "7d", "24h", etc. */
81+
period?: string;
82+
/** Custom start date */
83+
from?: Date;
84+
/** Custom end date */
85+
to?: Date;
86+
};
7887
};
7988
/** Custom per-org concurrency limit (overrides default) */
8089
customOrgConcurrencyLimit?: number;
@@ -174,11 +183,17 @@ export async function executeQuery<TOut extends z.ZodSchema>(
174183
userId: history.userId ?? null,
175184
},
176185
orderBy: { createdAt: "desc" },
177-
select: { query: true, scope: true },
186+
select: { query: true, scope: true, filterPeriod: true, filterFrom: true, filterTo: true },
178187
});
179188

189+
const timeFilter = history.timeFilter;
180190
const isDuplicate =
181-
lastQuery && lastQuery.query === options.query && lastQuery.scope === scopeToEnum[scope];
191+
lastQuery &&
192+
lastQuery.query === options.query &&
193+
lastQuery.scope === scopeToEnum[scope] &&
194+
lastQuery.filterPeriod === (timeFilter?.period ?? null) &&
195+
lastQuery.filterFrom?.getTime() === (timeFilter?.from?.getTime() ?? undefined) &&
196+
lastQuery.filterTo?.getTime() === (timeFilter?.to?.getTime() ?? undefined);
182197

183198
if (!isDuplicate) {
184199
const stats = result[1].stats;
@@ -196,6 +211,9 @@ export async function executeQuery<TOut extends z.ZodSchema>(
196211
projectId: scope === "project" || scope === "environment" ? projectId : null,
197212
environmentId: scope === "environment" ? environmentId : null,
198213
userId: history.userId ?? null,
214+
filterPeriod: history.timeFilter?.period ?? null,
215+
filterFrom: history.timeFilter?.from ?? null,
216+
filterTo: history.timeFilter?.to ?? null,
199217
},
200218
});
201219
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
-- AlterTable
2+
ALTER TABLE "public"."CustomerQuery"
3+
ADD COLUMN "filterFrom" TIMESTAMP(3),
4+
ADD COLUMN "filterPeriod" TEXT,
5+
ADD COLUMN "filterTo" TIMESTAMP(3);

internal-packages/database/prisma/schema.prisma

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ model User {
6262
6363
impersonationsPerformed ImpersonationAuditLog[] @relation("ImpersonationAdmin")
6464
impersonationsReceived ImpersonationAuditLog[] @relation("ImpersonationTarget")
65-
customerQueries CustomerQuery[]
65+
customerQueries CustomerQuery[]
6666
}
6767

6868
model MfaBackupCode {
@@ -2425,7 +2425,6 @@ model ImpersonationAuditLog {
24252425
@@index([adminId])
24262426
@@index([targetId])
24272427
@@index([createdAt])
2428-
24292428
}
24302429

24312430
enum CustomerQuerySource {
@@ -2470,6 +2469,14 @@ model CustomerQuery {
24702469
user User? @relation(fields: [userId], references: [id], onDelete: SetNull, onUpdate: Cascade)
24712470
userId String?
24722471
2472+
/// Time filter settings used when the query was executed
2473+
/// Period like "7d", "24h", etc.
2474+
filterPeriod String?
2475+
/// Custom start date (ISO 8601)
2476+
filterFrom DateTime?
2477+
/// Custom end date (ISO 8601)
2478+
filterTo DateTime?
2479+
24732480
createdAt DateTime @default(now())
24742481
24752482
/// Fast lookup for history menu (most recent 20 per org)

0 commit comments

Comments
 (0)