@kumori/aurora-backend-handler 1.0.100 → 1.0.111
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/.gitlab-ci.yml +21 -21
- package/CHANGELOG.md +10 -0
- package/api/account-api-service.ts +31 -23
- package/api/deploy-service-helper.ts +72 -33
- package/api/environment-api-service.ts +15 -10
- package/api/marketplace-api-service.ts +31 -80
- package/api/resources-api-service.ts +20 -20
- package/api/service-api-service.ts +18 -14
- package/api/tenant-api-service.ts +130 -242
- package/api/user-api-service.ts +24 -9
- package/backend-handler.ts +374 -348
- package/developer.md +998 -0
- package/event-helper.ts +13 -3
- package/event-names.ts +3 -0
- package/helpers/account-helper.ts +12 -13
- package/helpers/environment-helper.ts +25 -29
- package/helpers/marketplace-helper.ts +109 -0
- package/helpers/resource-helper.ts +19 -1
- package/helpers/revision-helper.ts +68 -18
- package/helpers/service-helper.ts +49 -33
- package/helpers/tenant-helper.ts +0 -5
- package/helpers/token-helper.ts +74 -2
- package/helpers/user-helper.ts +72 -31
- package/jest.config.ts +1 -0
- package/package.json +3 -3
- package/test/backend-handler.test.ts +992 -730
- package/test/deploy-service-helper.test.ts +707 -273
- package/test/event-helper.test.ts +489 -104
- package/test/event-names.test.ts +186 -0
- package/websocket-manager.ts +375 -71
package/websocket-manager.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { v7 as uuidv7 } from "uuid";
|
|
2
2
|
import { environment } from "./environment";
|
|
3
|
+
import { AccountStatus } from "@kumori/aurora-interfaces/enums/accountStatusEnum";
|
|
3
4
|
import {
|
|
4
5
|
Account,
|
|
5
6
|
Channel,
|
|
6
7
|
ClusterToken,
|
|
7
8
|
Environment,
|
|
9
|
+
errors,
|
|
8
10
|
Instance,
|
|
9
|
-
|
|
10
|
-
MarketplaceService,
|
|
11
|
+
MarketplaceItem,
|
|
11
12
|
Notification,
|
|
12
13
|
Organization,
|
|
13
14
|
Plan,
|
|
@@ -17,11 +18,10 @@ import {
|
|
|
17
18
|
Resource,
|
|
18
19
|
Service,
|
|
19
20
|
Tenant,
|
|
20
|
-
tenantRole,
|
|
21
21
|
Token,
|
|
22
|
-
Usage,
|
|
23
22
|
User,
|
|
24
23
|
UserData,
|
|
24
|
+
UserStatus
|
|
25
25
|
} from "@kumori/aurora-interfaces";
|
|
26
26
|
import { loadMarketplaceItemsForTenant } from "./api/marketplace-api-service";
|
|
27
27
|
import { getReporting } from "./api/reporting-api-service";
|
|
@@ -31,8 +31,8 @@ import {
|
|
|
31
31
|
handleTenantOperationSuccess,
|
|
32
32
|
} from "./helpers/tenant-helper";
|
|
33
33
|
import {
|
|
34
|
+
handleUserDelete,
|
|
34
35
|
handleUserEvent,
|
|
35
|
-
handleUserOperationError,
|
|
36
36
|
} from "./helpers/user-helper";
|
|
37
37
|
import {
|
|
38
38
|
handleEnvironmentEvent,
|
|
@@ -63,6 +63,7 @@ import {
|
|
|
63
63
|
handleSecretEvent,
|
|
64
64
|
handleVolumeEvent,
|
|
65
65
|
processResourceResult,
|
|
66
|
+
setResourceDeleting,
|
|
66
67
|
} from "./helpers/resource-helper";
|
|
67
68
|
import {
|
|
68
69
|
handlePlanInstanceEvent,
|
|
@@ -70,6 +71,7 @@ import {
|
|
|
70
71
|
} from "./helpers/plan-helper";
|
|
71
72
|
import { handleRegistryEvent } from "./helpers/registry-helper";
|
|
72
73
|
import {
|
|
74
|
+
handleTokenDeletion,
|
|
73
75
|
handleTokenEvent,
|
|
74
76
|
handleTokenOperationSuccess,
|
|
75
77
|
} from "./helpers/token-helper";
|
|
@@ -77,6 +79,7 @@ import { handleLinkEvent } from "./helpers/link-helper";
|
|
|
77
79
|
import { eventHelper } from "./backend-handler";
|
|
78
80
|
import { Revision } from "@kumori/aurora-interfaces/interfaces/revision-interface";
|
|
79
81
|
import { requestRevisionData } from "./api/service-api-service";
|
|
82
|
+
import { processMarketplaceSchemaResponse } from "./helpers/marketplace-helper";
|
|
80
83
|
|
|
81
84
|
let WebSocketClass: any;
|
|
82
85
|
|
|
@@ -145,10 +148,12 @@ interface Role {
|
|
|
145
148
|
*/
|
|
146
149
|
let wsConnection: WebSocket | null = null;
|
|
147
150
|
let pendingRequests = new Map<string, PendingOperation>();
|
|
151
|
+
let purgingEnvironments = new Set<string>();
|
|
148
152
|
let currentToken: string | null = null;
|
|
149
153
|
let connectionPromise: Promise<WebSocket> | null = null;
|
|
150
154
|
let userData: UserData = {
|
|
151
155
|
id: "",
|
|
156
|
+
created: "",
|
|
152
157
|
name: "",
|
|
153
158
|
surname: "",
|
|
154
159
|
provider: [],
|
|
@@ -171,6 +176,7 @@ let accountsMap = new Map<string, Account>();
|
|
|
171
176
|
let revisionsMap = new Map<string, Revision>();
|
|
172
177
|
let roleMap = new Map<string, Role[]>();
|
|
173
178
|
let tokenMap = new Map<string, Token>();
|
|
179
|
+
let deletedTokenIds = new Set<string>();
|
|
174
180
|
let platformInfo: Platform | null = null;
|
|
175
181
|
let isPlatformInfoLoading = false;
|
|
176
182
|
let isPlatformInfoLoaded = false;
|
|
@@ -192,6 +198,19 @@ const REPORTING_ITERATIONS = 5;
|
|
|
192
198
|
const REPORTING_INTERVAL = 1000;
|
|
193
199
|
let hasLoadedReportingOnce = false;
|
|
194
200
|
let recentlyUpdatedServices = new Map<string, Service>();
|
|
201
|
+
let pendingTenantStatus = new Map<string, string>();
|
|
202
|
+
let reconnectAttempts = 0;
|
|
203
|
+
let reconnectTimer: ReturnType<typeof setTimeout> | null = null;
|
|
204
|
+
let isManualClose = false;
|
|
205
|
+
let lastConnectionParams: {
|
|
206
|
+
token: string;
|
|
207
|
+
type?: string;
|
|
208
|
+
name?: string;
|
|
209
|
+
previousData?: UserData;
|
|
210
|
+
} | null = null;
|
|
211
|
+
const MAX_RECONNECT_ATTEMPTS = 5;
|
|
212
|
+
const RECONNECT_BASE_DELAY = 1000;
|
|
213
|
+
const RECONNECT_MAX_DELAY = 30000;
|
|
195
214
|
/**
|
|
196
215
|
* Helper function to safely stringify error objects
|
|
197
216
|
*/
|
|
@@ -234,6 +253,7 @@ export const initializeGlobalWebSocketClient = async (
|
|
|
234
253
|
): Promise<WebSocket> => {
|
|
235
254
|
userData.notifications = previousData?.notifications;
|
|
236
255
|
globalEntityName = name || null;
|
|
256
|
+
lastConnectionParams = { token, type, name, previousData };
|
|
237
257
|
if (
|
|
238
258
|
wsConnection &&
|
|
239
259
|
wsConnection.readyState === WebSocket.OPEN &&
|
|
@@ -265,8 +285,9 @@ export const initializeGlobalWebSocketClient = async (
|
|
|
265
285
|
if (typeof window === "undefined") {
|
|
266
286
|
wsConnection = new WebSocketClass(wsUrl, {
|
|
267
287
|
headers: {
|
|
268
|
-
authorization: `Bearer ${token}`,
|
|
288
|
+
// authorization: `Bearer ${token}`,
|
|
269
289
|
},
|
|
290
|
+
credentials: "include",
|
|
270
291
|
});
|
|
271
292
|
} else {
|
|
272
293
|
wsConnection = new WebSocketClass(wsUrl);
|
|
@@ -275,6 +296,11 @@ export const initializeGlobalWebSocketClient = async (
|
|
|
275
296
|
wsConnection?.addEventListener("open", async () => {
|
|
276
297
|
currentToken = token;
|
|
277
298
|
connectionPromise = null;
|
|
299
|
+
reconnectAttempts = 0;
|
|
300
|
+
if (reconnectTimer) {
|
|
301
|
+
clearTimeout(reconnectTimer);
|
|
302
|
+
reconnectTimer = null;
|
|
303
|
+
}
|
|
278
304
|
|
|
279
305
|
resolve(wsConnection!);
|
|
280
306
|
});
|
|
@@ -346,7 +372,7 @@ export const initializeGlobalWebSocketClient = async (
|
|
|
346
372
|
message.error?.code === "_unknown_user_" &&
|
|
347
373
|
message.error?.content !== "Unknown proposed user."
|
|
348
374
|
) {
|
|
349
|
-
userData.status =
|
|
375
|
+
userData.status = UserStatus.UNKNOWN;
|
|
350
376
|
user = new User(userData);
|
|
351
377
|
eventHelper.user.publish.loaded(user);
|
|
352
378
|
}
|
|
@@ -368,13 +394,17 @@ export const initializeGlobalWebSocketClient = async (
|
|
|
368
394
|
pending.reject(new Error("WebSocket connection closed"));
|
|
369
395
|
pendingRequests.delete(messageId);
|
|
370
396
|
});
|
|
397
|
+
|
|
398
|
+
if (isManualClose) {
|
|
399
|
+
isManualClose = false;
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
scheduleReconnect();
|
|
371
404
|
});
|
|
372
405
|
|
|
373
406
|
wsConnection?.addEventListener("error", (error) => {
|
|
374
407
|
console.error("Global WebSocket error:", error);
|
|
375
|
-
userData.status = "notlogged";
|
|
376
|
-
user = new User(userData);
|
|
377
|
-
eventHelper.user.publish.loaded(user);
|
|
378
408
|
connectionPromise = null;
|
|
379
409
|
reject(error);
|
|
380
410
|
});
|
|
@@ -387,6 +417,38 @@ export const initializeGlobalWebSocketClient = async (
|
|
|
387
417
|
return connectionPromise;
|
|
388
418
|
};
|
|
389
419
|
|
|
420
|
+
/**
|
|
421
|
+
* Schedule a reconnection attempt after an unexpected connection drop
|
|
422
|
+
* (e.g. a transient network blip while the tab was backgrounded).
|
|
423
|
+
* Uses exponential backoff and gives up after MAX_RECONNECT_ATTEMPTS.
|
|
424
|
+
*/
|
|
425
|
+
const scheduleReconnect = () => {
|
|
426
|
+
if (reconnectTimer || !lastConnectionParams) {
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
|
|
431
|
+
console.error("WebSocket reconnection attempts exhausted");
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const delay = Math.min(
|
|
436
|
+
RECONNECT_BASE_DELAY * Math.pow(2, reconnectAttempts),
|
|
437
|
+
RECONNECT_MAX_DELAY,
|
|
438
|
+
);
|
|
439
|
+
reconnectAttempts++;
|
|
440
|
+
|
|
441
|
+
reconnectTimer = setTimeout(() => {
|
|
442
|
+
reconnectTimer = null;
|
|
443
|
+
const { token, type, name, previousData } = lastConnectionParams!;
|
|
444
|
+
initializeGlobalWebSocketClient(token, type, name, previousData).catch(
|
|
445
|
+
(error) => {
|
|
446
|
+
console.error("WebSocket reconnect attempt failed:", error);
|
|
447
|
+
},
|
|
448
|
+
);
|
|
449
|
+
}, delay);
|
|
450
|
+
};
|
|
451
|
+
|
|
390
452
|
/**
|
|
391
453
|
* Function to make WebSocket requests using the global connection
|
|
392
454
|
* @param topic Request topic (group:method)
|
|
@@ -426,6 +488,14 @@ export const makeGlobalWebSocketRequest = async (
|
|
|
426
488
|
payload,
|
|
427
489
|
};
|
|
428
490
|
|
|
491
|
+
let purgeEnvKey: string | null = null;
|
|
492
|
+
if (petitionAction === "CLEAN" && entityType === "environment" && originalData) {
|
|
493
|
+
purgeEnvKey = originalData.tenant && originalData.account
|
|
494
|
+
? `${originalData.tenant}/${originalData.account}/${petitionInfo}`
|
|
495
|
+
: petitionInfo;
|
|
496
|
+
purgingEnvironments.add(purgeEnvKey);
|
|
497
|
+
}
|
|
498
|
+
|
|
429
499
|
return new Promise((resolve, reject) => {
|
|
430
500
|
const timeoutId = setTimeout(() => {
|
|
431
501
|
const pending = pendingRequests.get(messageId);
|
|
@@ -441,16 +511,23 @@ export const makeGlobalWebSocketRequest = async (
|
|
|
441
511
|
new Error(`Request timeout for ${topic}`),
|
|
442
512
|
);
|
|
443
513
|
}
|
|
444
|
-
|
|
514
|
+
if (purgeEnvKey) purgingEnvironments.delete(purgeEnvKey);
|
|
515
|
+
const timeoutError = Object.assign(
|
|
516
|
+
new Error(`Request timeout for ${topic}`),
|
|
517
|
+
{ isTimeout: true },
|
|
518
|
+
);
|
|
519
|
+
reject(timeoutError);
|
|
445
520
|
}, timeout);
|
|
446
521
|
|
|
447
522
|
const operation: PendingOperation = {
|
|
448
523
|
resolve: (response: any) => {
|
|
449
524
|
clearTimeout(timeoutId);
|
|
525
|
+
if (purgeEnvKey) purgingEnvironments.delete(purgeEnvKey);
|
|
450
526
|
resolve(response.payload || response);
|
|
451
527
|
},
|
|
452
528
|
reject: (error: any) => {
|
|
453
529
|
clearTimeout(timeoutId);
|
|
530
|
+
if (purgeEnvKey) purgingEnvironments.delete(purgeEnvKey);
|
|
454
531
|
const errorMessage = safeStringifyError(error);
|
|
455
532
|
console.error(`WebSocket request failed for ${topic}:`, {
|
|
456
533
|
originalError: error,
|
|
@@ -527,6 +604,23 @@ export const makeGlobalWebSocketRequestWithRetry = async (
|
|
|
527
604
|
);
|
|
528
605
|
};
|
|
529
606
|
|
|
607
|
+
export const markEnvironmentAsPurging = (envKey: string) => {
|
|
608
|
+
purgingEnvironments.add(envKey);
|
|
609
|
+
const env = environmentsMap.get(envKey);
|
|
610
|
+
if (env) {
|
|
611
|
+
const updatedEnv: Environment = {
|
|
612
|
+
...env,
|
|
613
|
+
status: {
|
|
614
|
+
code: "PURGING",
|
|
615
|
+
message: `Environment ${env.name} is being purged.`,
|
|
616
|
+
timestamp: new Date().toISOString(),
|
|
617
|
+
},
|
|
618
|
+
};
|
|
619
|
+
environmentsMap.set(envKey, updatedEnv);
|
|
620
|
+
eventHelper.environment.publish.updated(updatedEnv);
|
|
621
|
+
}
|
|
622
|
+
};
|
|
623
|
+
|
|
530
624
|
/**
|
|
531
625
|
* Get the current WebSocket connection status
|
|
532
626
|
* @returns Connection status and token info
|
|
@@ -545,6 +639,14 @@ export const getWebSocketStatus = () => {
|
|
|
545
639
|
* Close the global WebSocket connection
|
|
546
640
|
*/
|
|
547
641
|
export const closeGlobalWebSocketConnection = () => {
|
|
642
|
+
isManualClose = true;
|
|
643
|
+
lastConnectionParams = null;
|
|
644
|
+
reconnectAttempts = 0;
|
|
645
|
+
if (reconnectTimer) {
|
|
646
|
+
clearTimeout(reconnectTimer);
|
|
647
|
+
reconnectTimer = null;
|
|
648
|
+
}
|
|
649
|
+
|
|
548
650
|
if (wsConnection) {
|
|
549
651
|
wsConnection.close();
|
|
550
652
|
wsConnection = null;
|
|
@@ -562,13 +664,24 @@ export const closeGlobalWebSocketConnection = () => {
|
|
|
562
664
|
});
|
|
563
665
|
};
|
|
564
666
|
|
|
667
|
+
const computePromotionInfo = (
|
|
668
|
+
tenants: Tenant[],
|
|
669
|
+
): { completedSteps: number; remainingDays: number } => {
|
|
670
|
+
const hasValidCredentialsAccount = tenants.some((tenant) =>
|
|
671
|
+
tenant.accounts?.some((account) => account.status === AccountStatus.ACTIVE),
|
|
672
|
+
);
|
|
673
|
+
const hasDeployedService = tenants.some((tenant) => tenant.services?.length > 0);
|
|
674
|
+
const completedSteps = (hasValidCredentialsAccount ? 1 : 0) + (hasDeployedService ? 1 : 0);
|
|
675
|
+
return { completedSteps, remainingDays: 7 };
|
|
676
|
+
};
|
|
677
|
+
|
|
565
678
|
const rebuildHierarchy = () => {
|
|
566
679
|
const preservedUserData = { ...userData };
|
|
567
680
|
|
|
568
681
|
tenantsMap.forEach((tenant) => {
|
|
569
682
|
tenant.accounts = Array.from(accountsMap.values()).filter((account) => {
|
|
570
683
|
account.environments = Array.from(environmentsMap.values())
|
|
571
|
-
.filter((env) => env.account === account.id)
|
|
684
|
+
.filter((env) => env.account === account.id && env.tenant === account.tenant)
|
|
572
685
|
.map((env) => env.name);
|
|
573
686
|
return account.tenant === tenant.id;
|
|
574
687
|
});
|
|
@@ -594,16 +707,20 @@ const rebuildHierarchy = () => {
|
|
|
594
707
|
}
|
|
595
708
|
}
|
|
596
709
|
});
|
|
597
|
-
|
|
598
710
|
userData = {
|
|
599
711
|
id: preservedUserData.id,
|
|
712
|
+
created: preservedUserData.created,
|
|
600
713
|
name: preservedUserData.name,
|
|
601
714
|
surname: preservedUserData.surname,
|
|
602
715
|
provider: preservedUserData.provider.map((p) => ({ ...p })),
|
|
603
716
|
notificationsEnabled: preservedUserData.notificationsEnabled,
|
|
604
717
|
organizations: Array.from(organizationsMap.values()),
|
|
605
718
|
clusterTokens: Array.from(clusterTokensMap.values()),
|
|
606
|
-
tokens:
|
|
719
|
+
tokens: (
|
|
720
|
+
tokenMap.size > 0
|
|
721
|
+
? (preservedUserData.tokens || []).filter(t => tokenMap.has(t.name))
|
|
722
|
+
: (preservedUserData.tokens || [])
|
|
723
|
+
).filter(t => !deletedTokenIds.has(t.name)),
|
|
607
724
|
tenants: Array.from(tenantsMap.values()),
|
|
608
725
|
axebowPlan: preservedUserData.axebowPlan,
|
|
609
726
|
companyName: preservedUserData.companyName,
|
|
@@ -613,6 +730,7 @@ const rebuildHierarchy = () => {
|
|
|
613
730
|
notifications: preservedUserData.notifications || [],
|
|
614
731
|
plans: preservedUserData.plans || [],
|
|
615
732
|
discoveryMethod: preservedUserData.discoveryMethod,
|
|
733
|
+
promotionInfo: computePromotionInfo(Array.from(tenantsMap.values())),
|
|
616
734
|
};
|
|
617
735
|
};
|
|
618
736
|
const handleEvent = async (message: WSMessage) => {
|
|
@@ -630,6 +748,7 @@ const handleEvent = async (message: WSMessage) => {
|
|
|
630
748
|
: {};
|
|
631
749
|
switch (kind) {
|
|
632
750
|
case "user":
|
|
751
|
+
const previousTokens = userData.tokens || [];
|
|
633
752
|
const userEventResult = handleUserEvent({
|
|
634
753
|
eventData,
|
|
635
754
|
tenantsMap,
|
|
@@ -639,7 +758,22 @@ const handleEvent = async (message: WSMessage) => {
|
|
|
639
758
|
parseKeyPath,
|
|
640
759
|
eventHelper,
|
|
641
760
|
});
|
|
761
|
+
Object.entries(eventData.status.tenants).forEach(
|
|
762
|
+
([tenantId, tenantInfo]: [string, any]) => {
|
|
763
|
+
if (tenantInfo.status === "rejected") {
|
|
764
|
+
const tenant = tenantsMap.get(tenantId);
|
|
765
|
+
if (tenant) {
|
|
766
|
+
tenantsMap.set(tenantId, { ...tenant, status: "leaving" });
|
|
767
|
+
} else {
|
|
768
|
+
pendingTenantStatus.set(tenantId, "leaving");
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
},
|
|
772
|
+
);
|
|
642
773
|
userData = userEventResult.userData;
|
|
774
|
+
if (!userData.tokens?.length && previousTokens.length) {
|
|
775
|
+
userData.tokens = previousTokens;
|
|
776
|
+
}
|
|
643
777
|
tempProviders = userEventResult.tempProviders;
|
|
644
778
|
userEventResult.deletedTenantKeys.forEach((key) => {
|
|
645
779
|
tenantsMap.delete(key);
|
|
@@ -660,7 +794,19 @@ const handleEvent = async (message: WSMessage) => {
|
|
|
660
794
|
envEventResult.pendingCloudProviderUpdate,
|
|
661
795
|
);
|
|
662
796
|
}
|
|
663
|
-
|
|
797
|
+
const envSetKey = parentParts.tenant && parentParts.account ? `${parentParts.tenant}/${parentParts.account}/${entityId}` : entityId;
|
|
798
|
+
let envToStore = envEventResult.environment;
|
|
799
|
+
if (envToStore.status?.code?.startsWith("DELETING") && purgingEnvironments.has(envSetKey)) {
|
|
800
|
+
envToStore = {
|
|
801
|
+
...envToStore,
|
|
802
|
+
status: {
|
|
803
|
+
code: "PURGING",
|
|
804
|
+
message: `Environment ${entityId} is being purged.`,
|
|
805
|
+
timestamp: new Date().toISOString(),
|
|
806
|
+
},
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
environmentsMap.set(envSetKey, envToStore);
|
|
664
810
|
const envTenant = tenantsMap.get(envEventResult.tenantId);
|
|
665
811
|
if (!envTenant) {
|
|
666
812
|
pendingEnvironments.push({
|
|
@@ -694,12 +840,16 @@ const handleEvent = async (message: WSMessage) => {
|
|
|
694
840
|
}
|
|
695
841
|
if (revisionResult.updatedEnvironment) {
|
|
696
842
|
const envId = revisionResult.updatedService?.environment;
|
|
697
|
-
|
|
698
|
-
|
|
843
|
+
const envRevTenant = revisionResult.updatedEnvironment.tenant;
|
|
844
|
+
const envRevAccount = revisionResult.updatedEnvironment.account;
|
|
845
|
+
const envRevKey = envRevTenant && envRevAccount && envId ? `${envRevTenant}/${envRevAccount}/${envId}` : envId;
|
|
846
|
+
if (envRevKey) environmentsMap.set(envRevKey, revisionResult.updatedEnvironment);
|
|
699
847
|
}
|
|
700
848
|
if (revisionResult.updatedAccount) {
|
|
701
849
|
const accId = revisionResult.updatedService?.account;
|
|
702
|
-
|
|
850
|
+
const accRevTenant = revisionResult.updatedAccount.tenant;
|
|
851
|
+
const accRevKey = accRevTenant && accId ? `${accRevTenant}/${accId}` : accId;
|
|
852
|
+
if (accRevKey) accountsMap.set(accRevKey, revisionResult.updatedAccount);
|
|
703
853
|
}
|
|
704
854
|
if (revisionResult.pendingRevisionError) {
|
|
705
855
|
pendingRevisionErrors.push(revisionResult.pendingRevisionError);
|
|
@@ -792,8 +942,9 @@ const handleEvent = async (message: WSMessage) => {
|
|
|
792
942
|
});
|
|
793
943
|
|
|
794
944
|
if (!message.payload.deleted) {
|
|
795
|
-
|
|
796
|
-
|
|
945
|
+
const accountKey = parentParts.tenant ? `${parentParts.tenant}/${entityId}` : entityId;
|
|
946
|
+
accountsMap.set(accountKey, accountResult.account);
|
|
947
|
+
updateEnvironmentsCloudProvider(entityId, eventData.spec.api, parentParts.tenant);
|
|
797
948
|
}
|
|
798
949
|
break;
|
|
799
950
|
|
|
@@ -804,7 +955,6 @@ const handleEvent = async (message: WSMessage) => {
|
|
|
804
955
|
eventData,
|
|
805
956
|
userData,
|
|
806
957
|
);
|
|
807
|
-
|
|
808
958
|
if (
|
|
809
959
|
existingTenant &&
|
|
810
960
|
existingTenant.role &&
|
|
@@ -813,7 +963,7 @@ const handleEvent = async (message: WSMessage) => {
|
|
|
813
963
|
) {
|
|
814
964
|
const roleNotification: Notification = {
|
|
815
965
|
type: "info",
|
|
816
|
-
subtype:
|
|
966
|
+
subtype: errors.tenant.roleChanged.subtype,
|
|
817
967
|
date: Date.now().toString(),
|
|
818
968
|
status: "unread",
|
|
819
969
|
callToAction: false,
|
|
@@ -825,6 +975,25 @@ const handleEvent = async (message: WSMessage) => {
|
|
|
825
975
|
};
|
|
826
976
|
eventHelper.notification.publish.creation(roleNotification);
|
|
827
977
|
}
|
|
978
|
+
existingTenant?.users
|
|
979
|
+
?.filter((u) => u.status === "pending" && u.id !== userData.id)
|
|
980
|
+
.forEach((previousUser) => {
|
|
981
|
+
const currentUser = newTenant.users?.find((u) => u.id === previousUser.id);
|
|
982
|
+
if (currentUser?.status === "pending") return;
|
|
983
|
+
const invitationNotification: Notification = {
|
|
984
|
+
type: "info",
|
|
985
|
+
subtype: currentUser ? "tenant-invitation-accepted" : "tenant-invitation-declined",
|
|
986
|
+
date: Date.now().toString(),
|
|
987
|
+
status: "unread",
|
|
988
|
+
callToAction: false,
|
|
989
|
+
data: {
|
|
990
|
+
tenant: newTenant.name,
|
|
991
|
+
user: previousUser.id,
|
|
992
|
+
role: previousUser.role,
|
|
993
|
+
},
|
|
994
|
+
};
|
|
995
|
+
eventHelper.notification.publish.creation(invitationNotification);
|
|
996
|
+
});
|
|
828
997
|
if (existingTenant) {
|
|
829
998
|
if (
|
|
830
999
|
!newTenant.resources?.length &&
|
|
@@ -850,6 +1019,12 @@ const handleEvent = async (message: WSMessage) => {
|
|
|
850
1019
|
}
|
|
851
1020
|
|
|
852
1021
|
tenantsMap.set(entityId, newTenant);
|
|
1022
|
+
if (pendingTenantStatus.has(entityId)) {
|
|
1023
|
+
const pendingStatus = pendingTenantStatus.get(entityId)!;
|
|
1024
|
+
tenantsMap.set(entityId, { ...newTenant, status: pendingStatus });
|
|
1025
|
+
pendingTenantStatus.delete(entityId);
|
|
1026
|
+
}
|
|
1027
|
+
|
|
853
1028
|
loadMarketplaceItemsForTenant(entityId, "") //TODO Move to helper
|
|
854
1029
|
.then((items) => {
|
|
855
1030
|
const tenant = tenantsMap.get(entityId);
|
|
@@ -952,13 +1127,17 @@ const handleEvent = async (message: WSMessage) => {
|
|
|
952
1127
|
break;
|
|
953
1128
|
|
|
954
1129
|
case "ca":
|
|
955
|
-
const caResult = handleCAEvent(
|
|
1130
|
+
const caResult = handleCAEvent(
|
|
1131
|
+
eventData,
|
|
1132
|
+
parentParts,
|
|
1133
|
+
tenantsMap,
|
|
1134
|
+
hasRequestingServices,
|
|
1135
|
+
);
|
|
956
1136
|
processResourceResult(
|
|
957
1137
|
caResult,
|
|
958
1138
|
tenantsMap,
|
|
959
1139
|
pendingDomains,
|
|
960
1140
|
eventHelper,
|
|
961
|
-
|
|
962
1141
|
);
|
|
963
1142
|
break;
|
|
964
1143
|
|
|
@@ -1051,6 +1230,7 @@ const handleEvent = async (message: WSMessage) => {
|
|
|
1051
1230
|
eventData,
|
|
1052
1231
|
tokenMap,
|
|
1053
1232
|
userData,
|
|
1233
|
+
deletedTokenIds,
|
|
1054
1234
|
});
|
|
1055
1235
|
|
|
1056
1236
|
if (tokenResult.isUserToken) {
|
|
@@ -1257,6 +1437,7 @@ const handleOperationSuccess = (operation: PendingOperation, response: any) => {
|
|
|
1257
1437
|
const channelsInfo = mapChannelsFromApiData(
|
|
1258
1438
|
response.payload.data,
|
|
1259
1439
|
serviceName,
|
|
1440
|
+
service.resources,
|
|
1260
1441
|
);
|
|
1261
1442
|
service.serverChannels = channelsInfo.serverChannels;
|
|
1262
1443
|
service.clientChannels = channelsInfo.clientChannels;
|
|
@@ -1273,7 +1454,7 @@ const handleOperationSuccess = (operation: PendingOperation, response: any) => {
|
|
|
1273
1454
|
svcSuccessResult.revisionData
|
|
1274
1455
|
) {
|
|
1275
1456
|
try {
|
|
1276
|
-
|
|
1457
|
+
let updatedService = processRevisionData(
|
|
1277
1458
|
svcSuccessResult.updatedService!,
|
|
1278
1459
|
svcSuccessResult.revisionData,
|
|
1279
1460
|
revisionsMap,
|
|
@@ -1293,6 +1474,28 @@ const handleOperationSuccess = (operation: PendingOperation, response: any) => {
|
|
|
1293
1474
|
};
|
|
1294
1475
|
}
|
|
1295
1476
|
|
|
1477
|
+
const resources = updatedService.resources || [];
|
|
1478
|
+
if (resources.length > 0) {
|
|
1479
|
+
const applyIsPublic = (channels: Channel[]): Channel[] =>
|
|
1480
|
+
channels.map((ch) => ({
|
|
1481
|
+
...ch,
|
|
1482
|
+
isPublic:
|
|
1483
|
+
ch.isPublic ||
|
|
1484
|
+
resources.some(
|
|
1485
|
+
(r) =>
|
|
1486
|
+
(r.type === "port" || r.type === "domain") &&
|
|
1487
|
+
(r.name === `${ch.name}_port` || r.name === `${ch.name}_domain`),
|
|
1488
|
+
),
|
|
1489
|
+
}));
|
|
1490
|
+
|
|
1491
|
+
updatedService = {
|
|
1492
|
+
...updatedService,
|
|
1493
|
+
serverChannels: applyIsPublic(updatedService.serverChannels || []),
|
|
1494
|
+
clientChannels: applyIsPublic(updatedService.clientChannels || []),
|
|
1495
|
+
duplexChannels: applyIsPublic(updatedService.duplexChannels || []),
|
|
1496
|
+
};
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1296
1499
|
servicesMap.set(svcSuccessResult.serviceId, updatedService);
|
|
1297
1500
|
|
|
1298
1501
|
if (updatedService.role && updatedService.role.length > 0) {
|
|
@@ -1347,16 +1550,18 @@ const handleOperationSuccess = (operation: PendingOperation, response: any) => {
|
|
|
1347
1550
|
originalData: originalData as Account,
|
|
1348
1551
|
});
|
|
1349
1552
|
|
|
1553
|
+
const accTenant = (originalData as Account)?.tenant;
|
|
1554
|
+
const accSuccessKey = accTenant ? `${accTenant}/${entityName}` : entityName;
|
|
1350
1555
|
if (accSuccessResult.shouldDelete) {
|
|
1351
|
-
const acc = accountsMap.get(
|
|
1556
|
+
const acc = accountsMap.get(accSuccessKey);
|
|
1352
1557
|
if (acc) {
|
|
1353
|
-
accountsMap.delete(
|
|
1558
|
+
accountsMap.delete(accSuccessKey);
|
|
1354
1559
|
eventHelper.notification.publish.creation(
|
|
1355
1560
|
accSuccessResult.notification,
|
|
1356
1561
|
);
|
|
1357
1562
|
}
|
|
1358
1563
|
} else if (accSuccessResult.updatedAccount) {
|
|
1359
|
-
accountsMap.set(
|
|
1564
|
+
accountsMap.set(accSuccessKey, accSuccessResult.updatedAccount);
|
|
1360
1565
|
if (accSuccessResult.eventType === "created") {
|
|
1361
1566
|
eventHelper.account.publish.created(accSuccessResult.updatedAccount);
|
|
1362
1567
|
} else if (accSuccessResult.eventType === "updated") {
|
|
@@ -1375,10 +1580,12 @@ const handleOperationSuccess = (operation: PendingOperation, response: any) => {
|
|
|
1375
1580
|
originalData: originalData as Environment,
|
|
1376
1581
|
});
|
|
1377
1582
|
|
|
1583
|
+
const envOrigData = originalData as Environment;
|
|
1584
|
+
const envSuccessKey = envOrigData?.tenant && envOrigData?.account ? `${envOrigData.tenant}/${envOrigData.account}/${entityName}` : entityName;
|
|
1378
1585
|
if (envSuccessResult.shouldDelete) {
|
|
1379
|
-
environmentsMap.delete(
|
|
1586
|
+
environmentsMap.delete(envSuccessKey);
|
|
1380
1587
|
} else if (envSuccessResult.updatedEnvironment) {
|
|
1381
|
-
environmentsMap.set(
|
|
1588
|
+
environmentsMap.set(envSuccessKey, envSuccessResult.updatedEnvironment);
|
|
1382
1589
|
if (envSuccessResult.notification) {
|
|
1383
1590
|
eventHelper.notification.publish.creation(
|
|
1384
1591
|
envSuccessResult.notification,
|
|
@@ -1406,15 +1613,44 @@ const handleOperationSuccess = (operation: PendingOperation, response: any) => {
|
|
|
1406
1613
|
}
|
|
1407
1614
|
break;
|
|
1408
1615
|
case "token":
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1616
|
+
if (action === "DELETE") {
|
|
1617
|
+
const deletedTokenId = entityName.split("/").pop();
|
|
1618
|
+
if (deletedTokenId) {
|
|
1619
|
+
const tokenDeletionResult = handleTokenDeletion({
|
|
1620
|
+
tokenId: deletedTokenId,
|
|
1621
|
+
tokenMap,
|
|
1622
|
+
userData,
|
|
1623
|
+
deletedTokenIds,
|
|
1624
|
+
});
|
|
1625
|
+
if (tokenDeletionResult.removed) {
|
|
1626
|
+
userData.tokens = tokenDeletionResult.updatedUserTokens;
|
|
1627
|
+
eventHelper.notification.publish.creation(
|
|
1628
|
+
tokenDeletionResult.notification!,
|
|
1629
|
+
);
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
} else {
|
|
1633
|
+
const tokenSuccessResult = handleTokenOperationSuccess({
|
|
1634
|
+
responsePayload: response.payload,
|
|
1635
|
+
});
|
|
1636
|
+
tokenMap.set(tokenSuccessResult.token.name, tokenSuccessResult.token);
|
|
1637
|
+
}
|
|
1413
1638
|
break;
|
|
1414
1639
|
case "user":
|
|
1415
1640
|
if (action === "DELETE") {
|
|
1416
|
-
|
|
1417
|
-
|
|
1641
|
+
const newUser = handleUserDelete();
|
|
1642
|
+
userData = newUser;
|
|
1643
|
+
user = new User(newUser);
|
|
1644
|
+
}
|
|
1645
|
+
break;
|
|
1646
|
+
case "resource":
|
|
1647
|
+
if (action === "DELETE") {
|
|
1648
|
+
const tenant = originalData?.payload?.tenant;
|
|
1649
|
+
const resourceName = originalData?.payload?.resource;
|
|
1650
|
+
const resourceType = originalData?.payload?.kind;
|
|
1651
|
+
if (tenant && resourceName && resourceType) {
|
|
1652
|
+
setResourceDeleting(tenantsMap, tenant, resourceName, resourceType);
|
|
1653
|
+
}
|
|
1418
1654
|
}
|
|
1419
1655
|
break;
|
|
1420
1656
|
}
|
|
@@ -1479,10 +1715,12 @@ const handleOperationError = (operation: PendingOperation, error: any) => {
|
|
|
1479
1715
|
error,
|
|
1480
1716
|
});
|
|
1481
1717
|
|
|
1718
|
+
const accErrorTenant = (originalData as Account)?.tenant;
|
|
1719
|
+
const accErrorKey = accErrorTenant ? `${accErrorTenant}/${entityName}` : entityName;
|
|
1482
1720
|
if (accErrorResult.shouldDelete) {
|
|
1483
|
-
accountsMap.delete(
|
|
1721
|
+
accountsMap.delete(accErrorKey);
|
|
1484
1722
|
} else if (accErrorResult.updatedAccount) {
|
|
1485
|
-
accountsMap.set(
|
|
1723
|
+
accountsMap.set(accErrorKey, accErrorResult.updatedAccount);
|
|
1486
1724
|
}
|
|
1487
1725
|
|
|
1488
1726
|
if (accErrorResult.eventType === "creationError") {
|
|
@@ -1492,7 +1730,6 @@ const handleOperationError = (operation: PendingOperation, error: any) => {
|
|
|
1492
1730
|
} else if (accErrorResult.eventType === "deletionError") {
|
|
1493
1731
|
eventHelper.account.publish.deletionError(originalData);
|
|
1494
1732
|
}
|
|
1495
|
-
eventHelper.notification.publish.creation(accErrorResult.notification);
|
|
1496
1733
|
break;
|
|
1497
1734
|
case "environment":
|
|
1498
1735
|
const envErrorResult = handleEnvironmentOperationError({
|
|
@@ -1509,7 +1746,9 @@ const handleOperationError = (operation: PendingOperation, error: any) => {
|
|
|
1509
1746
|
eventHelper.environment.publish.deletionError(originalData);
|
|
1510
1747
|
}
|
|
1511
1748
|
eventHelper.notification.publish.creation(envErrorResult.notification);
|
|
1512
|
-
|
|
1749
|
+
const envErrOrigData = originalData as Environment;
|
|
1750
|
+
const envErrorKey = envErrOrigData?.tenant && envErrOrigData?.account ? `${envErrOrigData.tenant}/${envErrOrigData.account}/${entityName}` : entityName;
|
|
1751
|
+
environmentsMap.set(envErrorKey, envErrorResult.updatedEnvironment);
|
|
1513
1752
|
break;
|
|
1514
1753
|
}
|
|
1515
1754
|
setTimeout(async () => {
|
|
@@ -1540,11 +1779,12 @@ const handleDeleteEvent = async (message: WSMessage) => {
|
|
|
1540
1779
|
}
|
|
1541
1780
|
if (keyParts.environment && !keyParts.service) {
|
|
1542
1781
|
const environmentName = keyParts.environment;
|
|
1543
|
-
const
|
|
1782
|
+
const envDeleteKey = tenantName && keyParts.account ? `${tenantName}/${keyParts.account}/${environmentName}` : environmentName;
|
|
1783
|
+
const deletedEnv = environmentsMap.get(envDeleteKey)!;
|
|
1544
1784
|
eventHelper.environment.publish.deleted(deletedEnv);
|
|
1545
1785
|
const envNotification: Notification = {
|
|
1546
1786
|
type: "success",
|
|
1547
|
-
subtype:
|
|
1787
|
+
subtype: errors.environment.deleted.subtype,
|
|
1548
1788
|
date: Date.now().toString(),
|
|
1549
1789
|
callToAction: false,
|
|
1550
1790
|
status: "unread",
|
|
@@ -1555,15 +1795,16 @@ const handleDeleteEvent = async (message: WSMessage) => {
|
|
|
1555
1795
|
},
|
|
1556
1796
|
};
|
|
1557
1797
|
eventHelper.notification.publish.creation(envNotification);
|
|
1558
|
-
environmentsMap.delete(
|
|
1798
|
+
environmentsMap.delete(envDeleteKey);
|
|
1559
1799
|
}
|
|
1560
1800
|
if (keyParts.account && !keyParts.environment) {
|
|
1561
1801
|
const accountName = keyParts.account;
|
|
1562
|
-
const
|
|
1802
|
+
const accountDeleteKey = tenantName ? `${tenantName}/${accountName}` : accountName;
|
|
1803
|
+
const deletedAccount = accountsMap.get(accountDeleteKey)!;
|
|
1563
1804
|
eventHelper.account.publish.deleted(deletedAccount);
|
|
1564
1805
|
const accountNotification: Notification = {
|
|
1565
1806
|
type: "success",
|
|
1566
|
-
subtype:
|
|
1807
|
+
subtype: errors.account.deleted.subtype,
|
|
1567
1808
|
date: Date.now().toString(),
|
|
1568
1809
|
callToAction: false,
|
|
1569
1810
|
status: "unread",
|
|
@@ -1573,7 +1814,7 @@ const handleDeleteEvent = async (message: WSMessage) => {
|
|
|
1573
1814
|
},
|
|
1574
1815
|
};
|
|
1575
1816
|
eventHelper.notification.publish.creation(accountNotification);
|
|
1576
|
-
accountsMap.delete(
|
|
1817
|
+
accountsMap.delete(accountDeleteKey);
|
|
1577
1818
|
}
|
|
1578
1819
|
if (keyParts.domain) {
|
|
1579
1820
|
const domainName = keyParts.domain;
|
|
@@ -1701,7 +1942,7 @@ const handleDeleteEvent = async (message: WSMessage) => {
|
|
|
1701
1942
|
tenantsMap.set(tenantName, registryTenant);
|
|
1702
1943
|
const registryNotification: Notification = {
|
|
1703
1944
|
type: "success",
|
|
1704
|
-
subtype:
|
|
1945
|
+
subtype: errors.registry.deleted.subtype,
|
|
1705
1946
|
date: Date.now().toString(),
|
|
1706
1947
|
status: "unread",
|
|
1707
1948
|
callToAction: false,
|
|
@@ -1757,7 +1998,7 @@ const handleDeleteEvent = async (message: WSMessage) => {
|
|
|
1757
1998
|
if (deletedLinkInfo) {
|
|
1758
1999
|
const unlinkNotification: Notification = {
|
|
1759
2000
|
type: "success",
|
|
1760
|
-
subtype:
|
|
2001
|
+
subtype: errors.service.unlinked.subtype,
|
|
1761
2002
|
date: Date.now().toString(),
|
|
1762
2003
|
status: "unread",
|
|
1763
2004
|
callToAction: false,
|
|
@@ -1774,24 +2015,17 @@ const handleDeleteEvent = async (message: WSMessage) => {
|
|
|
1774
2015
|
}
|
|
1775
2016
|
}
|
|
1776
2017
|
if (keyParts.token && keyParts.user) {
|
|
1777
|
-
const
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
callToAction: false,
|
|
1789
|
-
data: {
|
|
1790
|
-
tokenName: deletedToken.name,
|
|
1791
|
-
tenant: deletedToken.tenant,
|
|
1792
|
-
},
|
|
1793
|
-
};
|
|
1794
|
-
eventHelper.notification.publish.creation(tokenNotification);
|
|
2018
|
+
const tokenDeletionResult = handleTokenDeletion({
|
|
2019
|
+
tokenId: keyParts.token,
|
|
2020
|
+
tokenMap,
|
|
2021
|
+
userData,
|
|
2022
|
+
deletedTokenIds,
|
|
2023
|
+
});
|
|
2024
|
+
if (tokenDeletionResult.removed) {
|
|
2025
|
+
userData.tokens = tokenDeletionResult.updatedUserTokens;
|
|
2026
|
+
eventHelper.notification.publish.creation(
|
|
2027
|
+
tokenDeletionResult.notification!,
|
|
2028
|
+
);
|
|
1795
2029
|
}
|
|
1796
2030
|
}
|
|
1797
2031
|
rebuildHierarchy();
|
|
@@ -1833,9 +2067,10 @@ const getChannelsInfo = async (
|
|
|
1833
2067
|
const updateEnvironmentsCloudProvider = (
|
|
1834
2068
|
accountId: string,
|
|
1835
2069
|
cloudProviderName: string,
|
|
2070
|
+
tenantId?: string,
|
|
1836
2071
|
) => {
|
|
1837
2072
|
environmentsMap.forEach((environment, envId) => {
|
|
1838
|
-
if (environment.account === accountId) {
|
|
2073
|
+
if (environment.account === accountId && (!tenantId || environment.tenant === tenantId)) {
|
|
1839
2074
|
environment.cloudProvider = cloudProviderName;
|
|
1840
2075
|
environmentsMap.set(envId, environment);
|
|
1841
2076
|
}
|
|
@@ -1853,7 +2088,8 @@ const loadReportingForEnvironment = async (environment: Environment) => {
|
|
|
1853
2088
|
reportingData !== null &&
|
|
1854
2089
|
Array.isArray(reportingData)
|
|
1855
2090
|
) {
|
|
1856
|
-
const
|
|
2091
|
+
const envReportKey = environment.tenant && environment.account ? `${environment.tenant}/${environment.account}/${environment.id}` : environment.id;
|
|
2092
|
+
const updatedEnvironment = environmentsMap.get(envReportKey);
|
|
1857
2093
|
|
|
1858
2094
|
if (!updatedEnvironment) {
|
|
1859
2095
|
console.warn(`Environment ${environment.id} not found in map`);
|
|
@@ -1884,7 +2120,7 @@ const loadReportingForEnvironment = async (environment: Environment) => {
|
|
|
1884
2120
|
);
|
|
1885
2121
|
}
|
|
1886
2122
|
|
|
1887
|
-
environmentsMap.set(
|
|
2123
|
+
environmentsMap.set(envReportKey, updatedEnvironment);
|
|
1888
2124
|
}
|
|
1889
2125
|
} catch (error) {
|
|
1890
2126
|
console.error(
|
|
@@ -1916,8 +2152,20 @@ export const updateUserComplete = (updatedUserData: UserData): User => {
|
|
|
1916
2152
|
try {
|
|
1917
2153
|
const preservedNotifications =
|
|
1918
2154
|
userData.notifications || updatedUserData.notifications || [];
|
|
2155
|
+
const incomingTokenNames = new Set(
|
|
2156
|
+
(updatedUserData.tokens || []).map((t) => t.name)
|
|
2157
|
+
);
|
|
2158
|
+
const localOnlyTokens = (userData.tokens || []).filter(
|
|
2159
|
+
(t) => !incomingTokenNames.has(t.name)
|
|
2160
|
+
);
|
|
2161
|
+
const mergedTokens = [...(updatedUserData.tokens || []), ...localOnlyTokens]
|
|
2162
|
+
.filter((t, index, arr) => arr.findIndex(x => x.name === t.name) === index)
|
|
2163
|
+
.filter(t => tokenMap.size === 0 || tokenMap.has(t.name))
|
|
2164
|
+
.filter(t => !deletedTokenIds.has(t.name));
|
|
2165
|
+
|
|
1919
2166
|
userData = {
|
|
1920
2167
|
id: updatedUserData.id || userData.id,
|
|
2168
|
+
created: updatedUserData.created || userData.created,
|
|
1921
2169
|
name: updatedUserData.name || userData.name,
|
|
1922
2170
|
surname: updatedUserData.surname || userData.surname,
|
|
1923
2171
|
provider: updatedUserData.provider || userData.provider || [],
|
|
@@ -1927,7 +2175,7 @@ export const updateUserComplete = (updatedUserData: UserData): User => {
|
|
|
1927
2175
|
"",
|
|
1928
2176
|
organizations: updatedUserData.organizations || [],
|
|
1929
2177
|
clusterTokens: updatedUserData.clusterTokens || [],
|
|
1930
|
-
tokens:
|
|
2178
|
+
tokens: mergedTokens,
|
|
1931
2179
|
tenants: updatedUserData.tenants || [],
|
|
1932
2180
|
axebowPlan:
|
|
1933
2181
|
updatedUserData.axebowPlan || userData.axebowPlan || "freemium",
|
|
@@ -1938,6 +2186,7 @@ export const updateUserComplete = (updatedUserData: UserData): User => {
|
|
|
1938
2186
|
status: updatedUserData.status,
|
|
1939
2187
|
discoveryMethod:
|
|
1940
2188
|
updatedUserData.discoveryMethod || userData.discoveryMethod,
|
|
2189
|
+
promotionInfo: computePromotionInfo(updatedUserData.tenants || userData.tenants || []),
|
|
1941
2190
|
};
|
|
1942
2191
|
user = new User(
|
|
1943
2192
|
userData,
|
|
@@ -1956,7 +2205,7 @@ const resolveServiceStatus = (service: Service): Service => {
|
|
|
1956
2205
|
return service;
|
|
1957
2206
|
}
|
|
1958
2207
|
|
|
1959
|
-
const revisionKey =
|
|
2208
|
+
const revisionKey = `/tenant/${service.tenant}/service/${service.name}/revision/${service.currentRevision}`;
|
|
1960
2209
|
const currentRevision = revisionsMap.get(revisionKey);
|
|
1961
2210
|
|
|
1962
2211
|
if (!currentRevision) {
|
|
@@ -1984,3 +2233,58 @@ const resolveServiceStatus = (service: Service): Service => {
|
|
|
1984
2233
|
status: currentRevision.status,
|
|
1985
2234
|
};
|
|
1986
2235
|
};
|
|
2236
|
+
export const fetchAndStoreMarketplaceSchema = async (
|
|
2237
|
+
item: MarketplaceItem,
|
|
2238
|
+
): Promise<void> => {
|
|
2239
|
+
const tenantsWithItem: string[] = [];
|
|
2240
|
+
tenantsMap.forEach((tenantEntry, tenantId) => {
|
|
2241
|
+
const hasItem = (tenantEntry.marketplaceItems || []).some(
|
|
2242
|
+
(i) => i.name === item.name && i.domain === item.domain && i.artifact === item.artifact,
|
|
2243
|
+
);
|
|
2244
|
+
if (hasItem) tenantsWithItem.push(tenantId);
|
|
2245
|
+
});
|
|
2246
|
+
|
|
2247
|
+
if (tenantsWithItem.length === 0) return;
|
|
2248
|
+
|
|
2249
|
+
await Promise.all(
|
|
2250
|
+
tenantsWithItem.map(async (tenantId) => {
|
|
2251
|
+
try {
|
|
2252
|
+
const response = await makeGlobalWebSocketRequest(
|
|
2253
|
+
"marketplace:artifact_schema",
|
|
2254
|
+
{
|
|
2255
|
+
tenant: tenantId,
|
|
2256
|
+
module: item.name,
|
|
2257
|
+
version: item.version,
|
|
2258
|
+
domain: item.domain,
|
|
2259
|
+
artifact: item.artifact,
|
|
2260
|
+
},
|
|
2261
|
+
30000,
|
|
2262
|
+
"GET",
|
|
2263
|
+
tenantId,
|
|
2264
|
+
);
|
|
2265
|
+
|
|
2266
|
+
const data = response?.data;
|
|
2267
|
+
if (!data) return;
|
|
2268
|
+
|
|
2269
|
+
const nameKeys = Object.keys(data);
|
|
2270
|
+
const schema = processMarketplaceSchemaResponse(data[nameKeys[0]], nameKeys[0]);
|
|
2271
|
+
|
|
2272
|
+
const tenantEntry = tenantsMap.get(tenantId);
|
|
2273
|
+
if (tenantEntry) {
|
|
2274
|
+
tenantEntry.marketplaceItems = tenantEntry.marketplaceItems.map((i) =>
|
|
2275
|
+
i.name === item.name && i.domain === item.domain && i.artifact === item.artifact
|
|
2276
|
+
? { ...i, schema }
|
|
2277
|
+
: i,
|
|
2278
|
+
);
|
|
2279
|
+
tenantsMap.set(tenantId, tenantEntry);
|
|
2280
|
+
}
|
|
2281
|
+
} catch (error) {
|
|
2282
|
+
console.error(`Error loading schema for tenant ${tenantId}:`, error);
|
|
2283
|
+
}
|
|
2284
|
+
}),
|
|
2285
|
+
);
|
|
2286
|
+
|
|
2287
|
+
rebuildHierarchy();
|
|
2288
|
+
await updateUserWithPlatformInfo();
|
|
2289
|
+
};
|
|
2290
|
+
|