@lightdash/cli 0.1419.1 → 0.1420.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -52,9 +52,13 @@ export declare const lightdashApi: <T extends string | boolean | unknown[] | imp
52
52
  } | {
53
53
  charts: import("@lightdash/common").ChartAsCode[];
54
54
  missingIds: string[];
55
+ total: number;
56
+ offset: number;
55
57
  } | {
56
58
  dashboards: import("@lightdash/common").DashboardAsCode[];
57
59
  missingIds: string[];
60
+ total: number;
61
+ offset: number;
58
62
  } | {
59
63
  edges: import("@lightdash/common").CatalogMetricsTreeEdge[];
60
64
  } | import("@lightdash/common").MetricTotalResults | null | undefined>({ method, url, body, }: LightdashApiProps) => Promise<T>;
@@ -29,7 +29,7 @@ const parseContentFilters = (items) => {
29
29
  };
30
30
  const dumpIntoFiles = async (folder, items) => {
31
31
  const outputDir = path.join(process.cwd(), DOWNLOAD_FOLDER, folder);
32
- console.info(`Writing ${items.length} ${folder} into ${outputDir}`);
32
+ globalState_1.default.debug(`Writing ${items.length} ${folder} into ${outputDir}`);
33
33
  // Make directory
34
34
  const created = await fs_1.promises.mkdir(outputDir, { recursive: true });
35
35
  if (created)
@@ -103,45 +103,80 @@ const downloadHandler = async (options) => {
103
103
  console.info(styles.warning(`No charts filters provided, skipping`));
104
104
  }
105
105
  else {
106
- globalState_1.default.debug(`Downloading charts`);
106
+ const spinner = globalState_1.default.startSpinner(`Downloading charts`);
107
107
  const chartFilters = parseContentFilters(options.charts);
108
- const chartsAsCode = await (0, apiClient_1.lightdashApi)({
109
- method: 'GET',
110
- url: `/api/v1/projects/${projectId}/charts/code${chartFilters}`,
111
- body: undefined,
112
- });
113
- chartsAsCode.missingIds.forEach((missingId) => {
114
- console.warn(styles.warning(`No chart with id "${missingId}"`));
115
- });
116
- await dumpIntoFiles('charts', chartsAsCode.charts);
108
+ let chartsAsCode;
109
+ let offset = 0;
110
+ do {
111
+ globalState_1.default.debug(`Downloading charts with offset "${offset}" and filters "${chartFilters}"`);
112
+ const queryParams = chartFilters
113
+ ? `${chartFilters}&offset=${offset}`
114
+ : `?offset=${offset}`;
115
+ chartsAsCode = await (0, apiClient_1.lightdashApi)({
116
+ method: 'GET',
117
+ url: `/api/v1/projects/${projectId}/charts/code${queryParams}`,
118
+ body: undefined,
119
+ });
120
+ spinner.start(`Downloaded ${chartsAsCode.offset} of ${chartsAsCode.total} charts`);
121
+ chartsAsCode.missingIds.forEach((missingId) => {
122
+ console.warn(styles.warning(`\nNo chart with id "${missingId}"`));
123
+ });
124
+ await dumpIntoFiles('charts', chartsAsCode.charts);
125
+ offset = chartsAsCode.offset;
126
+ } while (chartsAsCode.offset < chartsAsCode.total);
127
+ spinner.succeed(`Downloaded ${chartsAsCode.total} charts`);
117
128
  }
118
129
  // Download dashboards
119
130
  if (hasFilters && options.dashboards.length === 0) {
120
131
  console.info(styles.warning(`No dashboards filters provided, skipping`));
121
132
  }
122
133
  else {
123
- globalState_1.default.debug(`Downloading dashboards`);
134
+ const spinner = globalState_1.default.startSpinner(`Downloading dashboards`);
124
135
  const dashboardFilters = parseContentFilters(options.dashboards);
125
- const dashboardsAsCode = await (0, apiClient_1.lightdashApi)({
126
- method: 'GET',
127
- url: `/api/v1/projects/${projectId}/dashboards/code${dashboardFilters}`,
128
- body: undefined,
129
- });
130
- dashboardsAsCode.missingIds.forEach((missingId) => {
131
- console.warn(styles.warning(`No dashboard with id "${missingId}"`));
132
- });
133
- await dumpIntoFiles('dashboards', dashboardsAsCode.dashboards);
136
+ let offset = 0;
137
+ let dashboardsAsCode;
138
+ do {
139
+ globalState_1.default.debug(`Downloading dashboards with offset "${offset}" and filters "${dashboardFilters}"`);
140
+ const queryParams = dashboardFilters
141
+ ? `${dashboardFilters}&offset=${offset}`
142
+ : `?offset=${offset}`;
143
+ dashboardsAsCode = await (0, apiClient_1.lightdashApi)({
144
+ method: 'GET',
145
+ url: `/api/v1/projects/${projectId}/dashboards/code${queryParams}`,
146
+ body: undefined,
147
+ });
148
+ dashboardsAsCode.missingIds.forEach((missingId) => {
149
+ console.warn(styles.warning(`\nNo dashboard with id "${missingId}"`));
150
+ });
151
+ spinner?.start(`Downloaded ${dashboardsAsCode.offset} of ${dashboardsAsCode.total} dashboards`);
152
+ await dumpIntoFiles('dashboards', dashboardsAsCode.dashboards);
153
+ offset = dashboardsAsCode.offset;
154
+ } while (dashboardsAsCode.offset < dashboardsAsCode.total);
155
+ spinner.succeed(`Downloaded ${dashboardsAsCode.total} dashboards`);
134
156
  }
135
157
  // TODO delete files if chart don't exist ?*/
136
158
  };
