@c8y/ngx-components 1017.0.338 → 1017.0.343

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 (28) hide show
  1. package/core/common/date.pipe.d.ts +2 -2
  2. package/core/common/stringify-object.pipe.d.ts +2 -1
  3. package/ecosystem/packages/deploy-application/deploy-application.component.d.ts +6 -5
  4. package/ecosystem/shared/ecosystem.constants.d.ts +2 -0
  5. package/ecosystem/shared/ecosystem.model.d.ts +3 -1
  6. package/ecosystem/shared/ecosystem.service.d.ts +11 -5
  7. package/esm2020/core/common/date.pipe.mjs +12 -7
  8. package/esm2020/core/common/stringify-object.pipe.mjs +11 -8
  9. package/esm2020/ecosystem/application-properties/application-properties.component.mjs +3 -3
  10. package/esm2020/ecosystem/applications/install-from-package/install-from-package.component.mjs +2 -2
  11. package/esm2020/ecosystem/packages/deploy-application/deploy-application.component.mjs +26 -81
  12. package/esm2020/ecosystem/shared/ecosystem.constants.mjs +5 -3
  13. package/esm2020/ecosystem/shared/ecosystem.model.mjs +3 -1
  14. package/esm2020/ecosystem/shared/ecosystem.service.mjs +121 -24
  15. package/fesm2015/c8y-ngx-components-ecosystem-shared.mjs +139 -27
  16. package/fesm2015/c8y-ngx-components-ecosystem-shared.mjs.map +1 -1
  17. package/fesm2015/c8y-ngx-components-ecosystem.mjs +23 -77
  18. package/fesm2015/c8y-ngx-components-ecosystem.mjs.map +1 -1
  19. package/fesm2015/c8y-ngx-components.mjs +20 -13
  20. package/fesm2015/c8y-ngx-components.mjs.map +1 -1
  21. package/fesm2020/c8y-ngx-components-ecosystem-shared.mjs +126 -25
  22. package/fesm2020/c8y-ngx-components-ecosystem-shared.mjs.map +1 -1
  23. package/fesm2020/c8y-ngx-components-ecosystem.mjs +23 -78
  24. package/fesm2020/c8y-ngx-components-ecosystem.mjs.map +1 -1
  25. package/fesm2020/c8y-ngx-components.mjs +20 -13
  26. package/fesm2020/c8y-ngx-components.mjs.map +1 -1
  27. package/locales/locales.pot +15 -3
  28. package/package.json +2 -2
@@ -10,7 +10,7 @@ import * as i3 from '@c8y/client';
10
10
  import { ApplicationAvailability, ApplicationType } from '@c8y/client';
11
11
  import * as i2$1 from '@ngx-translate/core';
12
12
  import { saveAs } from 'file-saver';
13
- import { groupBy, uniqBy, get, pick, kebabCase, cloneDeep } from 'lodash-es';
13
+ import { groupBy, uniqBy, get, pick, omit, isUndefined, kebabCase, cloneDeep } from 'lodash-es';
14
14
  import { BehaviorSubject, defer, merge, combineLatest } from 'rxjs';
15
15
  import { map, shareReplay, debounceTime, take, distinctUntilKeyChanged, tap, filter, switchMap } from 'rxjs/operators';
16
16
  import { gt, coerce } from 'semver';
@@ -32,6 +32,7 @@ var ERROR_TYPE;
32
32
  (function (ERROR_TYPE) {
33
33
  ERROR_TYPE["TYPE_VALIDATION"] = "TYPE_VALIDATION";
34
34
  ERROR_TYPE["ALREADY_SUBSCRIBED"] = "ALREADY_SUBSCRIBED";
35
+ ERROR_TYPE["ALREADY_EXIST"] = "ALREADY_EXIST";
35
36
  ERROR_TYPE["INTERNAL_ERROR"] = "INTERNAL_ERROR";
36
37
  ERROR_TYPE["NO_MANIFEST_FILE"] = "NO_MANIFEST_FILE";
37
38
  ERROR_TYPE["INVALID_PACKAGE"] = "INVALID_PACKAGE";
@@ -39,6 +40,7 @@ var ERROR_TYPE;
39
40
  ERROR_TYPE["MICROSERVICE_NAME_TOO_LONG"] = "MICROSERVICE_NAME_TOO_LONG";
40
41
  ERROR_TYPE["APPLICATION_CREATION_FAILED"] = "APPLICATION_CREATION_FAILED";
41
42
  ERROR_TYPE["KEY_OR_CONTEXT_PATH_MISMATCH"] = "KEY_OR_CONTEXT_PATH_MISMATCH";
43
+ ERROR_TYPE["VERSION_NOT_FOUND"] = "VERSION_NOT_FOUND";
42
44
  })(ERROR_TYPE || (ERROR_TYPE = {}));
