@lightdash/cli 3.96.0 → 3.97.0

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.
@@ -197,6 +197,10 @@ order, `sortBy` describes result ordering, `totalColumnCount` exposes truncation
197
197
  `instructions` prop on `InsightsSummary` (or `useInsights({ instructions })`
198
198
  in a custom block). One string per app, max 2000 characters. See "Author
199
199
  instructions" in `/app/references/ai-analysis.md`.
200
+ - `analysis-on-load`: only when the user asks for the analysis to run on its
201
+ own ("analyse as soon as it loads"): set the `analyseOnLoad` prop on
202
+ `InsightsSummary` (or `useInsights({ analyseOnLoad: true })` in a custom
203
+ block). See "Analyse on load" in `/app/references/ai-analysis.md`.
200
204
  - `ai-prompt`: `useAiPrompt()` returns `{ available, ask, loading, text, error }`;
201
205
  `ask({ prompt, sources: [{ result, label }], focus?: { row } })` sends an
202
206
  author-written question over loaded `useLightdash` results and resolves to
@@ -49,7 +49,7 @@ const view = useInsights();
49
49
  // view.analyse() ask Lightdash to (re)run the analysis
50
50
  ```
51
51
 
52
- Render `<InsightsSummary />` near the top of the page. It handles every status (idle, analysing, ready, error, stale) and renders nothing when unavailable. Props: `title`, `idleText`, `instructions`, `className`. Write your own block only when the user asks for a layout the component cannot give, and then keep every status branch.
52
+ Render `<InsightsSummary />` near the top of the page. It handles every status (idle, analysing, ready, error, stale) and renders nothing when unavailable. Props: `title`, `idleText`, `instructions`, `analyseOnLoad`, `className`. Write your own block only when the user asks for a layout the component cannot give, and then keep every status branch.
53
53
 
54
54
  ### Author instructions for the analysis
55
55
 
@@ -63,6 +63,16 @@ Or equivalently `useInsights({ instructions })` in a custom block. One string pe
63
63
 
64
64
  The organization may also set default instructions in its settings; those apply first and the app's instructions are added after them, so keep app instructions to app-specific guidance (domain vocabulary) and leave org-wide style (language, currency) to the org default when the user says it should apply everywhere.
65
65
 
66
+ ### Analyse on load
67
+
68
+ By default the analysis runs when the viewer clicks **Analyse**. When the user wants it to run on its own ("analyse as soon as it loads", "show the summary when the page opens"), set `analyseOnLoad`:
69
+
70
+ ```tsx
71
+ <InsightsSummary analyseOnLoad />
72
+ ```
73
+
74
+ Or equivalently `useInsights({ analyseOnLoad: true })` in a custom block. One value per app (the last value set wins). The host runs the analysis once the page's queries settle and again when the view changes; a stored analysis of the same rows is reused instead of re-run. Do not set it unless the user asked for it.
75
+
66
76
  Rules for the block:
67
77
 
68
78
  - Say "AI-generated" in the footer. Never name a model or provider.
@@ -779,7 +779,7 @@ For any external HTTP API call, read `/app/references/external-apis.md` and use
779
779
 
780
780
  ### AI analysis — executive summary and anomalies
781
781
 
782
- When the user asks for AI analysis, an executive summary, "what changed and why", anomaly callouts, or any AI-generated insight about the data on the page, read `/app/references/ai-analysis.md` and build its **Default build** with the shipped components in `src/components/insights/` (`InsightsSummary`, `InsightMarker` / `insightCellProps`, `InvestigateMenuItem`, `InvestigationCard`): summary block at the top, markers on every query-bound chart, Investigate in every point menu, the investigation card under the chart. A short ask gets the whole set; only a narrower ask ("just a summary") gets a subset. Never rewrite those components. Lightdash runs the analysis over the queries the app already loaded and pushes the result in; the app renders it and never sends rows or keys. The components render nothing when the host has no analysis to offer. For an author-written question over loaded results (a takeaway under a chart, "explain this row"), use `useAiPrompt` from the same reference. When the user wants the summaries written a certain way (language, currency, domain vocabulary), pass it via the `instructions` prop on `InsightsSummary` — see "Author instructions" in the same reference.
782
+ When the user asks for AI analysis, an executive summary, "what changed and why", anomaly callouts, or any AI-generated insight about the data on the page, read `/app/references/ai-analysis.md` and build its **Default build** with the shipped components in `src/components/insights/` (`InsightsSummary`, `InsightMarker` / `insightCellProps`, `InvestigateMenuItem`, `InvestigationCard`): summary block at the top, markers on every query-bound chart, Investigate in every point menu, the investigation card under the chart. A short ask gets the whole set; only a narrower ask ("just a summary") gets a subset. Never rewrite those components. Lightdash runs the analysis over the queries the app already loaded and pushes the result in; the app renders it and never sends rows or keys. The components render nothing when the host has no analysis to offer. For an author-written question over loaded results (a takeaway under a chart, "explain this row"), use `useAiPrompt` from the same reference. When the user wants the summaries written a certain way (language, currency, domain vocabulary), pass it via the `instructions` prop on `InsightsSummary` — see "Author instructions" in the same reference. When the user wants the analysis to run as soon as the app loads, set the `analyseOnLoad` prop on `InsightsSummary` — see "Analyse on load" in the same reference; never set it unasked.
783
783
 
784
784
  ## Visual Design
785
785
 
@@ -6,7 +6,7 @@ import { useInsights } from '@lightdash/query-sdk';
6
6
  import { Button } from '@/components/ui/button';
7
7
  import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
8
8
  import { Loader2, RefreshCw, Sparkles } from 'lucide-react';
9
- import type { ReactNode } from 'react';
9
+ import { useEffect, useState, type ReactNode } from 'react';
10
10
 
11
11
  type Props = {
12
12
  title?: ReactNode;
@@ -15,6 +15,8 @@ type Props = {
15
15
  /** Guidance for the analysis model: language/format rules and a line or
16
16
  * two of domain vocabulary. One string per app. */
17
17
  instructions?: string;
18
+ /** Run the analysis when the view loads, without a click. */
19
+ analyseOnLoad?: boolean;
18
20
  className?: string;
19
21
  };
20
22
 
@@ -22,13 +24,30 @@ export function InsightsSummary({
22
24
  title = 'Executive summary',
23
25
  idleText = 'Click Analyse for an AI-generated read of everything on this page.',
24
26
  instructions,
27
+ analyseOnLoad,
25
28
  className,
26
29
  }: Props) {
27
30
  // Always pass the options object so clearing the prop clears the
28
31
  // guidance instead of leaving the previous value in force.
29
- const view = useInsights({ instructions });
32
+ const view = useInsights({ instructions, analyseOnLoad });
33
+ // The host only starts once the app reports analyseOnLoad, so show the
34
+ // run as pending meanwhile; a short cap keeps an older host from
35
+ // leaving it stuck.
36
+ const [pendingAutoRun, setPendingAutoRun] = useState(!!analyseOnLoad);
37
+ useEffect(() => {
38
+ if (!pendingAutoRun) return undefined;
39
+ // `unavailable` is also the SDK's state before the host's first push.
40
+ if (view.status !== 'idle' && view.status !== 'unavailable') {
41
+ setPendingAutoRun(false);
42
+ return undefined;
43
+ }
44
+ const timer = setTimeout(() => setPendingAutoRun(false), 5000);
45
+ return () => clearTimeout(timer);
46
+ }, [pendingAutoRun, view.status]);
30
47
  if (view.status === 'unavailable') return null;
31
- const busy = view.status === 'analysing';
48
+ const busy =
49
+ view.status === 'analysing' ||
50
+ (pendingAutoRun && view.status === 'idle');
32
51
 
33
52
  return (
34
53
  <Card className={className}>
@@ -52,7 +71,7 @@ export function InsightsSummary({
52
71
  </Button>
53
72
  </CardHeader>
54
73
  <CardContent className="space-y-3">
55
- {view.status === 'idle' && (
74
+ {view.status === 'idle' && !busy && (
56
75
  <p className="text-sm text-muted-foreground">{idleText}</p>
57
76
  )}
58
77
  {busy && (
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightdash/cli",
3
- "version": "3.96.0",
3
+ "version": "3.97.0",
4
4
  "description": "Lightdash CLI tool",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -22,8 +22,8 @@
22
22
  "@actions/core": "1.11.1",
23
23
  "@aws-sdk/credential-providers": "3.995.0",
24
24
  "@casl/ability": "6.8.0",
25
- "@lightdash/common": "3.96.0",
26
- "@lightdash/warehouses": "3.96.0",
25
+ "@lightdash/common": "3.97.0",
26
+ "@lightdash/warehouses": "3.97.0",
27
27
  "@sidvind/better-ajv-errors": "7.0.0",
28
28
  "@types/columnify": "1.5.1",
29
29
  "ajv": "8.18.0",