@oneuptime/common 9.2.16 → 9.2.17

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.
Files changed (115) hide show
  1. package/Models/DatabaseModels/CodeRepository.ts +664 -0
  2. package/Models/DatabaseModels/Index.ts +8 -0
  3. package/Models/DatabaseModels/LlmLog.ts +818 -0
  4. package/Models/DatabaseModels/LlmProvider.ts +21 -0
  5. package/Models/DatabaseModels/Project.ts +206 -0
  6. package/Models/DatabaseModels/ServiceCatalogCodeRepository.ts +549 -0
  7. package/Server/API/AIBillingAPI.ts +126 -0
  8. package/Server/API/GitHubAPI.ts +360 -0
  9. package/Server/API/IncidentAPI.ts +126 -0
  10. package/Server/EnvironmentConfig.ts +44 -0
  11. package/Server/Infrastructure/Postgres/SchemaMigrations/1765580181582-MigrationName.ts +79 -0
  12. package/Server/Infrastructure/Postgres/SchemaMigrations/1765633554715-MigrationName.ts +75 -0
  13. package/Server/Infrastructure/Postgres/SchemaMigrations/1765801357168-MigrationName.ts +32 -0
  14. package/Server/Infrastructure/Postgres/SchemaMigrations/1765810218488-MigrationName.ts +69 -0
  15. package/Server/Infrastructure/Postgres/SchemaMigrations/1765830758857-MigrationName.ts +111 -0
  16. package/Server/Infrastructure/Postgres/SchemaMigrations/1765834537501-MigrationName.ts +39 -0
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +12 -0
  18. package/Server/Services/AIBillingService.ts +247 -0
  19. package/Server/Services/AIService.ts +239 -0
  20. package/Server/Services/CodeRepositoryService.ts +10 -0
  21. package/Server/Services/IncidentService.ts +89 -0
  22. package/Server/Services/Index.ts +2 -0
  23. package/Server/Services/LlmLogService.ts +14 -0
  24. package/Server/Services/LlmProviderService.ts +58 -0
  25. package/Server/Services/ServiceCatalogCodeRepositoryService.ts +55 -0
  26. package/Server/Utils/AI/IncidentAIContextBuilder.ts +498 -0
  27. package/Server/Utils/CodeRepository/GitHub/GitHub.ts +226 -0
  28. package/Server/Utils/LLM/LLMService.ts +276 -0
  29. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +166 -0
  30. package/Server/Utils/Workspace/Slack/Slack.ts +134 -0
  31. package/Server/Utils/Workspace/Workspace.ts +126 -0
  32. package/Types/CodeRepository/CodeRepositoryType.ts +1 -1
  33. package/Types/LlmLogStatus.ts +7 -0
  34. package/Types/Permission.ts +87 -0
  35. package/Types/ServiceCatalog/CodeRepositoryImprovementAction.ts +9 -0
  36. package/UI/Components/AI/AILoader.tsx +95 -0
  37. package/UI/Components/AI/GenerateFromAIModal.tsx +295 -0
  38. package/UI/Components/Modal/Modal.tsx +6 -1
  39. package/build/dist/Models/DatabaseModels/CodeRepository.js +689 -0
  40. package/build/dist/Models/DatabaseModels/CodeRepository.js.map +1 -0
  41. package/build/dist/Models/DatabaseModels/Index.js +7 -0
  42. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  43. package/build/dist/Models/DatabaseModels/LlmLog.js +856 -0
  44. package/build/dist/Models/DatabaseModels/LlmLog.js.map +1 -0
  45. package/build/dist/Models/DatabaseModels/LlmProvider.js +22 -0
  46. package/build/dist/Models/DatabaseModels/LlmProvider.js.map +1 -1
  47. package/build/dist/Models/DatabaseModels/Project.js +220 -0
  48. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  49. package/build/dist/Models/DatabaseModels/ServiceCatalogCodeRepository.js +565 -0
  50. package/build/dist/Models/DatabaseModels/ServiceCatalogCodeRepository.js.map +1 -0
  51. package/build/dist/Server/API/AIBillingAPI.js +58 -0
  52. package/build/dist/Server/API/AIBillingAPI.js.map +1 -0
  53. package/build/dist/Server/API/GitHubAPI.js +207 -0
  54. package/build/dist/Server/API/GitHubAPI.js.map +1 -0
  55. package/build/dist/Server/API/IncidentAPI.js +84 -1
  56. package/build/dist/Server/API/IncidentAPI.js.map +1 -1
  57. package/build/dist/Server/EnvironmentConfig.js +31 -0
  58. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  59. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765580181582-MigrationName.js +34 -0
  60. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765580181582-MigrationName.js.map +1 -0
  61. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765633554715-MigrationName.js +32 -0
  62. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765633554715-MigrationName.js.map +1 -0
  63. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765801357168-MigrationName.js +38 -0
  64. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765801357168-MigrationName.js.map +1 -0
  65. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765810218488-MigrationName.js +30 -0
  66. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765810218488-MigrationName.js.map +1 -0
  67. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765830758857-MigrationName.js +44 -0
  68. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765830758857-MigrationName.js.map +1 -0
  69. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765834537501-MigrationName.js +22 -0
  70. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765834537501-MigrationName.js.map +1 -0
  71. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +12 -0
  72. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  73. package/build/dist/Server/Services/AIBillingService.js +187 -0
  74. package/build/dist/Server/Services/AIBillingService.js.map +1 -0
  75. package/build/dist/Server/Services/AIService.js +185 -0
  76. package/build/dist/Server/Services/AIService.js.map +1 -0
  77. package/build/dist/Server/Services/CodeRepositoryService.js +9 -0
  78. package/build/dist/Server/Services/CodeRepositoryService.js.map +1 -0
  79. package/build/dist/Server/Services/IncidentService.js +61 -0
  80. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  81. package/build/dist/Server/Services/Index.js +2 -0
  82. package/build/dist/Server/Services/Index.js.map +1 -1
  83. package/build/dist/Server/Services/LlmLogService.js +13 -0
  84. package/build/dist/Server/Services/LlmLogService.js.map +1 -0
  85. package/build/dist/Server/Services/LlmProviderService.js +65 -0
  86. package/build/dist/Server/Services/LlmProviderService.js.map +1 -1
  87. package/build/dist/Server/Services/ServiceCatalogCodeRepositoryService.js +54 -0
  88. package/build/dist/Server/Services/ServiceCatalogCodeRepositoryService.js.map +1 -0
  89. package/build/dist/Server/Utils/AI/IncidentAIContextBuilder.js +408 -0
  90. package/build/dist/Server/Utils/AI/IncidentAIContextBuilder.js.map +1 -0
  91. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js +163 -0
  92. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js.map +1 -1
  93. package/build/dist/Server/Utils/LLM/LLMService.js +225 -0
  94. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -0
  95. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +110 -0
  96. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  97. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +89 -0
  98. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  99. package/build/dist/Server/Utils/Workspace/Workspace.js +80 -0
  100. package/build/dist/Server/Utils/Workspace/Workspace.js.map +1 -1
  101. package/build/dist/Types/CodeRepository/CodeRepositoryType.js +1 -1
  102. package/build/dist/Types/CodeRepository/CodeRepositoryType.js.map +1 -1
  103. package/build/dist/Types/LlmLogStatus.js +8 -0
  104. package/build/dist/Types/LlmLogStatus.js.map +1 -0
  105. package/build/dist/Types/Permission.js +74 -0
  106. package/build/dist/Types/Permission.js.map +1 -1
  107. package/build/dist/Types/ServiceCatalog/CodeRepositoryImprovementAction.js +10 -0
  108. package/build/dist/Types/ServiceCatalog/CodeRepositoryImprovementAction.js.map +1 -0
  109. package/build/dist/UI/Components/AI/AILoader.js +64 -0
  110. package/build/dist/UI/Components/AI/AILoader.js.map +1 -0
  111. package/build/dist/UI/Components/AI/GenerateFromAIModal.js +207 -0
  112. package/build/dist/UI/Components/AI/GenerateFromAIModal.js.map +1 -0
  113. package/build/dist/UI/Components/Modal/Modal.js +6 -1
  114. package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
  115. package/package.json +1 -1