137
159
  exports.downloadHandler = downloadHandler;
160
+ const getPromoteAction = (action) => {
161
+ switch (action) {
162
+ case common_1.PromotionAction.CREATE:
163
+ return 'created';
164
+ case common_1.PromotionAction.UPDATE:
165
+ return 'updated';
166
+ case common_1.PromotionAction.DELETE:
167
+ return 'deleted';
168
+ case common_1.PromotionAction.NO_CHANGES:
169
+ return 'skipped';
170
+ default:
171
+ (0, common_1.assertUnreachable)(action, `Unknown promotion action: ${action}`);
172
+ }
173
+ return 'skipped';
174
+ };
138
175
  const storeUploadChanges = (changes, promoteChanges) => {
139
176
  const getPromoteChanges = (resource) => {
140
177
  const promotions = promoteChanges[resource];
141
178
  return promotions.reduce((acc, promoteChange) => {
142
- const action = promoteChange.action === common_1.PromotionAction.NO_CHANGES
143
- ? 'skipped'
144
- : promoteChange.action;
179
+ const action = getPromoteAction(promoteChange.action);
145
180
  const key = `${resource} ${action}`;
146
181
  acc[key] = (acc[key] ?? 0) + 1;
147
182
  return acc;
@@ -223,8 +258,21 @@ const uploadHandler = async (options) => {
223
258
  throw new Error('No project selected. Run lightdash config set-project');
224
259
  }
225
260
  let changes = {};
226
- changes = await upsertResources('charts', projectId, changes, options.force, options.charts);
227
- changes = await upsertResources('dashboards', projectId, changes, options.force, options.dashboards);
261
+ // If any filter is provided, we skip those items without filters
262
+ // eg: if a --charts filter is provided, we skip dashboards if no --dashboards filter is provided
263
+ const hasFilters = options.charts.length > 0 || options.dashboards.length > 0;
264
+ if (hasFilters && options.charts.length === 0) {
265
+ console.info(styles.warning(`No charts filters provided, skipping`));
266
+ }
267
+ else {
268
+ changes = await upsertResources('charts', projectId, changes, options.force, options.charts);
269
+ }
270
+ if (hasFilters && options.dashboards.length === 0) {
271
+ console.info(styles.warning(`No dashboard filters provided, skipping`));
272
+ }
273
+ else {
274
+ changes = await upsertResources('dashboards', projectId, changes, options.force, options.dashboards);
275
+ }
228
276
  logUploadChanges(changes);
229
277
  };
230
278
  exports.uploadHandler = uploadHandler;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightdash/cli",
3
- "version": "0.1419.1",
3
+ "version": "0.1420.1",
4
4
  "license": "MIT",
5
5
  "bin": {
6
6
  "lightdash": "dist/index.js"
@@ -11,8 +11,8 @@
11
11
  ],
12
12
  "dependencies": {
13
13
  "@actions/core": "^1.11.1",
14
- "@lightdash/common": "^0.1419.1",
15
- "@lightdash/warehouses": "^0.1419.1",
14
+ "@lightdash/common": "^0.1420.1",
15
+ "@lightdash/warehouses": "^0.1420.1",
16
16
  "@types/columnify": "^1.5.1",
17
17
  "ajv": "^8.11.0",
18
18
  "ajv-formats": "^2.1.1",