@agent-native/core 0.120.1 → 0.120.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +9 -0
- package/corpus/core/docs/content/extensions.mdx +23 -4
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/production-agent.ts +4 -0
- package/corpus/core/src/agent/run-manager.ts +36 -10
- package/corpus/core/src/agent/types.ts +2 -0
- package/corpus/core/src/client/extensions/ExtensionsListPage.tsx +16 -3
- package/corpus/core/src/client/settings/ExtensionsSettingsContent.tsx +24 -0
- package/corpus/core/src/client/settings/SettingsPanel.tsx +10 -0
- package/corpus/core/src/deploy/build.ts +3 -0
- package/corpus/core/src/server/analytics.ts +154 -25
- package/corpus/core/src/templates/chat/app/components/layout/Sidebar.tsx +35 -6
- package/corpus/core/src/templates/chat/app/routes/extensions._index.tsx +2 -2
- package/corpus/core/src/templates/chat/netlify.toml +1 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +16 -0
- package/corpus/core/src/vite/client.ts +6 -0
- package/corpus/templates/analytics/.agents/skills/adhoc-analysis/SKILL.md +27 -43
- package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +19 -8
- package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +2 -2
- package/corpus/templates/analytics/AGENTS.md +20 -8
- package/corpus/templates/analytics/actions/get-explorer-dashboard.ts +3 -0
- package/corpus/templates/analytics/actions/list-dashboard-usage-stats.ts +140 -46
- package/corpus/templates/analytics/actions/migrate-analytics-artifacts.ts +48 -0
- package/corpus/templates/analytics/actions/save-analysis.ts +2 -3
- package/corpus/templates/analytics/actions/view-screen.ts +1 -1
- package/corpus/templates/analytics/app/components/dashboard/DashboardMetadata.tsx +77 -0
- package/corpus/templates/analytics/app/components/dashboard/DashboardPanelSkeleton.tsx +7 -1
- package/corpus/templates/analytics/app/components/layout/NewDashboardDialog.tsx +1 -0
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +103 -502
- package/corpus/templates/analytics/app/global.css +30 -0
- package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +2 -2
- package/corpus/templates/analytics/app/i18n-data.ts +80 -0
- package/corpus/templates/analytics/app/pages/Agents.tsx +49 -2
- package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +54 -11
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +3 -53
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +23 -25
- package/corpus/templates/analytics/app/pages/analyses/AnalysisDetail.tsx +2 -2
- package/corpus/templates/analytics/app/routes/analyses._index.tsx +3 -2
- package/corpus/templates/analytics/app/routes/extensions._index.tsx +2 -2
- package/corpus/templates/analytics/changelog/2026-07-23-analytics-now-groups-saved-analyses-and-embedded-extensions-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-23-dashboard-menus-show-who-created-and-last-updated-each-dashb.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-23-dashboard-usage-now-loads-reliably-for-organizations-with-ma.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-23-long-dashboard-building-requests-now-continue-without-stoppi.md +6 -0
- package/corpus/templates/analytics/netlify.toml +4 -0
- package/corpus/templates/analytics/server/db/schema.ts +4 -0
- package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +0 -1
- package/corpus/templates/analytics/server/lib/agent-readable-resource-context.ts +1 -0
- package/corpus/templates/analytics/server/lib/migrate-analytics-artifacts.ts +1062 -0
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +6 -52
- package/corpus/templates/analytics/server/plugins/core-routes.ts +1 -1
- package/corpus/templates/analytics/server/plugins/db.ts +10 -0
- package/corpus/templates/assets/actions/generate-image-batch.ts +36 -1
- package/corpus/templates/assets/actions/generate-image.ts +28 -1
- package/corpus/templates/assets/app/components/layout/Sidebar.tsx +46 -8
- package/corpus/templates/assets/app/routes/extensions._index.tsx +2 -2
- package/corpus/templates/assets/changelog/2026-07-23-assets-image-generation-now-recovers-after-a-completed-tool-.md +6 -0
- package/corpus/templates/assets/netlify.toml +1 -0
- package/corpus/templates/brain/app/components/layout/Sidebar.tsx +38 -8
- package/corpus/templates/brain/app/routes/extensions._index.tsx +2 -2
- package/corpus/templates/brain/netlify.toml +1 -0
- package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +43 -5
- package/corpus/templates/calendar/app/routes/_app.extensions._index.tsx +2 -16
- package/corpus/templates/calendar/netlify.toml +1 -0
- package/corpus/templates/chat/app/components/layout/Sidebar.tsx +35 -6
- package/corpus/templates/chat/app/routes/extensions._index.tsx +2 -2
- package/corpus/templates/chat/netlify.toml +1 -0
- package/corpus/templates/clips/app/components/library/library-layout.tsx +52 -6
- package/corpus/templates/clips/app/routes/_app.extensions._index.tsx +2 -16
- package/corpus/templates/clips/changelog/2026-07-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-23-meeting-recording-meters-and-dismissed-prompts.md +6 -0
- package/corpus/templates/clips/desktop/src/hooks/useMicMeter.ts +1 -1
- package/corpus/templates/clips/desktop/src/lib/meeting-notification-dismissal.ts +2 -0
- package/corpus/templates/clips/desktop/src/lib/voice-dictation.ts +1 -3
- package/corpus/templates/clips/desktop/src/overlays/live-audio-bars.tsx +86 -0
- package/corpus/templates/clips/desktop/src/overlays/meeting-notification.tsx +24 -0
- package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +5 -69
- package/corpus/templates/clips/desktop/src/styles.css +35 -3
- package/corpus/templates/clips/desktop/src-tauri/src/adhoc_meetings_watcher.rs +13 -44
- package/corpus/templates/clips/desktop/src-tauri/src/notifications.rs +119 -17
- package/corpus/templates/clips/netlify.toml +1 -0
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +3 -7
- package/corpus/templates/content/app/routes/_app.extensions._index.tsx +2 -2
- package/corpus/templates/content/changelog/2026-07-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.md +6 -0
- package/corpus/templates/content/netlify.toml +1 -0
- package/corpus/templates/design/app/components/layout/Sidebar.tsx +55 -17
- package/corpus/templates/design/app/routes/extensions._index.tsx +2 -2
- package/corpus/templates/design/changelog/2026-07-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.md +6 -0
- package/corpus/templates/design/netlify.toml +1 -0
- package/corpus/templates/dispatch/app/dispatch-extensions.tsx +1 -1
- package/corpus/templates/dispatch/changelog/2026-07-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.md +6 -0
- package/corpus/templates/dispatch/netlify.toml +1 -0
- package/corpus/templates/forms/app/components/layout/Sidebar.tsx +41 -45
- package/corpus/templates/forms/app/routes/_app.extensions._index.tsx +2 -2
- package/corpus/templates/forms/changelog/2026-07-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.md +6 -0
- package/corpus/templates/forms/netlify.toml +1 -0
- package/corpus/templates/macros/app/components/layout/AppLayout.tsx +36 -5
- package/corpus/templates/macros/app/routes/extensions._index.tsx +2 -2
- package/corpus/templates/macros/netlify.toml +1 -0
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +0 -9
- package/corpus/templates/mail/app/routes/extensions._index.tsx +2 -2
- package/corpus/templates/mail/netlify.toml +1 -0
- package/corpus/templates/plan/app/components/layout/Sidebar.tsx +38 -5
- package/corpus/templates/plan/app/routes/extensions._index.tsx +2 -2
- package/corpus/templates/plan/netlify.toml +1 -0
- package/corpus/templates/slides/app/components/layout/Sidebar.tsx +47 -4
- package/corpus/templates/slides/app/routes/extensions._index.tsx +2 -2
- package/corpus/templates/slides/netlify.toml +1 -0
- package/corpus/templates/tasks/app/components/layout/Sidebar.tsx +37 -6
- package/corpus/templates/tasks/app/routes/extensions._index.tsx +2 -2
- package/corpus/templates/tasks/app/routes/settings.tsx +31 -0
- package/corpus/templates/tasks/netlify.toml +1 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +4 -0
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-manager.d.ts +9 -0
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +25 -10
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/types.d.ts +2 -2
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/client/extensions/ExtensionsListPage.d.ts +5 -1
- package/dist/client/extensions/ExtensionsListPage.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionsListPage.js +5 -3
- package/dist/client/extensions/ExtensionsListPage.js.map +1 -1
- package/dist/client/settings/ExtensionsSettingsContent.d.ts +2 -0
- package/dist/client/settings/ExtensionsSettingsContent.d.ts.map +1 -0
- package/dist/client/settings/ExtensionsSettingsContent.js +10 -0
- package/dist/client/settings/ExtensionsSettingsContent.js.map +1 -0
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +10 -1
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/deploy/build.js +1 -0
- package/dist/deploy/build.js.map +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +7 -7
- package/dist/provider-api/actions/provider-api.d.ts +11 -11
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/server/analytics.d.ts +9 -4
- package/dist/server/analytics.d.ts.map +1 -1
- package/dist/server/analytics.js +111 -22
- package/dist/server/analytics.js.map +1 -1
- package/dist/templates/chat/app/components/layout/Sidebar.tsx +35 -6
- package/dist/templates/chat/app/routes/extensions._index.tsx +2 -2
- package/dist/templates/chat/netlify.toml +1 -0
- package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +16 -0
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +2 -0
- package/dist/vite/client.js.map +1 -1
- package/docs/content/extensions.mdx +23 -4
- package/package.json +1 -1
- package/src/agent/production-agent.ts +4 -0
- package/src/agent/run-manager.ts +36 -10
- package/src/agent/types.ts +2 -0
- package/src/client/extensions/ExtensionsListPage.tsx +16 -3
- package/src/client/settings/ExtensionsSettingsContent.tsx +24 -0
- package/src/client/settings/SettingsPanel.tsx +10 -0
- package/src/deploy/build.ts +3 -0
- package/src/server/analytics.ts +154 -25
- package/src/templates/chat/app/components/layout/Sidebar.tsx +35 -6
- package/src/templates/chat/app/routes/extensions._index.tsx +2 -2
- package/src/templates/chat/netlify.toml +1 -0
- package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +16 -0
- package/src/vite/client.ts +6 -0
- package/corpus/templates/analytics/app/components/layout/NewAnalysisDialog.tsx +0 -165
- package/corpus/templates/analytics/app/pages/analyses/AnalysesList.tsx +0 -175
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
import { useSendToAgentChat } from "@agent-native/core/client/agent-chat";
|
|
2
|
-
import { PromptComposer } from "@agent-native/core/client/composer";
|
|
3
|
-
import { useActionQuery } from "@agent-native/core/client/hooks";
|
|
4
|
-
import { useT } from "@agent-native/core/client/i18n";
|
|
5
|
-
import {
|
|
6
|
-
IconAlertCircle,
|
|
7
|
-
IconCheck,
|
|
8
|
-
IconDatabase,
|
|
9
|
-
IconLoader2,
|
|
10
|
-
IconPlus,
|
|
11
|
-
} from "@tabler/icons-react";
|
|
12
|
-
import { useMemo, useState } from "react";
|
|
13
|
-
import { Link } from "react-router";
|
|
14
|
-
|
|
15
|
-
import { Badge } from "@/components/ui/badge";
|
|
16
|
-
import {
|
|
17
|
-
Popover,
|
|
18
|
-
PopoverContent,
|
|
19
|
-
PopoverTrigger,
|
|
20
|
-
} from "@/components/ui/popover";
|
|
21
|
-
import {
|
|
22
|
-
credentialRowsFromStatus,
|
|
23
|
-
getConfiguredDataSources,
|
|
24
|
-
type DataSourceStatusResponse,
|
|
25
|
-
} from "@/lib/data-source-status";
|
|
26
|
-
import { cn } from "@/lib/utils";
|
|
27
|
-
|
|
28
|
-
const ANALYSIS_CONTEXT =
|
|
29
|
-
"The user wants to kick off a new ad-hoc analysis. " +
|
|
30
|
-
"REAL_DATA_REQUIRED: before saving or answering, run at least one real data-source query action; `data-source-status`, `list-data-dictionary`, `generate-chart`, and `save-analysis` do not count as data queries. " +
|
|
31
|
-
"The built-in `demo` dashboard source is a demo-environment Prometheus source and never satisfies REAL_DATA_REQUIRED for user analytics answers or saved analyses unless the user explicitly asks to analyze the demo dashboard itself. " +
|
|
32
|
-
"If no source can answer, report the exact unavailable/error result instead of saving a guessed analysis. " +
|
|
33
|
-
"Read the `adhoc-analysis` skill first. Then: gather data from relevant sources, " +
|
|
34
|
-
"synthesize findings, and save via `save-analysis` with --id, --name, --question, " +
|
|
35
|
-
"--description, --instructions (markdown recipe for re-running), --resultMarkdown (polished writeup), " +
|
|
36
|
-
"--dataSources (JSON array of data sources used), and --resultData (structured raw query results and metrics from the successful data-source actions). " +
|
|
37
|
-
"After saving, call `navigate --view=analyses --analysisId=<id>` so the user sees it. " +
|
|
38
|
-
"No code files to create — analyses are persisted settings data.";
|
|
39
|
-
|
|
40
|
-
function buildAnalysisContext(configuredSourceNames: string[]): string {
|
|
41
|
-
const sourceContext = configuredSourceNames.length
|
|
42
|
-
? `Call \`data-source-status\` first to verify source availability. Current credential status shows these configured data sources: ${configuredSourceNames.join(", ")}. Prefer those sources unless the user names a different provider. The data dictionary can describe metrics, but it is not a live data source by itself. The demo source is not evidence for user analytics.`
|
|
43
|
-
: "Current credential status shows no configured data sources. Check `data-source-status` before analysis. If the requested provider is unavailable or missing credentials, report the exact connection problem and direct the user to Data Sources instead of saving guessed results. The data dictionary can describe metrics, but it is not a live data source by itself. The demo source is not evidence for user analytics.";
|
|
44
|
-
return `${ANALYSIS_CONTEXT} ${sourceContext}`;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function NewAnalysisDialog() {
|
|
48
|
-
const t = useT();
|
|
49
|
-
const [open, setOpen] = useState(false);
|
|
50
|
-
const { send, isGenerating } = useSendToAgentChat();
|
|
51
|
-
const { data: statusData, isLoading: isStatusLoading } = useActionQuery(
|
|
52
|
-
"data-source-status",
|
|
53
|
-
undefined,
|
|
54
|
-
{
|
|
55
|
-
staleTime: 10_000,
|
|
56
|
-
},
|
|
57
|
-
);
|
|
58
|
-
const status = statusData as DataSourceStatusResponse | undefined;
|
|
59
|
-
const envStatus = credentialRowsFromStatus(status);
|
|
60
|
-
const configuredSources = useMemo(
|
|
61
|
-
() => getConfiguredDataSources(envStatus, status),
|
|
62
|
-
[envStatus, status],
|
|
63
|
-
);
|
|
64
|
-
const configuredSourceNames = configuredSources.map((source) => source.name);
|
|
65
|
-
const statusMessage = status?.message || status?.error;
|
|
66
|
-
|
|
67
|
-
function handleSubmit(text: string) {
|
|
68
|
-
const trimmed = text.trim();
|
|
69
|
-
if (!trimmed || isGenerating) return;
|
|
70
|
-
send({
|
|
71
|
-
message: trimmed,
|
|
72
|
-
context: buildAnalysisContext(configuredSourceNames),
|
|
73
|
-
submit: true,
|
|
74
|
-
});
|
|
75
|
-
setOpen(false);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return (
|
|
79
|
-
<Popover open={open} onOpenChange={setOpen}>
|
|
80
|
-
<PopoverTrigger asChild>
|
|
81
|
-
<button className="flex w-full cursor-pointer items-center gap-2 rounded-lg px-3 py-1.5 text-xs text-muted-foreground/60 hover:bg-sidebar-accent/50 hover:text-primary">
|
|
82
|
-
<IconPlus className="h-3 w-3" />
|
|
83
|
-
{t("dialogs.newAnalysis")}
|
|
84
|
-
</button>
|
|
85
|
-
</PopoverTrigger>
|
|
86
|
-
<PopoverContent
|
|
87
|
-
className="w-[calc(100vw-2rem)] p-3 sm:w-[420px]"
|
|
88
|
-
side="right"
|
|
89
|
-
align="start"
|
|
90
|
-
>
|
|
91
|
-
<p className="px-1 pb-2 text-sm font-semibold text-foreground">
|
|
92
|
-
{t("dialogs.newAnalysisTitle")}
|
|
93
|
-
</p>
|
|
94
|
-
<div
|
|
95
|
-
className={cn(
|
|
96
|
-
"mb-3 rounded-md border px-3 py-2 text-xs",
|
|
97
|
-
configuredSources.length > 0
|
|
98
|
-
? "border-emerald-500/25 bg-emerald-500/10"
|
|
99
|
-
: "border-amber-500/25 bg-amber-500/10",
|
|
100
|
-
)}
|
|
101
|
-
>
|
|
102
|
-
<div className="flex gap-2">
|
|
103
|
-
{isStatusLoading ? (
|
|
104
|
-
<IconLoader2 className="mt-0.5 h-3.5 w-3.5 shrink-0 animate-spin text-muted-foreground" />
|
|
105
|
-
) : configuredSources.length > 0 ? (
|
|
106
|
-
<IconCheck className="mt-0.5 h-3.5 w-3.5 shrink-0 text-emerald-500" />
|
|
107
|
-
) : (
|
|
108
|
-
<IconAlertCircle className="mt-0.5 h-3.5 w-3.5 shrink-0 text-amber-500" />
|
|
109
|
-
)}
|
|
110
|
-
<div className="min-w-0 flex-1">
|
|
111
|
-
<div className="flex items-center gap-1.5 font-medium text-foreground">
|
|
112
|
-
<IconDatabase className="h-3.5 w-3.5 text-muted-foreground" />
|
|
113
|
-
{isStatusLoading
|
|
114
|
-
? t("dialogs.checkingDataSources")
|
|
115
|
-
: configuredSources.length > 0
|
|
116
|
-
? t("dialogs.sourcesConfigured", {
|
|
117
|
-
count: configuredSources.length,
|
|
118
|
-
plural: configuredSources.length === 1 ? "" : "s",
|
|
119
|
-
})
|
|
120
|
-
: t("dialogs.noDataSourcesConfigured")}
|
|
121
|
-
</div>
|
|
122
|
-
{configuredSources.length > 0 ? (
|
|
123
|
-
<div className="mt-2 flex flex-wrap gap-1">
|
|
124
|
-
{configuredSources.slice(0, 4).map((source) => (
|
|
125
|
-
<Badge
|
|
126
|
-
key={source.id}
|
|
127
|
-
variant="secondary"
|
|
128
|
-
className="px-1.5 py-0 text-[10px]"
|
|
129
|
-
>
|
|
130
|
-
{source.name}
|
|
131
|
-
</Badge>
|
|
132
|
-
))}
|
|
133
|
-
{configuredSources.length > 4 && (
|
|
134
|
-
<Badge
|
|
135
|
-
variant="outline"
|
|
136
|
-
className="px-1.5 py-0 text-[10px]"
|
|
137
|
-
>
|
|
138
|
-
{t("dialogs.more", {
|
|
139
|
-
count: configuredSources.length - 4,
|
|
140
|
-
})}
|
|
141
|
-
</Badge>
|
|
142
|
-
)}
|
|
143
|
-
</div>
|
|
144
|
-
) : (
|
|
145
|
-
<p className="mt-1 text-muted-foreground">
|
|
146
|
-
{statusMessage || t("dialogs.connectSourceFirst")}{" "}
|
|
147
|
-
<Link to="/data-sources" className="text-primary underline">
|
|
148
|
-
{t("dialogs.manageSources")}
|
|
149
|
-
</Link>
|
|
150
|
-
</p>
|
|
151
|
-
)}
|
|
152
|
-
</div>
|
|
153
|
-
</div>
|
|
154
|
-
</div>
|
|
155
|
-
<PromptComposer
|
|
156
|
-
autoFocus
|
|
157
|
-
disabled={isGenerating}
|
|
158
|
-
placeholder={t("dialogs.newAnalysisPlaceholder")}
|
|
159
|
-
draftScope="analytics:new-analysis"
|
|
160
|
-
onSubmit={handleSubmit}
|
|
161
|
-
/>
|
|
162
|
-
</PopoverContent>
|
|
163
|
-
</Popover>
|
|
164
|
-
);
|
|
165
|
-
}
|
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
import { useSendToAgentChat } from "@agent-native/core/client/agent-chat";
|
|
2
|
-
import { callAction, useChangeVersions } from "@agent-native/core/client/hooks";
|
|
3
|
-
import { useT } from "@agent-native/core/client/i18n";
|
|
4
|
-
import { IconFlask, IconClock, IconSearch } from "@tabler/icons-react";
|
|
5
|
-
import { useQuery } from "@tanstack/react-query";
|
|
6
|
-
import { useState } from "react";
|
|
7
|
-
import { Link } from "react-router";
|
|
8
|
-
|
|
9
|
-
import { Badge } from "@/components/ui/badge";
|
|
10
|
-
import {
|
|
11
|
-
Card,
|
|
12
|
-
CardContent,
|
|
13
|
-
CardDescription,
|
|
14
|
-
CardHeader,
|
|
15
|
-
CardTitle,
|
|
16
|
-
} from "@/components/ui/card";
|
|
17
|
-
import { Skeleton } from "@/components/ui/skeleton";
|
|
18
|
-
|
|
19
|
-
interface AnalysisSummary {
|
|
20
|
-
id: string;
|
|
21
|
-
name: string;
|
|
22
|
-
description: string;
|
|
23
|
-
dataSources: string[];
|
|
24
|
-
createdAt: string;
|
|
25
|
-
updatedAt: string;
|
|
26
|
-
author: string;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async function fetchAnalyses(): Promise<AnalysisSummary[]> {
|
|
30
|
-
const rows = await callAction("list-analyses", {}, { method: "GET" });
|
|
31
|
-
return (Array.isArray(rows) ? rows : []) as AnalysisSummary[];
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function formatRelativeDate(iso: string): string {
|
|
35
|
-
const date = new Date(iso);
|
|
36
|
-
const now = new Date();
|
|
37
|
-
const diffMs = now.getTime() - date.getTime();
|
|
38
|
-
const diffMins = Math.floor(diffMs / 60000);
|
|
39
|
-
const diffHours = Math.floor(diffMins / 60);
|
|
40
|
-
const diffDays = Math.floor(diffHours / 24);
|
|
41
|
-
|
|
42
|
-
if (diffMins < 1) return "just now";
|
|
43
|
-
if (diffMins < 60) return `${diffMins}m ago`;
|
|
44
|
-
if (diffHours < 24) return `${diffHours}h ago`;
|
|
45
|
-
if (diffDays < 7) return `${diffDays}d ago`;
|
|
46
|
-
return date.toLocaleDateString();
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export default function AnalysesList() {
|
|
50
|
-
const t = useT();
|
|
51
|
-
const analysesSync = useChangeVersions(["analyses", "action"]);
|
|
52
|
-
const { data: analyses, isLoading } = useQuery({
|
|
53
|
-
queryKey: ["analyses-list", analysesSync],
|
|
54
|
-
queryFn: fetchAnalyses,
|
|
55
|
-
staleTime: 10_000,
|
|
56
|
-
placeholderData: (prev) => prev,
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
const { send, codeRequiredDialog } = useSendToAgentChat();
|
|
60
|
-
const [searchQuery, setSearchQuery] = useState("");
|
|
61
|
-
|
|
62
|
-
const filteredAnalyses = analyses?.filter((a) => {
|
|
63
|
-
if (!searchQuery.trim()) return true;
|
|
64
|
-
const q = searchQuery.toLowerCase();
|
|
65
|
-
return (
|
|
66
|
-
a.name.toLowerCase().includes(q) ||
|
|
67
|
-
(a.description && a.description.toLowerCase().includes(q))
|
|
68
|
-
);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
return (
|
|
72
|
-
<>
|
|
73
|
-
{codeRequiredDialog}
|
|
74
|
-
<div className="space-y-6">
|
|
75
|
-
<div className="flex items-center gap-3">
|
|
76
|
-
<p className="text-sm text-muted-foreground flex-1">
|
|
77
|
-
{t("analyses.description")}
|
|
78
|
-
</p>
|
|
79
|
-
{analyses && analyses.length > 0 && (
|
|
80
|
-
<div className="relative">
|
|
81
|
-
<IconSearch className="absolute start-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground/60 pointer-events-none" />
|
|
82
|
-
<input
|
|
83
|
-
type="search"
|
|
84
|
-
placeholder={t("analyses.searchPlaceholder")}
|
|
85
|
-
value={searchQuery}
|
|
86
|
-
onChange={(e) => setSearchQuery(e.target.value)}
|
|
87
|
-
className="h-8 rounded-md border border-input bg-background ps-8 pe-3 text-xs placeholder:text-muted-foreground/60 focus:outline-none focus:ring-2 focus:ring-ring"
|
|
88
|
-
/>
|
|
89
|
-
</div>
|
|
90
|
-
)}
|
|
91
|
-
</div>
|
|
92
|
-
|
|
93
|
-
{isLoading ? (
|
|
94
|
-
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
95
|
-
{Array.from({ length: 3 }).map((_, i) => (
|
|
96
|
-
<Skeleton key={i} className="h-40 w-full rounded-xl" />
|
|
97
|
-
))}
|
|
98
|
-
</div>
|
|
99
|
-
) : !analyses?.length || filteredAnalyses?.length === 0 ? (
|
|
100
|
-
<Card className="border-dashed">
|
|
101
|
-
<CardContent className="flex flex-col items-center justify-center py-16 text-center">
|
|
102
|
-
<div className="flex h-14 w-14 items-center justify-center rounded-2xl bg-primary/10 mb-4">
|
|
103
|
-
<IconFlask className="h-7 w-7 text-primary" />
|
|
104
|
-
</div>
|
|
105
|
-
<h3 className="text-lg font-semibold mb-2">
|
|
106
|
-
{searchQuery
|
|
107
|
-
? t("analyses.noResults")
|
|
108
|
-
: t("analyses.noAnalysesYet")}
|
|
109
|
-
</h3>
|
|
110
|
-
<p className="text-sm text-muted-foreground max-w-sm mb-4">
|
|
111
|
-
{searchQuery
|
|
112
|
-
? t("analyses.noResultsForQuery", { query: searchQuery })
|
|
113
|
-
: t("analyses.emptyDescription")}
|
|
114
|
-
</p>
|
|
115
|
-
{!searchQuery && (
|
|
116
|
-
<button
|
|
117
|
-
onClick={() =>
|
|
118
|
-
send({
|
|
119
|
-
message: t("analyses.examplePrompt"),
|
|
120
|
-
submit: false,
|
|
121
|
-
})
|
|
122
|
-
}
|
|
123
|
-
className="text-sm text-primary hover:underline"
|
|
124
|
-
>
|
|
125
|
-
{t("analyses.tryExamplePrompt")}
|
|
126
|
-
</button>
|
|
127
|
-
)}
|
|
128
|
-
</CardContent>
|
|
129
|
-
</Card>
|
|
130
|
-
) : (
|
|
131
|
-
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
132
|
-
{(filteredAnalyses ?? analyses ?? []).map((a) => (
|
|
133
|
-
<Link key={a.id} to={`/analyses/${a.id}`} className="block">
|
|
134
|
-
<Card className="h-full hover:border-primary/40 transition-colors cursor-pointer">
|
|
135
|
-
<CardHeader className="pb-3">
|
|
136
|
-
<CardTitle className="text-base leading-snug">
|
|
137
|
-
{a.name}
|
|
138
|
-
</CardTitle>
|
|
139
|
-
{a.description && (
|
|
140
|
-
<CardDescription className="line-clamp-2 text-xs">
|
|
141
|
-
{a.description}
|
|
142
|
-
</CardDescription>
|
|
143
|
-
)}
|
|
144
|
-
</CardHeader>
|
|
145
|
-
<CardContent className="pt-0">
|
|
146
|
-
<div className="flex flex-wrap gap-1.5 mb-3">
|
|
147
|
-
{a.dataSources?.map((ds) => (
|
|
148
|
-
<Badge
|
|
149
|
-
key={ds}
|
|
150
|
-
variant="secondary"
|
|
151
|
-
className="text-[10px] px-1.5 py-0"
|
|
152
|
-
>
|
|
153
|
-
{ds}
|
|
154
|
-
</Badge>
|
|
155
|
-
))}
|
|
156
|
-
</div>
|
|
157
|
-
<div className="flex items-center gap-3 text-[11px] text-muted-foreground">
|
|
158
|
-
<span className="flex items-center gap-1">
|
|
159
|
-
<IconClock className="h-3 w-3" />
|
|
160
|
-
{formatRelativeDate(a.updatedAt)}
|
|
161
|
-
</span>
|
|
162
|
-
{a.author && (
|
|
163
|
-
<span className="truncate">by {a.author}</span>
|
|
164
|
-
)}
|
|
165
|
-
</div>
|
|
166
|
-
</CardContent>
|
|
167
|
-
</Card>
|
|
168
|
-
</Link>
|
|
169
|
-
))}
|
|
170
|
-
</div>
|
|
171
|
-
)}
|
|
172
|
-
</div>
|
|
173
|
-
</>
|
|
174
|
-
);
|
|
175
|
-
}
|