@contrail/cli 2.2.7 → 2.3.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.
Files changed (86) hide show
  1. package/README.md +135 -367
  2. package/dist/api/apps.js +1 -2
  3. package/dist/auth/auth.js +1 -0
  4. package/dist/basecommand.js +16 -19
  5. package/dist/commands/app/create.js +5 -5
  6. package/dist/commands/app/delete.js +7 -7
  7. package/dist/commands/app/getApiKey.js +8 -8
  8. package/dist/commands/app/init.js +5 -5
  9. package/dist/commands/app/install.js +24 -24
  10. package/dist/commands/app/publish.js +24 -24
  11. package/dist/commands/app/uninstall.js +14 -14
  12. package/dist/commands/app/upgrade.js +19 -19
  13. package/dist/commands/app/version/major.js +6 -9
  14. package/dist/commands/app/version/minor.js +6 -9
  15. package/dist/commands/app/version/patch.js +6 -9
  16. package/dist/commands/colors/deleteAll.js +5 -5
  17. package/dist/commands/colors/load.js +5 -5
  18. package/dist/commands/config/environments/list.js +6 -9
  19. package/dist/commands/config/environments/remove.js +12 -15
  20. package/dist/commands/config/environments/set.js +11 -14
  21. package/dist/commands/config/list.js +6 -9
  22. package/dist/commands/config/remove.js +16 -19
  23. package/dist/commands/config/set.js +22 -25
  24. package/dist/commands/groups/export.js +21 -22
  25. package/dist/commands/groups/upload.js +10 -11
  26. package/dist/commands/instance/export.js +19 -19
  27. package/dist/commands/instance/import.js +13 -13
  28. package/dist/commands/loader-process/load.js +12 -12
  29. package/dist/commands/loader-process/upload-and-load.js +17 -17
  30. package/dist/commands/projects/export.js +9 -9
  31. package/dist/commands/projects/list.js +5 -5
  32. package/dist/commands/projects/load.js +16 -17
  33. package/dist/commands/types/exportOptionSetHierarchies.js +5 -5
  34. package/dist/commands/types/getAll.js +73 -72
  35. package/dist/commands/types/loadAll.js +13 -13
  36. package/dist/commands/types/mergeOptionSets.js +9 -10
  37. package/dist/commands/types/mergeTypeProperties.js +11 -11
  38. package/dist/commands/types/parseOptionSetsHierarchyLocalFile.js +9 -9
  39. package/dist/commands/types/parseOptionSetsHierarchyValuesToKeysLocalFile.js +9 -9
  40. package/dist/commands/types/parseOptionSetsLocalFiles.d.ts +21 -0
  41. package/dist/commands/types/parseOptionSetsLocalFiles.js +95 -17
  42. package/dist/commands/types/parseOptionSetsToFolderStructure.d.ts +0 -1
  43. package/dist/commands/types/parseOptionSetsToFolderStructure.js +5 -41
  44. package/dist/commands/types/parseTypesFromFiles.js +13 -13
  45. package/dist/commands/types/parseTypesFromLocalFiles.js +10 -10
  46. package/dist/commands/types/parseTypesFromTemplateAndDataFromLocalFiles.js +10 -10
  47. package/dist/commands/types/parseTypesFromTemplateFromLocalFiles.js +9 -9
  48. package/dist/commands/types/uploadOptionSetHierarchies.js +15 -16
  49. package/dist/commands/types/uploadOptionSets.js +15 -13
  50. package/dist/commands/types/uploadOptionSetsHierarchyLocalFile.js +13 -13
  51. package/dist/commands/types/uploadRuleSets.js +13 -13
  52. package/dist/commands/types/uploadTypePolicies.js +16 -16
  53. package/dist/commands/types/uploadTypePropertyPolicies.js +16 -16
  54. package/dist/commands/types/uploadTypes.js +13 -13
  55. package/dist/commands/types/uploadUsageInfo.js +13 -13
  56. package/dist/commands/users/export.js +19 -20
  57. package/dist/commands/users/upload.js +8 -8
  58. package/dist/commands/webhooks/create.js +5 -5
  59. package/dist/commands/webhooks/delete.js +11 -11
  60. package/dist/commands/webhooks/getWebhookTrigger.js +5 -5
  61. package/dist/commands/webhooks/list.js +11 -11
  62. package/dist/commands/workflow-template-definitions/install.js +5 -5
  63. package/dist/commands/workflow-template-definitions/list.js +5 -5
  64. package/dist/commands/workflow-templates/delete.js +5 -5
  65. package/dist/commands/workflow-templates/export.js +19 -20
  66. package/dist/commands/workflow-templates/list.js +5 -5
  67. package/dist/commands/workflow-templates/load.js +11 -11
  68. package/dist/helpers/app/actions-deployer.js +4 -4
  69. package/dist/helpers/app/app-deployer.js +9 -9
  70. package/dist/helpers/app/app-template-parsers.js +1 -1
  71. package/dist/helpers/app/extensions-deployer.js +5 -6
  72. package/dist/helpers/app/load-app-config.js +1 -1
  73. package/dist/helpers/loader-process/helpers.js +3 -3
  74. package/dist/helpers/projects/helpers.js +5 -5
  75. package/dist/helpers/types/type-parser.js +8 -8
  76. package/dist/helpers/types/type-uploader.d.ts +17 -0
  77. package/dist/helpers/types/type-uploader.js +139 -92
  78. package/dist/helpers/types/type-uploader.spec.d.ts +1 -0
  79. package/dist/helpers/types/type-uploader.spec.js +119 -0
  80. package/dist/helpers/workflow-template-definitions/workflow-template-definition-deployer.js +3 -4
  81. package/dist/helpers/workflow-templates/helper.js +11 -16
  82. package/dist/interface-converters.js +1 -2
  83. package/dist/interfaces.js +79 -0
  84. package/dist/logger.js +7 -6
  85. package/oclif.manifest.json +60 -1422
  86. package/package.json +1 -1
