@lightdash/cli 0.3406.0 → 0.3406.1

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.
Files changed (44) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/handlers/contentAsCode/fileNames.d.ts +24 -0
  3. package/dist/handlers/contentAsCode/fileNames.d.ts.map +1 -0
  4. package/dist/handlers/contentAsCode/fileNames.js +67 -0
  5. package/dist/handlers/contentAsCode/fileNames.test.d.ts +2 -0
  6. package/dist/handlers/contentAsCode/fileNames.test.d.ts.map +1 -0
  7. package/dist/handlers/contentAsCode/fileNames.test.js +79 -0
  8. package/dist/handlers/contentAsCode/projectResources.d.ts +8 -0
  9. package/dist/handlers/contentAsCode/projectResources.d.ts.map +1 -0
  10. package/dist/handlers/contentAsCode/projectResources.js +95 -0
  11. package/dist/handlers/contentAsCode/registry.d.ts +9 -0
  12. package/dist/handlers/contentAsCode/registry.d.ts.map +1 -0
  13. package/dist/handlers/contentAsCode/registry.js +44 -0
  14. package/dist/handlers/contentAsCode/registry.test.d.ts +2 -0
  15. package/dist/handlers/contentAsCode/registry.test.d.ts.map +1 -0
  16. package/dist/handlers/contentAsCode/registry.test.js +18 -0
  17. package/dist/handlers/contentAsCode/resource.d.ts +67 -0
  18. package/dist/handlers/contentAsCode/resource.d.ts.map +1 -0
  19. package/dist/handlers/contentAsCode/resource.js +171 -0
  20. package/dist/handlers/contentAsCode/resource.test.d.ts +2 -0
  21. package/dist/handlers/contentAsCode/resource.test.d.ts.map +1 -0
  22. package/dist/handlers/contentAsCode/resource.test.js +39 -0
  23. package/dist/handlers/download.d.ts.map +1 -1
  24. package/dist/handlers/download.js +59 -109
  25. package/dist/handlers/organizationContent/customRoles.d.ts +4 -3
  26. package/dist/handlers/organizationContent/customRoles.d.ts.map +1 -1
  27. package/dist/handlers/organizationContent/customRoles.js +51 -137
  28. package/dist/handlers/organizationContent/customRoles.test.js +13 -2
  29. package/dist/handlers/organizationContent/fileNames.d.ts.map +1 -1
  30. package/dist/handlers/organizationContent/fileNames.js +8 -29
  31. package/dist/handlers/organizationContent/groups.d.ts +4 -3
  32. package/dist/handlers/organizationContent/groups.d.ts.map +1 -1
  33. package/dist/handlers/organizationContent/groups.js +54 -139
  34. package/dist/handlers/organizationContent/groups.test.js +2 -1
  35. package/dist/handlers/organizationContent/index.d.ts.map +1 -1
  36. package/dist/handlers/organizationContent/index.js +7 -22
  37. package/dist/handlers/organizationContent/users.d.ts +4 -3
  38. package/dist/handlers/organizationContent/users.d.ts.map +1 -1
  39. package/dist/handlers/organizationContent/users.js +75 -146
  40. package/dist/handlers/organizationContent/users.test.js +4 -3
  41. package/dist/handlers/spacesAsCode.d.ts +1 -1
  42. package/dist/handlers/spacesAsCode.d.ts.map +1 -1
  43. package/dist/handlers/spacesAsCode.js +21 -26
  44. package/package.json +3 -3
