@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.
- package/ecosystem/shared/ecosystem-error.d.ts +5 -0
- package/ecosystem/shared/ecosystem.constants.d.ts +2 -0
- package/ecosystem/shared/ecosystem.model.d.ts +3 -1
- package/ecosystem/shared/ecosystem.service.d.ts +11 -4
- package/esm2020/ecosystem/shared/ecosystem-error.mjs +8 -0
- package/esm2020/ecosystem/shared/ecosystem.constants.mjs +4 -2
- package/esm2020/ecosystem/shared/ecosystem.model.mjs +3 -1
- package/esm2020/ecosystem/shared/ecosystem.service.mjs +59 -26
- package/esm2020/ecosystem/shared/upload-archive.component.mjs +5 -8
- package/fesm2015/c8y-ngx-components-ecosystem-shared.mjs +76 -31
- package/fesm2015/c8y-ngx-components-ecosystem-shared.mjs.map +1 -1
- package/fesm2020/c8y-ngx-components-ecosystem-shared.mjs +72 -31
- package/fesm2020/c8y-ngx-components-ecosystem-shared.mjs.map +1 -1
- package/locales/locales.pot +6 -0
- package/package.json +2 -2
|
@@ -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.
|
|
410
|
+
this.alertError(ex);
|
|
400
411
|
if (deleteOnFailure) {
|
|
401
412
|
await this.applicationService.delete(app.id);
|
|
402
|
-
throw new
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
473
|
-
const
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
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
|
|
534
|
+
throw new EcosystemError(ERROR_TYPE.INVALID_PACKAGE);
|
|
510
535
|
}
|
|
511
536
|
else if (!isPackageTypeArchive && isPackage) {
|
|
512
|
-
throw new
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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 [
|
|
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 [
|
|
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: [{
|