@@ -1896,4 +1896,138 @@ export default class SlackUtil extends WorkspaceBase {
1896
1896
  public static convertMarkdownToSlackRichText(markdown: string): string {
1897
1897
  return SlackifyMarkdown(markdown);
1898
1898
  }
1899
+
1900
+ @CaptureSpan()
1901
+ public static async getChannelMessages(params: {
1902
+ channelId: string;
1903
+ authToken: string;
1904
+ limit?: number;
1905
+ oldestTimestamp?: Date;
1906
+ }): Promise<
1907
+ Array<{
1908
+ messageId: string;
1909
+ text: string;
1910
+ userId?: string;
1911
+ username?: string;
1912
+ timestamp: Date;
1913
+ isBot: boolean;
1914
+ }>
1915
+ > {
1916
+ const messages: Array<{
1917
+ messageId: string;
1918
+ text: string;
1919
+ userId?: string;
1920
+ username?: string;
1921
+ timestamp: Date;
1922
+ isBot: boolean;
1923
+ }> = [];
1924
+ let cursor: string | undefined = undefined;
1925
+ const maxMessages: number = params.limit || 1000;
1926
+ const maxPages: number = 10;
1927
+ let pageCount: number = 0;
1928
+
1929
+ do {
1930
+ const requestData: JSONObject = {
1931
+ channel: params.channelId,
1932
+ limit: Math.min(200, maxMessages - messages.length),
1933
+ };
1934
+
1935
+ if (cursor) {
1936
+ requestData["cursor"] = cursor;
1937
+ }
1938
+
1939
+ if (params.oldestTimestamp) {
1940
+ requestData["oldest"] = (
1941
+ params.oldestTimestamp.getTime() / 1000
1942
+ ).toString();
1943
+ }
1944
+
1945
+ const response: HTTPErrorResponse | HTTPResponse<JSONObject> =
1946
+ await API.post<JSONObject>({
1947
+ url: URL.fromString("https://slack.com/api/conversations.history"),
1948
+ data: requestData,
1949
+ headers: {
1950
+ Authorization: `Bearer ${params.authToken}`,
1951
+ "Content-Type": "application/x-www-form-urlencoded",
1952
+ },
1953
+ options: {
1954
+ retries: 3,
1955
+ exponentialBackoff: true,
1956
+ },
1957
+ });
1958
+
1959
+ if (response instanceof HTTPErrorResponse) {
1960
+ logger.error("Error response from Slack API for channel history:");
1961
+ logger.error(response);
1962
+ break;
1963
+ }
1964
+
1965
+ const jsonData: JSONObject = response.jsonData as JSONObject;
1966
+
1967
+ if (jsonData["ok"] !== true) {
1968
+ logger.error("Invalid response from Slack API for channel history:");
1969
+ logger.error(jsonData);
1970
+ break;
1971
+ }
1972
+
1973
+ const slackMessages: Array<JSONObject> =
1974
+ (jsonData["messages"] as Array<JSONObject>) || [];
1975
+
1976
+ for (const msg of slackMessages) {
1977
+ // Skip bot messages if they're from the OneUptime bot (app messages)
1978
+ const isBot: boolean =
1979
+ Boolean(msg["bot_id"]) || msg["subtype"] === "bot_message";
1980
+
1981
+ // Extract text, handling attachments and blocks
1982
+ let text: string = (msg["text"] as string) || "";
1983
+
1984
+ // If there are attachments, append their text
1985
+ const attachments: Array<JSONObject> | undefined = msg[
1986
+ "attachments"
1987
+ ] as Array<JSONObject> | undefined;
1988
+ if (attachments && Array.isArray(attachments)) {
1989
+ for (const attachment of attachments) {
1990
+ if (attachment && attachment["text"]) {
1991
+ text += "\n" + (attachment["text"] as string);
1992
+ }
1993
+ if (attachment && attachment["fallback"]) {
1994
+ text += "\n" + (attachment["fallback"] as string);
1995
+ }
1996
+ }
1997
+ }
1998
+
1999
+ // Skip empty messages
2000
+ if (!text.trim()) {
2001
+ continue;
2002
+ }
2003
+
2004
+ const timestamp: Date = msg["ts"]
2005
+ ? new Date(parseFloat(msg["ts"] as string) * 1000)
2006
+ : new Date();
2007
+
2008
+ messages.push({
2009
+ messageId: msg["ts"] as string,
2010
+ text: text,
2011
+ userId: msg["user"] as string,
2012
+ username: msg["username"] as string,
2013
+ timestamp: timestamp,
2014
+ isBot: isBot,
2015
+ });
2016
+ }
2017
+
2018
+ cursor = (jsonData["response_metadata"] as JSONObject)?.[
2019
+ "next_cursor"
2020
+ ] as string;
2021
+ pageCount++;
2022
+ } while (cursor && messages.length < maxMessages && pageCount < maxPages);
2023
+
2024
+ logger.debug(
2025
+ `Retrieved ${messages.length} messages from Slack channel ${params.channelId}`,
2026
+ );
2027
+
2028
+ // Reverse to get chronological order (Slack returns newest first)
2029
+ messages.reverse();
2030
+
2031
+ return messages;
2032
+ }
1899
2033
  }