@@ -1,33 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getOrganizationContentFileNames = void 0;
4
- const common_1 = require("@lightdash/common");
5
- const crypto_1 = require("crypto");
6
- const ORGANIZATION_CONTENT_FILENAME_MAX_LENGTH = 200;
7
- const FILENAME_HASH_LENGTH = 8;
8
- const getStableHash = (value) => (0, crypto_1.createHash)('sha256')
9
- .update(value)
10
- .digest('hex')
11
- .slice(0, FILENAME_HASH_LENGTH);
12
- const getFilenameBase = (value, fallbackPrefix) => {
13
- const normalizedValue = value
14
- .normalize('NFKD')
15
- .replace(/[\u0300-\u036f]/g, '');
16
- const slug = /[a-z0-9]/i.test(normalizedValue)
17
- ? (0, common_1.generateSlug)(normalizedValue)
18
- : `${fallbackPrefix}-${getStableHash(value)}`;
19
- return slug.slice(0, ORGANIZATION_CONTENT_FILENAME_MAX_LENGTH);
20
- };
21
- const getOrganizationContentFileNames = ({ values, fallbackPrefix, }) => {
22
- const filenameBases = values.map((value) => getFilenameBase(value, fallbackPrefix));
23
- const baseCounts = filenameBases.reduce((counts, filenameBase) => counts.set(filenameBase, (counts.get(filenameBase) ?? 0) + 1), new Map());
24
- return filenameBases.map((filenameBase, index) => {
25
- if ((baseCounts.get(filenameBase) ?? 0) === 1) {
26
- return `${filenameBase}.yml`;
27
- }
28
- const collisionSuffix = `-${getStableHash(values[index])}`;
29
- const uniqueFilenameBase = `${filenameBase.slice(0, ORGANIZATION_CONTENT_FILENAME_MAX_LENGTH - collisionSuffix.length)}${collisionSuffix}`;
30
- return `${uniqueFilenameBase}.yml`;
31
- });
32
- };
4
+ const fileNames_1 = require("../contentAsCode/fileNames");
5
+ const getOrganizationContentFileNames = ({ values, fallbackPrefix, }) => (0, fileNames_1.allocateContentFileNames)({
6
+ items: values.map((value) => ({
7
+ identity: value,
8
+ displayName: value,
9
+ })),
10
+ fallbackPrefix,
11
+ });
33
12
  exports.getOrganizationContentFileNames = getOrganizationContentFileNames;
