@kumori/aurora-backend-handler 1.0.99 → 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 +84 -68
- 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 -32
- 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 +394 -69
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,6 +955,45 @@ const handleEvent = async (message: WSMessage) => {
|
|
|
804
955
|
eventData,
|
|
805
956
|
userData,
|
|
806
957
|
);
|
|
958
|
+
if (
|
|
959
|
+
existingTenant &&
|
|
960
|
+
existingTenant.role &&
|
|
961
|
+
newTenant.role &&
|
|
962
|
+
existingTenant.role !== newTenant.role
|
|
963
|
+
) {
|
|
964
|
+
const roleNotification: Notification = {
|
|
965
|
+
type: "info",
|
|
966
|
+
subtype: errors.tenant.roleChanged.subtype,
|
|
967
|
+
date: Date.now().toString(),
|
|
968
|
+
status: "unread",
|
|
969
|
+
callToAction: false,
|
|
970
|
+
data: {
|
|
971
|
+
tenant: newTenant.name,
|
|
972
|
+
oldRole: existingTenant.role,
|
|
973
|
+
newRole: newTenant.role,
|
|
974
|
+
},
|
|
975
|
+
};
|
|
976
|
+
eventHelper.notification.publish.creation(roleNotification);
|
|
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
|
+
});
|
|
807
997
|
if (existingTenant) {
|
|
808
998
|
if (
|
|
809
999
|
!newTenant.resources?.length &&
|
|
@@ -829,6 +1019,12 @@ const handleEvent = async (message: WSMessage) => {
|
|
|
829
1019
|
}
|
|
830
1020
|
|
|
831
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
|
+
|
|
832
1028
|
loadMarketplaceItemsForTenant(entityId, "") //TODO Move to helper
|
|
833
1029
|
.then((items) => {
|
|
834
1030
|
const tenant = tenantsMap.get(entityId);
|
|
@@ -931,13 +1127,17 @@ const handleEvent = async (message: WSMessage) => {
|
|
|
931
1127
|
break;
|
|
932
1128
|
|
|
933
1129
|
case "ca":
|
|
934
|
-
const caResult = handleCAEvent(
|
|
1130
|
+
const caResult = handleCAEvent(
|
|
1131
|
+
eventData,
|
|
1132
|
+
parentParts,
|
|
1133
|
+
tenantsMap,
|
|
1134
|
+
hasRequestingServices,
|
|
1135
|
+
);
|
|
935
1136
|
processResourceResult(
|
|
936
1137
|
caResult,
|
|
937
1138
|
tenantsMap,
|
|
938
1139
|
pendingDomains,
|
|
939
1140
|
eventHelper,
|
|
940
|
-
|
|
941
1141
|
);
|
|
942
1142
|
break;
|
|
943
1143
|
|
|
@@ -1030,6 +1230,7 @@ const handleEvent = async (message: WSMessage) => {
|
|
|
1030
1230
|
eventData,
|
|
1031
1231
|
tokenMap,
|
|
1032
1232
|
userData,
|
|
1233
|
+
deletedTokenIds,
|
|
1033
1234
|
});
|
|
1034
1235
|
|
|
1035
1236
|
if (tokenResult.isUserToken) {
|
|
@@ -1236,6 +1437,7 @@ const handleOperationSuccess = (operation: PendingOperation, response: any) => {
|
|
|
1236
1437
|
const channelsInfo = mapChannelsFromApiData(
|
|
1237
1438
|
response.payload.data,
|
|
1238
1439
|
serviceName,
|
|
1440
|
+
service.resources,
|
|
1239
1441
|
);
|
|
1240
1442
|
service.serverChannels = channelsInfo.serverChannels;
|
|
1241
1443
|
service.clientChannels = channelsInfo.clientChannels;
|
|
@@ -1252,7 +1454,7 @@ const handleOperationSuccess = (operation: PendingOperation, response: any) => {
|
|
|
1252
1454
|
svcSuccessResult.revisionData
|
|
1253
1455
|
) {
|
|
1254
1456
|
try {
|
|
1255
|
-
|
|
1457
|
+
let updatedService = processRevisionData(
|
|
1256
1458
|
svcSuccessResult.updatedService!,
|
|
1257
1459
|
svcSuccessResult.revisionData,
|
|
1258
1460
|
revisionsMap,
|
|
@@ -1272,6 +1474,28 @@ const handleOperationSuccess = (operation: PendingOperation, response: any) => {
|
|
|
1272
1474
|
};
|
|
1273
1475
|
}
|
|
1274
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
|
+
|
|
1275
1499
|
servicesMap.set(svcSuccessResult.serviceId, updatedService);
|
|
1276
1500
|
|
|
1277
1501
|
if (updatedService.role && updatedService.role.length > 0) {
|
|
@@ -1326,16 +1550,18 @@ const handleOperationSuccess = (operation: PendingOperation, response: any) => {
|
|
|
1326
1550
|
originalData: originalData as Account,
|
|
1327
1551
|
});
|
|
1328
1552
|
|
|
1553
|
+
const accTenant = (originalData as Account)?.tenant;
|
|
1554
|
+
const accSuccessKey = accTenant ? `${accTenant}/${entityName}` : entityName;
|
|
1329
1555
|
if (accSuccessResult.shouldDelete) {
|
|
1330
|
-
const acc = accountsMap.get(
|
|
1556
|
+
const acc = accountsMap.get(accSuccessKey);
|
|
1331
1557
|
if (acc) {
|
|
1332
|
-
accountsMap.delete(
|
|
1558
|
+
accountsMap.delete(accSuccessKey);
|
|
1333
1559
|
eventHelper.notification.publish.creation(
|
|
1334
1560
|
accSuccessResult.notification,
|
|
1335
1561
|
);
|
|
1336
1562
|
}
|
|
1337
1563
|
} else if (accSuccessResult.updatedAccount) {
|
|
1338
|
-
accountsMap.set(
|
|
1564
|
+
accountsMap.set(accSuccessKey, accSuccessResult.updatedAccount);
|
|
1339
1565
|
if (accSuccessResult.eventType === "created") {
|
|
1340
1566
|
eventHelper.account.publish.created(accSuccessResult.updatedAccount);
|
|
1341
1567
|
} else if (accSuccessResult.eventType === "updated") {
|
|
@@ -1354,10 +1580,12 @@ const handleOperationSuccess = (operation: PendingOperation, response: any) => {
|
|
|
1354
1580
|
originalData: originalData as Environment,
|
|
1355
1581
|
});
|
|
1356
1582
|
|
|
1583
|
+
const envOrigData = originalData as Environment;
|
|
1584
|
+
const envSuccessKey = envOrigData?.tenant && envOrigData?.account ? `${envOrigData.tenant}/${envOrigData.account}/${entityName}` : entityName;
|
|
1357
1585
|
if (envSuccessResult.shouldDelete) {
|
|
1358
|
-
environmentsMap.delete(
|
|
1586
|
+
environmentsMap.delete(envSuccessKey);
|
|
1359
1587
|
} else if (envSuccessResult.updatedEnvironment) {
|
|
1360
|
-
environmentsMap.set(
|
|
1588
|
+
environmentsMap.set(envSuccessKey, envSuccessResult.updatedEnvironment);
|
|
1361
1589
|
if (envSuccessResult.notification) {
|
|
1362
1590
|
eventHelper.notification.publish.creation(
|
|
1363
1591
|
envSuccessResult.notification,
|
|
@@ -1385,15 +1613,44 @@ const handleOperationSuccess = (operation: PendingOperation, response: any) => {
|
|
|
1385
1613
|
}
|
|
1386
1614
|
break;
|
|
1387
1615
|
case "token":
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
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
|
+
}
|
|
1392
1638
|
break;
|
|
1393
1639
|
case "user":
|
|
1394
1640
|
if (action === "DELETE") {
|
|
1395
|
-
|
|
1396
|
-
|
|
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
|
+
}
|
|
1397
1654
|
}
|
|
1398
1655
|
break;
|
|
1399
1656
|
}
|
|
@@ -1458,10 +1715,12 @@ const handleOperationError = (operation: PendingOperation, error: any) => {
|
|
|
1458
1715
|
error,
|
|
1459
1716
|
});
|
|
1460
1717
|
|
|
1718
|
+
const accErrorTenant = (originalData as Account)?.tenant;
|
|
1719
|
+
const accErrorKey = accErrorTenant ? `${accErrorTenant}/${entityName}` : entityName;
|
|
1461
1720
|
if (accErrorResult.shouldDelete) {
|
|
1462
|
-
accountsMap.delete(
|
|
1721
|
+
accountsMap.delete(accErrorKey);
|
|
1463
1722
|
} else if (accErrorResult.updatedAccount) {
|
|
1464
|
-
accountsMap.set(
|
|
1723
|
+
accountsMap.set(accErrorKey, accErrorResult.updatedAccount);
|
|
1465
1724
|
}
|
|
1466
1725
|
|
|
1467
1726
|
if (accErrorResult.eventType === "creationError") {
|
|
@@ -1471,7 +1730,6 @@ const handleOperationError = (operation: PendingOperation, error: any) => {
|
|
|
1471
1730
|
} else if (accErrorResult.eventType === "deletionError") {
|
|
1472
1731
|
eventHelper.account.publish.deletionError(originalData);
|
|
1473
1732
|
}
|
|
1474
|
-
eventHelper.notification.publish.creation(accErrorResult.notification);
|
|
1475
1733
|
break;
|
|
1476
1734
|
case "environment":
|
|
1477
1735
|
const envErrorResult = handleEnvironmentOperationError({
|
|
@@ -1488,7 +1746,9 @@ const handleOperationError = (operation: PendingOperation, error: any) => {
|
|
|
1488
1746
|
eventHelper.environment.publish.deletionError(originalData);
|
|
1489
1747
|
}
|
|
1490
1748
|
eventHelper.notification.publish.creation(envErrorResult.notification);
|
|
1491
|
-
|
|
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);
|
|
1492
1752
|
break;
|
|
1493
1753
|
}
|
|
1494
1754
|
setTimeout(async () => {
|
|
@@ -1519,11 +1779,12 @@ const handleDeleteEvent = async (message: WSMessage) => {
|
|
|
1519
1779
|
}
|
|
1520
1780
|
if (keyParts.environment && !keyParts.service) {
|
|
1521
1781
|
const environmentName = keyParts.environment;
|
|
1522
|
-
const
|
|
1782
|
+
const envDeleteKey = tenantName && keyParts.account ? `${tenantName}/${keyParts.account}/${environmentName}` : environmentName;
|
|
1783
|
+
const deletedEnv = environmentsMap.get(envDeleteKey)!;
|
|
1523
1784
|
eventHelper.environment.publish.deleted(deletedEnv);
|
|
1524
1785
|
const envNotification: Notification = {
|
|
1525
1786
|
type: "success",
|
|
1526
|
-
subtype:
|
|
1787
|
+
subtype: errors.environment.deleted.subtype,
|
|
1527
1788
|
date: Date.now().toString(),
|
|
1528
1789
|
callToAction: false,
|
|
1529
1790
|
status: "unread",
|
|
@@ -1534,15 +1795,16 @@ const handleDeleteEvent = async (message: WSMessage) => {
|
|
|
1534
1795
|
},
|
|
1535
1796
|
};
|
|
1536
1797
|
eventHelper.notification.publish.creation(envNotification);
|
|
1537
|
-
environmentsMap.delete(
|
|
1798
|
+
environmentsMap.delete(envDeleteKey);
|
|
1538
1799
|
}
|
|
1539
1800
|
if (keyParts.account && !keyParts.environment) {
|
|
1540
1801
|
const accountName = keyParts.account;
|
|
1541
|
-
const
|
|
1802
|
+
const accountDeleteKey = tenantName ? `${tenantName}/${accountName}` : accountName;
|
|
1803
|
+
const deletedAccount = accountsMap.get(accountDeleteKey)!;
|
|
1542
1804
|
eventHelper.account.publish.deleted(deletedAccount);
|
|
1543
1805
|
const accountNotification: Notification = {
|
|
1544
1806
|
type: "success",
|
|
1545
|
-
subtype:
|
|
1807
|
+
subtype: errors.account.deleted.subtype,
|
|
1546
1808
|
date: Date.now().toString(),
|
|
1547
1809
|
callToAction: false,
|
|
1548
1810
|
status: "unread",
|
|
@@ -1552,7 +1814,7 @@ const handleDeleteEvent = async (message: WSMessage) => {
|
|
|
1552
1814
|
},
|
|
1553
1815
|
};
|
|
1554
1816
|
eventHelper.notification.publish.creation(accountNotification);
|
|
1555
|
-
accountsMap.delete(
|
|
1817
|
+
accountsMap.delete(accountDeleteKey);
|
|
1556
1818
|
}
|
|
1557
1819
|
if (keyParts.domain) {
|
|
1558
1820
|
const domainName = keyParts.domain;
|
|
@@ -1680,7 +1942,7 @@ const handleDeleteEvent = async (message: WSMessage) => {
|
|
|
1680
1942
|
tenantsMap.set(tenantName, registryTenant);
|
|
1681
1943
|
const registryNotification: Notification = {
|
|
1682
1944
|
type: "success",
|
|
1683
|
-
subtype:
|
|
1945
|
+
subtype: errors.registry.deleted.subtype,
|
|
1684
1946
|
date: Date.now().toString(),
|
|
1685
1947
|
status: "unread",
|
|
1686
1948
|
callToAction: false,
|
|
@@ -1736,7 +1998,7 @@ const handleDeleteEvent = async (message: WSMessage) => {
|
|
|
1736
1998
|
if (deletedLinkInfo) {
|
|
1737
1999
|
const unlinkNotification: Notification = {
|
|
1738
2000
|
type: "success",
|
|
1739
|
-
subtype:
|
|
2001
|
+
subtype: errors.service.unlinked.subtype,
|
|
1740
2002
|
date: Date.now().toString(),
|
|
1741
2003
|
status: "unread",
|
|
1742
2004
|
callToAction: false,
|
|
@@ -1753,24 +2015,17 @@ const handleDeleteEvent = async (message: WSMessage) => {
|
|
|
1753
2015
|
}
|
|
1754
2016
|
}
|
|
1755
2017
|
if (keyParts.token && keyParts.user) {
|
|
1756
|
-
const
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
callToAction: false,
|
|
1768
|
-
data: {
|
|
1769
|
-
tokenName: deletedToken.name,
|
|
1770
|
-
tenant: deletedToken.tenant,
|
|
1771
|
-
},
|
|
1772
|
-
};
|
|
1773
|
-
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
|
+
);
|
|
1774
2029
|
}
|
|
1775
2030
|
}
|
|
1776
2031
|
rebuildHierarchy();
|
|
@@ -1812,9 +2067,10 @@ const getChannelsInfo = async (
|
|
|
1812
2067
|
const updateEnvironmentsCloudProvider = (
|
|
1813
2068
|
accountId: string,
|
|
1814
2069
|
cloudProviderName: string,
|
|
2070
|
+
tenantId?: string,
|
|
1815
2071
|
) => {
|
|
1816
2072
|
environmentsMap.forEach((environment, envId) => {
|
|
1817
|
-
if (environment.account === accountId) {
|
|
2073
|
+
if (environment.account === accountId && (!tenantId || environment.tenant === tenantId)) {
|
|
1818
2074
|
environment.cloudProvider = cloudProviderName;
|
|
1819
2075
|
environmentsMap.set(envId, environment);
|
|
1820
2076
|
}
|
|
@@ -1832,7 +2088,8 @@ const loadReportingForEnvironment = async (environment: Environment) => {
|
|
|
1832
2088
|
reportingData !== null &&
|
|
1833
2089
|
Array.isArray(reportingData)
|
|
1834
2090
|
) {
|
|
1835
|
-
const
|
|
2091
|
+
const envReportKey = environment.tenant && environment.account ? `${environment.tenant}/${environment.account}/${environment.id}` : environment.id;
|
|
2092
|
+
const updatedEnvironment = environmentsMap.get(envReportKey);
|
|
1836
2093
|
|
|
1837
2094
|
if (!updatedEnvironment) {
|
|
1838
2095
|
console.warn(`Environment ${environment.id} not found in map`);
|
|
@@ -1863,7 +2120,7 @@ const loadReportingForEnvironment = async (environment: Environment) => {
|
|
|
1863
2120
|
);
|
|
1864
2121
|
}
|
|
1865
2122
|
|
|
1866
|
-
environmentsMap.set(
|
|
2123
|
+
environmentsMap.set(envReportKey, updatedEnvironment);
|
|
1867
2124
|
}
|
|
1868
2125
|
} catch (error) {
|
|
1869
2126
|
console.error(
|
|
@@ -1895,8 +2152,20 @@ export const updateUserComplete = (updatedUserData: UserData): User => {
|
|
|
1895
2152
|
try {
|
|
1896
2153
|
const preservedNotifications =
|
|
1897
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
|
+
|
|
1898
2166
|
userData = {
|
|
1899
2167
|
id: updatedUserData.id || userData.id,
|
|
2168
|
+
created: updatedUserData.created || userData.created,
|
|
1900
2169
|
name: updatedUserData.name || userData.name,
|
|
1901
2170
|
surname: updatedUserData.surname || userData.surname,
|
|
1902
2171
|
provider: updatedUserData.provider || userData.provider || [],
|
|
@@ -1906,7 +2175,7 @@ export const updateUserComplete = (updatedUserData: UserData): User => {
|
|
|
1906
2175
|
"",
|
|
1907
2176
|
organizations: updatedUserData.organizations || [],
|
|
1908
2177
|
clusterTokens: updatedUserData.clusterTokens || [],
|
|
1909
|
-
tokens:
|
|
2178
|
+
tokens: mergedTokens,
|
|
1910
2179
|
tenants: updatedUserData.tenants || [],
|
|
1911
2180
|
axebowPlan:
|
|
1912
2181
|
updatedUserData.axebowPlan || userData.axebowPlan || "freemium",
|
|
@@ -1917,6 +2186,7 @@ export const updateUserComplete = (updatedUserData: UserData): User => {
|
|
|
1917
2186
|
status: updatedUserData.status,
|
|
1918
2187
|
discoveryMethod:
|
|
1919
2188
|
updatedUserData.discoveryMethod || userData.discoveryMethod,
|
|
2189
|
+
promotionInfo: computePromotionInfo(updatedUserData.tenants || userData.tenants || []),
|
|
1920
2190
|
};
|
|
1921
2191
|
user = new User(
|
|
1922
2192
|
userData,
|
|
@@ -1935,7 +2205,7 @@ const resolveServiceStatus = (service: Service): Service => {
|
|
|
1935
2205
|
return service;
|
|
1936
2206
|
}
|
|
1937
2207
|
|
|
1938
|
-
const revisionKey =
|
|
2208
|
+
const revisionKey = `/tenant/${service.tenant}/service/${service.name}/revision/${service.currentRevision}`;
|
|
1939
2209
|
const currentRevision = revisionsMap.get(revisionKey);
|
|
1940
2210
|
|
|
1941
2211
|
if (!currentRevision) {
|
|
@@ -1963,3 +2233,58 @@ const resolveServiceStatus = (service: Service): Service => {
|
|
|
1963
2233
|
status: currentRevision.status,
|
|
1964
2234
|
};
|
|
1965
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
|
+
|