@eventcatalog/core 2.35.1 → 2.35.3

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 (29) hide show
  1. package/dist/analytics/analytics.cjs +1 -1
  2. package/dist/analytics/analytics.js +2 -2
  3. package/dist/analytics/log-build.cjs +1 -1
  4. package/dist/analytics/log-build.js +3 -3
  5. package/dist/catalog-to-astro-content-directory.cjs +5 -0
  6. package/dist/catalog-to-astro-content-directory.js +2 -2
  7. package/dist/{chunk-7SI5EVOX.js → chunk-5ZG43YD2.js} +4 -1
  8. package/dist/{chunk-DGRAYXHN.js → chunk-66QXZSU5.js} +1 -1
  9. package/dist/{chunk-J4VCEL32.js → chunk-BQ5AYBCA.js} +1 -1
  10. package/dist/{chunk-UKJ7F5WR.js → chunk-DCLTVJDP.js} +1 -1
  11. package/dist/{chunk-LP6AXVOF.js → chunk-DGPXNBAU.js} +1 -1
  12. package/dist/{chunk-HAYFEAB4.js → chunk-EXAALOQA.js} +2 -0
  13. package/dist/constants.cjs +1 -1
  14. package/dist/constants.js +1 -1
  15. package/dist/eventcatalog.cjs +19 -1
  16. package/dist/eventcatalog.js +19 -6
  17. package/dist/map-catalog-to-astro.cjs +2 -0
  18. package/dist/map-catalog-to-astro.js +1 -1
  19. package/dist/watcher.cjs +2 -0
  20. package/dist/watcher.js +2 -2
  21. package/eventcatalog/src/enterprise/eventcatalog-chat/components/ChatMessage.tsx +25 -0
  22. package/eventcatalog/src/enterprise/eventcatalog-chat/components/InputModal.tsx +20 -9
  23. package/eventcatalog/src/enterprise/eventcatalog-chat/components/WelcomePromptArea.tsx +132 -44
  24. package/eventcatalog/src/enterprise/eventcatalog-chat/components/default-prompts.ts +93 -0
  25. package/eventcatalog/src/enterprise/eventcatalog-chat/components/hooks/ChatProvider.tsx +1 -0
  26. package/eventcatalog/src/enterprise/eventcatalog-chat/components/windows/ChatWindow.server.tsx +3 -4
  27. package/eventcatalog/src/enterprise/eventcatalog-chat/pages/chat/index.astro +0 -5
  28. package/eventcatalog/src/pages/chat/index.astro +5 -0
  29. package/package.json +2 -1
@@ -37,7 +37,7 @@ var import_axios = __toESM(require("axios"), 1);
37
37
  var import_os = __toESM(require("os"), 1);
38
38
 
39
39
  // package.json
40
- var version = "2.35.1";
40
+ var version = "2.35.3";
41
41
 
42
42
  // src/constants.ts
43
43
  var VERSION = version;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  raiseEvent
3
- } from "../chunk-DGRAYXHN.js";
4
- import "../chunk-J4VCEL32.js";
3
+ } from "../chunk-66QXZSU5.js";
4
+ import "../chunk-BQ5AYBCA.js";
5
5
  export {
6
6
  raiseEvent
7
7
  };
@@ -106,7 +106,7 @@ var import_axios = __toESM(require("axios"), 1);
106
106
  var import_os = __toESM(require("os"), 1);
107
107
 
108
108
  // package.json
109
- var version = "2.35.1";
109
+ var version = "2.35.3";
110
110
 
111
111
  // src/constants.ts
112
112
  var VERSION = version;
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  log_build_default
3
- } from "../chunk-LP6AXVOF.js";
4
- import "../chunk-DGRAYXHN.js";
5
- import "../chunk-J4VCEL32.js";
3
+ } from "../chunk-DGPXNBAU.js";
4
+ import "../chunk-66QXZSU5.js";
5
+ import "../chunk-BQ5AYBCA.js";
6
6
  import "../chunk-E7TXTI7G.js";
7
7
  export {
8
8
  log_build_default as default
@@ -155,6 +155,8 @@ function isCatalogRelated(filePath) {
155
155
  // custom components
156
156
  "public",
157
157
  // public assets
158
+ ".env",
159
+ // env file
158
160
  ...COLLECTION_KEYS
159
161
  ].includes(filePathArr[0])) {
160
162
  return true;
@@ -200,6 +202,9 @@ var copyFiles = async (source, target) => {
200
202
  windowsPathsNoEscape: import_node_os.default.platform() == "win32",
201
203
  ignore: ["node_modules/**", "**/dist/**", "**/teams", "**/users", "**/*.mdx", "**/*.md", "**/package.json", "**/Dockerfile"]
202
204
  });
205
+ if (import_fs.default.existsSync(path3.join(source, ".env"))) {
206
+ files.push(path3.join(source, ".env"));
207
+ }
203
208
  for (const file of files) {
204
209
  mapCatalogToAstro({
205
210
  filePath: file,
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  catalogToAstro,
3
3
  checkAndConvertMdToMdx
4
- } from "./chunk-7SI5EVOX.js";
4
+ } from "./chunk-5ZG43YD2.js";
5
5
  import "./chunk-E7TXTI7G.js";
6
- import "./chunk-HAYFEAB4.js";
6
+ import "./chunk-EXAALOQA.js";
7
7
  export {
8
8
  catalogToAstro,
9
9
  checkAndConvertMdToMdx
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-E7TXTI7G.js";
4
4
  import {
5
5
  mapCatalogToAstro
6
- } from "./chunk-HAYFEAB4.js";
6
+ } from "./chunk-EXAALOQA.js";
7
7
 
8
8
  // src/catalog-to-astro-content-directory.js
9
9
  import { glob } from "glob";
@@ -19,6 +19,9 @@ var copyFiles = async (source, target) => {
19
19
  windowsPathsNoEscape: os.platform() == "win32",
20
20
  ignore: ["node_modules/**", "**/dist/**", "**/teams", "**/users", "**/*.mdx", "**/*.md", "**/package.json", "**/Dockerfile"]
21
21
  });