@@ -10,7 +10,7 @@ function loadAppConfig(config = { skipValidation: false }) {
10
10
  const TARGET_DIR = process.cwd();
11
11
  try {
12
12
  const doc = js_yaml_1.default.load(fs_1.default.readFileSync(path.resolve(path.join(TARGET_DIR, 'app.yml')), 'utf8'));
13
- if (!(config === null || config === void 0 ? void 0 : config.skipValidation)) {
13
+ if (!config?.skipValidation) {
14
14
  (0, app_config_validators_1.validateAppConfig)(doc);
15
15
  }
16
16
  return doc;
@@ -91,9 +91,9 @@ async function loadLocalFile(configFileName) {
91
91
  exports.loadLocalFile = loadLocalFile;
92
92
  function getFileExtension(fileName) {
93
93
  let ext = '';
94
- const parts = fileName === null || fileName === void 0 ? void 0 : fileName.split('.');
95
- if ((parts === null || parts === void 0 ? void 0 : parts.length) > 1) {
96
- ext = `.${parts[(parts === null || parts === void 0 ? void 0 : parts.length) - 1]}`;
94
+ const parts = fileName?.split('.');
95
+ if (parts?.length > 1) {
96
+ ext = `.${parts[parts?.length - 1]}`;
97
97
  }
98
98
  return ext;
99
99
  }
@@ -53,7 +53,7 @@ async function getAssortmentsAndSubFolders(parentId, assortments, subFolders, al
53
53
  },
54
54
  });
55
55
  const integrationAssortments = workspaceAssortments; //?.filter(a => a.assortmentType === 'INTEGRATION');
56
- if ((integrationAssortments === null || integrationAssortments === void 0 ? void 0 : integrationAssortments.length) > 0) {
56
+ if (integrationAssortments?.length > 0) {
57
57
  allAssortments.push(...integrationAssortments);
58
58
  for (const a of integrationAssortments) {
59
59
  const integrationAssortmentsCopy = util_1.ObjectUtil.cloneDeep(a);
@@ -81,8 +81,8 @@ async function getAssortmentsAndSubFolders(parentId, assortments, subFolders, al
81
81
  },
82
82
  relations: ['entity'],
83
83
  });
84
- const workspaceFolders = workspaceFolderLinks === null || workspaceFolderLinks === void 0 ? void 0 : workspaceFolderLinks.map((wfl) => wfl.entity);
85
- if ((workspaceFolders === null || workspaceFolders === void 0 ? void 0 : workspaceFolders.length) > 0) {
84
+ const workspaceFolders = workspaceFolderLinks?.map((wfl) => wfl.entity);
85
+ if (workspaceFolders?.length > 0) {
86
86
  for (const folder of workspaceFolders) {
87
87
  const converted = {
88
88
  identifier: folder.identifier,
@@ -112,11 +112,11 @@ function convertRelationshipsToIdentifiers(assortments, allAssortments) {
112
112
  }
113
113
  for (const assortment of assortments) {
114
114
  if (assortment.sourceAssortmentIds) {
115
- assortment.sourceAssortmentIdentifier = assortment.sourceAssortmentIds.map((id) => { var _a; return (_a = allAssortments.find((a) => a.id === id)) === null || _a === void 0 ? void 0 : _a.identifier; });
115
+ assortment.sourceAssortmentIdentifier = assortment.sourceAssortmentIds.map((id) => allAssortments.find((a) => a.id === id)?.identifier);
116
116
  }
117
117
  delete assortment.sourceAssortmentIds;
118
118
  if (assortment.composedFromAssortmentIds) {
119
- assortment.composedFromAssortmentIdentifiers = assortment.composedFromAssortmentIds.map((id) => { var _a; return (_a = allAssortments.find((a) => a.id === id)) === null || _a === void 0 ? void 0 : _a.identifier; });
119
+ assortment.composedFromAssortmentIdentifiers = assortment.composedFromAssortmentIds.map((id) => allAssortments.find((a) => a.id === id)?.identifier);
120
120
  }
121
121
  delete assortment.composedFromAssortmentIds;
122
122
  }
@@ -27,7 +27,7 @@ async function parseTypesFromLocalFiles(fileLocations) {
27
27
  try {
28
28
  logger_1.default.info(`Getting data for fileLocation: ${fileLocation}`);
29
29
  const csvData = await loadDataFromLocalCSV(fileLocation);
30
- logger_1.default.info(`CSV import was successful. ${csvData === null || csvData === void 0 ? void 0 : csvData.length} rows found. Adding to total rows.`);
30
+ logger_1.default.info(`CSV import was successful. ${csvData?.length} rows found. Adding to total rows.`);
31
31
  csvJSONData.push(...csvData);
32
32
  }
33
33
  catch (e) {
@@ -35,7 +35,7 @@ async function parseTypesFromLocalFiles(fileLocations) {
35
35
  throw e;
36
36
  }
37
37
  }
38
- logger_1.default.info(`CSV imports were successful. ${csvJSONData === null || csvJSONData === void 0 ? void 0 : csvJSONData.length} total rows found.`);
38
+ logger_1.default.info(`CSV imports were successful. ${csvJSONData?.length} total rows found.`);
39
39
  const suggestions = (0, types_1.GetSuggestedTypes)(csvJSONData);
40
40
  saveData(suggestions.OptionSets, 'parsed_optionSets.yml');
41
41
  saveData({ typeProperties: suggestions.TypeProperties }, 'parsed_typeProperties.yml');
@@ -47,10 +47,10 @@ async function parseTypesFromTemplateFromLocalFiles(templateFileLocation, dataFi
47
47
  try {
48
48
  logger_1.default.info(`Getting template from fileLocation: ${templateFileLocation}`);
49
49
  templateCSVData = await loadDataFromLocalCSV(templateFileLocation);
50
- logger_1.default.info(`CSV import was successful. ${templateCSVData === null || templateCSVData === void 0 ? void 0 : templateCSVData.length} rows found.`);
50
+ logger_1.default.info(`CSV import was successful. ${templateCSVData?.length} rows found.`);
51
51
  logger_1.default.info(`Getting data from fileLocation: ${dataFileLocation}`);
52
52
  dataCSVData = await loadDataFromLocalCSV(dataFileLocation);
53
- logger_1.default.info(`CSV import was successful. ${dataCSVData === null || dataCSVData === void 0 ? void 0 : dataCSVData.length} rows found.`);
53
+ logger_1.default.info(`CSV import was successful. ${dataCSVData?.length} rows found.`);
54
54
  }
55
55
  catch (e) {
56
56
  logger_1.default.info(`Error importing csv data. ${e}`);
@@ -66,7 +66,7 @@ async function parseTypesFromTemplateAndDataFromLocalFiles(templateFileLocation,
66
66
  try {
67
67
  logger_1.default.info(`Getting template from fileLocation: ${templateFileLocation}`);
68
68
  templateCSVData = await loadDataFromLocalCSV(templateFileLocation);
69
- logger_1.default.info(`CSV import was successful. ${templateCSVData === null || templateCSVData === void 0 ? void 0 : templateCSVData.length} rows found.`);
69
+ logger_1.default.info(`CSV import was successful. ${templateCSVData?.length} rows found.`);
70
70
  }
71
71
  catch (e) {
72
72
  logger_1.default.info(`Error importing csv data. ${e}`);
@@ -77,7 +77,7 @@ async function parseTypesFromTemplateAndDataFromLocalFiles(templateFileLocation,
77
77
  try {
78
78
  logger_1.default.info(`Getting data for dataFileLocation: ${dataFileLocation}`);
79
79
  const csvData = await loadDataFromLocalCSV(dataFileLocation);
80
- logger_1.default.info(`CSV import was successful. ${csvData === null || csvData === void 0 ? void 0 : csvData.length} rows found. Adding to total rows.`);
80
+ logger_1.default.info(`CSV import was successful. ${csvData?.length} rows found. Adding to total rows.`);
81
81
  dataCSVData.push(...csvData);
82
82
  }
83
83
  catch (e) {
@@ -98,7 +98,7 @@ async function parseTypesFromFiles(fileIds) {
98
98
  try {
99
99
  logger_1.default.info(`Getting data for fileId: ${loadFileId}`);
100
100
  const csvJSON = await (0, csv_parser_1.getCSVFromFile)(loadFileId);
101
- logger_1.default.info(`CSV download was successful. ${csvJSON === null || csvJSON === void 0 ? void 0 : csvJSON.length} rows found. Adding to total rows`);
101
+ logger_1.default.info(`CSV download was successful. ${csvJSON?.length} rows found. Adding to total rows`);
102
102
  csvJSONData.push(...csvJSON);
103
103
  }
104
104
  catch (e) {
@@ -106,7 +106,7 @@ async function parseTypesFromFiles(fileIds) {
106
106
  throw e;
107
107
  }
108
108
  }
109
- logger_1.default.info(`CSV downloads were successful. ${csvJSONData === null || csvJSONData === void 0 ? void 0 : csvJSONData.length} total rows found.`);
109
+ logger_1.default.info(`CSV downloads were successful. ${csvJSONData?.length} total rows found.`);
110
110
  const suggestions = (0, types_1.GetSuggestedTypes)(csvJSONData);
111
111
  saveData(suggestions.OptionSets, 'parsed_optionSets.yml');
112
112
  saveData({ typeProperties: suggestions.TypeProperties }, 'parsed_typeProperties.yml');
@@ -1 +1,18 @@
1
1
  export declare function uploadTypes(dir: string): Promise<void>;
2
+ export interface ValueDiff {
3
+ adds: any[];
4
+ updates: any[];
5
+ deletions: any[];
6
+ }
7
+ /**
8
+ * compares the keys between different objects and returns the differences
9
+ * captures in adds, updates, and deletions. Object 1 is considered the
10
+ * original, and object 2 is considered the "edit".
11
+ *
12
+ * An add is a property that exists in object2 but not in 1. An edit
13
+ * is a property that exists in both object 1 and 2, but with different values.
14
+ * A deletion is a property in object 1 but not in object 2.
15
+ * @param object1 any object
16
+ * @param object2 any other object
17
+ */
18
+ export declare function extractValueDifferences(object1: object, object2: object, keysToIgnore: Array<string>): ValueDiff;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.uploadTypes = void 0;
3
+ exports.extractValueDifferences = exports.uploadTypes = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const sdk_1 = require("@contrail/sdk");
6
6
  const chalk_1 = tslib_1.__importDefault(require("chalk"));
@@ -61,6 +61,13 @@ async function uploadReducedTypes(dir) {
61
61
  for (const type of types) {
62
62
  newTypesBySlug[type.slug] = type;
63
63
  }
64
+ const optionSets = await new sdk_1.Entities().get({
65
+ entityName: 'type-property-option-set',
66
+ });
67
+ if (logger_1.default.isDebugEnabled()) {
68
+ fs_1.default.writeFileSync('reducedTypes.json', JSON.stringify(types, null, 2));
69
+ fs_1.default.writeFileSync('currentTypes.json', JSON.stringify(currentTypes, null, 2));
70
+ }
64
71
  for (const type of types) {
65
72
  try {
66
73
  const found = currentTypesBySlug[type.slug];
@@ -81,21 +88,47 @@ async function uploadReducedTypes(dir) {
81
88
  });
82
89
  const newTypeProperties = (await new sdk_1.Types().getType({ id: createdType.id }))
83
90
  .typeProperties;
84
- await uploadReducedTypeProperties(createdType, newTypeProperties, type.typeProperties);
91
+ await uploadReducedTypeProperties(createdType, newTypeProperties, type.typeProperties, optionSets);
85
92
  }
86
93
  else {
87
- logger_1.default.info(`Updating Type: ${type.slug}`);
88
- const updatedType = await new sdk_1.Entities().update({
89
- entityName: 'type',
90
- id: found.id,
91
- object: {
92
- slug: type.slug,
93
- label: type.label,
94
- typePath: type.typePath,
95
- isArchived: type.isArchived,
96
- },
97
- });
98
- await uploadReducedTypeProperties(updatedType, found.typeProperties, type.typeProperties);
94
+ const proposedType = {
95
+ slug: type.slug,
96
+ label: type.label,
97
+ typePath: type.typePath,
98
+ isArchived: type.isArchived,
99
+ };
100
+ const differences = extractValueDifferences(found, proposedType, [
101
+ 'id',
102
+ 'createdOn',
103
+ 'updatedOn',
104
+ 'createdById',
105
+ 'updatedById',
106
+ 'orgId',
107
+ 'typeRootId',
108
+ 'parentId',
109
+ 'typePolicyIds',
110
+ 'typePolicies',
111
+ 'typeProperties',
112
+ 'typePropertyPolicies',
113
+ 'typeRuleSets',
114
+ 'typeOptionSetHierarchyLinks',
115
+ 'relations',
116
+ 'typeInterfaces',
117
+ ]);
118
+ let updatedType = found;
119
+ if (differences.updates.length || differences.adds.length || differences.deletions.length) {
120
+ logger_1.default.debug(`found differences: ${JSON.stringify(differences, null, 2)}`);
121
+ logger_1.default.info(`Updating Type: ${type.slug}`);
122
+ updatedType = await new sdk_1.Entities().update({
123
+ entityName: 'type',
124
+ id: found.id,
125
+ object: proposedType,
126
+ });
127
+ }
128
+ else {
129
+ logger_1.default.debug(`Skipping empty update of type ${type.slug}`);
130
+ }
131
+ await uploadReducedTypeProperties(updatedType, found.typeProperties, type.typeProperties, optionSets);
99
132
  }
100
133
  }
101
134
  catch (err) {
@@ -103,8 +136,7 @@ async function uploadReducedTypes(dir) {
103
136
  }
104
137
  }
105
138
  }
106
- async function uploadReducedTypeProperties(type, currentPropertyTypes, newPropertyTypes) {
107
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
139
+ async function uploadReducedTypeProperties(type, currentPropertyTypes, newPropertyTypes, optionSets) {
108
140
  const currentPropertyTypeBySlug = {};
109
141
  for (const currentPropertyType of currentPropertyTypes) {
110
142
  currentPropertyTypeBySlug[currentPropertyType.slug] = currentPropertyType;
@@ -113,9 +145,6 @@ async function uploadReducedTypeProperties(type, currentPropertyTypes, newProper
113
145
  for (const newPropertyType of newPropertyTypes) {
114
146
  newPropertyTypesBySlug[newPropertyType.slug] = newPropertyType;
115
147
  }
116
- const optionSets = await new sdk_1.Entities().get({
117
- entityName: 'type-property-option-set',
118
- });
119
148
  const optionSetIdBySlug = {};
120
149
  for (const optionSet of optionSets) {
121
150
  optionSetIdBySlug[optionSet.slug] = optionSet.id;
@@ -123,7 +152,7 @@ async function uploadReducedTypeProperties(type, currentPropertyTypes, newProper
123
152
  for (const newPropertyType of newPropertyTypes) {
124
153
  try {
125
154
  const found = currentPropertyTypeBySlug[newPropertyType.slug];
126
- if (!found && !newPropertyType.inherited) {
155
+ if (!found) {
127
156
  logger_1.default.info(`Creating Type-Property: ${newPropertyType.slug}`);
128
157
  await sdk_1.Request.request(`/types/${type.id}/type-properties`, {
129
158
  method: 'POST',
@@ -154,35 +183,68 @@ async function uploadReducedTypeProperties(type, currentPropertyTypes, newProper
154
183
  },
155
184
  });
156
185
  }
157
- else if (found &&
158
- !newPropertyType.inherited &&
159
- !typePropertiesEqual(found, newPropertyType, optionSetIdBySlug)) {
160
- logger_1.default.info(`Updating Type-Property: ${newPropertyType.slug}`);
161
- await new sdk_1.Entities().update({
162
- entityName: 'type-property',
163
- id: found.id,
164
- object: {
165
- isArchived: (_a = newPropertyType.isArchived) !== null && _a !== void 0 ? _a : null,
166
- propertyType: (_b = newPropertyType.propertyType) !== null && _b !== void 0 ? _b : null,
167
- slug: (_c = newPropertyType.slug) !== null && _c !== void 0 ? _c : null,
168
- label: (_d = newPropertyType.label) !== null && _d !== void 0 ? _d : null,
169
- editable: (_e = newPropertyType.editable) !== null && _e !== void 0 ? _e : null,
170
- searchable: (_f = newPropertyType.searchable) !== null && _f !== void 0 ? _f : null,
171
- core: (_g = newPropertyType.core) !== null && _g !== void 0 ? _g : null,
172
- typePropertyOptionSetId: (_h = optionSetIdBySlug[newPropertyType.typePropertyOptionSetSlug]) !== null && _h !== void 0 ? _h : null,
173
- formula: (_j = newPropertyType.formula) !== null && _j !== void 0 ? _j : null,
174
- referencedTypePath: (_k = newPropertyType.referencedTypePath) !== null && _k !== void 0 ? _k : null,
175
- carryOverBehavior: (_l = newPropertyType.carryOverBehavior) !== null && _l !== void 0 ? _l : null,
176
- carryOverDefault: (_m = newPropertyType.carryOverDefault) !== null && _m !== void 0 ? _m : null,
177
- referencedTypeRootSlug: (_o = newPropertyType.referencedTypeRootSlug) !== null && _o !== void 0 ? _o : null,
178
- defaultValue: (_p = newPropertyType.defaultValue) !== null && _p !== void 0 ? _p : null,
179
- propertyLevel: (_q = newPropertyType.propertyLevel) !== null && _q !== void 0 ? _q : null,
180
- formulaFunction: (_r = newPropertyType.formulaFunction) !== null && _r !== void 0 ? _r : null,
181
- validationFunction: (_s = newPropertyType.validationFunction) !== null && _s !== void 0 ? _s : null,
182
- numberFormat: (_t = newPropertyType.numberFormat) !== null && _t !== void 0 ? _t : null,
183
- sequenceSeedValue: (_u = newPropertyType.sequenceSeedValue) !== null && _u !== void 0 ? _u : null,
184
- },
185
- });
186
+ else if (found
187
+ // !newPropertyType.inherited &&
188
+ // !typePropertiesEqual(found, newPropertyType, optionSetIdBySlug)
189
+ ) {
190
+ const proposedTP = {
191
+ isArchived: newPropertyType.isArchived ?? null,
192
+ propertyType: newPropertyType.propertyType ?? null,
193
+ slug: newPropertyType.slug ?? null,
194
+ label: newPropertyType.label ?? null,
195
+ editable: newPropertyType.editable ?? null,
196
+ searchable: newPropertyType.searchable ?? null,
197
+ core: newPropertyType.core ?? null,
198
+ typePropertyOptionSetId: optionSetIdBySlug[newPropertyType.typePropertyOptionSetSlug] ?? null,
199
+ formula: newPropertyType.formula ?? null,
200
+ referencedTypePath: newPropertyType.referencedTypePath ?? null,
201
+ carryOverBehavior: newPropertyType.carryOverBehavior ?? null,
202
+ carryOverDefault: newPropertyType.carryOverDefault ?? null,
203
+ referencedTypeRootSlug: newPropertyType.referencedTypeRootSlug ?? null,
204
+ defaultValue: newPropertyType.defaultValue ?? null,
205
+ propertyLevel: newPropertyType.propertyLevel ?? null,
206
+ formulaFunction: newPropertyType.formulaFunction ?? null,
207
+ validationFunction: newPropertyType.validationFunction ?? null,
208
+ numberFormat: newPropertyType.numberFormat ?? null,
209
+ sequenceSeedValue: newPropertyType.sequenceSeedValue ?? null,
210
+ };
211
+ // logger.debug(
212
+ // `found type property option set: ${newPropertyType.typePropertyOptionSetSlug}, ${proposedTP.typePropertyOptionSetId}, `,
213
+ // );
214
+ const differences = extractValueDifferences(found, proposedTP, [
215
+ 'id',
216
+ 'createdOn',
217
+ 'updatedOn',
218
+ 'createdById',
219
+ 'updatedById',
220
+ 'orgId',
221
+ 'typePropertyUserListId',
222
+ 'referencedTypeRole',
223
+ 'referencedTypeFilterProperties',
224
+ 'referencedTypeId',
225
+ 'description',
226
+ 'apiDetails',
227
+ 'notes',
228
+ 'isFederationProperty',
229
+ 'required',
230
+ 'optionsSet',
231
+ 'options',
232
+ 'inherited',
233
+ 'used',
234
+ 'typePropertyPolicyIds',
235
+ ]);
236
+ if (differences.updates.length || differences.adds.length || differences.deletions.length) {
237
+ logger_1.default.debug(`found differences: ${JSON.stringify(differences, null, 2)}`);
238
+ logger_1.default.debug(`Updating Type-Property: ${newPropertyType.slug}, ${found.id}, ${JSON.stringify(proposedTP, null, 2)}`);
239
+ await new sdk_1.Entities().update({
240
+ entityName: 'type-property',
241
+ id: found.id,
242
+ object: proposedTP,
243
+ });
244
+ }
245
+ else {
246
+ logger_1.default.debug(`Skipping empty update of type property ${newPropertyType.slug}`);
247
+ }
186
248
  }
187
249
  }
188
250
  catch (err) {
@@ -208,48 +270,33 @@ async function uploadReducedTypeProperties(type, currentPropertyTypes, newProper
208
270
  }
209
271
  }
210
272
  }
211
- function typePropertiesEqual(typeProperty1, typeProperty2, optionSetIdByIdentifier) {
212
- const reducedProperty1 = {
213
- isArchived: typeProperty1.isArchived,
214
- propertyType: typeProperty1.propertyType,
215
- slug: typeProperty1.slug,
216
- label: typeProperty1.label,
217
- editable: typeProperty1.editable,
218
- searchable: typeProperty1.searchable,
219
- core: typeProperty1.core,
220
- typePropertyOptionSetId: optionSetIdByIdentifier[typeProperty1.typePropertyOptionSetSlug],
221
- formula: typeProperty1.formula,
222
- referencedTypePath: typeProperty1.referencedTypePath,
223
- referencedTypeRootSlug: typeProperty1.referencedTypeRootSlug,
224
- defaultValue: typeProperty1.defaultValue,
225
- propertyLevel: typeProperty1.propertyLevel,
226
- carryOverBehavior: typeProperty1.carryOverBehavior,
227
- carryOverDefault: typeProperty1.carryOverDefault,
228
- formulaFunction: typeProperty1.formulaFunction,
229
- validationFunction: typeProperty1.validationFunction,
230
- numberFormat: typeProperty1.numberFormat,
231
- sequenceSeedValue: typeProperty1.sequenceSeedValue,
232
- };
233
- const reducedProperty2 = {
234
- isArchived: typeProperty2.isArchived,
235
- propertyType: typeProperty2.propertyType,
236
- slug: typeProperty2.slug,
237
- label: typeProperty2.label,
238
- editable: typeProperty2.editable,
239
- searchable: typeProperty2.searchable,
240
- core: typeProperty2.core,
241
- typePropertyOptionSetId: optionSetIdByIdentifier[typeProperty2.typePropertyOptionSetSlug],
242
- formula: typeProperty2.formula,
243
- referencedTypePath: typeProperty2.referencedTypePath,
244
- referencedTypeRootSlug: typeProperty2.referencedTypeRootSlug,
245
- defaultValue: typeProperty2.defaultValue,
246
- propertyLevel: typeProperty2.propertyLevel,
247
- carryOverBehavior: typeProperty2.carryOverBehavior,
248
- carryOverDefault: typeProperty2.carryOverDefault,
249
- formulaFunction: typeProperty2.formulaFunction,
250
- validationFunction: typeProperty2.validationFunction,
251
- numberFormat: typeProperty2.numberFormat,
252
- sequenceSeedValue: typeProperty2.sequenceSeedValue,
273
+ /**
274
+ * compares the keys between different objects and returns the differences
275
+ * captures in adds, updates, and deletions. Object 1 is considered the
276
+ * original, and object 2 is considered the "edit".
277
+ *
278
+ * An add is a property that exists in object2 but not in 1. An edit
279
+ * is a property that exists in both object 1 and 2, but with different values.
280
+ * A deletion is a property in object 1 but not in object 2.
281
+ * @param object1 any object
282
+ * @param object2 any other object
283
+ */
284
+ function extractValueDifferences(object1, object2, keysToIgnore) {
285
+ const updates = [];
286
+ const object1Keys = Object.keys(object1);
287
+ const object2keys = Object.keys(object2);
288
+ const adds = object2keys.filter((key) => !object1Keys.includes(key) && !keysToIgnore.includes(key));
289
+ const deletions = object1Keys.filter((key) => !object2keys.includes(key) && !keysToIgnore.includes(key));
290
+ const shared = object1Keys.filter((key) => object2keys.includes(key) && !keysToIgnore.includes(key));
291
+ for (const key of shared) {
292
+ if (!_.isEqual(object1[key], object2[key])) {
293
+ updates.push(key);
294
+ }
295
+ }
296
+ return {
297
+ adds,
298
+ updates,
299
+ deletions,
253
300
  };
254
- return _.isEqual(reducedProperty1, reducedProperty2);
255
301
  }
302
+ exports.extractValueDifferences = extractValueDifferences;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const type_uploader_1 = require("./type-uploader");
4
+ describe('extractValueDifferences', () => {
5
+ it('should return the correct value differences', () => {
6
+ const object1 = {
7
+ name: 'John',
8
+ age: 30,
9
+ city: 'New York',
10
+ };
11
+ const object2 = {
12
+ name: 'John',
13
+ age: 35,
14
+ city: 'Los Angeles',
15
+ country: 'USA',
16
+ };
17
+ const expectedValueDiff = {
18
+ adds: ['country'],
19
+ updates: ['age', 'city'],
20
+ deletions: [],
21
+ };
22
+ const valueDiff = (0, type_uploader_1.extractValueDifferences)(object1, object2, []);
23
+ expect(valueDiff).toEqual(expectedValueDiff);
24
+ });
25
+ it('should handle empty objects', () => {
26
+ const object1 = {};
27
+ const object2 = {};
28
+ const expectedValueDiff = {
29
+ adds: [],
30
+ updates: [],
31
+ deletions: [],
32
+ };
33
+ const valueDiff = (0, type_uploader_1.extractValueDifferences)(object1, object2, []);
34
+ expect(valueDiff).toEqual(expectedValueDiff);
35
+ });
36
+ it('should handle objects with no shared keys', () => {
37
+ const object1 = {
38
+ name: 'John',
39
+ age: 30,
40
+ };
41
+ const object2 = {
42
+ city: 'New York',
43
+ country: 'USA',
44
+ };
45
+ const expectedValueDiff = {
46
+ adds: ['city', 'country'],
47
+ updates: [],
48
+ deletions: ['name', 'age'],
49
+ };
50
+ const valueDiff = (0, type_uploader_1.extractValueDifferences)(object1, object2, []);
51
+ expect(valueDiff).toEqual(expectedValueDiff);
52
+ });
53
+ it('should handle objects with shared keys but no differences', () => {
54
+ const object1 = {
55
+ name: 'John',
56
+ age: 30,
57
+ };
58
+ const object2 = {
59
+ name: 'John',
60
+ age: 30,
61
+ };
62
+ const expectedValueDiff = {
63
+ adds: [],
64
+ updates: [],
65
+ deletions: [],
66
+ };
67
+ const valueDiff = (0, type_uploader_1.extractValueDifferences)(object1, object2, []);
68
+ expect(valueDiff).toEqual(expectedValueDiff);
69
+ });
70
+ it('should handle correctly ignore keys on deletion', () => {
71
+ const object1 = {
72
+ name: 'John',
73
+ age: 30,
74
+ };
75
+ const object2 = {
76
+ name: 'John',
77
+ };
78
+ const expectedValueDiff = {
79
+ adds: [],
80
+ updates: [],
81
+ deletions: [],
82
+ };
83
+ const valueDiff = (0, type_uploader_1.extractValueDifferences)(object1, object2, ['age']);
84
+ expect(valueDiff).toEqual(expectedValueDiff);
85
+ });
86
+ it('should handle correctly ignore keys on updates', () => {
87
+ const object1 = {
88
+ name: 'John',
89
+ age: 30,
90
+ };
91
+ const object2 = {
92
+ name: 'John',
93
+ age: 15,
94
+ };
95
+ const expectedValueDiff = {
96
+ adds: [],
97
+ updates: [],
98
+ deletions: [],
99
+ };
100
+ const valueDiff = (0, type_uploader_1.extractValueDifferences)(object1, object2, ['age']);
101
+ expect(valueDiff).toEqual(expectedValueDiff);
102
+ });
103
+ it('should handle correctly ignore keys on deletion', () => {
104
+ const object1 = {
105
+ name: 'John',
106
+ };
107
+ const object2 = {
108
+ name: 'John',
109
+ age: 30,
110
+ };
111
+ const expectedValueDiff = {
112
+ adds: [],
113
+ updates: [],
114
+ deletions: [],
115
+ };
116
+ const valueDiff = (0, type_uploader_1.extractValueDifferences)(object1, object2, ['age']);
117
+ expect(valueDiff).toEqual(expectedValueDiff);
118
+ });
119
+ });
@@ -95,7 +95,7 @@ class WorkflowTemplateDefinitionDeployer {
95
95
  logger_1.default.info('WORKFLOW DEFINITION \tDeploying workflow definitions.');
96
96
  if (appDeclaration.workflows) {
97
97
  const localWorkflows = Object.keys(appDeclaration.workflows);
98
- if ((localWorkflows === null || localWorkflows === void 0 ? void 0 : localWorkflows.length) > 0) {
98
+ if (localWorkflows?.length > 0) {
99
99
  for (const workflowKey of localWorkflows) {
100
100
  await this.deployWorkflow(workflowKey, appDeclaration.workflows[workflowKey], app, existingWorkflows);
101
101
  }
@@ -131,13 +131,12 @@ class WorkflowTemplateDefinitionDeployer {
131
131
  return workflowTemplate;
132
132
  }
133
133
  async populateActionIds(workflowDefinition, app) {
134
- var _a;
135
134
  const availableAppActions = await (0, actions_deployer_1.getActionsForAppVersion)(app);
136
- if (!((_a = workflowDefinition.workflowDefinition) === null || _a === void 0 ? void 0 : _a.paths)) {
135
+ if (!workflowDefinition.workflowDefinition?.paths) {
137
136
  return;
138
137
  }
139
138
  for (const path of workflowDefinition.workflowDefinition.paths) {
140
- if (!(path === null || path === void 0 ? void 0 : path.actionDefinitionConfigs)) {
139
+ if (!path?.actionDefinitionConfigs) {
141
140
  continue;
142
141
  }
143
142
  for (const actionConfiguration of path.actionDefinitionConfigs) {