@lightdash/cli 1.68.0 → 1.69.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.
@@ -60,14 +60,24 @@ type MetadataEntry = {
60
60
  declare const sanitizeChartForDownload: (chart: ChartAsCode, stripPivotSeries: boolean) => ChartAsCode;
61
61
  type DownloadContentType = 'charts' | 'dashboards' | 'sqlCharts';
62
62
  declare const extractAppSlugsFromDashboards: (dashboards: DashboardAsCode[]) => string[];
63
+ declare const extractChartTableNames: (charts: ChartAsCode[]) => string[];
63
64
  export type DownloadContentResult = {
64
65
  total: number;
65
66
  chartSlugs: string[];
67
+ chartTableNames: string[];
66
68
  appSlugs: string[];
67
69
  metadataEntries: MetadataEntry[];
68
70
  spaces: SpaceAsCode[];
69
71
  };
70
72
  export declare const downloadContent: (ids: string[], type: DownloadContentType, projectId: string, projectName: string, customPath?: string, languageMap?: boolean, nested?: boolean, skipSpaces?: boolean, stripPivotSeries?: boolean, rootSpaces?: boolean, onProgress?: (detail: string) => void) => Promise<DownloadContentResult>;
73
+ declare const isVirtualViewsUnavailableError: (error: unknown) => boolean;
74
+ /**
75
+ * Downloads the virtual views backing a dashboard's charts. The candidates are
76
+ * chart table names, so ones the server reports as missing are just regular
77
+ * dbt explores — expected, never warned. Returns null when virtual views are
78
+ * unavailable on the server.
79
+ */
80
+ declare const downloadLinkedVirtualViews: (projectId: string, tableNames: string[], customPath?: string) => Promise<number | null>;
71
81
  declare const upsertVirtualViews: (projectId: string, slugs: string[], changes: Record<string, number>, force: boolean, canUpload: boolean, customPath?: string) => Promise<Record<string, number>>;
72
82
  export declare const getExternalConnectionSecretEnvVar: (slug: string) => string;
73
83
  /**
@@ -99,14 +109,17 @@ declare const isFilteredWithNoDashboards: (hasFilters: boolean, dashboardSlugs:
99
109
  export declare const uploadHandler: (options: DownloadHandlerOptions) => Promise<void>;
100
110
  export declare const testHelpers: {
101
111
  assertUniqueSpacePaths: typeof assertUniqueSpacePaths;
112
+ downloadLinkedVirtualViews: typeof downloadLinkedVirtualViews;
102
113
  downloadSpaces: typeof downloadSpaces;
103
114
  extractAppSlugsFromDashboards: typeof extractAppSlugsFromDashboards;
115
+ extractChartTableNames: typeof extractChartTableNames;
104
116
  getFlatSpaceFileNames: typeof getFlatSpaceFileNames;
105
117
  getDashboardAppSlugs: typeof getDashboardAppSlugs;
106
118
  getDashboardChartSlugs: typeof getDashboardChartSlugs;
107
119
  hasContentFilters: typeof hasContentFilters;
108
120
  isAiAgentsUnavailableError: typeof isAiAgentsUnavailableError;
109
121
  isExternalConnectionsUnavailableError: typeof isExternalConnectionsUnavailableError;
122
+ isVirtualViewsUnavailableError: typeof isVirtualViewsUnavailableError;
110
123
  downloadAiAgents: typeof downloadAiAgents;
111
124
  isFilteredWithNoDashboards: typeof isFilteredWithNoDashboards;
112
125
  readAiAgentFiles: typeof readAiAgentFiles;
@@ -1 +1 @@
1
- {"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../../src/handlers/download.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../../src/handlers/download.ts"],"names":[],"mappings":"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"}
@@ -341,6 +341,13 @@ const extractAppSlugsFromDashboards = (dashboards) => [
341
341
  : acc;
342
342
  }, []))),
343
343
  ];
344
+ // A virtual view's slug is the explore name charts store in tableName, so
345
+ // these names double as virtual view slug candidates.
346
+ const extractChartTableNames = (charts) => [
347
+ ...new Set(charts
348
+ .map((chart) => chart.tableName)
349
+ .filter((tableName) => !!tableName)),
350
+ ];
344
351
  const downloadContent = async (ids, type, projectId, projectName, customPath, languageMap = false, nested = false, skipSpaces = false, stripPivotSeries = false, rootSpaces = false, onProgress) => {
345
352
  const contentFilters = parseContentFilters(ids);
346
353
  const folderScheme = nested ? 'nested' : 'flat';
@@ -348,6 +355,7 @@ const downloadContent = async (ids, type, projectId, projectName, customPath, la
348
355
  let offset = 0;
349
356
  let total = 0;
350
357
  let chartSlugs = [];
358
+ let chartTableNames = [];
351
359
  let appSlugs = [];
352
360
  let allMetadataEntries = [];
353
361
  let allSpaces = [];
@@ -432,6 +440,10 @@ const downloadContent = async (ids, type, projectId, projectName, customPath, la
432
440
  });
433
441
  allMetadataEntries = [...allMetadataEntries, ...entries];
434
442
  }
443
+ chartTableNames = [
444
+ ...chartTableNames,
445
+ ...extractChartTableNames(results.charts),
446
+ ];
435
447
  }
436
448
  // Accumulate space metadata from each page
437
449
  if ('spaces' in results && results.spaces) {
@@ -450,6 +462,7 @@ const downloadContent = async (ids, type, projectId, projectName, customPath, la
450
462
  return {
451
463
  total,
452
464
  chartSlugs: [...new Set(chartSlugs)],
465
+ chartTableNames: [...new Set(chartTableNames)],
453
466
  appSlugs: [...new Set(appSlugs)],
454
467
  metadataEntries: allMetadataEntries,
455
468
  spaces: allSpaces,
@@ -476,6 +489,44 @@ const downloadVirtualViews = async (projectId, slugs, customPath) => {
476
489
  results.missingSlugs.forEach((slug) => globalState_1.default.log(styles.warning(`Virtual view "${slug}" was not found`)));
477
490
  return results.virtualViews.length;
478
491
  };
492
+ // This download is implicit (derived from a dashboard's charts, not asked for
493
+ // by the user), so an older server without the endpoint (404) or a user
494
+ // without content-as-code access (403) must not fail the run.
495
+ const isVirtualViewsUnavailableError = (error) => error instanceof common_1.LightdashError && [403, 404].includes(error.statusCode);
496
+ /**
497
+ * Downloads the virtual views backing a dashboard's charts. The candidates are
498
+ * chart table names, so ones the server reports as missing are just regular
499
+ * dbt explores — expected, never warned. Returns null when virtual views are
500
+ * unavailable on the server.
501
+ */
502
+ const downloadLinkedVirtualViews = async (projectId, tableNames, customPath) => {
503
+ const query = new URLSearchParams(tableNames.map((name) => ['slugs', name])).toString();
504
+ let results;
505
+ try {
506
+ results = await (0, apiClient_1.lightdashApi)({
507
+ method: 'GET',
508
+ url: `/api/v1/projects/${projectId}/code/virtualViews?${query}`,
509
+ body: undefined,
510
+ });
511
+ }
512
+ catch (error) {
513
+ if (isVirtualViewsUnavailableError(error)) {
514
+ globalState_1.default.debug(`Could not download linked virtual views: ${(0, common_1.getErrorMessage)(error)}`);
515
+ return null;
516
+ }
517
+ throw error;
518
+ }
519
+ if (results.virtualViews.length > 0) {
520
+ await (0, resource_1.writeCodeResourceDocuments)({
521
+ definition: projectResources_1.VIRTUAL_VIEW_CODE_RESOURCE,
522
+ basePath: (0, contentAsCodePaths_1.getDownloadFolder)(customPath),
523
+ documents: results.virtualViews,
524
+ pruneOtherDocuments: false,
525
+ });
526
+ }
527
+ results.skipped.forEach(({ slug, reason }) => globalState_1.default.log(styles.warning(`Skipped virtual view "${slug}": ${reason}`)));
528
+ return results.virtualViews.length;
529
+ };
479
530
  const readVirtualViewFiles = async (customPath) => {
480
531
  const result = await (0, resource_1.readCodeResourceFiles)({
481
532
  definition: projectResources_1.VIRTUAL_VIEW_CODE_RESOURCE,
@@ -1070,7 +1121,7 @@ const downloadHandler = async (options) => {
1070
1121
  !options.skipCharts) {
1071
1122
  output.startItem('Linked charts');
1072
1123
  output.updateActive(`${chartSlugs.length} dashboard dependencies`);
1073
- const { total: regularCharts, metadataEntries: linkedChartMeta, } = await (0, exports.downloadContent)(chartSlugs, 'charts', projectId, projectName, options.path, options.languageMap, options.nested, skipEmbeddedSpaces, options.stripPivotSeries, options.rootSpaces, output.updateActive);
1124
+ const { total: regularCharts, chartTableNames: linkedChartTableNames, metadataEntries: linkedChartMeta, } = await (0, exports.downloadContent)(chartSlugs, 'charts', projectId, projectName, options.path, options.languageMap, options.nested, skipEmbeddedSpaces, options.stripPivotSeries, options.rootSpaces, output.updateActive);
1074
1125
  allMetadataEntries = [
1075
1126
  ...allMetadataEntries,
1076
1127
  ...linkedChartMeta,
@@ -1081,6 +1132,20 @@ const downloadHandler = async (options) => {
1081
1132
  ...linkedSqlMeta,
1082
1133
  ];
1083
1134
  output.completeItem(`${regularCharts + sqlCharts} downloaded`);
1135
+ // Virtual views the linked charts are built on. Skipped
1136
+ // when a broader step already downloaded every one.
1137
+ if (linkedChartTableNames.length > 0 &&
1138
+ !includeAllOptionalContent &&
1139
+ !options.includeVirtualViews) {
1140
+ output.startItem('Linked virtual views');
1141
+ const linkedVirtualViews = await downloadLinkedVirtualViews(projectId, linkedChartTableNames, options.path);
1142
+ if (linkedVirtualViews === null) {
1143
+ output.completeItem('not available on this server', 'warning');
1144
+ }
1145
+ else {
1146
+ output.completeItem(`${linkedVirtualViews} downloaded`);
1147
+ }
1148
+ }
1084
1149
  }
1085
1150
  // Consumed after the explicit apps step (see cappedAppSlugs).
1086
1151
  dashboardAppSlugs = appSlugs;
@@ -2156,14 +2221,17 @@ const uploadHandler = async (options) => {
2156
2221
  exports.uploadHandler = uploadHandler;
2157
2222
  exports.testHelpers = {
2158
2223
  assertUniqueSpacePaths: spacesAsCode_1.assertUniqueSpacePaths,
2224
+ downloadLinkedVirtualViews,
2159
2225
  downloadSpaces: spacesAsCode_1.downloadSpaces,
2160
2226
  extractAppSlugsFromDashboards,
2227
+ extractChartTableNames,
2161
2228
  getFlatSpaceFileNames: spacesAsCode_1.getFlatSpaceFileNames,
2162
2229
  getDashboardAppSlugs,
2163
2230
  getDashboardChartSlugs,
2164
2231
  hasContentFilters,
2165
2232
  isAiAgentsUnavailableError,
2166
2233
  isExternalConnectionsUnavailableError,
2234
+ isVirtualViewsUnavailableError,
2167
2235
  downloadAiAgents,
2168
2236
  isFilteredWithNoDashboards,
2169
2237
  readAiAgentFiles,
@@ -38,7 +38,7 @@ vitest_1.vi.mock('./dbt/apiClient', async (importOriginal) => ({
38
38
  getContentAsCodeUploadPermissions: vitest_1.vi.fn(),
39
39
  lightdashApi: vitest_1.vi.fn(),
40
40
  }));
41
- const { assertUniqueSpacePaths, downloadSpaces, getDashboardAppSlugs, getDashboardChartSlugs, getFlatSpaceFileNames, hasContentFilters, isAiAgentsUnavailableError, isExternalConnectionsUnavailableError, downloadAiAgents, isFilteredWithNoDashboards, readAiAgentFiles, readSpaceFiles, readSpaceNames, sanitizeChartForDownload, shouldFallBackToEmbeddedSpaces, shouldDownloadAiAgents, summarizeUploadChanges, upsertAiAgents, upsertExternalConnections, upsertSpaces, upsertVirtualViews, validateSpaceIdentity, writeSpaceFiles, } = download_1.testHelpers;
41
+ const { assertUniqueSpacePaths, downloadLinkedVirtualViews, downloadSpaces, extractChartTableNames, getDashboardAppSlugs, getDashboardChartSlugs, getFlatSpaceFileNames, hasContentFilters, isAiAgentsUnavailableError, isExternalConnectionsUnavailableError, isVirtualViewsUnavailableError, downloadAiAgents, isFilteredWithNoDashboards, readAiAgentFiles, readSpaceFiles, readSpaceNames, sanitizeChartForDownload, shouldFallBackToEmbeddedSpaces, shouldDownloadAiAgents, summarizeUploadChanges, upsertAiAgents, upsertExternalConnections, upsertSpaces, upsertVirtualViews, validateSpaceIdentity, writeSpaceFiles, } = download_1.testHelpers;
42
42
  const makeDownloadHandlerOptions = (overrides = {}) => ({
43
43
  verbose: false,
44
44
  charts: [],
@@ -327,6 +327,22 @@ describe('extractAppSlugsFromDashboards', () => {
327
327
  ])).toEqual(['one']);
328
328
  });
329
329
  });
330
+ describe('extractChartTableNames', () => {
331
+ const chart = (tableName) => ({
332
+ slug: 'a-chart',
333
+ tableName,
334
+ });
335
+ it('dedupes table names across charts', () => {
336
+ expect(extractChartTableNames([
337
+ chart('orders'),
338
+ chart('customers'),
339
+ chart('orders'),
340
+ ])).toEqual(['orders', 'customers']);
341
+ });
342
+ it('drops missing table names (e.g. SQL charts)', () => {
343
+ expect(extractChartTableNames([chart(undefined), chart(''), chart('one')])).toEqual(['one']);
344
+ });
345
+ });
330
346
  describe('getDashboardAppSlugs', () => {
331
347
  let tmpDir;
332
348
  beforeEach(async () => {
@@ -425,6 +441,85 @@ describe('sanitizeChartForDownload', () => {
425
441
  });
426
442
  });
427
443
  });
444
+ describe('downloadLinkedVirtualViews', () => {
445
+ let tmpDir;
446
+ const virtualViewDocument = (slug) => ({
447
+ contentType: common_1.ContentAsCodeType.VIRTUAL_VIEW,
448
+ version: 1,
449
+ slug,
450
+ name: slug,
451
+ sql: 'SELECT 1 AS order_id',
452
+ columns: [{ reference: 'order_id', type: 'number' }],
453
+ parameters: null,
454
+ });
455
+ beforeEach(async () => {
456
+ vitest_1.vi.mocked(apiClient_1.lightdashApi).mockReset();
457
+ tmpDir = await fs_1.promises.mkdtemp(path.join(os.tmpdir(), 'linked-virtual-views-test-'));
458
+ });
459
+ afterEach(async () => {
460
+ vitest_1.vi.restoreAllMocks();
461
+ await fs_1.promises.rm(tmpDir, { recursive: true, force: true });
462
+ });
463
+ it('writes matched virtual views and stays silent on regular dbt table names', async () => {
464
+ const logSpy = vitest_1.vi
465
+ .spyOn(globalState_1.default, 'log')
466
+ .mockImplementation(() => undefined);
467
+ vitest_1.vi.mocked(apiClient_1.lightdashApi).mockResolvedValueOnce({
468
+ virtualViews: [virtualViewDocument('my_virtual_view')],
469
+ skipped: [],
470
+ missingSlugs: ['orders', 'customers'],
471
+ });
472
+ const count = await downloadLinkedVirtualViews('project-uuid', ['my_virtual_view', 'orders', 'customers'], tmpDir);
473
+ expect(count).toBe(1);
474
+ expect(apiClient_1.lightdashApi).toHaveBeenCalledExactlyOnceWith(expect.objectContaining({
475
+ url: '/api/v1/projects/project-uuid/code/virtualViews?slugs=my_virtual_view&slugs=orders&slugs=customers',
476
+ }));
477
+ await expect(fs_1.promises.readFile(path.join(tmpDir, 'virtual-views', 'my_virtual_view.yml'), 'utf-8')).resolves.toContain('slug: my_virtual_view');
478
+ expect(logSpy).not.toHaveBeenCalled();
479
+ });
480
+ it('warns about skipped virtual views', async () => {
481
+ const logSpy = vitest_1.vi
482
+ .spyOn(globalState_1.default, 'log')
483
+ .mockImplementation(() => undefined);
484
+ vitest_1.vi.mocked(apiClient_1.lightdashApi).mockResolvedValueOnce({
485
+ virtualViews: [],
486
+ skipped: [{ slug: 'broken_view', reason: 'malformed' }],
487
+ missingSlugs: [],
488
+ });
489
+ await expect(downloadLinkedVirtualViews('project-uuid', ['broken_view'], tmpDir)).resolves.toBe(0);
490
+ expect(logSpy).toHaveBeenCalledExactlyOnceWith(expect.stringContaining('Skipped virtual view "broken_view"'));
491
+ });
492
+ it('returns null when the server has no virtual views endpoint', async () => {
493
+ vitest_1.vi.mocked(apiClient_1.lightdashApi).mockRejectedValueOnce(new common_1.LightdashError({
494
+ message: 'Not found',
495
+ name: 'NotFoundError',
496
+ statusCode: 404,
497
+ data: {},
498
+ }));
499
+ await expect(downloadLinkedVirtualViews('project-uuid', ['orders'], tmpDir)).resolves.toBeNull();
500
+ });
501
+ it('rethrows unexpected errors', async () => {
502
+ const serverError = new common_1.LightdashError({
503
+ message: 'Boom',
504
+ name: 'UnexpectedServerError',
505
+ statusCode: 500,
506
+ data: {},
507
+ });
508
+ vitest_1.vi.mocked(apiClient_1.lightdashApi).mockRejectedValueOnce(serverError);
509
+ await expect(downloadLinkedVirtualViews('project-uuid', ['orders'], tmpDir)).rejects.toBe(serverError);
510
+ });
511
+ it('classifies permission and missing-route errors as unavailable', () => {
512
+ [403, 404].forEach((statusCode) => {
513
+ expect(isVirtualViewsUnavailableError(new common_1.LightdashError({
514
+ message: 'unavailable',
515
+ name: 'TestError',
516
+ statusCode,
517
+ data: {},
518
+ }))).toBe(true);
519
+ });
520
+ expect(isVirtualViewsUnavailableError(new Error('nope'))).toBe(false);
521
+ });
522
+ });
428
523
  describe('upsertVirtualViews', () => {
429
524
  let tmpDir;
430
525
  const virtualView = (slug) => `columns:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightdash/cli",
3
- "version": "1.68.0",
3
+ "version": "1.69.0",
4
4
  "description": "Lightdash CLI tool",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -41,8 +41,8 @@
41
41
  "unique-names-generator": "4.7.1",
42
42
  "uuid": "11.1.1",
43
43
  "yaml": "2.8.3",
44
- "@lightdash/common": "1.68.0",
45
- "@lightdash/warehouses": "1.68.0"
44
+ "@lightdash/common": "1.69.0",
45
+ "@lightdash/warehouses": "1.69.0"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/inquirer": "8.2.4",