@c8y/ngx-components 1017.0.92 → 1017.0.93

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.
@@ -37,6 +37,8 @@ var ERROR_TYPE;
37
37
  ERROR_TYPE["INVALID_PACKAGE"] = "INVALID_PACKAGE";
38
38
  ERROR_TYPE["INVALID_APPLICATION"] = "INVALID_APPLICATION";
39
39
  ERROR_TYPE["MICROSERVICE_NAME_TOO_LONG"] = "MICROSERVICE_NAME_TOO_LONG";
40
+ ERROR_TYPE["APPLICATION_CREATION_FAILED"] = "APPLICATION_CREATION_FAILED";
41
+ ERROR_TYPE["KEY_OR_CONTEXT_PATH_MISMATCH"] = "KEY_OR_CONTEXT_PATH_MISMATCH";
40
42
  })(ERROR_TYPE || (ERROR_TYPE = {}));
41
43
  const PRODUCT_EXPERIENCE = {
42
44
  APPLICATIONS: {
@@ -95,7 +97,9 @@ const ERROR_MESSAGES = {
95
97
  [ERROR_TYPE.INVALID_PACKAGE]: gettext('You have not uploaded a valid package.'),
96
98
  [ERROR_TYPE.INVALID_APPLICATION]: gettext('You have not uploaded a valid application.'),
97
99
  [ERROR_TYPE.INTERNAL_ERROR]: gettext('An internal error occurred, try to upload again.'),
98
- [ERROR_TYPE.MICROSERVICE_NAME_TOO_LONG]: gettext('Microservice name "{{ name }}" must not be longer than {{ maxChars }} characters.')
100
+ [ERROR_TYPE.MICROSERVICE_NAME_TOO_LONG]: gettext('Microservice name "{{ name }}" must not be longer than {{ maxChars }} characters.'),
101
+ [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.')
99
103
  };
100
104
  const APP_STATE = {
101
105
  SUBSCRIBED: {
@@ -159,6 +163,13 @@ const packageProperties = [
159
163
  }
160
164
  ];
161
165
 
166
+ class EcosystemError extends Error {
167
+ constructor(type) {
168
+ super(ERROR_MESSAGES[type]);
169
+ this.type = type;
170
+ }
171
+ }
172
+
162
173
  const CUMULOCITY_JSON = 'cumulocity.json';
163
174
  const MICROSERVICE_NAME_MAX_LENGTH = 23;
164
175
  class EcosystemService {
@@ -396,10 +407,10 @@ class EcosystemService {
396
407
  return await this.applicationService.update(app);
397
408
  }
398
409
  catch (ex) {
399
- this.alertService.addServerFailure(ex);
410
+ this.alertError(ex);
400
411
  if (deleteOnFailure) {
401
412
  await this.applicationService.delete(app.id);
402
- throw new Error('Application creation failed.');
413
+ throw new EcosystemError(ERROR_TYPE.APPLICATION_CREATION_FAILED);
403
414
  }
404
415
  }
405
416
  }
@@ -426,7 +437,7 @@ class EcosystemService {
426
437
  this.alertService.success(gettext('Successfully subscribed to application.'));
427
438
  }
428
439
  catch (ex) {
429
- this.alertService.addServerFailure(ex);
440
+ this.alertError(ex);
430
441
  }
431
442
  }
432
443
  async unsubscribeApp(app) {
@@ -436,14 +447,14 @@ class EcosystemService {
436
447
  this.alertService.success(gettext('Successfully unsubscribed from application.'));
437
448
  }
438
449
  catch (ex) {
439
- this.alertService.addServerFailure(ex);
450
+ this.alertError(ex);
440
451
  }
441
452
  }
442
453
  async isValidAppType(archive, appType) {
443
454
  try {
444
455
  const currentType = await this.getAppType(archive);
445
456
  if (currentType !== appType) {
446
- throw new Error(ERROR_TYPE.TYPE_VALIDATION);
457
+ throw new EcosystemError(ERROR_TYPE.TYPE_VALIDATION);
447
458
  }
448
459
  else {
449
460
  this.progress.next(this.progress.value + 10);
@@ -451,7 +462,7 @@ class EcosystemService {
451
462
  }
452
463
  }
453
464
  catch (ex) {
454
- throw new Error(ERROR_TYPE.TYPE_VALIDATION);
465
+ throw new EcosystemError(ERROR_TYPE.TYPE_VALIDATION);
455
466
  }
456
467
  }
457
468
  async uploadArchiveToApp(archive, app, isNewVersion = false) {
@@ -469,15 +480,29 @@ class EcosystemService {
469
480
  // }
470
481
  return (await this.setAppActiveVersion(app, (binaryMo.binaryId || binaryMo.id))).data;
471
482
  }
472
- async validatePackageKeyAndContextPath(archive, app) {
473
- const manifest = await this.getCumulocityJson(archive).toPromise();
474
- const contextPath = get(manifest, 'contextPath');
475
- const appKey = get(manifest, 'key');
476
- if (contextPath !== app.contextPath || appKey !== app.key) {
477
- const error = {
478
- data: { message: this.translateService.instant(ERROR_MESSAGES.INVALID_PACKAGE) }
479
- };
480
- throw error;
483
+ async validateArchiveToAppCompatibility(archive, app) {
484
+ const appType = await this.getAppType(archive);
485
+ if (appType !== app.type) {
486
+ throw new EcosystemError(ERROR_TYPE.INVALID_APPLICATION);
487
+ }
488
+ else {
489
+ this.progress.next(this.progress.value + 10);
490
+ }
491
+ const manifest = await this.getCumulocityJson(archive);
492
+ // A user can upload an app without a Cumulocity JSON file (e.g. a react app).
493
+ // This is allowed and should not trigger a validation error.
494
+ if (!manifest) {
495
+ return;
496
+ }
497
+ await this.validatePackageKeyAndContextPath(manifest, app);
498
+ }
499
+ async getCumulocityJson(archive) {
500
+ try {
501
+ const c8yManifest = await this.getCumulocityJson$(archive).toPromise();
502
+ return c8yManifest;
503
+ }
504
+ catch (ex) {
505
+ return null;
481
506
  }
482
507
  }
483
508
  async createAppForArchive(archive, isPackageTypeArchive = false) {
@@ -487,7 +512,7 @@ class EcosystemService {
487
512
  const supportedAppTypes = [ApplicationType.HOSTED, ApplicationType.MICROSERVICE];
488
513
  if (supportedAppTypes.includes(appType)) {
489
514
  try {
490
- appModel = await this.getCumulocityJson(archive).toPromise();
515
+ appModel = await this.getCumulocityJson$(archive).toPromise();
491
516
  isPackage = appModel.isPackage;
492
517
  }
493
518
  catch (e) {
@@ -506,10 +531,10 @@ class EcosystemService {
506
531
  contextPath
507
532
  };
508
533
  if (isPackageTypeArchive && !isPackage) {
509
- throw new Error(ERROR_TYPE.INVALID_PACKAGE);
534
+ throw new EcosystemError(ERROR_TYPE.INVALID_PACKAGE);
510
535
  }
511
536
  else if (!isPackageTypeArchive && isPackage) {
512
- throw new Error(ERROR_TYPE.INVALID_APPLICATION);
537
+ throw new EcosystemError(ERROR_TYPE.INVALID_APPLICATION);
513
538
  }
514
539
  else if (this.isNameLengthExceeded(name, appType)) {
515
540
  const error = new Error();
@@ -534,7 +559,7 @@ class EcosystemService {
534
559
  this.alertService.success(gettext('Application reactivated.'));
535
560
  }
536
561
  catch (ex) {
537
- this.alertService.addServerFailure(ex);
562
+ this.alertError(ex);
538
563
  }
539
564
  }
540
565
  async removeOldestArchive(app, archives) {
@@ -545,7 +570,7 @@ class EcosystemService {
545
570
  this.alertService.success(gettext('Archive deleted.'));
546
571
  }
547
572
  catch (ex) {
548
- this.alertService.addServerFailure(ex);
573
+ this.alertError(ex);
549
574
  }
550
575
  }
551
576
  getAppState(app) {
@@ -612,6 +637,25 @@ class EcosystemService {
612
637
  app.availability = ApplicationAvailability.PRIVATE;
613
638
  return app;
614
639
  }
640
+ /**
641
+ * Shows an error dialog.
642
+ * @param error Either a server error or an internal [[EcosystemError]].
643
+ */
644
+ alertError(error) {
645
+ if (error instanceof EcosystemError) {
646
+ this.alertService.danger(error.message);
647
+ }
648
+ else {
649
+ this.alertService.addServerFailure(error);
650
+ }
651
+ }
652
+ async validatePackageKeyAndContextPath(manifest, app) {
653
+ const contextPath = get(manifest, 'contextPath');
654
+ const appKey = get(manifest, 'key');
655
+ if (contextPath !== app.contextPath || appKey !== app.key) {
656
+ throw new EcosystemError(ERROR_TYPE.KEY_OR_CONTEXT_PATH_MISMATCH);
657
+ }
658
+ }
615
659
  getAppKey(appModel, name) {
616
660
  let key = appModel?.key;
617
661
  if (!key) {
@@ -629,13 +673,13 @@ class EcosystemService {
629
673
  const currentApp = this.appStateService.state.app;
630
674
  return currentApp.contextPath === app.contextPath;
631
675
  }
632
- getCumulocityJson(archive) {
676
+ getCumulocityJson$(archive) {
633
677
  return this.zipService.getJsonData(archive, {
634
678
  filename: CUMULOCITY_JSON
635
679
  });
636
680
  }
637
681
  getAppType(archive) {
638
- return this.getCumulocityJson(archive)
682
+ return this.getCumulocityJson$(archive)
639
683
  .toPromise()
640
684
  .then(data => get(data, 'type') ||
641
685
  (get(data, 'apiVersion') ? ApplicationType.MICROSERVICE : ApplicationType.HOSTED))
@@ -663,7 +707,7 @@ class EcosystemService {
663
707
  return tempApp;
664
708
  }
665
709
  async getUploadOverrides(archive, app) {
666
- const { version } = await this.getCumulocityJson(archive).toPromise();
710
+ const { version } = await this.getCumulocityJson$(archive).toPromise();
667
711
  const isInitialPackage = app.applicationVersions?.length === 0;
668
712
  return {
669
713
  listUrl: 'versions',
@@ -980,7 +1024,7 @@ class UploadArchiveComponent {
980
1024
  }
981
1025
  async onFile(file) {
982
1026
  try {
983
- await this.ecosystemService.isValidAppType(file, this.application.type);
1027
+ await this.ecosystemService.validateArchiveToAppCompatibility(file, this.application);
984
1028
  const isCustomMicroservice = this.ecosystemService.isCustomMicroservice(this.application);
985
1029
  this.archives = isCustomMicroservice
986
1030
  ? []
@@ -993,9 +1037,6 @@ class UploadArchiveComponent {
993
1037
  if (this.archives.length === 6 && !isCustomMicroservice) {
994
1038
  await this.ecosystemService.removeOldestArchive(this.application, this.archives);
995
1039
  }
996
- if (this.uploadNewVersion) {
997
- await this.ecosystemService.validatePackageKeyAndContextPath(file, this.application);
998
- }
999
1040
  const app = await this.ecosystemService.uploadArchiveToApp(file, this.application, this.uploadNewVersion);
1000
1041
  this.applicationChange.emit(app);
1001
1042
  this.uploadProgress.next(100);
@@ -1008,15 +1049,15 @@ class UploadArchiveComponent {
1008
1049
  }
1009
1050
  catch (ex) {
1010
1051
  this.uploadInProgress = false;
1011
- this.alertService.addServerFailure(ex);
1052
+ this.ecosystemService.alertError(ex);
1012
1053
  }
1013
1054
  }
1014
1055
  }
1015
1056
  UploadArchiveComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: UploadArchiveComponent, deps: [{ token: EcosystemService }, { token: i2.AlertService }], target: i0.ɵɵFactoryTarget.Component });
1016
- UploadArchiveComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: UploadArchiveComponent, selector: "c8y-upload-archive", inputs: { application: "application", uploadNewVersion: "uploadNewVersion", preUploadCallback: "preUploadCallback" }, outputs: { applicationChange: "applicationChange", refresh: "refresh" }, ngImport: i0, template: "<c8y-drop-area\n (dropped)=\"onFileDroppedEvent($event)\"\n [accept]=\"'.zip'\"\n [files]=\"fileList\"\n [loading]=\"uploadInProgress\"\n [maxAllowedFiles]=\"1\"\n [message]=\"'Upload a *.zip file' | translate\"\n [progress]=\"uploadProgress | async\"\n [forceHideList]=\"true\"\n class=\"drop-area-sm\"\n>\n</c8y-drop-area>\n", dependencies: [{ kind: "component", type: i2.DropAreaComponent, selector: "c8y-drop-area", inputs: ["formControl", "title", "message", "icon", "loadingMessage", "forceHideList", "alwaysShow", "clickToOpen", "loading", "progress", "maxAllowedFiles", "files", "accept"], outputs: ["dropped"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3$1.AsyncPipe, name: "async" }] });
1057
+ UploadArchiveComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: UploadArchiveComponent, selector: "c8y-upload-archive", inputs: { application: "application", uploadNewVersion: "uploadNewVersion", preUploadCallback: "preUploadCallback" }, outputs: { applicationChange: "applicationChange", refresh: "refresh" }, ngImport: i0, template: "<c8y-drop-area\n (dropped)=\"onFileDroppedEvent($event)\"\n [accept]=\"'.zip'\"\n [loading]=\"uploadInProgress\"\n [maxAllowedFiles]=\"1\"\n [message]=\"'Upload a *.zip file' | translate\"\n [progress]=\"uploadProgress | async\"\n [forceHideList]=\"true\"\n class=\"drop-area-sm\"\n>\n</c8y-drop-area>\n", dependencies: [{ kind: "component", type: i2.DropAreaComponent, selector: "c8y-drop-area", inputs: ["formControl", "title", "message", "icon", "loadingMessage", "forceHideList", "alwaysShow", "clickToOpen", "loading", "progress", "maxAllowedFiles", "files", "accept"], outputs: ["dropped"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3$1.AsyncPipe, name: "async" }] });
1017
1058
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: UploadArchiveComponent, decorators: [{
1018
1059
  type: Component,
1019
- args: [{ selector: 'c8y-upload-archive', template: "<c8y-drop-area\n (dropped)=\"onFileDroppedEvent($event)\"\n [accept]=\"'.zip'\"\n [files]=\"fileList\"\n [loading]=\"uploadInProgress\"\n [maxAllowedFiles]=\"1\"\n [message]=\"'Upload a *.zip file' | translate\"\n [progress]=\"uploadProgress | async\"\n [forceHideList]=\"true\"\n class=\"drop-area-sm\"\n>\n</c8y-drop-area>\n" }]
1060
+ args: [{ selector: 'c8y-upload-archive', template: "<c8y-drop-area\n (dropped)=\"onFileDroppedEvent($event)\"\n [accept]=\"'.zip'\"\n [loading]=\"uploadInProgress\"\n [maxAllowedFiles]=\"1\"\n [message]=\"'Upload a *.zip file' | translate\"\n [progress]=\"uploadProgress | async\"\n [forceHideList]=\"true\"\n class=\"drop-area-sm\"\n>\n</c8y-drop-area>\n" }]
1020
1061
  }], ctorParameters: function () { return [{ type: EcosystemService }, { type: i2.AlertService }]; }, propDecorators: { application: [{
1021
1062
  type: Input
1022
1063
  }], uploadNewVersion: [{