@@ -1,6 +1,6 @@
1
- export type GroupUploadFailure = {
2
- message: string;
3
- };
1
+ import { type GroupAsCode } from '@lightdash/common';
2
+ import { type CodeFileFailure, type CodeResourceDefinition } from '../contentAsCode/resource';
3
+ export type GroupUploadFailure = CodeFileFailure;
4
4
  export type GroupUploadSummary = {
5
5
  created: number;
6
6
  updated: number;
@@ -9,6 +9,7 @@ export type GroupUploadSummary = {
9
9
  dependencySkipped: number;
10
10
  failures: GroupUploadFailure[];
11
11
  };
12
+ export declare const GROUP_CODE_RESOURCE: CodeResourceDefinition<GroupAsCode>;
12
13
  export declare const getGroupsFolder: (organizationContentPath: string) => string;
13
14
  export declare const formatGroupUploadSummary: (summary: GroupUploadSummary) => string;
14
15
  export declare const readGroupFiles: (organizationContentPath: string) => Promise<unknown[]>;
@@ -1 +1 @@
1
- {"version":3,"file":"groups.d.ts","sourceRoot":"","sources":["../../../src/handlers/organizationContent/groups.ts"],"names":[],"mappings":"AAgBA,MAAM,MAAM,kBAAkB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,kBAAkB,EAAE,CAAC;CAClC,CAAC;AAgBF,eAAO,MAAM,eAAe,GAAI,yBAAyB,MAAM,KAAG,MAClB,CAAC;AAEjD,eAAO,MAAM,wBAAwB,GAAI,SAAS,kBAAkB,KAAG,MACgG,CAAC;AAiFxK,eAAO,MAAM,cAAc,GACvB,yBAAyB,MAAM,KAChC,OAAO,CAAC,OAAO,EAAE,CAUnB,CAAC;AAEF,eAAO,MAAM,4BAA4B,GACrC,yBAAyB,MAAM,KAChC,OAAO,CAAC,MAAM,CAahB,CAAC;AAEF,eAAO,MAAM,YAAY,GACrB,kBAAkB,MAAM,EACxB,yBAAyB,MAAM,KAChC,OAAO,CAAC,kBAAkB,CA8C5B,CAAC;AAEF,eAAO,MAAM,cAAc,GACvB,kBAAkB,MAAM,EACxB,yBAAyB,MAAM,KAChC,OAAO,CAAC,MAAM,CAuChB,CAAC"}
1
+ {"version":3,"file":"groups.d.ts","sourceRoot":"","sources":["../../../src/handlers/organizationContent/groups.ts"],"names":[],"mappings":"AAAA,OAAO,EAIH,KAAK,WAAW,EACnB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAKH,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC9B,MAAM,2BAA2B,CAAC;AAGnC,MAAM,MAAM,kBAAkB,GAAG,eAAe,CAAC;AAEjD,MAAM,MAAM,kBAAkB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,kBAAkB,EAAE,CAAC;CAClC,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,sBAAsB,CAAC,WAAW,CAiBnE,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,yBAAyB,MAAM,KAAG,MACI,CAAC;AAEvE,eAAO,MAAM,wBAAwB,GAAI,SAAS,kBAAkB,KAAG,MACgG,CAAC;AAExK,eAAO,MAAM,cAAc,GACvB,yBAAyB,MAAM,KAChC,OAAO,CAAC,OAAO,EAAE,CAOnB,CAAC;AAEF,eAAO,MAAM,4BAA4B,GACrC,yBAAyB,MAAM,KAChC,OAAO,CAAC,MAAM,CAehB,CAAC;AAEF,eAAO,MAAM,YAAY,GACrB,kBAAkB,MAAM,EACxB,yBAAyB,MAAM,KAChC,OAAO,CAAC,kBAAkB,CAgB5B,CAAC;AAEF,eAAO,MAAM,cAAc,GACvB,kBAAkB,MAAM,EACxB,yBAAyB,MAAM,KAChC,OAAO,CAAC,MAAM,CAiBX,CAAC"}
@@ -1,171 +1,86 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.downloadGroups = exports.uploadGroups = exports.countDependencySkippedGroups = exports.readGroupFiles = exports.formatGroupUploadSummary = exports.getGroupsFolder = void 0;
3
+ exports.downloadGroups = exports.uploadGroups = exports.countDependencySkippedGroups = exports.readGroupFiles = exports.formatGroupUploadSummary = exports.getGroupsFolder = exports.GROUP_CODE_RESOURCE = void 0;
4
4
  const tslib_1 = require("tslib");
5
- /* eslint-disable no-await-in-loop */
6
5
  const common_1 = require("@lightdash/common");
7
6
  const fs_1 = require("fs");
8
- const yaml = tslib_1.__importStar(require("js-yaml"));
9
- const groupBy_1 = tslib_1.__importDefault(require("lodash/groupBy"));
10
7
  const path = tslib_1.__importStar(require("path"));
8
+ const resource_1 = require("../contentAsCode/resource");
11
9
  const apiClient_1 = require("../dbt/apiClient");
12
- const fileNames_1 = require("./fileNames");
13
- const getGroupsFolder = (organizationContentPath) => path.join(organizationContentPath, 'groups');
10
+ exports.GROUP_CODE_RESOURCE = {
11
+ kind: 'group',
12
+ displayLabel: 'group',
13
+ identityLabel: 'name',
14
+ scope: 'organization',
15
+ folderName: 'groups',
16
+ acceptedExtensions: ['.yml'],
17
+ fileName: {
18
+ strategy: 'normalizedDisplayName',
19
+ fallbackPrefix: 'group',
20
+ extension: '.yml',
21
+ },
22
+ dependencies: ['custom_role', 'user'],
23
+ identity: ({ name }) => name,
24
+ displayName: ({ name }) => name,
25
+ parse: common_1.parseGroupAsCode,
26
+ sort: (left, right) => left.name.localeCompare(right.name),
27
+ };
28
+ const getGroupsFolder = (organizationContentPath) => path.join(organizationContentPath, exports.GROUP_CODE_RESOURCE.folderName);
14
29
  exports.getGroupsFolder = getGroupsFolder;
15
30
  const formatGroupUploadSummary = (summary) => `${summary.created} created, ${summary.updated} updated, ${summary.unchanged} unchanged, ${summary.failed} failed, ${summary.dependencySkipped} dependency-skipped`;
16
31
  exports.formatGroupUploadSummary = formatGroupUploadSummary;
17
- const getGroupName = (group) => {
18
- if (typeof group !== 'object' || group === null || Array.isArray(group)) {
19
- return undefined;
20
- }
21
- const { name } = group;
22
- return typeof name === 'string' ? name : undefined;
23
- };
24
- const readGroupFileResults = async (organizationContentPath) => {
25
- const folder = (0, exports.getGroupsFolder)(organizationContentPath);
26
- let entries;
27
- try {
28
- entries = await fs_1.promises.readdir(folder, { withFileTypes: true });
29
- }
30
- catch (error) {
31
- if (error.code === 'ENOENT') {
32
- return { groupFiles: [], failures: [] };
33
- }
34
- throw error;
35
- }
36
- const files = entries
37
- .filter((entry) => entry.isFile() && entry.name.endsWith('.yml'))
38
- .sort((left, right) => left.name.localeCompare(right.name));
39
- const results = await Promise.all(files.map(async (file) => {
40
- const filePath = path.join(folder, file.name);
41
- try {
42
- return {
43
- kind: 'group',
44
- groupFile: {
45
- filePath,
46
- group: yaml.load(await fs_1.promises.readFile(filePath, 'utf8')),
47
- },
48
- };
49
- }
50
- catch (error) {
51
- return {
52
- kind: 'failure',
53
- failure: {
54
- message: `Unable to parse group file "${filePath}": ${(0, common_1.getErrorMessage)(error)}`,
55
- },
56
- };
57
- }
58
- }));
59
- const parsedGroupFiles = results.flatMap((result) => result.kind === 'group' ? [result.groupFile] : []);
60
- const failures = results.flatMap((result) => result.kind === 'failure' ? [result.failure] : []);
61
- const namedGroupFiles = parsedGroupFiles.flatMap((groupFile) => {
62
- const name = getGroupName(groupFile.group);
63
- return name === undefined ? [] : [{ name, groupFile }];
64
- });
65
- const filesByName = (0, groupBy_1.default)(namedGroupFiles, ({ name }) => name);
66
- const duplicateNames = new Set(Object.entries(filesByName)
67
- .filter(([, matchingFiles]) => matchingFiles.length > 1)
68
- .map(([name]) => name));
69
- for (const duplicateName of [...duplicateNames].sort()) {
70
- for (const { groupFile } of filesByName[duplicateName]) {
71
- failures.push({
72
- message: `Duplicate group name "${duplicateName}" in "${groupFile.filePath}"`,
73
- });
74
- }
75
- }
76
- return {
77
- groupFiles: parsedGroupFiles.filter(({ group }) => !duplicateNames.has(getGroupName(group) ?? '')),
78
- failures,
79
- };
80
- };
81
32
  const readGroupFiles = async (organizationContentPath) => {
82
- const { groupFiles, failures } = await readGroupFileResults(organizationContentPath);
83
- if (failures.length > 0) {
84
- throw new common_1.ParameterError(failures.map(({ message }) => message).join('\n'));
85
- }
86
- return groupFiles.map(({ group }) => group);
33
+ const result = await (0, resource_1.readCodeResourceFiles)({
34
+ definition: exports.GROUP_CODE_RESOURCE,
35
+ basePath: organizationContentPath,
36
+ });
37
+ (0, resource_1.assertCodeResourceFilesValid)(result);
38
+ return result.files.map(({ document }) => document);
87
39
  };
88
40
  exports.readGroupFiles = readGroupFiles;
89
41
  const countDependencySkippedGroups = async (organizationContentPath) => {
90
42
  const folder = (0, exports.getGroupsFolder)(organizationContentPath);
91
43
  try {
92
44
  const entries = await fs_1.promises.readdir(folder, { withFileTypes: true });
93
- return entries.filter((entry) => entry.isFile() && entry.name.endsWith('.yml')).length;
45
+ return entries.filter((entry) => entry.isFile() &&
46
+ exports.GROUP_CODE_RESOURCE.acceptedExtensions.some((extension) => entry.name.endsWith(extension))).length;
94
47
  }
95
48
  catch (error) {
96
- if (error.code === 'ENOENT') {
49
+ if (error.code === 'ENOENT')
97
50
  return 0;
98
- }
99
51
  throw error;
100
52
  }
101
53
  };
102
54
  exports.countDependencySkippedGroups = countDependencySkippedGroups;
103
55
  const uploadGroups = async (organizationUuid, organizationContentPath) => {
104
- const { groupFiles, failures } = await readGroupFileResults(organizationContentPath);
105
- const summary = {
106
- created: 0,
107
- updated: 0,
108
- unchanged: 0,
109
- failed: 0,
110
- dependencySkipped: 0,
111
- failures,
112
- };
113
- for (const { filePath, group } of groupFiles) {
114
- try {
56
+ const summary = await (0, resource_1.uploadCodeResource)({
57
+ definition: exports.GROUP_CODE_RESOURCE,
58
+ basePath: organizationContentPath,
59
+ upsert: async (group) => {
115
60
  const result = await (0, apiClient_1.lightdashApi)({
116
61
  method: 'POST',
117
- url: `/api/v2/orgs/${organizationUuid}/groups/code`,
62
+ url: `/api/v2/orgs/${organizationUuid}/code/groups`,
118
63
  body: JSON.stringify(group),
119
64
  });
120
- switch (result.action) {
121
- case common_1.PromotionAction.CREATE:
122
- summary.created += 1;
123
- break;
124
- case common_1.PromotionAction.UPDATE:
125
- summary.updated += 1;
126
- break;
127
- case common_1.PromotionAction.NO_CHANGES:
128
- summary.unchanged += 1;
129
- break;
130
- default:
131
- throw new common_1.ParameterError(`Unsupported group promotion action: ${result.action}`);
132
- }
133
- }
134
- catch (error) {
135
- summary.failures.push({
136
- message: `Invalid group file "${filePath}": ${(0, common_1.getErrorMessage)(error)}`,
137
- });
138
- }
139
- }
140
- summary.failed = summary.failures.length;
141
- return summary;
142
- };
143
- exports.uploadGroups = uploadGroups;
144
- const downloadGroups = async (organizationUuid, organizationContentPath) => {
145
- const { groups } = await (0, apiClient_1.lightdashApi)({
146
- method: 'GET',
147
- url: `/api/v2/orgs/${organizationUuid}/groups/code`,
148
- body: undefined,
149
- });
150
- const folder = (0, exports.getGroupsFolder)(organizationContentPath);
151
- await fs_1.promises.mkdir(folder, { recursive: true });
152
- const existingFiles = await fs_1.promises.readdir(folder, { withFileTypes: true });
153
- await Promise.all(existingFiles
154
- .filter((entry) => entry.isFile() && entry.name.endsWith('.yml'))
155
- .map((entry) => fs_1.promises.unlink(path.join(folder, entry.name))));
156
- const sortedGroups = [...groups]
157
- .map((group) => ({
158
- ...group,
159
- members: [...group.members].sort(),
160
- }))
161
- .sort((left, right) => left.name.localeCompare(right.name));
162
- const filenames = (0, fileNames_1.getOrganizationContentFileNames)({
163
- values: sortedGroups.map(({ name }) => name),
164
- fallbackPrefix: 'group',
65
+ return result.action;
66
+ },
165
67
  });
166
- await Promise.all(sortedGroups.map(async (group, index) => {
167
- await fs_1.promises.writeFile(path.join(folder, filenames[index]), yaml.dump(group, { quotingType: '"', sortKeys: true }));
168
- }));
169
- return sortedGroups.length;
68
+ return { ...summary, dependencySkipped: 0 };
170
69
  };
70
+ exports.uploadGroups = uploadGroups;
71
+ const downloadGroups = async (organizationUuid, organizationContentPath) => (0, resource_1.downloadCodeResource)({
72
+ definition: exports.GROUP_CODE_RESOURCE,
73
+ basePath: organizationContentPath,
74
+ list: async () => {
75
+ const { groups } = await (0, apiClient_1.lightdashApi)({
76
+ method: 'GET',
77
+ url: `/api/v2/orgs/${organizationUuid}/code/groups`,
78
+ body: undefined,
79
+ });
80
+ return groups.map((group) => ({
81
+ ...group,
82
+ members: [...group.members].sort(),
83
+ }));
84
+ },
85
+ });
171
86
  exports.downloadGroups = downloadGroups;
@@ -60,6 +60,7 @@ describe('groups as code', () => {
60
60
  'empty.yml',
61
61
  `finance-${financeBangHash}.yml`,
62
62
  `finance-${financeQuestionHash}.yml`,
63
+ 'stale.yml',
63
64
  ].sort());
64
65
  expect(yaml.load(await fs_1.promises.readFile(path.join(folder, `finance-${financeQuestionHash}.yml`), 'utf8'))).toStrictEqual({
65
66
  version: 1,
@@ -120,7 +121,7 @@ describe('groups as code', () => {
120
121
  });
121
122
  expect(apiClient_1.lightdashApi).toHaveBeenNthCalledWith(3, {
122
123
  method: 'POST',
123
- url: '/api/v2/orgs/organization-uuid/groups/code',
124
+ url: '/api/v2/orgs/organization-uuid/code/groups',
124
125
  body: expect.any(String),
125
126
  });
126
127
  expect(JSON.parse(vitest_1.vi.mocked(apiClient_1.lightdashApi).mock.calls[2][0].body)).toStrictEqual(group('Update', ['member@example.com']));
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/handlers/organizationContent/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAiB3C,KAAK,0BAA0B,GAAG;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAmCF,eAAO,MAAM,4BAA4B,GAAI,aAAa,MAAM,KAAG,MAClC,CAAC;AAElC,eAAO,MAAM,2BAA2B,GAAU,yBAG/C,0BAA0B,KAAG,OAAO,CAAC,IAAI,CAqF3C,CAAC;AAEF,eAAO,MAAM,yBAAyB,GAAU,sCAI7C,0BAA0B,KAAG,OAAO,CAAC,IAAI,CAiI3C,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/handlers/organizationContent/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAyB3C,KAAK,0BAA0B,GAAG;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAkBF,eAAO,MAAM,4BAA4B,GAAI,aAAa,MAAM,KAAG,MAClC,CAAC;AAElC,eAAO,MAAM,2BAA2B,GAAU,yBAG/C,0BAA0B,KAAG,OAAO,CAAC,IAAI,CAqF3C,CAAC;AAEF,eAAO,MAAM,yBAAyB,GAAU,sCAI7C,0BAA0B,KAAG,OAAO,CAAC,IAAI,CAkI3C,CAAC"}
@@ -6,32 +6,16 @@ const common_1 = require("@lightdash/common");
6
6
  const analytics_1 = require("../../analytics/analytics");
7
7
  const globalState_1 = tslib_1.__importDefault(require("../../globalState"));
8
8
  const styles = tslib_1.__importStar(require("../../styles"));
9
+ const registry_1 = require("../contentAsCode/registry");
10
+ const resource_1 = require("../contentAsCode/resource");
9
11
  const contentAsCodePaths_1 = require("../contentAsCodePaths");
10
12
  const customRoles_1 = require("./customRoles");
11
13
  const groups_1 = require("./groups");
12
14
  const users_1 = require("./users");
13
- const customRolePartialUploadErrors = new WeakSet();
14
- const groupPartialUploadErrors = new WeakSet();
15
- const userPartialUploadErrors = new WeakSet();
16
- const createCustomRolePartialUploadError = (message) => {
17
- const error = new common_1.ParameterError(message);
18
- customRolePartialUploadErrors.add(error);
19
- return error;
20
- };
21
- const createUserPartialUploadError = (message) => {
22
- const error = new common_1.ParameterError(message);
23
- userPartialUploadErrors.add(error);
24
- return error;
25
- };
26
- const createGroupPartialUploadError = (message) => {
27
- const error = new common_1.ParameterError(message);
28
- groupPartialUploadErrors.add(error);
29
- return error;
30
- };
31
- const isPartialUploadError = (error) => error instanceof Error &&
32
- (customRolePartialUploadErrors.has(error) ||
33
- groupPartialUploadErrors.has(error) ||
34
- userPartialUploadErrors.has(error));
15
+ const createCustomRolePartialUploadError = (message) => new resource_1.CodeResourcePhaseError('custom_role', message);
16
+ const createUserPartialUploadError = (message) => new resource_1.CodeResourcePhaseError('user', message);
17
+ const createGroupPartialUploadError = (message) => new resource_1.CodeResourcePhaseError('group', message);
18
+ const isPartialUploadError = resource_1.isCodeResourcePhaseError;
35
19
  const isGroupServiceDisabledError = (error) => error instanceof common_1.LightdashError &&
36
20
  error.statusCode === 403 &&
37
21
  error.message === 'Group service is not enabled';
@@ -102,6 +86,7 @@ const downloadOrganizationContent = async ({ customPath, config, }) => {
102
86
  };
103
87
  exports.downloadOrganizationContent = downloadOrganizationContent;
104
88
  const uploadOrganizationContent = async ({ customPath, config, sendInvites = false, }) => {
89
+ (0, registry_1.assertCodeResourceDependencyOrder)(registry_1.ORGANIZATION_CODE_RESOURCES);
105
90
  const organizationUuid = config.user?.organizationUuid;
106
91
  if (!organizationUuid) {
107
92
  throw new common_1.AuthorizationError(`No organization selected. Log in again with 'lightdash login'.`);
@@ -1,6 +1,6 @@
1
- export type UserUploadFailure = {
2
- message: string;
3
- };
1
+ import { type UserAsCode } from '@lightdash/common';
2
+ import { type CodeFileFailure, type CodeResourceDefinition } from '../contentAsCode/resource';
3
+ export type UserUploadFailure = CodeFileFailure;
4
4
  export type UserUploadSummary = {
5
5
  created: number;
6
6
  updated: number;
@@ -13,6 +13,7 @@ export type UserUploadSummary = {
13
13
  failed: number;
14
14
  failures: UserUploadFailure[];
15
15
  };
16
+ export declare const USER_CODE_RESOURCE: CodeResourceDefinition<UserAsCode>;
16
17
  export declare const getUsersFolder: (organizationContentPath: string) => string;
17
18
  export declare const formatUserUploadSummary: (summary: UserUploadSummary) => string;
18
19
  export declare const readUserFiles: (organizationContentPath: string) => Promise<unknown[]>;
@@ -1 +1 @@
1
- {"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../../src/handlers/organizationContent/users.ts"],"names":[],"mappings":"AAoBA,MAAM,MAAM,iBAAiB,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,iBAAiB,EAAE,CAAC;CACjC,CAAC;AAgBF,eAAO,MAAM,cAAc,GAAI,yBAAyB,MAAM,KAAG,MAClB,CAAC;AAEhD,eAAO,MAAM,uBAAuB,GAAI,SAAS,iBAAiB,KAAG,MAUpE,CAAC;AAyGF,eAAO,MAAM,aAAa,GACtB,yBAAyB,MAAM,KAChC,OAAO,CAAC,OAAO,EAAE,CAUnB,CAAC;AAsCF,eAAO,MAAM,WAAW,GACpB,kBAAkB,MAAM,EACxB,yBAAyB,MAAM,EAC/B,cAAa,OAAe,KAC7B,OAAO,CAAC,iBAAiB,CAkG3B,CAAC;AAEF,eAAO,MAAM,aAAa,GACtB,kBAAkB,MAAM,EACxB,yBAAyB,MAAM,KAChC,OAAO,CAAC,MAAM,CAkChB,CAAC"}
1
+ {"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../../src/handlers/organizationContent/users.ts"],"names":[],"mappings":"AACA,OAAO,EAUH,KAAK,UAAU,EAClB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAIH,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC9B,MAAM,2BAA2B,CAAC;AAGnC,MAAM,MAAM,iBAAiB,GAAG,eAAe,CAAC;AAEhD,MAAM,MAAM,iBAAiB,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,iBAAiB,EAAE,CAAC;CACjC,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,sBAAsB,CAAC,UAAU,CAkBjE,CAAC;AAIF,eAAO,MAAM,cAAc,GAAI,yBAAyB,MAAM,KAAG,MACI,CAAC;AAEtE,eAAO,MAAM,uBAAuB,GAAI,SAAS,iBAAiB,KAAG,MAiBpE,CAAC;AAEF,eAAO,MAAM,aAAa,GACtB,yBAAyB,MAAM,KAChC,OAAO,CAAC,OAAO,EAAE,CAOnB,CAAC;AAkCF,eAAO,MAAM,WAAW,GACpB,kBAAkB,MAAM,EACxB,yBAAyB,MAAM,EAC/B,cAAa,OAAe,KAC7B,OAAO,CAAC,iBAAiB,CAgG3B,CAAC;AAEF,eAAO,MAAM,aAAa,GACtB,kBAAkB,MAAM,EACxB,yBAAyB,MAAM,KAChC,OAAO,CAAC,MAAM,CAcX,CAAC"}