43
45
  const PRODUCT_EXPERIENCE = {
44
46
  APPLICATIONS: {
@@ -91,6 +93,7 @@ const PRODUCT_EXPERIENCE = {
91
93
  };
92
94
 
93
95
  const ERROR_MESSAGES = {
96
+ [ERROR_TYPE.ALREADY_EXIST]: gettext('Could not deploy the application, as the application with the same name, context-path or key exist already.'),
94
97
  [ERROR_TYPE.TYPE_VALIDATION]: gettext('Wrong file format. Expected a *.zip file with a valid manifest.'),
95
98
  [ERROR_TYPE.ALREADY_SUBSCRIBED]: gettext('Could not subscribe to the microservice because another application with the same context path is already subscribed.'),
96
99
  [ERROR_TYPE.NO_MANIFEST_FILE]: gettext('Could not find a manifest.'),
@@ -99,7 +102,8 @@ const ERROR_MESSAGES = {
99
102
  [ERROR_TYPE.INTERNAL_ERROR]: gettext('An internal error occurred, try to upload again.'),
100
103
  [ERROR_TYPE.MICROSERVICE_NAME_TOO_LONG]: gettext('Microservice name "{{ name }}" must not be longer than {{ maxChars }} characters.'),
101
104
  [ERROR_TYPE.APPLICATION_CREATION_FAILED]: gettext('Application creation failed.'),
102
- [ERROR_TYPE.KEY_OR_CONTEXT_PATH_MISMATCH]: gettext('The contextPath or key of the uploaded archive do not match with the existing app.')
105
+ [ERROR_TYPE.KEY_OR_CONTEXT_PATH_MISMATCH]: gettext('The "contextPath`KEEP_ORIGINAL`" or "key`KEEP_ORIGINAL`" of the uploaded archive do not match with the existing application.'),
106
+ [ERROR_TYPE.VERSION_NOT_FOUND]: gettext('The selected version was not found on the server.')
103
107
  };
104
108
  const APP_STATE = {
105
109
  SUBSCRIBED: {
@@ -129,7 +133,7 @@ const APP_STATE = {
129
133
  };
130
134
  const packageProperties = [
131
135
  {
132
- label: gettext('Version'),
136
+ label: gettext('Latest version'),
133
137
  key: 'version'
134
138
  },
135
139
  {
@@ -264,6 +268,14 @@ class EcosystemService {
264
268
  return webApps.sort((a, b) => a.name.localeCompare(b.name));
265
269
  }
266
270
  async getPackageApplications(customFilter = {}) {
271
+ const filterCallback = app => this.isPackage(app);
272
+ return this.getApplicationsFiltered(customFilter, filterCallback);
273
+ }
274
+ async getHostedAndPackageApplications(customFilter = {}) {
275
+ const filterCallback = app => this.isPackage(app) || this.isApplication(app);
276
+ return this.getApplicationsFiltered(customFilter, filterCallback);
277
+ }
278
+ async getApplicationsFiltered(customFilter = {}, filterCallback = (app) => !!app) {
267
279
  const filter = Object.assign({}, customFilter);
268
280
  const sharedFilter = Object.assign({
269
281
  availability: ApplicationAvailability.SHARED,
@@ -274,7 +286,7 @@ class EcosystemService {
274
286
  this.getApplications(filter),
275
287
  this.applicationService.list(sharedFilter)
276
288
  ]);
277
- const webApps = [...apps, ...shared].filter(app => this.isPackage(app));
289
+ const webApps = [...apps, ...shared].filter(filterCallback);
278
290
  // an app could be subscribed to a tenant, but also have it's availability set to SHARED, in that case it would occur twice.
279
291
  const uniqWebApps = uniqBy(webApps, (app) => app.id);
280
292
  return uniqWebApps.sort((a, b) => a.name.localeCompare(b.name));
@@ -357,18 +369,6 @@ class EcosystemService {
357
369
  };
358
370
  return config;
359
371
  }
360
- async updateAppManifest(application, sourcePackage) {
361
- const { id } = application;
362
- const cleanedApp = this.removeAppProperties(application);
363
- if (!cleanedApp.manifest) {
364
- cleanedApp.manifest = {};
365
- }
366
- cleanedApp.manifest.isPackage = false;
367
- cleanedApp.manifest.source = sourcePackage.id;
368
- return await this.applicationService
369
- .binary(id)
370
- .updateFiles([{ path: CUMULOCITY_JSON, contents: JSON.stringify(cleanedApp) }]);
371
- }
372
372
  async listArchives(appId) {
373
373
  const filter = {
374
374
  pageSize: 100
@@ -576,6 +576,78 @@ class EcosystemService {
576
576
  this.alertError(ex);
577
577
  }
578
578
  }
579
+ async deployApp(selectedPackage, formGroupValue, model) {
580
+ // Create new app config
581
+ const config = this.createConfig(selectedPackage, formGroupValue);
582
+ const requestedVersion = model.selected.version;
583
+ let cleanManifest;
584
+ try {
585
+ const manifest = await this.applicationService.getAppManifest(selectedPackage, requestedVersion);
586
+ cleanManifest = omit(manifest, ['name', 'contextPath', 'key']);
587
+ }
588
+ catch (ex) {
589
+ throw new EcosystemError(ERROR_TYPE.VERSION_NOT_FOUND);
590
+ }
591
+ config.isSetup = true;
592
+ config.manifest = cleanManifest;
593
+ config.availability = ApplicationAvailability.PRIVATE;
594
+ config.manifest.isPackage = false;
595
+ config.manifest.source = selectedPackage.id;
596
+ config.manifest.package = 'blueprint';
597
+ // because of a issue with SHARED availability we always should check again
598
+ // if the app not exist already
599
+ const allExistingApps = await this.getHostedAndPackageApplications();
600
+ const doesAppKeyOrContextPathExist = this.checkIfAppNameKeyPathExists(allExistingApps, config);
601
+ if (doesAppKeyOrContextPathExist) {
602
+ throw new EcosystemError(ERROR_TYPE.ALREADY_EXIST);
603
+ }
604
+ // Create new app
605
+ const newApp = (await this.applicationService.create(config)).data;
606
+ try {
607
+ // Binary upload can fail if SHARED package
608
+ // in this case, catch error and fall back to
609
+ // clone API.
610
+ await this.uploadBinaryFromOtherPackage(selectedPackage, newApp, model.selected.binaryId, requestedVersion);
611
+ }
612
+ catch (error) {
613
+ if (error?.res?.status === 404) {
614
+ await this.fallbackToClone(newApp, selectedPackage, requestedVersion);
615
+ }
616
+ }
617
+ return newApp;
618
+ }
619
+ async fallbackToClone(application, selectedPackage, requestedVersion) {
620
+ let wasSuccess = true;
621
+ let clonedPkg;
622
+ try {
623
+ clonedPkg = (await this.applicationService.clone(selectedPackage, requestedVersion)).data;
624
+ await this.uploadBinaryFromOtherPackage(selectedPackage, application, clonedPkg.activeVersionId, requestedVersion, clonedPkg);
625
+ }
626
+ catch (error) {
627
+ this.alertError(error);
628
+ wasSuccess = false;
629
+ }
630
+ finally {
631
+ await this.deleteApp(clonedPkg, true);
632
+ }
633
+ return wasSuccess;
634
+ }
635
+ async uploadBinaryFromOtherPackage(selectedPackage, applicationToUploadBinaryTo, binaryId, requestedVersion, useBinariesFrom) {
636
+ const { data: binaryDetails } = await this.inventoryService.detail(binaryId);
637
+ // Get binary from specific package version
638
+ const binary = await this.getBinary(useBinariesFrom || selectedPackage, {
639
+ id: binaryId
640
+ });
641
+ // Create zip
642
+ const fileBinary = new Blob([binary], { type: binaryDetails.contentType });
643
+ const file = new File([fileBinary], binaryDetails.name, {
644
+ type: binaryDetails.contentType
645
+ });
646
+ // Upload binary to new app
647
+ await this.uploadArchiveToApp(file, applicationToUploadBinaryTo);
648
+ // update the app manifest
649
+ await this.updateAppManifest(applicationToUploadBinaryTo, selectedPackage, requestedVersion);
650
+ }
579
651
  getAppState(app) {
580
652
  if (!this.isOwner(app)) {
581
653
  return APP_STATE.SUBSCRIBED;
@@ -657,6 +729,43 @@ class EcosystemService {
657
729
  throw new EcosystemError(ERROR_TYPE.KEY_OR_CONTEXT_PATH_MISMATCH);
658
730
  }
659
731
  }
732
+ filterContainString(name, filterTerm) {
733
+ const term = filterTerm.toLowerCase().trim();
734
+ return name && name.toLowerCase().indexOf(term) > -1;
735
+ }
736
+ async updateAppManifest(application, selectedPackage, requestedVersion) {
737
+ const { id } = application;
738
+ const cleanedApp = this.removeAppProperties(application);
739
+ let manifest = selectedPackage.manifest || {};
740
+ if (requestedVersion) {
741
+ try {
742
+ const versionedAppManifest = await this.applicationService.getAppManifest(selectedPackage, requestedVersion);
743
+ manifest = versionedAppManifest;
744
+ }
745
+ catch (ex) {
746
+ throw new EcosystemError(ERROR_TYPE.VERSION_NOT_FOUND);
747
+ }
748
+ }
749
+ cleanedApp.manifest = manifest;
750
+ cleanedApp.manifest.isPackage = false;
751
+ cleanedApp.manifest.source = selectedPackage.id;
752
+ return await this.applicationService
753
+ .binary(id)
754
+ .updateFiles([{ path: CUMULOCITY_JSON, contents: JSON.stringify(cleanedApp) }]);
755
+ }
756
+ checkIfAppNameKeyPathExists(existingApps, app, retryNo) {
757
+ if (isUndefined(retryNo)) {
758
+ return existingApps.find(existingApp => existingApp.name === app.name ||
759
+ existingApp.key === app.key ||
760
+ existingApp.contextPath === app.contextPath);
761
+ }
762
+ return existingApps.find(existingApp => existingApp.name === app.name ||
763
+ existingApp.key === app.key ||
764
+ existingApp.contextPath === app.contextPath ||
765
+ existingApp.name === [app.name, retryNo].join('-') ||
766
+ existingApp.key === [app.key, retryNo].join('-') ||
767
+ existingApp.contextPath === [app.contextPath, retryNo].join('-'));
768
+ }
660
769
  getAppKey(appModel, name) {
661
770
  let key = appModel?.key;
662
771
  if (!key) {
@@ -693,17 +802,9 @@ class EcosystemService {
693
802
  }
694
803
  return baseName;
695
804
  }
696
- checkIfAppNameKeyPathExists(existingApps, app, retryNo) {
697
- return existingApps.find(existingApp => existingApp.name === app.name ||
698
- existingApp.key === app.key ||
699
- existingApp.contextPath === app.contextPath ||
700
- existingApp.name === [app.name, retryNo].join('-') ||
701
- existingApp.key === [app.key, retryNo].join('-') ||
702
- existingApp.contextPath === [app.contextPath, retryNo].join('-'));
703
- }
704
805
  removeAppProperties(app) {
705
806
  const tempApp = cloneDeep(app);
706
- const propertiesToRemove = ['id', 'owner', 'activeVersionId', 'self'];
807
+ const propertiesToRemove = ['id', 'owner', 'activeVersionId', 'self', 'type'];
707
808
  propertiesToRemove.forEach(prop => delete tempApp[prop]);
708
809
  return tempApp;
709
810
  }