@@ -17,6 +17,16 @@ import WorkspaceUserAuthToken from "../../../Models/DatabaseModels/WorkspaceUser
17
17
  import WorkspaceUserAuthTokenService from "../../Services/WorkspaceUserAuthTokenService";
18
18
  import UserService from "../../Services/UserService";
19
19
  import CaptureSpan from "../Telemetry/CaptureSpan";
20
+ import OneUptimeDate from "../../../Types/Date";
21
+
22
+ export interface WorkspaceChannelMessage {
23
+ messageId: string;
24
+ text: string;
25
+ userId?: string;
26
+ username?: string;
27
+ timestamp: Date;
28
+ isBot: boolean;
29
+ }
20
30
 
21
31
  export default class WorkspaceUtil {
22
32
  @CaptureSpan()
@@ -236,4 +246,120 @@ export default class WorkspaceUtil {
236
246
 
237
247
  return result;
238
248
  }
249
+
250
+ @CaptureSpan()
251
+ public static async getChannelMessages(params: {
252
+ channelId: string;
253
+ authToken: string;
254
+ projectId: ObjectID;
255
+ workspaceType: WorkspaceType;
256
+ teamId?: string;
257
+ limit?: number;
258
+ oldestTimestamp?: Date;
259
+ }): Promise<Array<WorkspaceChannelMessage>> {
260
+ switch (params.workspaceType) {
261
+ case WorkspaceType.Slack: {
262
+ const slackParams: {
263
+ channelId: string;
264
+ authToken: string;
265
+ limit?: number;
266
+ oldestTimestamp?: Date;
267
+ } = {
268
+ channelId: params.channelId,
269
+ authToken: params.authToken,
270
+ };
271
+
272
+ if (params.limit !== undefined) {
273
+ slackParams.limit = params.limit;
274
+ }
275
+
276
+ if (params.oldestTimestamp) {
277
+ slackParams.oldestTimestamp = params.oldestTimestamp;
278
+ }
279
+
280
+ return await SlackWorkspace.getChannelMessages(slackParams);
281
+ }
282
+ case WorkspaceType.MicrosoftTeams: {
283
+ if (!params.teamId) {
284
+ logger.error(
285
+ "Team ID is required for Microsoft Teams channel messages",
286
+ );
287
+ return [];
288
+ }
289
+
290
+ const teamsParams: {
291
+ channelId: string;
292
+ teamId: string;
293
+ projectId: ObjectID;
294
+ limit?: number;
295
+ oldestTimestamp?: Date;
296
+ } = {
297
+ channelId: params.channelId,
298
+ teamId: params.teamId,
299
+ projectId: params.projectId,
300
+ };
301
+
302
+ if (params.limit !== undefined) {
303
+ teamsParams.limit = params.limit;
304
+ }
305
+
306
+ if (params.oldestTimestamp) {
307
+ teamsParams.oldestTimestamp = params.oldestTimestamp;
308
+ }
309
+
310
+ return await MicrosoftTeamsUtil.getChannelMessages(teamsParams);
311
+ }
312
+ default:
313
+ logger.debug(
314
+ `Unsupported workspace type for channel messages: ${params.workspaceType}`,
315
+ );
316
+ return [];
317
+ }
318
+ }
319
+
320
+ @CaptureSpan()
321
+ public static formatMessagesAsContext(
322
+ messages: Array<WorkspaceChannelMessage>,
323
+ options?: {
324
+ includeTimestamp?: boolean;
325
+ includeUsername?: boolean;
326
+ maxLength?: number;
327
+ },
328
+ ): string {
329
+ const includeTimestamp: boolean = options?.includeTimestamp ?? true;
330
+ const includeUsername: boolean = options?.includeUsername ?? true;
331
+ const maxLength: number = options?.maxLength || 50000;
332
+
333
+ let context: string = "";
334
+
335
+ for (const msg of messages) {
336
+ let line: string = "";
337
+
338
+ if (includeTimestamp) {
339
+ const dateStr: string = OneUptimeDate.getDateAsFormattedString(
340
+ msg.timestamp,
341
+ );
342
+ line += `[${dateStr}] `;
343
+ }
344
+
345
+ if (includeUsername && msg.username) {
346
+ line += `${msg.username}: `;
347
+ } else if (includeUsername && msg.userId) {
348
+ line += `User ${msg.userId}: `;
349
+ }
350
+
351
+ line += msg.text;
352
+ line += "\n";
353
+
354
+ // Check if adding this line would exceed max length
355
+ if (context.length + line.length > maxLength) {
356
+ context += "\n... (messages truncated due to length)";
357
+ break;
358
+ }
359
+
360
+ context += line;
361
+ }
362
+
363
+ return context.trim();
364
+ }
239
365
  }
