@contrail/cli 1.0.50 → 1.0.53

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.
package/lib/cli.js CHANGED
@@ -4,6 +4,7 @@ import { getTypes } from './types/types-extractor';
4
4
  import { uploadTypes } from './types/types-uploader';
5
5
  import { UploadOptionSets } from './types/option-set-uploader';
6
6
  import { ParseOptionSetsLocalFiles } from './types/option-set-parser';
7
+ import { ParseOptionSetsHierarchyLocalFiles, UploadOptionSetsHierarchyLocalFiles } from './types/option-set-hierarchy-parser';
7
8
  import { MergeOptionSets } from './types/option-set-merger';
8
9
  import { MergeTypeProperties } from './types/types-properties-merger';
9
10
  import { ParseTypesFromFiles, ParseTypesFromLocalFiles, ParseTypesFromTemplateFromLocalFiles, ParseTypesFromTemplateAndDataFromLocalFiles } from './types/parse-types';
@@ -14,6 +15,7 @@ import { installApp, uninstallApp } from './apps/install-app/app-installer';
14
15
  import { upgradeApp } from './apps/upgrade-app/app-upgrader';
15
16
  import { cliInstallWorkflowTemplateDefinitions, listWorkflowTemplateDefinitions } from './workflow-template-definitions/workflow-template-definition-commands';
16
17
  import { configureProject } from './projects/project-uploader';
18
+ import { ListProjects, ExportProject } from './projects/project-exporter';
17
19
  import { Load, UploadAndLoad } from './loader-process/loader-process';
18
20
  const cliUsage = require('command-line-usage');
