@oneuptime/common 9.2.16 → 9.2.18

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 (133) 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/AlertAPI.ts +139 -0
  9. package/Server/API/GitHubAPI.ts +360 -0
  10. package/Server/API/IncidentAPI.ts +258 -0
  11. package/Server/API/ScheduledMaintenanceAPI.ts +164 -0
  12. package/Server/EnvironmentConfig.ts +44 -0
  13. package/Server/Infrastructure/Postgres/SchemaMigrations/1765580181582-MigrationName.ts +79 -0
  14. package/Server/Infrastructure/Postgres/SchemaMigrations/1765633554715-MigrationName.ts +75 -0
  15. package/Server/Infrastructure/Postgres/SchemaMigrations/1765801357168-MigrationName.ts +32 -0
  16. package/Server/Infrastructure/Postgres/SchemaMigrations/1765810218488-MigrationName.ts +69 -0
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/1765830758857-MigrationName.ts +111 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/1765834537501-MigrationName.ts +39 -0
  19. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +12 -0
  20. package/Server/Services/AIBillingService.ts +247 -0
  21. package/Server/Services/AIService.ts +238 -0
  22. package/Server/Services/CodeRepositoryService.ts +10 -0
  23. package/Server/Services/IncidentService.ts +88 -0
  24. package/Server/Services/Index.ts +2 -0
  25. package/Server/Services/LlmLogService.ts +14 -0
  26. package/Server/Services/LlmProviderService.ts +58 -0
  27. package/Server/Services/ServiceCatalogCodeRepositoryService.ts +55 -0
  28. package/Server/Utils/AI/AlertAIContextBuilder.ts +264 -0
  29. package/Server/Utils/AI/IncidentAIContextBuilder.ts +710 -0
  30. package/Server/Utils/AI/ScheduledMaintenanceAIContextBuilder.ts +345 -0
  31. package/Server/Utils/CodeRepository/GitHub/GitHub.ts +226 -0
  32. package/Server/Utils/LLM/LLMService.ts +276 -0
  33. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +166 -0
  34. package/Server/Utils/Workspace/Slack/Slack.ts +134 -0
  35. package/Server/Utils/Workspace/Workspace.ts +126 -0
  36. package/Tests/Types/Domain.test.ts +24 -3
  37. package/Types/CodeRepository/CodeRepositoryType.ts +1 -1
  38. package/Types/Domain.ts +21 -24
  39. package/Types/LlmLogStatus.ts +7 -0
  40. package/Types/Permission.ts +87 -0
  41. package/Types/ServiceCatalog/CodeRepositoryImprovementAction.ts +9 -0
  42. package/UI/Components/AI/AILoader.tsx +95 -0
  43. package/UI/Components/AI/GenerateFromAIModal.tsx +432 -0
  44. package/UI/Components/Modal/Modal.tsx +6 -1
  45. package/build/dist/Models/DatabaseModels/CodeRepository.js +689 -0
  46. package/build/dist/Models/DatabaseModels/CodeRepository.js.map +1 -0
  47. package/build/dist/Models/DatabaseModels/Index.js +7 -0
  48. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  49. package/build/dist/Models/DatabaseModels/LlmLog.js +856 -0
  50. package/build/dist/Models/DatabaseModels/LlmLog.js.map +1 -0
  51. package/build/dist/Models/DatabaseModels/LlmProvider.js +22 -0
  52. package/build/dist/Models/DatabaseModels/LlmProvider.js.map +1 -1
  53. package/build/dist/Models/DatabaseModels/Project.js +220 -0
  54. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  55. package/build/dist/Models/DatabaseModels/ServiceCatalogCodeRepository.js +565 -0
  56. package/build/dist/Models/DatabaseModels/ServiceCatalogCodeRepository.js.map +1 -0
  57. package/build/dist/Server/API/AIBillingAPI.js +58 -0
  58. package/build/dist/Server/API/AIBillingAPI.js.map +1 -0
  59. package/build/dist/Server/API/AlertAPI.js +94 -0
  60. package/build/dist/Server/API/AlertAPI.js.map +1 -0
  61. package/build/dist/Server/API/GitHubAPI.js +207 -0
  62. package/build/dist/Server/API/GitHubAPI.js.map +1 -0
  63. package/build/dist/Server/API/IncidentAPI.js +171 -1
  64. package/build/dist/Server/API/IncidentAPI.js.map +1 -1
  65. package/build/dist/Server/API/ScheduledMaintenanceAPI.js +103 -0
  66. package/build/dist/Server/API/ScheduledMaintenanceAPI.js.map +1 -0
  67. package/build/dist/Server/EnvironmentConfig.js +31 -0
  68. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  69. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765580181582-MigrationName.js +34 -0
  70. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765580181582-MigrationName.js.map +1 -0
  71. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765633554715-MigrationName.js +32 -0
  72. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765633554715-MigrationName.js.map +1 -0
  73. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765801357168-MigrationName.js +38 -0
  74. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765801357168-MigrationName.js.map +1 -0
  75. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765810218488-MigrationName.js +30 -0
  76. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765810218488-MigrationName.js.map +1 -0
  77. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765830758857-MigrationName.js +44 -0
  78. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765830758857-MigrationName.js.map +1 -0
  79. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765834537501-MigrationName.js +22 -0
  80. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1765834537501-MigrationName.js.map +1 -0
  81. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +12 -0
  82. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  83. package/build/dist/Server/Services/AIBillingService.js +187 -0
  84. package/build/dist/Server/Services/AIBillingService.js.map +1 -0
  85. package/build/dist/Server/Services/AIService.js +184 -0
  86. package/build/dist/Server/Services/AIService.js.map +1 -0
  87. package/build/dist/Server/Services/CodeRepositoryService.js +9 -0
  88. package/build/dist/Server/Services/CodeRepositoryService.js.map +1 -0
  89. package/build/dist/Server/Services/IncidentService.js +60 -0
  90. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  91. package/build/dist/Server/Services/Index.js +2 -0
  92. package/build/dist/Server/Services/Index.js.map +1 -1
  93. package/build/dist/Server/Services/LlmLogService.js +13 -0
  94. package/build/dist/Server/Services/LlmLogService.js.map +1 -0
  95. package/build/dist/Server/Services/LlmProviderService.js +65 -0
  96. package/build/dist/Server/Services/LlmProviderService.js.map +1 -1
  97. package/build/dist/Server/Services/ServiceCatalogCodeRepositoryService.js +54 -0
  98. package/build/dist/Server/Services/ServiceCatalogCodeRepositoryService.js.map +1 -0
  99. package/build/dist/Server/Utils/AI/AlertAIContextBuilder.js +238 -0
  100. package/build/dist/Server/Utils/AI/AlertAIContextBuilder.js.map +1 -0
  101. package/build/dist/Server/Utils/AI/IncidentAIContextBuilder.js +597 -0
  102. package/build/dist/Server/Utils/AI/IncidentAIContextBuilder.js.map +1 -0
  103. package/build/dist/Server/Utils/AI/ScheduledMaintenanceAIContextBuilder.js +311 -0
  104. package/build/dist/Server/Utils/AI/ScheduledMaintenanceAIContextBuilder.js.map +1 -0
  105. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js +163 -0
  106. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js.map +1 -1
  107. package/build/dist/Server/Utils/LLM/LLMService.js +225 -0
  108. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -0
  109. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +110 -0
  110. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  111. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +89 -0
  112. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  113. package/build/dist/Server/Utils/Workspace/Workspace.js +80 -0
  114. package/build/dist/Server/Utils/Workspace/Workspace.js.map +1 -1
  115. package/build/dist/Tests/Types/Domain.test.js +19 -3
  116. package/build/dist/Tests/Types/Domain.test.js.map +1 -1
  117. package/build/dist/Types/CodeRepository/CodeRepositoryType.js +1 -1
  118. package/build/dist/Types/CodeRepository/CodeRepositoryType.js.map +1 -1
  119. package/build/dist/Types/Domain.js +18 -16
  120. package/build/dist/Types/Domain.js.map +1 -1
  121. package/build/dist/Types/LlmLogStatus.js +8 -0
  122. package/build/dist/Types/LlmLogStatus.js.map +1 -0
  123. package/build/dist/Types/Permission.js +74 -0
  124. package/build/dist/Types/Permission.js.map +1 -1
  125. package/build/dist/Types/ServiceCatalog/CodeRepositoryImprovementAction.js +10 -0
  126. package/build/dist/Types/ServiceCatalog/CodeRepositoryImprovementAction.js.map +1 -0
  127. package/build/dist/UI/Components/AI/AILoader.js +64 -0
  128. package/build/dist/UI/Components/AI/AILoader.js.map +1 -0
  129. package/build/dist/UI/Components/AI/GenerateFromAIModal.js +320 -0
  130. package/build/dist/UI/Components/AI/GenerateFromAIModal.js.map +1 -0
  131. package/build/dist/UI/Components/Modal/Modal.js +6 -1
  132. package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
  133. package/package.json +1 -1