@@ -1,6 +1,6 @@
1
1
  enum CodeRepositoryType {
2
2
  GitHub = "GitHub",
3
- // GitLab = 'GitLab',
3
+ GitLab = "GitLab",
4
4
  }
5
5
 
6
6
  export default CodeRepositoryType;
@@ -0,0 +1,7 @@
1
+ enum LlmLogStatus {
2
+ Success = "Success",
3
+ Error = "Error",
4
+ InsufficientBalance = "Insufficient Balance",
5
+ }
6
+
7
+ export default LlmLogStatus;
@@ -147,6 +147,7 @@ enum Permission {
147
147
  ReadCallLog = "ReadCallLog",
148
148
  ReadPushLog = "ReadPushLog",
149
149
  ReadWorkspaceNotificationLog = "ReadWorkspaceNotificationLog",
150
+ ReadLlmLog = "ReadLlmLog",
150
151
 
151
152
  CreateIncidentOwnerTeam = "CreateIncidentOwnerTeam",
152
153
  DeleteIncidentOwnerTeam = "DeleteIncidentOwnerTeam",
@@ -624,6 +625,17 @@ enum Permission {
624
625
  EditServiceCatalogTelemetryService = "EditServiceCatalogTelemetryService",
625
626
  ReadServiceCatalogTelemetryService = "ReadServiceCatalogTelemetryService",
626
627
 
628
+ CreateServiceCatalogCodeRepository = "CreateServiceCatalogCodeRepository",
629
+ DeleteServiceCatalogCodeRepository = "DeleteServiceCatalogCodeRepository",
630
+ EditServiceCatalogCodeRepository = "EditServiceCatalogCodeRepository",
631
+ ReadServiceCatalogCodeRepository = "ReadServiceCatalogCodeRepository",
632
+
633
+ // Code Repository
634
+ CreateCodeRepository = "CreateCodeRepository",
635
+ DeleteCodeRepository = "DeleteCodeRepository",
636
+ EditCodeRepository = "EditCodeRepository",
637
+ ReadCodeRepository = "ReadCodeRepository",
638
+
627
639
  CreateProbeOwnerTeam = "CreateProbeOwnerTeam",
628
640
  DeleteProbeOwnerTeam = "DeleteProbeOwnerTeam",
629
641
  EditProbeOwnerTeam = "EditProbeOwnerTeam",
@@ -3132,6 +3144,14 @@ export class PermissionHelper {
3132
3144
  isAccessControlPermission: false,
3133
3145
  },
3134
3146
 
3147
+ {
3148
+ permission: Permission.ReadLlmLog,
3149
+ title: "Read LLM Log",
3150
+ description: "This permission can read LLM Logs of this project.",
3151
+ isAssignableToTenant: true,
3152
+ isAccessControlPermission: false,
3153
+ },
3154
+
3135
3155
  {
3136
3156
  permission: Permission.CreateMonitorProbe,
3137
3157
  title: "Create Monitor Probe",
@@ -3417,6 +3437,73 @@ export class PermissionHelper {
3417
3437
  isAccessControlPermission: false,
3418
3438
  },
3419
3439
 
3440
+ {
3441
+ permission: Permission.CreateServiceCatalogCodeRepository,
3442
+ title: "Create Service Catalog Code Repository",
3443
+ description:
3444
+ "This permission can create Service Catalog Code Repository in this project.",
3445
+ isAssignableToTenant: true,
3446
+ isAccessControlPermission: false,
3447
+ },
3448
+ {
3449
+ permission: Permission.DeleteServiceCatalogCodeRepository,
3450
+ title: "Delete Service Catalog Code Repository",
3451
+ description:
3452
+ "This permission can delete Service Catalog Code Repository of this project.",
3453
+ isAssignableToTenant: true,
3454
+ isAccessControlPermission: false,
3455
+ },
3456
+ {
3457
+ permission: Permission.EditServiceCatalogCodeRepository,
3458
+ title: "Edit Service Catalog Code Repository",
3459
+ description:
3460
+ "This permission can edit Service Catalog Code Repository of this project.",
3461
+ isAssignableToTenant: true,
3462
+ isAccessControlPermission: false,
3463
+ },
3464
+ {
3465
+ permission: Permission.ReadServiceCatalogCodeRepository,
3466
+ title: "Read Service Catalog Code Repository",
3467
+ description:
3468
+ "This permission can read Service Catalog Code Repository of this project.",
3469
+ isAssignableToTenant: true,
3470
+ isAccessControlPermission: false,
3471
+ },
3472
+
3473
+ // Code Repository Permissions
3474
+ {
3475
+ permission: Permission.CreateCodeRepository,
3476
+ title: "Create Code Repository",
3477
+ description:
3478
+ "This permission can create Code Repositories in this project.",
3479
+ isAssignableToTenant: true,
3480
+ isAccessControlPermission: true,
3481
+ },
3482
+ {
3483
+ permission: Permission.DeleteCodeRepository,
3484
+ title: "Delete Code Repository",
3485
+ description:
3486
+ "This permission can delete Code Repositories of this project.",
3487
+ isAssignableToTenant: true,
3488
+ isAccessControlPermission: true,
3489
+ },
3490
+ {
3491
+ permission: Permission.EditCodeRepository,
3492
+ title: "Edit Code Repository",
3493
+ description:
3494
+ "This permission can edit Code Repositories of this project.",
3495
+ isAssignableToTenant: true,
3496
+ isAccessControlPermission: true,
3497
+ },
3498
+ {
3499
+ permission: Permission.ReadCodeRepository,
3500
+ title: "Read Code Repository",
3501
+ description:
3502
+ "This permission can read Code Repositories of this project.",
3503
+ isAssignableToTenant: true,
3504
+ isAccessControlPermission: true,
3505
+ },
3506
+
3420
3507
  {
3421
3508
  permission: Permission.CreateTelemetryServiceTraces,
3422
3509
  title: "Create Telemetry Service Traces",
@@ -0,0 +1,9 @@
1
+ enum CodeRepositoryImprovementAction {
2
+ FixExceptions = "Fix Exceptions",
3
+ ImproveLogs = "Improve Logs",
4
+ ImproveSpans = "Improve Spans",
5
+ ImproveMetrics = "Improve Metrics",
6
+ FixPerformanceIssues = "Fix Performance Issues",
7
+ }
8
+
9
+ export default CodeRepositoryImprovementAction;
@@ -0,0 +1,95 @@
1
+ import React, {
2
+ FunctionComponent,
3
+ ReactElement,
4
+ useEffect,
5
+ useState,
6
+ } from "react";
7
+
8
+ const loadingStages: Array<string> = ["Analyzing", "Processing", "Generating"];
9
+
10
+ const AILoader: FunctionComponent = (): ReactElement => {
11
+ const [stageIndex, setStageIndex] = useState<number>(0);
12
+ const [dots, setDots] = useState<string>("");
13
+
14
+ // Cycle through stages
15
+ useEffect(() => {
16
+ const interval: NodeJS.Timeout = setInterval(() => {
17
+ setStageIndex((prev: number) => {
18
+ return (prev + 1) % loadingStages.length;
19
+ });
20
+ }, 2500);
21
+
22
+ return () => {
23
+ clearInterval(interval);
24
+ };
25
+ }, []);
26
+
27
+ // Animate dots
28
+ useEffect(() => {
29
+ const interval: NodeJS.Timeout = setInterval(() => {
30
+ setDots((prev: string) => {
31
+ return prev.length >= 3 ? "" : prev + ".";
32
+ });
33
+ }, 400);
34
+
35
+ return () => {
36
+ clearInterval(interval);
37
+ };
38
+ }, []);
39
+
40
+ return (
41
+ <div className="py-8 px-4">
42
+ <div className="flex items-center justify-center gap-3">
43
+ {/* Pulsing AI indicator */}
44
+ <div className="relative">
45
+ <div
46
+ className="w-2 h-2 bg-indigo-600 rounded-full"
47
+ style={{
48
+ animation: "aiPulse 1.5s ease-in-out infinite",
49
+ }}
50
+ />
51
+ <div
52
+ className="absolute inset-0 w-2 h-2 bg-indigo-600 rounded-full"
53
+ style={{
54
+ animation: "aiPing 1.5s ease-out infinite",
55
+ }}
56
+ />
57
+ </div>
58
+
59
+ {/* Status text */}
60
+ <span className="text-sm text-gray-600 font-medium min-w-[100px]">
61
+ {loadingStages[stageIndex]}
62
+ <span className="inline-block w-4 text-left">{dots}</span>
63
+ </span>
64
+ </div>
65
+
66
+ {/* CSS for animations */}
67
+ <style>
68
+ {`
69
+ @keyframes aiPulse {
70
+ 0%, 100% {
71
+ opacity: 1;
72
+ transform: scale(1);
73
+ }
74
+ 50% {
75
+ opacity: 0.7;
76
+ transform: scale(1.1);
77
+ }
78
+ }
79
+ @keyframes aiPing {
80
+ 0% {
81
+ opacity: 0.6;
82
+ transform: scale(1);
83
+ }
84
+ 100% {
85
+ opacity: 0;
86
+ transform: scale(2.5);
87
+ }
88
+ }
89
+ `}
90
+ </style>
91
+ </div>
92
+ );
93
+ };
94
+
95
+ export default AILoader;