@c8y/ngx-components 1017.0.336 → 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.
- package/core/common/date.pipe.d.ts +2 -2
- package/core/common/stringify-object.pipe.d.ts +2 -1
- package/ecosystem/packages/deploy-application/deploy-application.component.d.ts +6 -5
- 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 -5
- package/esm2020/core/common/date.pipe.mjs +12 -7
- package/esm2020/core/common/stringify-object.pipe.mjs +11 -8
- package/esm2020/ecosystem/application-properties/application-properties.component.mjs +3 -3
- package/esm2020/ecosystem/applications/install-from-package/install-from-package.component.mjs +2 -2
- package/esm2020/ecosystem/packages/deploy-application/deploy-application.component.mjs +26 -81
- package/esm2020/ecosystem/shared/ecosystem.constants.mjs +5 -3
- package/esm2020/ecosystem/shared/ecosystem.model.mjs +3 -1
- package/esm2020/ecosystem/shared/ecosystem.service.mjs +121 -24
- package/fesm2015/c8y-ngx-components-ecosystem-shared.mjs +139 -27
- package/fesm2015/c8y-ngx-components-ecosystem-shared.mjs.map +1 -1
- package/fesm2015/c8y-ngx-components-ecosystem.mjs +23 -77
- package/fesm2015/c8y-ngx-components-ecosystem.mjs.map +1 -1
- package/fesm2015/c8y-ngx-components.mjs +20 -13
- package/fesm2015/c8y-ngx-components.mjs.map +1 -1
- package/fesm2020/c8y-ngx-components-ecosystem-shared.mjs +126 -25
- package/fesm2020/c8y-ngx-components-ecosystem-shared.mjs.map +1 -1
- package/fesm2020/c8y-ngx-components-ecosystem.mjs +23 -78
- package/fesm2020/c8y-ngx-components-ecosystem.mjs.map +1 -1
- package/fesm2020/c8y-ngx-components.mjs +20 -13
- package/fesm2020/c8y-ngx-components.mjs.map +1 -1
- package/locales/locales.pot +15 -3
- 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
|
|
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('
|
|
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(
|
|
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
|
}
|