@@ -0,0 +1,432 @@
1
+ import React, {
2
+ FunctionComponent,
3
+ ReactElement,
4
+ useState,
5
+ useEffect,
6
+ } from "react";
7
+ import Modal, { ModalWidth } from "../Modal/Modal";
8
+ import AILoader from "./AILoader";
9
+ import ErrorMessage from "../ErrorMessage/ErrorMessage";
10
+ import ButtonType from "../Button/ButtonTypes";
11
+ import { ButtonStyleType } from "../Button/Button";
12
+ import IconProp from "../../../Types/Icon/IconProp";
13
+ import Dropdown, { DropdownOption, DropdownValue } from "../Dropdown/Dropdown";
14
+ import MarkdownEditor from "../Markdown.tsx/MarkdownEditor";
15
+
16
+ export interface GenerateFromAIModalProps {
17
+ title: string;
18
+ description?: string;
19
+ onClose: () => void;
20
+ onGenerate: (data: GenerateAIRequestData) => Promise<string>;
21
+ onSuccess: (generatedContent: string) => void;
22
+ templates?: Array<{ id: string; name: string; content?: string }>;
23
+ noteType?: NoteType; // Type of note being generated (determines default templates)
24
+ }
25
+
26
+ export interface GenerateAIRequestData {
27
+ template?: string;
28
+ templateId?: string;
29
+ }
30
+
31
+ // Template categories for different note types
32
+ export type NoteType = "postmortem" | "public-note" | "internal-note";
33
+
34
+ // Default hardcoded templates for incident postmortem
35
+ const POSTMORTEM_TEMPLATES: Array<{
36
+ id: string;
37
+ name: string;
38
+ content: string;
39
+ }> = [
40
+ {
41
+ id: "default-standard",
42
+ name: "Standard Postmortem",
43
+ content: `## Executive Summary
44
+ [Brief overview of the incident, its impact, and resolution]
45
+
46
+ ## Incident Timeline
47
+ | Time | Event |
48
+ |------|-------|
49
+ | [Time] | [Event description] |
50
+
51
+ ## Root Cause Analysis
52
+ [Detailed analysis of what caused the incident]
53
+
54
+ ## Impact Assessment
55
+ - **Duration**: [How long the incident lasted]
56
+ - **Users Affected**: [Number or percentage of affected users]
57
+ - **Services Affected**: [List of affected services]
58
+
59
+ ## Resolution
60
+ [Steps taken to resolve the incident]
61
+
62
+ ## Action Items
63
+ - [ ] [Action item 1]
64
+ - [ ] [Action item 2]
65
+ - [ ] [Action item 3]
66
+
67
+ ## Lessons Learned
68
+ [Key takeaways and improvements identified]`,
69
+ },
70
+ {
71
+ id: "default-detailed",
72
+ name: "Detailed Technical Postmortem",
73
+ content: `## Incident Overview
74
+ **Incident Title**: [Title]
75
+ **Severity**: [P1/P2/P3/P4]
76
+ **Duration**: [Start time] - [End time]
77
+ **Authors**: [Names]
78
+
79
+ ## Summary
80
+ [2-3 sentence summary of the incident]
81
+
82
+ ## Detection
83
+ - **How was the incident detected?** [Monitoring alert / Customer report / etc.]
84
+ - **Time to detection**: [Duration from start to detection]
85
+
86
+ ## Timeline
87
+ | Timestamp | Action | Owner |
88
+ |-----------|--------|-------|
89
+ | [Time] | [What happened] | [Who did it] |
90
+
91
+ ## Root Cause
92
+ ### Primary Cause
93
+ [Detailed explanation of the root cause]
94
+
95
+ ### Contributing Factors
96
+ 1. [Factor 1]
97
+ 2. [Factor 2]
98
+
99
+ ## Impact
100
+ ### Customer Impact
101
+ [Description of how customers were affected]
102
+
103
+ ### Business Impact
104
+ [Description of business consequences]
105
+
106
+ ### Technical Impact
107
+ [Systems and services affected]
108
+
109
+ ## Mitigation & Resolution
110
+ ### Immediate Actions
111
+ [Steps taken to stop the bleeding]
112
+
113
+ ### Permanent Fix
114
+ [Long-term solution implemented]
115
+
116
+ ## Prevention
117
+ ### What Went Well
118
+ - [Item 1]
119
+ - [Item 2]
120
+
121
+ ### What Went Wrong
122
+ - [Item 1]
123
+ - [Item 2]
124
+
125
+ ### Where We Got Lucky
126
+ - [Item 1]
127
+
128
+ ## Action Items
129
+ | Action | Owner | Priority | Due Date |
130
+ |--------|-------|----------|----------|
131
+ | [Action] | [Name] | [High/Medium/Low] | [Date] |
132
+
133
+ ## Appendix
134
+ [Any additional technical details, logs, or graphs]`,
135
+ },
136
+ {
137
+ id: "default-brief",
138
+ name: "Brief Postmortem",
139
+ content: `## What Happened
140
+ [Concise description of the incident]
141
+
142
+ ## Why It Happened
143
+ [Root cause explanation]
144
+
145
+ ## How We Fixed It
146
+ [Resolution steps]
147
+
148
+ ## How We Prevent It
149
+ - [ ] [Prevention action 1]
150
+ - [ ] [Prevention action 2]`,
151
+ },
152
+ ];
153
+
154
+ // Default templates for public notes (customer-facing)
155
+ const PUBLIC_NOTE_TEMPLATES: Array<{
156
+ id: string;
157
+ name: string;
158
+ content: string;
159
+ }> = [
160
+ {
161
+ id: "public-status-update",
162
+ name: "Status Update",
163
+ content: `## Current Status
164
+ [Brief description of the current situation]
165
+
166
+ ## What We're Doing
167
+ [Actions being taken to resolve the issue]
168
+
169
+ ## Next Update
170
+ [Expected time for next update or resolution]`,
171
+ },
172
+ {
173
+ id: "public-resolution",
174
+ name: "Resolution Notice",
175
+ content: `## Issue Resolved
176
+ [Brief description of what was resolved]
177
+
178
+ ## Summary
179
+ [What happened and how it was fixed]
180
+
181
+ ## Prevention
182
+ [Steps taken to prevent recurrence]
183
+
184
+ Thank you for your patience.`,
185
+ },
186
+ {
187
+ id: "public-maintenance",
188
+ name: "Maintenance Update",
189
+ content: `## Maintenance Status
190
+ [Current phase of the maintenance]
191
+
192
+ ## Progress
193
+ [What has been completed]
194
+
195
+ ## Remaining Work
196
+ [What still needs to be done]
197
+
198
+ ## Expected Completion
199
+ [Estimated completion time]`,
200
+ },
201
+ ];
202
+
203
+ // Default templates for internal notes (team-facing)
204
+ const INTERNAL_NOTE_TEMPLATES: Array<{
205
+ id: string;
206
+ name: string;
207
+ content: string;
208
+ }> = [
209
+ {
210
+ id: "internal-investigation",
211
+ name: "Investigation Update",
212
+ content: `## Current Investigation Status
213
+ [What we're looking at]
214
+
215
+ ## Findings So Far
216
+ - [Finding 1]
217
+ - [Finding 2]
218
+
219
+ ## Hypothesis
220
+ [Current theory about the root cause]
221
+
222
+ ## Next Steps
223
+ - [ ] [Action 1]
224
+ - [ ] [Action 2]`,
225
+ },
226
+ {
227
+ id: "internal-technical",
228
+ name: "Technical Analysis",
229
+ content: `## Technical Details
230
+ [Detailed technical observations]
231
+
232
+ ## Metrics/Logs
233
+ [Relevant metrics or log entries]
234
+
235
+ ## Impact Assessment
236
+ [Technical impact analysis]
237
+
238
+ ## Recommendations
239
+ [Technical recommendations for resolution]`,
240
+ },
241
+ {
242
+ id: "internal-handoff",
243
+ name: "Shift Handoff",
244
+ content: `## Current State
245
+ [Where things stand now]
246
+
247
+ ## Actions Taken
248
+ [What has been done so far]
249
+
250
+ ## Open Questions
251
+ [Things that still need investigation]
252
+
253
+ ## Immediate Priorities
254
+ - [ ] [Priority 1]
255
+ - [ ] [Priority 2]
256
+
257
+ ## Contacts
258
+ [Key people involved or to contact]`,
259
+ },
260
+ ];
261
+
262
+ // Function to get default templates based on note type
263
+ const getDefaultTemplates: (
264
+ noteType: NoteType,
265
+ ) => Array<{ id: string; name: string; content: string }> = (
266
+ noteType: NoteType,
267
+ ): Array<{ id: string; name: string; content: string }> => {
268
+ switch (noteType) {
269
+ case "postmortem":
270
+ return POSTMORTEM_TEMPLATES;
271
+ case "public-note":
272
+ return PUBLIC_NOTE_TEMPLATES;
273
+ case "internal-note":
274
+ return INTERNAL_NOTE_TEMPLATES;
275
+ default:
276
+ return POSTMORTEM_TEMPLATES;
277
+ }
278
+ };
279
+
280
+ const GenerateFromAIModal: FunctionComponent<GenerateFromAIModalProps> = (
281
+ props: GenerateFromAIModalProps,
282
+ ): ReactElement => {
283
+ // Get default templates based on note type
284
+ const defaultTemplates: Array<{ id: string; name: string; content: string }> =
285
+ getDefaultTemplates(props.noteType || "postmortem");
286
+
287
+ const [isGenerating, setIsGenerating] = useState<boolean>(false);
288
+ const [error, setError] = useState<string>("");
289
+ const [selectedTemplateId, setSelectedTemplateId] = useState<string>(
290
+ defaultTemplates[0]?.id || "",
291
+ );
292
+ const [templateContent, setTemplateContent] = useState<string>("");
293
+
294
+ // Combine default templates with custom templates
295
+ const allTemplates: Array<{ id: string; name: string; content?: string }> = [
296
+ ...defaultTemplates,
297
+ ...(props.templates || []),
298
+ ];
299
+
300
+ // Build dropdown options
301
+ const templateOptions: Array<DropdownOption> = allTemplates.map(
302
+ (template: { id: string; name: string; content?: string }) => {
303
+ return {
304
+ label: template.name,
305
+ value: template.id,
306
+ };
307
+ },
308
+ );
309
+
310
+ // Update template content when selection changes
311
+ useEffect(() => {
312
+ if (selectedTemplateId) {
313
+ const selectedTemplate:
314
+ | { id: string; name: string; content?: string }
315
+ | undefined = allTemplates.find(
316
+ (t: { id: string; name: string; content?: string }) => {
317
+ return t.id === selectedTemplateId;
318
+ },
319
+ );
320
+ setTemplateContent(selectedTemplate?.content || "");
321
+ } else {
322
+ setTemplateContent("");
323
+ }
324
+ }, [selectedTemplateId]);
325
+
326
+ const handleGenerate: () => Promise<void> = async (): Promise<void> => {
327
+ setIsGenerating(true);
328
+ setError("");
329
+
330
+ try {
331
+ const requestData: GenerateAIRequestData = {};
332
+
333
+ // Use the edited template content if a template was selected
334
+ if (selectedTemplateId && templateContent) {
335
+ requestData.template = templateContent;
336
+ requestData.templateId = selectedTemplateId;
337
+ }
338
+
339
+ const generatedContent: string = await props.onGenerate(requestData);
340
+ props.onSuccess(generatedContent);
341
+ } catch (err) {
342
+ if (err instanceof Error) {
343
+ setError(err.message);
344
+ } else {
345
+ setError("An error occurred while generating content.");
346
+ }
347
+ } finally {
348
+ setIsGenerating(false);
349
+ }
350
+ };
351
+
352
+ return (
353
+ <Modal
354
+ title={props.title}
355
+ description={
356
+ props.description ||
357
+ "Generate content using AI based on the available data."
358
+ }
359
+ onClose={() => {
360
+ if (!isGenerating) {
361
+ props.onClose();
362
+ }
363
+ }}
364
+ submitButtonText={isGenerating ? "Generating..." : "Generate with AI"}
365
+ submitButtonStyleType={ButtonStyleType.PRIMARY}
366
+ submitButtonType={ButtonType.Button}
367
+ isLoading={isGenerating}
368
+ disableSubmitButton={isGenerating}
369
+ onSubmit={handleGenerate}
370
+ modalWidth={ModalWidth.Large}
371
+ icon={IconProp.Bolt}
372
+ >
373
+ <>
374
+ {error && <ErrorMessage message={error} />}
375
+
376
+ {isGenerating && <AILoader />}
377
+
378
+ {!isGenerating && (
379
+ <div className="space-y-4">
380
+ {/* Template Selection */}
381
+ <div>
382
+ <label className="block text-sm font-medium text-gray-700 mb-1">
383
+ Select Template
384
+ </label>
385
+ <Dropdown
386
+ options={templateOptions}
387
+ value={templateOptions.find((opt: DropdownOption) => {
388
+ return opt.value === selectedTemplateId;
389
+ })}
390
+ onChange={(
391
+ value: DropdownValue | Array<DropdownValue> | null,
392
+ ) => {
393
+ setSelectedTemplateId((value as string) || "");
394
+ }}
395
+ placeholder="Select a template..."
396
+ />
397
+ <p className="mt-1 text-xs text-gray-500">
398
+ Choose a template to guide the AI generation. You can edit it
399
+ below before generating.
400
+ </p>
401
+ </div>
402
+
403
+ {/* Template Preview/Editor */}
404
+ {selectedTemplateId && (
405
+ <div>
406
+ <label className="block text-sm font-medium text-gray-700 mb-1">
407
+ Template Preview
408
+ </label>
409
+ <p className="text-xs text-gray-500 mb-2">
410
+ Edit the template below. AI will fill in the sections with
411
+ incident data.
412
+ </p>
413
+ <div className="">
414
+ <MarkdownEditor
415
+ key={selectedTemplateId}
416
+ initialValue={templateContent}
417
+ onChange={(value: string) => {
418
+ setTemplateContent(value);
419
+ }}
420
+ placeholder="Template content..."
421
+ />
422
+ </div>
423
+ </div>
424
+ )}
425
+ </div>
426
+ )}
427
+ </>
428
+ </Modal>
429
+ );
430
+ };
431
+
432
+ export default GenerateFromAIModal;
@@ -39,15 +39,20 @@ const Modal: FunctionComponent<ComponentProps> = (
39
39
  props: ComponentProps,
40
40
  ): ReactElement => {
41
41
  let iconBgColor: string = "bg-indigo-100";
42
+ let iconColor: string = "text-indigo-600";
42
43
 
43
44
  if (props.iconType === IconType.Info) {
44
45
  iconBgColor = "bg-indigo-100";
46
+ iconColor = "text-indigo-600";
45
47
  } else if (props.iconType === IconType.Warning) {
46
48
  iconBgColor = "bg-yellow-100";
49
+ iconColor = "text-yellow-600";
47
50
  } else if (props.iconType === IconType.Success) {
48
51
  iconBgColor = "bg-green-100";
52
+ iconColor = "text-green-600";
49
53
  } else if (props.iconType === IconType.Danger) {
50
54
  iconBgColor = "bg-red-100";
55
+ iconColor = "text-red-600";
51
56
  }
52
57
 
53
58
  return (
@@ -98,7 +103,7 @@ const Modal: FunctionComponent<ComponentProps> = (
98
103
  ? IconType.Info
99
104
  : props.iconType
100
105
  }
101
- className={"text-red-600 h-6 w-6 stroke-2"}
106
+ className={`${iconColor} h-6 w-6 stroke-2`}
102
107
  icon={props.icon}
103
108
  size={SizeProp.Large}
104
109
  />