@eeacms/volto-eea-chatbot 1.0.9

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/.coverage.babel.config.js +9 -0
  2. package/.eslintrc.js +68 -0
  3. package/.husky/pre-commit +2 -0
  4. package/.release-it.json +17 -0
  5. package/AGENTS.md +89 -0
  6. package/CHANGELOG.md +770 -0
  7. package/DEVELOP.md +124 -0
  8. package/LICENSE.md +9 -0
  9. package/README.md +170 -0
  10. package/RELEASE.md +74 -0
  11. package/TESTING.md +5 -0
  12. package/babel.config.js +17 -0
  13. package/bootstrap +41 -0
  14. package/cypress.config.js +27 -0
  15. package/docker-compose.yml +32 -0
  16. package/jest-addon.config.js +465 -0
  17. package/jest.setup.js +65 -0
  18. package/locales/de/LC_MESSAGES/volto.po +14 -0
  19. package/locales/en/LC_MESSAGES/volto.po +14 -0
  20. package/locales/it/LC_MESSAGES/volto.po +14 -0
  21. package/locales/ro/LC_MESSAGES/volto.po +14 -0
  22. package/locales/volto.pot +16 -0
  23. package/package.json +98 -0
  24. package/razzle.extend.js +40 -0
  25. package/src/ChatBlock/ChatBlockEdit.jsx +46 -0
  26. package/src/ChatBlock/ChatBlockView.jsx +21 -0
  27. package/src/ChatBlock/chat/AIMessage.tsx +566 -0
  28. package/src/ChatBlock/chat/ChatMessage.tsx +35 -0
  29. package/src/ChatBlock/chat/ChatWindow.tsx +288 -0
  30. package/src/ChatBlock/chat/UserMessage.tsx +27 -0
  31. package/src/ChatBlock/chat/index.ts +4 -0
  32. package/src/ChatBlock/components/AutoResizeTextarea.jsx +67 -0
  33. package/src/ChatBlock/components/BlinkingDot.tsx +3 -0
  34. package/src/ChatBlock/components/ChatMessageFeedback.jsx +77 -0
  35. package/src/ChatBlock/components/EmptyState.jsx +70 -0
  36. package/src/ChatBlock/components/FeedbackModal.jsx +125 -0
  37. package/src/ChatBlock/components/HalloumiFeedback.jsx +126 -0
  38. package/src/ChatBlock/components/Icon.tsx +35 -0
  39. package/src/ChatBlock/components/QualityCheckToggle.jsx +26 -0
  40. package/src/ChatBlock/components/RelatedQuestions.jsx +59 -0
  41. package/src/ChatBlock/components/Source.jsx +93 -0
  42. package/src/ChatBlock/components/SourceChip.tsx +55 -0
  43. package/src/ChatBlock/components/Spinner.jsx +3 -0
  44. package/src/ChatBlock/components/UserActionsToolbar.jsx +44 -0
  45. package/src/ChatBlock/components/WebResultIcon.tsx +42 -0
  46. package/src/ChatBlock/components/markdown/Citation.jsx +70 -0
  47. package/src/ChatBlock/components/markdown/ClaimModal.jsx +98 -0
  48. package/src/ChatBlock/components/markdown/ClaimSegments.jsx +172 -0
  49. package/src/ChatBlock/components/markdown/RenderClaimView.jsx +96 -0
  50. package/src/ChatBlock/components/markdown/colors.js +29 -0
  51. package/src/ChatBlock/components/markdown/colors.less +52 -0
  52. package/src/ChatBlock/components/markdown/colors.test.js +69 -0
  53. package/src/ChatBlock/components/markdown/index.js +115 -0
  54. package/src/ChatBlock/fonts/DejaVuSans.ttf +0 -0
  55. package/src/ChatBlock/hocs/withOnyxData.jsx +46 -0
  56. package/src/ChatBlock/hooks/index.ts +7 -0
  57. package/src/ChatBlock/hooks/useChatController.ts +333 -0
  58. package/src/ChatBlock/hooks/useChatStreaming.ts +82 -0
  59. package/src/ChatBlock/hooks/useDeepCompareMemoize.js +17 -0
  60. package/src/ChatBlock/hooks/useMarked.js +44 -0
  61. package/src/ChatBlock/hooks/useQualityMarkers.js +119 -0
  62. package/src/ChatBlock/hooks/useScrollonStream.ts +131 -0
  63. package/src/ChatBlock/hooks/useToolDisplayTiming.ts +80 -0
  64. package/src/ChatBlock/index.js +32 -0
  65. package/src/ChatBlock/packets/MultiToolRenderer.tsx +235 -0
  66. package/src/ChatBlock/packets/RendererComponent.tsx +115 -0
  67. package/src/ChatBlock/packets/index.ts +4 -0
  68. package/src/ChatBlock/packets/renderers/CustomToolRenderer.tsx +63 -0
  69. package/src/ChatBlock/packets/renderers/FetchToolRenderer.tsx +59 -0
  70. package/src/ChatBlock/packets/renderers/ImageToolRenderer.tsx +62 -0
  71. package/src/ChatBlock/packets/renderers/MessageTextRenderer.tsx +172 -0
  72. package/src/ChatBlock/packets/renderers/ReasoningRenderer.tsx +122 -0
  73. package/src/ChatBlock/packets/renderers/SearchToolRenderer.tsx +323 -0
  74. package/src/ChatBlock/packets/renderers/index.ts +6 -0
  75. package/src/ChatBlock/schema.js +403 -0
  76. package/src/ChatBlock/services/index.ts +3 -0
  77. package/src/ChatBlock/services/messageProcessor.ts +348 -0
  78. package/src/ChatBlock/services/packetUtils.ts +48 -0
  79. package/src/ChatBlock/services/streamingService.ts +342 -0
  80. package/src/ChatBlock/style.less +1881 -0
  81. package/src/ChatBlock/tests/AIMessage.test.jsx +95 -0
  82. package/src/ChatBlock/tests/AutoResizeTextarea.test.jsx +49 -0
  83. package/src/ChatBlock/tests/BlinkingDot.test.jsx +71 -0
  84. package/src/ChatBlock/tests/ChatMessageFeedback.test.jsx +73 -0
  85. package/src/ChatBlock/tests/Citation.test.jsx +107 -0
  86. package/src/ChatBlock/tests/EmptyState.test.jsx +137 -0
  87. package/src/ChatBlock/tests/FeedbackModal.test.jsx +138 -0
  88. package/src/ChatBlock/tests/HalloumiFeedback.test.jsx +94 -0
  89. package/src/ChatBlock/tests/QualityCheckToggle.test.jsx +105 -0
  90. package/src/ChatBlock/tests/RelatedQuestions.test.jsx +215 -0
  91. package/src/ChatBlock/tests/Source.test.jsx +79 -0
  92. package/src/ChatBlock/tests/Spinner.test.jsx +18 -0
  93. package/src/ChatBlock/tests/index.test.js +51 -0
  94. package/src/ChatBlock/tests/messageProcessor.test.jsx +154 -0
  95. package/src/ChatBlock/tests/schema.test.js +166 -0
  96. package/src/ChatBlock/tests/useDeepCompareMemoize.test.js +107 -0
  97. package/src/ChatBlock/tests/useToolDisplayTiming.test.jsx +151 -0
  98. package/src/ChatBlock/types/cssmodules.d.ts +7 -0
  99. package/src/ChatBlock/types/interfaces.ts +154 -0
  100. package/src/ChatBlock/types/slate.d.ts +3 -0
  101. package/src/ChatBlock/types/streamingModels.ts +267 -0
  102. package/src/ChatBlock/types/volto.d.ts +3 -0
  103. package/src/ChatBlock/utils/citations.ts +25 -0
  104. package/src/ChatBlock/utils/index.tsx +114 -0
  105. package/src/halloumi/README.md +1 -0
  106. package/src/halloumi/generative.js +219 -0
  107. package/src/halloumi/generative.test.js +88 -0
  108. package/src/halloumi/middleware.js +70 -0
  109. package/src/halloumi/postprocessing.js +273 -0
  110. package/src/halloumi/postprocessing.test.js +441 -0
  111. package/src/halloumi/preprocessing.js +115 -0
  112. package/src/halloumi/preprocessing.test.js +245 -0
  113. package/src/icons/bot.svg +1 -0
  114. package/src/icons/check.svg +1 -0
  115. package/src/icons/chevron.svg +3 -0
  116. package/src/icons/clear.svg +1 -0
  117. package/src/icons/copy.svg +1 -0
  118. package/src/icons/done.svg +5 -0
  119. package/src/icons/external-link.svg +1 -0
  120. package/src/icons/file.svg +1 -0
  121. package/src/icons/glasses.svg +1 -0
  122. package/src/icons/globe.svg +1 -0
  123. package/src/icons/rotate.svg +1 -0
  124. package/src/icons/search.svg +5 -0
  125. package/src/icons/send.svg +1 -0
  126. package/src/icons/square-pen.svg +1 -0
  127. package/src/icons/stop.svg +9 -0
  128. package/src/icons/thumbs-down.svg +1 -0
  129. package/src/icons/thumbs-up.svg +1 -0
  130. package/src/icons/user.svg +1 -0
  131. package/src/index.js +58 -0
  132. package/src/middleware.js +250 -0
  133. package/tsconfig.json +40 -0
