diff --git a/backend/package-lock.json b/backend/package-lock.json index e231b48..8c4ca5a 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -1901,9 +1901,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1920,9 +1917,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1939,9 +1933,6 @@ "cpu": [ "riscv64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1958,9 +1949,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1977,9 +1965,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ diff --git a/frontend/app/dataset/[id]/page.tsx b/frontend/app/dataset/[id]/page.tsx index 697addd..c61bcbc 100644 --- a/frontend/app/dataset/[id]/page.tsx +++ b/frontend/app/dataset/[id]/page.tsx @@ -65,6 +65,16 @@ export default function DatasetPage() { const selection = useSelection(rowIds); const selectedCount = selection.selected.size; + const maxRows = dataset?.maxRowCount ?? 100; + const generatedRows = rows?.length ?? 0; + const remainingRows = Math.max(maxRows - generatedRows, 0); + const isBuilding = dataset?.status === "building"; + + const estimatedMinutesRemaining = + isBuilding && remainingRows > 0 + ? Math.max(1, Math.ceil(remainingRows / 20)) + : null; + const handlePopulate = useCallback(async () => { if (!dataset || populating || dataset.status === "building") return; // A new run is starting — discard any lingering stop-latch from the previous run. @@ -442,7 +452,19 @@ export default function DatasetPage() { | )} - {rows.length} rows + + {generatedRows} / {maxRows} rows + + + {generatedRows < maxRows && ( + <> + | + + {remainingRows} remaining + + + )} + | {dataset.columns.length} columns diff --git a/frontend/app/dataset/new/page.tsx b/frontend/app/dataset/new/page.tsx index 63b8ebf..79a7a86 100644 --- a/frontend/app/dataset/new/page.tsx +++ b/frontend/app/dataset/new/page.tsx @@ -13,7 +13,6 @@ import { type RefreshCadence, } from "@/lib/refresh-cadence"; - type ColumnType = "text" | "number" | "boolean" | "url" | "date"; interface ProposedColumn { @@ -55,7 +54,13 @@ function mapBackendColumn(col: InferredColumn, index: number): ProposedColumn { }; } -function TypeSelector({ value, onChange }: { value: ColumnType; onChange: (v: ColumnType) => void }) { +function TypeSelector({ + value, + onChange, +}: { + value: ColumnType; + onChange: (v: ColumnType) => void; +}) { return (
- +
@@ -97,14 +110,8 @@ export default function NewDatasetPage() { const { getToken } = useAppAuth(); const createDataset = useMutation(api.datasets.create); - const usage = useQuery( - api.quota.getMy, - isAuthenticated ? {} : "skip", - ); + const usage = useQuery(api.quota.getMy, isAuthenticated ? {} : "skip"); - // Page-view event: fires once when the wizard becomes visible (after - // auth resolves and the user is authenticated; we don't want to fire - // for unauth visitors who'll be redirected to /sign-in). const startFired = useRef(false); useEffect(() => { if (!startFired.current && !isLoading && isAuthenticated) { @@ -139,7 +146,7 @@ export default function NewDatasetPage() { schema.dataset_name .split("_") .map((w) => w.charAt(0).toUpperCase() + w.slice(1)) - .join(" ") + .join(" "), ); setRetrievalStrategy(schema.retrieval_strategy); setSourceHint(schema.source_hint); @@ -153,9 +160,13 @@ export default function NewDatasetPage() { } } - function handleUpdateColumn(id: string, field: "name" | "type" | "description", value: string) { + function handleUpdateColumn( + id: string, + field: "name" | "type" | "description", + value: string, + ) { setColumns((prev) => - prev.map((c) => (c.id === id ? { ...c, [field]: value } : c)) + prev.map((c) => (c.id === id ? { ...c, [field]: value } : c)), ); } @@ -166,26 +177,38 @@ export default function NewDatasetPage() { function handleAddColumn() { setColumns((prev) => [ ...prev, - { id: String(Date.now()), name: "New Column", type: "text", description: "", isPrimaryKey: false }, + { + id: String(Date.now()), + name: "New Column", + type: "text", + description: "", + isPrimaryKey: false, + }, ]); } async function handleConfirm() { if (isCreating) return; + const maxRowCount = Number(maxRowCountInput); + if (!Number.isInteger(maxRowCount) || maxRowCount < 1) { setError("Max rows must be a whole number greater than 0."); return; } + if (usage && maxRowCount > usage.remaining) { setError( `Max rows cannot exceed your remaining monthly quota of ${usage.remaining.toLocaleString()} row operations.`, ); return; } + setIsCreating(true); setError(null); + let datasetId: string; + try { datasetId = await createDataset({ name: datasetName, @@ -202,7 +225,9 @@ export default function NewDatasetPage() { sourceHint: sourceHint || undefined, }); } catch (err) { - const message = err instanceof Error ? err.message : "Failed to create dataset"; + const message = + err instanceof Error ? err.message : "Failed to create dataset"; + setError( message.includes("quota exceeded") ? "You've used all of this month's free-tier quota. New datasets will be available again at the start of next month." @@ -211,6 +236,7 @@ export default function NewDatasetPage() { setIsCreating(false); return; } + try { track(EVENTS.DATASET_CREATED, { datasetId, @@ -219,6 +245,7 @@ export default function NewDatasetPage() { maxRowCount, }); } catch {} + router.push(`/dataset/${datasetId}`); } @@ -227,8 +254,16 @@ export default function NewDatasetPage() {
- BigSet - BigSet + BigSet + BigSet /

New Dataset

@@ -244,12 +279,15 @@ export default function NewDatasetPage() { Create a new dataset

- Describe what data you want to collect. Our agents will figure out the schema; you can start populating it from the dataset page. + Describe what data you want to collect. Our agents will figure out + the schema; you can start populating it from the dataset page.

- +