22
+ if (fs.existsSync(path.join(source, ".env"))) {
23
+ files.push(path.join(source, ".env"));
24
+ }
22
25
  for (const file of files) {
23
26
  mapCatalogToAstro({
24
27
  filePath: file,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-J4VCEL32.js";
3
+ } from "./chunk-BQ5AYBCA.js";
4
4
 
5
5
  // src/analytics/analytics.js
6
6
  import axios from "axios";
@@ -1,5 +1,5 @@
1
1
  // package.json
2
- var version = "2.35.1";
2
+ var version = "2.35.3";
3
3
 
4
4
  // src/constants.ts
5
5
  var VERSION = version;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  mapCatalogToAstro
3
- } from "./chunk-HAYFEAB4.js";
3
+ } from "./chunk-EXAALOQA.js";
4
4
 
5
5
  // src/watcher.js
6
6
  import watcher from "@parcel/watcher";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  raiseEvent
3
- } from "./chunk-DGRAYXHN.js";
3
+ } from "./chunk-66QXZSU5.js";
4
4
  import {
5
5
  getEventCatalogConfigFile,
6
6
  verifyRequiredFieldsAreInCatalogConfigFile
@@ -40,6 +40,8 @@ function isCatalogRelated(filePath) {
40
40
  // custom components
41
41
  "public",
42
42
  // public assets
43
+ ".env",
44
+ // env file
43
45
  ...COLLECTION_KEYS
44
46
  ].includes(filePathArr[0])) {
45
47
  return true;
@@ -25,7 +25,7 @@ __export(constants_exports, {
25
25
  module.exports = __toCommonJS(constants_exports);
26
26
 
27
27
  // package.json
28
- var version = "2.35.1";
28
+ var version = "2.35.3";
29
29
 
30
30
  // src/constants.ts
31
31
  var VERSION = version;
package/dist/constants.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-J4VCEL32.js";
3
+ } from "./chunk-BQ5AYBCA.js";
4
4
  export {
5
5
  VERSION
6
6
  };
@@ -157,7 +157,7 @@ var import_axios = __toESM(require("axios"), 1);
157
157
  var import_os = __toESM(require("os"), 1);
158
158
 
159
159
  // package.json
160
- var version = "2.35.1";
160
+ var version = "2.35.3";
161
161
 
162
162
  // src/constants.ts
163
163
  var VERSION = version;
@@ -261,6 +261,8 @@ function isCatalogRelated(filePath) {
261
261
  // custom components
262
262
  "public",
263
263
  // public assets
264
+ ".env",
265
+ // env file
264
266
  ...COLLECTION_KEYS
265
267
  ].includes(filePathArr[0])) {
266
268
  return true;
@@ -392,6 +394,9 @@ var copyFiles = async (source, target) => {
392
394
  windowsPathsNoEscape: import_node_os.default.platform() == "win32",
393
395
  ignore: ["node_modules/**", "**/dist/**", "**/teams", "**/users", "**/*.mdx", "**/*.md", "**/package.json", "**/Dockerfile"]
394
396
  });
397
+ if (import_fs.default.existsSync(path5.join(source, ".env"))) {
398
+ files.push(path5.join(source, ".env"));
399
+ }
395
400
  for (const file of files) {
396
401
  mapCatalogToAstro({
397
402
  filePath: file,
@@ -608,6 +613,7 @@ var isEventCatalogStarterEnabled = async (licenseKey) => {
608
613
  // src/eventcatalog.ts
609
614
  var import_update_notifier = __toESM(require("update-notifier"), 1);
610
615
  var import_stream = __toESM(require("stream"), 1);
616
+ var import_dotenv = __toESM(require("dotenv"), 1);
611
617
  var currentDir = import_node_path7.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
612
618
  var program = new import_commander.Command().version(VERSION);
613
619
  var dir = import_node_path7.default.resolve(process.env.PROJECT_DIR || process.cwd());
@@ -685,6 +691,9 @@ Run npm i @eventcatalog/core to update`;
685
691
  };
686
692
  program.command("dev").description("Run development server of EventCatalog").option("-d, --debug", "Output EventCatalog application information into your terminal").option("--force-recreate", "Recreate the eventcatalog-core directory", false).action(async (options, command) => {
687
693
  console.log("Setting up EventCatalog....");
694
+ if (import_fs2.default.existsSync(import_node_path7.default.join(dir, ".env"))) {
695
+ import_dotenv.default.config({ path: import_node_path7.default.join(dir, ".env") });
696
+ }
688
697
  if (options.debug) {
689
698
  console.log("Debug mode enabled");
690
699
  console.log("PROJECT_DIR", dir);
@@ -741,6 +750,9 @@ program.command("dev").description("Run development server of EventCatalog").opt
741
750
  });
742
751
  program.command("build").description("Run build of EventCatalog").action(async (options, command) => {
743
752
  console.log("Building EventCatalog...");
753
+ if (import_fs2.default.existsSync(import_node_path7.default.join(dir, ".env"))) {
754
+ import_dotenv.default.config({ path: import_node_path7.default.join(dir, ".env") });
755
+ }
744
756
  copyCore();
745
757
  await copyServerFiles();
746
758
  const canEmbedPages = await isBackstagePluginEnabled();
@@ -782,6 +794,9 @@ var previewCatalog = ({
782
794
  };
783
795
  program.command("preview").description("Serves the contents of your eventcatalog build directory").action(async (options, command) => {
784
796
  console.log("Starting preview of your build...");
797
+ if (import_fs2.default.existsSync(import_node_path7.default.join(dir, ".env"))) {
798
+ import_dotenv.default.config({ path: import_node_path7.default.join(dir, ".env") });
799
+ }
785
800
  const canEmbedPages = await isBackstagePluginEnabled();
786
801
  const isEventCatalogStarter = await isEventCatalogStarterEnabled();
787
802
  const isEventCatalogScale = await isEventCatalogScaleEnabled();
@@ -790,6 +805,9 @@ program.command("preview").description("Serves the contents of your eventcatalog
790
805
  });
791
806
  program.command("start").description("Serves the contents of your eventcatalog build directory").action(async (options, command) => {
792
807
  console.log("Starting preview of your build...");
808
+ if (import_fs2.default.existsSync(import_node_path7.default.join(dir, ".env"))) {
809
+ import_dotenv.default.config({ path: import_node_path7.default.join(dir, ".env") });
810
+ }
793
811
  const canEmbedPages = await isBackstagePluginEnabled();
794
812
  const isEventCatalogStarter = await isEventCatalogStarterEnabled();
795
813
  const isEventCatalogScale = await isEventCatalogScaleEnabled();
@@ -3,18 +3,18 @@ import {
3
3
  } from "./chunk-BLDONK5J.js";
4
4
  import {
5
5
  watch
6
- } from "./chunk-UKJ7F5WR.js";
6
+ } from "./chunk-DCLTVJDP.js";
7
7
  import {
8
8
  log_build_default
9
- } from "./chunk-LP6AXVOF.js";
10
- import "./chunk-DGRAYXHN.js";
9
+ } from "./chunk-DGPXNBAU.js";
10
+ import "./chunk-66QXZSU5.js";
11
11
  import {
12
12
  catalogToAstro,
13
13
  checkAndConvertMdToMdx
14
- } from "./chunk-7SI5EVOX.js";
14
+ } from "./chunk-5ZG43YD2.js";
15
15
  import {
16
16
  VERSION
17
- } from "./chunk-J4VCEL32.js";
17
+ } from "./chunk-BQ5AYBCA.js";
18
18
  import {
19
19
  isBackstagePluginEnabled,
20
20
  isEventCatalogScaleEnabled,
@@ -25,7 +25,7 @@ import {
25
25
  generate
26
26
  } from "./chunk-YEQVKHST.js";
27
27
  import "./chunk-E7TXTI7G.js";
28
- import "./chunk-HAYFEAB4.js";
28
+ import "./chunk-EXAALOQA.js";
29
29
 
30
30
  // src/eventcatalog.ts
31
31
  import { Command } from "commander";
@@ -38,6 +38,7 @@ import concurrently from "concurrently";
38
38
  import boxen from "boxen";
39
39
  import updateNotifier from "update-notifier";
40
40
  import stream from "stream";
41
+ import dotenv from "dotenv";
41
42
  var currentDir = path.dirname(fileURLToPath(import.meta.url));
42
43
  var program = new Command().version(VERSION);
43
44
  var dir = path.resolve(process.env.PROJECT_DIR || process.cwd());
@@ -115,6 +116,9 @@ Run npm i @eventcatalog/core to update`;
115
116
  };
116
117
  program.command("dev").description("Run development server of EventCatalog").option("-d, --debug", "Output EventCatalog application information into your terminal").option("--force-recreate", "Recreate the eventcatalog-core directory", false).action(async (options, command) => {
117
118
  console.log("Setting up EventCatalog....");
119
+ if (fs.existsSync(path.join(dir, ".env"))) {
120
+ dotenv.config({ path: path.join(dir, ".env") });
121
+ }
118
122
  if (options.debug) {
119
123
  console.log("Debug mode enabled");
120
124
  console.log("PROJECT_DIR", dir);
@@ -171,6 +175,9 @@ program.command("dev").description("Run development server of EventCatalog").opt
171
175
  });
172
176
  program.command("build").description("Run build of EventCatalog").action(async (options, command) => {
173
177
  console.log("Building EventCatalog...");
178
+ if (fs.existsSync(path.join(dir, ".env"))) {
179
+ dotenv.config({ path: path.join(dir, ".env") });
180
+ }
174
181
  copyCore();
175
182
  await copyServerFiles();
176
183
  const canEmbedPages = await isBackstagePluginEnabled();
@@ -212,6 +219,9 @@ var previewCatalog = ({
212
219
  };
213
220
  program.command("preview").description("Serves the contents of your eventcatalog build directory").action(async (options, command) => {
214
221
  console.log("Starting preview of your build...");
222
+ if (fs.existsSync(path.join(dir, ".env"))) {
223
+ dotenv.config({ path: path.join(dir, ".env") });
224
+ }
215
225
  const canEmbedPages = await isBackstagePluginEnabled();
216
226
  const isEventCatalogStarter = await isEventCatalogStarterEnabled();
217
227
  const isEventCatalogScale = await isEventCatalogScaleEnabled();
@@ -220,6 +230,9 @@ program.command("preview").description("Serves the contents of your eventcatalog
220
230
  });
221
231
  program.command("start").description("Serves the contents of your eventcatalog build directory").action(async (options, command) => {
222
232
  console.log("Starting preview of your build...");
233
+ if (fs.existsSync(path.join(dir, ".env"))) {
234
+ dotenv.config({ path: path.join(dir, ".env") });
235
+ }
223
236
  const canEmbedPages = await isBackstagePluginEnabled();
224
237
  const isEventCatalogStarter = await isEventCatalogStarterEnabled();
225
238
  const isEventCatalogScale = await isEventCatalogScaleEnabled();
@@ -74,6 +74,8 @@ function isCatalogRelated(filePath) {
74
74
  // custom components
75
75
  "public",
76
76
  // public assets
77
+ ".env",
78
+ // env file
77
79
  ...COLLECTION_KEYS
78
80
  ].includes(filePathArr[0])) {
79
81
  return true;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  mapCatalogToAstro
3
- } from "./chunk-HAYFEAB4.js";
3
+ } from "./chunk-EXAALOQA.js";
4
4
  export {
5
5
  mapCatalogToAstro
6
6
  };
package/dist/watcher.cjs CHANGED
@@ -78,6 +78,8 @@ function isCatalogRelated(filePath) {
78
78
  // custom components
79
79
  "public",
80
80
  // public assets
81
+ ".env",
82
+ // env file
81
83
  ...COLLECTION_KEYS
82
84
  ].includes(filePathArr[0])) {
83
85
  return true;
package/dist/watcher.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  watch
3
- } from "./chunk-UKJ7F5WR.js";
3
+ } from "./chunk-DCLTVJDP.js";
4
4
  import "./chunk-E7TXTI7G.js";
5
- import "./chunk-HAYFEAB4.js";
5
+ import "./chunk-EXAALOQA.js";
6
6
  export {
7
7
  watch
8
8
  };
@@ -34,6 +34,7 @@ const ChatMessage = React.memo(({ message }: ChatMessageProps) => {
34
34
  const [modalContent, setModalContent] = useState<{ language: string; code: string } | null>(null);
35
35
  const [copiedStates, setCopiedStates] = useState<Record<string, boolean>>({}); // State for copy feedback
36
36
  const [isResourcesCollapsed, setIsResourcesCollapsed] = useState(true); // State for resource section collapse
37
+ const [isContextCollapsed, setIsContextCollapsed] = useState(true); // State for additional context collapse
37
38
 
38
39
  // Helper to get display name for resource, ensuring a fallback
39
40
  const getResourceDisplayName = (resource: Resource): string => {
@@ -137,6 +138,30 @@ const ChatMessage = React.memo(({ message }: ChatMessageProps) => {
137
138
  </ReactMarkdown>
138
139
  </div>
139
140
 
141
+ {/* Additional Context section (for user messages) */}
142
+ {message.isUser && message.additionalContext && (
143
+ <div className="mt-3 pt-3 border-t border-purple-700/50">
144
+ {' '}
145
+ {/* Adjusted border color for subtlety */}
146
+ <button
147
+ className="flex items-center text-xs text-purple-300 mb-1 w-full text-left focus:outline-none" // Adjusted text color for subtlety
148
+ onClick={() => setIsContextCollapsed(!isContextCollapsed)}
149
+ aria-expanded={!isContextCollapsed}
150
+ aria-controls="additional-context-content"
151
+ >
152
+ {isContextCollapsed ? <ChevronRight size={14} className="mr-1" /> : <ChevronDown size={14} className="mr-1" />}
153
+ Prompt used:
154
+ </button>
155
+ {!isContextCollapsed && (
156
+ <div className="text-[10px] mt-1 pl-5 prose prose-sm prose-invert" id="additional-context-content">
157
+ {' '}
158
+ {/* Removed max-w-none */}
159
+ <pre className="whitespace-pre-wrap break-words">{message.additionalContext}</pre> {/* Use pre for formatting */}
160
+ </div>
161
+ )}
162
+ </div>
163
+ )}
164
+
140
165
  {/* Resource section */}
141
166
  {!message.isUser && message.resources && message.resources.length > 0 && (
142
167
  <div className="mt-3 pt-3 border-t border-gray-200">
@@ -1,5 +1,6 @@
1
1
  import React, { useEffect, useState, useMemo } from 'react';
2
2
  import * as Dialog from '@radix-ui/react-dialog';
3
+ import { Wand2 } from 'lucide-react';
3
4
  // TODO: Import ChatPrompt and ChatPromptInput from a central types location
4
5
  import type { ChatPrompt } from '@enterprise/eventcatalog-chat/utils/chat-prompts';
5
6
 
@@ -111,9 +112,9 @@ const InputModal: React.FC<InputModalProps> = ({ isOpen, onClose, prompt, onSubm
111
112
  <Dialog.Root open={isOpen} onOpenChange={onClose}>
112
113
  <Dialog.Portal>
113
114
  <Dialog.Overlay className="fixed inset-0 bg-black/50 data-[state=open]:animate-overlayShow z-50" />
114
- <Dialog.Content className="fixed top-1/2 left-1/2 w-[90vw] max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg bg-white p-6 shadow-lg focus:outline-none data-[state=open]:animate-contentShow z-[100]">
115
- <Dialog.Title className="text-lg font-semibold text-gray-900">{prompt.data.title}</Dialog.Title>
116
- <Dialog.Description className="mt-1 mb-5 text-sm text-gray-500">
115
+ <Dialog.Content className="fixed top-1/2 left-1/2 w-[90vw] max-w-lg -translate-x-1/2 -translate-y-1/2 rounded-lg bg-gray-50 p-8 shadow-xl focus:outline-none data-[state=open]:animate-contentShow z-[100]">
116
+ <Dialog.Title className="text-lg font-semibold text-gray-800 mb-3">{prompt.data.title}</Dialog.Title>
117
+ <Dialog.Description className="mt-1 mb-6 text-sm text-gray-600">
117
118
  Please provide the following details:
118
119
  </Dialog.Description>
119
120
  <form onSubmit={handleSubmit} className="space-y-4">
@@ -127,7 +128,7 @@ const InputModal: React.FC<InputModalProps> = ({ isOpen, onClose, prompt, onSubm
127
128
 
128
129
  return (
129
130
  <div key={input.id}>
130
- <label htmlFor={input.id} className="block text-sm font-medium text-gray-700 mb-1">
131
+ <label htmlFor={input.id} className="block text-sm font-medium text-gray-700 mb-1.5">
131
132
  {input.label}
132
133
  </label>
133
134
  {isResourceList ? (
@@ -137,7 +138,7 @@ const InputModal: React.FC<InputModalProps> = ({ isOpen, onClose, prompt, onSubm
137
138
  value={inputValues[input.id] || ''}
138
139
  onChange={(e) => handleInputChange(input.id, e.target.value)}
139
140
  required
140
- className="w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-purple-500 focus:outline-none focus:ring-1 focus:ring-purple-500 sm:text-sm"
141
+ className="w-full rounded-md border border-gray-300 bg-white px-3 py-2 shadow-sm focus:border-purple-500 focus:outline-none focus:ring-2 focus:ring-purple-300 focus:ring-offset-1 sm:text-sm transition duration-150 ease-in-out"
141
142
  >
142
143
  <option value="" disabled>
143
144
  Select a {resourceType}...
@@ -160,7 +161,7 @@ const InputModal: React.FC<InputModalProps> = ({ isOpen, onClose, prompt, onSubm
160
161
  value={inputValues[input.id] || ''}
161
162
  onChange={(e) => handleInputChange(input.id, e.target.value)}
162
163
  required
163
- className="w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-purple-500 focus:outline-none focus:ring-1 focus:ring-purple-500 sm:text-sm"
164
+ className="w-full rounded-md border border-gray-300 bg-white px-3 py-2 shadow-sm focus:border-purple-500 focus:outline-none focus:ring-2 focus:ring-purple-300 focus:ring-offset-1 sm:text-sm transition duration-150 ease-in-out"
164
165
  >
165
166
  <option value="" disabled>
166
167
  Select an option...
@@ -184,9 +185,18 @@ const InputModal: React.FC<InputModalProps> = ({ isOpen, onClose, prompt, onSubm
184
185
  name={input.id}
185
186
  value={inputValues[input.id] || ''}
186
187
  onChange={(e) => handleInputChange(input.id, e.target.value)}
188
+ onKeyDown={(e) => {
189
+ // Prevent form submission on Enter key press unless Shift is held
190
+ if (e.key === 'Enter' && !e.shiftKey) {
191
+ e.preventDefault();
192
+ // Optionally, you could trigger submission here if needed,
193
+ // but the default behavior is just to prevent it.
194
+ handleSubmit(e); // Example: trigger submit manually
195
+ }
196
+ }}
187
197
  required
188
198
  rows={isCode ? 6 : 3} // More rows for code input
189
- className={`w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-purple-500 focus:outline-none focus:ring-1 focus:ring-purple-500 sm:text-sm ${isCode ? 'font-mono text-sm' : ''}`} // Basic monospaced font for code
199
+ className={`w-full rounded-md border border-gray-300 bg-white px-3 py-2 shadow-sm focus:border-purple-500 focus:outline-none focus:ring-2 focus:ring-purple-300 focus:ring-offset-1 sm:text-sm transition duration-150 ease-in-out ${isCode ? 'font-mono text-sm' : ''}`}
190
200
  placeholder={isCode ? 'Paste your code here...' : ''}
191
201
  />
192
202
  ) : (
@@ -197,7 +207,7 @@ const InputModal: React.FC<InputModalProps> = ({ isOpen, onClose, prompt, onSubm
197
207
  value={inputValues[input.id] || ''}
198
208
  onChange={(e) => handleInputChange(input.id, e.target.value)}
199
209
  required
200
- className="w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-purple-500 focus:outline-none focus:ring-1 focus:ring-purple-500 sm:text-sm"
210
+ className="w-full rounded-md border border-gray-300 bg-white px-3 py-2 shadow-sm focus:border-purple-500 focus:outline-none focus:ring-2 focus:ring-purple-300 focus:ring-offset-1 sm:text-sm transition duration-150 ease-in-out"
201
211
  />
202
212
  )}
203
213
  </>
@@ -217,8 +227,9 @@ const InputModal: React.FC<InputModalProps> = ({ isOpen, onClose, prompt, onSubm
217
227
  </Dialog.Close>
218
228
  <button
219
229
  type="submit"
220
- className="inline-flex justify-center rounded-md border border-transparent bg-purple-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-purple-700 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:ring-offset-2"
230
+ className="inline-flex items-center justify-center gap-1.5 rounded-md border border-transparent bg-purple-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-purple-700 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:ring-offset-2"
221
231
  >
232
+ <Wand2 size={16} />
222
233
  Submit
223
234
  </button>
224
235
  </div>
@@ -1,7 +1,7 @@
1
- import React, { useMemo } from 'react';
2
- import { HelpCircle } from 'lucide-react';
1
+ import React, { useState, useMemo } from 'react';
3
2
  import * as icons from 'lucide-react'; // Import all icons
4
3
  import type { ChatPromptCategoryGroup, ChatPrompt } from '@enterprise/eventcatalog-chat/utils/chat-prompts';
4
+ import { defaultPrompts } from './default-prompts';
5
5
 
6
6
  // Removed the static iconMap
7
7
 
@@ -26,60 +26,148 @@ interface WelcomePromptAreaProps {
26
26
  isProcessing: boolean; // Combined thinking/streaming state
27
27
  }
28
28
 
29
+ // Helper function to group default prompts by category label
30
+ const groupDefaultPrompts = (prompts: ChatPrompt[]): ChatPromptCategoryGroup[] => {
31
+ const groups: { [key: string]: { label: string; icon?: string; items: ChatPrompt[] } } = {};
32
+
33
+ prompts.forEach((prompt) => {
34
+ const categoryLabel = prompt.data.category.label;
35
+ const categoryIcon = prompt.data.category.icon; // Get icon from prompt data
36
+
37
+ if (!groups[categoryLabel]) {
38
+ groups[categoryLabel] = { label: categoryLabel, icon: categoryIcon, items: [] };
39
+ }
40
+ groups[categoryLabel].items.push(prompt);
41
+ });
42
+
43
+ // Convert the groups object into an array matching ChatPromptCategoryGroup structure
44
+ return Object.values(groups);
45
+ };
46
+
29
47
  const WelcomePromptArea: React.FC<WelcomePromptAreaProps> = ({
30
48
  chatPrompts,
31
- activeCategory,
32
- setActiveCategory,
49
+ activeCategory: activeCustomCategory, // Rename to avoid conflict
50
+ setActiveCategory: setActiveCustomCategory, // Rename to avoid conflict
33
51
  onPromptClick,
34
52
  isProcessing,
35
53
  }) => {
54
+ // Group default prompts and derive initial state only once
55
+ const defaultPromptGroups = useMemo(() => groupDefaultPrompts(defaultPrompts), []);
56
+ const [activeDefaultCategory, setActiveDefaultCategory] = useState<string>(() => defaultPromptGroups[0]?.label || '');
57
+
36
58
  // Find the currently active category's questions from chatPrompts
37
- const activeQuestions: ChatPrompt[] = useMemo(() => {
38
- // Find the category group by label
39
- const activeGroup = chatPrompts.find((group) => group.label === activeCategory);
40
- // Return the items (questions) from that group, or an empty array if not found
59
+ const activeCustomQuestions: ChatPrompt[] = useMemo(() => {
60
+ if (!chatPrompts || chatPrompts.length === 0) return [];
61
+ const activeGroup = chatPrompts.find((group) => group.label === activeCustomCategory);
62
+ return activeGroup?.items || (chatPrompts[0]?.items ?? []);
63
+ }, [activeCustomCategory, chatPrompts]);
64
+
65
+ // Find the currently active category's default questions
66
+ const activeDefaultQuestions: ChatPrompt[] = useMemo(() => {
67
+ if (!defaultPromptGroups || defaultPromptGroups.length === 0) return [];
68
+ const activeGroup = defaultPromptGroups.find((group) => group.label === activeDefaultCategory);
41
69
  return activeGroup?.items || [];
42
- }, [activeCategory, chatPrompts]);
70
+ }, [activeDefaultCategory, defaultPromptGroups]);
43
71
 
44
72
  return (
45
73
  <div className="h-full flex flex-col justify-center items-center px-4 pb-4 pt-0">
46
- {' '}
47
- {/* Use h-full and flex centering */}
48
74
  <div className="max-w-2xl w-full text-left">
49
75
  <h2 className="text-2xl font-semibold mb-6 text-gray-800">How can I help you?</h2>
50
- {/* Category Tabs - Use chatPrompts */}
51
- <div className="flex flex-wrap justify-left gap-2 mb-6 border-b border-gray-200 pb-4">
52
- {chatPrompts.map((categoryGroup) => (
53
- <button
54
- key={categoryGroup.label} // Use label as key, assuming it's unique
55
- onClick={() => setActiveCategory(categoryGroup.label)}
56
- disabled={isProcessing}
57
- className={`flex items-center px-3 py-2 rounded-md text-sm font-medium transition-colors duration-150 focus:outline-none focus:ring-2 focus:ring-purple-400 focus:ring-offset-2 focus:ring-offset-white disabled:opacity-50 ${
58
- activeCategory === categoryGroup.label
59
- ? 'bg-purple-600 text-white'
60
- : 'bg-gray-100 text-gray-700 hover:bg-gray-200'
61
- }`}
62
- >
63
- {/* Use the icon mapping function */}
64
- {getCategoryIcon(categoryGroup.icon)}
65
- {categoryGroup.label}
66
- </button>
67
- ))}
68
- </div>
69
- {/* Questions List - Use activeQuestions derived from chatPrompts */}
70
- <div className="space-y-2 text-left">
71
- {activeQuestions.map((item, index) => (
72
- <button
73
- key={item.id || index} // Use item.id if available, otherwise index
74
- onClick={() => onPromptClick(item)} // Use the passed handler
75
- className="block w-full text-left px-3 py-2 text-gray-700 hover:bg-gray-100 rounded-md text-sm transition-colors duration-150 focus:outline-none focus:ring-1 focus:ring-purple-400 disabled:opacity-50"
76
- disabled={isProcessing} // Disable while processing
77
- >
78
- {/* Display the question title */}
79
- {item.data.title}
80
- </button>
81
- ))}
82
- </div>
76
+
77
+ {/* Conditional Rendering: Custom Prompts OR Default Prompts */}
78
+ {chatPrompts && chatPrompts.length > 0 ? (
79
+ /* --- CUSTOM PROMPTS UI --- */
80
+ <>
81
+ {/* Category Tabs - Use chatPrompts */}
82
+ <div className="flex flex-wrap justify-left gap-2 mb-6 border-b border-gray-200 pb-4">
83
+ {chatPrompts.map((categoryGroup) => (
84
+ <button
85
+ key={categoryGroup.label}
86
+ onClick={() => setActiveCustomCategory(categoryGroup.label)}
87
+ disabled={isProcessing}
88
+ className={`flex items-center px-3 py-2 rounded-md text-sm font-medium transition-colors duration-150 focus:outline-none focus:ring-2 focus:ring-purple-400 focus:ring-offset-2 focus:ring-offset-white disabled:opacity-50 ${
89
+ activeCustomCategory === categoryGroup.label
90
+ ? 'bg-purple-600 text-white'
91
+ : 'bg-gray-100 text-gray-700 hover:bg-gray-200'
92
+ }`}
93
+ >
94
+ {getCategoryIcon(categoryGroup.icon)}
95
+ {categoryGroup.label}
96
+ </button>
97
+ ))}
98
+ </div>
99
+ {/* Questions List - Use activeCustomQuestions */}
100
+ <div className="space-y-2 text-left">
101
+ {activeCustomQuestions.map((item) => (
102
+ <button
103
+ key={item.id}
104
+ onClick={() => onPromptClick(item)}
105
+ className="block w-full text-left px-3 py-2 text-gray-700 hover:bg-gray-100 rounded-md text-sm transition-colors duration-150 focus:outline-none focus:ring-1 focus:ring-purple-400 disabled:opacity-50"
106
+ disabled={isProcessing}
107
+ >
108
+ {item.data.title}
109
+ </button>
110
+ ))}
111
+ </div>
112
+ </>
113
+ ) : (
114
+ /* --- DEFAULT PROMPTS UI (Grouped) --- */
115
+ <>
116
+ {/* Default Category Tabs - Use defaultPromptGroups */}
117
+ <div className="flex flex-wrap justify-left gap-2 mb-6 border-b border-gray-200 pb-4">
118
+ {defaultPromptGroups.map((categoryGroup) => (
119
+ <button
120
+ key={categoryGroup.label} // Use label as key
121
+ onClick={() => setActiveDefaultCategory(categoryGroup.label)}
122
+ disabled={isProcessing}
123
+ className={`flex items-center px-3 py-2 rounded-md text-sm font-medium transition-colors duration-150 focus:outline-none focus:ring-2 focus:ring-purple-400 focus:ring-offset-2 focus:ring-offset-white disabled:opacity-50 ${
124
+ activeDefaultCategory === categoryGroup.label
125
+ ? 'bg-purple-600 text-white'
126
+ : 'bg-gray-100 text-gray-700 hover:bg-gray-200'
127
+ }`}
128
+ >
129
+ {/* Use the icon mapping function */}
130
+ {getCategoryIcon(categoryGroup.icon)}
131
+ {categoryGroup.label}
132
+ </button>
133
+ ))}
134
+ </div>
135
+ {/* Default Questions List - Use activeDefaultQuestions */}
136
+ <div className="space-y-2 text-left">
137
+ {activeDefaultQuestions.map((item) => (
138
+ <button
139
+ key={item.id}
140
+ onClick={() => onPromptClick(item)}
141
+ className="block w-full text-left px-3 py-2 text-gray-700 hover:bg-gray-100 rounded-md text-sm transition-colors duration-150 focus:outline-none focus:ring-1 focus:ring-purple-400 disabled:opacity-50"
142
+ disabled={isProcessing}
143
+ >
144
+ {item.data.title}
145
+ </button>
146
+ ))}
147
+ </div>
148
+
149
+ {/* Enhanced Bring Your Own Prompts section */}
150
+ <div className="bg-purple-50 border border-purple-200 rounded-lg p-4 mt-6 text-gray-700 text-sm">
151
+ <p className="flex items-center">
152
+ <icons.Wand2 size={18} className="text-purple-600 mr-2 flex-shrink-0" /> {/* Added Icon */}
153
+ <span>
154
+ Want to tailor these suggestions?{' '}
155
+ <a
156
+ href="https://www.eventcatalog.dev/docs/development/guides/eventcatlaog-chat/what-is-eventcatalog-chat"
157
+ target="_blank"
158
+ rel="noopener noreferrer"
159
+ className="text-purple-700 hover:underline font-semibold"
160
+ >
161
+ {' '}
162
+ {/* Added target and rel */}
163
+ Bring your own prompts!
164
+ </a>{' '}
165
+ Easily configure this list with relevant questions for your teams and organization.
166
+ </span>
167
+ </p>
168
+ </div>
169
+ </>
170
+ )}
83
171
  </div>
84
172
  </div>
85
173
  );
@@ -0,0 +1,93 @@
1
+ import type { ChatPrompt } from '@enterprise/eventcatalog-chat/utils/chat-prompts';
2
+
3
+ export const defaultPrompts: ChatPrompt[] = [
4
+ {
5
+ id: 'default-events',
6
+ collection: 'chatPrompts', // Required field
7
+ body: 'List all events.', // The actual prompt text
8
+ data: {
9
+ title: 'What events do we have in our architecture?', // Text displayed on the button
10
+ type: 'text', // Default type
11
+ category: { id: 'general', label: 'General', icon: 'HelpCircle' },
12
+ },
13
+ },
14
+ {
15
+ id: 'default-events-by-domain-feature',
16
+ collection: 'chatPrompts',
17
+ body: 'What events are relevant to this feature {{feature-description}}?',
18
+ data: {
19
+ title: 'Im building a new feature, what events are relevant to this feature?',
20
+ type: 'text',
21
+ inputs: [
22
+ {
23
+ id: 'feature-description',
24
+ label: 'Feature Description',
25
+ type: 'text-area',
26
+ },
27
+ ],
28
+ category: { id: 'general', label: 'General', icon: 'HelpCircle' },
29
+ },
30
+ },
31
+ {
32
+ id: 'default-events-by-domain-service',
33
+ collection: 'chatPrompts',
34
+ body: 'Review the given service {{service-name}}, and let me know how it works? You are an expert in the domain and architecture of the service.',
35
+ data: {
36
+ title: 'Review the given service, and let me know how it works?',
37
+ type: 'text',
38
+ inputs: [
39
+ {
40
+ id: 'service-name',
41
+ label: 'Service Name',
42
+ type: 'resource-list-services',
43
+ },
44
+ ],
45
+ category: { id: 'general', label: 'General', icon: 'HelpCircle' },
46
+ },
47
+ },
48
+ {
49
+ id: 'default-services',
50
+ collection: 'chatPrompts',
51
+ body: 'List all services.',
52
+ data: {
53
+ title: 'What services do we have in our architecture?',
54
+ type: 'text',
55
+ category: { id: 'general', label: 'General', icon: 'HelpCircle' },
56
+ },
57
+ },
58
+ // Example of another category
59
+ {
60
+ id: 'default-schema-json',
61
+ collection: 'chatPrompts',
62
+ body: 'Generate a JSON schema for {{event-name}}.',
63
+ data: {
64
+ title: 'Generate a JSON schema for the given event',
65
+ type: 'text',
66
+ inputs: [
67
+ {
68
+ id: 'event-name',
69
+ label: 'Event Name',
70
+ type: 'resource-list-events',
71
+ },
72
+ ],
73
+ category: { id: 'code', label: 'Code Generation', icon: 'Code' },
74
+ },
75
+ },
76
+ {
77
+ id: 'default-schema-avro',
78
+ collection: 'chatPrompts',
79
+ body: 'Generate a Avro schema for {{event-name}}.',
80
+ data: {
81
+ title: 'Generate a Avro schema for the given event',
82
+ type: 'text',
83
+ inputs: [
84
+ {
85
+ id: 'event-name',
86
+ label: 'Event Name',
87
+ type: 'resource-list-events',
88
+ },
89
+ ],
90
+ category: { id: 'code', label: 'Code Generation', icon: 'Code' },
91
+ },
92
+ },
93
+ ];
@@ -3,6 +3,7 @@ import type { ReactNode } from 'react';
3
3
 
4
4
  export interface Message {
5
5
  content: string;
6
+ additionalContext?: string;
6
7
  isUser: boolean;
7
8
  timestamp: number;
8
9
  resources?: Array<{
@@ -211,7 +211,7 @@ const ChatWindow = ({
211
211
  async (question: string, additionalContext?: string) => {
212
212
  if (!question.trim() || isStreaming || isThinking) return;
213
213
 
214
- const userMessage: Message = { content: question, isUser: true, timestamp: Date.now() };
214
+ const userMessage: Message = { content: question, isUser: true, timestamp: Date.now(), additionalContext };
215
215
  const isFirstMessage = messages.length === 0;
216
216
 
217
217
  setMessages((prev) => [...prev, userMessage]);
@@ -252,7 +252,6 @@ const ChatWindow = ({
252
252
  const handleSubmitWithInputs = useCallback(
253
253
  (prompt: ChatPrompt, inputValues: Record<string, string>) => {
254
254
  let finalBody = prompt.body || ''; // Start with the original body
255
-
256
255
  // Ensure prompt and prompt.data exist before accessing properties
257
256
  if (!prompt || !prompt.data) {
258
257
  console.error('handleSubmitWithInputs called without a valid prompt.');
@@ -264,10 +263,10 @@ const ChatWindow = ({
264
263
  for (const [key, value] of Object.entries(inputValues)) {
265
264
  const placeholder = `{{${key}}}`;
266
265
  // Replace all occurrences of the placeholder in the body
267
- finalBody = finalBody.replaceAll(placeholder, value);
266
+ finalBody = finalBody.replaceAll(placeholder, `"${value}"`);
268
267
  }
269
268
 
270
- // Submit the original title and the processed body as additional context
269
+ // Submit the processed title and the processed body as additional context
271
270
  submitQuestion(prompt.data.title, finalBody);
272
271
 
273
272
  setIsInputModalOpen(false); // Close modal
@@ -5,7 +5,6 @@ import { getChatPromptsGroupedByCategory } from '@enterprise/eventcatalog-chat/u
5
5
  import config from '@config';
6
6
  import path from 'node:path';
7
7
  import fs from 'node:fs';
8
- import { isEventCatalogChatEnabled } from '@utils/feature';
9
8
  import { Code } from 'astro-expressive-code/components';
10
9
  import { getDomains } from '@utils/collections/domains';
11
10
  import { getEvents } from '@utils/events';
@@ -43,10 +42,6 @@ const generatorConfig = `
43
42
  ],
44
43
  ],
45
44
  `;
46
-
47
- if (!isEventCatalogChatEnabled()) {
48
- return Astro.redirect(buildUrl('/chat/feature'));
49
- }
50
45
  ---
51
46
 
52
47
  <VerticalSideBarLayout title="AI Chat">
@@ -1,5 +1,10 @@
1
1
  ---
2
2
  import ChatPage from '@enterprise/eventcatalog-chat/pages/chat/index.astro';
3
+ import { isEventCatalogChatEnabled } from '@utils/feature';
4
+ import { buildUrl } from '@utils/url-builder';
5
+ if (!isEventCatalogChatEnabled()) {
6
+ return Astro.redirect(buildUrl('/chat/feature'));
7
+ }
3
8
  ---
4
9
 
5
10
  <ChatPage />
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "url": "https://github.com/event-catalog/eventcatalog.git"
7
7
  },
8
8
  "type": "module",
9
- "version": "2.35.1",
9
+ "version": "2.35.3",
10
10
  "publishConfig": {
11
11
  "access": "public"
12
12
  },
@@ -63,6 +63,7 @@
63
63
  "date-fns": "^4.1.0",
64
64
  "diff": "^7.0.0",
65
65
  "diff2html": "^3.4.48",
66
+ "dotenv": "^16.5.0",
66
67
  "glob": "^10.4.1",
67
68
  "gray-matter": "^4.0.3",
68
69
  "html-to-image": "^1.11.11",