@@ -0,0 +1,465 @@
1
+ /**
2
+ * Generic Jest configuration for Volto addons
3
+ *
4
+ * This configuration automatically:
5
+ * - Detects the addon name from the config file path
6
+ * - Configures test coverage to focus on the specific test path
7
+ * - Handles different ways of specifying test paths:
8
+ * - Full paths like src/addons/addon-name/src/components
9
+ * - Just filenames like Component.test.jsx
10
+ * - Just directory names like components
11
+ *
12
+ * Usage:
13
+ * RAZZLE_JEST_CONFIG=src/addons/addon-name/jest-addon.config.js CI=true yarn test [test-path] --collectCoverage
14
+ */
15
+
16
+ require('dotenv').config({ path: __dirname + '/.env' });
17
+
18
+ const path = require('path');
19
+ const fs = require('fs');
20
+ const fg = require('fast-glob');
21
+
22
+ // Get the addon name from the current file path
23
+ const pathParts = __filename.split(path.sep);
24
+ const addonsIdx = pathParts.lastIndexOf('addons');
25
+ const addonName =
26
+ addonsIdx !== -1 && addonsIdx < pathParts.length - 1
27
+ ? pathParts[addonsIdx + 1]
28
+ : path.basename(path.dirname(__filename)); // Fallback to folder name
29
+ const addonBasePath = `src/addons/${addonName}/src`;
30
+
31
+ // --- Performance caches ---
32
+ const fileSearchCache = new Map();
33
+ const dirSearchCache = new Map();
34
+ const dirListingCache = new Map();
35
+ const statCache = new Map();
36
+ const implementationCache = new Map();
37
+
38
+ /**
39
+ * Cached fs.statSync wrapper to avoid redundant filesystem calls
40
+ * @param {string} p
41
+ * @returns {fs.Stats|null}
42
+ */
43
+ const getStatSync = (p) => {
44
+ if (statCache.has(p)) return statCache.get(p);
45
+ try {
46
+ const s = fs.statSync(p);
47
+ statCache.set(p, s);
48
+ return s;
49
+ } catch {
50
+ statCache.set(p, null);
51
+ return null;
52
+ }
53
+ };
54
+
55
+ /**
56
+ * Find files that match a specific pattern using fast-glob
57
+ * @param {string} baseDir - The base directory to search in
58
+ * @param {string} fileName - The name of the file to find
59
+ * @param {string} [pathPattern=''] - Optional path pattern to filter results
60
+ * @returns {string[]} - Array of matching file paths
61
+ */
62
+ const findFilesWithPattern = (baseDir, fileName, pathPattern = '') => {
63
+ const cacheKey = `${baseDir}|${fileName}|${pathPattern}`;
64
+ if (fileSearchCache.has(cacheKey)) {
65
+ return fileSearchCache.get(cacheKey);
66
+ }
67
+
68
+ let files = [];
69
+ try {
70
+ const patterns = fileName
71
+ ? [`${baseDir}/**/${fileName}`]
72
+ : [`${baseDir}/**/*.{js,jsx,ts,tsx}`];
73
+
74
+ files = fg.sync(patterns, { onlyFiles: true });
75
+
76
+ if (pathPattern) {
77
+ files = files.filter((file) => file.includes(pathPattern));
78
+ }
79
+ } catch {
80
+ files = [];
81
+ }
82
+
83
+ fileSearchCache.set(cacheKey, files);
84
+ return files;
85
+ };
86
+
87
+ /**
88
+ * Find directories that match a specific pattern using fast-glob
89
+ * @param {string} baseDir - The base directory to search in
90
+ * @param {string} dirName - The name of the directory to find
91
+ * @param {string} [pathPattern=''] - Optional path pattern to filter results
92
+ * @returns {string[]} - Array of matching directory paths
93
+ */
94
+ const findDirsWithPattern = (baseDir, dirName, pathPattern = '') => {
95
+ const cacheKey = `${baseDir}|${dirName}|${pathPattern}`;
96
+ if (dirSearchCache.has(cacheKey)) {
97
+ return dirSearchCache.get(cacheKey);
98
+ }
99
+
100
+ let dirs = [];
101
+ try {
102
+ const patterns = dirName
103
+ ? [`${baseDir}/**/${dirName}`]
104
+ : [`${baseDir}/**/`];
105
+
106
+ dirs = fg.sync(patterns, { onlyDirectories: true });
107
+
108
+ if (pathPattern) {
109
+ dirs = dirs.filter((dir) => dir.includes(pathPattern));
110
+ }
111
+ } catch {
112
+ dirs = [];
113
+ }
114
+
115
+ dirSearchCache.set(cacheKey, dirs);
116
+ return dirs;
117
+ };
118
+
119
+ /**
120
+ * Find files or directories in the addon using fast-glob
121
+ * @param {string} name - The name to search for
122
+ * @param {string} type - The type of item to find ('f' for files, 'd' for directories)
123
+ * @param {string} [additionalOptions=''] - Additional options for flexible path matching
124
+ * @returns {string|null} - The path of the found item or null if not found
125
+ */
126
+ const findInAddon = (name, type, additionalOptions = '') => {
127
+ const isFile = type === 'f';
128
+ const isDirectory = type === 'd';
129
+ const isFlexiblePathMatch = additionalOptions.includes('-path');
130
+
131
+ let pathPattern = '';
132
+ if (isFlexiblePathMatch) {
133
+ const match = additionalOptions.match(/-path "([^"]+)"/);
134
+ if (match && match[1]) {
135
+ pathPattern = match[1].replace(/\*/g, '');
136
+ }
137
+ }
138
+
139
+ try {
140
+ let results = [];
141
+ if (isFile) {
142
+ results = findFilesWithPattern(addonBasePath, name, pathPattern);
143
+ } else if (isDirectory) {
144
+ results = findDirsWithPattern(addonBasePath, name, pathPattern);
145
+ }
146
+ return results.length > 0 ? results[0] : null;
147
+ } catch (error) {
148
+ return null;
149
+ }
150
+ };
151
+
152
+ /**
153
+ * Find the implementation file for a test file
154
+ * @param {string} testPath - Path to the test file
155
+ * @returns {string|null} - Path to the implementation file or null if not found
156
+ */
157
+ const findImplementationFile = (testPath) => {
158
+ if (implementationCache.has(testPath)) {
159
+ return implementationCache.get(testPath);
160
+ }
161
+
162
+ if (!fs.existsSync(testPath)) {
163
+ implementationCache.set(testPath, null);
164
+ return null;
165
+ }
166
+
167
+ const dirPath = path.dirname(testPath);
168
+ const fileName = path.basename(testPath);
169
+
170
+ // Regex for common test file patterns (e.g., .test.js, .spec.ts)
171
+ const TEST_OR_SPEC_FILE_REGEX = /\.(test|spec)\.[jt]sx?$/;
172
+
173
+ if (!TEST_OR_SPEC_FILE_REGEX.test(fileName)) {
174
+ implementationCache.set(testPath, null);
175
+ return null;
176
+ }
177
+
178
+ const baseFileName = path
179
+ .basename(fileName, path.extname(fileName))
180
+ .replace(/\.(test|spec)$/, ''); // Remove .test or .spec
181
+
182
+ let dirFiles = dirListingCache.get(dirPath);
183
+ if (!dirFiles) {
184
+ dirFiles = fs.readdirSync(dirPath);
185
+ dirListingCache.set(dirPath, dirFiles);
186
+ }
187
+
188
+ const exactMatch = dirFiles.find((file) => {
189
+ const fileBaseName = path.basename(file, path.extname(file));
190
+ return (
191
+ fileBaseName === baseFileName && !TEST_OR_SPEC_FILE_REGEX.test(file) // Ensure it's not another test/spec file
192
+ );
193
+ });
194
+
195
+ if (exactMatch) {
196
+ const result = `${dirPath}/${exactMatch}`;
197
+ implementationCache.set(testPath, result);
198
+ return result;
199
+ }
200
+
201
+ const similarMatch = dirFiles.find((file) => {
202
+ if (
203
+ TEST_OR_SPEC_FILE_REGEX.test(file) ||
204
+ (getStatSync(`${dirPath}/${file}`)?.isDirectory() ?? false)
205
+ ) {
206
+ return false;
207
+ }
208
+ const fileBaseName = path.basename(file, path.extname(file));
209
+ return (
210
+ fileBaseName.toLowerCase().includes(baseFileName.toLowerCase()) ||
211
+ baseFileName.toLowerCase().includes(fileBaseName.toLowerCase())
212
+ );
213
+ });
214
+
215
+ if (similarMatch) {
216
+ const result = `${dirPath}/${similarMatch}`;
217
+ implementationCache.set(testPath, result);
218
+ return result;
219
+ }
220
+
221
+ implementationCache.set(testPath, null);
222
+ return null;
223
+ };
224
+
225
+ /**
226
+ * Get the test path from command line arguments
227
+ * @returns {string|null} - The resolved test path or null if not found
228
+ */
229
+ const getTestPath = () => {
230
+ const args = process.argv;
231
+ let testPath = null;
232
+ const TEST_FILE_REGEX = /\.test\.[jt]sx?$/; // Matches .test.js, .test.jsx, .test.ts, .test.tsx
233
+
234
+ testPath = args.find(
235
+ (arg) =>
236
+ arg.includes(addonName) &&
237
+ !arg.startsWith('--') &&
238
+ arg !== 'test' &&
239
+ arg !== 'node',
240
+ );
241
+
242
+ if (!testPath) {
243
+ const testIndex = args.findIndex((arg) => arg === 'test');
244
+ if (testIndex !== -1 && testIndex < args.length - 1) {
245
+ const nextArg = args[testIndex + 1];
246
+ if (!nextArg.startsWith('--')) {
247
+ testPath = nextArg;
248
+ }
249
+ }
250
+ }
251
+
252
+ if (!testPath) {
253
+ testPath = args.find((arg) => TEST_FILE_REGEX.test(arg));
254
+ }
255
+
256
+ if (!testPath) {
257
+ return null;
258
+ }
259
+
260
+ if (!testPath.includes(path.sep)) {
261
+ if (TEST_FILE_REGEX.test(testPath)) {
262
+ const foundTestFile = findInAddon(testPath, 'f');
263
+ if (foundTestFile) {
264
+ return foundTestFile;
265
+ }
266
+ } else {
267
+ const foundDir = findInAddon(testPath, 'd');
268
+ if (foundDir) {
269
+ return foundDir;
270
+ }
271
+ const flexibleDir = findInAddon(testPath, 'd', `-path "*${testPath}*"`);
272
+ if (flexibleDir) {
273
+ return flexibleDir;
274
+ }
275
+ }
276
+ } else if (
277
+ TEST_FILE_REGEX.test(testPath) && // Check if it looks like a test file path
278
+ !testPath.startsWith('src/addons/')
279
+ ) {
280
+ const testFileName = path.basename(testPath);
281
+ const foundTestFile = findInAddon(testFileName, 'f');
282
+ if (foundTestFile) {
283
+ const relativePath = path.dirname(testPath);
284
+ if (foundTestFile.includes(relativePath)) {
285
+ return foundTestFile;
286
+ }
287
+ const similarFiles = findFilesWithPattern(
288
+ addonBasePath,
289
+ testFileName,
290
+ relativePath,
291
+ );
292
+ if (similarFiles && similarFiles.length > 0) {
293
+ return similarFiles[0];
294
+ }
295
+ }
296
+ }
297
+
298
+ if (
299
+ !path
300
+ .normalize(testPath)
301
+ .startsWith(path.join('src', 'addons', addonName, 'src')) &&
302
+ !path.isAbsolute(testPath) // Use path.isAbsolute for robust check
303
+ ) {
304
+ testPath = path.join(addonBasePath, testPath); // Use path.join for OS-agnostic paths
305
+ }
306
+
307
+ if (fs.existsSync(testPath)) {
308
+ return testPath;
309
+ }
310
+
311
+ const pathWithoutTrailingSlash = testPath.endsWith(path.sep)
312
+ ? testPath.slice(0, -1)
313
+ : null;
314
+ if (pathWithoutTrailingSlash && fs.existsSync(pathWithoutTrailingSlash)) {
315
+ return pathWithoutTrailingSlash;
316
+ }
317
+
318
+ const pathWithTrailingSlash = !testPath.endsWith(path.sep)
319
+ ? testPath + path.sep
320
+ : null;
321
+ if (pathWithTrailingSlash && fs.existsSync(pathWithTrailingSlash)) {
322
+ // Generally, return paths without trailing slashes for consistency,
323
+ // unless it's specifically needed for a directory that only exists with it (rare).
324
+ return testPath;
325
+ }
326
+ return testPath; // Return the original path if no variations exist
327
+ };
328
+
329
+ /**
330
+ * Determine collectCoverageFrom patterns based on test path
331
+ * @returns {string[]} - Array of coverage patterns
332
+ */
333
+ const getCoveragePatterns = () => {
334
+ const excludePatterns = [
335
+ '!src/**/*.d.ts',
336
+ '!**/*.test.{js,jsx,ts,tsx}',
337
+ '!**/*.spec.{js,jsx,ts,tsx}',
338
+ ];
339
+
340
+ const defaultPatterns = [
341
+ `${addonBasePath}/**/*.{js,jsx,ts,tsx}`,
342
+ ...excludePatterns,
343
+ ];
344
+
345
+ const ANY_SCRIPT_FILE_REGEX = /\.[jt]sx?$/;
346
+
347
+ const directoryArg = process.argv.find(
348
+ (arg) =>
349
+ !arg.includes(path.sep) &&
350
+ !arg.startsWith('--') &&
351
+ arg !== 'test' &&
352
+ arg !== 'node' &&
353
+ !ANY_SCRIPT_FILE_REGEX.test(arg) &&
354
+ ![
355
+ 'yarn',
356
+ 'npm',
357
+ 'npx',
358
+ 'collectCoverage',
359
+ 'CI',
360
+ 'RAZZLE_JEST_CONFIG',
361
+ ].some(
362
+ (reserved) =>
363
+ arg === reserved || arg.startsWith(reserved.split('=')[0] + '='),
364
+ ) &&
365
+ process.argv.indexOf(arg) >
366
+ process.argv.findIndex((item) => item === 'test'),
367
+ );
368
+
369
+ if (directoryArg) {
370
+ const foundDir = findInAddon(directoryArg, 'd');
371
+ if (foundDir) {
372
+ return [`${foundDir}/**/*.{js,jsx,ts,tsx}`, ...excludePatterns];
373
+ }
374
+ }
375
+
376
+ let testPath = getTestPath();
377
+
378
+ if (!testPath) {
379
+ return defaultPatterns;
380
+ }
381
+
382
+ if (testPath.endsWith(path.sep)) {
383
+ testPath = testPath.slice(0, -1);
384
+ }
385
+
386
+ const stats = getStatSync(testPath);
387
+
388
+ if (stats && stats.isFile()) {
389
+ const implFile = findImplementationFile(testPath);
390
+ if (implFile) {
391
+ return [implFile, '!src/**/*.d.ts'];
392
+ }
393
+ const dirPath = path.dirname(testPath);
394
+ return [`${dirPath}/**/*.{js,jsx,ts,tsx}`, ...excludePatterns];
395
+ } else if (stats && stats.isDirectory()) {
396
+ return [`${testPath}/**/*.{js,jsx,ts,tsx}`, ...excludePatterns];
397
+ }
398
+
399
+ return defaultPatterns;
400
+ };
401
+
402
+ const coverageConfig = getCoveragePatterns();
403
+
404
+ module.exports = {
405
+ testMatch: ['**/src/addons/**/?(*.)+(spec|test).[jt]s?(x)'],
406
+ collectCoverageFrom: coverageConfig,
407
+ coveragePathIgnorePatterns: [
408
+ '/node_modules/',
409
+ 'schema\\.[jt]s?$',
410
+ 'index\\.[jt]s?$',
411
+ 'config\\.[jt]sx?$',
412
+ ],
413
+ moduleNameMapper: {
414
+ '\\.(css|less|scss|sass)$': 'identity-obj-proxy',
415
+ '@plone/volto/cypress': '<rootDir>/node_modules/@plone/volto/cypress',
416
+ '@plone/volto/babel': '<rootDir>/node_modules/@plone/volto/babel',
417
+ '@plone/volto/(.*)$': '<rootDir>/node_modules/@plone/volto/src/$1',
418
+ '@package/(.*)$': '<rootDir>/node_modules/@plone/volto/src/$1',
419
+ '@root/(.*)$': '<rootDir>/node_modules/@plone/volto/src/$1',
420
+ '@plone/volto-quanta/(.*)$': '<rootDir>/src/addons/volto-quanta/src/$1',
421
+ '@eeacms/search/(.*)$': '<rootDir>/src/addons/volto-searchlib/searchlib/$1',
422
+ '@eeacms/search': '<rootDir>/src/addons/volto-searchlib/searchlib',
423
+ '@eeacms/(.*?)/(.*)$': '<rootDir>/node_modules/@eeacms/$1/src/$2',
424
+ '@plone/volto-slate$':
425
+ '<rootDir>/node_modules/@plone/volto/packages/volto-slate/src',
426
+ '@plone/volto-slate/(.*)$':
427
+ '<rootDir>/node_modules/@plone/volto/packages/volto-slate/src/$1',
428
+ '~/(.*)$': '<rootDir>/src/$1',
429
+ 'load-volto-addons':
430
+ '<rootDir>/node_modules/@plone/volto/jest-addons-loader.js',
431
+ },
432
+ transformIgnorePatterns: [
433
+ '/node_modules/(?!(@plone|@root|@package|@eeacms)/).*/',
434
+ ],
435
+ transform: {
436
+ '^.+\\.js(x)?$': 'babel-jest',
437
+ '^.+\\.ts(x)?$': 'babel-jest',
438
+ '^.+\\.(png)$': 'jest-file',
439
+ '^.+\\.(jpg)$': 'jest-file',
440
+ '^.+\\.(svg)$': './node_modules/@plone/volto/jest-svgsystem-transform.js',
441
+ },
442
+ coverageThreshold: {
443
+ global: {
444
+ branches: 5,
445
+ functions: 5,
446
+ lines: 5,
447
+ statements: 5,
448
+ },
449
+ },
450
+ ...(process.env.JEST_USE_SETUP === 'ON' && {
451
+ setupFilesAfterEnv: [
452
+ fs.existsSync(
453
+ path.join(
454
+ __dirname,
455
+ 'node_modules',
456
+ '@eeacms',
457
+ addonName,
458
+ 'jest.setup.js',
459
+ ),
460
+ )
461
+ ? `<rootDir>/node_modules/@eeacms/${addonName}/jest.setup.js`
462
+ : `<rootDir>/src/addons/${addonName}/jest.setup.js`,
463
+ ],
464
+ }),
465
+ };
package/jest.setup.js ADDED
@@ -0,0 +1,65 @@
1
+ import { jest } from '@jest/globals';
2
+ import configureStore from 'redux-mock-store';
3
+ import thunk from 'redux-thunk';
4
+ import { blocksConfig } from '@plone/volto/config/Blocks';
5
+ import installSlate from '@plone/volto-slate/index';
6
+
7
+ var mockSemanticComponents = jest.requireActual('semantic-ui-react');
8
+ var mockComponents = jest.requireActual('@plone/volto/components');
9
+ var config = jest.requireActual('@plone/volto/registry').default;
10
+
11
+ config.blocks.blocksConfig = {
12
+ ...blocksConfig,
13
+ ...config.blocks.blocksConfig,
14
+ };
15
+
16
+ jest.doMock('semantic-ui-react', () => ({
17
+ __esModule: true,
18
+ ...mockSemanticComponents,
19
+ Popup: ({ content, trigger }) => {
20
+ return (
21
+ <div className="popup">
22
+ <div className="trigger">{trigger}</div>
23
+ <div className="content">{content}</div>
24
+ </div>
25
+ );
26
+ },
27
+ }));
28
+
29
+ jest.doMock('@plone/volto/components', () => {
30
+ return {
31
+ __esModule: true,
32
+ ...mockComponents,
33
+ SidebarPortal: ({ children }) => <div id="sidebar">{children}</div>,
34
+ };
35
+ });
36
+
37
+ jest.doMock('@plone/volto/registry', () =>
38
+ [installSlate].reduce((acc, apply) => apply(acc), config),
39
+ );
40
+
41
+ const mockStore = configureStore([thunk]);
42
+
43
+ global.fetch = jest.fn(() =>
44
+ Promise.resolve({
45
+ json: () => Promise.resolve({}),
46
+ }),
47
+ );
48
+
49
+ global.store = mockStore({
50
+ intl: {
51
+ locale: 'en',
52
+ messages: {},
53
+ formatMessage: jest.fn(),
54
+ },
55
+ content: {
56
+ create: {},
57
+ subrequests: [],
58
+ },
59
+ connected_data_parameters: {},
60
+ screen: {
61
+ page: {
62
+ width: 768,
63
+ },
64
+ },
65
+ });
@@ -0,0 +1,14 @@
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: \n"
4
+ "Report-Msgid-Bugs-To: \n"
5
+ "POT-Creation-Date: \n"
6
+ "PO-Revision-Date: \n"
7
+ "Last-Translator: \n"
8
+ "Language: \n"
9
+ "Language-Team: \n"
10
+ "Content-Type: \n"
11
+ "Content-Transfer-Encoding: \n"
12
+ "Plural-Forms: \n"
13
+
14
+
@@ -0,0 +1,14 @@
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: \n"
4
+ "Report-Msgid-Bugs-To: \n"
5
+ "POT-Creation-Date: \n"
6
+ "PO-Revision-Date: \n"
7
+ "Last-Translator: \n"
8
+ "Language: \n"
9
+ "Language-Team: \n"
10
+ "Content-Type: \n"
11
+ "Content-Transfer-Encoding: \n"
12
+ "Plural-Forms: \n"
13
+
14
+
@@ -0,0 +1,14 @@
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: \n"
4
+ "Report-Msgid-Bugs-To: \n"
5
+ "POT-Creation-Date: \n"
6
+ "PO-Revision-Date: \n"
7
+ "Last-Translator: \n"
8
+ "Language: \n"
9
+ "Language-Team: \n"
10
+ "Content-Type: \n"
11
+ "Content-Transfer-Encoding: \n"
12
+ "Plural-Forms: \n"
13
+
14
+
@@ -0,0 +1,14 @@
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: \n"
4
+ "Report-Msgid-Bugs-To: \n"
5
+ "POT-Creation-Date: \n"
6
+ "PO-Revision-Date: \n"
7
+ "Last-Translator: \n"
8
+ "Language: \n"
9
+ "Language-Team: \n"
10
+ "Content-Type: \n"
11
+ "Content-Transfer-Encoding: \n"
12
+ "Plural-Forms: \n"
13
+
14
+
@@ -0,0 +1,16 @@
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: Plone\n"
4
+ "POT-Creation-Date: 2023-06-28T10:48:22.678Z\n"
5
+ "Last-Translator: Plone i18n <plone-i18n@lists.sourceforge.net>\n"
6
+ "Language-Team: Plone i18n <plone-i18n@lists.sourceforge.net>\n"
7
+ "MIME-Version: 1.0\n"
8
+ "Content-Type: text/plain; charset=utf-8\n"
9
+ "Content-Transfer-Encoding: 8bit\n"
10
+ "Plural-Forms: nplurals=1; plural=0;\n"
11
+ "Language-Code: en\n"
12
+ "Language-Name: English\n"
13
+ "Preferred-Encodings: utf-8\n"
14
+ "Domain: volto\n"
15
+
16
+
package/package.json ADDED
@@ -0,0 +1,98 @@
1
+ {
2
+ "name": "@eeacms/volto-eea-chatbot",
3
+ "version": "1.0.9",
4
+ "description": "@eeacms/volto-eea-chatbot: Volto add-on",
5
+ "main": "src/index.js",
6
+ "author": "European Environment Agency: IDM2 A-Team",
7
+ "license": "MIT",
8
+ "homepage": "https://github.com/eea/volto-eea-chatbot",
9
+ "keywords": [
10
+ "volto-addon",
11
+ "volto",
12
+ "plone",
13
+ "react"
14
+ ],
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git@github.com:eea/volto-eea-chatbot.git"
18
+ },
19
+ "addons": [
20
+ "@eeacms/volto-matomo"
21
+ ],
22
+ "devDependencies": {
23
+ "@babel/plugin-proposal-private-methods": "7.18.6",
24
+ "@cypress/code-coverage": "^3.10.0",
25
+ "@plone/scripts": "*",
26
+ "@plone/types": "*",
27
+ "@types/loadable__component": "5.13.10",
28
+ "@types/node": "^24",
29
+ "@types/react": "^18",
30
+ "@types/react-dom": "^18",
31
+ "babel-plugin-transform-class-properties": "^6.24.1",
32
+ "cypress": "13.1.0",
33
+ "cypress-fail-fast": "^5.0.1",
34
+ "husky": "^8.0.3",
35
+ "i": "0.3.7",
36
+ "lint-staged": "^14.0.1",
37
+ "md5": "^2.3.0",
38
+ "npm": "11.6.3",
39
+ "remark-preset-wooorm": "^7.0.0",
40
+ "typescript": "^5.7.3"
41
+ },
42
+ "dependencies": {
43
+ "@eeacms/volto-matomo": "*",
44
+ "@microsoft/fetch-event-source": "2.0.1",
45
+ "@plone-collective/volto-sentry": "*",
46
+ "fast-json-patch": "3.1.1",
47
+ "highlight.js": "11.10.0",
48
+ "luxon": "3.5.0",
49
+ "marked": "13.0.3",
50
+ "node-fetch": "2.7.0",
51
+ "react-markdown": "8.0.7",
52
+ "react-textarea-autosize": "^8.5.3",
53
+ "rehype-prism-plus": "1.6.0",
54
+ "remark-gfm": "3.0.1",
55
+ "uuid": "10.0.0"
56
+ },
57
+ "lint-staged": {
58
+ "src/**/*.{js,jsx,ts,tsx,json}": [
59
+ "make lint-fix",
60
+ "make prettier-fix"
61
+ ],
62
+ "src/**/*.{jsx}": [
63
+ "make i18n"
64
+ ],
65
+ "theme/**/*.{css,less}": [
66
+ "make stylelint-fix"
67
+ ],
68
+ "src/**/*.{css,less}": [
69
+ "make stylelint-fix"
70
+ ],
71
+ "theme/**/*.overrides": [
72
+ "make stylelint-fix"
73
+ ],
74
+ "src/**/*.overrides": [
75
+ "make stylelint-fix"
76
+ ]
77
+ },
78
+ "scripts": {
79
+ "prepare": "husky install",
80
+ "release": "release-it",
81
+ "release-major-beta": "release-it major --preRelease=beta",
82
+ "release-beta": "release-it --preRelease=beta",
83
+ "bootstrap": "npm install -g ejs; npm link ejs; node bootstrap",
84
+ "test": "make test",
85
+ "test:fix": "make test-update",
86
+ "pre-commit": "yarn stylelint:fix && yarn prettier:fix && yarn lint:fix",
87
+ "stylelint": "make stylelint",
88
+ "stylelint:overrides": "make stylelint-overrides",
89
+ "stylelint:fix": "make stylelint-fix",
90
+ "prettier": "make prettier",
91
+ "prettier:fix": "make prettier-fix",
92
+ "lint": "make lint",
93
+ "lint:fix": "make lint-fix",
94
+ "i18n": "make i18n",
95
+ "cypress:run": "make cypress-run",
96
+ "cypress:open": "make cypress-open"
97
+ }
98
+ }