19
21
  /**
@@ -91,6 +93,14 @@ export async function cli(args) {
91
93
  ParseOptionSetsLocalFiles(args);
92
94
  break;
93
95
  }
96
+ case 'parseOptionSetsHierarchyLocalFiles': {
97
+ ParseOptionSetsHierarchyLocalFiles(args);
98
+ break;
99
+ }
100
+ case 'uploadOptionSetsHierarchyLocalFiles': {
101
+ UploadOptionSetsHierarchyLocalFiles(args);
102
+ break;
103
+ }
94
104
  case 'parseTypesFromLocalFiles': {
95
105
  ParseTypesFromLocalFiles(args);
96
106
  break;
@@ -155,10 +165,18 @@ export async function cli(args) {
155
165
  }
156
166
  case 'projects': {
157
167
  switch (command) {
158
- case 'configure': {
168
+ case 'load': {
159
169
  await configureProject(args);
160
170
  break;
161
171
  }
172
+ case 'list': {
173
+ await ListProjects();
174
+ break;
175
+ }
176
+ case 'export': {
177
+ await ExportProject(args);
178
+ break;
179
+ }
162
180
  default: {
163
181
  printIllegalCommand();
164
182
  }
@@ -307,8 +325,16 @@ const helpSections = [
307
325
  {
308
326
  header: 'Project Commands - Domain: projects',
309
327
  content: [{
310
- name: 'configure',
328
+ name: 'load <File Path>',
311
329
  summary: 'Configure a project from a yml file.'
330
+ },
331
+ {
332
+ name: 'list',
333
+ summary: 'Get a list of all projects.'
334
+ },
335
+ {
336
+ name: 'export <Project Name>',
337
+ summary: 'Export a project.'
312
338
  }
313
339
  ],
314
340
  },
@@ -358,7 +384,15 @@ const helpSections = [
358
384
  },
359
385
  {
360
386
  name: 'parseOptionSetsLocalFiles <File Paths>',
361
- summary: 'Parse CSV files into OptionSets'
387
+ summary: 'Parse CSV files into OptionSets.'
388
+ },
389
+ {
390
+ name: 'parseOptionSetsHierarchyLocalFiles <File Paths>',
391
+ summary: 'Parse CSV files into OptionSetHierarchies.'
392
+ },
393
+ {
394
+ name: 'uploadOptionSetsHierarchyLocalFiles <File Paths> <name>',
395
+ summary: 'upload CSV files into OptionSetHierarchies.'
362
396
  },
363
397
  {
364
398
  name: 'parseTypesFromLocalFiles <File Paths>',
@@ -0,0 +1,2 @@
1
+ export declare function ListProjects(): Promise<void>;
2
+ export declare function ExportProject(args: any): Promise<void>;
@@ -0,0 +1,163 @@
1
+ import { Entities } from '@contrail/sdk';
2
+ import { ObjectUtil } from '@contrail/util';
3
+ import chalk from 'chalk';
4
+ import fs from 'fs';
5
+ import { authUser } from '../auth/login';
6
+ import { getSeparatorByPlatform } from '../common';
7
+ import yaml from 'js-yaml';
8
+ export async function ListProjects() {
9
+ try {
10
+ await authUser();
11
+ console.log('%s Getting Projects.', chalk.blue.bold('START'));
12
+ await listProjects();
13
+ console.log('%s Done', chalk.yellow.bold('PROJECTS'));
14
+ }
15
+ catch (e) {
16
+ console.log(`%s Project download Failed. ${e}`, chalk.red.bold('FAIL'));
17
+ return;
18
+ }
19
+ console.log('%s Project download Complete.', chalk.green.bold('COMPLETE'));
20
+ }
21
+ export async function ExportProject(args) {
22
+ try {
23
+ await authUser();
24
+ console.log('%s Exporting Project.', chalk.blue.bold('START'));
25
+ console.log('%s Exporting', chalk.yellow.bold('PROJECT'));
26
+ const projectName = args[3];
27
+ await exportProject(projectName);
28
+ console.log('%s Exported', chalk.yellow.bold('PROJECT'));
29
+ }
30
+ catch (e) {
31
+ console.log(`%s Project Export Failed. ${e}`, chalk.red.bold('FAIL'));
32
+ return;
33
+ }
34
+ console.log('%s Project Export Complete.', chalk.green.bold('COMPLETE'));
35
+ }
36
+ async function listProjects() {
37
+ const allWorkspaces = await new Entities().get({
38
+ entityName: 'workspace',
39
+ criteria: { isArchived: false }
40
+ });
41
+ console.log('%s', chalk.green.bold('PROJECTS:'));
42
+ //console.log(allWorkspaces.map(w => Object.assign({}, {name: w.name, id: w.id}))); // if we want ids
43
+ console.log(allWorkspaces.map(w => w.name));
44
+ }
45
+ async function exportProject(name) {
46
+ const allWorkspaces = await new Entities().get({
47
+ entityName: 'workspace',
48
+ useSearch: false,
49
+ });
50
+ const workspace = allWorkspaces.find(w => w.name === name);
51
+ if (!workspace) {
52
+ throw new Error('Project was not found.');
53
+ }
54
+ const projectConfiguration = {
55
+ projectName: workspace.name,
56
+ identifier: workspace.identifier,
57
+ commonConfig: {},
58
+ assortments: [],
59
+ subFolders: []
60
+ };
61
+ const allAssortments = [];
62
+ await getAssortmentsAndSubFolders(workspace.id, projectConfiguration.assortments, projectConfiguration.subFolders, allAssortments);
63
+ await convertRelationshipsInFolders(projectConfiguration, allAssortments);
64
+ saveData({ projectConfiguration: projectConfiguration }, name);
65
+ }
66
+ async function getAssortmentsAndSubFolders(parentId, assortments, subFolders, allAssortments) {
67
+ const workspaceAssortments = await new Entities().get({
68
+ entityName: 'assortment',
69
+ criteria: {
70
+ workspaceId: parentId,
71
+ }
72
+ });
73
+ const integrationAssortments = workspaceAssortments === null || workspaceAssortments === void 0 ? void 0 : workspaceAssortments.filter(a => a.assortmentType === 'INTEGRATION');
74
+ if ((integrationAssortments === null || integrationAssortments === void 0 ? void 0 : integrationAssortments.length) > 0) {
75
+ allAssortments.push(...integrationAssortments);
76
+ for (const a of integrationAssortments) {
77
+ const integrationAssortmentsCopy = ObjectUtil.cloneDeep(a);
78
+ deleteNonUserKeys(integrationAssortmentsCopy);
79
+ const converted = {
80
+ identifier: a.identifier,
81
+ name: a.name,
82
+ type: 'ASSORTMENT',
83
+ sourceAssortmentIdentifier: [],
84
+ sourceAssortmentIds: a.sourceAssortmentIds,
85
+ composedFromAssortmentIdentifiers: [],
86
+ composedFromAssortmentIds: a.composedFromAssortmentIds,
87
+ assortmentAtts: Object.assign({}, integrationAssortmentsCopy),
88
+ };
89
+ assortments.push(converted);
90
+ }
91
+ }
92
+ console.log('workspaceFolderLinks call');
93
+ const workspaceFolderLinks = await new Entities().get({
94
+ entityName: 'workspace-entity',
95
+ criteria: {
96
+ workspaceId: parentId,
97
+ entityType: 'workspace'
98
+ },
99
+ relations: ['entity']
100
+ });
101
+ const workspaceFolders = workspaceFolderLinks === null || workspaceFolderLinks === void 0 ? void 0 : workspaceFolderLinks.map(wfl => wfl.entity);
102
+ if ((workspaceFolders === null || workspaceFolders === void 0 ? void 0 : workspaceFolders.length) > 0) {
103
+ for (const folder of workspaceFolders) {
104
+ const converted = {
105
+ identifier: folder.identifier,
106
+ name: folder.name,
107
+ assortments: [],
108
+ subFolders: [],
109
+ };
110
+ await getAssortmentsAndSubFolders(folder.id, converted.assortments, converted.subFolders, allAssortments);
111
+ subFolders.push(converted);
112
+ }
113
+ }
114
+ }
115
+ async function convertRelationshipsInFolders(folder, allAssortments) {
116
+ if (!(allAssortments.length > 0)) {
117
+ return;
118
+ }
119
+ convertRelationshipsToIdentifiers(folder.assortments, allAssortments);
120
+ for (const f of folder.subFolders) {
121
+ convertRelationshipsInFolders(f, allAssortments);
122
+ }
123
+ }
124
+ function convertRelationshipsToIdentifiers(assortments, allAssortments) {
125
+ if (!(allAssortments.length > 0)) {
126
+ return;
127
+ }
128
+ for (const assortment of assortments) {
129
+ if (assortment.sourceAssortmentIds) {
130
+ assortment.sourceAssortmentIdentifier = assortment.sourceAssortmentIds.map(id => { var _a; return (_a = allAssortments.find(a => a.id === id)) === null || _a === void 0 ? void 0 : _a.identifier; });
131
+ }
132
+ delete assortment.sourceAssortmentIds;
133
+ if (assortment.composedFromAssortmentIds) {
134
+ assortment.composedFromAssortmentIdentifiers = assortment.composedFromAssortmentIds.map(id => { var _a; return (_a = allAssortments.find(a => a.id === id)) === null || _a === void 0 ? void 0 : _a.identifier; });
135
+ }
136
+ delete assortment.composedFromAssortmentIds;
137
+ }
138
+ }
139
+ function deleteNonUserKeys(assortment) {
140
+ delete assortment.name;
141
+ delete assortment.identifier;
142
+ delete assortment.assortmentType;
143
+ delete assortment.createdById;
144
+ delete assortment.createdForReference;
145
+ delete assortment.createdOn;
146
+ delete assortment.entityType;
147
+ delete assortment.id;
148
+ delete assortment.orgId;
149
+ delete assortment.rootWorkspaceId;
150
+ delete assortment.composedFromAssortmentIds;
151
+ delete assortment.sourceAssortmentIds;
152
+ delete assortment.typeId;
153
+ delete assortment.typePath;
154
+ delete assortment.updatedById;
155
+ delete assortment.updatedOn;
156
+ delete assortment.workspaceId;
157
+ }
158
+ function saveData(data, name) {
159
+ const yamlStr = yaml.dump(data);
160
+ const CURRENT_DIR = process.cwd();
161
+ const separator = getSeparatorByPlatform();
162
+ fs.writeFileSync(CURRENT_DIR + separator + name + '-export.yml', yamlStr, 'utf8');
163
+ }
@@ -0,0 +1,2 @@
1
+ export declare function ParseOptionSetsHierarchyLocalFiles(args: any): Promise<void>;
2
+ export declare function UploadOptionSetsHierarchyLocalFiles(args: any): Promise<void>;
@@ -0,0 +1,140 @@
1
+ import fs from 'fs';
2
+ import { getSeparatorByPlatform } from '../common';
3
+ import chalk from 'chalk';
4
+ const csv = require('csvtojson');
5
+ import { Entities } from '@contrail/sdk';
6
+ import { StringUtil } from '@contrail/util';
7
+ import { authUser } from '../auth/login';
8
+ export async function ParseOptionSetsHierarchyLocalFiles(args) {
9
+ try {
10
+ await authUser();
11
+ if ((args === null || args === void 0 ? void 0 : args.length) < 4) {
12
+ throw new Error('File name must be included.');
13
+ }
14
+ console.log('%s Importing local file', chalk.yellow.bold('OPTION SET HIERARCHY PARSE'));
15
+ const fileLocation = args[3];
16
+ console.log('Using File: ', fileLocation);
17
+ await parseAndSaveOptionSetHierarchiesLocalFiles(fileLocation);
18
+ console.log('%s Parsed', chalk.yellow.bold('OPTION SET HIERARCHY PARSE'));
19
+ }
20
+ catch (e) {
21
+ console.log(`%s PARSE Failed. ${e}`, chalk.red.bold('FAIL'));
22
+ return;
23
+ }
24
+ console.log('%s PARSE Complete.', chalk.green.bold('COMPLETE'));
25
+ }
26
+ export async function UploadOptionSetsHierarchyLocalFiles(args) {
27
+ try {
28
+ await authUser();
29
+ if ((args === null || args === void 0 ? void 0 : args.length) < 4) {
30
+ throw new Error('File name must be included.');
31
+ }
32
+ console.log('%s Importing local file', chalk.yellow.bold('OPTION SET HIERARCHY UPLOAD'));
33
+ const fileLocation = args[3];
34
+ const name = args[4];
35
+ console.log('Using File: ', fileLocation);
36
+ console.log('Using Name: ', name);
37
+ await uploadOptionSetHierarchiesLocalFiles(fileLocation, name);
38
+ console.log('%s Uploaded', chalk.yellow.bold('OPTION SET HIERARCHY UPLOAD'));
39
+ }
40
+ catch (e) {
41
+ console.log(`%s UPLOAD Failed. ${e}`, chalk.red.bold('FAIL'));
42
+ return;
43
+ }
44
+ console.log('%s UPLOAD Complete.', chalk.green.bold('COMPLETE'));
45
+ }
46
+ async function loadOptionSetHierarchyCSV(fileLocation) {
47
+ const TARGET_DIR = process.cwd();
48
+ try {
49
+ const separator = getSeparatorByPlatform();
50
+ const fullPath = TARGET_DIR + separator + fileLocation;
51
+ console.log('Getting file from path: ', fullPath);
52
+ return await csv().fromFile(fullPath);
53
+ }
54
+ catch (e) {
55
+ throw new Error(`ERROR PARSING CSV: ${e}`);
56
+ }
57
+ }
58
+ async function parseOptionSetHierarchiesLocalFiles(fileLocation) {
59
+ const uploadedOptionHierarchyData = await loadOptionSetHierarchyCSV(fileLocation);
60
+ const optionSetHierarchy = {
61
+ hierarchy: [],
62
+ maxDepth: 0,
63
+ name: 'No Name',
64
+ options: []
65
+ };
66
+ if (!((uploadedOptionHierarchyData === null || uploadedOptionHierarchyData === void 0 ? void 0 : uploadedOptionHierarchyData.length) > 0)) {
67
+ return optionSetHierarchy;
68
+ }
69
+ const keysInOrder = Object.keys(uploadedOptionHierarchyData[0]);
70
+ const currentOptionSets = await new Entities().get({
71
+ entityName: 'type-property-option-set',
72
+ });
73
+ const currentOptionSetsByName = {};
74
+ for (const currentOptionSet of currentOptionSets) {
75
+ currentOptionSetsByName[StringUtil.convertToCamelCase(currentOptionSet.name)] = currentOptionSet;
76
+ }
77
+ const optionSetIds = [];
78
+ for (const key of keysInOrder) {
79
+ if (currentOptionSetsByName[key]) {
80
+ optionSetIds.push(currentOptionSetsByName[key].id);
81
+ }
82
+ else {
83
+ throw new Error(`No OptionSet found for ${key}`);
84
+ }
85
+ }
86
+ optionSetHierarchy.maxDepth = keysInOrder.length;
87
+ optionSetHierarchy.hierarchy = optionSetIds;
88
+ for (const row of uploadedOptionHierarchyData) {
89
+ addRowToOptions(optionSetHierarchy, keysInOrder, row);
90
+ }
91
+ return optionSetHierarchy;
92
+ }
93
+ async function parseAndSaveOptionSetHierarchiesLocalFiles(fileLocation) {
94
+ const optionSetHierarchy = await parseOptionSetHierarchiesLocalFiles(fileLocation);
95
+ saveData(optionSetHierarchy.options);
96
+ }
97
+ async function uploadOptionSetHierarchiesLocalFiles(fileLocation, name) {
98
+ const optionSetHierarchy = await parseOptionSetHierarchiesLocalFiles(fileLocation);
99
+ optionSetHierarchy.name = name;
100
+ const currentOptionSetHierarchies = await new Entities().get({
101
+ entityName: 'option-set-hierarchy',
102
+ });
103
+ const existing = currentOptionSetHierarchies.find(osh => osh.name === name);
104
+ if (existing) {
105
+ console.log('Updating: ', optionSetHierarchy.name);
106
+ await new Entities().update({
107
+ entityName: 'option-set-hierarchy',
108
+ id: existing.id,
109
+ object: optionSetHierarchy,
110
+ });
111
+ }
112
+ else {
113
+ console.log('Creating: ', optionSetHierarchy.name);
114
+ await new Entities().create({
115
+ entityName: 'option-set-hierarchy',
116
+ object: optionSetHierarchy,
117
+ });
118
+ }
119
+ }
120
+ function addRowToOptions(optionSetHierarchy, keysInOrder, row) {
121
+ let options = optionSetHierarchy.options;
122
+ for (let i = 0; i < keysInOrder.length; i++) {
123
+ const optionValues = options.map(op => op.value);
124
+ const value = row[keysInOrder[i]];
125
+ if (!optionValues.includes(value)) {
126
+ const obj = i === (keysInOrder.length - 1) ? { value: value } : { value: value, options: [] };
127
+ options.push(obj);
128
+ options = obj.options;
129
+ }
130
+ else {
131
+ const optionObj = options.find(op => op.value === value);
132
+ options = optionObj.options;
133
+ }
134
+ }
135
+ }
136
+ function saveData(data) {
137
+ const CURRENT_DIR = process.cwd();
138
+ const separator = getSeparatorByPlatform();
139
+ fs.writeFileSync(CURRENT_DIR + separator + 'parsed_local_optionSetHierarchy.json', JSON.stringify(data), 'utf8');
140
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrail/cli",
3
- "version": "1.0.50",
3
+ "version": "1.0.53",
4
4
  "description": "VibeIQ's Contrail Platform CLI.",
5
5
  "main": "lib/index.js",
6
6
  "bin": {
@@ -23,7 +23,7 @@
23
23
  "author": "",
24
24
  "license": "ISC",
25
25
  "dependencies": {
26
- "@contrail/sdk": "^1.1.43",
26
+ "@contrail/sdk": "^1.1.52",
27
27
  "@contrail/types": "^3.0.20",
28
28
  "@contrail/util": "^1.0.17",
29
29
  "amazon-cognito-identity-js": "^5.2.3",
package/src/cli.ts CHANGED
@@ -5,6 +5,7 @@ import { getTypes } from './types/types-extractor';
5
5
  import { uploadTypes } from './types/types-uploader';
6
6
  import { UploadOptionSets } from './types/option-set-uploader';
7
7
  import { ParseOptionSetsLocalFiles } from './types/option-set-parser';
8
+ import { ParseOptionSetsHierarchyLocalFiles, UploadOptionSetsHierarchyLocalFiles } from './types/option-set-hierarchy-parser';
8
9
  import { MergeOptionSets } from './types/option-set-merger';
9
10
  import { MergeTypeProperties } from './types/types-properties-merger';
10
11
  import { ParseTypesFromFiles, ParseTypesFromLocalFiles, ParseTypesFromTemplateFromLocalFiles, ParseTypesFromTemplateAndDataFromLocalFiles } from './types/parse-types';
@@ -15,6 +16,7 @@ import { installApp, uninstallApp } from './apps/install-app/app-installer';
15
16
  import { upgradeApp } from './apps/upgrade-app/app-upgrader';
16
17
  import { cliInstallWorkflowTemplateDefinitions, listWorkflowTemplateDefinitions } from './workflow-template-definitions/workflow-template-definition-commands';
17
18
  import { configureProject } from './projects/project-uploader';
19
+ import { ListProjects, ExportProject } from './projects/project-exporter';
18
20
  import { Load, UploadAndLoad } from './loader-process/loader-process';
19
21
 
20
22
  const cliUsage = require('command-line-usage');
@@ -101,6 +103,14 @@ export async function cli(args) {
101
103
  ParseOptionSetsLocalFiles(args);
102
104
  break;
103
105
  }
106
+ case 'parseOptionSetsHierarchyLocalFiles': {
107
+ ParseOptionSetsHierarchyLocalFiles(args);
108
+ break;
109
+ }
110
+ case 'uploadOptionSetsHierarchyLocalFiles': {
111
+ UploadOptionSetsHierarchyLocalFiles(args);
112
+ break;
113
+ }
104
114
  case 'parseTypesFromLocalFiles': {
105
115
  ParseTypesFromLocalFiles(args);
106
116
  break;
@@ -165,10 +175,18 @@ export async function cli(args) {
165
175
  }
166
176
  case 'projects': {
167
177
  switch (command) {
168
- case 'configure': {
178
+ case 'load': {
169
179
  await configureProject(args);
170
180
  break;
171
181
  }
182
+ case 'list': {
183
+ await ListProjects();
184
+ break;
185
+ }
186
+ case 'export': {
187
+ await ExportProject(args);
188
+ break;
189
+ }
172
190
  default: {
173
191
  printIllegalCommand();
174
192
  }
@@ -322,8 +340,16 @@ const helpSections = [
322
340
  {
323
341
  header: 'Project Commands - Domain: projects',
324
342
  content: [{
325
- name: 'configure',
343
+ name: 'load <File Path>',
326
344
  summary: 'Configure a project from a yml file.'
345
+ },
346
+ {
347
+ name: 'list',
348
+ summary: 'Get a list of all projects.'
349
+ },
350
+ {
351
+ name: 'export <Project Name>',
352
+ summary: 'Export a project.'
327
353
  }
328
354
  ],
329
355
  },
@@ -373,7 +399,15 @@ const helpSections = [
373
399
  },
374
400
  {
375
401
  name: 'parseOptionSetsLocalFiles <File Paths>',
376
- summary: 'Parse CSV files into OptionSets'
402
+ summary: 'Parse CSV files into OptionSets.'
403
+ },
404
+ {
405
+ name: 'parseOptionSetsHierarchyLocalFiles <File Paths>',
406
+ summary: 'Parse CSV files into OptionSetHierarchies.'
407
+ },
408
+ {
409
+ name: 'uploadOptionSetsHierarchyLocalFiles <File Paths> <name>',
410
+ summary: 'upload CSV files into OptionSetHierarchies.'
377
411
  },
378
412
  {
379
413
  name: 'parseTypesFromLocalFiles <File Paths>',
@@ -0,0 +1,194 @@
1
+ import { Entities } from '@contrail/sdk';
2
+ import { ObjectUtil } from '@contrail/util';
3
+ import chalk from 'chalk';
4
+ import fs from 'fs';
5
+ import { authUser } from '../auth/login';
6
+ import { getSeparatorByPlatform } from '../common';
7
+ import yaml from 'js-yaml';
8
+
9
+ export async function ListProjects() {
10
+ try {
11
+ await authUser();
12
+ console.log('%s Getting Projects.', chalk.blue.bold('START'));
13
+
14
+ await listProjects();
15
+ console.log('%s Done', chalk.yellow.bold('PROJECTS'));
16
+
17
+ }
18
+ catch (e) {
19
+ console.log(`%s Project download Failed. ${e}`, chalk.red.bold('FAIL'));
20
+ return;
21
+ }
22
+
23
+ console.log('%s Project download Complete.', chalk.green.bold('COMPLETE'));
24
+ }
25
+
26
+ export async function ExportProject(args) {
27
+ try {
28
+ await authUser();
29
+ console.log('%s Exporting Project.', chalk.blue.bold('START'));
30
+
31
+ console.log('%s Exporting', chalk.yellow.bold('PROJECT'));
32
+ const projectName = args[3];
33
+ await exportProject(projectName);
34
+ console.log('%s Exported', chalk.yellow.bold('PROJECT'));
35
+
36
+ }
37
+ catch (e) {
38
+ console.log(`%s Project Export Failed. ${e}`, chalk.red.bold('FAIL'));
39
+ return;
40
+ }
41
+
42
+ console.log('%s Project Export Complete.', chalk.green.bold('COMPLETE'));
43
+ }
44
+
45
+ async function listProjects() {
46
+ const allWorkspaces = await new Entities().get({
47
+ entityName: 'workspace',
48
+ criteria: {isArchived: false}
49
+ });
50
+
51
+ console.log('%s', chalk.green.bold('PROJECTS:'));
52
+ //console.log(allWorkspaces.map(w => Object.assign({}, {name: w.name, id: w.id}))); // if we want ids
53
+ console.log(allWorkspaces.map(w => w.name));
54
+ }
55
+
56
+ async function exportProject(name) {
57
+ const allWorkspaces = await new Entities().get({
58
+ entityName: 'workspace',
59
+ useSearch: false,
60
+ });
61
+
62
+ const workspace = allWorkspaces.find(w => w.name === name);
63
+ if (!workspace) {
64
+ throw new Error('Project was not found.');
65
+ }
66
+
67
+ const projectConfiguration = {
68
+ projectName: workspace.name,
69
+ identifier: workspace.identifier,
70
+ commonConfig: {},
71
+ assortments: [],
72
+ subFolders: []
73
+ };
74
+
75
+ const allAssortments = [];
76
+ await getAssortmentsAndSubFolders(workspace.id, projectConfiguration.assortments, projectConfiguration.subFolders, allAssortments);
77
+ await convertRelationshipsInFolders(projectConfiguration, allAssortments);
78
+ saveData({projectConfiguration: projectConfiguration}, name);
79
+ }
80
+
81
+ async function getAssortmentsAndSubFolders(parentId, assortments, subFolders, allAssortments) {
82
+ const workspaceAssortments = await new Entities().get({
83
+ entityName: 'assortment',
84
+ criteria: {
85
+ workspaceId: parentId,
86
+ }
87
+ });
88
+
89
+ const integrationAssortments = workspaceAssortments?.filter(a => a.assortmentType === 'INTEGRATION');
90
+
91
+ if (integrationAssortments?.length > 0) {
92
+ allAssortments.push(...integrationAssortments);
93
+ for (const a of integrationAssortments) {
94
+ const integrationAssortmentsCopy = ObjectUtil.cloneDeep(a);
95
+ deleteNonUserKeys(integrationAssortmentsCopy);
96
+ const converted = {
97
+ identifier: a.identifier,
98
+ name: a.name,
99
+ type: 'ASSORTMENT',
100
+ sourceAssortmentIdentifier: [],
101
+ sourceAssortmentIds: a.sourceAssortmentIds,
102
+ composedFromAssortmentIdentifiers: [],
103
+ composedFromAssortmentIds: a.composedFromAssortmentIds,
104
+ assortmentAtts: Object.assign({}, integrationAssortmentsCopy),
105
+ };
106
+ assortments.push(converted);
107
+ }
108
+ }
109
+
110
+ console.log('workspaceFolderLinks call');
111
+
112
+ const workspaceFolderLinks = await new Entities().get({
113
+ entityName: 'workspace-entity',
114
+ criteria: {
115
+ workspaceId: parentId,
116
+ entityType: 'workspace'
117
+ },
118
+ relations: ['entity']
119
+ });
120
+
121
+ const workspaceFolders = workspaceFolderLinks?.map(wfl => wfl.entity);
122
+
123
+ if (workspaceFolders?.length > 0) {
124
+ for (const folder of workspaceFolders) {
125
+ const converted = {
126
+ identifier: folder.identifier,
127
+ name: folder.name,
128
+ assortments: [],
129
+ subFolders: [],
130
+ };
131
+ await getAssortmentsAndSubFolders(folder.id, converted.assortments, converted.subFolders, allAssortments);
132
+ subFolders.push(converted);
133
+ }
134
+ }
135
+
136
+ }
137
+
138
+ async function convertRelationshipsInFolders(folder, allAssortments) {
139
+ if (!(allAssortments.length > 0)) {
140
+ return;
141
+ }
142
+
143
+ convertRelationshipsToIdentifiers(folder.assortments, allAssortments);
144
+
145
+ for (const f of folder.subFolders) {
146
+ convertRelationshipsInFolders(f, allAssortments);
147
+ }
148
+
149
+ }
150
+
151
+ function convertRelationshipsToIdentifiers(assortments, allAssortments) {
152
+ if (!(allAssortments.length > 0)) {
153
+ return;
154
+ }
155
+
156
+ for (const assortment of assortments) {
157
+ if (assortment.sourceAssortmentIds) {
158
+ assortment.sourceAssortmentIdentifier = assortment.sourceAssortmentIds.map(id => allAssortments.find(a => a.id === id)?.identifier);
159
+ }
160
+ delete assortment.sourceAssortmentIds;
161
+
162
+ if (assortment.composedFromAssortmentIds) {
163
+ assortment.composedFromAssortmentIdentifiers = assortment.composedFromAssortmentIds.map(id => allAssortments.find(a => a.id === id)?.identifier);
164
+ }
165
+ delete assortment.composedFromAssortmentIds;
166
+ }
167
+ }
168
+
169
+ function deleteNonUserKeys(assortment) {
170
+ delete assortment.name;
171
+ delete assortment.identifier;
172
+ delete assortment.assortmentType;
173
+ delete assortment.createdById;
174
+ delete assortment.createdForReference;
175
+ delete assortment.createdOn;
176
+ delete assortment.entityType;
177
+ delete assortment.id;
178
+ delete assortment.orgId;
179
+ delete assortment.rootWorkspaceId;
180
+ delete assortment.composedFromAssortmentIds;
181
+ delete assortment.sourceAssortmentIds;
182
+ delete assortment.typeId;
183
+ delete assortment.typePath;
184
+ delete assortment.updatedById;
185
+ delete assortment.updatedOn;
186
+ delete assortment.workspaceId;
187
+ }
188
+
189
+ function saveData(data, name) {
190
+ const yamlStr = yaml.dump(data);
191
+ const CURRENT_DIR = process.cwd();
192
+ const separator = getSeparatorByPlatform();
193
+ fs.writeFileSync(CURRENT_DIR + separator + name + '-export.yml', yamlStr, 'utf8');
194
+ }
@@ -0,0 +1,169 @@
1
+ import fs from 'fs';
2
+ import { getSeparatorByPlatform } from '../common';
3
+ import chalk from 'chalk';
4
+ const csv = require('csvtojson');
5
+ import { Entities } from '@contrail/sdk';
6
+ import { StringUtil } from '@contrail/util';
7
+ import { authUser } from '../auth/login';
8
+
9
+ export async function ParseOptionSetsHierarchyLocalFiles(args) {
10
+ try {
11
+ await authUser();
12
+
13
+ if (args?.length < 4) {
14
+ throw new Error('File name must be included.');
15
+ }
16
+ console.log('%s Importing local file', chalk.yellow.bold('OPTION SET HIERARCHY PARSE'));
17
+ const fileLocation = args[3];
18
+ console.log('Using File: ', fileLocation);
19
+
20
+ await parseAndSaveOptionSetHierarchiesLocalFiles(fileLocation);
21
+ console.log('%s Parsed', chalk.yellow.bold('OPTION SET HIERARCHY PARSE'));
22
+
23
+ }
24
+ catch (e) {
25
+ console.log(`%s PARSE Failed. ${e}`, chalk.red.bold('FAIL'));
26
+ return;
27
+ }
28
+
29
+ console.log('%s PARSE Complete.', chalk.green.bold('COMPLETE'));
30
+ }
31
+
32
+ export async function UploadOptionSetsHierarchyLocalFiles(args) {
33
+ try {
34
+ await authUser();
35
+
36
+ if (args?.length < 4) {
37
+ throw new Error('File name must be included.');
38
+ }
39
+ console.log('%s Importing local file', chalk.yellow.bold('OPTION SET HIERARCHY UPLOAD'));
40
+ const fileLocation = args[3];
41
+ const name = args[4];
42
+ console.log('Using File: ', fileLocation);
43
+ console.log('Using Name: ', name);
44
+
45
+ await uploadOptionSetHierarchiesLocalFiles(fileLocation, name);
46
+ console.log('%s Uploaded', chalk.yellow.bold('OPTION SET HIERARCHY UPLOAD'));
47
+
48
+ }
49
+ catch (e) {
50
+ console.log(`%s UPLOAD Failed. ${e}`, chalk.red.bold('FAIL'));
51
+ return;
52
+ }
53
+
54
+ console.log('%s UPLOAD Complete.', chalk.green.bold('COMPLETE'));
55
+ }
56
+
57
+ async function loadOptionSetHierarchyCSV(fileLocation) {
58
+ const TARGET_DIR = process.cwd();
59
+ try {
60
+ const separator = getSeparatorByPlatform();
61
+
62
+ const fullPath = TARGET_DIR + separator + fileLocation;
63
+ console.log('Getting file from path: ', fullPath);
64
+
65
+ return await csv().fromFile(fullPath);
66
+ } catch (e) {
67
+ throw new Error(`ERROR PARSING CSV: ${e}`);
68
+ }
69
+ }
70
+
71
+ async function parseOptionSetHierarchiesLocalFiles(fileLocation) {
72
+ const uploadedOptionHierarchyData = await loadOptionSetHierarchyCSV(fileLocation);
73
+
74
+ const optionSetHierarchy = {
75
+ hierarchy:[],
76
+ maxDepth: 0,
77
+ name: 'No Name',
78
+ options: []
79
+ };
80
+
81
+ if (!(uploadedOptionHierarchyData?.length > 0)) {
82
+ return optionSetHierarchy;
83
+ }
84
+
85
+ const keysInOrder = Object.keys(uploadedOptionHierarchyData[0]);
86
+ const currentOptionSets = await new Entities().get({
87
+ entityName: 'type-property-option-set',
88
+ });
89
+
90
+ const currentOptionSetsByName = {};
91
+ for (const currentOptionSet of currentOptionSets) {
92
+ currentOptionSetsByName[StringUtil.convertToCamelCase(currentOptionSet.name)] = currentOptionSet;
93
+ }
94
+
95
+ const optionSetIds = [];
96
+ for(const key of keysInOrder) {
97
+ if (currentOptionSetsByName[key]) {
98
+ optionSetIds.push(currentOptionSetsByName[key].id);
99
+ }
100
+ else {
101
+ throw new Error(`No OptionSet found for ${key}`);
102
+ }
103
+ }
104
+
105
+ optionSetHierarchy.maxDepth = keysInOrder.length;
106
+ optionSetHierarchy.hierarchy = optionSetIds;
107
+
108
+ for (const row of uploadedOptionHierarchyData) {
109
+ addRowToOptions(optionSetHierarchy, keysInOrder, row);
110
+ }
111
+
112
+ return optionSetHierarchy;
113
+ }
114
+
115
+ async function parseAndSaveOptionSetHierarchiesLocalFiles(fileLocation) {
116
+ const optionSetHierarchy = await parseOptionSetHierarchiesLocalFiles(fileLocation);
117
+ saveData(optionSetHierarchy.options);
118
+ }
119
+
120
+ async function uploadOptionSetHierarchiesLocalFiles(fileLocation, name) {
121
+ const optionSetHierarchy = await parseOptionSetHierarchiesLocalFiles(fileLocation);
122
+ optionSetHierarchy.name = name;
123
+
124
+ const currentOptionSetHierarchies = await new Entities().get({
125
+ entityName: 'option-set-hierarchy',
126
+ });
127
+
128
+ const existing = currentOptionSetHierarchies.find(osh => osh.name === name);
129
+
130
+ if (existing) {
131
+ console.log('Updating: ', optionSetHierarchy.name);
132
+ await new Entities().update({
133
+ entityName: 'option-set-hierarchy',
134
+ id: existing.id,
135
+ object: optionSetHierarchy,
136
+ });
137
+ }
138
+ else {
139
+ console.log('Creating: ', optionSetHierarchy.name);
140
+ await new Entities().create({
141
+ entityName: 'option-set-hierarchy',
142
+ object: optionSetHierarchy,
143
+ });
144
+ }
145
+ }
146
+
147
+ function addRowToOptions(optionSetHierarchy, keysInOrder, row) {
148
+ let options: any[] = optionSetHierarchy.options;
149
+
150
+ for (let i = 0; i < keysInOrder.length; i++) {
151
+ const optionValues = options.map(op => op.value);
152
+ const value = row[keysInOrder[i]];
153
+ if (!optionValues.includes(value)) {
154
+ const obj = i === (keysInOrder.length - 1) ? {value: value} : {value: value, options: []};
155
+ options.push(obj);
156
+ options = obj.options;
157
+ }
158
+ else {
159
+ const optionObj = options.find(op => op.value === value);
160
+ options = optionObj.options;
161
+ }
162
+ }
163
+ }
164
+
165
+ function saveData(data) {
166
+ const CURRENT_DIR = process.cwd();
167
+ const separator = getSeparatorByPlatform();
168
+ fs.writeFileSync(CURRENT_DIR + separator + 'parsed_local_optionSetHierarchy.json', JSON.stringify(data), 'utf8');
169
+ }